iCub-main
compensationThread.cpp
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) 2009 RobotCub Consortium, European Commission FP6 Project IST-004370
4  * Authors: Andrea Del Prete, Alexander Schmitz
5  * email: andrea.delprete@iit.it, alexander.schmitz@iit.it
6  * website: www.robotcub.org
7  * Permission is granted to copy, distribute, and/or modify this program
8  * under the terms of the GNU General Public License, version 2 or any
9  * later version published by the Free Software Foundation.
10  *
11  * A copy of the license can be found at
12  * http://www.robotcub.org/icub/license/gpl.txt
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details
18  */
19 #include <yarp/os/Time.h>
20 #include <yarp/math/Math.h>
21 #include "math.h"
22 #include "memory.h"
24 
25 #define FOR_ALL_PORTS(i) for(unsigned int i=0;i<portNum;i++)
26 
27 using namespace std;
28 using namespace yarp::os;
29 using namespace yarp::sig;
30 using namespace yarp::math;
31 using namespace iCub::skinManager;
32 
33 
34 CompensationThread::CompensationThread(string name, ResourceFinder* rf, string robotName, double _compensationGain, double _contactCompensationGain,
35  int addThreshold, float minBaseline, bool zeroUpRawData,
36  int period, bool binarization, bool smoothFilter, float smoothFactor)
37  :
38  PeriodicThread((double)period/1000.0), moduleName(name), compensationGain(_compensationGain),
39  contactCompensationGain(_contactCompensationGain),
40  ADD_THRESHOLD(addThreshold), robotName(robotName),
41  binarization(binarization), smoothFilter(smoothFilter), smoothFactor(smoothFactor)
42 {
43  this->rf = rf;
44  this->minBaseline = minBaseline;
45  this->zeroUpRawData = zeroUpRawData;
46  initializationFinished = false;
47 }
48 
50 {
51  yTrace("[CompensationThread] threadInit()\n");
52 
53  /* initialize variables and create data-structures if needed */
54  readErrorCounter = 0;
56  calibrationCounter = 0;
57  CAL_SAMPLES = (int)((double)CAL_TIME/getPeriod()); // samples needed for calibration
58 
59  // open the output ports for communicating with the gui
60  string monitorPortName = "/" + moduleName + "/monitor:o"; // output streaming data
61  string infoPortName = "/" + moduleName + "/info:o"; // output occasional data
62  if(!monitorPort.open(monitorPortName.c_str())){
63  stringstream msg; msg<< "Unable to open port " << monitorPortName << endl;
64  sendErrorMsg(msg.str());
65  initializationFinished = true;
66  return false;
67  }
68  if(!infoPort.open(infoPortName.c_str())){
69  stringstream msg; msg<< "Unable to open port " << infoPortName << endl;
70  sendErrorMsg(msg.str());
71  initializationFinished = true;
72  return false;
73  }
74 
75  // open the input and output ports for the skin data
76  if(!rf->check("outputPorts") || !rf->check("inputPorts")){
77  stringstream msg; msg<< "Input ports and/or output ports missing. Closing the module.";
78  sendErrorMsg(msg.str());
79  initializationFinished = true;
80  return false;
81  }
82 
83  Bottle* outputPortList = rf->find("outputPorts").asList();
84  Bottle* inputPortList = rf->find("inputPorts").asList();
85  portNum = outputPortList->size();
86  if(portNum<=0 || portNum!=inputPortList->size()){
87  stringstream msg;
88  msg<< "No input port specified or mismatching number of input and output ports ("
89  << portNum<< " out ports; "<< inputPortList->size()<< " in ports).";
90  sendErrorMsg(msg.str());
91  initializationFinished = true;
92  return false;
93  }
94 
95  compensators.resize(portNum);
96  compWorking.resize(portNum);
97  compEnable.resize(portNum, true);
98  compensatorCounter = portNum;
99  SKIN_DIM = 0;
100  cout<< portNum<< " input ports found in the configuration file\n";
101  FOR_ALL_PORTS(i){
102  string outputPortName = outputPortList->get(i).asString().c_str();
103  string inputPortName = inputPortList->get(i).asString().c_str();
104  // cout << "Input port: "<< inputPortName<< " -> Output port: "<< outputPortName<< endl;
105  yInfo("Input port: %s -> Output port: %s",inputPortName.c_str(),outputPortName.c_str());
106  stringstream name;
107  name<< moduleName<< i;
108  compensators[i] = new Compensator(name.str(), robotName, outputPortName, inputPortName, &infoPort,
109  compensationGain, contactCompensationGain, ADD_THRESHOLD, minBaseline, zeroUpRawData, binarization,
110  smoothFilter, smoothFactor);
111  SKIN_DIM += compensators[i]->getNumTaxels();
112  }
113 
114  // remove the compensators that did not open correctly
115  FOR_ALL_PORTS(i){
116  compWorking[i] = compensators[i]->isWorking();
117  if(!compWorking[i]){
118  stringstream msg;
119  msg<< " Compensator "<< compensators[i]->getInputPortName().c_str()
120  << " did not open correctly. Removing the port.";
121  sendErrorMsg(msg.str());
122  if(compensatorCounter==1){
123  msg.str("");
124  msg<< "No input port left. Stopping the thread.";
125  sendErrorMsg(msg.str());
126  this->threadRelease();
127  initializationFinished = true;
128  return false;
129  }
130  compensatorCounter--;
131  SKIN_DIM -= compensators[i]->getNumTaxels();
132  }
133  }
134 
135 
136  // configure the SKIN_EVENT if the corresponding section exists
137  skinEventsOn = false;
138  Bottle &skinEventsConf = rf->findGroup("SKIN_EVENTS");
139  if(!skinEventsConf.isNull()){
140  yDebug("SKIN_EVENTS section found");
141  string eventPortName = "/" + moduleName + "/skin_events:o"; // output skin events
142  if(!skinEventsPort.open(eventPortName.c_str()))
143  sendErrorMsg("Unable to open port "+eventPortName);
144  else
145  skinEventsOn = true;
146 
147  if(skinEventsConf.check("skinParts")){
148  Bottle* skinPartList = skinEventsConf.find("skinParts").asList();
149  if(skinPartList->size() != portNum){
150  stringstream msg;
151  msg<< "ERROR: the number of skin part ids is not equal to the number of input ports ("
152  << skinPartList->size()<< "!="<< portNum<< "). Skin parts will not be set.";
153  sendDebugMsg(msg.str());
154  }else{
155  FOR_ALL_PORTS(i){
156  // cout<< "Skin part "<< SkinPart_s[skinPartList->get(i).asInt32()]<< endl;
157  yDebug("Skin part %s",SkinPart_s[skinPartList->get(i).asInt32()].c_str());
158  compensators[i]->setSkinPart((SkinPart)skinPartList->get(i).asInt32());
159  }
160  }
161  }
162 
163  if(skinEventsConf.check("taxelPositionFiles")){
164  Bottle *taxelPosFiles = skinEventsConf.find("taxelPositionFiles").asList();
165  if(portNum!=taxelPosFiles->size()){
166  stringstream msg;
167  msg<< "Mismatching number of taxel position files and input ports ("
168  <<portNum<< " in ports; "<< taxelPosFiles->size()<< " taxel position files). ";
169  msg<< "Taxel positions will not be set.";
170  msg<< ". Taxel position file list: "<< taxelPosFiles->toString().c_str();
171  sendDebugMsg(msg.str());
172  }
173  else{
174  maxNeighDist = skinEventsConf.check("maxNeighborDist", Value(MAX_NEIGHBOR_DISTANCE)).asFloat64();
175 
176  yInfo("Max neighbor distance: %f m\n", maxNeighDist);
177  FOR_ALL_PORTS(i){
178  if(compWorking[i]){
179  string taxelPosFile = taxelPosFiles->get(i).asString().c_str();
180  string filePath(rf->findFile(taxelPosFile.c_str()));
181  compensators[i]->setMaxNeighborDistance(maxNeighDist);
182  compensators[i]->setTaxelPosesFromFile(filePath.c_str());
183  }
184  }
185  }
186  }
187  }
188  if(skinEventsOn)
189  sendDebugMsg("Skin events ENABLED.");
190  else
191  sendDebugMsg("Skin events DISABLED.");
192 
193  initializationFinished = true;
194  return true;
195 }
196 
198  lock_guard<mutex> lck(stateSem);
199  if(state != calibration){
200  state = calibration;
201  calibrationCounter = 0;
202  }
203 }
204 
206  stateSem.lock();
207 
208  if( state == compensation){
209  // It reads the raw data, computes the difference between the read values and the baseline
210  // and outputs these values
211  FOR_ALL_PORTS(i){
212  if(compWorking[i]){
213  if(compensators[i]->readRawAndWriteCompensatedData()){
214  //If the read succeeded, update the baseline
215  compensators[i]->updateBaseline();
216  }
217  }
218  }
219 
220  if(skinEventsOn){
221  sendSkinEvents();
222  }
223  }
224  else if(state == calibration){
225  FOR_ALL_PORTS(i){
226  if(compWorking[i]){
227  if(calibrationCounter==0)
228  compensators[i]->calibrationInit();
229 
230  compensators[i]->calibrationDataCollection();
231 
232  if(calibrationCounter==CAL_SAMPLES){
233  compensators[i]->calibrationFinish();
235  }
236  }
237  }
238  calibrationCounter++;
239  }
240  else{
241  stateSem.unlock();
242  sendDebugMsg("[ERROR] Unknown state in CompensationThread. Suspending the thread.\n");
243  this->suspend();
244  return;
245  }
246  stateSem.unlock();
247  sendMonitorData();
248  checkErrors();
249 }
250 
251 void CompensationThread::sendSkinEvents(){
252  skinContactList &skinEvents = skinEventsPort.prepare();
253  skinEvents.clear();
254 
255  skinContactList temp;
256  Stamp timestamp;
257  FOR_ALL_PORTS(i){
258  if(compWorking[i] && compEnable[i]){
259  temp = compensators[i]->getContacts();
260  timestamp = compensators[i]->getTimestamp();
261  skinEvents.insert(skinEvents.end(), temp.begin(), temp.end());
262  }
263  }
264 #ifdef _DEBUG
265  if(skinEvents.size()>0)
266  printf("SkinContacts size: %d\n", skinEvents.size());
267  /*printf("SkinContacts:\n%s\n", skinEvents.toString().c_str());*/
268 #endif
269 
270  skinEventsPort.setEnvelope(timestamp);
271  skinEventsPort.write(); // send something anyway (if there is no contact the bottle is empty)
272 }
273 
274 void CompensationThread::checkErrors(){
275  FOR_ALL_PORTS(i){
276  if(compWorking[i]){
277  compWorking[i] = compensators[i]->isWorking();
278  if(!compWorking[i]){ // read failed too many times in a row, remove the port
279  if(compensatorCounter==1){
280  fprintf(stderr, "No input port left. Stopping the compensation thread\n");
281  this->threadRelease();
282  this->suspend();
283  return;
284  }
285 
286  compensatorCounter--;
287  SKIN_DIM -= compensators[i]->getNumTaxels(); // remove the taxel from the total count
288  }
289  }
290  }
291 
292  unsigned int taxInd, compInd;
293  double baseline, initialBaseline;
294  if(doesBaselineExceed(compInd, taxInd, baseline, initialBaseline)){
295  stringstream msg;
296  msg<< "Baseline of the taxel "<< taxInd<< " of port "<< compensators[compInd]->getInputPortName()
297  << " saturated (current baseline="<< baseline<< "; initial baseline="<< initialBaseline<<
298  ")! A skin calibration is suggested.";
299  sendDebugMsg(msg.str());
300  }
301 }
302 
303 bool CompensationThread::doesBaselineExceed(unsigned int &compInd, unsigned int &taxInd, double &baseline, double &initialBaseline){
304  stateSem.lock();
305  CompensationThreadState currentState = state;
306  stateSem.unlock();
307  if(currentState==compensation){
308  FOR_ALL_PORTS(i){
309  if(compWorking[i] && compensators[i]->doesBaselineExceed(taxInd, baseline, initialBaseline)){
310  compInd = i;
311  return true;
312  }
313  }
314  }
315  return false;
316 }
317 
319 {
320  FOR_ALL_PORTS(i){
321  delete compensators[i];
322  }
323  portNum = 0;
324  state = compensation; // to prevent the GUI from looping calling isCalibrating() on the thread
325 
326  monitorPort.interrupt();
327  infoPort.interrupt();
328  monitorPort.close();
329  infoPort.close();
330 }
331 
332 // send the data on the monitor port
333 void CompensationThread::sendMonitorData(){
334  // send the monitor data (if there is at least a connection)
335  if(monitorPort.getOutputCount()>0){
336  int originalSkinDim = 0;
337  FOR_ALL_PORTS(i)
338  originalSkinDim += compensators[i]->getNumTaxels();
339 
340  Vector &b = monitorPort.prepare();
341  b.clear();
342  b.resize(1+ 2*originalSkinDim);
343  b[0] = 1.0/getEstimatedPeriod(); // thread frequency
344 
345  stateSem.lock();
346  if(state==compensation){ // during calibration don't send this data
347  // for each taxel add how much the baseline has changed so far (i.e. the drift)
348  int index = 1;
349  FOR_ALL_PORTS(i){
350  if(compWorking[i]){
351  b.setSubvector(index, compensators[i]->getCompensation());
352  }
353  index += compensators[i]->getNumTaxels();
354  }
355  FOR_ALL_PORTS(i){
356  if(compWorking[i]){
357  b.setSubvector(index, compensators[i]->getRawData());
358  }
359  index += compensators[i]->getNumTaxels();
360  }
361  }
362  stateSem.unlock();
363  //printf("Writing %d data on monitor port\n", b.size());
364  monitorPort.write();
365  }
366 }
367 
368 void CompensationThread::sendDebugMsg(string msg){
369  //printf("\n");
370  yDebug("[CompensationThread] %s", msg.c_str());
371  Bottle& b = infoPort.prepare();
372  b.clear();
373  b.addString(msg.c_str());
374  infoPort.write(true);
375 }
376 
377 void CompensationThread::sendErrorMsg(string msg){
378  //printf("\n");
379  yError("[CompensationThread] %s", msg.c_str());
380  Bottle& b = infoPort.prepare();
381  b.clear();
382  b.addString(msg.c_str());
383  infoPort.write(true);
384 }
385 
387  Bottle res;
388  if(initializationFinished){ // check whether the thread has been initialized
389  Bottle& nameB = res.addList();
390  nameB.addString("Name: ");
391  nameB.addString(moduleName.c_str());
392  Bottle& robotB = res.addList();
393  robotB.addString("Robot Name: ");
394  robotB.addString(robotName.c_str());
395  Bottle& portB = res.addList();
396  string compName;
397  FOR_ALL_PORTS(i){
398  compName = compensators[i]->getInputPortName().c_str();
399  if(!compWorking[i])
400  compName = compName + " (NOT WORKING)";
401  portB.addString(compName.c_str());
402  portB.addInt32(compensators[i]->getNumTaxels());
403  }
404  }else{
405  res.addString("Module initialization has not been completed yet.");
406  }
407  return res;
408 }
409 
411  binarization = value;
412  FOR_ALL_PORTS(i){
413  compensators[i]->setBinarization(value);
414  }
415 }
417  if(smoothFilter != value){
418  lock_guard<mutex> lck(stateSem);
419  smoothFilter = value;
420  FOR_ALL_PORTS(i){
421  compensators[i]->setSmoothFilter(value);
422  }
423  }
424 }
426  if(value<0 || value>1)
427  return false;
428  if(value==1)
429  value = 0.99f; // otherwise with 1 the values don't update
430  smoothFactor = value;
431  FOR_ALL_PORTS(i){
432  compensators[i]->setSmoothFactor(value);
433  }
434  return true;
435 }
436 bool CompensationThread::setAddThreshold(unsigned int thr){
437  bool res = true;
438  FOR_ALL_PORTS(i){
439  res = res && compensators[i]->setAddThreshold(thr);
440  }
441  if(res)
442  ADD_THRESHOLD = thr;
443  return res;
444 }
445 
447  bool res = true;
448  FOR_ALL_PORTS(i){
449  res = res && compensators[i]->setCompensationGain(gain);
450  }
451  if(res)
452  compensationGain = gain;
453  return res;
454 }
455 
457  bool res = true;
458  FOR_ALL_PORTS(i){
459  res = res && compensators[i]->setContactCompensationGain(gain);
460  }
461  if(res)
462  contactCompensationGain = gain;
463  return res;
464 }
466  bool res = true;
467  FOR_ALL_PORTS(i){
468  res = res && compensators[i]->setMaxNeighborDistance(dist);
469  }
470  if(res)
471  maxNeighDist = dist;
472  return res;
473 }
474 bool CompensationThread::setTaxelPosition(SkinPart sp, unsigned int taxelId, const Vector &position){
475  FOR_ALL_PORTS(i){
476  if(compensators[i]->getSkinPart()==sp){
477  return compensators[i]->setTaxelPosition(taxelId, position);
478  }
479  }
480  return false;
481 }
482 bool CompensationThread::setTaxelPositions(SkinPart sp, const Vector &positions){
483  FOR_ALL_PORTS(i){
484  if(compensators[i]->getSkinPart()==sp){
485  return compensators[i]->setTaxelPositions(positions);
486  }
487  }
488  return false;
489 }
490 bool CompensationThread::setTaxelOrientation(SkinPart sp, unsigned int taxelId, const Vector &orientation){
491  FOR_ALL_PORTS(i){
492  if(compensators[i]->getSkinPart()==sp){
493  return compensators[i]->setTaxelOrientation(taxelId, orientation);
494  }
495  }
496  return false;
497 }
498 bool CompensationThread::setTaxelOrientations(SkinPart sp, const vector<Vector> &orientations){
499  FOR_ALL_PORTS(i){
500  if(compensators[i]->getSkinPart()==sp){
501  return compensators[i]->setTaxelOrientations(orientations);
502  }
503  }
504  return false;
505 }
506 bool CompensationThread::setTaxelPose(SkinPart sp, unsigned int taxelId, const Vector &pose){
507  FOR_ALL_PORTS(i){
508  if(compensators[i]->getSkinPart()==sp){
509  return compensators[i]->setTaxelPose(taxelId, pose);
510  }
511  }
512  return false;
513 }
514 bool CompensationThread::setTaxelPoses(SkinPart sp, const vector<Vector> &poses){
515  FOR_ALL_PORTS(i){
516  if(compensators[i]->getSkinPart()==sp){
517  return compensators[i]->setTaxelPoses(poses);
518  }
519  }
520  return false;
521 }
522 bool CompensationThread::setTaxelPoses(SkinPart sp, const Vector &poses){
523  FOR_ALL_PORTS(i){
524  if(compensators[i]->getSkinPart()==sp){
525  unsigned int numTax = compensators[i]->getNumTaxels();
526  if(poses.size()==6*numTax){
527  //return false;
528  vector<Vector> p(numTax);
529  for(unsigned int j=0; j<numTax; j++){
530  p[j] = poses.subVector(6*j, 6*j+5);
531  }
532  return compensators[i]->setTaxelPoses(p);
533  }
534  else if(poses.size()==7*numTax){ //check if there is also a confidence value of the estimation
535  vector<Vector> p(numTax);
536  for(unsigned int j=0; j<numTax; j++){
537  p[j] = poses.subVector(7*j, 7*j+6);
538  }
539  return compensators[i]->setTaxelPoses(p);
540  }
541  else
542  return false;
543  }
544  }
545  return false;
546 }
547 
548 //************************************************************************************************************
549 //************************************************************************************************************
550 // GET METHODS
551 //************************************************************************************************************
552 //************************************************************************************************************
554  Vector res(SKIN_DIM);
555  int currentDim=0;
556  FOR_ALL_PORTS(i){
557  if(compWorking[i]){
558  Vector temp = compensators[i]->getTouchThreshold();
559  memcpy(res.data()+currentDim, temp.data(), temp.size()*sizeof(double));
560  currentDim += temp.size();
561  }
562  }
563  return res;
564 }
565 
567  return ADD_THRESHOLD;
568 }
570  return compensationGain;
571 }
573  return contactCompensationGain;
574 }
576  return binarization;
577 }
579  return smoothFilter;
580 }
582  lock_guard<mutex> lck(stateSem);
583  bool res = state==calibration;
584  return res;
585 }
587  return smoothFactor;
588 }
589 Vector CompensationThread::getTaxelPosition(SkinPart sp, unsigned int taxelId){
590  FOR_ALL_PORTS(i){
591  if(compensators[i]->getSkinPart()==sp){
592  return compensators[i]->getTaxelPosition(taxelId);
593  }
594  }
595  return zeros(3);
596 }
598  if(sp==SKIN_PART_ALL){
599  vector<Vector> res;
600  FOR_ALL_PORTS(i){
601  vector<Vector> temp = compensators[i]->getTaxelPositions();
602  res.insert(res.end(), temp.begin(), temp.end());
603  }
604  return res;
605  }
606  FOR_ALL_PORTS(i){
607  if(compensators[i]->getSkinPart()==sp){
608  return compensators[i]->getTaxelPositions();
609  }
610  }
611  return vector<Vector>();
612 }
613 Vector CompensationThread::getTaxelOrientation(SkinPart sp, unsigned int taxelId){
614  FOR_ALL_PORTS(i){
615  if(compensators[i]->getSkinPart()==sp){
616  return compensators[i]->getTaxelOrientation(taxelId);
617  }
618  }
619  return zeros(3);
620 }
622  if(sp==SKIN_PART_ALL){
623  vector<Vector> res;
624  FOR_ALL_PORTS(i){
625  vector<Vector> temp = compensators[i]->getTaxelOrientations();
626  res.insert(res.end(), temp.begin(), temp.end());
627  }
628  return res;
629  }
630  FOR_ALL_PORTS(i){
631  if(compensators[i]->getSkinPart()==sp){
632  return compensators[i]->getTaxelOrientations();
633  }
634  }
635  return vector<Vector>();
636 }
637 Vector CompensationThread::getTaxelPose(SkinPart sp, unsigned int taxelId){
638  FOR_ALL_PORTS(i){
639  if(compensators[i]->getSkinPart()==sp){
640  return compensators[i]->getTaxelPose(taxelId);
641  }
642  }
643  return zeros(3);
644 }
646  if(sp==SKIN_PART_ALL){
647  vector<Vector> res;
648  FOR_ALL_PORTS(i){
649  vector<Vector> temp = compensators[i]->getTaxelPoses();
650  res.insert(res.end(), temp.begin(), temp.end());
651  }
652  return res;
653  }
654  FOR_ALL_PORTS(i){
655  if(compensators[i]->getSkinPart()==sp){
656  return compensators[i]->getTaxelPoses();
657  }
658  }
659  return vector<Vector>();
660 }
661 
662 double CompensationThread::getPoseConfidence(SkinPart sp, unsigned int taxelId){
663  FOR_ALL_PORTS(i){
664  if(compensators[i]->getSkinPart()==sp){
665  return compensators[i]->getPoseConfidence(taxelId);
666  }
667  }
668  return 0.0;
669 }
670 
672  FOR_ALL_PORTS(i){
673  if(compensators[i]->getSkinPart()==sp){
674  return compensators[i]->getPoseConfidences();
675  }
676  }
677  return zeros(0);
678 }
679 
681  vector<SkinPart> res(compensators.size());
682  FOR_ALL_PORTS(i)
683  res[i] = compensators[i]->getSkinPart();
684  return res;
685 }
687  FOR_ALL_PORTS(i)
688  if(compensators[i]->getSkinPart()==sp){
689  compEnable[i] = true;
690  return true;
691  }
692  return false;
693 }
695  FOR_ALL_PORTS(i)
696  if(compensators[i]->getSkinPart()==sp){
697  compEnable[i] = false;
698  return true;
699  }
700  return false;
701 }
703  FOR_ALL_PORTS(i)
704  if(compensators[i]->getSkinPart()==sp)
705  return compEnable[i];
706  return false;
707 }
Class representing a list of external contacts acting on the iCub' skin.
bool setTaxelPosition(SkinPart sp, unsigned int taxelId, const Vector &position)
Vector getTaxelPose(SkinPart sp, unsigned int taxelId)
Vector getTaxelOrientation(SkinPart sp, unsigned int taxelId)
bool setTaxelPose(SkinPart sp, unsigned int taxelId, const Vector &pose)
double getPoseConfidence(SkinPart sp, unsigned int taxelId)
vector< Vector > getTaxelPoses(SkinPart sp=SKIN_PART_ALL)
bool setTaxelPositions(SkinPart sp, const Vector &positions)
bool setTaxelPoses(SkinPart sp, const vector< Vector > &poses)
Vector getTaxelPosition(SkinPart sp, unsigned int taxelId)
bool setTaxelOrientation(SkinPart sp, unsigned int taxelId, const Vector &orientation)
bool setTaxelOrientations(SkinPart sp, const vector< Vector > &orientations)
vector< Vector > getTaxelPositions(SkinPart sp=SKIN_PART_ALL)
vector< Vector > getTaxelOrientations(SkinPart sp=SKIN_PART_ALL)
#define FOR_ALL_PORTS(i)
zeros(2, 2) eye(2
const std::string SkinPart_s[]
Definition: common.h:64
static const double MAX_NEIGHBOR_DISTANCE
fprintf(fid,'\n')