icub-test
motorEncodersSignCheck.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 
22 #include <robottestingframework/TestAssert.h>
23 #include <robottestingframework/dll/Plugin.h>
24 #include <yarp/os/Time.h>
25 #include <yarp/os/Property.h>
26 #include <algorithm>
27 #include "motorEncodersSignCheck.h"
28 #include "iostream"
29 
30 
31 using namespace robottestingframework;
32 
33 using namespace yarp::os;
34 using namespace yarp::dev;
35 
36 // prepare the plugin
37 ROBOTTESTINGFRAMEWORK_PREPARE_PLUGIN(MotorEncodersSignCheck)
38 
39 MotorEncodersSignCheck::MotorEncodersSignCheck() : yarp::robottestingframework::TestCase("MotorEncodersSignCheck") {
40  jointsList=0;
41  dd=0;
42  icmd=0;
43  iimd=0;
44  ienc=0;
45  imenc=0;
46  jPosMotion=0;
47 }
48 
49 MotorEncodersSignCheck::~MotorEncodersSignCheck() { }
50 
51 bool MotorEncodersSignCheck::setup(yarp::os::Property& property) {
52 
53  if(property.check("name"))
54  setName(property.find("name").asString());
55 
56  // updating parameters
57  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("robot"), "The robot name must be given as the test parameter!");
58  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("part"), "The part name must be given as the test parameter!");
59  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("joints"), "The joints list must be given as the test parameter!");
60  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("home"), "The home position must be given as the test parameter!");
61 
62  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("pwmStep"), "The output_step must be given as the test parameter!");
63  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("pwmMax"), "The output_max must be given as the test parameter!");
64 
65  robotName = property.find("robot").asString();
66  partName = property.find("part").asString();
67 
68  Bottle* homeBottle = property.find("home").asList();
69  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(homeBottle!=0,"unable to parse zero parameter");
70 
71  Bottle* jointsBottle = property.find("joints").asList();
72  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(jointsBottle!=0,"unable to parse joints parameter");
73 
74  Bottle* pwm_step_Bottle = property.find("pwmStep").asList();
75  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(pwm_step_Bottle!=0,"unable to parse pwmStep parameter");
76 
77  Bottle* command_delay_Bottle = property.find("commandDelay").asList();
78  if(command_delay_Bottle==0)
79  ROBOTTESTINGFRAMEWORK_TEST_REPORT("Command delay not configured. default value (0.1 sec) will be used ");
80 
81 
82  Bottle* pwm_max_Bottle = property.find("pwmMax").asList();
83  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(pwm_max_Bottle!=0,"unable to parse joints parameter");
84 
85  Bottle* threshold_Bottle = property.find("PosThreshold").asList();
86  if(threshold_Bottle==0)
87  ROBOTTESTINGFRAMEWORK_TEST_REPORT("Position threshold not configured. default value (5 deg) will be used ");
88 
89  Bottle* pwm_start_Bottle = property.find("pwmStart").asList();
90  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(pwm_start_Bottle!=0,"unable to parse pwmStart parameter");
91 
92 
93  Property options;
94  options.put("device", "remote_controlboard");
95  options.put("remote", "/"+robotName+"/"+partName);
96  options.put("local", "/mEncSignCheckTest/"+robotName+"/"+partName);
97 
98  dd = new PolyDriver(options);
99  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->isValid(),"Unable to open device driver");
100  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipwm),"Unable to open pwm interface");
101  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ienc),"Unable to open encoders interface");
102  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(icmd),"Unable to open control mode interface");
103  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(iimd),"Unable to open interaction mode interface");
104  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(imenc),"Unable to open interaction mode interface");
105  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipid),"Unable to open ipidcontrol interface");
106 
107  if (!ienc->getAxes(&n_part_joints))
108  {
109  ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("unable to get the number of joints of the part");
110  }
111 
112  int n_cmd_joints = jointsBottle->size();
113  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");
114  jointsList.clear();
115  for (int i=0; i <n_cmd_joints; i++) jointsList.push_back(jointsBottle->get(i).asInt32());
116 
117  home.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) home[i]=homeBottle->get(i).asFloat64();
118  opl_step.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) opl_step[i]=pwm_step_Bottle->get(i).asFloat64();
119  opl_max.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) opl_max[i]=pwm_max_Bottle->get(i).asFloat64();
120  opl_start.resize(n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) opl_start[i]=pwm_start_Bottle->get(i).asFloat64();
121  pos_threshold.resize (n_cmd_joints);
122  if(threshold_Bottle!=0)
123  {
124  for (int i=0; i< n_cmd_joints; i++)
125  pos_threshold[i]=threshold_Bottle->get(i).asFloat64();
126  }
127  else
128  {
129  for (int i=0; i< n_cmd_joints; i++)
130  pos_threshold[i]=5;
131  }
132 
133  opl_delay.resize (n_cmd_joints);
134  if(command_delay_Bottle!=0)
135  {
136  for (int i=0; i< n_cmd_joints; i++)
137  opl_delay[i]=command_delay_Bottle->get(i).asFloat64();
138  }
139  else
140  {
141  for (int i=0; i< n_cmd_joints; i++)
142  opl_delay[i]=0.1;
143  }
144 
145  jPosMotion = new yarp::robottestingframework::jointsPosMotion(dd, jointsList);
146  jPosMotion->setTolerance(2.0);
147  jPosMotion->setTimeout(10); //10 sec
148 
149 
150  return true;
151 }
152 
153 void MotorEncodersSignCheck::tearDown()
154 {
155  char buff[500];
156  sprintf(buff,"Closing test module");ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
157  if(jPosMotion)
158  {
159  jPosMotion->setAndCheckPosControlMode();
160  jPosMotion->goTo(home);
161  }
162  delete jPosMotion;
163 
164  if (dd) {delete dd; dd =0;}
165 }
166 
167 
168 void MotorEncodersSignCheck::setModeSingle(int i, int desired_control_mode, yarp::dev::InteractionModeEnum desired_interaction_mode)
169 {
170  icmd->setControlMode((int)jointsList[i],desired_control_mode);
171  iimd->setInteractionMode((int)jointsList[i],desired_interaction_mode);
172  yarp::os::Time::delay(0.010);
173 }
174 
175 void MotorEncodersSignCheck::OplExecute(int i)
176 {
177  char buff[500];
178  double time = yarp::os::Time::now();
179  double time_old = yarp::os::Time::now();
180  double enc=0;
181  double start_enc=0;
182  double const delta = 10;
183  bool not_moving = true;
184  double opl=opl_start[i];
185 
186  ipwm->setRefDutyCycle((int)jointsList[i], opl);
187  double last_opl_cmd=yarp::os::Time::now();
188  yarp::os::Time::delay(3.0); //i need to wait a while because when i set ref output zero, joint may move (due to stiction or gravity) and I should save the position when pwm=0
189 
190  imenc->getMotorEncoder((int)jointsList[i],&start_enc);
191 
192 
193  while (not_moving)
194  {
195 
196  ipwm->setRefDutyCycle(jointsList[i], opl);
197  imenc->getMotorEncoder((int)jointsList[i],&enc);
198 
199  if(enc > start_enc+pos_threshold[i])
200  {
201  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
202  not_moving=false;
203  sprintf(buff,"TEST SUCCESS (pwm=%f) enc=%f start_enc=%f",opl, enc, start_enc);
204  ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
205  }
206  else if(enc < start_enc-pos_threshold[i])
207  {
208  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
209  not_moving=false;
210  ROBOTTESTINGFRAMEWORK_TEST_FAIL_IF_FALSE(0, robottestingframework::Asserter::format("because enc readings drecrease enc=%f start_enc=%f (output=%f)", enc, start_enc, opl));
211  }
212  else if (jPosMotion->checkJointLimitsReached((int)jointsList[i]))
213  {
214  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
215  not_moving=false;
216  ROBOTTESTINGFRAMEWORK_TEST_FAIL_IF_FALSE(0,robottestingframework::Asserter::format("Test failed because hw limit was touched (enc=%f)",enc));
217  }
218 
219  if (yarp::os::Time::now()-last_opl_cmd>opl_delay[i])
220  {
221  opl+=opl_step[i];
222  last_opl_cmd=yarp::os::Time::now();
223  }
224  if (opl>=opl_max[i])
225  {
226  ipwm->setRefDutyCycle((int)jointsList[i], 0.0);
227  not_moving=false;
228  ROBOTTESTINGFRAMEWORK_TEST_FAIL_IF_FALSE(0,robottestingframework::Asserter::format("Test failed failed because max output was reached(output=%f)",opl));
229  }
230 
231  yarp::os::Time::delay(0.010);
232 
233  if (time-time_old>5.0 && not_moving==true)
234  {
235  sprintf(buff,"test in progress on joint %d, current output value = %f",(int)jointsList[i],opl);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
236  time_old=time;
237  }
238  }
239 }
240 
241 void MotorEncodersSignCheck::run()
242 {
243 
244  char buff[500];
245  jPosMotion->setAndCheckPosControlMode();
246  jPosMotion->goTo(home);
247 
248 
249  for (unsigned int i=0 ; i<jointsList.size(); i++)
250  {
251  double posout=0;
252  ROBOTTESTINGFRAMEWORK_TEST_FAIL_IF_FALSE((ipid->getPidOutput(yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_POSITION, (int)jointsList[i], &posout)),
253  robottestingframework::Asserter::format(" getOutput j %d return false",(int)jointsList[i]));
254 
255  setModeSingle(i,VOCAB_CM_PWM,VOCAB_IM_STIFF);
256  ipwm->setRefDutyCycle((int)jointsList[i],0.0);
257 
258  ROBOTTESTINGFRAMEWORK_TEST_REPORT(robottestingframework::Asserter::format("Testing joint %d with starting pwm = %.2f. In position j had pwm = %.2f",(int)jointsList[i], opl_start[i], posout));
259  OplExecute(i);
260 
261  jPosMotion->setAndCheckPosControlMode();
262  jPosMotion->goTo(home);
263 
264  }
265 
266  }
This tests checks if the motor encoder readings increase when positive pwm is applayed to motor.