icub-test
Loading...
Searching...
No Matches
Public Member Functions
PositionControlAccuracyExernalPid Class Reference

This tests checks the response of the system to a position step, sending directly PWM commands to a joint. More...

#include <PositionControlAccuracyExternalPid.h>

Inherits yarp::robottestingframework::TestCase.

Public Member Functions

virtual bool setup (yarp::os::Property &property)
 
virtual void tearDown ()
 
virtual void run ()
 
bool goHome ()
 
void executeCmd ()
 
void setMode (int desired_mode)
 
void saveToFile (std::string filename, yarp::os::Bottle &b)
 

Detailed Description

This tests checks the response of the system to a position step, sending directly PWM commands to a joint.

The PWM commands are computed using iCub::ctrl::parallelPID class. This test currently does not return any error report. It simply moves a joint, and saves data to a different file for each joint. The data acquired can be analyzed with a Matlab script to evaluate the position PID properties. Be aware that a step greater than 5 degrees at the maximum speed can be dangerous for both the robot and the human operator!

example: testRunner -v -t PositionControlAccuracyExternalPid.dll -p "--robot icubSim --part head --joints ""(0 1 2)"" --zeros ""(0 0 0)"" --step 5 --cycles 10 --sampleTime 0.010 --Kp 1.0" example: testRunner -v -t PositionControlAccuracyExternalPid.dll -p "--robot icubSim --part head --joints ""(2)"" --zeros ""(0)"" --step 5 --cycles 10 --sampleTime 0.010 --homeTolerance 1.0 --step_duration 8 --Kp 2.2 --Kd 0.01 --Ki 100 --MaxValue 80"

Accepts the following parameters:

Parameter name Type Units Default Value Required Description Notes
robot string - - Yes The name of the robot. e.g. icub
part string - - Yes The name of the robot part. e.g. left_arm
joints vector of ints - - Yes List of joints to be tested
zeros double deg - Yes The home position for each joint
cycles int - - Yes Each joint will be tested multiple times
step double deg - Yes The amplitude of the step reference signal Recommended max: 5 deg!
sampleTime double s - Yes The sample time of the control thread
home_tolerance double deg 0.5 No The max acceptable position error during the homing phase.
filename string No The output filename. If not specified, the name will be generated using 'part' parameter and joint number
step_duration double s 4 No The duration of the step. After this time, a new test cycle starts.
Kp double 0 No The Proportional gain
Ki double 0 No The Integral gain
Kd double 0 No The Derivative gain
MaxValue double % 100 No max value for PID output (saturator).

Definition at line 62 of file PositionControlAccuracyExternalPid.h.

Constructor & Destructor Documentation

◆ PositionControlAccuracyExernalPid()

PositionControlAccuracyExernalPid::PositionControlAccuracyExernalPid ( )

Definition at line 40 of file PositionControlAccuracyExternalPid.cpp.

40 : yarp::robottestingframework::TestCase("PositionControlAccuracyExernalPid") {
41 m_jointsList = 0;
42 m_encoders = 0;
43 m_zeros = 0;
44 dd=0;
45 ipos=0;
46 icmd=0;
47 iimd=0;
48 ienc=0;
49 idir=0;
50 ipwm=0;
51 m_home_tolerance=0.5;
52 m_step_duration=4;
53 m_pospid_vup=0;
54 m_pospid_vdown=0;
55}

◆ ~PositionControlAccuracyExernalPid()

PositionControlAccuracyExernalPid::~PositionControlAccuracyExernalPid ( )
virtual

Definition at line 57 of file PositionControlAccuracyExternalPid.cpp.

57{ }

Member Function Documentation

◆ goHome()

bool PositionControlAccuracyExernalPid::goHome ( )

Definition at line 216 of file PositionControlAccuracyExternalPid.cpp.

217{
218 for (int i = 0; i<m_n_cmd_joints; i++)
219 {
220 ipos->setRefSpeed(m_jointsList[i], 20.0);
221 ipos->positionMove(m_jointsList[i], m_zeros[i]);
222 }
223
224 int timeout = 0;
225 while (1)
226 {
227 int in_position=0;
228 for (int i = 0; i<m_n_cmd_joints; i++)
229 {
230 ienc->getEncoder(m_jointsList[i], &m_encoders[m_jointsList[i]]);
231 if (fabs(m_encoders[m_jointsList[i]] - m_zeros[i])<m_home_tolerance) in_position++;
232 }
233 if (in_position == m_n_cmd_joints) break;
234 if (timeout>100)
235 {
236 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Timeout while reaching zero position");
237 return false;
238 }
239 yarp::os::Time::delay(0.2);
240 timeout++;
241 }
242 //sleep some additional time to complete movement from m_home_tolerance to 0
243 yarp::os::Time::delay(0.5);
244 return true;
245}

◆ run()

void PositionControlAccuracyExernalPid::run ( )
virtual

Definition at line 247 of file PositionControlAccuracyExternalPid.cpp.

248{
249 for (int i = 0; i < m_n_cmd_joints; i++)
250 {
251 for (int cycle = 0; cycle < m_cycles; cycle++)
252 {
253 setMode(VOCAB_CM_POSITION);
254 if (goHome() == false)
255 {
256 ROBOTTESTINGFRAMEWORK_ASSERT_FAIL("Test stopped");
257 };
258
259 ppid->reset(yarp::sig::Vector(1,0.0));
260
261 setMode(VOCAB_CM_PWM);
262 double start_time = yarp::os::Time::now();
263
264 char cbuff[64];
265 sprintf(cbuff, "Testing Joint: %d cycle: %d", i, cycle);
266
267 std::string buff(cbuff);
268 ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
269
270 double time_zero = 0;
271 yarp::os::Bottle dataToPlotRaw;
272 yarp::os::Bottle dataToPlotSync;
273 ienc->getEncoders(m_encoders);
274
275 while (1)
276 {
277 double curr_time = yarp::os::Time::now();
278 double elapsed = curr_time - start_time;
279 double ref=0;
280 if (elapsed <= 1.0)
281 {
282 ref=m_zeros[i];
283 }
284 else if (elapsed > 1.0 && elapsed <= m_step_duration)
285 {
286 ref=m_zeros[i]+m_step;
287 if (time_zero == 0) time_zero = elapsed;
288 }
289 else
290 {
291 break;
292 }
293
294 //pid computation
295 ienc->getEncoders(m_encoders);
296 m_cmd_single = ppid->compute(yarp::sig::Vector(1,ref),yarp::sig::Vector(1,m_encoders[m_jointsList[i]]))[0];
297
298 //stiction compensation
299 if (ref>m_encoders[m_jointsList[i]])
300 {
301 m_cmd_single+=m_pospid_vup;
302 }
303 else
304 {
305 m_cmd_single+=m_pospid_vdown;
306 }
307
308 //control
309 ipwm->setRefDutyCycle(m_jointsList[i], m_cmd_single);
310
311 Bottle& b1 = dataToPlotRaw.addList();
312 b1.addInt32(cycle);
313 b1.addFloat64(elapsed);
314 b1.addFloat64(m_encoders[m_jointsList[i]]);
315 b1.addFloat64(ref);
316 b1.addFloat64(m_cmd_single);
317 yarp::os::Time::delay(m_sampleTime);
318 }
319
320 //reorder data
321 for (int t = 0; t < dataToPlotRaw.size(); t++)
322 {
323 int cycle = dataToPlotRaw.get(t).asList()->get(0).asInt32();
324 double time = dataToPlotRaw.get(t).asList()->get(1).asFloat64();
325 double val = dataToPlotRaw.get(t).asList()->get(2).asFloat64();
326 double cmd = dataToPlotRaw.get(t).asList()->get(3).asFloat64();
327 double duty = dataToPlotRaw.get(t).asList()->get(4).asFloat64();
328 Bottle& b1 = dataToPlotSync.addList();
329 b1.addInt32(cycle);
330 b1.addFloat64(time - time_zero);
331 b1.addFloat64(val);
332 b1.addFloat64(cmd);
333 b1.addFloat64(duty);
334 }
335
336 m_dataToSave.append(dataToPlotSync);
337 } //cycle loop
338
339 //save data
340 std::string filename;
341 if (m_requested_filename=="")
342 {
343 char cfilename[128];
344 sprintf(cfilename, "positionControlAccuracyExternalPid_plot_%s%d.txt", m_partName.c_str(), i);
345 filename = cfilename;
346 //filename += m_partName;
347 //filename += std::to_string(i);
348 //filename += ".txt";
349 }
350 else
351 {
352 filename=m_requested_filename;
353 }
354 yInfo() << "Saving file to: "<< filename;
355 saveToFile(filename, m_dataToSave);
356 } //joint loop
357
358 //data acquisition ends here
359 setMode(VOCAB_CM_POSITION);
360 goHome();
361 ROBOTTESTINGFRAMEWORK_TEST_REPORT("Data acquisition complete");
362
363 //plot data
364 /*for (int i = 0; i < m_n_cmd_joints; i++)
365 {
366 std::string filename = "positionControlAccuracy_plot_";
367 filename += m_partName;
368 filename += std::to_string(i);
369 filename += ".txt";
370 char plotstring[1000];
371 sprintf(plotstring, "gnuplot -e \" unset key; plot for [col=1:%d] '%s' using col with lines \" -persist", m_n_cmd_joints, filename.c_str());
372 system(plotstring);
373 }*/
374}

◆ saveToFile()

void PositionControlAccuracyExernalPid::saveToFile ( std::string  filename,
yarp::os::Bottle &  b 
)

Definition at line 376 of file PositionControlAccuracyExternalPid.cpp.

377{
378 std::fstream fs;
379 fs.open(filename.c_str(), std::fstream::out);
380
381 for (int i = 0; i<b.size(); i++)
382 {
383 std::string s = b.get(i).toString();
384 std::replace(s.begin(), s.end(), '(', ' ');
385 std::replace(s.begin(), s.end(), ')', ' ');
386 fs << s << std::endl;
387 }
388
389 fs.close();
390}

◆ setMode()

void PositionControlAccuracyExernalPid::setMode ( int  desired_mode)

Definition at line 184 of file PositionControlAccuracyExternalPid.cpp.

185{
186 for (int i = 0; i<m_n_cmd_joints; i++)
187 {
188 icmd->setControlMode(m_jointsList[i], desired_mode);
189 iimd->setInteractionMode(m_jointsList[i], VOCAB_IM_STIFF);
190 yarp::os::Time::delay(0.010);
191 }
192
193 int cmode;
194 yarp::dev::InteractionModeEnum imode;
195 int timeout = 0;
196
197 while (1)
198 {
199 int ok=0;
200 for (int i = 0; i<m_n_cmd_joints; i++)
201 {
202 icmd->getControlMode(m_jointsList[i], &cmode);
203 iimd->getInteractionMode(m_jointsList[i], &imode);
204 if (cmode==desired_mode && imode==VOCAB_IM_STIFF) ok++;
205 }
206 if (ok == m_n_cmd_joints) break;
207 if (timeout>100)
208 {
209 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Unable to set control mode/interaction mode");
210 }
211 yarp::os::Time::delay(0.2);
212 timeout++;
213 }
214}

◆ setup()

bool PositionControlAccuracyExernalPid::setup ( yarp::os::Property &  property)
virtual

Definition at line 59 of file PositionControlAccuracyExternalPid.cpp.

59 {
60
61 //updating the test name
62 if(property.check("name"))
63 setName(property.find("name").asString());
64
65 // updating parameters
66 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("robot"), "The robot name must be given as the test parameter!");
67 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("part"), "The part name must be given as the test parameter!");
68 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("joints"), "The joints list must be given as the test parameter!");
69 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("zeros"), "The zero position list must be given as the test parameter!");
70 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("cycles"), "The number of cycles of the control signal must be given as the test parameter!");
71 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("step"), "The amplitude of the step reference signal expressed in degrees!");
72 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("sampleTime"), "The sampleTime of the control signal must be given as the test parameter!");
73
74 if(property.check("filename"))
75 {m_requested_filename = property.find("filename").asString();}
76 if(property.check("home_tolerance"))
77 {m_home_tolerance = property.find("home_tolerance").asFloat64();}
78 if(property.check("step_duration"))
79 {m_step_duration = property.find("step_duration").asFloat64();}
80 if(property.check("pid_vup"))
81 {m_pospid_vup = property.find("pid_vup").asFloat64();}
82 if(property.check("pid_vdown"))
83 {m_pospid_vdown = property.find("pid_vdown").asFloat64();}
84
85 m_robotName = property.find("robot").asString();
86 m_partName = property.find("part").asString();
87
88 Bottle* jointsBottle = property.find("joints").asList();
89 Bottle* zerosBottle = property.find("zeros").asList();
90
91 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(jointsBottle!=0,"unable to parse joints parameter");
92 m_n_cmd_joints = jointsBottle->size();
93 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(m_n_cmd_joints>0, "invalid number of joints, it must be >0");
94
95 m_step = property.find("step").asFloat64();
96
97 m_cycles = property.find("cycles").asInt32();
98 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(m_cycles>0, "invalid cycles");
99
100 m_sampleTime = property.find("sampleTime").asFloat64();
101 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(m_sampleTime>0, "invalid sampleTime");
102
103 Property options;
104 options.put("device", "remote_controlboard");
105 options.put("remote", "/" + m_robotName + "/" + m_partName);
106 options.put("local", "/positionControlAccuracyTest/" + m_robotName + "/" + m_partName);
107
108 dd = new PolyDriver(options);
109 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->isValid(),"Unable to open device driver");
110 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(idir),"Unable to open position direct interface");
111 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ienc),"Unable to open encoders interface");
112 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipos),"Unable to open position interface");
113 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(icmd),"Unable to open control mode interface");
114 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(iimd),"Unable to open interaction mode interface");
115 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipwm),"Unable to open pwm mode interface");
116
117 if (!ienc->getAxes(&m_n_part_joints))
118 {
119 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("unable to get the number of joints of the part");
120 }
121
122 m_zeros = new double[m_n_part_joints];
123 m_encoders = new double[m_n_part_joints];
124 m_jointsList = new int[m_n_cmd_joints];
125 for (int i = 0; i <m_n_cmd_joints; i++) m_jointsList[i] = jointsBottle->get(i).asInt32();
126 for (int i = 0; i <m_n_cmd_joints; i++) m_zeros[i] = zerosBottle->get(i).asFloat64();
127
128 double p_Ts = m_sampleTime;
129 yarp::sig::Vector p_Kp(1,0.0);
130 yarp::sig::Vector p_Ki(1,0.0);
131 yarp::sig::Vector p_Kd(1,0.0);
132 if(property.check("Kp"))
133 {p_Kp = property.find("Kp").asFloat64();}
134 if(property.check("Ki"))
135 {p_Ki = property.find("Ki").asFloat64();}
136 if(property.check("Kd"))
137 {p_Kd = property.find("Kd").asFloat64();}
138 double p_Max=100;
139 if(property.check("MaxValue"))
140 {p_Max = property.find("MaxValue").asFloat64();}
141 yarp::sig::Vector p_Wp(1,1);
142 yarp::sig::Vector p_Wi(1,1);
143 yarp::sig::Vector p_Wd(1,1);
144 yarp::sig::Vector p_N (1,10);
145 yarp::sig::Vector p_Tt (1,1);
146 yarp::sig::Matrix p_Lim (1,2);
147 yInfo() << "Using gains Kp:" << p_Kp[0] << " Ki:"<<p_Ki[0] << " Kd:"<<p_Kd[0] << " Max:" << p_Max;
148 p_Lim[0][0]=-p_Max;
149 p_Lim[0][1]=+p_Max;
150 ppid = new iCub::ctrl::parallelPID(p_Ts, p_Kp, p_Ki, p_Kd, p_Wp, p_Wi, p_Wd, p_N, p_Tt, p_Lim);
151
152 if (m_requested_filename=="auto")
153 {
154 char buff[50];
155 m_requested_filename="ext_";
156 m_requested_filename+=(m_robotName+"_");
157 m_requested_filename+=(m_partName+"_");
158 sprintf(buff,"%.3f",p_Kp[0]);
159 m_requested_filename+=("Kp_"+std::string(buff)+"_");
160 sprintf(buff,"%.3f",p_Ki[0]);
161 m_requested_filename+=("Ki_"+std::string(buff)+"_");
162 sprintf(buff,"%.3f",p_Kd[0]);
163 m_requested_filename+=("Kdi_"+std::string(buff)+"_");
164 sprintf(buff,"%.3f",m_pospid_vup);
165 m_requested_filename+=("Vup_"+std::string(buff)+"_");
166 sprintf(buff,"%.3f",m_pospid_vdown);
167 m_requested_filename+=("Vdown_"+std::string(buff)+"_");
168 sprintf(buff,"%.1f",m_step);
169 m_requested_filename+=("step_"+std::string(buff)+".txt");
170 }
171 yDebug() << "File: " << m_requested_filename << " will be used";
172
173 return true;
174}

◆ tearDown()

void PositionControlAccuracyExernalPid::tearDown ( )
virtual

Definition at line 176 of file PositionControlAccuracyExternalPid.cpp.

177{
178 if (m_jointsList) { delete [] m_jointsList; m_jointsList = 0; }
179 if (m_zeros) { delete [] m_zeros; m_zeros = 0; }
180 if (m_encoders) { delete [] m_encoders; m_encoders = 0; }
181 if (dd) {delete dd; dd =0;}
182}

The documentation for this class was generated from the following files: