icub-test
Loading...
Searching...
No Matches
jointLimits.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 "jointLimits.h"
31
32#include <stdio.h>
33
34using namespace robottestingframework;
35using namespace yarp::os;
36using namespace yarp::dev;
37using namespace yarp::math;
38
39// prepare the plugin
40ROBOTTESTINGFRAMEWORK_PREPARE_PLUGIN(JointLimits)
41
42JointLimits::JointLimits() : yarp::robottestingframework::TestCase("JointLimits") {
43 jointsList=0;
44 dd=0;
45 ipos=0;
46 icmd=0;
47 iimd=0;
48 ienc=0;
49 ilim=0;
50 enc_jnt=0;
51 original_pids=0;
52 pids_saved=false;
53}
54
55JointLimits::~JointLimits() { }
56
57bool JointLimits::setup(yarp::os::Property& property) {
58 if(property.check("name"))
59 setName(property.find("name").asString());
60
61 // updating parameters
62 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("robot"), "The robot name must be given as the test parameter!");
63 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("part"), "The part name must be given as the test parameter!");
64 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("joints"), "The joints list must be given as the test parameter!");
65 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("home"), "The home position must be given as the test parameter!");
66 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("speed"), "The positionMove reference speed must be given as the test parameter!");
67 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("outOfBoundPosition"), "The outOfBoundPosition parameter must be given as the test parameter!");
68 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("outputLimitPercent"), "The outputLimitPercent must be given as the test parameter!");
69 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(property.check("tolerance"), " The max error tolerance must be given as the test parameter!");
70
71 robotName = property.find("robot").asString();
72 partName = property.find("part").asString();
73
74 char buff[500];
75 sprintf(buff, "setting up test for %s", partName.c_str());
76 ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
77
78 Bottle* jointsBottle = property.find("joints").asList();
79 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(jointsBottle!=0,"unable to parse joints parameter");
80
81 Bottle* homeBottle = property.find("home").asList();
82 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(homeBottle!=0,"unable to parse zero parameter");
83
84 Bottle* speedBottle = property.find("speed").asList();
85 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(speedBottle!=0,"unable to parse speed parameter");
86
87 Bottle* outOfBoundPosition = property.find("outOfBoundPosition").asList();
88 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(outOfBoundPosition != 0, "unable to parse outOfBoundPosition parameter");
89
90 Bottle* outputLimitBottle = property.find("outputLimitPercent").asList();
91 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(outputLimitBottle!=0,"unable to parse speed parameter");
92
93 tolerance = property.find("tolerance").asFloat64();
94 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(tolerance>=0,"invalid tolerance");
95
96 Bottle* toleranceListBottle = property.find("toleranceList").asList(); //optional param
97
98 Property options;
99 options.put("device", "remote_controlboard");
100 options.put("remote", "/"+robotName+"/"+partName);
101 options.put("local", "/jointsLimitsTest/"+robotName+"/"+partName);
102
103 dd = new PolyDriver(options);
104 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->isValid(),"Unable to open device driver");
105 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ienc),"Unable to open encoders interface");
106 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipos),"Unable to open position interface");
107 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(icmd),"Unable to open control mode interface");
108 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(iimd),"Unable to open interaction mode interface");
109 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ilim),"Unable to open limits interface");
110 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(dd->view(ipid),"Unable to open pid interface");
111
112 if (!ienc->getAxes(&n_part_joints))
113 {
114 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("unable to get the number of joints of the part");
115 }
116
117 int n_cmd_joints = jointsBottle->size();
118 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");
119 for (int i=0; i <n_cmd_joints; i++) jointsList.push_back(jointsBottle->get(i).asInt32());
120
121 enc_jnt.resize(n_part_joints);
122 max_lims.resize(n_cmd_joints);
123 min_lims.resize(n_cmd_joints);
124
125 home.resize (n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) home[i]=homeBottle->get(i).asFloat64();
126 speed.resize(n_cmd_joints); for (int i=0; i< n_cmd_joints; i++) speed[i]=speedBottle->get(i).asFloat64();
127 outputLimit.resize(n_cmd_joints);for (int i=0; i< n_cmd_joints; i++) outputLimit[i]=outputLimitBottle->get(i).asFloat64();
128 outOfBoundPos.resize(n_cmd_joints); for (int i = 0; i < n_cmd_joints; i++) { outOfBoundPos[i] = outOfBoundPosition->get(i).asFloat64(); ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(outOfBoundPos[i] > 0 , "outOfBoundPosition must be > 0"); }
129 toleranceList.resize(n_cmd_joints);
130 for (int i = 0; i < n_cmd_joints; i++)
131 {
132 if(toleranceListBottle)
133 {
134 toleranceList[i] = toleranceListBottle->get(i).asFloat64();
135 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(toleranceList[i] >= 0 , "toleranceList must be > 0");
136 }
137 else
138 toleranceList[i] = tolerance;
139 }
140
141 original_pids = new yarp::dev::Pid[n_cmd_joints];
142 for (unsigned int i=0; i<jointsList.size(); i++)
143 {
144 ipid->getPid(yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_POSITION, (int)jointsList[i],&original_pids[i]);
145 }
146 pids_saved=true;
147
148 for (unsigned int i=0; i<jointsList.size(); i++)
149 {
150 yarp::dev::Pid p = original_pids[i];
151 p.max_output = p.max_output/100*outputLimit[i];
152 p.max_int = p.max_int/100*outputLimit[i];
153 ipid->setPid(yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_POSITION, (int)jointsList[i],p);
154 yarp::os::Time::delay(0.010);
155 yarp::dev::Pid t;
156 ipid->getPid(yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_POSITION, (int)jointsList[i],&t);
157
158 //since pid values are double, the returned values may differ from those sent due to conversion.
159 if (fabs(t.max_output-p.max_output) > 1.0 ||
160 fabs(t.max_int-p.max_int) > 1.0 ||
161 fabs(t.kp-p.kp) > 1.0 ||
162 fabs(t.kd-p.kd) > 1.0 ||
163 fabs(t.ki-p.ki) > 1.0)
164 {
165 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Unable to set output limits");
166 }
167
168 }
169 return true;
170}
171
172void JointLimits::tearDown()
173{
174 if (original_pids)
175 {
176 if (pids_saved)
177 {
178 for (unsigned int i=0; i<jointsList.size(); i++)
179 {
180 ipid->setPid(yarp::dev::PidControlTypeEnum::VOCAB_PIDTYPE_POSITION, (int)jointsList[i],original_pids[i]);
181 }
182 }
183 delete[] original_pids; original_pids=0;
184 }
185 if (dd) {delete dd; dd =0;}
186}
187
188void JointLimits::setMode(int desired_mode)
189{
190 for (unsigned int i=0; i<jointsList.size(); i++)
191 {
192 icmd->setControlMode((int)jointsList[i],desired_mode);
193 iimd->setInteractionMode((int)jointsList[i],VOCAB_IM_STIFF);
194 yarp::os::Time::delay(0.010);
195 }
196
197 int cmode;
198 yarp::dev::InteractionModeEnum imode;
199 int timeout = 0;
200
201 while (1)
202 {
203 int ok=0;
204 for (unsigned int i=0; i<jointsList.size(); i++)
205 {
206 icmd->getControlMode ((int)jointsList[i],&cmode);
207 iimd->getInteractionMode((int)jointsList[i],&imode);
208 if (cmode==desired_mode && imode==VOCAB_IM_STIFF) ok++;
209 }
210 if (ok==jointsList.size()) break;
211 if (timeout>100)
212 {
213 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Unable to set control mode/interaction mode");
214 }
215 yarp::os::Time::delay(0.2);
216 timeout++;
217 }
218}
219
220void JointLimits::goTo(yarp::sig::Vector position)
221{
222 for (unsigned int i=0; i<jointsList.size(); i++)
223 {
224 ipos->setRefSpeed((int)jointsList[i],speed[i]);
225 ipos->positionMove((int)jointsList[i],position[i]);
226 }
227
228 int timeout = 0;
229 while (1)
230 {
231 int in_position=0;
232 for (unsigned int i=0; i<jointsList.size(); i++)
233 {
234 double tmp=0;
235 ienc->getEncoder((int)jointsList[i],&tmp);
236 if (fabs(tmp-position[i])<toleranceList[i]) in_position++;
237 }
238 if (in_position==jointsList.size()) break;
239 if (timeout>100)
240 {
241 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Timeout while reaching desired position");
242 }
243 yarp::os::Time::delay(0.2);
244 timeout++;
245 }
246}
247
248bool JointLimits::goToSingle(int i, double pos, double *reached_pos)
249{
250 ipos->setRefSpeed((int)jointsList[i],speed[i]);
251 ipos->positionMove((int)jointsList[i],pos);
252 double tmp=0;
253
254 int timeout = 0;
255 while (1)
256 {
257 ienc->getEncoder((int)jointsList[i],&tmp);
258 if (fabs(tmp-pos)<toleranceList[i]) break;
259
260 if (timeout>100)
261 {
262 if(reached_pos != NULL)
263 {
264 *reached_pos = tmp;
265 }
266 return(false);
267 }
268
269 yarp::os::Time::delay(0.2);
270 timeout++;
271 }
272 if(reached_pos != NULL)
273 {
274 *reached_pos = tmp;
275 }
276 return(true);
277}
278
279bool JointLimits::goToSingleExceed(int i, double position_to_reach, double limit, double reachedLimit, double *reached_pos)
280{
281 ipos->setRefSpeed((int)jointsList[i], speed[i]);
282 ipos->positionMove((int)jointsList[i], position_to_reach);
283 double tmp = 0;
284 bool excededLimit = false;
285 int timeout = 0;
286 double limitToCheck;
287 if(fabs(reachedLimit-limit)>toleranceList[i])
288 {
289 //if i'm here joint did NOT reached the limit and I would check joint doesn't exced reached limit
290 limitToCheck = reachedLimit;
291 }
292 else
293 {
294 limitToCheck = limit;
295 }
296 while (1)
297 {
298 ienc->getEncoder((int)jointsList[i], &tmp);
299 if(fabs(tmp - limitToCheck)>toleranceList[i])
300 {
301 excededLimit = true;
302 //ROBOTTESTINGFRAMEWORK_TEST_REPORT (Asserter::format("j %d exced limitTocheck %f: reached %f",(int)jointsList[i], limitToCheck, tmp));
303 break;
304 }
305 if (fabs(tmp - position_to_reach)<toleranceList[i])
306 {
307 excededLimit = true;
308 //ROBOTTESTINGFRAMEWORK_TEST_REPORT (Asserter::format("j %d is near position_to_reach %f: reached %f",(int)jointsList[i], position_to_reach, tmp));
309 break;
310 }
311
312 if (timeout>50) break;
313 yarp::os::Time::delay(0.2);
314 timeout++;
315 }
316
317 *reached_pos = tmp;
318
319/* if (fabs(tmp - position_to_reach)<toleranceList[i])
320 {
321 //I reached the out of bound target. That's bad!
322 return (true);
323 }
324 if (fabs(tmp - limit)<toleranceList[i])
325 {
326 //I'm still near the joint limit. That's fine.
327 return (false);
328 }
329 //I dont know where I am, that's bad!
330 return(true);
331*/
332
333 if( excededLimit)
334 return (true);
335 else
336 return(false);
337}
338
339
340void JointLimits::run()
341{
342 char buff[500];
343 setMode(VOCAB_CM_POSITION);
344 ROBOTTESTINGFRAMEWORK_TEST_REPORT("all joints are going to home....");
345 goTo(home);
346
347 for (unsigned int i=0; i<jointsList.size(); i++)
348 {
349 ilim->getLimits((int)jointsList[i],&min_lims[i],&max_lims[i]);
350 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(max_lims[i]!=min_lims[i],"Invalid limit: max==min?");
351 ROBOTTESTINGFRAMEWORK_ASSERT_ERROR_IF_FALSE(max_lims[i]>min_lims[i],"Invalid limit: max<min?");
352 if (max_lims[i] == 0 && min_lims[i] == 0) ROBOTTESTINGFRAMEWORK_ASSERT_ERROR("Invalid limit: max==min==0");
353 }
354
355 for (unsigned int i=0; i<jointsList.size(); i++)
356 {
357 bool res;
358 double reached_pos=0;
359 double excededpos_reached = 0;
360
361 //1) Check max limit
362 sprintf(buff,"Testing if max limit is reachable, joint %d, max limit: %f",(int)jointsList[i],max_lims[i]);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
363 //check that max_limit is reachable
364 res = goToSingle(i, max_lims[i], &reached_pos);
365 ROBOTTESTINGFRAMEWORK_TEST_CHECK (res, Asserter::format("joint %d moved to max limit: %f reached: %f", (int)jointsList[i], max_lims[i], reached_pos));
366 //if(!res)
367 //{
368 // goToSingle(i,home[i], NULL); //I need to go to home in order to leave joint in safe position for further tests (other body parts)
369 // sprintf(buff, "Timeout while reaching desired position(%.2f). Reached pos=%.2f", max_lims[i], reached_pos);ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
370 //}
371 //else { sprintf(buff, "Test successfull, joint %d, max limit: %f reached: %f", (int)jointsList[i], max_lims[i], reached_pos); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff); }
372
373 //2) check that max_limit + outOfBoundPos is NOT reachable
374 sprintf(buff, "Testing that max limit cannot be exceeded, joint %d, max limit: %f", (int)jointsList[i], max_lims[i]); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
375 res = goToSingleExceed(i, max_lims[i] + outOfBoundPos[i], max_lims[i], reached_pos, &excededpos_reached);
376 ROBOTTESTINGFRAMEWORK_TEST_CHECK (!res, Asserter::format("check if joint %d desn't exced max limit. target was: %f reached: %f, limit %f ", (int)jointsList[i], max_lims[i] + outOfBoundPos[i], excededpos_reached, max_lims[i]));
377 //if (res)
378 //{
379 // goToSingle(i, home[i], NULL); //I need to go to home in order to leave joint in safe position for further tests (other body parts)
380 // sprintf(buff, "Limit execeeded! Limit was (%.2f). Reached pos=%.2f", max_lims[i], reached_pos); ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
381 //}
382 //else { sprintf(buff, "Test successfull, joint %d, target was: %f reached: %f, limit %f ", (int)jointsList[i], max_lims[i] + outOfBoundPos[i], reached_pos, max_lims[i]); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff); }
383
384 //3) Check min limit
385 //check that min_limit is reachable
386 sprintf(buff,"Testing if min limit is reachable, joint %d, min limit: %f",(int)jointsList[i],min_lims[i]);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
387 res = goToSingle(i, min_lims[i], &reached_pos);
388 ROBOTTESTINGFRAMEWORK_TEST_CHECK (res, Asserter::format("joint %d moved to min limit: %f reached: %f", (int)jointsList[i], min_lims[i], reached_pos));
389
390 /*if(!res)
391 {
392 goToSingle(i,home[i], NULL);
393 sprintf(buff, "Timeout while reaching desired position(%.2f). Reached pos=%.2f", min_lims[i], reached_pos);ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
394 }
395 else { sprintf(buff, "Test successfull, joint %d, min limit: %f reached: %f", (int)jointsList[i], min_lims[i], reached_pos); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff); }*/
396
397 //4) check that min_limit - outOfBoundPos is NOT reachable
398 sprintf(buff, "Testing that min limit cannot be exceeded, joint %d, min limit: %f", (int)jointsList[i], min_lims[i]); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
399 res = goToSingleExceed(i, min_lims[i] - outOfBoundPos[i], min_lims[i], reached_pos, & excededpos_reached);
400 ROBOTTESTINGFRAMEWORK_TEST_CHECK (!res, Asserter::format("check if joint %d desn't exced min limit. target was: %f reached: %f, limit %f ", (int)jointsList[i], min_lims[i] - outOfBoundPos[i], excededpos_reached, min_lims[i]));
401
402 //if (res)
403 //{
404 // goToSingle(i, home[i], NULL); //I need to go to home in order to leave joint in safe position for further tests (other body parts)
405 // sprintf(buff, "Limit execeeded! Limit was (%.2f). Reached pos=%.2f", min_lims[i], reached_pos); ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
406 //}
407 //else { sprintf(buff, "Test successfull, joint %d, target was: %f reached: %f, limit %f ", (int)jointsList[i], min_lims[i] - outOfBoundPos[i], reached_pos, min_lims[i]); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff); }
408
409 //5) Check home position
410 sprintf(buff,"Testing joint %d, homing to: %f",(int)jointsList[i],home[i]);ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff);
411 res = goToSingle(i, home[i], &reached_pos);
412 if(!res)
413 {
414 sprintf(buff, "Timeout while reaching desired position(%.2f). Reached pos=%.2f", home[i], reached_pos);ROBOTTESTINGFRAMEWORK_ASSERT_ERROR(buff);
415 }
416 else{ sprintf(buff, "Homing joint %d complete", (int)jointsList[i]); ROBOTTESTINGFRAMEWORK_TEST_REPORT(buff); }
417
418 }
419 ienc->getEncoders(enc_jnt.data());
420 ROBOTTESTINGFRAMEWORK_TEST_REPORT("Test ends. All joints are going to home....");
421 goTo(home);
422 yarp::os::Time::delay(2.0);
423}
Check if the software joint limits are properly set.
Definition jointLimits.h:74