93 #include <yarp/os/all.h>
94 #include <yarp/dev/all.h>
95 #include <yarp/sig/Vector.h>
101 using namespace yarp::os;
103 using namespace yarp::sig;
111 typedef enum { download,
upload, synced } pidStatus;
123 PidData() : Kp(0.0), Ki(0.0), Kd(0.0), scale(0.0),
124 st_up(0.0), st_down(0.0), encs_ratio(1.0),
132 pid.stiction_up_val=st_up;
133 pid.stiction_down_val=st_down;
141 st_up=pid.stiction_up_val;
142 st_down=pid.stiction_down_val;
156 PolyDriver *
waitPart(
const Property &partOpt,
const double ping_robot_tmo)
158 PolyDriver *pDrv=NULL;
160 double t0=Time::now();
161 while (Time::now()-t0<ping_robot_tmo)
166 pDrv=
new PolyDriver(
const_cast<Property&
>(partOpt));
167 bool ok=pDrv->isValid();
171 yInfo(
"Checking if %s is active ... yes",device.c_str());
176 double dt=ping_robot_tmo-(Time::now()-t0);
177 yInfo(
"Checking if %s is active ... not yet: still %.1f [s] to timeout expiry",
178 device.c_str(),dt>0.0?dt:0.0);
180 double t1=Time::now();
181 while (Time::now()-t1<1.0)
199 Bottle &bJoint=bGroup.findGroup(joint.str());
201 pid.
Kp=bJoint.check(
"Kp",Value(0.0)).asFloat64();
202 pid.
Ki=bJoint.check(
"Ki",Value(0.0)).asFloat64();
203 pid.
Kd=bJoint.check(
"Kd",Value(0.0)).asFloat64();
204 pid.
scale=bJoint.check(
"scale",Value(0.0)).asFloat64();
205 pid.
st_up=bJoint.check(
"st_up",Value(0.0)).asFloat64();
206 pid.
st_down=bJoint.check(
"st_down",Value(0.0)).asFloat64();
207 pid.
encs_ratio=bJoint.check(
"encs_ratio",Value(1.0)).asFloat64();
208 pid.
status=(bJoint.check(
"status",Value(
"download")).asString()==
"download"?download:upload);
209 if (bJoint.check(
"idling"))
211 if (Bottle *bIdlingJoints=bJoint.find(
"idling").asList())
214 for (
int j=0; j<bIdlingJoints->size(); j++)
216 int k=bIdlingJoints->get(j).asInt32();
219 for (l=0; l<rJoints.size(); l++)
221 if (rJoints.get(l).asInt32()==k)
228 if (l>=rJoints.size())
229 yError(
"unrecognized joint %d to put in idle",k);
246 sw?VOCAB_CM_IDLE:VOCAB_CM_POSITION);
255 pGeneral.put(
"joint",i);
256 string sGeneral=
"(general ";
257 sGeneral+=pGeneral.toString();
260 Bottle bGeneral,bPlantEstimation,bStictionEstimation;
261 bGeneral.fromString(sGeneral);
262 bPlantEstimation.fromString(
"(plant_estimation (Ts 0.01) (Q 1.0) (R 1.0) (P0 100000.0) (tau 1.0) (K 1.0) (max_pwm 800.0))");
263 bStictionEstimation.fromString(
"(stiction_estimation (Ts 0.01) (T 2.0) (vel_thres 5.0) (e_thres 1.0) (gamma (10.0 10.0)) (stiction (0.0 0.0)))");
265 Bottle bConf=bGeneral;
266 bConf.append(bPlantEstimation);
267 bConf.append(bStictionEstimation);
269 Property pOptions(bConf.toString().c_str());
271 if (!designer.
configure(*driver,pOptions))
273 yError(
"designer configuration failed!");
277 idlingCoupledJoints(i,
true);
279 Property pPlantEstimation;
280 pPlantEstimation.put(
"max_time",20.0);
281 pPlantEstimation.put(
"switch_timeout",2.0);
284 yInfo(
"Estimating plant for joint %d: max duration = %g seconds",
285 i,pPlantEstimation.find(
"max_time").asFloat64());
287 double t0=Time::now();
288 while (!designer.
isDone())
290 yInfo(
"elapsed %d [s]",(
int)(Time::now()-t0));
294 idlingCoupledJoints(i,
false);
301 double tau=pResults.find(
"tau_mean").asFloat64();
302 double K=pResults.find(
"K_mean").asFloat64();
303 yInfo(
"plant = %g/s * 1/(1+s*%g)",K,tau);
305 Property pControllerRequirements,pController;
306 pControllerRequirements.put(
"tau",tau);
307 pControllerRequirements.put(
"K",K);
308 pControllerRequirements.put(
"f_c",0.75);
312 pControllerRequirements.put(
"T_dr",1.0);
313 pControllerRequirements.put(
"type",
"PI");
316 pControllerRequirements.put(
"type",
"P");
319 yInfo(
"tuning results: %s",pController.toString().c_str());
320 double Kp=pController.find(
"Kp").asFloat64();
321 double Ki=pController.find(
"Ki").asFloat64();
323 int scale=(int)pid.
scale;
int shift=1<<scale;
325 double fwKi=floor(Ki*pid.
encs_ratio*shift/1000.0);
326 pid.
Kp=yarp::math::sign(pid.
Kp*fwKp)>0.0?fwKp:-fwKp;
327 pid.
Ki=yarp::math::sign(pid.
Ki*fwKi)>0.0?fwKi:-fwKi;
329 yInfo(
"Kp (FW) = %g; Ki (FW) = %g; Kd (FW) = %g; shift factor = %d",pid.
Kp,pid.
Ki,pid.
Kd,scale);
331 Property pStictionEstimation;
332 pStictionEstimation.put(
"max_time",60.0);
333 pStictionEstimation.put(
"Kp",Kp);
334 pStictionEstimation.put(
"Ki",0.0);
335 pStictionEstimation.put(
"Kd",0.0);
338 yInfo(
"Estimating stiction for joint %d: max duration = %g seconds",
339 i,pStictionEstimation.find(
"max_time").asFloat64());
342 while (!designer.
isDone())
344 yInfo(
"elapsed %d [s]",(
int)(Time::now()-t0));
348 idlingCoupledJoints(i,
false);
354 pid.
st_up=floor(pResults.find(
"stiction").asList()->get(0).asFloat64());
355 pid.
st_down=floor(pResults.find(
"stiction").asList()->get(1).asFloat64());
356 yInfo(
"Stiction values: up = %g; down = %g",pid.
st_up,pid.
st_down);
359 IPositionControl *ipos;
364 imod->setControlMode(i,VOCAB_CM_POSITION);
365 ipos->setRefSpeed(i,50.0);
366 ipos->positionMove(i,0.0);
367 yInfo(
"Driving the joint back to rest... ");
369 while (Time::now()-t0<5.0)
372 ienc->getEncoder(i,&enc);
378 idlingCoupledJoints(i,
false);
386 idlingCoupledJoints(i,
false);
392 Tuner() : interrupting(false), driver(NULL)
401 Bottle &bGeneral=rf.findGroup(
"general");
402 if (bGeneral.isNull())
404 yError(
"group [general] is missing!");
408 Bottle &bPart=rf.findGroup(part);
411 yError(
"group [%s] is missing!",part.c_str());
415 if (!bPart.check(
"device"))
417 yError(
"\"device\" option is missing!");
421 name=bGeneral.check(
"name",Value(
"fingersTuner")).asString();
422 robot=bGeneral.check(
"robot",Value(
"icub")).asString();
423 double ping_robot_tmo=bGeneral.check(
"ping_robot_tmo",Value(0.0)).asFloat64();
424 device=bPart.find(
"device").asString();
426 if (Bottle *rj=bGeneral.find(
"relevantJoints").asList())
430 yError(
"\"relevantJoints\" option is missing!");
434 int numAlias=bGeneral.check(
"numAlias",Value(0)).asInt32();
435 for (
int i=0; i<numAlias; i++)
439 Bottle &bAlias=bGeneral.findGroup(item.str());
440 if (Bottle *joints=bAlias.find(
"joints").asList())
441 alias[bAlias.find(
"tag").asString()]=*joints;
447 for (
int i=0; i<rJoints.size(); i++)
449 int j=rJoints.get(i).asInt32();
450 pids[j]=getPidData(bPart,j);
453 ostringstream portsSuffix;
454 portsSuffix<<instances<<
"/"<<device;
456 Property option(
"(device remote_controlboard)");
457 option.put(
"remote",
"/"+robot+
"/"+device);
458 option.put(
"local",
"/"+name+
"/"+portsSuffix.str());
460 if (ping_robot_tmo>0.0)
461 driver=waitPart(option,ping_robot_tmo);
463 driver=
new PolyDriver(option);
465 if (!driver->isValid())
467 yError(
"%s device driver not available!",device.c_str());
479 joints.addInt32(sel.asInt32());
480 else if (sel.isString())
482 map<string,Bottle>::iterator it=alias.find(sel.asString());
491 for (
int i=0; i<joints.size(); i++)
493 int j=rJoints.get(i).asInt32();
494 map<int,PidData>::iterator it=pids.find(j);
501 ipid->getPid(VOCAB_PIDTYPE_POSITION,j,&_pid);
509 ipid->setPid(VOCAB_PIDTYPE_POSITION,j,_pid);
523 joints.addInt32(sel.asInt32());
524 else if (sel.isString())
526 map<string,Bottle>::iterator it=alias.find(sel.asString());
535 for (
int i=0; i<joints.size(); i++)
537 int j=joints.get(i).asInt32();
538 map<int,PidData>::iterator it=pids.find(j);
547 ipid->getPid(VOCAB_PIDTYPE_POSITION,j,&_pid);
551 ipid->setPid(VOCAB_PIDTYPE_POSITION,j,_pid);
565 ostringstream stream;
566 stream<<
"["<<part<<
"]"<<endl;
567 stream<<
"device "<<device<<endl;
569 for (
int i=0; i<rJoints.size(); i++)
571 int j=rJoints.get(i).asInt32();
575 prop.put(
"Kp",pid.
Kp);
576 prop.put(
"Ki",pid.
Ki);
577 prop.put(
"Kd",pid.
Kd);
578 prop.put(
"scale",pid.
scale);
579 prop.put(
"st_up",pid.
st_up);
580 prop.put(
"st_down",pid.
st_down);
582 prop.put(
"status",pid.
status==download?
"download":
"upload");
584 stream<<
"joint_"<<j<<
" ";
585 stream<<prop.toString()<<endl;
624 Bottle &bGeneral=rf.findGroup(
"general");
625 if (bGeneral.isNull())
627 yError(
"group [general] is missing!");
631 string name=bGeneral.check(
"name",Value(
"fingersTuner")).asString();
632 setName(name.c_str());
634 if (Bottle *bParts=bGeneral.find(
"relevantParts").asList())
636 for (
int i=0; (i<bParts->size()) && !interrupting; i++)
638 string part=bParts->get(i).asString();
639 tuners[part]=
new Tuner;
640 Tuner *tuner=tuners[part];
648 tuner->
sync(Value(
"*"));
653 yError(
"\"relevantParts\" option is missing!");
657 rpcPort.open(
"/"+name+
"/rpc");
666 return this->
yarp().attachAsServer(source);
685 for (map<string,Tuner*>::iterator it=tuners.begin(); it!=tuners.end(); ++it)
686 it->second->interrupt();
694 for (map<string,Tuner*>::iterator it=tuners.begin(); it!=tuners.end(); ++it)
699 bool sync(
const string &part,
const Value &val)
701 map<string,Tuner*>::iterator it=tuners.find(part);
702 if (it!=tuners.end())
703 if (it->second->sync(val))
710 bool tune(
const string &part,
const Value &val)
712 map<string,Tuner*>::iterator it=tuners.find(part);
713 if (it!=tuners.end())
714 if (it->second->tune(val))
723 string fileName=rf->getHomeContextPath();
725 fileName+=rf->find(
"from").asString();
728 fout.open(fileName.c_str());
730 Bottle &bGeneral=rf->findGroup(
"general");
731 fout<<
"["<<bGeneral.get(0).asString()<<
"]"<<endl;
732 for (
int i=1; i<bGeneral.size(); i++)
733 fout<<bGeneral.get(i).toString()<<endl;
736 for (map<string,Tuner*>::iterator it=tuners.begin(); it!=tuners.end(); ++it)
737 fout<<it->second->toString()<<endl;
764 if (!
yarp.checkNetwork())
766 yError(
"YARP server not available!");
771 rf.setDefaultContext(
"fingersTuner");
772 rf.setDefaultConfigFile(
"config.ini");
773 rf.configure(
argc,argv);
776 return mod.runModule(rf);