Loading [MathJax]/extensions/tex2jax.js
iCub-main
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
parametricCalibratorEth.cpp
Go to the documentation of this file.
1
2// -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
3
4/*
5 * Copyright (C) 2014 iCub Facility, Istituto Italiano di Tecnologia
6 * Authors: Alberto Cardellino, Marco Randazzo, Valentina Gaggero
7 * CopyPolicy: Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
8 *
9 */
10
11#include <yarp/os/Time.h>
12#include <yarp/dev/PolyDriver.h>
13
15#include <math.h>
16#include <algorithm>
17
18#include <yarp/os/LogStream.h>
19
20using namespace yarp::os;
21using namespace yarp::dev;
22
23const int PARK_TIMEOUT = 30;
24const double GO_TO_ZERO_TIMEOUT = 10;
26
27//#warning "Use extractGroup to verify size of parameters matches with number of joints, this will avoid crashes"
28static bool extractGroup(Bottle &input, Bottle &out, const std::string &key1, const std::string &txt, int size)
29{
30 size++; // size includes also the name of the parameter
31 Bottle &tmp=input.findGroup(key1.c_str(), txt.c_str());
32 if (tmp.isNull())
33 {
34 yError () << key1.c_str() << " not found\n";
35 return false;
36 }
37
38 if(tmp.size()!=size)
39 {
40 yError () << key1.c_str() << " incorrect number of entries in board.";
41 return false;
42 }
43
44 out=tmp;
45 return true;
46}
47
48
49// helper for parsing config file
50bool parametricCalibratorEth::parseSequenceGroup(yarp::os::Searchable &config, std::string sequence, std::vector<PositionSequence> &seqList)
51{
52 Bottle parkSeq_group = config.findGroup(sequence);
53 if (parkSeq_group.isNull())
54 {
55 // yWarning() << "parametricCalibrator " << deviceName << "Missing <" << sequence << "> group";
56 return false;
57 }
58
59 Bottle xtmp;
60 int numOfSeq = 0;
61
62 if(!extractGroup(parkSeq_group, xtmp, "numberOfSequences", "number of sequences listed ", 1))
63 {
64 return false;
65 }
66
67 numOfSeq = xtmp.get(1).asInt32();
68 // create space in vector of sequences
69 seqList.resize(numOfSeq);
70
71 if(numOfSeq < 0)
72 {
73 yError() << "ParametricCalibratorEth " << deviceName << "<numberOfSequences> must be a positive integer";
74 return false;
75 }
76
77 // read all sequences
78 for(int seq_idx=0; seq_idx<numOfSeq; seq_idx++)
79 {
80 char sequence_name[80];
81 snprintf(sequence_name, 80, "SEQUENCE_%d", seq_idx);
82
83 Bottle &seq_i = parkSeq_group.findGroup(sequence_name);
84 if(seq_i.isNull())
85 {
86 yError() << "ParametricCalibratorEth " << deviceName << "cannot find " << sequence_name;
87 return false;
88 }
89
90 // 1) Seq number
91 seqList.at(seq_idx).seq_num = seq_idx;
92
93 // 2) Read positions fromn config file
94 Bottle & poss = seq_i.findGroup("position", "desired parking position");
95 if (poss.isNull())
96 {
97 yError() << "ParametricCalibratorEth " << deviceName << ": <position> parameter not found for sequence " << sequence_name;
98 return false;
99 }
100
101 // 3) Read velocities fromn config file
102 Bottle &vels = seq_i.findGroup("velocity", "desired parking velocities");
103 if (vels.isNull())
104 {
105 yError() << "ParametricCalibratorEth " << deviceName << ": <velocity> parameter not found for sequence " << sequence_name;
106 return false;
107 }
108
109 if(( poss.size() -1 != n_joints) || (vels.size() -1 != n_joints))
110 {
111 yError() << "ParametricCalibratorEth " << deviceName << ": <position> or <velocity> parameter size for sequence " << sequence_name << " doesn not match the number of joint being calibrated.\n" << \
112 "Part joint number is " << n_joints << " while <position> size is " << poss.size()-1 << " and <velocity> size is " << vels.size()-1 << "; joint number is " << n_joints;
113 return false;
114 }
115
116 // Store data in memory
117 seqList[seq_idx].seq_num = seq_idx;
118 seqList[seq_idx].positions.reserve(n_joints);
119 seqList[seq_idx].velocities.reserve(n_joints);
120
121 for (int j = 1; j <n_joints+1; j++)
122 {
123 seqList[seq_idx].positions .push_back(poss.get(j).asFloat64());
124 seqList[seq_idx].velocities.push_back(vels.get(j).asFloat64());
125 }
126 }
127 return true;
128}
129
131 calibParams(nullptr),
132 original_max_pwm(nullptr),
133 limited_max_pwm(nullptr),
134 startupMaxPWM(nullptr),
135 currPos(nullptr),
136 currVel(nullptr),
137// legacyParkingPosition(0),
138 startupPosThreshold(0),
139 abortCalib(false),
140 isCalibrated(false),
141 skipCalibration(false),
142 clearHwFault(false),
143 skipReCalibration(false),
144 n_joints(0),
145 timeout_goToZero(nullptr),
146 timeout_calibration(nullptr),
147 disableHomeAndPark(nullptr),
148 disableStartupPosCheck(nullptr),
149 totJointsToCalibrate(0),
150 useLegacyParking(true),
151 currentParkingSeq_step(0)
152{
153}
154
160
161bool parametricCalibratorEth::open(yarp::os::Searchable& config)
162{
163 yTrace();
164 Property p;
165 p.fromString(config.toString());
166
167 if (p.check("GENERAL")==false)
168 {
169 yError() << "Parametric calibrator: missing [GENERAL] section";
170 return false;
171 }
172
173 if(p.findGroup("GENERAL").check("deviceName"))
174 {
175 deviceName = p.findGroup("GENERAL").find("deviceName").asString();
176 }
177 else
178 {
179 yError() << "Parametric calibrator: missing deviceName parameter";
180 return false;
181 }
182
183 std::string str;
184 if(config.findGroup("GENERAL").find("verbose").asInt32())
185 {
186 str=config.toString().c_str();
187 yTrace() << deviceName.c_str() << str;
188 }
189
190 // Check clearHwFaultBeforeCalibration
191 Value val_clearHwFault = config.findGroup("GENERAL").find("clearHwFaultBeforeCalibration");
192 if(val_clearHwFault.isNull())
193 {
194 clearHwFault = false;
195 }
196 else
197 {
198 if(!val_clearHwFault.isBool())
199 {
200 yError() << deviceName.c_str() << ": clearHwFaultBeforeCalibration bool param is different from accepted values (true / false). Assuming false";
201 clearHwFault = false;
202 }
203 else
204 {
205 clearHwFault = val_clearHwFault.asBool();
206 if(clearHwFault)
207 yInfo() << deviceName.c_str() << ": clearHwFaultBeforeCalibration option enabled\n";
208 }
209 }
210
211 // Check useRawEncoderData, it robot is using raw data, force to skip the calibration because it will be dangerous!
212 Value use_raw = config.findGroup("GENERAL").find("useRawEncoderData");
213 bool useRawEncoderData;
214
215 if(use_raw.isNull())
216 {
217 useRawEncoderData = false;
218 }
219 else
220 {
221 if(!use_raw.isBool())
222 {
223 yError() << deviceName.c_str() << ": useRawEncoderData bool param is different from accepted values (true / false). Assuming false";
224 useRawEncoderData = false;
225 }
226 else
227 {
228 useRawEncoderData = use_raw.asBool();
229 if(useRawEncoderData)
230 yWarning() << deviceName.c_str() << ": MotionControl is using raw data from encoders! Be careful. \n" <<
231 "\t forcing to skip the calibration";
232 }
233 }
234
235 if(useRawEncoderData)
236 {
237 skipCalibration = true;
238 }
239 else // Check skipCalibration flag, the robot will skip the calibration process
240 {
241 // Check useRawEncoderData = skip root calibration -- use with care
242 Value checkSkipCalib = config.findGroup("GENERAL").find("skipCalibration");
243 if(checkSkipCalib.isNull())
244 {
245 skipCalibration = false;
246 }
247 else
248 {
249 if(!checkSkipCalib.isBool())
250 {
251 yWarning() << deviceName << ": skipCalibration bool param is different from accepted values (true / false). Assuming false";
252 skipCalibration = false;
253 }
254 else
255 {
256 skipCalibration = checkSkipCalib.asBool();
257 if(skipCalibration)
258 {
259 yWarning() << deviceName << ": skipping calibration!! This option was set in general.xml file.";
260 yWarning() << deviceName << ": BE CAREFUL USING THE ROBOT IN THIS CONFIGURATION! See 'skipCalibration' param in config file";
261 }
262 }
263 }
264 }
265
266 // Check skipRecalibration flag in MAINTENANCE group, if true the rebot will skip the recalibration at each yri restart. First time calibration needs to be triggered
267 Value checkSkipReCalib = config.findGroup("MAINTENANCE").find("skipRecalibration");
268 if(checkSkipReCalib.isNull())
269 {
270 skipReCalibration = false;
271 }
272 else
273 {
274 if(!checkSkipReCalib.isBool())
275 {
276 yError() << deviceName << ": skipRecalibration bool param is different from accepted values (true / false). Assuming false";
277 skipReCalibration = false;
278 }
279 else
280 {
281 skipReCalibration = checkSkipReCalib.asBool();
282 if(skipReCalibration)
283 {
284 yWarning() << deviceName << ": skipping recalibration at each yri restart!! This option was set in MAINTENANCE group in general.xml file.";
285 yWarning() << deviceName << ": BE CAREFUL USING THE ROBOT IN THIS CONFIGURATION! See 'skipRecalibration' param in config file";
286 }
287 }
288 }
289
290 if(p.findGroup("GENERAL").check("joints"))
291 {
292 n_joints = p.findGroup("GENERAL").find("joints").asInt32();
293 }
294 else if(p.findGroup("GENERAL").check("Joints"))
295 {
296 // This is needed to be backward compatibile with old iCubInterface
297 n_joints = p.findGroup("GENERAL").find("Joints").asInt32();
298 }
299 else
300 {
301 yError() << deviceName.c_str() << ": missing joints parameter" ;
302 return false;
303 }
304
305 calibParams = new CalibrationParameters[n_joints];
306 startupMaxPWM = new int[n_joints];
307
308 legacyStartupPosition.seq_num = 0;
309 legacyStartupPosition.positions.resize(n_joints);
310 legacyStartupPosition.velocities.resize(n_joints);
311 currPos = new double[n_joints];
312 currVel = new double[n_joints];
313 legacyParkingPosition.seq_num = 0;
314 legacyParkingPosition.positions.resize(n_joints);
315 legacyParkingPosition.velocities.resize(n_joints);
316
317
318 timeout_goToZero = new int[n_joints];
319 timeout_calibration = new int[n_joints];
320 startupPosThreshold = new double[n_joints];
321 disableHomeAndPark = new int[n_joints];
322 disableStartupPosCheck = new int[n_joints];
323 original_max_pwm = new double[n_joints];
324 limited_max_pwm = new double[n_joints];
325
326 for (int i = 0; i < n_joints; i++) timeout_goToZero[i] = 10;
327 for (int i = 0; i < n_joints; i++) timeout_calibration[i] = 20;
328 for (int i = 0; i < n_joints; i++) disableHomeAndPark[i] = false;
329 for (int i = 0; i < n_joints; i++) disableStartupPosCheck[i] = false;
330
331 int i=0;
332
333 Bottle& xtmp = p.findGroup("CALIBRATION").findGroup("calibration1");
334 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of Calibration1 params " << xtmp.size()<< " " << n_joints; return false;}
335 for (i = 1; i < xtmp.size(); i++) calibParams[i-1].param1 = xtmp.get(i).asFloat64();
336
337 xtmp = p.findGroup("CALIBRATION").findGroup("calibration2");
338 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of Calibration2 params"; return false;}
339 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].param2 = xtmp.get(i).asFloat64();
340
341 xtmp = p.findGroup("CALIBRATION").findGroup("calibration3");
342 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of Calibration3 params"; return false;}
343 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].param3 = xtmp.get(i).asFloat64();
344
345 xtmp = p.findGroup("CALIBRATION").findGroup("calibration4");
346 if (xtmp.size() - 1 != n_joints) { yError() << deviceName << ": invalid number of Calibration4 params"; return false; }
347 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].param4 = xtmp.get(i).asFloat64();
348
349 xtmp = p.findGroup("CALIBRATION").findGroup("calibration5");
350 if (xtmp.size() - 1 != n_joints) { yError() << deviceName << ": invalid number of Calibration5 params"; return false; }
351 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].param5 = xtmp.get(i).asFloat64();
352
353 xtmp = p.findGroup("CALIBRATION").findGroup("calibrationType");
354 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of Calibration3 params"; return false;}
355 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].type = (unsigned char)xtmp.get(i).asFloat64();
356
357 xtmp = p.findGroup("CALIBRATION").findGroup("calibrationZero");
358 if (xtmp.size() - 1 != n_joints) { yError() << deviceName << ": invalid number of calibrationZero params"; return false; }
359 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].paramZero = xtmp.get(i).asFloat64();
360
361 xtmp = p.findGroup("CALIBRATION").findGroup("calibrationDelta");
362 if (xtmp.size() - 1 != n_joints) { yError() << deviceName << ": invalid number of calibrationDelta params"; return false; }
363 for (i = 1; i < xtmp.size(); i++) calibParams[i - 1].paramZero += xtmp.get(i).asFloat64();
364
365 xtmp = p.findGroup("CALIBRATION").findGroup("calibrationTimeout");
366 if (xtmp.size() - 1 != n_joints) { } //this parameter is optional
367 else { for (i = 1; i < xtmp.size(); i++) timeout_calibration[i - 1] = (int)xtmp.get(i).asFloat64(); }
368
369 xtmp = p.findGroup("CALIBRATION").findGroup("startupPosition");
370 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of startupPosition params"; return false;}
371 for (i = 1; i < xtmp.size(); i++) legacyStartupPosition.positions[i-1] = xtmp.get(i).asFloat64();
372
373 xtmp = p.findGroup("CALIBRATION").findGroup("startupVelocity");
374 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of startupVelocity params"; return false;}
375 for (i = 1; i < xtmp.size(); i++) legacyStartupPosition.velocities[i - 1] = xtmp.get(i).asFloat64();
376
377 // First find new version of parking sequence. Optional right now for back compatibility
378 useLegacyParking = ! parseSequenceGroup(p, "PARKING_SEQUENCE", parkingSequence);
379
380 Bottle homeGroup = p.findGroup("HOME");
381 if(useLegacyParking)
382 {
383 if( homeGroup.isNull())
384 {
385 yError() << "Parking position not found. Either <HOME> or <PARKING_SEQUENCE> must be specified in config file";
386 return false;
387 }
388 /*
389 else
390 {
391 yWarning() << "<HOME> group is deprecated in favour of <PARKING_SEQUENCE>";
392 }
393 */
394 xtmp = homeGroup.findGroup("positionHome");
395 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of PositionHome params"; return false;}
396 legacyParkingPosition.positions.resize(n_joints);
397 for (i = 1; i < xtmp.size(); i++)
398 legacyParkingPosition.positions[i-1] = xtmp.get(i).asFloat64();
399
400 xtmp = homeGroup.findGroup("velocityHome");
401 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of VelocityHome params"; return false;}
402 legacyParkingPosition.velocities.resize(n_joints);
403 for (i = 1; i < xtmp.size(); i++)
404 legacyParkingPosition.velocities[i-1] = xtmp.get(i).asFloat64();
405 }
406
407 // this parameter may be superseded by new park sequence mechanism, probably also for startup.
408 xtmp = homeGroup.findGroup("disableHomeAndPark");
409 if (xtmp.size() - 1 != n_joints) { } //this parameter is optional
410 else { for (i = 1; i < xtmp.size(); i++) disableHomeAndPark[i - 1] = xtmp.get(i).asInt32(); }
411
412 xtmp = p.findGroup("CALIBRATION").findGroup("startupMaxPwm");
413 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of startupMaxPwm params"; return false;}
414 for (i = 1; i < xtmp.size(); i++) startupMaxPWM[i-1] = xtmp.get(i).asInt32();
415
416 xtmp = p.findGroup("CALIBRATION").findGroup("startupPosThreshold");
417 if (xtmp.size()-1!=n_joints) {yError() << deviceName << ": invalid number of startupPosThreshold params"; return false;}
418 for (i = 1; i < xtmp.size(); i++) startupPosThreshold[i-1] = xtmp.get(i).asFloat64();
419
420 xtmp = p.findGroup("CALIBRATION").findGroup("startupDisablePosCheck");
421 if (xtmp.size() - 1 != n_joints) { } //this parameter is optional
422 else { for (i = 1; i < xtmp.size(); i++) disableStartupPosCheck[i - 1] = xtmp.get(i).asInt32(); }
423
424 xtmp = p.findGroup("CALIBRATION").findGroup("startupTimeout");
425 if (xtmp.size() - 1 != n_joints) {} //this parameter is optional
426 else { for (i = 1; i < xtmp.size(); i++) timeout_goToZero[i - 1] = xtmp.get(i).asFloat64(); }
427
428 xtmp = p.findGroup("CALIB_ORDER");
429 int calib_order_size = xtmp.size();
430 if (calib_order_size <= 1) {yError() << deviceName << ": invalid number CALIB_ORDER params"; return false;}
431 //yDebug() << "CALIB_ORDER: group size: " << xtmp.size() << " values: " << xtmp.toString().c_str();
432
433 std::list<int> tmp;
434 for(int i=1; i<xtmp.size(); i++)
435 {
436 tmp.clear();
437 Bottle *set;
438 set= xtmp.get(i).asList();
439
440 for(int j=0; j<set->size(); j++)
441 {
442 tmp.push_back(set->get(j).asInt32() );
443 }
444 joints.push_back(tmp);
445 }
446 return true;
447}
448
450{
451 yTrace();
452 if (calibParams != NULL) {
453 delete[] calibParams;
454 calibParams = NULL;
455 }
456
457 if (startupMaxPWM != NULL) {
458 delete[] startupMaxPWM;
459 startupMaxPWM = NULL;
460 }
461 if (original_max_pwm != NULL) {
462 delete[] original_max_pwm;
463 original_max_pwm = NULL;
464 }
465 if (limited_max_pwm != NULL) {
466 delete[] limited_max_pwm;
467 limited_max_pwm = NULL;
468 }
469
470 if (timeout_goToZero != NULL) {
471 delete[] timeout_goToZero;
472 timeout_goToZero = NULL;
473 }
474
475 if (timeout_calibration != NULL) {
476 delete[] timeout_calibration;
477 timeout_calibration = NULL;
478 }
479
480 if (currPos != NULL) {
481 delete[] currPos;
482 currPos = NULL;
483 }
484 if (currVel != NULL) {
485 delete[] currVel;
486 currVel = NULL;
487 }
488
489 if (disableHomeAndPark != NULL) {
490 delete[] disableHomeAndPark;
491 disableHomeAndPark = NULL;
492 }
493
494 if (disableStartupPosCheck != NULL) {
495 delete[] disableStartupPosCheck;
496 disableStartupPosCheck = NULL;
497 }
498
499 return true;
500}
501
502bool parametricCalibratorEth::calibrate(DeviceDriver *device)
503{
504 yInfo() << deviceName << ": starting calibration";
505 yTrace();
506 abortCalib = false; //set true in quitCalibrate function (called on ctrl +c signal )
507
508 if (device==0)
509 {
510 yError() << deviceName << ": invalid device driver";
511 return false;
512 }
513
514 yarp::dev::PolyDriver *p = dynamic_cast<yarp::dev::PolyDriver *>(device);
515 dev2calibrate = p;
516 if (p!=0)
517 {
518 p->view(iCalibrate);
519 p->view(iEncoders);
520 p->view(iPosition);
521 p->view(iPids);
522 p->view(iControlMode);
523 p->view(iAmp);
524 }
525 else
526 {
527 //yError() << deviceName << ": invalid dynamic cast to yarp::dev::PolyDriver";
528 //return false;
529
530 //This is to ensure backward-compatibility with iCubInterface
531 yWarning() << deviceName << ": using parametricCalibrator on an old iCubInterface system. Upgrade to robotInterface is recommended.";
532 device->view(iCalibrate);
533 device->view(iEncoders);
534 device->view(iPosition);
535 device->view(iPids);
536 device->view(iControlMode);
537 device->view(iAmp);
538 }
539
540 if (!(iCalibrate && iEncoders && iPosition && iPids && iControlMode)) {
541 yError() << deviceName << ": interface not found" << iCalibrate << iPosition << iPids << iControlMode;
542 return false;
543 }
544
545 return calibrate();
546}
547
548bool parametricCalibratorEth::calibrate()
549{
550 int setOfJoint_idx = 0;
551 totJointsToCalibrate = 0;
552 calibJoints.clear();
553
554 if (dev2calibrate==0)
555 {
556 yError() << deviceName << ": not able to find a valid device to calibrate";
557 return false;
558 }
559
560 int n_joints_board{0};
561 if ( !iEncoders->getAxes(&n_joints_board))
562 {
563 yError() << deviceName << ": error getting number of axes" ;
564 return false;
565 }
566 if(n_joints_board != n_joints)
567 {
568 yError() << "ParametricCalibratorEth: " << deviceName << ": number of joints of device to calibrate (" << n_joints_board << \
569 ") does not match the number of joints in calibrator config file ("<< n_joints << ")";
570 return false;
571 }
572
573 std::list<int> currentSetList;
574 std::list<std::list<int> >::iterator Bit=joints.begin();
575 std::list<std::list<int> >::iterator Bend=joints.end();
576
577 // count how many joints there are in the list of things to be calibrated
578 while(Bit != Bend)
579 {
580 currentSetList.clear();
581 currentSetList = (*Bit);
582 std::list<int>::iterator lit = currentSetList.begin();
583 std::list<int>::iterator lend = currentSetList.end();
584 totJointsToCalibrate += currentSetList.size();
585
586 while(lit != lend)
587 {
588 calibJoints.push_back(*lit);
589 calibJointsString.addInt32(*lit);
590 lit++;
591 }
592 Bit++;
593 }
594
595 yDebug() << deviceName << ": Joints calibration order:" << calibJointsString.toString();
596
597 if (totJointsToCalibrate > n_joints)
598 {
599 yError() << deviceName << ": too much axis to calibrate for this part..." << totJointsToCalibrate << " bigger than " << n_joints;
600 return false;
601 }
602
603 //before starting the calibration, checks for joints in hardware fault, and clears them if the user set the clearHwFaultBeforeCalibration option
604 if(!checkHwFault())
605 return false;
606
607 if (totJointsToCalibrate < n_joints)
608 {
609 yWarning() << deviceName << " is calibrating only a subset of the robot part. Calibrating " << totJointsToCalibrate << " over a total of " << n_joints;
610 }
611
612
613 if(skipCalibration)
614 yWarning() << deviceName << ": skipCalibration flag is on! Setting safe pid but skipping calibration.";
615
616 Bit=joints.begin();
617 std::list<int>::iterator lit; //iterator for joint in a set
618 while( (Bit != Bend) && (!abortCalib) ) // for each set of joints
619 {
620
621 setOfJoint_idx++;
622 currentSetList.clear();
623 currentSetList = (*Bit);
624
625 // 1) set safe pid
626 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++) //for each joint of set
627 {
628 if ( ((*lit) <0) || ((*lit) >= n_joints) ) // check the axes actually exists
629 {
630 yError() << deviceName << ": asked to calibrate joint" << (*lit) << ", which is negative OR bigger than the number of axes for this part ("<< n_joints << ")";
631 abortCalib = true;
632 break;
633 }
634
635 if(!iAmp->getPWMLimit((*lit), &original_max_pwm[(*lit)]) )
636 {
637 yError() << deviceName << ": getPid joint " << (*lit) << "failed... aborting calibration";
638 abortCalib = true;
639 break;
640 }
641
642 limited_max_pwm[(*lit)] = original_max_pwm[(*lit)];
643
644 if (startupMaxPWM[(*lit)]==0)
645 {
646 yDebug() << deviceName << ": skipping startupMaxPWM=0 of joint " << (*lit);
647 iAmp->setPWMLimit((*lit),original_max_pwm[(*lit)]);
648 }
649 else
650 {
651 if (startupMaxPWM[(*lit)]<limited_max_pwm[(*lit)])
652 {
653 limited_max_pwm[(*lit)]=startupMaxPWM[(*lit)];
654 iAmp->setPWMLimit((*lit), limited_max_pwm[(*lit)]);
655 }
656 else
657 {
658 yDebug() << deviceName << ": joint " << (*lit) << " has max_output already limited to a safe value: " << limited_max_pwm[(*lit)];
659 }
660 }
661 }
662
663 if(skipCalibration) // if this flag is on, fake calibration
664 {
665 Bit++;
666 continue;
667 }
668
669 Time::delay(0.1f);
670 if(abortCalib)
671 {
672 Bit++;
673 continue;
674 }
675
676 //3) send calibration command
677 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++) //for each joint of set
678 {
679 // Enable amp moved into EMS class;
680 // Here we just call the calibration procedure
681 calibrateJoint((*lit)); // just set the parameters
682 }
683
684 Time::delay(0.1f);
685
686 for(lit = currentSetList.begin(); lit != currentSetList.end(); lit++) //for each joint of set
687 {
688 iEncoders->getEncoder((*lit), &currPos[(*lit)]);
689 yDebug() << deviceName << ": set" << setOfJoint_idx << "j" << (*lit) << ": Calibrating... enc values just before starting low-level calibration: " << currPos[(*lit)];
690 }
691
692 if(abortCalib)
693 {
694 Bit++;
695 continue;
696 }
697
698 //4) check calibration result
699 std::list<int> failedJoints = {};
700 if(checkCalibrateJointEnded(*Bit, failedJoints )) //check calibration on entire set
701 {
702 yDebug() << deviceName << ": set" << setOfJoint_idx << ": Calibration ended, going to zero!";
703 }
704 else // keep pid safe for failed joints and go on
705 {
706 yError() << deviceName << ": set" << setOfJoint_idx << ": Detected errors during calibration! Idling failed joints and set on those safe PWM limits";
707 for (lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
708 {
709 auto it = std::find_if(failedJoints.begin(), failedJoints.end(),
710 [lit](int id) { return id == *lit; });
711
712 if (it != failedJoints.end())
713 {
714 yError() << deviceName << ": joint # " << *lit << " failed the calibration. Idling it and keeping safe PWM limits";
715 // stop calibration for expired timeout
716 iControlMode->setControlMode((*it),VOCAB_CM_IDLE); // eventually think to set FORCE_IDLE or NOT_CONFIGURED
717 }
718 }
719 Bit++;
720 continue; //go to next set
721 }
722
723 if(abortCalib)
724 {
725 Bit++;
726 continue;
727 }
728 Time::delay(0.5f); // needed?
729
730 //6) go to zero
731 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++) //for each joint of set
732 {
733 // Manda in Zero
734 goToStartupPosition((*lit));
735
736 }
737
738 if(abortCalib)
739 {
740 Bit++;
741 continue;
742 }
743 Time::delay(1.0); // needed?
744
745 //7) check joints are in position
746 bool goneToZero = true;
747 failedJoints.clear(); // I can reuse the same list --> I'm in a new phase of the calibration
748
749 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++) //for each joint of set
750 {
751 goneToZero &= checkGoneToZeroThreshold(*lit, failedJoints);
752 }
753
754 if(abortCalib)
755 {
756 Bit++;
757 continue;
758 }
759
760 if(goneToZero)
761 {
762 yDebug() << deviceName << ": set" << setOfJoint_idx << ": Reached zero position!";
763 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++) //for each joint of set
764 {
765 iAmp->setPWMLimit((*lit),original_max_pwm[(*lit)]);
766 }
767 }
768 else // keep pid safe for failed joints and go on
769 {
770 yError() << deviceName << ": set" << setOfJoint_idx << ": some axis got timeout while reaching zero position. Idling failed joints and set on those safe PWM limits";
771 // set the failed joints to idle and set safe PWM limits
772 for (lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++)
773 {
774 auto it = std::find_if(failedJoints.begin(), failedJoints.end(),
775 [lit](int id) { return id == *lit; });
776
777 if (it != failedJoints.end())
778 {
779 yError() << deviceName << ": joint # " << *lit << " failed reaching zero position. Idling it and keeping safe PWM limits";
780 iControlMode->setControlMode((*it),VOCAB_CM_IDLE); // eventually think to set FORCE_IDLE
781 }
782 else
783 {
784 yDebug() << deviceName << ": joint # " << *lit << " reached zero position. Setting original max PWM limits";
785 iAmp->setPWMLimit((*it),original_max_pwm[(*it)]);
786 }
787 }
788 }
789
790 // Go to the next set of joints to calibrate... if any
791 Bit++;
792 }
793
794 if(abortCalib)
795 {
796 yError() << deviceName << ": calibration has been aborted!I'm going to disable all joints..." ;
797 for(lit = currentSetList.begin(); lit != currentSetList.end() && !abortCalib; lit++) //for each joint of set
798 {
799 iControlMode->setControlMode(*lit, VOCAB_CM_IDLE);
800 }
801 return false;
802 }
803 isCalibrated = true;
804 return isCalibrated;
805}
806
807bool parametricCalibratorEth::calibrateJoint(int j)
808{
809 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
810 {
811 yError("%s cannot perform 'calibration' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
812 return false;
813 }
814 yDebug() << deviceName << ": Calling calibrateJoint on joint " << j << ": type "<< calibParams[j].type << " with params: " << calibParams[j].param1 << calibParams[j].param2 << calibParams[j].param3 << calibParams[j].param4 << calibParams[j].param5;
815 bool b = iCalibrate->setCalibrationParameters(j, calibParams[j]);
816 return b;
817}
818
819bool parametricCalibratorEth::checkCalibrateJointEnded(std::list<int> set, std::list<int> &failedJoints)
820{
821 bool calibration_ok = true;
822 int timeout = 0;
823
824 std::list<int>::iterator lit;
825 std::list<int>::iterator lend;
826 failedJoints.clear();
827
828 lit = set.begin();
829 lend = set.end();
830
831 while (lit != lend)
832 {
833 if (abortCalib)
834 {
835 yWarning() << deviceName << ": calibration aborted\n";
836 }
837
838 if (iCalibrate->calibrationDone(*lit))
839 {
840 yDebug() << deviceName << ": calib joint " << (*lit) << "ended";
841 lit++;
842 timeout = 0;
843 }
844 else
845 {
846 if (timeout > timeout_calibration[*lit])
847 {
848 yError() << deviceName << ": Timeout while calibrating joint" << (*lit);
849 failedJoints.push_back(*lit);
850 calibration_ok = false;
851 lit++;
852 timeout = 0;
853 }
854
855 yarp::os::Time::delay(1.0);
856 timeout++;
857 }
858 }
859
860 return calibration_ok;
861}
862
863bool parametricCalibratorEth::checkHwFault()
864{
865 for(auto j : calibJoints)
866 {
867 int mode=0;
868 iControlMode->getControlMode(j,&mode);
869 if (mode == VOCAB_CM_HW_FAULT)
870 {
871 if (clearHwFault)
872 {
873 iControlMode->setControlMode(j,VOCAB_CM_FORCE_IDLE);
874 yWarning() << deviceName <<": detected an hardware fault on joint " << j << ". An attempt will be made to clear it.";
875 Time::delay(0.02f);
876 iControlMode->getControlMode(j,&mode);
877 if (mode == VOCAB_CM_HW_FAULT)
878 {
879 yError() << deviceName <<": unable to clear the hardware fault detected on joint " << j << " before starting the calibration procedure!";
880 return false;
881 }
882 else if (mode == VOCAB_CM_IDLE)
883 {
884 yWarning() << deviceName <<": hardware fault on joint " << j << " successfully cleared.";
885 return true;
886 }
887 else
888 {
889 yError() << deviceName <<": an unknown error occured while trying the hardware fault on joint " << j ;
890 return false;
891 }
892 }
893 else
894 {
895 yError() << deviceName <<": detected an hardware fault on joint " << j << " before starting the calibration procedure!";
896 return false;
897 }
898 }
899 }
900 return true;
901}
902
903// this function may be updated in the future to use a startup sequence, like parking
904bool parametricCalibratorEth::goToStartupPosition(int j)
905{
906 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
907 {
908 yError("%s cannot perform 'go to zero' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
909 return false;
910 }
911
912 bool ret = true;
913 int mode = 0;
914 if (disableStartupPosCheck[j])
915 {
916 yWarning() << deviceName << ": goToZero, joint " << j << " is disabled on user request";
917 return true;
918 }
919
920 if (abortCalib) return true;
921 iControlMode->getControlMode(j, &mode);
922
923 if((mode == VOCAB_CM_IDLE) && (skipReCalibration))
924 {
925 yWarning() << deviceName << ": goToZero, joint " << j << " is idle and skipRecalibration is requested, skipping!";
926 return true;
927 }
928
929 yDebug() << deviceName << ": Sending positionMove to joint" << j << " (desired pos: " << legacyStartupPosition.positions[j] << \
930 "desired speed: " << legacyStartupPosition.velocities[j] <<" )";
931 ret = iPosition->setRefSpeed(j, legacyStartupPosition.velocities[j]);
932 ret &= iPosition->positionMove(j, legacyStartupPosition.positions[j]);
933 return ret;
934}
935
936bool parametricCalibratorEth::checkGoneToZeroThreshold(int j, std::list<int> &failedJoints)
937{
938 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
939 {
940 yError("%s cannot perform 'check gone to zero' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
941 return false;
942 }
943
944 if (disableStartupPosCheck[j])
945 {
946 yWarning() << deviceName << ": checkGoneToZeroThreshold, joint " << j << " is disabled on user request";
947 return true;
948 }
949 if (skipCalibration)
950 {
951 yWarning() << deviceName << ": checkGoneToZeroThreshold, joint " << j << " is set with safe PWM limits on user request (skipCalibration flag is on)";
952 failedJoints.push_back(j);
953 return false;
954 }
955
956 // wait.
957 bool finished = false;
958// double ang[4];
959 double angj = 0;
960 double output = 0;
961 double delta=0;
962 int mode=0;
963 bool done = false;
964
965 double start_time = yarp::os::Time::now();
966 while ( (!finished) && (!abortCalib))
967 {
968 iEncoders->getEncoder(j, &angj);
969 iPosition->checkMotionDone(j, &done);
970 iControlMode->getControlMode(j, &mode);
971 iPids->getPidOutput(VOCAB_PIDTYPE_POSITION,j, &output);
972
973 if((skipReCalibration) && (mode == VOCAB_CM_IDLE))
974 {
975 yDebug() << deviceName << ": checkGoneToZeroThreshold, joint " << j << " is IDLE and skipRecalibration is requested, return completed!";
976 finished = true;
977 break;
978 }
979 delta = fabs(angj-legacyStartupPosition.positions[j]);
980 yDebug("%s: checkGoneToZeroThreshold: joint: %d curr: %.3f des: %.3f -> delta: %.3f threshold: %.3f output: %.3f mode: %s" , \
981 deviceName.c_str(), j, angj, legacyStartupPosition.positions[j], delta, startupPosThreshold[j], output, yarp::os::Vocab32::decode(mode).c_str());
982
983 if (delta < startupPosThreshold[j] && done)
984 {
985 yDebug("%s: checkGoneToZeroThreshold: joint: %d completed with delta: %.3f over: %.3f" ,deviceName.c_str(),j,delta, startupPosThreshold[j]);
986 finished=true;
987 break;
988 }
989 if (yarp::os::Time::now() - start_time > timeout_goToZero[j])
990 {
991 yError() << deviceName << ": checkGoneToZeroThreshold: joint " << j << " Timeout while going to zero!";
992 break;
993 }
994 if (mode == VOCAB_CM_IDLE)
995 {
996 yError() << deviceName << ": checkGoneToZeroThreshold: joint " << j << " is idle, skipping!";
997 break;
998 }
999 if (mode == VOCAB_CM_HW_FAULT)
1000 {
1001 yError() << deviceName <<": checkGoneToZeroThreshold: hardware fault on joint " << j << ", skipping!";
1002 break;
1003 }
1004 if (abortCalib)
1005 {
1006 yWarning() << deviceName <<": checkGoneToZeroThreshold: joint " << j << " Aborting wait while going to zero!\n";
1007 break;
1008 }
1009 Time::delay(0.5);
1010 }
1011
1012 if(!finished)
1013 {
1014 failedJoints.push_back(j); // adding joint that failed goingToZero for any reason to the list of failed joints. Specific warning given before.
1015 }
1016 return finished;
1017}
1018
1019// called by robotinterface (during interrupt action??) // done
1020bool parametricCalibratorEth::park(DeviceDriver *dd, bool wait)
1021{
1022 // parameter device driver is not used, because we already stored and got interfaces view
1023 // when function 'calibration' was called.
1024 yTrace();
1025 std::list<int>::iterator joint;
1026
1027 // legacy version: can be removed when legacy will not be supported anymore
1028 if (useLegacyParking)
1029 {
1030 bool allJointsCanParkSimultaneously = true;
1031 for (int i = 0; i < n_joints; i++)
1032 {
1033 if (disableHomeAndPark[i]) allJointsCanParkSimultaneously = false;
1034 }
1035
1036 if(allJointsCanParkSimultaneously == false)
1037 {
1038 yWarning() << deviceName << "Joints will be parked separately, since some of them have the disableHomeAndPark flag set";
1039 bool ret = true;
1040 for(joint = calibJoints.begin(); joint != calibJoints.end() && !abortCalib; joint++) //for each joint of set
1041 {
1042 ret &= this->parkSingleJoint(*joint);
1043 }
1044 return ret;
1045 }
1046 }
1047 abortParking=false;
1048
1049 if(!isCalibrated)
1050 {
1051 yWarning() << deviceName << ": Calling park without calibration... skipping";
1052 return true;
1053 }
1054
1055 if(skipCalibration)
1056 {
1057 yWarning() << deviceName << ": skipCalibration flag is on!! Faking park!!";
1058 return true;
1059 }
1060
1061 int * currentControlModes = new int[n_joints];
1062 std::vector<bool> cannotPark(n_joints);
1063 bool res = iControlMode->getControlModes(currentControlModes);
1064 if(!res)
1065 {
1066 yError() << deviceName << ": error getting control mode during parking";
1067 }
1068
1069 for(joint = calibJoints.begin(); joint != calibJoints.end() && !abortCalib; joint++) //for each joint of set
1070 {
1071 switch(currentControlModes[(*joint)])
1072 {
1073 case VOCAB_CM_IDLE:
1074 {
1075 yError() << deviceName << ": joint " << (*joint) << " is idle, skipping park";
1076 cannotPark[(*joint)] = true;
1077 }
1078 break;
1079
1080 case VOCAB_CM_HW_FAULT:
1081 {
1082 yError() << deviceName << ": joint " << (*joint) << " has an hardware fault, skipping park";
1083 cannotPark[(*joint)] = true;
1084 }
1085 break;
1086
1087 case VOCAB_CM_NOT_CONFIGURED:
1088 {
1089 yError() << deviceName << ": joint " << (*joint) << " is not configured, skipping park";
1090 cannotPark[(*joint)] = true;
1091 }
1092 break;
1093
1094 case VOCAB_CM_UNKNOWN:
1095 {
1096 yError() << deviceName << ": joint " << (*joint) << " is in unknown state, skipping park";
1097 cannotPark[(*joint)] = true;
1098 }
1099
1100 default:
1101 {
1102 iControlMode->setControlMode((*joint), VOCAB_CM_POSITION);
1103 cannotPark[(*joint)] = false;
1104 }
1105 }
1106 }
1107
1108 bool parkSequenceDone{false};
1109 if(useLegacyParking)
1110 {
1111 moveAndCheck_legacy(legacyParkingPosition, cannotPark, wait);
1112 // for legacy version, parkSequenceDone is always true, because there is no sequence
1113 parkSequenceDone = true;
1114 }
1115 else
1116 {
1117 // call one step of parking sequence for each 'park' call
1118
1119 bool stepDone = true;
1120 if(parkingSequence.size() > 0)
1121 {
1122 stepDone = moveAndCheck(parkingSequence.at(currentParkingSeq_step));
1123 }
1124 if(stepDone)
1125 {
1126 yDebug() << "ParametricCalibratorEth: park sequence step num " << currentParkingSeq_step << " ended with " << \
1127 (abortParking ? "failure" : "success");
1128 }
1129 else
1130 abortParking = true;
1131
1132 currentParkingSeq_step++;
1133 // parking sequence is completed if all steps are completed, or aborted if any one goes bad.
1134 // It is not safe to continue, if one parking step fails
1135 if( (currentParkingSeq_step >= parkingSequence.size()) || stepDone == false)
1136 parkSequenceDone = true;
1137 }
1138
1139 // when parking is done (all steps of sequence where is the case), set all joints in idle
1140 if(parkSequenceDone)
1141 {
1142 yDebug() << deviceName.c_str() << ": Park " << (abortParking ? "aborted" : "completed");
1143 for(joint = calibJoints.begin(); joint != calibJoints.end() && !abortCalib; joint++) //for each joint of set
1144 {
1145 switch(currentControlModes[(*joint)])
1146 {
1147 case VOCAB_CM_IDLE:
1148 case VOCAB_CM_HW_FAULT:
1149 case VOCAB_CM_NOT_CONFIGURED:
1150 case VOCAB_CM_UNKNOWN:
1151 // Do nothing.
1152 break;
1153 default:
1154 {
1155 iControlMode->setControlMode((*joint), VOCAB_CM_IDLE);
1156 }
1157 }
1158 }
1159 }
1160 return true;
1161}
1162
1163bool parametricCalibratorEth::moveAndCheck(PositionSequence &data)
1164{
1165 iPosition->setRefSpeeds(data.velocities.data());
1166 iPosition->positionMove(data.positions.data());
1167
1168 bool done = false;
1169 int timeout = 0;
1170 do
1171 {
1172 Time::delay(1);
1173 timeout++;
1174 iPosition->checkMotionDone(&done);
1175 }
1176 while((!done) && (timeout < PARK_TIMEOUT) && (!abortParking));
1177
1178 if(!done)
1179 {
1180 yError() << "ParametricCalibratorEth: parking " << deviceName << " not in position after a timeout of" << PARK_TIMEOUT << " seconds";
1181 }
1182
1183 return done;
1184}
1185
1186bool parametricCalibratorEth::moveAndCheck_legacy(PositionSequence &data, std::vector<bool> &cannotPark, bool wait)
1187{
1188 bool done=false;
1189 // send references to joints that need to be parked
1190 for(auto joint = calibJoints.begin(); joint != calibJoints.end() && !abortCalib; joint++) //for each joint of set
1191 {
1192 if (cannotPark[(*joint)] ==false)
1193 {
1194 iPosition->setRefSpeed((*joint), data.velocities[(*joint)]);
1195 iPosition->positionMove((*joint), data.positions[(*joint)]);
1196 }
1197 }
1198
1199 // wait for the parking to be completed
1200 if (wait)
1201 {
1202 for(auto joint = calibJoints.begin(); joint != calibJoints.end() && !abortCalib; joint++) //for each joint of set
1203 {
1204 int timeout = 0;
1205 if (cannotPark[(*joint)] ==false)
1206 {
1207 yDebug() << deviceName.c_str() << ": Moving to park position, joint:" << (*joint);
1208 done=false;
1209 iPosition->checkMotionDone((*joint), &done);
1210 while ((!done) && (timeout < PARK_TIMEOUT) && (!abortParking))
1211 {
1212 Time::delay(1);
1213 timeout++;
1214 iPosition->checkMotionDone((*joint), &done);
1215 }
1216 if(!done)
1217 {
1218 yError() << deviceName << ": joint " << (*joint) << " not in position after a timeout of" << PARK_TIMEOUT << " seconds";
1219 }
1220 }
1221 }
1222 }
1223 return done;
1224}
1225
1227{
1228 yDebug() << deviceName.c_str() << ": Quitting calibrate\n";
1229 abortCalib = true;
1230 return true;
1231}
1232
1234{
1235 yDebug() << deviceName.c_str() << ": Quitting parking\n";
1236 abortParking=true;
1237 return true;
1238}
1239
1241{
1242 return this;
1243}
1244
1246{
1247 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
1248 {
1249 yError("%s cannot perform 'calibration' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
1250 return false;
1251 }
1252
1253 return calibrateJoint(j);
1254}
1255
1257{
1258 yTrace();
1259 return calibrate();
1260}
1261
1263{
1264 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
1265 {
1266 yError("%s cannot perform 'homing' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
1267 return false;
1268 }
1269
1270 if (disableHomeAndPark[j])
1271 {
1272 yWarning() << deviceName << ": homingSingleJoint, joint " << j << " is disabled on user request";
1273 return true;
1274 }
1275 return goToStartupPosition(j);
1276}
1277
1279{
1280 yTrace();
1281 bool ret = true;
1282 std::list<int>::iterator lit;
1283 for(lit = calibJoints.begin(); lit != calibJoints.end() && !abortCalib; lit++) //for each joint of set
1284 {
1285 ret = homingSingleJoint(*lit) && ret;
1286 }
1287 return ret;
1288}
1289
1291{
1292 // check input joint number is valid
1293 if(std::find(calibJoints.begin(), calibJoints.end(), j) == calibJoints.end())
1294 {
1295 yError("%s cannot perform 'park' operation because joint number %d is out of range [%s].", deviceName.c_str(), j, calibJointsString.toString().c_str());
1296 return false;
1297 }
1298
1299 if(useLegacyParking) // legacy version: can be removed when legacy will not be supported anymore
1300 {
1301 if (disableHomeAndPark[j])
1302 {
1303 yWarning() << deviceName << ": parkSingleJoint, joint " << j << " is disabled on user request";
1304 return true;
1305 }
1306 }
1307
1308 abortParking=false;
1309
1310 if(!isCalibrated)
1311 {
1312 yWarning() << deviceName << ": Calling park without calibration... skipping";
1313 return true;
1314 }
1315
1316 if(skipCalibration)
1317 {
1318 yWarning() << deviceName << ": skipCalibration flag is on!! Faking park!!";
1319 return true;
1320 }
1321
1322 int currentControlMode;
1323 bool cannotPark;
1324 bool res = iControlMode->getControlMode(j, &currentControlMode);
1325 if(!res)
1326 {
1327 yError() << deviceName << ": error getting control mode during parking";
1328 }
1329
1330 if(currentControlMode != VOCAB_CM_IDLE &&
1331 currentControlMode != VOCAB_CM_HW_FAULT)
1332 {
1333 iControlMode->setControlMode(j, VOCAB_CM_POSITION);
1334 cannotPark = false;
1335 }
1336 else if (currentControlMode == VOCAB_CM_IDLE)
1337 {
1338 yError() << deviceName << ": joint " << j << " is idle, skipping park";
1339 cannotPark = true;
1340 }
1341 else if (currentControlMode == VOCAB_CM_HW_FAULT)
1342 {
1343 yError() << deviceName << ": joint " << j << " has an hardware fault, skipping park";
1344 cannotPark = true;
1345 }
1346
1347 if(useLegacyParking) // legacy version: can be removed when legacy will not be supported anymore
1348 {
1349 iPosition->setRefSpeed (j, legacyStartupPosition.velocities[j]);
1350 iPosition->positionMove(j, legacyStartupPosition.positions[j]);
1351 }
1352 else
1353 {
1354 // Send the position and velocities of the last sequence step
1355 iPosition->setRefSpeed (j, parkingSequence.rbegin()->velocities[j]);
1356 iPosition->positionMove(j, parkingSequence.rbegin()->positions[j]);
1357 }
1358
1359 if (_wait)
1360 {
1361 if (cannotPark == false)
1362 {
1363 int timeout = 0;
1364 yDebug() << deviceName.c_str() << ": Moving to park position, joint:" << j;
1365 bool done=false;
1366 iPosition->checkMotionDone(j, &done);
1367 while ((!done) && (timeout < PARK_TIMEOUT) && (!abortParking))
1368 {
1369 Time::delay(1);
1370 timeout++;
1371 iPosition->checkMotionDone(j, &done);
1372 }
1373 if(!done)
1374 {
1375 yError() << deviceName << ": joint " << j << " not in position after a timeout of" << PARK_TIMEOUT << " seconds";
1376 }
1377 }
1378 }
1379
1380 yDebug() << deviceName.c_str() << ": Park " << (abortParking ? "aborted" : "completed");
1381 iControlMode->setControlMode(j,VOCAB_CM_IDLE);
1382 return true;
1383}
1384
1385// called from motorgui or remote devices
1387{
1388 yTrace();
1389
1390 if(!isCalibrated)
1391 {
1392 yError() << "Device is not calibrated therefore cannot be parked";
1393 return false;
1394 }
1395
1396 return park(dev2calibrate);
1397}
1398
1399
1400// eof
1401
@ data
virtual bool park(DeviceDriver *dd, bool wait=true) override
virtual bool open(yarp::os::Searchable &config) override
Open the device driver.
virtual bool homingSingleJoint(int j) override
virtual bool calibrateSingleJoint(int j) override
virtual bool parkSingleJoint(int j, bool _wait=true) override
virtual bool close() override
Close the device driver.
virtual yarp::dev::IRemoteCalibrator * getCalibratorDevice() override
bool calibrate(DeviceDriver *device) override
Calibrate method.
bool done
Definition main.cpp:42
const double GO_TO_ZERO_TIMEOUT
const int CALIBRATE_JOINT_TIMEOUT
static bool extractGroup(Bottle &input, Bottle &out, const std::string &key1, const std::string &txt, int size)
const int PARK_TIMEOUT
static bool extractGroup(Bottle &input, Bottle &out, const std::string &key1, const std::string &txt, int size)
const int PARK_TIMEOUT
out
Definition sine.m:8