18#include <yarp/os/Time.h>
19#include <yarp/math/Math.h>
20#include <yarp/math/Rand.h>
27using namespace yarp::os;
28using namespace yarp::sig;
29using namespace yarp::math;
33const double Compensator::BIN_TOUCH = 100.0;
34const double Compensator::BIN_NO_TOUCH = 0.0;
36Compensator::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)
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)
45 this->zeroUpRawData = _zeroUpRawData;
46 _isWorking = init(_name, _robotName, outputPortName, inputPortName);
50 if(tactileSensorDevice){
51 tactileSensorDevice->close();
52 delete tactileSensorDevice;
55 compensatedTactileDataPort.interrupt();
56 compensatedTactileDataPort.close();
59bool Compensator::init(
string name,
string robotName,
string outputPortName,
string inputPortName){
63 if (!compensatedTactileDataPort.open(outputPortName.c_str())) {
64 stringstream msg; msg<<
"Unable to open output port "<< outputPortName;
65 sendInfoMsg(msg.str());
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();
79 tactileSensorDevice =
new PolyDriver(options);
80 if (!tactileSensorDevice->isValid()){
81 sendInfoMsg(
"Device not available.\n");
86 bool ok = tactileSensorDevice->view(tactileSensor);
88 sendInfoMsg(
"Problems acquiring interfaces");
93 localPortName<<
"_temp";
94 if(!inputPort.open(localPortName.str().c_str()))
96 stringstream msg; msg<<
"Unable to open input data port "<< localPortName.str();
97 sendInfoMsg(msg.str());
101 if( !Network::connect(inputPortName.c_str(), localPortName.str().c_str()))
104 msg<<
"Problems trying to connect ports %s and %s."<< inputPortName.c_str()<< localPortName.str().c_str();
105 sendInfoMsg(msg.str());
109 int getChannelsCounter = 0;
110 skinDim = tactileSensor->getChannels();
114 if(++getChannelsCounter==50){
117 sendInfoMsg(
"Error reading the number of channels of the port. Using 192 as default value.");
121 skinDim = tactileSensor->getChannels();
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);
138 list<int> defaultNeighbors(skinDim);
140 for(list<int>::iterator it=defaultNeighbors.begin();it!=defaultNeighbors.end();it++, i++)
142 neighborsXtaxel.resize(skinDim, defaultNeighbors);
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){
154 sendInfoMsg(
"The output of all the taxels is 0. Probably there is a hardware problem.");
163 lock_guard<mutex> lck(touchThresholdSem);
166 if(robotName!=
"icubSim"){
167 tactileSensor->calibrateSensor();
172 saturatedTaxels.resize(0);
173 start_sum.assign(skinDim, 0);
174 skin_empty.assign(skinDim, vector<int>(MAX_SKIN+1, 0));
178 Vector skin_values(skinDim);
179 if(!readInputData(skin_values))
183 for (
unsigned int j=0; j<skinDim; j++) {
184 if (zeroUpRawData==
false)
185 skin_values[j] = MAX_SKIN - skin_values[j];
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]));
190 skin_empty[j][int(skin_values[j])]++;
191 start_sum[j] += int(skin_values[j]);
200 for (
unsigned int i=0; i<skinDim; i++) {
202 baselines[i] = start_sum[i]/ (calibrationRead!=0.0 ? calibrationRead : 1.0);
205 for (
int j=1; j<=MAX_SKIN; j++) {
207 skin_empty[i][j] += skin_empty[i][j-1] ;
212 if( skin_empty[i][MAX_SKIN] < 0.95*calibrationRead )
214 sendInfoMsg(
"Error during calibration. Most readings were out of range.");
219 for (
int j=0; j<=MAX_SKIN; j++)
221 if (skin_empty[i][j] > (calibrationRead*0.95))
224 touchThresholds[i] = (double)j - baselines[i];
233 initialBaselines = baselines;
236 compensatedDataOld = baselines;
239 bool baseline255 =
true, thresholdZero =
true;
240 for(
unsigned int i=0; i<skinDim; i++){
241 if(baselines[i]!=255){
244 if(robotName==
"icubSim" || touchThresholds[i]>1
e-5){
245 thresholdZero =
false;
248 if(baseline255 || thresholdZero){
255 for (
unsigned int i=0; i<skinDim; i++)
256 touchThresholds[i] = max<double>(MIN_TOUCH_THR, touchThresholds[i]);
273 sendInfoMsg(
"Calibration finished");
276bool Compensator::readInputData(Vector& skin_values){
278 if((tmp=inputPort.read(
false))==0){
280 if(readErrorCounter>MAX_READ_ERROR){
282 sendInfoMsg(
"Too many errors in a row. Stopping the compensator.");
287 inputPort.getEnvelope(timestamp);
291 if(skin_values.size() != skinDim){
293 sendInfoMsg(
"Unexpected size of the input array (raw tactile data): "+
toString(skin_values.size()));
294 if(readErrorCounter>MAX_READ_ERROR){
296 sendInfoMsg(
"Too many errors in a row. Stopping the compensator.");
301 readErrorCounter = 0;
339 if(!readInputData(rawData))
342 Vector& compensatedData2Send = compensatedTactileDataPort.prepare();
343 compensatedData2Send.resize(skinDim);
344 compensatedData.resize(skinDim);
347 for(
unsigned int i=0; i<skinDim; i++){
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;
354 touchDetected[i] = (d > touchThresholds[i] + addThreshold);
357 subTouchDetected[i] = (d < -touchThresholds[i] - addThreshold);
361 lock_guard<mutex> lck(smoothFactorSem);
362 d = (1-smoothFactor)*d + smoothFactor*compensatedDataOld(i);
363 compensatedDataOld(i) = d;
365 compensatedDataFilt[i] = d;
370 touchDetectedFilt[i] = (d > touchThresholds[i] + addThreshold);
372 d = ( touchDetectedFilt[i] ? BIN_TOUCH : BIN_NO_TOUCH );
374 compensatedData2Send[i] = max<double>(0.0, d);
377 compensatedTactileDataPort.write();
382 double mean_change = 0, change, gain;
383 unsigned int non_touching_taxels = 0;
386 for(
unsigned int j=0; j<skinDim; j++) {
409 d = compensatedData(j);
410 if(touchDetected[j]){
411 gain = contactCompensationGain*0.02;
413 gain = compensationGain*0.02;
414 non_touching_taxels++;
416 change = gain*d/touchThresholds[j];
417 baselines[j] += change;
418 mean_change += change;
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]);
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()){
454 saturatedTaxels.push_back(i);
455 baseline = baselines[i];
456 initialBaseline = initialBaselines[i];
466 vector<int> contactXtaxel(skinDim, -1);
467 deque<deque<int> > taxelsXcontact;
473 for(
unsigned int i=0; i<skinDim; i++){
474 if(touchDetectedFilt[i] ){
475 list<int> *neighbors = &(neighborsXtaxel[i]);
477 for(list<int>::iterator it=neighbors->begin(); it!=neighbors->end(); it++){
478 neighCont = contactXtaxel[(*it)];
480 if(contactXtaxel[i]<0){
481 contactXtaxel[i] = neighCont;
482 taxelsXcontact[neighCont].push_back(i);
484 }
else if(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;
491 taxelsXcontact[newId].push_back((*it));
493 taxelsXcontact[oldId].clear();
499 if(contactXtaxel[i]<0){
500 contactXtaxel[i] = contactId;
501 taxelsXcontact.resize(contactId+1);
502 taxelsXcontact[contactId].push_back(i);
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;
520 taxelList.resize(activeTaxels);
524 pressure = pressureCoP = pressureNormal = 0.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){
530 CoP += taxelPos[(*tax)] *
out;
533 geoCenter += taxelPos[(*tax)];
535 if(norm(taxelOri[(*tax)])!=0.0){
536 normal += taxelOri[(*tax)] *
out;
537 pressureNormal +=
out;
543 if(taxelsXcontact.size()>1 && activeTaxelsGeo==0)
545 if(pressureCoP!=0.0) CoP /= pressureCoP;
546 if(pressureNormal!=0.0) normal /= pressureNormal;
547 if(activeTaxelsGeo!=0) geoCenter /= activeTaxelsGeo;
548 pressure /= activeTaxels;
551 c.
setForce(-0.05*activeTaxels*pressure*normal);
552 contactList.push_back(c);
560 if(smoothFilter != value){
561 smoothFilter = value;
564 compensatedDataOld = compensatedData;
569 if(value<0.0 || value>1.0)
573 lock_guard<mutex> lck(smoothFactorSem);
574 smoothFactor = value;
594 compensationGain = gain;
601 contactCompensationGain = gain;
614 lock_guard<mutex> lck(touchThresholdSem);
615 return touchThresholds;
619 lock_guard<mutex> lck(smoothFactorSem);
625 lock_guard<mutex> lck(poseSem);
626 Vector res = taxelPos[taxelId];
627 res.push_back(taxelPoseConfidence[taxelId]);
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]);
640 lock_guard<mutex> lck(poseSem);
641 Vector res = taxelOri[taxelId];
642 res.push_back(taxelPoseConfidence[taxelId]);
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]);
655 lock_guard<mutex> lck(poseSem);
656 Vector res = cat(taxelPos[taxelId], taxelOri[taxelId]);
657 res.push_back(taxelPoseConfidence[taxelId]);
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]);
673 lock_guard<mutex> lck(poseSem);
674 return taxelPoseConfidence[taxelId];
678 lock_guard<mutex> lck(poseSem);
679 return taxelPoseConfidence;
686 lock_guard<mutex> lck(poseSem);
692 yarp::os::ResourceFinder rf;
693 rf.setDefaultContext(
"skinGui");
694 rf.setDefaultConfigFile(filePath);
695 rf.configure(0,NULL);
697 yarp::os::Bottle &calibration = rf.findGroup(
"calibration");
698 if (calibration.isNull())
704 lock_guard<mutex> lck(poseSem);
705 int size=calibration.size()-1;
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)
712 if (i<(
int)taxelPos.size())
714 Vector taxelPosNrm(6,0.0);
716 taxelPos[i] = taxelPosNrm.subVector(0,2);
717 taxelOri[i] = taxelPosNrm.subVector(3,5);
719 if(norm(taxelPos[i])>0.0)
720 taxelPoseConfidence[i] = 1.0;
730 posFile.open(filePath);
731 if (!posFile.is_open())
736 while (getline(posFile,posLine)){
737 posLine.erase(posLine.find_last_not_of(
" \n\r\t")+1);
738 if(!posLine.empty())totalLines++;
741 posFile.seekg(0, std::ios::beg);
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);
748 lock_guard<mutex> lck(poseSem);
750 for(
unsigned int i= 0; getline(posFile,posLine); i++) {
751 posLine.erase(posLine.find_last_not_of(
" \n\r\t")+1);
755 istringstream iss(posLine, istringstream::in);
756 for(
unsigned int j = 0; iss >> number; j++ ){
757 if(i<taxelPos.size()){
759 taxelPos[i][j] = strtod(number.c_str(),NULL);
761 taxelOri[i][j-3] = strtod(number.c_str(),NULL);
764 if(norm(taxelPos[i])>0.0)
765 taxelPoseConfidence[i] = 1.0;
772 if(poses.size()!=skinDim)
774 lock_guard<mutex> lck(poseSem);
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];
787 if(taxelId>=skinDim || pose.size()!=6)
789 lock_guard<mutex> lck(poseSem);
791 taxelPos[taxelId] = pose.subVector(0,2);
792 taxelOri[taxelId] = pose.subVector(3,5);
794 taxelPoseConfidence[taxelId] = pose[6];
796 updateNeighbors(taxelId);
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);
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];
820 if(taxelId>=skinDim || (position.size()!=3 && position.size()!=4))
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);
830 if(orientations.size()!=skinDim)
832 lock_guard<mutex> lck(poseSem);
833 taxelOri = orientations;
837 if(taxelId>=skinDim || (orientation.size()!=3 && orientation.size()!=4))
839 lock_guard<mutex> lck(poseSem);
840 taxelOri[taxelId] = orientation.subVector(0,2);
841 if(orientation.size()==4)
842 taxelPoseConfidence[taxelId] = orientation[3];
845void Compensator::computeNeighbors(){
846 neighborsXtaxel.clear();
847 neighborsXtaxel.resize(skinDim, list<int>(0));
849 double d2 = maxNeighDist*maxNeighDist;
850 for(
unsigned int i=0; i<skinDim; i++){
851 for(
unsigned int j=i+1; j<skinDim; j++){
853 v = taxelPos[i]-taxelPos[j];
855 neighborsXtaxel[i].push_back(j);
856 neighborsXtaxel[j].push_back(i);
863 int minNeighbors=skinDim, maxNeighbors=0, ns;
864 for(
unsigned int i=0; i<skinDim; i++){
866 ns = neighborsXtaxel[i].size();
867 if(ns>maxNeighbors) maxNeighbors = ns;
868 if(ns<minNeighbors) minNeighbors = ns;
871 ss<<
"Neighbors computed. Min neighbors: "<<minNeighbors<<
"; max neighbors: "<<maxNeighbors;
872 sendInfoMsg(ss.str());
874void Compensator::updateNeighbors(
unsigned int taxelId){
876 double d2 = maxNeighDist*maxNeighDist;
878 neighborsXtaxel[taxelId].clear();
880 for(
unsigned int i=0; i<skinDim; i++){
883 neighborsXtaxel[i].remove(taxelId);
885 v = taxelPos[i]-taxelPos[taxelId];
887 neighborsXtaxel[i].push_back(taxelId);
888 neighborsXtaxel[taxelId].push_back(i);
893void Compensator::sendInfoMsg(
string msg){
895 Bottle& b = infoPort->prepare();
898 b.addString((
": " + msg).c_str());
899 infoPort->write(
true);
Class that encloses everything relate to a skinPart.
Vector getPoseConfidences()
bool setTaxelPoses(const vector< Vector > &poses)
bool setTaxelPose(unsigned int taxelId, const Vector &pose)
bool setTaxelPosesFromFile(const char *filePath)
vector< Vector > getTaxelOrientations()
Compensator(string name, string robotName, string outputPortName, string inputPortName, BufferedPort< Bottle > *_infoPort, double _compensationGain, double _contactCompensationGain, int addThreshold, float _minBaseline, bool _zeroUpRawData, bool _binarization, bool _smoothFilter, float _smoothFactor, unsigned int _linkId=0)
vector< Vector > getTaxelPoses()
bool setSmoothFactor(float value)
bool setTaxelOrientations(const vector< Vector > &orientations)
bool readRawAndWriteCompensatedData()
bool setTaxelPosition(unsigned int taxelId, const Vector &position)
double getPoseConfidence(unsigned int taxelId)
bool setAddThreshold(unsigned int thr)
string getInputPortName()
bool setContactCompensationGain(double gain)
unsigned int getNumTaxels()
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)
void calibrationDataCollection()
Vector getTaxelPose(unsigned int taxelId)
Vector getTouchThreshold()
skinContactList getContacts()
bool setCompensationGain(double gain)
bool setMaxNeighborDistance(double d)
Vector getTaxelOrientation(unsigned int taxelId)
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).
int getLinkNum(SkinPart s)
Get the link number associated to the specified skin part.
yarp::sig::Vector vectorFromBottle(const yarp::os::Bottle b, int in, const int size)
Retrieves a vector from a bottle.
BodyPart getBodyPart(SkinPart s)
Get the body part associated to the specified skin part.
const std::string SkinPart_s[]
std::string toString(const T &t)
static const double MAX_NEIGHBOR_DISTANCE