10#include <yarp/os/Time.h>
11#include <yarp/dev/PolyDriver.h>
16#include <yarp/os/LogStream.h>
18using namespace yarp::os;
30static bool extractGroup(Bottle &input, Bottle &
out,
const std::string &key1,
const std::string &txt,
int size)
33 Bottle &tmp=input.findGroup(key1.c_str(), txt.c_str());
36 yError () << key1.c_str() <<
" not found\n";
42 yError () << key1.c_str() <<
" incorrect number of entries in board.";
55 original_max_pwm(NULL),
56 limited_max_pwm(NULL),
67 skipCalibration(false),
70 totJointsToCalibrate(0)
84 p.fromString(config.toString());
86 if (
p.check(
"GENERAL") ==
false)
88 yError() <<
"Parametric calibrator: missing [GENERAL] section";
92 if (
p.findGroup(
"GENERAL").check(
"deviceName"))
94 deviceName =
p.findGroup(
"GENERAL").find(
"deviceName").asString();
98 yError() <<
"Parametric calibrator: missing deviceName parameter";
103 if (config.findGroup(
"GENERAL").find(
"verbose").asInt32())
105 str = config.toString().c_str();
106 yTrace() << deviceName.c_str() << str;
110 Value val_clearHwFault = config.findGroup(
"GENERAL").find(
"clearHwFaultBeforeCalibration");
111 if (val_clearHwFault.isNull())
113 clearHwFault =
false;
117 if (!val_clearHwFault.isBool())
119 yError() << deviceName.c_str() <<
": clearHwFaultBeforeCalibration bool param is different from accepted values (true / false). Assuming false";
120 clearHwFault =
false;
124 clearHwFault = val_clearHwFault.asBool();
126 yInfo() << deviceName.c_str() <<
": clearHwFaultBeforeCalibration option enabled\n";
131 skipCalibration = config.findGroup(
"GENERAL").find(
"skipCalibration").asBool();
132 skipCalibration = !!skipCalibration;
135 yWarning() << deviceName <<
": skipping calibration!! This option was set in general.xml file.";
136 yWarning() << deviceName <<
": BE CAREFUL USING THE ROBOT IN THIS CONFIGURATION! See 'skipCalibration' param in config file";
140 if (
p.findGroup(
"GENERAL").check(
"joints"))
142 nj =
p.findGroup(
"GENERAL").find(
"joints").asInt32();
144 else if (
p.findGroup(
"GENERAL").check(
"Joints"))
147 nj =
p.findGroup(
"GENERAL").find(
"Joints").asInt32();
151 yError() << deviceName.c_str() <<
": missing joints parameter";
155 type =
new unsigned char[nj];
156 param1 =
new double[nj];
157 param2 =
new double[nj];
158 param3 =
new double[nj];
159 maxPWM =
new int[nj];
161 zeroPos =
new double[nj];
162 zeroVel =
new double[nj];
163 currPos =
new double[nj];
164 currVel =
new double[nj];
165 homePos =
new double[nj];
166 homeVel =
new double[nj];
167 zeroPosThreshold =
new double[nj];
171 Bottle& xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"calibration1");
172 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of Calibration1 params " << xtmp.size() <<
" " << nj;
return false; }
173 for (i = 1; i < xtmp.size(); i++) param1[i - 1] = xtmp.get(i).asFloat64();
175 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"calibration2");
176 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of Calibration2 params";
return false; }
177 for (i = 1; i < xtmp.size(); i++) param2[i - 1] = xtmp.get(i).asFloat64();
179 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"calibration3");
180 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of Calibration3 params";
return false; }
181 for (i = 1; i < xtmp.size(); i++) param3[i - 1] = xtmp.get(i).asFloat64();
183 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"calibrationType");
184 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of Calibration3 params";
return false; }
185 for (i = 1; i < xtmp.size(); i++) type[i - 1] = (
unsigned char)xtmp.get(i).asFloat64();
187 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"startupPosition");
188 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of startupPosition params";
return false; }
189 for (i = 1; i < xtmp.size(); i++) zeroPos[i - 1] = xtmp.get(i).asFloat64();
191 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"startupVelocity");
192 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of startupVelocity params";
return false; }
193 for (i = 1; i < xtmp.size(); i++) zeroVel[i - 1] = xtmp.get(i).asFloat64();
195 xtmp =
p.findGroup(
"HOME").findGroup(
"positionHome");
196 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of PositionHome params";
return false; }
197 for (i = 1; i < xtmp.size(); i++) homePos[i - 1] = xtmp.get(i).asFloat64();
199 xtmp =
p.findGroup(
"HOME").findGroup(
"velocityHome");
200 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of VelocityHome params";
return false; }
201 for (i = 1; i < xtmp.size(); i++) homeVel[i - 1] = xtmp.get(i).asFloat64();
203 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"startupMaxPwm");
204 if (xtmp.size() - 1 != nj) { yError() << deviceName <<
": invalid number of startupMaxPwm params";
return false; }
205 for (i = 1; i < xtmp.size(); i++) maxPWM[i - 1] = xtmp.get(i).asInt32();
207 xtmp =
p.findGroup(
"CALIBRATION").findGroup(
"startupPosThreshold");
208 if (xtmp.size()-1!=nj) {yError() << deviceName <<
": invalid number of startupPosThreshold params";
return false;}
209 for (i = 1; i < xtmp.size(); i++) zeroPosThreshold[i-1] = xtmp.get(i).asFloat64();
211 calibJointsString =
p.findGroup(
"CALIB_ORDER");
212 int calib_order_size = calibJointsString.size();
213 if (calib_order_size <= 1) {yError() << deviceName <<
": invalid number CALIB_ORDER params";
return false;}
217 for(
int i=1; i<calibJointsString.size(); i++)
221 set= calibJointsString.get(i).asList();
223 for(
int j=0; j<set->size(); j++)
225 tmp.push_back(set->get(j).asInt32() );
227 joints.push_back(tmp);
239 if (param1 != NULL) {
243 if (param2 != NULL) {
247 if (param3 != NULL) {
252 if (maxPWM != NULL) {
256 if (original_max_pwm != NULL) {
257 delete[] original_max_pwm;
258 original_max_pwm = NULL;
260 if (limited_max_pwm != NULL) {
261 delete[] limited_max_pwm;
262 limited_max_pwm = NULL;
265 if (currPos != NULL) {
269 if (currVel != NULL) {
274 if (zeroPos != NULL) {
278 if (zeroVel != NULL) {
283 if (homePos != NULL) {
287 if (homeVel != NULL) {
295bool parametricCalibrator::calibrate(DeviceDriver *device)
297 yInfo() << deviceName <<
": starting calibration";
304 yError() << deviceName <<
": invalid device driver";
308 yarp::dev::PolyDriver *
p =
dynamic_cast<yarp::dev::PolyDriver *
>(device);
316 p->view(iControlMode);
325 yWarning() << deviceName <<
": using parametricCalibrator on an old iCubInterface system. Upgrade to robotInterface is recommended.";
326 device->view(iCalibrate);
327 device->view(iEncoders);
328 device->view(iPosition);
330 device->view(iControlMode);
334 if (!(iCalibrate && iEncoders && iPosition && iPids && iControlMode)) {
335 yError() << deviceName <<
": interface not found" << iCalibrate << iPosition << iPids << iControlMode;
342bool parametricCalibrator::calibrate()
344 int setOfJoint_idx = 0;
345 totJointsToCalibrate = 0;
348 if (dev2calibrate==0)
350 yError() << deviceName <<
": not able to find a valid device to calibrate";
354 if ( !iEncoders->getAxes(&n_joints))
356 yError() << deviceName <<
": error getting number of axes" ;
360 std::list<int> currentSetList;
361 std::list<std::list<int> >::iterator Bit=joints.begin();
362 std::list<std::list<int> >::iterator Bend=joints.end();
367 currentSetList.clear();
368 currentSetList = (*Bit);
369 std::list<int>::iterator lit = currentSetList.begin();
370 std::list<int>::iterator lend = currentSetList.end();
371 totJointsToCalibrate += currentSetList.size();
375 calibJoints.push_back(*lit);
382 for (
int i=0; i<totJointsToCalibrate; i++)
387 yDebug() << deviceName <<
": Joints calibration order:" << calibJointsString.toString();
389 if (totJointsToCalibrate > n_joints)
391 yError() << deviceName <<
": too much axis to calibrate for this part..." << totJointsToCalibrate <<
" bigger than "<< n_joints;
395 if (totJointsToCalibrate < n_joints)
397 yWarning() << deviceName <<
" is calibrating only a subset of the robot part. Calibrating " << totJointsToCalibrate <<
" over a total of " << n_joints;
400 original_max_pwm =
new double[n_joints];
401 limited_max_pwm =
new double[n_joints];
404 yWarning() << deviceName <<
": skipCalibration flag is on! Setting safe pid but skipping calibration.";
407 std::list<int>::iterator lit;
408 while( (Bit != Bend) && (!abortCalib) )
411 currentSetList.clear();
412 currentSetList = (*Bit);
415 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
417 yWarning() << deviceName <<
"lit is " << *lit;
418 if ( ((*lit) <0) || ((*lit) >= n_joints) )
420 yError() << deviceName <<
": asked to calibrate joint" << (*lit) <<
", which is negative OR bigger than the number of axes for this part ("<< n_joints <<
")";
425 if(!iAmp->getPWMLimit((*lit), &original_max_pwm[(*lit)]) )
427 yError() << deviceName <<
": getPWMLimit joint " << (*lit) <<
"failed... aborting calibration";
432 limited_max_pwm[(*lit)] = original_max_pwm[(*lit)];
434 if (maxPWM[(*lit)]==0)
436 yDebug() << deviceName <<
": skipping maxPwm=0 of joint " << (*lit);
437 iAmp->setPWMLimit((*lit), original_max_pwm[(*lit)]);
441 if (maxPWM[(*lit)]<limited_max_pwm[(*lit)])
443 limited_max_pwm[(*lit)] = maxPWM[(*lit)];
444 iAmp->setPWMLimit((*lit), limited_max_pwm[(*lit)]);
448 yDebug() << deviceName <<
": joint " << (*lit) <<
" has max_output already limited to a safe value: " << limited_max_pwm[(*lit)];
463 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
469 yDebug() <<
"In calibration " << deviceName <<
": enabling joint " << *lit <<
" to test hardware limit";
470 iControlMode->setControlMode((*lit), VOCAB_CM_POSITION);
482 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
486 calibrateJoint((*lit));
491 for(lit = currentSetList.begin(); lit != currentSetList.end(); lit++)
493 iEncoders->getEncoder((*lit), &currPos[(*lit)]);
494 yDebug() << deviceName <<
": set" << setOfJoint_idx <<
"j" << (*lit) <<
": Calibrating... enc values AFTER calib: " << currPos[(*lit)];
504 if(checkCalibrateJointEnded((*Bit)) )
506 yDebug() << deviceName <<
": set" << setOfJoint_idx <<
": Calibration ended, going to zero!\n";
510 yError() << deviceName <<
": set" << setOfJoint_idx <<
": Calibration went wrong! Disabling axes and keeping safe pid limit\n";
512 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
514 iControlMode->setControlMode((*lit),VOCAB_CM_IDLE);
521 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
529 iControlMode->setControlMode((*lit), VOCAB_CM_POSITION);
541 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
555 bool goneToZero =
true;
556 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
558 goneToZero &= checkGoneToZeroThreshold(*lit);
569 yDebug() << deviceName <<
": set" << setOfJoint_idx <<
": Reached zero position!\n";
570 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
572 iAmp->setPWMLimit((*lit),original_max_pwm[(*lit)]);
577 yError() << deviceName <<
": set" << setOfJoint_idx <<
": some axis got timeout while reaching zero position... disabling this set of axes\n";
578 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
580 iControlMode->setControlMode((*lit),VOCAB_CM_IDLE);
590 yError() << deviceName <<
": calibration has been aborted!I'm going to disable all joints..." ;
591 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
593 iControlMode->setControlMode(*lit, VOCAB_CM_IDLE);
597 std::lock_guard<std::mutex> lck(calibMutex);
602bool parametricCalibrator::calibrateJoint(
int j)
604 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
606 yError(
"%s cannot perform 'calibration' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
609 yInfo() << deviceName <<
": Calling calibrateJoint on joint "<< j <<
" with params: " << type[j] << param1[j] << param2[j] << param3[j];
610 return iCalibrate->calibrateAxisWithParams(j, type[j], param1[j], param2[j], param3[j]);
613bool parametricCalibrator::checkCalibrateJointEnded(std::list<int> set)
616 bool calibration_ok =
false;
618 std::list<int>::iterator lit;
619 std::list<int>::iterator lend;
624 calibration_ok =
true;
631 yWarning() << deviceName <<
": calibration aborted\n";
636 if( !(calibration_ok &= iCalibrate->calibrationDone((*lit))) )
645 yError() << deviceName <<
":Timeout while calibrating " << (*lit) <<
"\n";
647 yDebug() << deviceName <<
": calib joint ended";
649 return calibration_ok;
652bool parametricCalibrator::checkHwFault(
int j)
654 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
656 yError(
"%s cannot perform 'check hw fault' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
661 iControlMode->getControlMode(j,&mode);
662 if (mode == VOCAB_CM_HW_FAULT)
666 iControlMode->setControlMode(j,VOCAB_CM_FORCE_IDLE);
667 yWarning() << deviceName <<
": detected an hardware fault on joint " << j <<
". An attempt will be made to clear it.";
669 iControlMode->getControlMode(j,&mode);
670 if (mode == VOCAB_CM_HW_FAULT)
672 yError() << deviceName <<
": unable to clear the hardware fault detected on joint " << j <<
" before starting the calibration procedure!";
675 else if (mode == VOCAB_CM_IDLE)
677 yWarning() << deviceName <<
": hardware fault on joint " << j <<
" successfully cleared.";
682 yError() << deviceName <<
": an unknown error occured while trying the hardware fault on joint " << j ;
688 yError() << deviceName <<
": detected an hardware fault on joint " << j <<
" before starting the calibration procedure!";
695bool parametricCalibrator::goToZero(
int j)
697 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
699 yError(
"%s cannot perform 'go to zero' operation because joint number %d is out of range [%s]!!", deviceName.c_str(), j, calibJointsString.toString().c_str());
704 if (abortCalib)
return true;
705 yDebug() << deviceName <<
": Sending positionMove to joint" << j <<
" (desired pos: " << zeroPos[j] <<
"desired speed: " << zeroVel[j] <<
" )";
706 ret = iPosition->setRefSpeed(j, zeroVel[j]);
707 ret &= iPosition->positionMove(j, zeroPos[j]);
711bool parametricCalibrator::checkGoneToZeroThreshold(
int j)
713 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
715 yError(
"%s cannot perform 'check gone to zero' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
719 if (skipCalibration)
return false;
722 bool finished =
false;
730 double start_time = yarp::os::Time::now();
731 while ( (!finished) && (!abortCalib))
733 iEncoders->getEncoder(j, &angj);
734 iPosition->checkMotionDone(j, &
done);
735 iControlMode->getControlMode(j, &mode);
736 iPids->getPidOutput(VOCAB_PIDTYPE_POSITION, j, &output);
738 delta = fabs(angj-zeroPos[j]);
739 yDebug(
"%s: checkGoneToZeroThreshold: joint: %d curr: %.3f des: %.3f -> delta: %.3f threshold: %.3f output: %.3f mode: %s" ,deviceName.c_str(),j,angj, zeroPos[j],delta, zeroPosThreshold[j], output, yarp::os::Vocab32::decode(mode).c_str());
741 if (delta < zeroPosThreshold[j] &&
done)
743 yDebug(
"%s: checkGoneToZeroThreshold: joint: %d completed with delta: %.3f over: %.3f" ,deviceName.c_str(),j,delta, zeroPosThreshold[j]);
749 yError() << deviceName <<
": checkGoneToZeroThreshold: joint " << j <<
" Timeout while going to zero!";
752 if (mode == VOCAB_CM_IDLE)
754 yError() << deviceName <<
": checkGoneToZeroThreshold: joint " << j <<
" is idle, skipping!";
757 if (mode == VOCAB_CM_HW_FAULT)
759 yError() << deviceName <<
": checkGoneToZeroThreshold: hardware fault on joint " << j <<
", skipping!";
764 yWarning() << deviceName <<
": checkGoneToZeroThreshold: joint " << j <<
" Aborting wait while going to zero!\n";
781 yWarning() << deviceName <<
": Calling park without calibration... skipping";
789 yWarning() << deviceName <<
": skipCalibration flag is on!! Faking park!!";
793 int* currentControlModes =
new int [n_joints];
794 bool* cannotPark =
new bool [n_joints];
795 bool res = iControlMode->getControlModes(currentControlModes);
798 yError() << deviceName <<
": error getting control mode during parking";
801 std::list<int>::iterator lit;
802 for(lit = calibJoints.begin(); lit != calibJoints.end() && !abortCalib; lit++)
804 switch(currentControlModes[(*lit)])
808 yError() << deviceName <<
": joint " << (*lit) <<
" is idle, skipping park";
809 cannotPark[(*lit)] =
true;
813 case VOCAB_CM_HW_FAULT:
815 yError() << deviceName <<
": joint " << (*lit) <<
" has an hardware fault, skipping park";
816 cannotPark[(*lit)] =
true;
820 case VOCAB_CM_NOT_CONFIGURED:
822 yError() << deviceName <<
": joint " << (*lit) <<
" is not configured, skipping park";
823 cannotPark[(*lit)] =
true;
827 case VOCAB_CM_UNKNOWN:
829 yError() << deviceName <<
": joint " << (*lit) <<
" is in unknown state, skipping park";
830 cannotPark[(*lit)] =
true;
835 iControlMode->setControlMode((*lit), VOCAB_CM_POSITION);
836 cannotPark[(*lit)] =
false;
841 iPosition->setRefSpeeds(homeVel);
842 iPosition->positionMove(homePos);
848 for(lit = calibJoints.begin(); lit != calibJoints.end() && !abortCalib; lit++)
850 if (cannotPark[(*lit)] ==
false)
852 yDebug() << deviceName.c_str() <<
": Moving to park position, joint:" << (*lit);
854 iPosition->checkMotionDone((*lit), &
done);
859 iPosition->checkMotionDone((*lit), &
done);
863 yError() << deviceName <<
": joint " << (*lit) <<
" not in position after a timeout of" <<
PARK_TIMEOUT <<
" seconds";
869 yDebug() << deviceName.c_str() <<
": Park " << (abortParking ?
"aborted" :
"completed");
870 for(lit = calibJoints.begin(); lit != calibJoints.end() && !abortCalib; lit++)
873 switch(currentControlModes[(*lit)])
876 case VOCAB_CM_HW_FAULT:
877 case VOCAB_CM_NOT_CONFIGURED:
878 case VOCAB_CM_UNKNOWN:
883 iControlMode->setControlMode((*lit), VOCAB_CM_IDLE);
892 yDebug() << deviceName.c_str() <<
": Quitting calibrate\n";
899 yDebug() << deviceName.c_str() <<
": Quitting parking\n";
911 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
913 yError(
"%s cannot perform 'calibrate' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
916 return calibrateJoint(j);
927 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
929 yError(
"%s cannot perform 'homing' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
939 std::list<int>::iterator lit;
940 for(lit = calibJoints.begin(); lit != calibJoints.end() && !abortCalib; lit++)
949 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
951 yError(
"%s cannot perform 'park' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
961 yWarning() << deviceName <<
": Calling park without calibration... skipping";
969 yWarning() << deviceName <<
": skipCalibration flag is on!! Faking park!!";
973 int currentControlMode;
975 bool res = iControlMode->getControlMode(j, ¤tControlMode);
978 yError() << deviceName <<
": error getting control mode during parking";
981 if(currentControlMode != VOCAB_CM_IDLE &&
982 currentControlMode != VOCAB_CM_HW_FAULT)
984 iControlMode->setControlMode(j, VOCAB_CM_POSITION);
987 else if (currentControlMode == VOCAB_CM_IDLE)
989 yError() << deviceName <<
": joint " << j <<
" is idle, skipping park";
992 else if (currentControlMode == VOCAB_CM_HW_FAULT)
994 yError() << deviceName <<
": joint " << j <<
" has an hardware fault, skipping park";
998 iPosition->setRefSpeed(j, homeVel[j]);
999 iPosition->positionMove(j, homePos[j]);
1005 if (cannotPark ==
false)
1007 yDebug() << deviceName.c_str() <<
": Moving to park position, joint:" << j;
1009 iPosition->checkMotionDone(j, &
done);
1014 iPosition->checkMotionDone(j, &
done);
1018 yError() << deviceName <<
": joint " << j <<
" not in position after a timeout of" <<
PARK_TIMEOUT <<
" seconds";
1023 yDebug() << deviceName.c_str() <<
": Park " << (abortParking ?
"aborted" :
"completed");
1024 iControlMode->setControlMode(j,VOCAB_CM_IDLE);
1033 yError() <<
"Device is not calibrated therefore cannot be parked";
1037 return park(dev2calibrate);
parametricCalibrator()
Default constructor.
virtual bool homingSingleJoint(int j) override
virtual bool calibrateSingleJoint(int j) override
virtual bool parkSingleJoint(int j, bool _wait=true) override
virtual bool close() override
Close the device driver.
virtual bool quitPark() override
~parametricCalibrator()
Destructor.
virtual bool park(DeviceDriver *dd, bool wait=true) override
virtual bool calibrateWholePart() override
virtual bool parkWholePart() override
virtual yarp::dev::IRemoteCalibrator * getCalibratorDevice()
bool calibrate(DeviceDriver *dd) override
Calibrate method.
virtual bool homingWholePart() override
virtual bool quitCalibrate() override
virtual bool open(yarp::os::Searchable &config) override
Open the device driver.
const double GO_TO_ZERO_TIMEOUT
const int CALIBRATE_JOINT_TIMEOUT
static bool extractGroup(Bottle &input, Bottle &out, const std::string &key1, const std::string &txt, int size)
const double POSITION_THRESHOLD