iCub-main
compensator.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 RobotCub Consortium, European Commission FP6 Project IST-004370
3  * Authors: Andrea Del Prete, Alexander Schmitz
4  * email: andrea.delprete@iit.it, alexander.schmitz@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17  */
18 #include <yarp/os/Time.h>
19 #include <yarp/math/Math.h>
20 #include <yarp/math/Rand.h> // TEMP
21 #include "math.h"
22 #include <algorithm>
24 
25 
26 using namespace std;
27 using namespace yarp::os;
28 using namespace yarp::sig;
29 using namespace yarp::math;
30 using namespace iCub::skinManager;
31 using namespace iCub::skinDynLib;
32 
33 const double Compensator::BIN_TOUCH = 100.0;
34 const double Compensator::BIN_NO_TOUCH = 0.0;
35 
36 Compensator::Compensator(string _name, string _robotName, string outputPortName, string inputPortName, BufferedPort<Bottle>* _infoPort,
37  double _compensationGain, double _contactCompensationGain, int addThreshold, float _minBaseline, bool _zeroUpRawData,
38  bool _binarization, bool _smoothFilter, float _smoothFactor, unsigned int _linkNum)
39  :
40  compensationGain(_compensationGain), contactCompensationGain(_contactCompensationGain),
41  addThreshold(addThreshold), infoPort(_infoPort),
42  minBaseline(_minBaseline), binarization(_binarization), smoothFilter(_smoothFilter),
43  smoothFactor(_smoothFactor), robotName(_robotName), name(_name), linkNum(_linkNum)
44 {
45  this->zeroUpRawData = _zeroUpRawData;
46  _isWorking = init(_name, _robotName, outputPortName, inputPortName);
47 }
48 
50  if(tactileSensorDevice){
51  tactileSensorDevice->close();
52  delete tactileSensorDevice;
53  }
54 
55  compensatedTactileDataPort.interrupt();
56  compensatedTactileDataPort.close();
57 }
58 
59 bool Compensator::init(string name, string robotName, string outputPortName, string inputPortName){
61  bodyPart = BODY_PART_UNKNOWN;
62 
63  if (!compensatedTactileDataPort.open(outputPortName.c_str())) {
64  stringstream msg; msg<< "Unable to open output port "<< outputPortName;
65  sendInfoMsg(msg.str());
66  return false; // unable to open
67  }
68 
69  Property options;
70  stringstream localPortName;
71  localPortName<< "/"<< name<< "/input";
72  options.put("robot", robotName.c_str());
73  options.put("local", localPortName.str().c_str());
74  options.put("remote", inputPortName.c_str());
75  options.put("device", "analogsensorclient");
76  tactileSensorDevice_inputPortName=inputPortName.c_str();
77 
78  // create a new device driver
79  tactileSensorDevice = new PolyDriver(options);
80  if (!tactileSensorDevice->isValid()){
81  sendInfoMsg("Device not available.\n");
82  //printf("%s", Drivers::factory().toString().c_str());
83  return false;
84  }
85  // open the sensor interface
86  bool ok = tactileSensorDevice->view(tactileSensor);
87  if (!ok) {
88  sendInfoMsg("Problems acquiring interfaces");
89  return false;
90  }
91 
92  // (temp) open port to read skin data with timestamp (because device driver doesn't provide timestamps)
93  localPortName<< "_temp";
94  if(!inputPort.open(localPortName.str().c_str()))
95  {
96  stringstream msg; msg<< "Unable to open input data port "<< localPortName.str();
97  sendInfoMsg(msg.str());
98  return false;
99  }
100 
101  if( !Network::connect(inputPortName.c_str(), localPortName.str().c_str()))
102  {
103  stringstream msg;
104  msg<< "Problems trying to connect ports %s and %s."<< inputPortName.c_str()<< localPortName.str().c_str();
105  sendInfoMsg(msg.str());
106  return false;
107  }
108 
109  int getChannelsCounter = 0;
110  skinDim = tactileSensor->getChannels();
111  while(skinDim<=0){
112  // getChannels() returns 0 if it hasn't performed the first reading yet
113  // so wait for 1/50 sec, then try again
114  if(++getChannelsCounter==50){
115  // after 50 failed trials give up and use the default value
116  skinDim = 192;
117  sendInfoMsg("Error reading the number of channels of the port. Using 192 as default value.");
118  break;
119  }
120  Time::delay(0.02);
121  skinDim = tactileSensor->getChannels();
122  }
123  readErrorCounter = 0;
124  rawData.resize(skinDim);
125  baselines.resize(skinDim);
126  touchThresholds.resize(skinDim);
127  touchDetected.resize(skinDim);
128  subTouchDetected.resize(skinDim);
129  touchDetectedFilt.resize(skinDim);
130  compensatedData.resize(skinDim);
131  compensatedDataOld.resize(skinDim);
132  compensatedDataFilt.resize(skinDim);
133  taxelPos.resize(skinDim, zeros(3));
134  taxelOri.resize(skinDim, zeros(3));
135  taxelPoseConfidence.resize(skinDim,0.0);
136  maxNeighDist = MAX_NEIGHBOR_DISTANCE;
137  // by default every taxel is neighbor with all the other taxels
138  list<int> defaultNeighbors(skinDim);
139  int i=0;
140  for(list<int>::iterator it=defaultNeighbors.begin();it!=defaultNeighbors.end();it++, i++)
141  *it = i;
142  neighborsXtaxel.resize(skinDim, defaultNeighbors);
143 
144  // test read to check if the skin is broken (all taxel output is 0)
145  if(robotName!="icubSim" && readInputData(compensatedData)){
146  bool skinBroken = true;
147  for(unsigned int i=0; i<skinDim; i++){
148  if(compensatedData[i]!=0.0){
149  skinBroken = false;
150  break;
151  }
152  }
153  if(skinBroken)
154  sendInfoMsg("The output of all the taxels is 0. Probably there is a hardware problem.");
155  return !skinBroken;
156  }
157 
158  return true;
159 }
160 
162  // take the semaphore so that the touchThreshold can't be read during the calibration phase
163  lock_guard<mutex> lck(touchThresholdSem);
164 
165  // send a command to the microcontroller for calibrating the skin sensors
166  if(robotName!="icubSim"){ // this feature isn't implemented in the simulator and causes a runtime error
167  tactileSensor->calibrateSensor();
168  }
169 
170  // initialize
171  calibrationRead = 0;
172  saturatedTaxels.resize(0);
173  start_sum.assign(skinDim, 0);
174  skin_empty.assign(skinDim, vector<int>(MAX_SKIN+1, 0));
175 }
176 
178  Vector skin_values(skinDim);
179  if(!readInputData(skin_values))
180  return;
181  calibrationRead++;
182 
183  for (unsigned int j=0; j<skinDim; j++) {
184  if (zeroUpRawData==false)
185  skin_values[j] = MAX_SKIN - skin_values[j];
186 
187  if(skin_values[j]<0 || skin_values[j]>MAX_SKIN)
188  sendInfoMsg("Error while reading the tactile data! Data out of range: "+toString(skin_values[j]));
189  else{
190  skin_empty[j][int(skin_values[j])]++;
191  start_sum[j] += int(skin_values[j]);
192  }
193  }
194 }
195 
197 
198  //vector<float> standard_dev(skinDim, 0);
199  //get percentile
200  for (unsigned int i=0; i<skinDim; i++) {
201  //avg start value
202  baselines[i] = start_sum[i]/ (calibrationRead!=0.0 ? calibrationRead : 1.0);
203 
204  //cumulative values
205  for (int j=1; j<=MAX_SKIN; j++) {
206  //standard_dev[i] += fabs(j-baselines[i]) * skin_empty[i][j];
207  skin_empty[i][j] += skin_empty[i][j-1] ;
208  }
209  //standard_dev[i] /= (CAL_TIME*PERIOD);
210 
211  //when do we cross the threshold? Compute 95 percentile
212  if( skin_empty[i][MAX_SKIN] < 0.95*calibrationRead )
213  {
214  sendInfoMsg("Error during calibration. Most readings were out of range.");
215  _isWorking = false;
216  }
217  else
218  {
219  for (int j=0; j<=MAX_SKIN; j++)
220  {
221  if (skin_empty[i][j] > (calibrationRead*0.95))
222  {
223  // the threshold can not be less than MIN_TOUCH_THR
224  touchThresholds[i] = (double)j - baselines[i];
225  j = MAX_SKIN; // break
226  }
227  }
228  }
229 
230 
231  }
232  // store the initial baseline to compute the drift compensated later
233  initialBaselines = baselines;
234 
235  // set the "old output value" for the smoothing filter to the baseline value to get a smooth start
236  compensatedDataOld = baselines;
237 
238  // test to check if the skin is broken (all taxel baselines are 255 OR thresholds are 0)
239  bool baseline255 = true, thresholdZero = true;
240  for(unsigned int i=0; i<skinDim; i++){
241  if(baselines[i]!=255){
242  baseline255 = false;
243  }
244  if(robotName=="icubSim" || touchThresholds[i]>1e-5){
245  thresholdZero = false;
246  }
247  }
248  if(baseline255 || thresholdZero){
249  _isWorking = false;
250 // if(baseline255)
251 // sendInfoMsg("The baselines of all the taxels are 255. Probably there is a hardware problem.");
252 // if(thresholdZero)
253 // sendInfoMsg("The noise of all taxels is 0. Probably there is a hardware problem.");
254  }
255  for (unsigned int i=0; i<skinDim; i++)
256  touchThresholds[i] = max<double>(MIN_TOUCH_THR, touchThresholds[i]);
257 
258  // print to console
259  /*if(_isWorking){
260  printf("\n[%s (%s)] Baselines:\n", name.c_str(), getSkinPartName().c_str());
261  for (unsigned int i=0; i<skinDim; i++) {
262  if(!(i%12)) fprintf(stderr, "\n");
263  fprintf(stderr,"%5.1f ", baselines[i]);
264  }
265  printf("\n[%s (%s)] Thresholds (95 percentile):\n", name.c_str(), getSkinPartName().c_str());
266  for (unsigned int i=0; i<skinDim; i++) {
267  if(!(i%12)) fprintf(stderr, "\n");
268  touchThresholds[i] = max<double>(MIN_TOUCH_THR, touchThresholds[i]);
269  fprintf(stderr,"%3.1f ", touchThresholds[i]);
270  }
271  printf("\n");
272  }*/
273  sendInfoMsg("Calibration finished");
274 }
275 
276 bool Compensator::readInputData(Vector& skin_values){
277  Vector *tmp=0;
278  if((tmp=inputPort.read(false))==0){
279  readErrorCounter++;
280  if(readErrorCounter>MAX_READ_ERROR){
281  _isWorking = false;
282  sendInfoMsg("Too many errors in a row. Stopping the compensator.");
283  }
284  return false;
285  }
286  //try to read envelope of input data port
287  inputPort.getEnvelope(timestamp);
288 
289  skin_values = *tmp; // copy data
290 
291  if(skin_values.size() != skinDim){
292  readErrorCounter++;
293  sendInfoMsg("Unexpected size of the input array (raw tactile data): "+toString(skin_values.size()));
294  if(readErrorCounter>MAX_READ_ERROR){
295  _isWorking = false;
296  sendInfoMsg("Too many errors in a row. Stopping the compensator.");
297  }
298  return false;
299  }
300 
301  readErrorCounter = 0;
302  return true;
303 /*
304  int err;
305  if((err=tactileSensor->read(skin_values))!=IAnalogSensor::AS_OK){
306  readErrorCounter++;
307 
308  stringstream msg;
309  if(err == IAnalogSensor::AS_TIMEOUT)
310  msg<< "Timeout error reading tactile sensor.";
311  else if(err == IAnalogSensor::AS_OVF)
312  msg<< "Ovf error reading tactile sensor.";
313  else if(err == IAnalogSensor::AS_ERROR)
314  msg<< "Generic error reading tactile sensor.";
315  sendInfoMsg(msg.str());
316 
317  if(readErrorCounter>MAX_READ_ERROR){
318  _isWorking = false;
319  sendInfoMsg("Too many errors in a row. Stopping the compensator.");
320  }
321  return false;
322  }
323 
324  if(skin_values.size() != skinDim){
325  readErrorCounter++;
326  sendInfoMsg("Unexpected size of the input array (raw tactile data): "+toString(skin_values.size()));
327  if(readErrorCounter>MAX_READ_ERROR){
328  _isWorking = false;
329  sendInfoMsg("Too many errors in a row. Stopping the compensator.");
330  }
331  return false;
332  }
333 
334  readErrorCounter = 0;
335  return true;*/
336 }
337 
339  if(!readInputData(rawData))
340  return false;
341 
342  Vector& compensatedData2Send = compensatedTactileDataPort.prepare();
343  compensatedData2Send.resize(skinDim); // local variable with data to send
344  compensatedData.resize(skinDim); // global variable with data to store
345 
346  double d;
347  for(unsigned int i=0; i<skinDim; i++){
348  // baseline compensation
349  d = (double)( zeroUpRawData ? rawData(i)-baselines[i] : MAX_SKIN-rawData(i)-baselines[i] );
350  d = min<double>( MAX_SKIN, d);
351  compensatedData[i] = d; // save the data before applying filtering
352 
353  // detect touch (before applying filtering, so the compensation algorithm is not affected by the filters)
354  touchDetected[i] = (d > touchThresholds[i] + addThreshold);
355 
356  // detect subtouch
357  subTouchDetected[i] = (d < -touchThresholds[i] - addThreshold);
358 
359  // smooth filter
360  if(smoothFilter){
361  lock_guard<mutex> lck(smoothFactorSem);
362  d = (1-smoothFactor)*d + smoothFactor*compensatedDataOld(i);
363  compensatedDataOld(i) = d; // update old value
364  }
365  compensatedDataFilt[i] = d;
366 
367  // binarization filter
368  // here we don't use the touchDetected array because, if the smooth filter is on,
369  // we want to use the filtered values
370  touchDetectedFilt[i] = (d > touchThresholds[i] + addThreshold);
371  if(binarization)
372  d = ( touchDetectedFilt[i] ? BIN_TOUCH : BIN_NO_TOUCH );
373 
374  compensatedData2Send[i] = max<double>(0.0, d); // trim only data to send because you need negative values for update baseline
375  }
376 
377  compensatedTactileDataPort.write();
378  return true;
379 }
380 
382  double mean_change = 0, change, gain;
383  unsigned int non_touching_taxels = 0;
384  double d;
385 
386  for(unsigned int j=0; j<skinDim; j++) {
387  // *** Algorithm 1
388  /*if(!touchDetected[j]){
389  if(d > 0.5) {
390  baselines[j] += compensationGain;
391  mean_change += compensationGain; //for changing the taxels where we detected touch
392  }else if(d < -0.5) {
393  baselines[j] -= compensationGain;
394  mean_change -= compensationGain; //for changing the taxels where we detected touch
395  }
396  }*/
397 
398  // *** Algorithm 2
399  /*if(!(touchDetected[j] || subTouchDetected[j])){
400  non_touching_taxels++; //for changing the taxels where we detected touch
401  d = compensatedData(j);
402  if(fabs(d)>0.5){
403  change = (compensationGain/50)*d/touchThresholds[j];
404  baselines[j] += change;
405  mean_change += change;
406  }
407  }*/
408 
409  d = compensatedData(j);
410  if(touchDetected[j]){
411  gain = contactCompensationGain*0.02;
412  }else{
413  gain = compensationGain*0.02;
414  non_touching_taxels++;
415  }
416  change = gain*d/touchThresholds[j];
417  baselines[j] += change;
418  mean_change += change;
419 
420  // if(j<5)
421  // printf("%d touch detected %s, change %.6f, gain: %.3f\n", j, touchDetected[j]?"yes":"no", change, touchDetected[j]?contactCompensationGain:compensationGain);
422 
423  if(baselines[j]<0){
424  char* temp = new char[300];
425  sprintf(temp, "ERROR-Negative baseline. Port %s; tax %d; baseline %.2f; gain: %.4f; d: %.2f; raw: %.2f; change: %f; touchThr: %.2f",
426  SkinPart_s[skinPart].c_str(), j, baselines[j], gain, d, rawData[j], change, touchThresholds[j]);
427  sendInfoMsg(temp);
428  }
429  }
430 
431  //for compensating the taxels where we detected touch
432  /*if (non_touching_taxels>0 && non_touching_taxels<skinDim && mean_change!=0){
433  mean_change /= non_touching_taxels;
434  for(unsigned int j=0; j<skinDim; j++) {
435  if (touchDetected[j]) {
436  baselines[j] += mean_change;
437  if(baselines[j]<0){
438  char* temp = new char[300];
439  sprintf(temp, "ERROR-Negative baseline. Taxel %d; baseline %.2f; meanchange: %f", j, baselines[j], mean_change);
440  sendInfoMsg(temp);
441  }
442  }
443  }
444  }*/
445 }
446 
447 bool Compensator::doesBaselineExceed(unsigned int &taxelIndex, double &baseline, double &initialBaseline){
448  vector<unsigned int>::iterator it;
449  for(unsigned int i=0; i<skinDim; i++){
450  if(baselines[i]<minBaseline || baselines[i]>MAX_SKIN-minBaseline){
451  it = find(saturatedTaxels.begin(), saturatedTaxels.end(), i);
452  if(it==saturatedTaxels.end()){ // if the taxel hasn't been already signalled
453  //fprintf(stderr, "Baseline %d exceeds: %f\n", i, baselines[i]);
454  saturatedTaxels.push_back(i);
455  baseline = baselines[i];
456  initialBaseline = initialBaselines[i];
457  taxelIndex = i;
458  return true;
459  }
460  }
461  }
462  return false;
463 }
464 
466  vector<int> contactXtaxel(skinDim, -1); // contact for each taxel (-1 means no contact)
467  deque<deque<int> > taxelsXcontact; // taxels for each contact
468  int contactId = 0; // id of the next contact to create
469  int neighCont; // id of the contact of the current neighbor
470 
471  poseSem.lock();
472  {
473  for(unsigned int i=0; i<skinDim; i++){
474  if(touchDetectedFilt[i] ){ // && contactXtaxel[i]<0 (second condition should always be true)
475  list<int> *neighbors = &(neighborsXtaxel[i]);
476  //printf("Taxel %d active. Going to check its %d neighbors\n", i, neighbors->size());
477  for(list<int>::iterator it=neighbors->begin(); it!=neighbors->end(); it++){
478  neighCont = contactXtaxel[(*it)];
479  if(neighCont >= 0){ // ** if neighbor belongs to a contact
480  if(contactXtaxel[i]<0){ // ** add taxel to pre-existing contact
481  contactXtaxel[i] = neighCont;
482  taxelsXcontact[neighCont].push_back(i);
483  //printf("Add taxel to pre existing contact %d (neighbor %d)\n", neighCont, (*neighbors)[n]);
484  }else if(contactXtaxel[i]!=neighCont){ // ** merge 2 contacts
485  //mergeContacts(contactXtaxel[i], neighCont);
486  int newId = min(contactXtaxel[i], neighCont);
487  int oldId = max(contactXtaxel[i], neighCont);
488  deque<int> tax2move = taxelsXcontact[oldId];
489  for(deque<int>::iterator it=tax2move.begin(); it!=tax2move.end(); it++){
490  contactXtaxel[(*it)] = newId; // assign new contact id
491  taxelsXcontact[newId].push_back((*it)); // add taxel ids to contact
492  }
493  taxelsXcontact[oldId].clear(); // clear the list of taxels belonging to the merged contact
494  //printf("Merge two contacts: %d and %d\n", oldId, newId);
495  }
496  }
497 
498  }
499  if(contactXtaxel[i]<0){ // ** if no neighbor belongs to a contact -> create new contact
500  contactXtaxel[i] = contactId;
501  taxelsXcontact.resize(contactId+1);
502  taxelsXcontact[contactId].push_back(i);
503  contactId++;
504  //printf("New contact created: %d\n", contactId-1);
505  }
506  }
507  }
508  }
509  poseSem.unlock();
510 
511  skinContactList contactList;
512  Vector CoP(3), geoCenter(3), normal(3);
513  double pressure, pressureCoP, pressureNormal, out;
514  int activeTaxels, activeTaxelsGeo;
515  vector<unsigned int> taxelList;
516  for( deque<deque<int> >::iterator it=taxelsXcontact.begin(); it!=taxelsXcontact.end(); it++){
517  activeTaxels = it->size();
518  if(activeTaxels==0) continue;
519 
520  taxelList.resize(activeTaxels);
521  CoP.zero();
522  geoCenter.zero();
523  normal.zero();
524  pressure = pressureCoP = pressureNormal = 0.0;
525  activeTaxelsGeo = 0;
526  int i=0;
527  for( deque<int>::iterator tax=it->begin(); tax!=it->end(); tax++, i++){
528  out = max(compensatedDataFilt[(*tax)], 0.0);
529  if(norm(taxelPos[(*tax)])!=0.0){ // if the taxel position estimate exists
530  CoP += taxelPos[(*tax)] * out;
531  pressureCoP += out;
532  activeTaxelsGeo++;
533  geoCenter += taxelPos[(*tax)];
534  }
535  if(norm(taxelOri[(*tax)])!=0.0){ // if the taxel orientation estimate exists
536  normal += taxelOri[(*tax)] * out;
537  pressureNormal += out;
538  }
539  pressure += out;
540  taxelList[i] = *tax;
541  }
542  // if this is not the only contact and no taxel in this contact has a position => discard it
543  if(taxelsXcontact.size()>1 && activeTaxelsGeo==0)
544  continue;
545  if(pressureCoP!=0.0) CoP /= pressureCoP;
546  if(pressureNormal!=0.0) normal /= pressureNormal;
547  if(activeTaxelsGeo!=0) geoCenter /= activeTaxelsGeo;
548  pressure /= activeTaxels;
549  skinContact c(bodyPart, skinPart, linkNum, CoP, geoCenter, taxelList, pressure, normal);
550  // set an estimate of the force that is with normal direction and intensity equal to the pressure
551  c.setForce(-0.05*activeTaxels*pressure*normal);
552  contactList.push_back(c);
553  }
554  //printf("ContactList: %s\n", contactList.toString().c_str());
555 
556  return contactList;
557 }
558 
560  if(smoothFilter != value){
561  smoothFilter = value;
562  if(value){
563  // set the old output value of the smooth filter to the last read, to get a smooth start
564  compensatedDataOld = compensatedData;
565  }
566  }
567 }
569  if(value<0.0 || value>1.0)
570  return false;
571  if(value==1.0)
572  value = 0.99f; // otherwise with 1 the values don't update
573  lock_guard<mutex> lck(smoothFactorSem);
574  smoothFactor = value;
575  return true;
576 }
577 
579  this->skinPart = _skinPart;
580  this->bodyPart = skinDynLib::getBodyPart(skinPart);
581  this->linkNum = skinDynLib::getLinkNum(skinPart);
582 }
583 
584 bool Compensator::setAddThreshold(unsigned int thr){
585  if(thr>=MAX_SKIN)
586  return false;
587  addThreshold = thr;
588  return true;
589 }
590 
592  if(gain<=0.0)
593  return false;
594  compensationGain = gain;
595  return true;
596 }
597 
599  if(gain<0.0)
600  return false;
601  contactCompensationGain = gain;
602  return true;
603 }
604 
606  if(_isWorking)
607  return skinDim;
608  return 0;
609 }
610 
611 Vector Compensator::getCompensation(){ return baselines-initialBaselines; }
612 
614  lock_guard<mutex> lck(touchThresholdSem);
615  return touchThresholds;
616 }
617 
619  lock_guard<mutex> lck(smoothFactorSem);
620  return smoothFactor;
621 }
622 Vector Compensator::getTaxelPosition(unsigned int taxelId){
623  if(taxelId>=skinDim)
624  return zeros(0);
625  lock_guard<mutex> lck(poseSem);
626  Vector res = taxelPos[taxelId];
627  res.push_back(taxelPoseConfidence[taxelId]);
628  return res;
629 }
631  lock_guard<mutex> lck(poseSem);
632  vector<Vector> res = taxelPos;
633  for(unsigned int i=0; i<res.size(); i++)
634  res[i].push_back(taxelPoseConfidence[i]);
635  return res;
636 }
637 Vector Compensator::getTaxelOrientation(unsigned int taxelId){
638  if(taxelId>=skinDim)
639  return zeros(0);
640  lock_guard<mutex> lck(poseSem);
641  Vector res = taxelOri[taxelId];
642  res.push_back(taxelPoseConfidence[taxelId]);
643  return res;
644 }
646  lock_guard<mutex> lck(poseSem);
647  vector<Vector> res = taxelOri;
648  for(unsigned int i=0; i<res.size(); i++)
649  res[i].push_back(taxelPoseConfidence[i]);
650  return res;
651 }
652 Vector Compensator::getTaxelPose(unsigned int taxelId){
653  if(taxelId>=skinDim)
654  return zeros(0);
655  lock_guard<mutex> lck(poseSem);
656  Vector res = cat(taxelPos[taxelId], taxelOri[taxelId]);
657  res.push_back(taxelPoseConfidence[taxelId]);
658  return res;
659 }
660 vector<Vector> Compensator::getTaxelPoses(){
661  vector<Vector> res(skinDim);
662  lock_guard<mutex> lck(poseSem);
663  for(unsigned int i=0; i<skinDim; i++){
664  res[i] = cat(taxelPos[i], taxelOri[i]);
665  res[i].push_back(taxelPoseConfidence[i]);
666  }
667  return res;
668 }
669 
670 double Compensator::getPoseConfidence(unsigned int taxelId){
671  if(taxelId>=skinDim)
672  return -1.0;
673  lock_guard<mutex> lck(poseSem);
674  return taxelPoseConfidence[taxelId];
675 }
676 
678  lock_guard<mutex> lck(poseSem);
679  return taxelPoseConfidence;
680 }
681 
683  if(d<0.0)
684  return false;
685  maxNeighDist = d;
686  lock_guard<mutex> lck(poseSem);
687  computeNeighbors();
688  return true;
689 }
690 
691 bool Compensator::setTaxelPosesFromFile(const char *filePath){
692  yarp::os::ResourceFinder rf;
693  rf.setDefaultContext("skinGui"); //overridden by --context parameter
694  rf.setDefaultConfigFile(filePath); //overridden by --from parameter
695  rf.configure(0,NULL);
696 
697  yarp::os::Bottle &calibration = rf.findGroup("calibration");
698  if (calibration.isNull())
699  {
700  return setTaxelPosesFromFileOld(filePath);
701  }
702  else
703  {
704  lock_guard<mutex> lck(poseSem);
705  int size=calibration.size()-1;
706  skinDim=size;
707  taxelPos.resize(skinDim, zeros(3));
708  taxelOri.resize(skinDim, zeros(3));
709  taxelPoseConfidence.resize(skinDim, 0.0);
710  for (int i = 0; i < size; ++i)
711  {
712  if (i<(int)taxelPos.size())
713  {
714  Vector taxelPosNrm(6,0.0);
715  taxelPosNrm = iCub::skinDynLib::vectorFromBottle(*(calibration.get(i+1).asList()),0,6);
716  taxelPos[i] = taxelPosNrm.subVector(0,2);
717  taxelOri[i] = taxelPosNrm.subVector(3,5);
718  }
719  if(norm(taxelPos[i])>0.0)
720  taxelPoseConfidence[i] = 1.0;
721  }
722  computeNeighbors();
723  }
724 
725  return true;
726 }
727 
728 bool Compensator::setTaxelPosesFromFileOld(const char *filePath){
729  ifstream posFile;
730  posFile.open(filePath);
731  if (!posFile.is_open())
732  return false;
733 
734  string posLine;
735  int totalLines = 0;
736  while (getline(posFile,posLine)){
737  posLine.erase(posLine.find_last_not_of(" \n\r\t")+1);
738  if(!posLine.empty())totalLines++;
739  }
740  posFile.clear();
741  posFile.seekg(0, std::ios::beg);//rewind iterator
742  if(totalLines!=skinDim){
743  char* temp = new char[200];
744  sprintf(temp, "Error while reading taxel position file %s: num of lines %d is not equal to num of taxels %d.\n",
745  filePath, totalLines, skinDim);
746  sendInfoMsg(temp);
747  }
748  lock_guard<mutex> lck(poseSem);
749  {
750  for(unsigned int i= 0; getline(posFile,posLine); i++) {
751  posLine.erase(posLine.find_last_not_of(" \n\r\t")+1);
752  if(posLine.empty())
753  continue;
754  string number;
755  istringstream iss(posLine, istringstream::in);
756  for(unsigned int j = 0; iss >> number; j++ ){
757  if(i<taxelPos.size()){
758  if(j<3)
759  taxelPos[i][j] = strtod(number.c_str(),NULL);
760  else
761  taxelOri[i][j-3] = strtod(number.c_str(),NULL);
762  }
763  }
764  if(norm(taxelPos[i])>0.0)
765  taxelPoseConfidence[i] = 1.0;
766  }
767  computeNeighbors();
768  }
769  return true;
770 }
771 bool Compensator::setTaxelPoses(const vector<Vector> &poses){
772  if(poses.size()!=skinDim)
773  return false;
774  lock_guard<mutex> lck(poseSem);
775  {
776  for(unsigned int i=0; i<skinDim; i++){
777  taxelPos[i] = poses[i].subVector(0,2);
778  taxelOri[i] = poses[i].subVector(3,5);
779  if(poses[i].size() == 7)
780  taxelPoseConfidence[i] = poses[i][6];
781  }
782  }
783  computeNeighbors();
784  return true;
785 }
786 bool Compensator::setTaxelPose(unsigned int taxelId, const Vector &pose){
787  if(taxelId>=skinDim || pose.size()!=6)
788  return false;
789  lock_guard<mutex> lck(poseSem);
790  {
791  taxelPos[taxelId] = pose.subVector(0,2);
792  taxelOri[taxelId] = pose.subVector(3,5);
793  if(pose.size() == 7)
794  taxelPoseConfidence[taxelId] = pose[6];
795  }
796  updateNeighbors(taxelId);
797  return true;
798 }
799 bool Compensator::setTaxelPositions(const Vector &positions){
800  lock_guard<mutex> lck(poseSem);
801  if(skinDim*3 == positions.size()){
802  for(unsigned int j=0; j<skinDim; j++){
803  taxelPos[j] = positions.subVector(3*j, 3*j+2);
804  }
805  }
806  else if(skinDim*4 == positions.size()){
807  for(unsigned int j=0; j<skinDim; j++){
808  taxelPos[j] = positions.subVector(4*j, 4*j+2);
809  taxelPoseConfidence[j] = positions[4*j+3];
810  }
811  }
812  else
813  return false;
814 
815  computeNeighbors();
816  return true;
817 }
818 
819 bool Compensator::setTaxelPosition(unsigned int taxelId, const Vector &position){
820  if(taxelId>=skinDim || (position.size()!=3 && position.size()!=4))
821  return false;
822  lock_guard<mutex> lck(poseSem);
823  taxelPos[taxelId] = position.subVector(0,2);
824  if(position.size()==4)
825  taxelPoseConfidence[taxelId] = position[3];
826  updateNeighbors(taxelId);
827  return true;
828 }
829 bool Compensator::setTaxelOrientations(const vector<Vector> &orientations){
830  if(orientations.size()!=skinDim)
831  return false;
832  lock_guard<mutex> lck(poseSem);
833  taxelOri = orientations;
834  return true;
835 }
836 bool Compensator::setTaxelOrientation(unsigned int taxelId, const Vector &orientation){
837  if(taxelId>=skinDim || (orientation.size()!=3 && orientation.size()!=4))
838  return false;
839  lock_guard<mutex> lck(poseSem);
840  taxelOri[taxelId] = orientation.subVector(0,2);
841  if(orientation.size()==4)
842  taxelPoseConfidence[taxelId] = orientation[3];
843  return true;
844 }
845 void Compensator::computeNeighbors(){
846  neighborsXtaxel.clear();
847  neighborsXtaxel.resize(skinDim, list<int>(0));
848  Vector v;
849  double d2 = maxNeighDist*maxNeighDist;
850  for(unsigned int i=0; i<skinDim; i++){
851  for(unsigned int j=i+1; j<skinDim; j++){
852  //if(taxelPos[i][0]!=0.0 || taxelPos[i][1]!=0.0 || taxelPos[i][2]!=0.0){ // if the taxel exists
853  v = taxelPos[i]-taxelPos[j];
854  if( dot(v,v) <= d2){
855  neighborsXtaxel[i].push_back(j);
856  neighborsXtaxel[j].push_back(i);
857  //printf("Taxels %d (%s) and %d (%s) are neighbors\n", i, taxelPos[i].toString().c_str(), j, taxelPos[j].toString().c_str());
858  }
859  //}
860  }
861  }
862 
863  int minNeighbors=skinDim, maxNeighbors=0, ns;
864  for(unsigned int i=0; i<skinDim; i++){
865  //if(taxelPos[i][0]!=0.0 || taxelPos[i][1]!=0.0 || taxelPos[i][2]!=0.0){ // if the taxel exists
866  ns = neighborsXtaxel[i].size();
867  if(ns>maxNeighbors) maxNeighbors = ns;
868  if(ns<minNeighbors) minNeighbors = ns;
869  }
870  stringstream ss;
871  ss<<"Neighbors computed. Min neighbors: "<<minNeighbors<<"; max neighbors: "<<maxNeighbors;
872  sendInfoMsg(ss.str());
873 }
874 void Compensator::updateNeighbors(unsigned int taxelId){
875  Vector v;
876  double d2 = maxNeighDist*maxNeighDist;
877  // remove all the neighbors of the taxel with id=taxelId
878  neighborsXtaxel[taxelId].clear();
879 
880  for(unsigned int i=0; i<skinDim; i++){
881  //if(taxelPos[i][0]!=0.0 || taxelPos[i][1]!=0.0 || taxelPos[i][2]!=0.0){ // if the taxel exists
882  // remove taxelId from the neighbor list (if there is)
883  neighborsXtaxel[i].remove(taxelId);
884  // check whether they are neighbors
885  v = taxelPos[i]-taxelPos[taxelId];
886  if( dot(v,v) <= d2){
887  neighborsXtaxel[i].push_back(taxelId);
888  neighborsXtaxel[taxelId].push_back(i);
889  }
890  }
891 }
892 
893 void Compensator::sendInfoMsg(string msg){
894  yInfo("[%s]: %s", getInputPortName().c_str(), msg.c_str());
895  Bottle& b = infoPort->prepare();
896  b.clear();
897  b.addString(getInputPortName().c_str());
898  b.addString((": " + msg).c_str());
899  infoPort->write(true);
900 }
virtual bool setForce(const yarp::sig::Vector &_F)
Set the contact force.
Definition: dynContact.cpp:101
Class representing a list of external contacts acting on the iCub' skin.
Class representing an external contact acting on the iCub' skin.
Definition: skinContact.h:50
Class that encloses everything relate to a skinPart.
Definition: skinPart.h:146
bool setTaxelPoses(const vector< Vector > &poses)
bool setTaxelPose(unsigned int taxelId, const Vector &pose)
bool setTaxelPosesFromFile(const char *filePath)
vector< Vector > getTaxelOrientations()
vector< Vector > getTaxelPoses()
bool setSmoothFactor(float value)
bool setTaxelOrientations(const vector< Vector > &orientations)
bool setTaxelPosition(unsigned int taxelId, const Vector &position)
double getPoseConfidence(unsigned int taxelId)
bool setAddThreshold(unsigned int thr)
bool setContactCompensationGain(double gain)
bool doesBaselineExceed(unsigned int &taxelIndex, double &baseline, double &initialBaseline)
bool setTaxelPosesFromFileOld(const char *filePath)
void setSkinPart(SkinPart _skinPart)
vector< Vector > getTaxelPositions()
Vector getTaxelPosition(unsigned int taxelId)
bool setTaxelOrientation(unsigned int taxelId, const Vector &orientation)
void setSmoothFilter(bool value)
bool setTaxelPositions(const Vector &positions)
Vector getTaxelPose(unsigned int taxelId)
bool setCompensationGain(double gain)
bool setMaxNeighborDistance(double d)
Vector getTaxelOrientation(unsigned int taxelId)
zeros(2, 2) eye(2
double dot(const yarp::sig::Matrix &A, int colA, const yarp::sig::Matrix &B, int colB)
Returns the dot product between two vectors given in the form: matrix(:,col).
double norm(const yarp::sig::Matrix &M, int col)
Returns the norm of the vector given in the form: matrix(:,col).
int getLinkNum(SkinPart s)
Get the link number associated to the specified skin part.
Definition: common.cpp:34
yarp::sig::Vector vectorFromBottle(const yarp::os::Bottle b, int in, const int size)
Retrieves a vector from a bottle.
Definition: common.cpp:89
BodyPart getBodyPart(SkinPart s)
Get the body part associated to the specified skin part.
Definition: common.cpp:26
const std::string SkinPart_s[]
Definition: common.h:64
@ SKIN_PART_UNKNOWN
Definition: common.h:57
@ BODY_PART_UNKNOWN
Definition: common.h:45
std::string toString(const T &t)
Definition: compensator.h:200
static const double MAX_NEIGHBOR_DISTANCE
const FSC max
Definition: strain.h:48
const FSC min
Definition: strain.h:49
out
Definition: sine.m:8