icub-basic-demos
main.cpp
1 /*
2  * Copyright (C) 2010 RobotCub Consortium, European Commission FP6 Project IST-004370
3  * Author: Lorenzo Natale
4  * email: lorenzo.natale@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 
71 #include <list>
72 #include <map>
73 #include <vector>
74 #include <string>
75 #include <iostream>
76 #include <fstream>
77 #include <cmath>
78 
79 #include <yarp/os/BufferedPort.h>
80 #include <yarp/os/Time.h>
81 #include <yarp/os/Network.h>
82 #include <yarp/os/PeriodicThread.h>
83 #include <yarp/os/Thread.h>
84 #include <yarp/os/Property.h>
85 #include <yarp/os/Vocab.h>
86 #include <yarp/os/Log.h>
87 #include <yarp/os/LogStream.h>
88 #include <yarp/os/Terminator.h>
89 #include <yarp/dev/ControlBoardInterfaces.h>
90 #include <yarp/dev/PolyDriver.h>
91 #include <yarp/sig/Vector.h>
92 #include <yarp/os/ResourceFinder.h>
93 
94 using namespace std;
95 using namespace yarp::dev;
96 using namespace yarp::os;
97 using namespace yarp::sig;
98 
99 const int FIXED_TIME_MOVE=5;
100 const int SAMPLER_RATE=100;
102 
103 struct LimbInterfaces
104 {
105  PolyDriver *dd;
106  IPositionControl *ipos;
107  IEncoders *ienc;
108  Vector encoders;
109  Vector speed;
110  Vector cmd;
111  bool *md;
112  int nj;
113  LimbInterfaces() : dd(0), ipos(0), ienc(0), md(0)
114  { }
115 
116  ~LimbInterfaces()
117  {
118  if (!md)
119  delete[] md;
120  }
121 
122  void resize(int n)
123  {
124  nj=n;
125  cmd.resize(nj);
126  encoders.resize(nj);
127  speed.resize(nj);
128  md=new bool[nj];
129  }
130 
131 };
132 
133 typedef std::list<Vector> PositionList;
134 typedef PositionList::iterator PositionListIterator;
135 typedef std::vector<PositionList> RobotSequence;
136 typedef std::vector<LimbInterfaces> RobotInterfaces;
137 typedef RobotInterfaces::iterator RobotInterfacesIterator;
138 
139 uint8_t LIMBS = 6;
140 
141 enum Index
142 {
143  RIGHTARM=0,
144  LEFTARM=1,
145  HEAD=2,
146  TORSO=3,
147  RIGHTLEG=4,
148  LEFTLEG=5};
149 
150 class DemoSequences
151 {
152 public:
153  std::vector<std::string> tags;
154  RobotSequence sequences;
155 
156  DemoSequences(const std::vector<std::string> &t)
157  {
158  tags=t;
159  sequences.resize(LIMBS);
160  }
161 
162  bool fromFile(const char *filename)
163  {
164  Property config;
165  config.fromConfigFile(filename);
166  bool ret=true;
167 
168  for (int k=0; k<LIMBS; k++)
169  {
170  Bottle seqFile=config.findGroup(tags[k].c_str());
171  int length=(seqFile.findGroup("DIMENSIONS").find("numberOfPoses")).asInt32();
172  int nj=seqFile.findGroup("DIMENSIONS").find("numberOfJoints").asInt32();
173  for (int ii=0; ii<length; ii++)
174  {
175  char tmp[80];
176  if (seqFile.findGroup("REORDER").isNull())
177  sprintf(tmp,"POSITION%d",ii);
178  else
179  sprintf(tmp,"POSITION%d",seqFile.findGroup("REORDER").findGroup("order").get(ii+1).asInt32());
180  Bottle &xtmp=seqFile.findGroup(tmp).findGroup("jointPositions");
181  Vector vect;
182  vect.resize(nj);
183  if (nj!=xtmp.size()-1)
184  yWarning("**** WARNING: mismatch of sizes in the input file! nj=%d, xtmp=%d \n",nj,xtmp.size());
185  for (int l=0; l<xtmp.size()-1; l++)
186  vect[l]=xtmp.get(l+1).asFloat64();
187  sequences[k].push_back(vect);
188  }
189  }
190 
191  return ret;
192  }
193 
194  void dump()
195  {
196  for (int l=0; l<LIMBS; l++)
197  {
198  yInfo("Sequence for %s:",tags[l].c_str());
199 
200  int s=sequences[l].size();
201  PositionListIterator it=sequences[l].begin();
202  while (it!=sequences[l].end())
203  {
204  Vector &v=(*it);
205  yInfo("%s",v.toString().c_str());
206  it++;
207  }
208 
209  yInfo("-----");
210  }
211  }
212 };
213 
214 class Robot
215 {
216 public:
217 
218  std::vector<std::string> tags;
219  std::vector<Property> options;
220  RobotInterfaces interfaces;
221 
222  Robot()
223  {
224  tags.resize(LIMBS);
225  options.resize(LIMBS);
226  interfaces.resize(LIMBS);
227  }
228 
229  ~Robot()
230  {
231  RobotInterfacesIterator it;
232  for (it=interfaces.begin(); it!=interfaces.end(); it++)
233  {
234  if ((*it).dd!=0)
235  {
236  (*it).dd->close();
237  delete (*it).dd;
238  }
239  }
240  }
241 
242  bool createDevices()
243  {
244  bool success=true;
245  for (int k=0; k<LIMBS; k++)
246  {
247  LimbInterfaces tmp;
248  tmp.dd=new PolyDriver;
249  tmp.dd->open(options[k]);
250  if (!tmp.dd->isValid())
251  {
252  yError("Error opening %s",tags[k].c_str());
253  return false;
254  }
255 
256  bool ret=true;
257  ret=ret && tmp.dd->view(tmp.ipos);
258  ret=ret && tmp.dd->view(tmp.ienc);
259 
260  interfaces[k]=tmp;
261  success=success && ret;
262  }
263  return success;
264  }
265 };
266 
267 class RobotMover : public PeriodicThread
268 {
269 private:
270  RobotSequence sequences;
271  bool sequencesF;
272 
273  bool motion_done;
274  int nJoints;
275 
276  int count;
277  Robot *robot;
278  bool done;
279 
280  bool verbose;
281 
282  PositionListIterator *its;
283  PositionListIterator *itends;
284  double motionTime;
285  bool spoke;
286 public:
287  RobotMover(Robot *r, int rate) : PeriodicThread((double)rate/1000.0)
288  {
289  sequencesF=false;
290  robot=r;
291  verbose=false;
292  its=new PositionListIterator[LIMBS];
293  itends=new PositionListIterator[LIMBS];
294  motionTime=FIXED_TIME_MOVE;
295  spoke=false;
296  }
297 
298  ~RobotMover()
299  {
300  delete[] its;
301  delete[] itends;
302  }
303 
304  void setVerbose(bool f)
305  { verbose=f; }
306 
307  void waitMotion(double dT, bool checkDone=false)
308  {
309  bool done=false;
310  Time::delay(dT);
311  if (checkDone)
312  {
313  double acc=0;
314  while (!done)
315  {
316  done=true;
317  for (int k=0; k<LIMBS; k++)
318  {
319  bool d=true;
320  bool *tmp=robot->interfaces[k].md;
321  for (int j=0; j<robot->interfaces[k].nj; j++)
322  {
323  //robot->interfaces[k].ipos->checkMotionDone(j, tmp);
324  *tmp=true;
325  done=done && (*tmp);
326  tmp++;
327  }
328 
329  Time::delay(0.05);
330  acc+=0.05;
331  }
332  Time::delay(0.1);
333  acc+=0.1;
334 
335  if (acc>2)
336  done=true;
337  }
338 
339  for (int k=0; k<LIMBS; k++)
340  {
341  bool d=true;
342  yInfo("%s dumping MotionDone:",robot->tags[k].c_str());
343  for (int j=0; j<robot->interfaces[k].nj; j++)
344  yInfo("%s",robot->interfaces[k].md[j]?"true":"false");
345  }
346  }
347  }
348 
349  void computeSpeed(double dT)
350  {
351  if (dT<=0)
352  return;
353 
354  for (int l=0; l<LIMBS; l++)
355  {
356  int nj=robot->interfaces[l].nj;
357  Vector &encs=robot->interfaces[l].encoders;
358  Vector &sp=robot->interfaces[l].speed;
359  Vector &cmd=robot->interfaces[l].cmd;
360 
361  for (int j=0; j<nj; j++)
362  {
363  double dp=fabs(encs[j]-cmd[j]);
364  double tmp=dp/dT;
365  if (tmp<0.1)
366  tmp=0.1;
367 
368  sp[j]=tmp;
369  }
370  }
371  }
372 
373  void resetSequence()
374  {
375  for (int l=0; l<LIMBS; l++)
376  {
377  its[l]=sequences[l].begin();
378  itends[l]=sequences[l].end();
379  }
380  }
381 
382  bool threadInit()
383  {
384  yInfo("Starting controller...");
385  if (!sequencesF)
386  {
387  yError("sequences not set, returning false");
388  return false;
389  }
390 
391  resetSequence();
392  for (int l=0; l<LIMBS; l++)
393  {
394  int nj;
395  robot->interfaces[l].ipos->getAxes(&nj);
396  robot->interfaces[l].resize(nj);
397  robot->interfaces[l].speed=0;
398  robot->interfaces[l].encoders=0;
399  robot->interfaces[l].cmd=0;
400  }
401 
402  done=false;
403  return true;
404  }
405 
406  void run()
407  {
408  yInfo("Running...");
409  spoke=false;
410  if (!done)
411  {
412  for (int l=0; l<LIMBS; l++)
413  {
414  Vector &p=*(its[l]);
415  while (!robot->interfaces[l].ienc->getEncoders(robot->interfaces[l].encoders.data()))
416  {
417  if (!spoke)
418  {
419  yDebug("Waiting for encoders!\n");
420  spoke=true;
421  }
422 
423  }
424  robot->interfaces[l].cmd=p;
425  its[l]++;
426  }
427 
428  computeSpeed(motionTime);
429 
430  for (int l=0; l<LIMBS; l++)
431  {
432  robot->interfaces[l].ipos->setRefSpeeds(robot->interfaces[l].speed.data());
433  robot->interfaces[l].ipos->positionMove(robot->interfaces[l].cmd.data());
434 
435  if (verbose)
436  {
437  yInfo("%s",robot->tags[l].c_str());
438  yInfo("going to: %s ",robot->interfaces[l].cmd.toString().c_str());
439  yInfo("speed: %s ",robot->interfaces[l].speed.toString().c_str());
440  yInfo("-------");
441  }
442  }
443 
444  //wait a bit less, adjustment
445  waitMotion(motionTime);
446  }
447 
448  if (its[0]==itends[0])
449  {
450  static int count=1;
451  resetSequence();
452  yInfo("Sequence %d completed",count);
453  count++;
454  //done=true;
455  }
456  }
457 
458  void setTime(double dT)
459  {
460  motionTime=dT;
461  }
462 
463  void waitDone()
464  {
465  while (!done)
466  Time::delay(0.5);
467  }
468 
469  void suspend()
470  {
471 
472  }
473 
474  void resume()
475  {
476 
477  }
478 
479  void threadRelease()
480  {
481  yInfo("Stopping controller...");
482  }
483 
484  void setSequences(const RobotSequence &seq)
485  {
486  sequences=seq;
487  sequencesF=true;
488  }
489 };
490 
491 
492 int main(int argc, char *argv[])
493 {
494  Network yarp;
495  // pick up name of main configuration file
496 
497  // find configuration file via ResourceFinder if needed
498  // This is trivial if full path has already been provided,
499  // but less trivial if just a filename has been given.
500  // There is also the possibility of user overrides in
501  // standardized forms not anticipated in this program.
502  ResourceFinder finder;
503  bool no_legs{ false };
504  finder.setDefaultContext("demoYoga");
505  finder.configure(argc,argv);
506  finder.setDefault("positions","yoga.ini");
507  finder.setDefault("robot","icub");
508  std::string inifile=finder.findFile("positions").c_str();
509  std::string robotName=finder.find("robot").asString().c_str();
510 
511  bool verbose=finder.check("verbose");
512  bool diagnostic=finder.check("diagnostic");
513  no_legs = finder.check("no_legs");
514  if (no_legs)
515  LIMBS = 4;
516 
517  if (inifile=="")
518  {
519  yError("No position file specified");
520  return 1;
521  }
522  else
523  {
524  yInfo("Reading positions file from %s",inifile.c_str());
525  }
526 
527  std::string prefix=string("/")+robotName+"/";
528 
529  Robot icub;
530 
531  icub.options[0].put("device","remote_controlboard");
532  icub.options[0].put("local",(prefix+"demoYoga/right_arm/client").c_str());
533  icub.options[0].put("remote",(prefix+"right_arm").c_str());
534  icub.tags[0]="RIGHTARM";
535 
536  icub.options[1].put("device","remote_controlboard");
537  icub.options[1].put("local",(prefix+"demoYoga/left_arm/client").c_str());
538  icub.options[1].put("remote",(prefix+"left_arm").c_str());
539  icub.tags[1]="LEFTARM";
540 
541  icub.options[2].put("device","remote_controlboard");
542  icub.options[2].put("local",(prefix+"demoYoga/head/client").c_str());
543  icub.options[2].put("remote",(prefix+"head").c_str());
544  icub.tags[2]="HEAD";
545 
546  icub.options[3].put("device","remote_controlboard");
547  icub.options[3].put("local",(prefix+"demoYoga/torso/client").c_str());
548  icub.options[3].put("remote",(prefix+"torso").c_str());
549  icub.tags[3]="TORSO";
550 
551  if (!no_legs) {
552  icub.options[4].put("device", "remote_controlboard");
553  icub.options[4].put("local", (prefix + "demoYoga/right_leg/client").c_str());
554  icub.options[4].put("remote", (prefix + "right_leg").c_str());
555  icub.tags[4] = "RIGHTLEG";
556 
557  icub.options[5].put("device", "remote_controlboard");
558  icub.options[5].put("local", (prefix + "demoYoga/left_leg/client").c_str());
559  icub.options[5].put("remote", (prefix + "left_leg").c_str());
560  icub.tags[5] = "LEFTLEG";
561  }
562 
563  if (diagnostic)
564  {
565  for (int k=0; k<LIMBS; k++)
566  icub.options[k].put("diagnostic","");
567  }
568 
569  DemoSequences *sequences=new DemoSequences(icub.tags);
570 
571  sequences->fromFile(inifile.c_str());
572  if (verbose)
573  sequences->dump();
574 
575  Property op;
576  op.fromConfigFile(inifile.c_str());
577  double dT=-1;
578  if (op.check("time"))
579  dT=op.find("time").asFloat64();
580 
581  if (!icub.createDevices())
582  {
583  yError("Error creating devices, check parameters");
584  return 1;
585  }
586 
587  RobotMover *robot_mover=new RobotMover(&icub,SAMPLER_RATE);
588  robot_mover->setVerbose(verbose);
589  robot_mover->setSequences(sequences->sequences);
590  if (dT>0)
591  {
592  yInfo("Setting time to %g",dT);
593  robot_mover->setTime(dT);
594  }
595 
596  robot_mover->start();
597 
598  std::string reply;
599  while (reply!="quit")
600  {
601  std::cin>>reply;
602  }
603 
604  yInfo("Received a quit message");
605  robot_mover->stop();
606 
607  delete robot_mover;
608  delete sequences;
609 
610  return 0;
611 }