icub-test
All Data Structures Modules Pages
MotorStiction.cpp
1 /*
2  * iCub Robot Unit Tests (Robot Testing Framework)
3  *
4  * Copyright (C) 2015-2019 Istituto Italiano di Tecnologia (IIT)
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <math.h>
22 #include <robottestingframework/TestAssert.h>
23 #include <robottestingframework/dll/Plugin.h>
24 #include <yarp/os/Time.h>
25 #include <yarp/math/Math.h>
26 #include <yarp/os/Property.h>
27 #include <fstream>
28 #include <algorithm>
29 #include <cstdlib>
30 #include "MotorStiction.h"
31 
32 //example1 -v -t MotorStiction.dll -p "--robot icub --part left_arm --joints ""(4)"" --home ""(45)"" --outputStep ""(0.5)"" --outputMax ""(50)"" --outputDelay ""(2.0)"" --threshold ""(5.0)"" "
33 
34 using namespace robottestingframework;
35 using namespace yarp::os;
36 using namespace yarp::dev;
37 
38 // prepare the plugin
39 ROBOTTESTINGFRAMEWORK_PREPARE_PLUGIN(MotorStiction)
40 
41 MotorStiction::MotorStiction() : yarp::robottestingframework::TestCase("MotorStiction") {
42  jointsList=0;
43  dd=0;
44  ipos=0;
45  iamp=0;
46  icmd=0;
47  iimd=0;
48  ienc=0;
49  ipwm = 0;
50 }
51 
52 MotorStiction::~MotorStiction() { }
53 
54 bool MotorStiction::setup(yarp::os::Property& property) {
55  if(property.check("name"))
56  setName(property.find("name").asString());
57 
58  // updating parameters
59  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("robot"), "The robot name must be given as the test parameter!");
60  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("part"), "The part name must be given as the test parameter!");
61  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("joints"), "The joints list must be given as the test parameter!");
62  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("home"), "The home position must be given as the test parameter!");
63 
64  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("outputStep"), "The output_step must be given as the test parameter!");
65  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("outputDelay") , "The output_delay must be given as the test parameter!");
66  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("outputMax"), "The output_max must be given as the test parameter!");
67  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("threshold"), "The threshold must be given as the test parameter!");
68  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("repeat"), "The repeat must be given as the test parameter!");
69 
70  robotName = property.find("robot").asString();
71  partName = property.find("part").asString();
72 
73  repeat = property.find("repeat").asInt32();
74  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(repeat>=0,"repeat must be greater than zero");
75 
76  Bottle* homeBottle = property.find("home").asList();
77  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(homeBottle!=0,"unable to parse zero parameter");
78 
79  Bottle* jointsBottle = property.find("joints").asList();
80  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(jointsBottle!=0,"unable to parse joints parameter");
81 
82  Bottle* output_step_Bottle = property.find("outputStep").asList();
83  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(output_step_Bottle!=0,"unable to parse joints parameter");
84 
85  Bottle* output_delay_Bottle = property.find("outputDelay").asList();
86  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(output_delay_Bottle!=0,"unable to parse joints parameter");
87 
88  Bottle* output_max_Bottle = property.find("outputMax").asList();
89  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(output_max_Bottle!=0,"unable to parse joints parameter");
90 
91  Bottle* threshold_Bottle = property.find("threshold").asList();
92  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(threshold_Bottle!=0,"unable to parse joints parameter");
93 
94  Property options;
95  options.put("device", "remote_controlboard");
96  options.put("remote", "/"+robotName+"/"+partName);
97  options.put("local", "/MotorStictionTest/"+robotName+"/"+partName);
98 
99  dd = new PolyDriver(options);
100  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->isValid(),"Unable to open device driver");
101  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipwm),"Unable to open pwm control interface");
102  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ienc),"Unable to open encoders interface");
103  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(iamp),"Unable to open ampliefier interface");
104  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipos),"Unable to open position interface");
105  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(icmd),"Unable to open control mode interface");
106  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(iimd),"Unable to open interaction mode interface");
107  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ilim),"Unable to open limits interface");
108 
109  if (!ienc->getAxes(&n_part_joints))
110  {
111  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("unable to get the number of joints of the part");
112  }
113 
114  int n_cmd_joints = jointsBottle->size();
115  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(n_cmd_joints>0 && n_cmd_joints<=n_part_joints,"invalid number of joints, it must be >0 & <= number of part joints");
116  for (int i=0; i <n_cmd_joints; i++) jointsList.push_back(jointsBottle->get(i).asInt32());
117 
118  home.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) home[i]=homeBottle->get(i).asFloat64();
119  opl_step.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) opl_step[i]=output_step_Bottle->get(i).asFloat64();
120  opl_delay.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) opl_delay[i]=output_delay_Bottle->get(i).asFloat64();
121  opl_max.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) opl_max[i]=output_max_Bottle->get(i).asFloat64();
122  movement_threshold.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) movement_threshold[i]=threshold_Bottle->get(i).asFloat64();
123 
124  max_lims.resize(n_cmd_joints);
125  min_lims.resize(n_cmd_joints);
126  for (int i=0; i <n_cmd_joints; i++) ilim->getLimits((int)jointsList[i],&min_lims[i],&max_lims[i]);
127 
128  return true;
129 }
130 
131 void MotorStiction::tearDown()
132 {
133  char buff[500];
134  sprintf(buff,"Closing test module");ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
135  setMode(VOCAB_CM_POSITION,VOCAB_IM_STIFF);
136  verifyMode(VOCAB_CM_POSITION,VOCAB_IM_STIFF,"test0");
137  goHome();
138  if (dd) {delete dd; dd =0;}
139 }
140 
141 void MotorStiction::setMode(int desired_control_mode, yarp::dev::InteractionModeEnum desired_interaction_mode)
142 {
143  for (unsigned int i=0; i<jointsList.size(); i++)
144  {
145  icmd->setControlMode((int)jointsList[i],desired_control_mode);
146  iimd->setInteractionMode((int)jointsList[i],desired_interaction_mode);
147  yarp::os::Time::delay(0.010);
148  }
149 }
150 
151 void MotorStiction::setModeSingle(int i, int desired_control_mode, yarp::dev::InteractionModeEnum desired_interaction_mode)
152 {
153  icmd->setControlMode((int)jointsList[i],desired_control_mode);
154  iimd->setInteractionMode((int)jointsList[i],desired_interaction_mode);
155  yarp::os::Time::delay(0.010);
156 }
157 
158 void MotorStiction::verifyMode(int desired_control_mode, yarp::dev::InteractionModeEnum desired_interaction_mode, std::string title)
159 {
160  int cmode;
161  yarp::dev::InteractionModeEnum imode;
162  int timeout = 0;
163 
164  while (1)
165  {
166  int ok=0;
167  for (unsigned int i=0; i<jointsList.size(); i++)
168  {
169  icmd->getControlMode ((int)jointsList[i],&cmode);
170  iimd->getInteractionMode((int)jointsList[i],&imode);
171  if (cmode==desired_control_mode && imode==desired_interaction_mode) ok++;
172  }
173  if (ok==jointsList.size()) break;
174  if (timeout>100)
175  {
176  char sbuf[500];
177  sprintf(sbuf,"Test (%s) failed: current mode is (%d,%d), it should be (%d,%d)",title.c_str(), desired_control_mode,desired_interaction_mode,cmode,imode);
178  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(sbuf);
179  }
180  yarp::os::Time::delay(0.2);
181  timeout++;
182  }
183  char sbuf[500];
184  sprintf(sbuf,"Test (%s) passed: current mode is (%d,%d)",title.c_str(), desired_control_mode,desired_interaction_mode);
185  ROBOTTESTINGFRAMEWORK_TEST_REPORT(sbuf);
186 }
187 
188 void MotorStiction::goHome()
189 {
190  for (unsigned int i=0; i<jointsList.size(); i++)
191  {
192  ipos->setRefSpeed((int)jointsList[i],20.0);
193  ipos->positionMove((int)jointsList[i],home[i]);
194  yarp::os::Time::delay(0.010);
195  }
196 
197  char buff [500];
198  sprintf(buff,"Homing the whole part");ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
199 
200  int in_position=0;
201  for (unsigned int i=0; i<jointsList.size(); i++)
202  {
203  double time_started = yarp::os::Time::now();
204  while (1)
205  {
206  double pos;
207  ienc->getEncoder((int)jointsList[i],&pos);
208  if (fabs(pos-home[i])<1.0) break;
209  if (yarp::os::Time::now()-time_started>20)
210  {
211  sprintf(buff,"Timeout while reaching zero position, joint %d, curr_enc %f, home %f", (int)jointsList[i],pos,home[i]);
212  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
213  }
214  }
215  }
216 
217  sprintf(buff,"Homing succesfully completed");ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
218 }
219 
220 void MotorStiction::saveToFile(std::string filename, yarp::os::Bottle &b)
221 {
222  std::fstream fs;
223  fs.open (filename.c_str(), std::fstream::out);
224 
225  for (int i=0; i<b.size(); i++)
226  {
227  std::string s = b.get(i).toString();
228  std::replace(s.begin(), s.end(), '(', ' ');
229  std::replace(s.begin(), s.end(), ')', ' ');
230  fs << s << std::endl;
231  }
232 
233  fs.close();
234 }
235 
236 void MotorStiction::OplExecute(int i, std::vector<yarp::os::Bottle>& dataToPlotList, stiction_data& current_test, bool positive_sign)
237 {
238  char buff[500];
239  double time = yarp::os::Time::now();
240  double time_old = yarp::os::Time::now();
241  double enc=0;
242  double start_enc=0;
243  ienc->getEncoder((int)jointsList[i],&enc);
244  ienc->getEncoder((int)jointsList[i],&start_enc);
245  bool not_moving = true;
246  double opl=0;
247  setMode(VOCAB_CM_PWM, VOCAB_IM_STIFF);
248  ipwm->setRefDutyCycle((int)jointsList[i], opl);
249  double last_opl_cmd=yarp::os::Time::now();
250  Bottle dataToPlot;
251 
252  while (not_moving)
253  {
254  Bottle& row = dataToPlot.addList();
255  Bottle& v1 = row.addList();
256  Bottle& v2 = row.addList();
257 
258  ipwm->setRefDutyCycle((int)jointsList[i],opl);
259  ienc->getEncoder((int)jointsList[i],&enc);
260 
261  //sprintf(buff,"%f %f %f %f",enc,start_enc,fabs(enc-start_enc),movement_threshold[i]);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
262 
263  if (fabs(enc-start_enc)>movement_threshold[i])
264  {
265  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
266  not_moving=false;
267  if (positive_sign) {current_test.pos_opl=opl; current_test.pos_test_passed=true;}
268  else {current_test.neg_opl=opl; current_test.neg_test_passed=true;}
269  dataToPlotList.push_back(dataToPlot);
270  sprintf(buff,"Test success (output=%f)",opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
271  }
272  else if (opl>=opl_max[i])
273  {
274  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
275  not_moving=false;
276  if (positive_sign) {current_test.pos_opl=opl; current_test.pos_test_passed=false;}
277  else {current_test.neg_opl=opl; current_test.neg_test_passed=false;}
278  dataToPlotList.push_back(dataToPlot);
279  sprintf(buff,"Test failed failed because max output was reached(output=%f)",opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
280  }
281  else if (fabs(enc-max_lims[i]) < 1.0 ||
282  fabs(enc-min_lims[i]) < 1.0 )
283  {
284  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
285  not_moving=false;
286  if (positive_sign) {current_test.pos_opl=opl; current_test.pos_test_passed=false;}
287  else {current_test.neg_opl=opl; current_test.neg_test_passed=false;}
288  dataToPlotList.push_back(dataToPlot);
289  sprintf(buff,"Test failed because hw limit was touched (enc=%f)",enc);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
290  }
291 
292  if (yarp::os::Time::now()-last_opl_cmd>opl_delay[i])
293  {
294  if (positive_sign)
295  {opl+=opl_step[i];}
296  else
297  {opl-=opl_step[i];}
298  last_opl_cmd=yarp::os::Time::now();
299  }
300 
301  time = yarp::os::Time::now();
302  v1.addFloat64(time);
303  v2.addFloat64(enc);
304  v2.addFloat64(opl);
305  yarp::os::Time::delay(0.010);
306 
307  if (time-time_old>5.0 && not_moving==true)
308  {
309  sprintf(buff,"test in progress on joint %d, current output value = %f",(int)jointsList[i],opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
310  time_old=time;
311  }
312  }
313 }
314 
315 void MotorStiction::OplExecute2(int i, std::vector<yarp::os::Bottle>& dataToPlotList, stiction_data& current_test, bool positive_sign)
316 {
317  char buff[500];
318  double time = yarp::os::Time::now();
319  double time_old = yarp::os::Time::now();
320  double enc=0;
321  double start_enc=0;
322  ienc->getEncoder((int)jointsList[i],&enc);
323  ienc->getEncoder((int)jointsList[i],&start_enc);
324  bool not_moving = true;
325  double opl=0;
326  setMode(VOCAB_CM_PWM,VOCAB_IM_STIFF);
327  ipwm->setRefDutyCycle((int)jointsList[i], opl);
328  double last_opl_cmd=yarp::os::Time::now();
329  Bottle dataToPlot;
330 
331  while (not_moving)
332  {
333  Bottle& row = dataToPlot.addList();
334  Bottle& v1 = row.addList();
335  Bottle& v2 = row.addList();
336 
337  ipwm->setRefDutyCycle((int)jointsList[i], opl);
338  ienc->getEncoder((int)jointsList[i],&enc);
339 
340  //sprintf(buff,"%f %f %f %f",enc,start_enc,fabs(enc-start_enc),movement_threshold[i]);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
341 
342  if (opl>=opl_max[i])
343  {
344  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
345  not_moving=false;
346  if (positive_sign) {current_test.pos_opl=opl; current_test.pos_test_passed=false;}
347  else {current_test.neg_opl=opl; current_test.neg_test_passed=false;}
348  dataToPlotList.push_back(dataToPlot);
349  sprintf(buff,"Test failed failed because max output was reached(output=%f)",opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
350  }
351  else if (fabs(enc-max_lims[i]) < 1.0 ||
352  fabs(enc-min_lims[i]) < 1.0 )
353  {
354  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
355  not_moving=false;
356  if (positive_sign) {current_test.pos_opl=opl; current_test.pos_test_passed=true;}
357  else {current_test.neg_opl=opl; current_test.neg_test_passed=true;}
358  dataToPlotList.push_back(dataToPlot);
359  sprintf(buff,"Test success (output=%f)",opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
360  }
361 
362  if (yarp::os::Time::now()-last_opl_cmd>opl_delay[i])
363  {
364  if (positive_sign)
365  {opl+=opl_step[i];}
366  else
367  {opl-=opl_step[i];}
368  last_opl_cmd=yarp::os::Time::now();
369  }
370 
371  time = yarp::os::Time::now();
372  v1.addFloat64(time);
373  v2.addFloat64(enc);
374  v2.addFloat64(opl);
375  yarp::os::Time::delay(0.010);
376 
377  if (time-time_old>5.0 && not_moving==true)
378  {
379  sprintf(buff,"test in progress on joint %d, current output value = %f",(int)jointsList[i],opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
380  time_old=time;
381  }
382  }
383 }
384 
385 void MotorStiction::run()
386 {
387  //yarp::os::Time::delay(10);
388 
389  char buff[500];
390  std::vector<Bottle> dataToPlotList;
391 
392  setMode(VOCAB_CM_POSITION,VOCAB_IM_STIFF);
393  goHome();
394 
395  for (unsigned int i=0 ; i<jointsList.size(); i++)
396  {
397  for (int repeat_count=0; repeat_count<repeat; repeat_count++)
398  {
399  stiction_data current_test;
400  current_test.jnt=(int)jointsList[i];
401  current_test.cycle= repeat_count;
402 
403  setModeSingle(i,VOCAB_CM_PWM,VOCAB_IM_STIFF);
404  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
405 
406  sprintf(buff,"Testing joint %d, cycle %d, positive output",(int)jointsList[i],repeat_count);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
407  OplExecute(i,dataToPlotList,current_test, true);
408 
409  setMode(VOCAB_CM_POSITION,VOCAB_IM_STIFF);
410  goHome();
411 
412  setModeSingle(i, VOCAB_CM_PWM,VOCAB_IM_STIFF);
413  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
414 
415  sprintf(buff,"Testing joint %d, cycle %d, negative output",(int)jointsList[i],repeat_count);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
416  OplExecute(i,dataToPlotList,current_test, false);
417 
418  setMode(VOCAB_CM_POSITION,VOCAB_IM_STIFF);
419  goHome();
420 
421  //test cycle complete, save data
422  stiction_data_list.push_back(current_test);
423 
424  char filename[500];
425  sprintf (filename, "plot_stiction_%s_j%d_n_c%d.txt",partName.c_str(),(int)jointsList[i],repeat_count);
426  saveToFile(filename,dataToPlotList.rbegin()[0]); //last element
427  sprintf (filename, "plot_stiction_%s_j%d_p_c%d.txt",partName.c_str(),(int)jointsList[i],repeat_count);
428  saveToFile(filename,dataToPlotList.rbegin()[1]); //second last element
429  }
430  }
431 
432  goHome();
433 
434  for (unsigned int i=0 ; i<jointsList.size(); i++)
435  {
436  char filename[500];
437  char plotstring[1000];
438  sprintf (filename, "plot_stiction_j%d.txt",(int)jointsList[i]);
439  //gnuplot -e "unset key; plot for [col=1:6] 'C:\software\icub-tests\build\plugins\Debug\plot.txt' using col with lines" -persist
440  sprintf (plotstring, "gnuplot -e \" unset key; plot for [col=1:%d] '%s' using col with lines \" -persist", n_part_joints,filename);
441  //system (plotstring);
442  }
443 
444  //stiction_data_list.size() include tests for all joints, multiple cycles
445  for (unsigned int i=0; i <stiction_data_list.size(); i++)
446  {
447  if (stiction_data_list[i].neg_test_passed==false)
448  {
449  char buff [500];
450  sprintf(buff, "test failed on joint %d, cycle %d, negative output value: %f",stiction_data_list[i].jnt,stiction_data_list[i].cycle,stiction_data_list[i].neg_opl);
451  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
452  }
453  else if (stiction_data_list[i].pos_test_passed==false)
454  {
455  char buff [500];
456  sprintf(buff, "test failed on joint %d, cycle %d, positive output value: %f",stiction_data_list[i].jnt,stiction_data_list[i].cycle,stiction_data_list[i].pos_opl);
457  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
458  }
459  }
460 
461 }