iCub-main
main.cpp
Go to the documentation of this file.
1 
14 #include <cstdio>
15 #include <math.h>
16 #include <string>
17 #include <sstream>
18 #include <algorithm>
19 
20 #include <yarp/os/all.h>
21 #include <yarp/dev/all.h>
22 #include <yarp/sig/all.h>
23 #include <yarp/math/Math.h>
24 
25 #include <iCub/ctrl/tuning.h>
26 
27 using namespace std;
28 using namespace yarp::os;
29 using namespace yarp::dev;
30 using namespace yarp::sig;
31 using namespace yarp::math;
32 using namespace iCub::ctrl;
33 
34 
35 /*******************************************************/
36 int main(int argc, char *argv[])
37 {
38  // usual stuff...
39  Network yarp;
40  if (!yarp.checkNetwork())
41  {
42  printf("YARP is not available!\n");
43  return 1;
44  }
45 
46  ResourceFinder rf;
47  rf.configure(argc,argv);
48 
49  string name=rf.check("name",Value("tuner")).asString();
50  string robot=rf.check("robot",Value("icub")).asString();
51  string part=rf.check("part",Value("right_arm")).asString();
52  int joint=rf.check("joint",Value(11)).asInt32();
53  double encoder=rf.check("encoder",Value(2.43)).asFloat64();
54 
55  Property pOptions;
56  pOptions.put("device","remote_controlboard");
57  pOptions.put("remote","/"+robot+"/"+part);
58  pOptions.put("local","/"+name+"/"+part);
59  PolyDriver driver(pOptions);
60  if (!driver.isValid())
61  {
62  printf("Part \"%s\" is not ready!\n",string("/"+robot+"/"+part).c_str());
63  return 1;
64  }
65 
66  // ##### Preamble
67  // The objective is to tune online a P controller that will make
68  // the joint move complying with some given bandwidth specification.
69  //
70  // The plant is to be identified using an Extended-Kalman-Filter (EKF)
71  // under the assumption that the adopted model obeys to the following
72  // tansfer function which gives out the position when fed with voltage:
73  //
74  // K / (s*(1 + tau*s))
75  //
76  // You might have realized that we disregard the electrical dynamics in
77  // favour of the slower mechanical one represented by the time constant tau.
78  //
79  // ##### Additional notes on the control design
80  // The low-level layer provides the user with a PID controller. However, the
81  // I part is not specifically required for such control task since by virtue
82  // of the internal model principle the steady-state error can be already
83  // compensated thanks to the presence of the integrator in the plant. On the
84  // other hand, this principle holds only for linear systems and indeed,
85  // nonlinear effects - such as the stiction - make the final behavior deviate
86  // from this baseline, eventually requiring the integral part. Nonetheless,
87  // if stiction is compensated separately, I is again not strictly needed.
88  //
89  // Finally, a few words about the D part. In order to include D within the design,
90  // the derivative part must be implemented according to the standard which states
91  // that D = Kd*s / (1 + tau_d*s).
92  //
93  // In the following a short example will guide you through the steps required
94  // to identify the plant, validate the retrieved model and then design the
95  // P controller that meets the user specifications. Stiction identification is
96  // carried out as well.
97 
98  // First thing to do is to prepare configuration options
99  // which are to be given in the form:
100  //
101  // [general]
102  // joint ...
103  // port ...
104  // [plant_estimation]
105  // Ts ...
106  // ...
107  // [stiction_estimation]
108  // ...
109  Property pGeneral;
110  pGeneral.put("joint",joint);
111  // the "port" option allows opening up a yarp port which
112  // will stream out useful information while identifying
113  // and validating the system
114  pGeneral.put("port","/"+name+"/info:o");
115  string sGeneral="(general ";
116  sGeneral+=pGeneral.toString();
117  sGeneral+=')';
118 
119  Bottle bGeneral,bPlantEstimation,bStictionEstimation;
120  bGeneral.fromString(sGeneral);
121  // here follow the parameters for the EKF along with the
122  // initial values for tau and K
123  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))");
124  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)))");
125 
126  // compose the overall configuration
127  Bottle bConf=bGeneral;
128  bConf.append(bPlantEstimation);
129  bConf.append(bStictionEstimation);
130  pOptions.fromString(bConf.toString());
131 
132  OnlineCompensatorDesign designer;
133  if (!designer.configure(driver,pOptions))
134  {
135  printf("Configuration failed!\n");
136  return 1;
137  }
138 
139  // let's start the plant estimation by
140  // setting up an experiment that will
141  // last 20 seconds
142  //
143  // the experiment foresees a direct control
144  // in voltage (pwm)
145  Property pPlantEstimation;
146  pPlantEstimation.put("max_time",20.0);
147  // the switch_timeout option enforces a timeout
148  // in the voltage switching logic to produce
149  // rising and falling transitions.
150  pPlantEstimation.put("switch_timeout",2.0);
151  designer.startPlantEstimation(pPlantEstimation);
152 
153  printf("Estimation experiment will last %g seconds...\n",
154  pPlantEstimation.find("max_time").asFloat64());
155 
156  double t0=Time::now();
157  while (!designer.isDone())
158  {
159  printf("elapsed %d [s]\n",(int)(Time::now()-t0));
160  Time::delay(1.0);
161  }
162 
163  // retrieve the identified values (averaged over time)
164  Property pResults;
165  designer.getResults(pResults);
166  double tau=pResults.find("tau_mean").asFloat64();
167  double K=pResults.find("K_mean").asFloat64();
168 
169  printf("plant = K/s * 1/(1+s*tau)\n");
170  printf("Estimated parameters...\n");
171  printf("tau = %g\n",tau);
172  printf("K = %g\n",K);
173 
174  // put the model to test for 10 seconds by
175  // simulating the plant with a Kalman filter
176  Property pPlantValidation;
177  pPlantValidation.put("max_time",10.0);
178  pPlantValidation.put("switch_timeout",2.0);
179  pPlantValidation.put("tau",tau);
180  pPlantValidation.put("K",K);
181  // the "measure_update_ticks" option tells that
182  // the measurement update will occur 100 times slower
183  // with respect to the sample time. This way we give
184  // the model enough time to evolve to test its properties
185  // before comparing its response with the real output
186  // to counteract drift phenomena.
187  pPlantValidation.put("measure_update_ticks",100);
188  designer.startPlantValidation(pPlantValidation);
189 
190  printf("Validation experiment will last %g seconds...\n",
191  pPlantValidation.find("max_time").asFloat64());
192 
193  t0=Time::now();
194  while (!designer.isDone())
195  {
196  printf("elapsed %d [s]\n",(int)(Time::now()-t0));
197  Time::delay(1.0);
198  }
199 
200  // The design part...
201  printf("Tuning P controller...\n");
202  Property pControllerRequirements,pController;
203  pControllerRequirements.put("tau",tau);
204  pControllerRequirements.put("K",K);
205  // The bandwidth specification is provided in terms of gain crossover
206  // frequency (in Hz) which amounts to the frequency where the
207  // open loop response given by Kp * plant has a unity-gain;
208  // f_c roughly determines the bandwidth of the closed loop response.
209  // Requirements: track min-jerk profiles whose trajectory
210  // time is 2.0 seconds.
211  // From spectral analysis we know that the most of the
212  // frequency content of a signal composed of the given
213  // min-jerk pulses lies whithin the range [0,0.6] Hz.
214  // A crossover frequency of 0.75 is therefore suitable.
215  pControllerRequirements.put("f_c",0.75);
216  pControllerRequirements.put("type","P");
217  designer.tuneController(pControllerRequirements,pController);
218  printf("tuning results: %s\n",pController.toString().c_str());
219  double Kp=pController.find("Kp").asFloat64();
220  printf("found Kp = %g\n",Kp);
221  int scale=4;
222  double Kp_fw=Kp*encoder*(1<<scale);
223  printf("Kp (firmware) = %g; shift factor = %d\n",Kp_fw,scale);
224 
225  // let's identify the stictions values as well
226  Property pStictionEstimation;
227  pStictionEstimation.put("max_time",60.0);
228  // the joint will be controlled under the action
229  // of a high-level PID controller
230  pStictionEstimation.put("Kp",Kp);
231  pStictionEstimation.put("Ki",0.0);
232  pStictionEstimation.put("Kd",0.0);
233  designer.startStictionEstimation(pStictionEstimation);
234 
235  printf("Stiction estimation experiment will last no more than %g seconds...\n",
236  pStictionEstimation.find("max_time").asFloat64());
237 
238  t0=Time::now();
239  while (!designer.isDone())
240  {
241  printf("elapsed %d [s]\n",(int)(Time::now()-t0));
242  Time::delay(1.0);
243  }
244 
245  // retrieve the stiction values
246  designer.getResults(pResults);
247  Vector stiction(2);
248  stiction[0]=pResults.find("stiction").asList()->get(0).asFloat64();
249  stiction[1]=pResults.find("stiction").asList()->get(1).asFloat64();
250  printf("Stiction values: up = %g; down = %g\n",stiction[0],stiction[1]);
251 
252  // now that we know P and stiction, let's try out our controller
253  // against the current version
254  Property pControllerValidation;
255  pControllerValidation.put("max_time",60.0);
256  pControllerValidation.put("Kp",Kp_fw);
257  pControllerValidation.put("scale",scale);
258  ostringstream str;
259  str<<"( ";
260  str<<stiction[0];
261  str<<" ";
262  str<<stiction[1];
263  str<<" )";
264  Value val; val.fromString(str.str().c_str());
265  pControllerValidation.put("stiction",val);
266  // we let yarp apply the stiction values upon transitions;
267  // by default the "firmware" takes care of it.
268  pControllerValidation.put("stiction_compensation","middleware");
269  // let's go for the classical "min-jerk" reference input with a
270  // period of 2 seconds.
271  // we have also the "square" waveform at our disposal, just in
272  // case we aim at measuring traditional controller step response.
273  pControllerValidation.put("ref_type","min-jerk");
274  pControllerValidation.put("ref_period",2.0);
275  // for the "min-jerk" reference type it turns to be useful to
276  // have a "sustain" time where the reference is kept to the
277  // final set-point before switching to the next value.
278  pControllerValidation.put("ref_sustain_time",1.0);
279  // in this experiment both the current controller and our controller
280  // will act, one after other, each for 4 cycles of 1 rising and 1 falling
281  // transition in a row.
282  pControllerValidation.put("cycles_to_switch",4);
283  designer.startControllerValidation(pControllerValidation);
284 
285  printf("Controller validation will last %g seconds...\n",
286  pControllerValidation.find("max_time").asFloat64());
287 
288  t0=Time::now();
289  while (!designer.isDone())
290  {
291  printf("elapsed %d [s]\n",(int)(Time::now()-t0));
292  Time::delay(1.0);
293  }
294 
295  return 0;
296 }
297 
298 
Online Compensator Design.
Definition: tuning.h:348
virtual bool isDone()
Check the status of the current ongoing operation.
Definition: tuning.cpp:1025
virtual bool tuneController(const yarp::os::Property &options, yarp::os::Property &results)
Tune the controller once given the plant characteristics.
Definition: tuning.cpp:838
virtual bool startStictionEstimation(const yarp::os::Property &options)
Start off the stiction estimation procedure.
Definition: tuning.cpp:953
virtual bool startPlantEstimation(const yarp::os::Property &options)
Start off the plant estimation procedure.
Definition: tuning.cpp:891
virtual bool startPlantValidation(const yarp::os::Property &options)
Start off the plant validation procedure.
Definition: tuning.cpp:905
virtual bool getResults(yarp::os::Property &results)
Retrieve the results of the current ongoing operation.
Definition: tuning.cpp:1048
virtual bool configure(yarp::dev::PolyDriver &driver, const yarp::os::Property &options)
Configure the design.
Definition: tuning.cpp:459
virtual bool startControllerValidation(const yarp::os::Property &options)
Start off the controller validation procedure.
Definition: tuning.cpp:971
int main(int argc, char *argv[])
Definition: main.cpp:31
Copyright (C) 2008 RobotCub Consortium.