iCub-main
controller.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2010 RobotCub Consortium, European Commission FP6 Project IST-004370
3  * Author: Ugo Pattacini, Alessandro Roncone
4  * email: ugo.pattacini@iit.it, alessandro.roncone@iit.it
5  * website: www.robotcub.org
6  * Permission is granted to copy, distribute, and/or modify this program
7  * under the terms of the GNU General Public License, version 2 or any
8  * later version published by the Free Software Foundation.
9  *
10  * A copy of the license can be found at
11  * http://www.robotcub.org/icub/license/gpl.txt
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16  * Public License for more details
17 */
18 
19 #include <limits>
20 #include <cstdio>
21 #include <sstream>
22 
23 #include <iCub/solver.h>
24 #include <iCub/controller.h>
25 
26 
27 /************************************************************************/
28 Controller::Controller(PolyDriver *_drvTorso, PolyDriver *_drvHead, ExchangeData *_commData,
29  const double _neckTime, const double _eyesTime, const double _min_abs_vel,
30  const unsigned int _period) :
31  PeriodicThread((double)_period/1000.0), drvTorso(_drvTorso), drvHead(_drvHead),
32  commData(_commData), neckTime(_neckTime), eyesTime(_eyesTime),
33  min_abs_vel(_min_abs_vel), period(_period), Ts(_period/1000.0),
34  printAccTime(0.0)
35 {
36  // Instantiate objects
38  eyeL=new iCubEye("left_v"+commData->head_version.get_version());
39  eyeR=new iCubEye("right_v"+commData->head_version.get_version());
41 
42  // remove constraints on the links: logging purpose
43  imu->setAllConstraints(false);
44 
45  // release links
49 
50  // Get the chain objects
54 
55  // add aligning matrices read from configuration file
56  getAlignHN(commData->rf_cameras,"ALIGN_KIN_LEFT",eyeL->asChain());
57  getAlignHN(commData->rf_cameras,"ALIGN_KIN_RIGHT",eyeR->asChain());
58 
59  // overwrite aligning matrices iff specified through tweak values
61  {
62  getAlignHN(commData->rf_tweak,"ALIGN_KIN_LEFT",eyeL->asChain());
63  getAlignHN(commData->rf_tweak,"ALIGN_KIN_RIGHT",eyeR->asChain());
64  }
65 
66  // read number of joints
67  if (drvTorso!=nullptr)
68  {
69  IEncoders *encTorso; drvTorso->view(encTorso);
70  encTorso->getAxes(&nJointsTorso);
71  }
72  else
73  nJointsTorso=3;
74 
75  IEncoders *encHead; drvHead->view(encHead);
76  encHead->getAxes(&nJointsHead);
77 
78  drvHead->view(modHead);
79  drvHead->view(posHead);
80  drvHead->view(velHead);
81 
82  // if requested check if position control is available
84  {
86  yInfo("### neck control - requested POSITION mode: IPositionDirect [%s] => %s mode selected",
87  commData->neckPosCtrlOn?"available":"not available",commData->neckPosCtrlOn?"POSITION":"VELOCITY");
88  }
89  else
90  yInfo("### neck control - requested VELOCITY mode => VELOCITY mode selected");
91 
92  // joints bounds alignment
94 
95  // read starting position
96  fbTorso.resize(nJointsTorso,0.0);
97  fbHead.resize(nJointsHead,0.0);
98 
99  // exclude acceleration constraints by fixing
100  // thresholds at high values
101  Vector a_robHead(nJointsHead,std::numeric_limits<double>::max());
102  velHead->setRefAccelerations(a_robHead.data());
103 
106 
107  // find minimum allowed vergence
110 
111  // reinforce vergence min bound
114 
115  fbNeck=fbHead.subVector(0,2);
116  fbEyes=fbHead.subVector(3,5);
117  qdNeck.resize(3,0.0); qdEyes.resize(3,0.0);
118  vNeck.resize(3,0.0); vEyes.resize(3,0.0);
119  v.resize(nJointsHead,0.0);
120 
121  // Set the task execution time
124 
125  mjCtrlNeck=new minJerkVelCtrlForIdealPlant(Ts,(int)fbNeck.length());
126  mjCtrlEyes=new minJerkVelCtrlForIdealPlant(Ts,(int)fbEyes.length());
128  IntPlan=new Integrator(Ts,fbNeck,lim.submatrix(0,2,0,1));
129  IntStabilizer=new Integrator(Ts,zeros((int)vNeck.length()));
130 
131  neckJoints.resize(3);
132  eyesJoints.resize(3);
133  neckJoints[0]=0;
134  neckJoints[1]=1;
135  neckJoints[2]=2;
136  eyesJoints[0]=3;
137  eyesJoints[1]=4;
138  eyesJoints[2]=5;
139 
140  qd=fbHead;
141  q0=qd;
144 
146  saccadeStartTime=0.0;
147  pathPerc=0.0;
148 
149  unplugCtrlEyes=false;
150  ctrlInhibited=false;
151  motionDone=true;
152  reliableGyro=true;
153  stabilizeGaze=false;
154 }
155 
156 
157 /************************************************************************/
159 {
160  delete neck;
161  delete eyeL;
162  delete eyeR;
163  delete imu;
164  delete mjCtrlNeck;
165  delete mjCtrlEyes;
166  delete IntState;
167  delete IntPlan;
168  delete IntStabilizer;
169 }
170 
171 
172 /************************************************************************/
174 {
175  iKinChain cl(*chainEyeL), cr(*chainEyeR);
176  cl.setAng(zeros(cl.getDOF()));
177  cr.setAng(zeros(cl.getDOF()));
178 
179  double minVer=startupMinVer;
180  double maxVer=lim(nJointsHead-1,1);
181  for (double ver=minVer; ver<maxVer; ver+=0.5*CTRL_DEG2RAD)
182  {
183  cl(cl.getDOF()-1).setAng(ver/2.0);
184  cr(cr.getDOF()-1).setAng(-ver/2.0);
185 
186  Vector fp;
187  if (CartesianHelper::computeFixationPointData(cl,cr,fp))
188  {
189  // impose homogeneous coordinates
190  fp.push_back(1.0);
191 
192  // if the component along eye's z-axis is positive
193  // then this means that the fixation point is ok,
194  // being in front of the robot
195  Vector fpe=SE3inv(cl.getH())*fp;
196  if (fpe[2]>0.0)
197  {
198  minVer=ver;
199  break;
200  }
201  }
202  }
203 
204  yInfo("### computed minimum allowed vergence = %g [deg]",minVer*CTRL_RAD2DEG);
206 }
207 
208 
209 /************************************************************************/
211 {
213  IntState->setLim(lim);
214 }
215 
216 
217 /************************************************************************/
218 void Controller::notifyEvent(const string &event, const double checkPoint)
219 {
220  if (port_event.getOutputCount()>0)
221  {
222  Bottle &ev=port_event.prepare();
223  ev.clear();
224 
225  ev.addString(event);
226  ev.addFloat64(q_stamp);
227  if (checkPoint>=0.0)
228  ev.addFloat64(checkPoint);
229 
230  txInfo_event.update(q_stamp);
231  port_event.setEnvelope(txInfo_event);
232  port_event.writeStrict();
233  }
234 }
235 
236 
237 /************************************************************************/
239 {
240  if (!motionOngoingEventsCurrent.empty())
241  {
242  double curCheckPoint=*motionOngoingEventsCurrent.begin();
243  if (pathPerc>=curCheckPoint)
244  {
245  notifyEvent("motion-ongoing",curCheckPoint);
246  motionOngoingEventsCurrent.erase(curCheckPoint);
247  }
248  }
249 }
250 
251 
252 /************************************************************************/
254 {
255  while (!motionOngoingEventsCurrent.empty())
256  {
257  double curCheckPoint=*motionOngoingEventsCurrent.begin();
258  notifyEvent("motion-ongoing",curCheckPoint);
259  motionOngoingEventsCurrent.erase(curCheckPoint);
260  }
261 }
262 
263 
264 /************************************************************************/
265 void Controller::stopLimb(const bool execStopPosition)
266 {
267  if (commData->neckPosCtrlOn)
268  {
269  if (execStopPosition)
270  posHead->stop((int)neckJoints.size(),neckJoints.data());
271 
272  // note: vel==0.0 is always achievable
273  velHead->velocityMove((int)eyesJoints.size(),eyesJoints.data(),
274  Vector(eyesJoints.size(),0.0).data());
275  }
276  else
277  velHead->velocityMove(Vector(nJointsHead,0.0).data());
278 
279  if (commData->debugInfoEnabled && (port_debug.getOutputCount()>0))
280  {
281  Bottle info;
282  int j=0;
283 
284  if (commData->neckPosCtrlOn)
285  {
286  if (execStopPosition)
287  {
288  for (auto neckJoint : neckJoints)
289  {
290  ostringstream ss;
291  ss<<"pos_"<<neckJoint;
292  info.addString(ss.str());
293  info.addString("stop");
294  }
295  }
296 
297  j=eyesJoints[0];
298  }
299 
300  for (int i=j; i<nJointsHead; i++)
301  {
302  ostringstream ss;
303  ss<<"vel_"<<i;
304  info.addString(ss.str());
305  info.addFloat64(0.0);
306  }
307 
308  port_debug.prepare()=info;
309  txInfo_debug.update(q_stamp);
310  port_debug.setEnvelope(txInfo_debug);
311  port_debug.writeStrict();
312  }
313 
314  commData->ctrlActive=false;
315  motionDone=true;
316  cv_eventLook.notify_all();
317 }
318 
319 
320 /************************************************************************/
322 {
323  lock_guard<mutex> lg(mutexRun);
325 }
326 
327 
328 /************************************************************************/
330 {
331  lock_guard<mutex> lg(mutexCtrl);
332  if (commData->ctrlActive)
333  {
334  q_stamp=Time::now();
335  ctrlInhibited=true;
336  stopLimb();
337  notifyEvent("motion-done");
338  }
339 }
340 
341 
342 /************************************************************************/
343 void Controller::printIter(Vector &xd, Vector &fp, Vector &qd, Vector &q,
344  Vector &v, double printTime)
345 {
346  if ((printAccTime+=Ts)>=printTime)
347  {
348  printAccTime=0.0;
349 
350  printf("norm(e) = %g\n",norm(xd-fp));
351  printf("Target fix. point = %s\n",xd.toString().c_str());
352  printf("Actual fix. point = %s\n",fp.toString().c_str());
353  printf("Target Joints = %s\n",qd.toString().c_str());
354  printf("Actual Joints = %s\n",q.toString().c_str());
355  printf("Velocity = %s\n",v.toString().c_str());
356  printf("\n");
357  }
358 }
359 
360 
361 /************************************************************************/
363 {
364  port_x.open(commData->localStemName+"/x:o");
365  port_q.open(commData->localStemName+"/q:o");
366  port_event.open(commData->localStemName+"/events:o");
367 
369  port_debug.open(commData->localStemName+"/dbg:o");
370 
371  yInfo("Starting Controller at %d ms",period);
372  q_stamp=Time::now();
373 
374  return true;
375 }
376 
377 
378 /************************************************************************/
380 {
381  stopLimb();
382  notifyEvent("closing");
383 
384  port_x.interrupt();
385  port_x.close();
386 
387  port_q.interrupt();
388  port_q.close();
389 
390  port_event.interrupt();
391  port_event.close();
392 
394  {
395  port_debug.interrupt();
396  port_debug.close();
397  }
398 }
399 
400 
401 /************************************************************************/
403 {
404  if (s)
405  yInfo("Controller started successfully");
406  else
407  yError("Controller did not start!");
408 }
409 
410 
411 /************************************************************************/
412 Vector Controller::computedxFP(const Matrix &H, const Vector &v,
413  const Vector &w, const Vector &x_FP)
414 {
415  Matrix H_=H;
416  Vector w_=w;
417  w_.push_back(1.0);
418 
419  H_(0,3)=x_FP[0]-H_(0,3);
420  H_(1,3)=x_FP[1]-H_(1,3);
421  H_(2,3)=x_FP[2]-H_(2,3);
422  Vector dx_FP_pos=v+(w_[0]*cross(H_,0,H_,3)+
423  w_[1]*cross(H_,1,H_,3)+
424  w_[2]*cross(H_,2,H_,3));
425 
426  H_(0,3)=H_(1,3)=H_(2,3)=0.0;
427  Vector dx_FP_rot=H_*w_;
428  dx_FP_rot.pop_back();
429 
430  return cat(dx_FP_pos,dx_FP_rot);
431 }
432 
433 
434 /************************************************************************/
435 Vector Controller::computeNeckVelFromdxFP(const Vector &fp, const Vector &dfp)
436 {
437  // convert fp from root to the neck reference frame
438  Vector fpR=fp;
439  fpR.push_back(1.0);
440  Vector fpE=SE3inv(chainNeck->getH())*fpR;
441 
442  // compute the Jacobian of the head joints alone
443  // (by adding the new fixation point beforehand)
444  Matrix HN=eye(4,4);
445  HN(0,3)=fpE[0];
446  HN(1,3)=fpE[1];
447  HN(2,3)=fpE[2];
448 
449  mutexChain.lock();
450  chainNeck->setHN(HN);
451  Matrix JN=chainNeck->GeoJacobian();
452  chainNeck->setHN(eye(4,4));
453  mutexChain.unlock();
454 
455  // take only the last three rows of the Jacobian
456  // belonging to the head joints
457  Matrix JNp=JN.submatrix(3,5,3,5);
458 
459  return pinv(JNp)*dfp.subVector(3,5);
460 }
461 
462 
463 /************************************************************************/
464 Vector Controller::computeEyesVelFromdxFP(const Vector &dfp)
465 {
466  Matrix eyesJ; Vector tmp;
468  CartesianHelper::computeFixationPointData(*chainEyeL,*chainEyeR,tmp,eyesJ))
469  return pinv(eyesJ)*dfp.subVector(0,2);
470  else
471  return zeros((int)vEyes.length());
472 }
473 
474 
475 /************************************************************************/
476 void Controller::doSaccade(const Vector &ang, const Vector &vel)
477 {
478  lock_guard<mutex> lg(mutexCtrl);
479  if (ctrlInhibited)
480  return;
481 
483 
484  // enforce joints bounds
485  Vector ang_(3);
486  ang_[0]=CTRL_RAD2DEG*sat(ang[0],lim(eyesJoints[0],0),lim(eyesJoints[0],1));
487  ang_[1]=CTRL_RAD2DEG*sat(ang[1],lim(eyesJoints[1],0),lim(eyesJoints[1],1));
488  ang_[2]=CTRL_RAD2DEG*sat(ang[2],lim(eyesJoints[2],0),lim(eyesJoints[2],1));
489 
490  posHead->setRefSpeeds((int)eyesJoints.size(),eyesJoints.data(),vel.data());
491  posHead->positionMove((int)eyesJoints.size(),eyesJoints.data(),ang_.data());
492 
493  if (commData->debugInfoEnabled && (port_debug.getOutputCount()>0))
494  {
495  Bottle info;
496  for (size_t i=0; i<ang_.length(); i++)
497  {
498  ostringstream ss;
499  ss<<"pos_"<<eyesJoints[i];
500  info.addString(ss.str());
501  info.addFloat64(ang_[i]);
502  }
503 
504  port_debug.prepare()=info;
505  txInfo_debug.update(q_stamp);
506  port_debug.setEnvelope(txInfo_debug);
507  port_debug.writeStrict();
508  }
509 
510  saccadeStartTime=Time::now();
512  unplugCtrlEyes=true;
513 
514  notifyEvent("saccade-onset");
515 }
516 
517 
518 /************************************************************************/
519 bool Controller::look(const Vector &x)
520 {
521  lock_guard<mutex> lg(mutexLook);
522 
523  mutexRun.lock();
524  bool ret=commData->port_xd->set_xd(x);
525  mutexRun.unlock();
526 
527  if (ret)
528  {
529  unique_lock<mutex> lck(mtx_eventLook);
530  cv_eventLook.wait(lck);
531  }
532 
533  return ret;
534 }
535 
536 
537 /************************************************************************/
539 {
540  lock_guard<mutex> lg(mutexCtrl);
541  mjCtrlEyes->reset(zeros((int)fbEyes.length()));
542  unplugCtrlEyes=false;
543 }
544 
545 
546 /************************************************************************/
548 {
549  vector<int> modes(nJointsHead);
550  modHead->getControlModes(modes.data());
551 
552  jointsToSet.clear();
553  for (int i=0; i<(int)modes.size(); i++)
554  {
555  if ((modes[i]==VOCAB_CM_HW_FAULT) || (modes[i]==VOCAB_CM_IDLE))
556  return false;
557  else if (i<eyesJoints[0])
558  {
559  if (commData->neckPosCtrlOn)
560  {
561  if (modes[i]!=VOCAB_CM_POSITION_DIRECT)
562  jointsToSet.push_back(i);
563  }
564  else if (modes[i]!=VOCAB_CM_VELOCITY)
565  jointsToSet.push_back(i);
566  }
567  else if (modes[i]!=VOCAB_CM_MIXED)
568  jointsToSet.push_back(i);
569  }
570 
571  return true;
572 }
573 
574 
575 /************************************************************************/
577 {
578  if (jointsToSet.empty())
579  return;
580 
581  vector<int> modes;
582  for (auto i : jointsToSet)
583  {
584  if (i<eyesJoints[0])
585  {
586  if (commData->neckPosCtrlOn)
587  modes.push_back(VOCAB_CM_POSITION_DIRECT);
588  else
589  modes.push_back(VOCAB_CM_VELOCITY);
590  }
591  else
592  modes.push_back(VOCAB_CM_MIXED);
593  }
594 
595  modHead->setControlModes((int)jointsToSet.size(),jointsToSet.data(),modes.data());
596 }
597 
598 
599 /************************************************************************/
601 {
603  {
604  if (stabilizeGaze!=f)
605  {
606  lock_guard<mutex> lg(mutexRun);
607  if (f)
608  {
609  if (!commData->ctrlActive)
610  {
611  IntPlan->reset(fbNeck);
612  IntStabilizer->reset(zeros((int)vNeck.length()));
613  }
614  notifyEvent("stabilization-on");
615  }
616  else
617  {
618  lock_guard<mutex> lg(mutexCtrl);
619  q_stamp=Time::now();
620  stopLimb();
621  notifyEvent("stabilization-off");
622  }
623 
625  }
626 
627  return true;
628  }
629  else
630  return false;
631 }
632 
633 
634 /************************************************************************/
636 {
637  return stabilizeGaze;
638 }
639 
640 
641 /************************************************************************/
643 {
644  lock_guard<mutex> lg(mutexRun);
645 
646  mutexCtrl.lock();
647  bool jointsHealthy=areJointsHealthyAndSet();
648  mutexCtrl.unlock();
649 
650  if (!jointsHealthy)
651  {
653  commData->port_xd->get_new()=false;
654  cv_eventLook.notify_all();
655  }
656 
657  string event="none";
658 
659  // verify if any saccade is still underway
660  mutexCtrl.lock();
661  if (commData->saccadeUnderway && (Time::now()-saccadeStartTime>=Ts))
662  {
663  bool done;
664  posHead->checkMotionDone((int)eyesJoints.size(),eyesJoints.data(),&done);
666 
668  notifyEvent("saccade-done");
669  }
670  mutexCtrl.unlock();
671 
672  // get data
673  double x_stamp;
674  Vector xd=commData->get_xd();
675  Vector x=commData->get_x(x_stamp);
676  qd=commData->get_qd();
677 
678  // read feedbacks
679  q_stamp=Time::now();
681  {
682  yError("Communication timeout detected!");
683  notifyEvent("comm-timeout");
684  suspend();
685  return;
686  }
687 
688  // update pose information
689  {
690  mutexChain.lock();
691  for (int i=0; i<nJointsTorso; i++)
692  {
693  chainNeck->setAng(i,fbTorso[i]);
694  chainEyeL->setAng(i,fbTorso[i]);
695  chainEyeR->setAng(i,fbTorso[i]);
696  }
697  for (int i=0; i<3; i++)
698  {
702  }
703 
705  chainEyeL->setAng(nJointsTorso+4,fbHead[4]+fbHead[5]/2.0);
707  chainEyeR->setAng(nJointsTorso+4,fbHead[4]-fbHead[5]/2.0);
708 
709  txInfo_pose.update(q_stamp);
710  mutexChain.unlock();
711  }
712 
714 
715  fbNeck=fbHead.subVector(0,2);
716  fbEyes=fbHead.subVector(3,5);
717 
718  double errNeck=norm(qd.subVector(0,2)-fbNeck);
719  double errEyes=norm(qd.subVector(3,(unsigned int)qd.length()-1)-fbEyes);
720  bool swOffCond=(Time::now()-ctrlActiveRisingEdgeTime<GAZECTRL_SWOFFCOND_DISABLESLOT*getPeriod()) ? false :
724 
725  // verify control switching conditions
726  if (commData->ctrlActive)
727  {
728  // manage new target while controller is active
729  if (commData->port_xd->get_new())
730  {
731  reliableGyro=true;
732 
733  event="motion-onset";
734 
735  mutexData.lock();
737  mutexData.unlock();
738 
739  ctrlActiveRisingEdgeTime=Time::now();
740  commData->port_xd->get_new()=false;
741  }
742  // switch-off condition
743  else if (swOffCond)
744  {
746  {
747  if (!motionDone)
748  event="motion-done";
749  motionDone=true;
750  }
751  else
752  {
753  event="motion-done";
754  mutexCtrl.lock();
755  stopLimb(false);
756  mutexCtrl.unlock();
757  }
758  }
759  }
760  else if (jointsHealthy)
761  {
762  // inhibition is cleared upon new target arrival
763  if (ctrlInhibited)
765 
766  // switch-on condition
768 
769  // reset controllers
770  if (commData->ctrlActive)
771  {
772  ctrlActiveRisingEdgeTime=Time::now();
773  commData->port_xd->get_new()=false;
775 
776  if (stabilizeGaze)
777  {
780  }
781  else
782  {
783  mjCtrlNeck->reset(zeros((int)fbNeck.length()));
784  mjCtrlEyes->reset(zeros((int)fbEyes.length()));
785  IntStabilizer->reset(zeros((int)vNeck.length()));
786  IntPlan->reset(fbNeck);
787  }
788 
789  reliableGyro=true;
790 
791  event="motion-onset";
792 
793  mutexData.lock();
795  mutexData.unlock();
796  }
797  }
798 
799  mutexCtrl.lock();
800  if (event=="motion-onset")
801  {
803  jointsToSet.clear();
804  motionDone=false;
805  q0=fbHead;
806  cv_eventLook.notify_all();
807  }
808  mutexCtrl.unlock();
809 
811  {
812  mutexCtrl.lock();
814  mutexCtrl.unlock();
815  }
816 
817  qdNeck=qd.subVector(0,2);
818  qdEyes=qd.subVector(3,5);
819 
820  // compute current point [%] in the path
821  double dist=norm(qd-q0);
822  pathPerc=(dist>IKIN_ALMOST_ZERO)?norm(fbHead-q0)/dist:1.0;
823  pathPerc=sat(pathPerc,0.0,1.0);
824 
825  if (commData->ctrlActive)
826  {
827  // control
829 
830  if (unplugCtrlEyes)
831  {
832  if (Time::now()-saccadeStartTime>=Ts)
834  }
835  else
837 
838  // stabilization
840  {
841  auto resGyro =commData->get_gyro();
842  Vector gyro{resGyro.first};
843  bool statusGyro = resGyro.second;
844 
845  if (statusGyro) {
846  Vector dx=computedxFP(imu->getH(cat(fbTorso,fbNeck)),zeros((int)fbNeck.length()),gyro,x);
847  Vector imuNeck=computeNeckVelFromdxFP(x,dx);
848  if (reliableGyro)
849  {
851 
852  // only if the speed is low and we are close to the target
854  reliableGyro=false;
855  }
856  // hysteresis
857  else if ((norm(imuNeck)>1.5*commData->gyro_noise_threshold) || (pathPerc<0.9))
858  {
859  IntStabilizer->reset(zeros((int)vNeck.length()));
860  reliableGyro=true;
861  }
862  }
863  }
864 
866  }
867  else if (stabilizeGaze)
868  {
869  auto resGyro =commData->get_gyro();
870  Vector gyro{resGyro.first};
871  bool statusGyro = resGyro.second;
872  if (statusGyro) {
873  Vector dx = computedxFP(imu->getH(cat(fbTorso, fbNeck)), zeros((int) fbNeck.length()), gyro, x);
874  Vector imuNeck = computeNeckVelFromdxFP(x, dx);
875 
878  }
880  }
881  else
882  {
883  vNeck=0.0;
884  vEyes=0.0;
885  }
886 
887  v.setSubvector(0,vNeck);
888  v.setSubvector(3,vEyes);
889 
890  // apply bang-bang just in case to compensate
891  // for unachievable low velocities
892  for (size_t i=0; i<v.length(); i++)
893  if ((v[i]!=0.0) && (v[i]>-min_abs_vel) && (v[i]<min_abs_vel))
894  v[i]=yarp::math::sign(qd[i]-fbHead[i])*min_abs_vel;
895 
896  // convert to degrees
897  mutexData.lock();
901  mutexData.unlock();
902 
903  // send commands to the robot
905  {
906  mutexCtrl.lock();
907 
908  Vector posdeg;
909  if (commData->neckPosCtrlOn)
910  {
911  posdeg=(CTRL_RAD2DEG)*IntPlan->get();
912  posNeck->setPositions((int)neckJoints.size(),neckJoints.data(),posdeg.data());
913  velHead->velocityMove((int)eyesJoints.size(),eyesJoints.data(),vdeg.subVector(3,5).data());
914  }
915  else
916  velHead->velocityMove(vdeg.data());
917 
918  if (commData->debugInfoEnabled && (port_debug.getOutputCount()>0))
919  {
920  Bottle info;
921  int j=0;
922 
923  if (commData->neckPosCtrlOn)
924  {
925  for (size_t i=0; i<posdeg.length(); i++)
926  {
927  ostringstream ss;
928  ss<<"pos_"<<i;
929  info.addString(ss.str());
930  info.addFloat64(posdeg[i]);
931  }
932 
933  j=eyesJoints[0];
934  }
935 
936  for (size_t i=j; i<vdeg.length(); i++)
937  {
938  ostringstream ss;
939  ss<<"vel_"<<i;
940  info.addString(ss.str());
941  info.addFloat64(vdeg[i]);
942  }
943 
944  port_debug.prepare()=info;
945  txInfo_debug.update(q_stamp);
946  port_debug.setEnvelope(txInfo_debug);
947  port_debug.writeStrict();
948  }
949 
950  mutexCtrl.unlock();
951  }
952 
953  // print info
954  if (commData->verbose)
955  printIter(xd,x,qddeg,qdeg,vdeg,1.0);
956 
957  // send x,q through YARP ports
958  Vector q(nJointsTorso+nJointsHead);
959  int j;
960  for (j=0; j<nJointsTorso; j++)
961  q[j]=CTRL_RAD2DEG*fbTorso[j];
962  for (; (size_t)j<q.length(); j++)
963  q[j]=qdeg[j-nJointsTorso];
964 
965  txInfo_x.update(x_stamp);
966  if (port_x.getOutputCount()>0)
967  {
968  port_x.prepare()=x;
969  port_x.setEnvelope(txInfo_x);
970  port_x.write();
971  }
972 
973  txInfo_q.update(q_stamp);
974  if (port_q.getOutputCount()>0)
975  {
976  port_q.prepare()=q;
977  port_q.setEnvelope(txInfo_q);
978  port_q.write();
979  }
980 
981  if (event=="motion-onset")
982  notifyEvent(event);
983 
985 
986  if (event=="motion-done")
987  {
989  notifyEvent(event);
990  }
991 
992  // update joints angles
996  commData->set_v(v);
997 }
998 
999 
1000 /************************************************************************/
1002 {
1003  lock_guard<mutex> lg(mutexCtrl);
1004  PeriodicThread::suspend();
1005  stopLimb();
1006  commData->saccadeUnderway=false;
1007  yInfo("Controller has been suspended!");
1008  notifyEvent("suspended");
1009 }
1010 
1011 
1012 /************************************************************************/
1014 {
1016  fbNeck=fbHead.subVector(0,2);
1017  fbEyes=fbHead.subVector(3,5);
1018 
1019  PeriodicThread::resume();
1020  yInfo("Controller has been resumed!");
1021  notifyEvent("resumed");
1022 }
1023 
1024 
1025 /************************************************************************/
1026 double Controller::getTneck() const
1027 {
1028  return neckTime;
1029 }
1030 
1031 
1032 /************************************************************************/
1033 double Controller::getTeyes() const
1034 {
1035  return eyesTime;
1036 }
1037 
1038 
1039 /************************************************************************/
1040 void Controller::setTneck(const double execTime)
1041 {
1042  double lowerThresNeck=eyesTime+0.2;
1043  if (execTime<lowerThresNeck)
1044  {
1045  yWarning("neck execution time is under the lower bound!");
1046  yWarning("a new neck execution time of %g s is chosen",lowerThresNeck);
1047  neckTime=lowerThresNeck;
1048  }
1049  else
1050  neckTime=execTime;
1051 }
1052 
1053 
1054 /************************************************************************/
1055 void Controller::setTeyes(const double execTime)
1056 {
1057  double lowerThresEyes=10.0*Ts;
1058  if (execTime<lowerThresEyes)
1059  {
1060  yWarning("eyes execution time is under the lower bound!");
1061  yWarning("a new eyes execution time of %g s is chosen",lowerThresEyes);
1062  eyesTime=lowerThresEyes;
1063  }
1064  else
1065  eyesTime=execTime;
1066 
1067  // to realign neck time
1068  setTneck(neckTime);
1069 }
1070 
1071 
1072 /************************************************************************/
1074 {
1075  lock_guard<mutex> lg(mutexRun);
1076  return motionDone;
1077 }
1078 
1079 
1080 /************************************************************************/
1082 {
1083  if (commData->trackingModeOn!=f)
1084  {
1085  if (f)
1086  look(commData->get_x());
1087 
1088  lock_guard<mutex> lg(mutexRun);
1090  yInfo("tracking mode set to %s",
1091  commData->trackingModeOn?"on":"off");
1092  }
1093 }
1094 
1095 
1096 /************************************************************************/
1098 {
1099  return commData->trackingModeOn;
1100 }
1101 
1102 
1103 /************************************************************************/
1104 bool Controller::getDesired(Vector &des)
1105 {
1106  lock_guard<mutex> lg(mutexData);
1107  des=qddeg;
1108  return true;
1109 }
1110 
1111 
1112 /************************************************************************/
1113 bool Controller::getVelocity(Vector &vel)
1114 {
1115  lock_guard<mutex> lg(mutexData);
1116  vel=vdeg;
1117  return true;
1118 }
1119 
1120 
1121 /************************************************************************/
1122 bool Controller::getPose(const string &poseSel, Vector &x, Stamp &stamp)
1123 {
1124  lock_guard<mutex> lg(mutexChain);
1125  if (poseSel=="left")
1126  {
1127  x=chainEyeL->EndEffPose();
1128  stamp=txInfo_pose;
1129  return true;
1130  }
1131  else if (poseSel=="right")
1132  {
1133  x=chainEyeR->EndEffPose();
1134  stamp=txInfo_pose;
1135  return true;
1136  }
1137  else if (poseSel=="head")
1138  {
1139  x=chainNeck->EndEffPose();
1140  stamp=txInfo_pose;
1141  return true;
1142  }
1143  else
1144  return false;
1145 }
1146 
1147 
1148 /************************************************************************/
1149 bool Controller::registerMotionOngoingEvent(const double checkPoint)
1150 {
1151  lock_guard<mutex> lg(mutexData);
1152  if ((checkPoint>=0.0) && (checkPoint<=1.0))
1153  {
1154  motionOngoingEvents.insert(checkPoint);
1155  return true;
1156  }
1157  else
1158  return false;
1159 }
1160 
1161 
1162 /************************************************************************/
1163 bool Controller::unregisterMotionOngoingEvent(const double checkPoint)
1164 {
1165  lock_guard<mutex> lg(mutexData);
1166 
1167  bool ret=false;
1168  if ((checkPoint>=0.0) && (checkPoint<=1.0))
1169  {
1170  auto itr=motionOngoingEvents.find(checkPoint);
1171  if (itr!=motionOngoingEvents.end())
1172  {
1173  motionOngoingEvents.erase(itr);
1174  ret=true;
1175  }
1176  }
1177 
1178  return ret;
1179 }
1180 
1181 
1182 /************************************************************************/
1184 {
1185  lock_guard<mutex> lg(mutexData);
1186 
1187  Bottle events;
1188  for (auto motionOngoingEvent : motionOngoingEvents)
1189  events.addFloat64(motionOngoingEvent);
1190 
1191  return events;
1192 }
1193 
1194 
@ data
#define CTRL_RAD2DEG
Definition: XSensMTx.cpp:25
#define CTRL_DEG2RAD
Definition: XSensMTx.cpp:26
bool unregisterMotionOngoingEvent(const double checkPoint)
iCubInertialSensor * imu
Definition: controller.h:57
mutex mtx_eventLook
Definition: controller.h:87
void stopControlHelper()
Definition: controller.cpp:329
iKinChain * chainNeck
Definition: controller.h:58
virtual ~Controller()
Definition: controller.cpp:158
void stopLimb(const bool execStopPosition=true)
Definition: controller.cpp:265
double eyesTime
Definition: controller.h:101
Vector vNeck
Definition: controller.h:110
bool setGazeStabilization(const bool f)
Definition: controller.cpp:600
void setJointsCtrlMode()
Definition: controller.cpp:576
BufferedPort< Bottle > port_event
Definition: controller.h:74
double saccadeStartTime
Definition: controller.h:98
bool getPose(const string &poseSel, Vector &x, Stamp &stamp)
double getTeyes() const
mutex mutexRun
Definition: controller.h:82
void resume()
void afterStart(bool s) override
Definition: controller.cpp:402
bool reliableGyro
Definition: controller.h:93
iKinChain * chainEyeR
Definition: controller.h:58
void threadRelease() override
Definition: controller.cpp:379
Vector qdEyes
Definition: controller.h:111
Vector computedxFP(const Matrix &H, const Vector &v, const Vector &w, const Vector &x_FP)
Definition: controller.cpp:412
void printIter(Vector &xd, Vector &fp, Vector &qd, Vector &q, Vector &v, double printTime)
Definition: controller.cpp:343
double printAccTime
Definition: controller.h:99
void suspend()
PolyDriver * drvHead
Definition: controller.h:59
vector< int > neckJoints
Definition: controller.h:113
void stopControl()
Definition: controller.cpp:321
int nJointsHead
Definition: controller.h:96
mutex mutexChain
Definition: controller.h:83
minJerkVelCtrl * mjCtrlNeck
Definition: controller.h:66
unsigned int period
Definition: controller.h:89
Matrix lim
Definition: controller.h:108
double startupMinVer
Definition: controller.h:104
iKinChain * chainEyeL
Definition: controller.h:58
bool ctrlInhibited
Definition: controller.h:91
PolyDriver * drvTorso
Definition: controller.h:59
mutex mutexCtrl
Definition: controller.h:84
Vector computeEyesVelFromdxFP(const Vector &dfp)
Definition: controller.cpp:464
void setTeyes(const double execTime)
bool areJointsHealthyAndSet()
Definition: controller.cpp:547
Vector fbHead
Definition: controller.h:112
void motionOngoingEventsFlush()
Definition: controller.cpp:253
vector< int > jointsToSet
Definition: controller.h:114
multiset< double > motionOngoingEvents
Definition: controller.h:116
bool look(const Vector &x)
Definition: controller.cpp:519
Vector fbEyes
Definition: controller.h:112
void notifyEvent(const string &event, const double checkPoint=-1.0)
Definition: controller.cpp:218
minJerkVelCtrl * mjCtrlEyes
Definition: controller.h:67
void minAllowedVergenceChanged() override
Definition: controller.cpp:210
void setTneck(const double execTime)
bool getVelocity(Vector &vel)
int nJointsTorso
Definition: controller.h:95
void doSaccade(const Vector &ang, const Vector &vel)
Definition: controller.cpp:476
Stamp txInfo_event
Definition: controller.h:79
bool threadInit() override
Definition: controller.cpp:362
mutex mutexLook
Definition: controller.h:86
Vector fbNeck
Definition: controller.h:112
Vector qdNeck
Definition: controller.h:111
bool isMotionDone()
ExchangeData * commData
Definition: controller.h:64
Vector vEyes
Definition: controller.h:110
Vector qddeg
Definition: controller.h:109
Vector q0
Definition: controller.h:111
bool getDesired(Vector &des)
void findMinimumAllowedVergence()
Definition: controller.cpp:173
vector< int > eyesJoints
Definition: controller.h:113
void resetCtrlEyes()
Definition: controller.cpp:538
Vector qd
Definition: controller.h:111
IPositionControl * posHead
Definition: controller.h:61
Integrator * IntState
Definition: controller.h:68
Stamp txInfo_pose
Definition: controller.h:78
void setTrackingMode(const bool f)
bool getGazeStabilization() const
Definition: controller.cpp:635
Stamp txInfo_debug
Definition: controller.h:80
double ctrlActiveRisingEdgeTime
Definition: controller.h:97
void motionOngoingEventsHandling()
Definition: controller.cpp:238
Stamp txInfo_x
Definition: controller.h:76
Vector qdeg
Definition: controller.h:109
BufferedPort< Vector > port_q
Definition: controller.h:73
Integrator * IntStabilizer
Definition: controller.h:70
IPositionDirect * posNeck
Definition: controller.h:63
Vector fbTorso
Definition: controller.h:112
IVelocityControl * velHead
Definition: controller.h:62
Vector vdeg
Definition: controller.h:109
IControlMode * modHead
Definition: controller.h:60
double q_stamp
Definition: controller.h:105
Controller(PolyDriver *_drvTorso, PolyDriver *_drvHead, ExchangeData *_commData, const double _neckTime, const double _eyesTime, const double _min_abs_vel, const unsigned int _period)
Definition: controller.cpp:28
BufferedPort< Bottle > port_debug
Definition: controller.h:75
Stamp txInfo_q
Definition: controller.h:77
bool stabilizeGaze
Definition: controller.h:94
double min_abs_vel
Definition: controller.h:103
BufferedPort< Vector > port_x
Definition: controller.h:72
void run() override
Definition: controller.cpp:642
double pathPerc
Definition: controller.h:102
bool unplugCtrlEyes
Definition: controller.h:90
mutex mutexData
Definition: controller.h:85
double getTneck() const
double Ts
Definition: controller.h:106
double neckTime
Definition: controller.h:100
iCubHeadCenter * neck
Definition: controller.h:56
Integrator * IntPlan
Definition: controller.h:69
multiset< double > motionOngoingEventsCurrent
Definition: controller.h:117
Vector computeNeckVelFromdxFP(const Vector &fp, const Vector &dfp)
Definition: controller.cpp:435
bool getTrackingMode() const
bool motionDone
Definition: controller.h:92
condition_variable cv_eventLook
Definition: controller.h:88
Vector v
Definition: controller.h:110
Bottle listMotionOngoingEvents()
bool registerMotionOngoingEvent(const double checkPoint)
ResourceFinder rf_cameras
Definition: utils.h:156
Vector get_xd()
Definition: utils.cpp:264
Vector get_qd()
Definition: utils.cpp:273
bool stabilizationOn
Definition: utils.h:154
double stabilizationGain
Definition: utils.h:142
bool trackingModeOn
Definition: utils.h:148
std::pair< Vector, bool > get_gyro()
Definition: utils.cpp:345
Vector get_x()
Definition: utils.cpp:282
double gyro_noise_threshold
Definition: utils.h:141
void set_q(const Vector &_q)
Definition: utils.cpp:225
bool tweakOverwrite
Definition: utils.h:151
Vector get_counterv()
Definition: utils.cpp:328
ResourceFinder rf_tweak
Definition: utils.h:157
bool ctrlActive
Definition: utils.h:147
double minAllowedVergence
Definition: utils.h:139
int neckSolveCnt
Definition: utils.h:146
xdPort * port_xd
Definition: utils.h:135
bool debugInfoEnabled
Definition: utils.h:159
void set_v(const Vector &_v)
Definition: utils.cpp:241
iKinLimbVersion head_version
Definition: utils.h:143
bool neckPosCtrlOn
Definition: utils.h:153
bool saccadeUnderway
Definition: utils.h:149
bool verbose
Definition: utils.h:150
string localStemName
Definition: utils.h:137
void set_torso(const Vector &_torso)
Definition: utils.cpp:233
iCubEye * eyeR
Definition: utils.h:173
iCubEye * eyeL
Definition: utils.h:172
A class for defining a saturated integrator based on Tustin formula: .
Definition: pids.h:48
const yarp::sig::Vector & integrate(const yarp::sig::Vector &x)
Executes one-step integration of input vector.
Definition: pids.cpp:115
void reset(const yarp::sig::Vector &y0)
Resets the internal state and sets the output vector to the given value.
Definition: pids.cpp:128
void setLim(const yarp::sig::Matrix &_lim)
Sets the output vector constraints matrix.
Definition: pids.cpp:104
const yarp::sig::Vector & get() const
Returns the current output vector.
Definition: pids.h:154
Implements a minimum-jerk controller with velocity commands in the assumption that the plant can be m...
Definition: minJerkCtrl.h:82
virtual void reset(const yarp::sig::Vector &u0)=0
Resets the controller to a given value.
virtual yarp::sig::Vector computeCmd(const double _T, const yarp::sig::Vector &e)=0
Computes the velocity command.
A class for defining the iCub Eye.
Definition: iKinFwd.h:1386
A class for describing the kinematic of the straight line coming out from the point located between t...
Definition: iKinFwd.h:1451
A class for defining the Inertia Sensor Kinematics of the iCub.
Definition: iKinFwd.h:1477
A Base class for defining a Serial Link Chain.
Definition: iKinFwd.h:355
yarp::sig::Matrix getH(const unsigned int i, const bool allLink=false)
Returns the rigid roto-translation matrix from the root reference frame to the ith frame in Denavit-H...
Definition: iKinFwd.cpp:732
bool setHN(const yarp::sig::Matrix &_HN)
Sets HN, the rigid roto-translation matrix from the Nth frame to the end-effector.
Definition: iKinFwd.cpp:580
yarp::sig::Matrix GeoJacobian(const unsigned int i)
Returns the geometric Jacobian of the ith link.
Definition: iKinFwd.cpp:1012
bool releaseLink(const unsigned int i)
Releases the ith Link.
Definition: iKinFwd.cpp:463
yarp::sig::Vector EndEffPose(const bool axisRep=true)
Returns the coordinates of end-effector.
Definition: iKinFwd.cpp:850
yarp::sig::Vector setAng(const yarp::sig::Vector &q)
Sets the free joint angles to values of q[i].
unsigned int getDOF() const
Returns the current number of Chain's DOF.
Definition: iKinFwd.h:557
void setAllConstraints(bool _constrained)
Sets the constraint status of all chain links.
Definition: iKinFwd.cpp:498
std::string get_version() const
Return the version string.
Definition: iKinFwd.cpp:1600
iKinChain * asChain()
Returns a pointer to the Limb seen as Chain object.
Definition: iKinFwd.h:1013
bool set_xd(const Vector &_xd)
Definition: utils.cpp:83
bool & get_new()
Definition: utils.h:84
zeros(2, 2) eye(2
constexpr double GAZECTRL_MOTIONDONE_EYES_QTHRES
Definition: controller.h:39
constexpr int32_t GAZECTRL_SWOFFCOND_DISABLESLOT
Definition: controller.h:37
constexpr double GAZECTRL_CRITICVER_STABILIZATION
Definition: controller.h:40
constexpr double GAZECTRL_MOTIONDONE_NECK_QTHRES
Definition: controller.h:38
double norm(const yarp::sig::Matrix &M, int col)
Returns the norm of the vector given in the form: matrix(:,col).
yarp::sig::Vector cross(const yarp::sig::Matrix &A, int colA, const yarp::sig::Matrix &B, int colB)
Returns the cross product between two vectors given in the form: matrix(:,col).
#define IKIN_ALMOST_ZERO
Definition: iKinHlp.h:27
bool done
Definition: main.cpp:42
void copyJointsBounds(iKinChain *ch1, iKinChain *ch2)
Definition: utils.cpp:602
bool getAlignHN(const ResourceFinder &rf, const string &type, iKinChain *chain, const bool verbose=false)
Definition: utils.cpp:474
bool getFeedback(Vector &fbTorso, Vector &fbHead, PolyDriver *drvTorso, PolyDriver *drvHead, const ExchangeData *commData, double *timeStamp=nullptr)
Definition: utils.cpp:633
Matrix alignJointsBounds(iKinChain *chain, PolyDriver *drvTorso, PolyDriver *drvHead, const ExchangeData *commData)
Definition: utils.cpp:531
double sat(const double val, const double min, const double max)
Definition: utils.h:183
const FSC max
Definition: strain.h:48
static struct bpf_program fp