95 #include <yarp/os/all.h>
96 #include <yarp/dev/all.h>
97 #include <yarp/sig/Vector.h>
103 using namespace yarp::os;
105 using namespace yarp::sig;
113 typedef enum {
download, upload, synced } pidStatus;
125 PidData() : Kp(0.0), Ki(0.0), Kd(0.0), scale(0.0),
126 st_up(0.0), st_down(0.0), encs_ratio(1.0),
134 pid.stiction_up_val=st_up;
135 pid.stiction_down_val=st_down;
143 st_up=pid.stiction_up_val;
144 st_down=pid.stiction_down_val;
158 PolyDriver *
waitPart(
const Property &partOpt,
const double ping_robot_tmo)
160 PolyDriver *pDrv=NULL;
162 double t0=Time::now();
163 while (Time::now()-t0<ping_robot_tmo)
168 pDrv=
new PolyDriver(
const_cast<Property&
>(partOpt));
169 bool ok=pDrv->isValid();
173 yInfo(
"Checking if %s is active ... yes",device.c_str());
178 double dt=ping_robot_tmo-(Time::now()-t0);
179 yInfo(
"Checking if %s is active ... not yet: still %.1f [s] to timeout expiry",
180 device.c_str(),dt>0.0?dt:0.0);
182 double t1=Time::now();
183 while (Time::now()-t1<1.0)
201 Bottle &bJoint=bGroup.findGroup(joint.str());
203 pid.
Kp=bJoint.check(
"Kp",Value(0.0)).asFloat64();
204 pid.
Ki=bJoint.check(
"Ki",Value(0.0)).asFloat64();
205 pid.
Kd=bJoint.check(
"Kd",Value(0.0)).asFloat64();
206 pid.
scale=bJoint.check(
"scale",Value(0.0)).asFloat64();
207 pid.
st_up=bJoint.check(
"st_up",Value(0.0)).asFloat64();
208 pid.
st_down=bJoint.check(
"st_down",Value(0.0)).asFloat64();
209 pid.
encs_ratio=bJoint.check(
"encs_ratio",Value(1.0)).asFloat64();
210 pid.
status=(bJoint.check(
"status",Value(
"download")).asString()==
"download"?download:upload);
211 if (bJoint.check(
"idling"))
213 if (Bottle *bIdlingJoints=bJoint.find(
"idling").asList())
216 for (
int j=0; j<bIdlingJoints->size(); j++)
218 int k=bIdlingJoints->get(j).asInt32();
221 for (l=0; l<rJoints.size(); l++)
223 if (rJoints.get(l).asInt32()==k)
230 if (l>=rJoints.size())
231 yError(
"unrecognized joint %d to put in idle",k);
248 sw?VOCAB_CM_IDLE:VOCAB_CM_POSITION);
257 pGeneral.put(
"joint",i);
258 string sGeneral=
"(general ";
259 sGeneral+=pGeneral.toString();
262 Bottle bGeneral,bPlantEstimation,bStictionEstimation;
263 bGeneral.fromString(sGeneral);
264 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))");
265 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)))");
267 Bottle bConf=bGeneral;
268 bConf.append(bPlantEstimation);
269 bConf.append(bStictionEstimation);
271 Property pOptions(bConf.toString().c_str());
273 if (!designer.
configure(*driver,pOptions))
275 yError(
"designer configuration failed!");
279 idlingCoupledJoints(i,
true);
281 Property pPlantEstimation;
282 pPlantEstimation.put(
"max_time",20.0);
283 pPlantEstimation.put(
"switch_timeout",2.0);
286 yInfo(
"Estimating plant for joint %d: max duration = %g seconds",
287 i,pPlantEstimation.find(
"max_time").asFloat64());
289 double t0=Time::now();
290 while (!designer.
isDone())
292 yInfo(
"elapsed %d [s]",(
int)(Time::now()-t0));
296 idlingCoupledJoints(i,
false);
303 double tau=pResults.find(
"tau_mean").asFloat64();
304 double K=pResults.find(
"K_mean").asFloat64();
305 yInfo(
"plant = %g/s * 1/(1+s*%g)",K,tau);
307 Property pControllerRequirements,pController;
308 pControllerRequirements.put(
"tau",tau);
309 pControllerRequirements.put(
"K",K);
310 pControllerRequirements.put(
"f_c",0.75);
314 pControllerRequirements.put(
"T_dr",1.0);
315 pControllerRequirements.put(
"type",
"PI");
318 pControllerRequirements.put(
"type",
"P");
321 yInfo(
"tuning results: %s",pController.toString().c_str());
322 double Kp=pController.find(
"Kp").asFloat64();
323 double Ki=pController.find(
"Ki").asFloat64();
325 int scale=(int)pid.
scale;
int shift=1<<scale;
327 double fwKi=floor(Ki*pid.
encs_ratio*shift/1000.0);
328 pid.
Kp=yarp::math::sign(pid.
Kp*fwKp)>0.0?fwKp:-fwKp;
329 pid.
Ki=yarp::math::sign(pid.
Ki*fwKi)>0.0?fwKi:-fwKi;
331 yInfo(
"Kp (FW) = %g; Ki (FW) = %g; Kd (FW) = %g; shift factor = %d",pid.
Kp,pid.
Ki,pid.
Kd,scale);
333 Property pStictionEstimation;
334 pStictionEstimation.put(
"max_time",60.0);
335 pStictionEstimation.put(
"Kp",Kp);
336 pStictionEstimation.put(
"Ki",0.0);
337 pStictionEstimation.put(
"Kd",0.0);
340 yInfo(
"Estimating stiction for joint %d: max duration = %g seconds",
341 i,pStictionEstimation.find(
"max_time").asFloat64());
344 while (!designer.
isDone())
346 yInfo(
"elapsed %d [s]",(
int)(Time::now()-t0));
350 idlingCoupledJoints(i,
false);
356 pid.
st_up=floor(pResults.find(
"stiction").asList()->get(0).asFloat64());
357 pid.
st_down=floor(pResults.find(
"stiction").asList()->get(1).asFloat64());
358 yInfo(
"Stiction values: up = %g; down = %g",pid.
st_up,pid.
st_down);
361 IPositionControl *ipos;
366 imod->setControlMode(i,VOCAB_CM_POSITION);
367 ipos->setRefSpeed(i,50.0);
368 ipos->positionMove(i,0.0);
369 yInfo(
"Driving the joint back to rest... ");
371 while (Time::now()-t0<5.0)
374 ienc->getEncoder(i,&enc);
380 idlingCoupledJoints(i,
false);
388 idlingCoupledJoints(i,
false);
394 Tuner() : interrupting(false), driver(NULL)
403 Bottle &bGeneral=rf.findGroup(
"general");
404 if (bGeneral.isNull())
406 yError(
"group [general] is missing!");
410 Bottle &bPart=rf.findGroup(part);
413 yError(
"group [%s] is missing!",part.c_str());
417 if (!bPart.check(
"device"))
419 yError(
"\"device\" option is missing!");
423 name=bGeneral.check(
"name",Value(
"fingersTuner")).asString();
424 robot=bGeneral.check(
"robot",Value(
"icub")).asString();
425 double ping_robot_tmo=bGeneral.check(
"ping_robot_tmo",Value(0.0)).asFloat64();
426 device=bPart.find(
"device").asString();
428 if (Bottle *rj=bGeneral.find(
"relevantJoints").asList())
432 yError(
"\"relevantJoints\" option is missing!");
436 int numAlias=bGeneral.check(
"numAlias",Value(0)).asInt32();
437 for (
int i=0; i<numAlias; i++)
441 Bottle &bAlias=bGeneral.findGroup(item.str());
442 if (Bottle *joints=bAlias.find(
"joints").asList())
443 alias[bAlias.find(
"tag").asString()]=*joints;
449 for (
int i=0; i<rJoints.size(); i++)
451 int j=rJoints.get(i).asInt32();
452 pids[j]=getPidData(bPart,j);
455 ostringstream portsSuffix;
456 portsSuffix<<instances<<
"/"<<device;
458 Property option(
"(device remote_controlboard)");
459 option.put(
"remote",
"/"+robot+
"/"+device);
460 option.put(
"local",
"/"+name+
"/"+portsSuffix.str());
462 if (ping_robot_tmo>0.0)
463 driver=waitPart(option,ping_robot_tmo);
465 driver=
new PolyDriver(option);
467 if (!driver->isValid())
469 yError(
"%s device driver not available!",device.c_str());
481 joints.addInt32(sel.asInt32());
482 else if (sel.isString())
484 map<string,Bottle>::iterator it=alias.find(sel.asString());
493 for (
int i=0; i<joints.size(); i++)
495 int j=rJoints.get(i).asInt32();
496 map<int,PidData>::iterator it=pids.find(j);
503 ipid->getPid(VOCAB_PIDTYPE_POSITION,j,&_pid);
511 ipid->setPid(VOCAB_PIDTYPE_POSITION,j,_pid);
525 joints.addInt32(sel.asInt32());
526 else if (sel.isString())
528 map<string,Bottle>::iterator it=alias.find(sel.asString());
537 for (
int i=0; i<joints.size(); i++)
539 int j=joints.get(i).asInt32();
540 map<int,PidData>::iterator it=pids.find(j);
549 ipid->getPid(VOCAB_PIDTYPE_POSITION,j,&_pid);
553 ipid->setPid(VOCAB_PIDTYPE_POSITION,j,_pid);
567 ostringstream stream;
568 stream<<
"["<<part<<
"]"<<endl;
569 stream<<
"device "<<device<<endl;
571 for (
int i=0; i<rJoints.size(); i++)
573 int j=rJoints.get(i).asInt32();
577 prop.put(
"Kp",pid.
Kp);
578 prop.put(
"Ki",pid.
Ki);
579 prop.put(
"Kd",pid.
Kd);
580 prop.put(
"scale",pid.
scale);
581 prop.put(
"st_up",pid.
st_up);
582 prop.put(
"st_down",pid.
st_down);
584 prop.put(
"status",pid.
status==download?
"download":
"upload");
586 stream<<
"joint_"<<j<<
" ";
587 stream<<prop.toString()<<endl;
626 Bottle &bGeneral=rf.findGroup(
"general");
627 if (bGeneral.isNull())
629 yError(
"group [general] is missing!");
633 string name=bGeneral.check(
"name",Value(
"fingersTuner")).asString();
634 setName(name.c_str());
636 if (Bottle *bParts=bGeneral.find(
"relevantParts").asList())
638 for (
int i=0; (i<bParts->size()) && !interrupting; i++)
640 string part=bParts->get(i).asString();
641 tuners[part]=
new Tuner;
642 Tuner *tuner=tuners[part];
650 tuner->
sync(Value(
"*"));
655 yError(
"\"relevantParts\" option is missing!");
659 rpcPort.open(
"/"+name+
"/rpc");
668 return this->
yarp().attachAsServer(source);
687 for (map<string,Tuner*>::iterator it=tuners.begin(); it!=tuners.end(); ++it)
688 it->second->interrupt();
696 for (map<string,Tuner*>::iterator it=tuners.begin(); it!=tuners.end(); ++it)
701 bool sync(
const string &part,
const Value &val)
703 map<string,Tuner*>::iterator it=tuners.find(part);
704 if (it!=tuners.end())
705 if (it->second->sync(val))
712 bool tune(
const string &part,
const Value &val)
714 map<string,Tuner*>::iterator it=tuners.find(part);
715 if (it!=tuners.end())
716 if (it->second->tune(val))
725 string fileName=rf->getHomeContextPath();
727 fileName+=rf->find(
"from").asString();
730 fout.open(fileName.c_str());
732 Bottle &bGeneral=rf->findGroup(
"general");
733 fout<<
"["<<bGeneral.get(0).asString()<<
"]"<<endl;
734 for (
int i=1; i<bGeneral.size(); i++)
735 fout<<bGeneral.get(i).toString()<<endl;
738 for (map<string,Tuner*>::iterator it=tuners.begin(); it!=tuners.end(); ++it)
739 fout<<it->second->toString()<<endl;
766 if (!
yarp.checkNetwork())
768 yError(
"YARP server not available!");
773 rf.setDefaultContext(
"fingersTuner");
774 rf.setDefaultConfigFile(
"config.ini");
775 rf.configure(
argc,argv);
778 return mod.runModule(rf);
bool quit()
Quit the module.
bool configure(ResourceFinder &rf)
bool attach(RpcServer &source)
bool save()
Save the PID parameters on configuration file.
map< string, Tuner * > tuners
bool sync(const string &part, const Value &val)
bool tune(const string &part, const Value &val)
bool configure(ResourceFinder &rf, const string &part)
bool tune(const Value &sel)
bool sync(const Value &sel)
map< string, Bottle > alias
PidData getPidData(Bottle &bGroup, const int i)
void idlingCoupledJoints(const int i, const bool sw)
PolyDriver * waitPart(const Property &partOpt, const double ping_robot_tmo)
static unsigned int instances
fingersTuner_IDL IDL Interface to Fingers PID Tuner services.
Online Compensator Design.
virtual bool isDone()
Check the status of the current ongoing operation.
virtual bool tuneController(const yarp::os::Property &options, yarp::os::Property &results)
Tune the controller once given the plant characteristics.
virtual bool startStictionEstimation(const yarp::os::Property &options)
Start off the stiction estimation procedure.
virtual bool startPlantEstimation(const yarp::os::Property &options)
Start off the plant estimation procedure.
virtual bool getResults(yarp::os::Property &results)
Retrieve the results of the current ongoing operation.
virtual bool configure(yarp::dev::PolyDriver &driver, const yarp::os::Property &options)
Configure the design.
int main(int argc, char *argv[])
Copyright (C) 2008 RobotCub Consortium.
void fromRobot(const Pid &pid)
vector< int > idling_joints