funny-things
All Modules
main.cpp
1/*
2 * Copyright (C) 2013 iCub Facility - Istituto Italiano di Tecnologia
3 * Author: Ugo Pattacini
4 * email: ugo.pattacini@iit.it
5 * Permission is granted to copy, distribute, and/or modify this program
6 * under the terms of the GNU General Public License, version 2 or any
7 * later version published by the Free Software Foundation.
8 *
9 * A copy of the license can be found at
10 * http://www.robotcub.org/icub/license/gpl.txt
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15 * Public License for more details
16*/
17
51#include <string>
52#include <sstream>
53#include <deque>
54#include <algorithm>
55
56#include <yarp/os/all.h>
57#include <yarp/sig/all.h>
58#include <yarp/dev/all.h>
59#include <yarp/math/Math.h>
60#include <iCub/action/actionPrimitives.h>
61
62#include <tinyxml.h>
63
64using namespace std;
65using namespace yarp::os;
66using namespace yarp::dev;
67using namespace yarp::sig;
68using namespace yarp::math;
69using namespace iCub::action;
70
71
72/************************************************************************/
73class Gazer : public PeriodicThread
74{
75 IGazeControl *igaze;
76 ActionPrimitives *action;
77 Vector offset;
78
79public:
80 /************************************************************************/
81 Gazer(PolyDriver &driver, ActionPrimitives *action, const Vector &offset) :
82 PeriodicThread(0.05)
83 {
84 driver.view(this->igaze);
85 this->action=action;
86 this->offset=offset;
87 }
88
89 /************************************************************************/
90 void run()
91 {
92 Vector x,o;
93 action->getPose(x,o);
94 igaze->lookAtFixationPoint(x+offset);
95 }
96};
97
98
99/************************************************************************/
100class WriterModule: public RFModule
101{
102protected:
103 ActionPrimitives *action;
104 PolyDriver driverArm;
105 PolyDriver driverGaze;
106 Gazer *gazer;
107 RpcServer rpcPort;
108 bool interrupting;
109 bool impedanceOn;
110
111 struct SegmentParameters
112 {
113 string type;
114 Vector orientation;
115 double delta_z;
116 double reach_above;
117 double segment_time;
118 double cartesian_time;
119 double cartesian_straightness;
120 };
121
122 deque<SegmentParameters> segParams;
123 deque<deque<ActionPrimitivesWayPoint> > wayPoints;
124 Vector stiffness_old,damping_old,orientation;
125 double scale,reach_above,segment_time,cartesian_time,cartesian_straightness;
126 Matrix H;
127
128 /************************************************************************/
129 void setStraightness(const double straightness)
130 {
131 ICartesianControl *icart;
132 action->getCartesianIF(icart);
133
134 Bottle options;
135 Bottle &straightOpt=options.addList();
136 straightOpt.addString("straightness");
137 straightOpt.addFloat64(straightness);
138 icart->tweakSet(options);
139 }
140
141 /************************************************************************/
142 Vector parseDrawing(TiXmlDocument& drawing)
143 {
144 SegmentParameters params;
145 params.orientation=orientation;
146 params.delta_z=0.0;
147 params.reach_above=reach_above;
148 params.segment_time=segment_time;
149 params.cartesian_time=cartesian_time;
150 params.cartesian_straightness=cartesian_straightness;
151
152 ActionPrimitivesWayPoint wp;
153 wp.granularity=0.05;
154 wp.trajTime=cartesian_time;
155 wp.duration=segment_time;
156 wp.x=0.0;
157 wp.o=orientation;
158 wp.oEnabled=true;
159
160 Vector top_left_corner(2,0.0);
161
162 TiXmlHandle hText(&drawing);
163 TiXmlElement *pElem;
164
165 pElem=hText.FirstChildElement().Element();
166 if (pElem==NULL)
167 return top_left_corner;
168
169 string type=pElem->Value();
170 if (type!="svg")
171 return top_left_corner;
172
173 pElem=TiXmlHandle(pElem).FirstChildElement().Element();
174 while (pElem!=NULL)
175 {
176 string type=pElem->Value();
177 if (type=="line")
178 {
179 deque<ActionPrimitivesWayPoint> path;
180
181 pElem->QueryDoubleAttribute("x1",&wp.x[0]);
182 pElem->QueryDoubleAttribute("y1",&wp.x[1]);
183 wp.x*=scale;
184 path.push_back(wp);
185
186 top_left_corner[0]=std::min(top_left_corner[0],wp.x[0]);
187 top_left_corner[1]=std::min(top_left_corner[1],wp.x[1]);
188
189 pElem->QueryDoubleAttribute("x2",&wp.x[0]);
190 pElem->QueryDoubleAttribute("y2",&wp.x[1]);
191 wp.x*=scale;
192 path.push_back(wp);
193
194 top_left_corner[0]=std::min(top_left_corner[0],wp.x[0]);
195 top_left_corner[1]=std::min(top_left_corner[1],wp.x[1]);
196
197 params.type="line";
198 segParams.push_back(params);
199 wayPoints.push_back(path);
200 }
201 else if (type=="polyline")
202 {
203 deque<ActionPrimitivesWayPoint> path;
204 Bottle points(pElem->Attribute("points"));
205 wp.duration/=points.size();
206
207 for (int i=0; i<points.size(); i+=2)
208 {
209 wp.x[0]=scale*points.get(i).asFloat64();
210 wp.x[1]=scale*points.get(i+1).asFloat64();
211 path.push_back(wp);
212
213 top_left_corner[0]=std::min(top_left_corner[0],wp.x[0]);
214 top_left_corner[1]=std::min(top_left_corner[1],wp.x[1]);
215 }
216
217 params.type="polyline";
218 segParams.push_back(params);
219 wayPoints.push_back(path);
220 }
221
222 pElem=pElem->NextSiblingElement();
223 }
224
225 return top_left_corner;
226 }
227
228 /************************************************************************/
229 void tranformPoints(const Vector &data_top_left_corner)
230 {
231 for (size_t i=0; i<wayPoints.size(); i++)
232 {
233 for (size_t j=0; j<wayPoints[i].size(); j++)
234 {
235 Vector p=wayPoints[i][j].x;
236 p.push_back(1.0);
237
238 p[0]-=data_top_left_corner[0];
239 p[1]-=data_top_left_corner[1];
240
241 wayPoints[i][j].x=(H*p).subVector(0,2);
242 wayPoints[i][j].x[2]+=segParams[i].delta_z;
243 }
244 }
245 }
246
247 /************************************************************************/
248 void printPoints()
249 {
250 for (size_t i=0; i<wayPoints.size(); i++)
251 {
252 for (size_t j=0; j<wayPoints[i].size(); j++)
253 {
254 yInfo()<<"point["<<i<<"]["<<j<<"]=("
255 <<wayPoints[i][j].x.toString(3,3).c_str()<<")";
256 }
257 }
258 }
259
260 /************************************************************************/
261 bool doWriting()
262 {
263 if (gazer!=NULL)
264 {
265 if (gazer->isSuspended())
266 gazer->resume();
267 else
268 gazer->start();
269 }
270
271 Vector torsoEnabled,torsoDisabled(3,0.0);
272 action->getTorsoJoints(torsoEnabled);
273
274 Vector x,o,x_offset(3,0.0);
275
276 bool done;
277 size_t i;
278 for (i=0; i<wayPoints.size(); i++)
279 {
280 setStraightness(segParams[i].cartesian_straightness);
281
282 action->getPose(x,o);
283 x_offset[2]=segParams[i].reach_above;
284 action->pushAction(x+x_offset,segParams[i].orientation);
285 action->pushAction(wayPoints[i][0].x+x_offset,segParams[i].orientation);
286 action->pushAction(wayPoints[i][0].x,segParams[i].orientation);
287
288 action->checkActionsDone(done,true);
289 if (interrupting)
290 return false;
291
292 action->setTorsoJoints(torsoDisabled);
293 action->pushAction(wayPoints[i]);
294
295 action->checkActionsDone(done,true);
296 action->setTorsoJoints(torsoEnabled);
297 if (interrupting)
298 return false;
299 }
300
301 i--;
302 action->getPose(x,o);
303 x_offset[2]=segParams[i].reach_above;
304 action->pushAction(x+x_offset,segParams[i].orientation);
305
306 if (gazer!=NULL)
307 gazer->suspend();
308
309 return true;
310 }
311
312public:
313 /************************************************************************/
314 WriterModule() : action(NULL), gazer(NULL), interrupting(false) { }
315
316 /************************************************************************/
317 bool configure(ResourceFinder &rf)
318 {
319 string name=rf.find("name").asString().c_str();
320 setName(name.c_str());
321
322 string partUsed=rf.find("part").asString().c_str();
323 if ((partUsed!="left_arm") && (partUsed!="right_arm"))
324 {
325 yError()<<"invalid part requested!";
326 return false;
327 }
328
329 Property config; config.fromConfigFile(rf.findFile("from").c_str());
330 Bottle &bGeneral=config.findGroup("general");
331 if (bGeneral.isNull())
332 {
333 yError()<<"group \"general\" is missing!";
334 return false;
335 }
336
337 Property option(bGeneral.toString().c_str());
338 option.put("local",name.c_str());
339 option.put("part",partUsed.c_str());
340 option.put("grasp_model_type",rf.find("grasp_model_type").asString().c_str());
341 option.put("grasp_model_file",rf.findFile("grasp_model_file").c_str());
342 option.put("hand_sequences_file",rf.findFile("hand_sequences_file").c_str());
343
344 Bottle &bWriting=config.findGroup("writing_general");
345 if (bWriting.isNull())
346 {
347 yError()<<"group \"writing_general\" is missing!";
348 return false;
349 }
350
351 scale=bWriting.check("scale",Value(1.0)).asFloat64();
352 scale*=bWriting.check("conversion",Value(1.0)).asFloat64();
353 reach_above=bWriting.check("reach_above",Value(0.05)).asFloat64();
354 segment_time=bWriting.check("segment_time",Value(1.0)).asFloat64();
355 cartesian_time=bWriting.check("cartesian_time",Value(1.0)).asFloat64();
356 cartesian_straightness=bWriting.check("cartesian_straightness",Value(1.0)).asFloat64();
357
358 orientation.resize(4,0.0);
359 if (Bottle *pB=bWriting.find("orientation").asList())
360 {
361 int len=std::min(orientation.length(),pB->size());
362 for (int i=0; i<len; i++)
363 orientation[i]=pB->get(i).asFloat64();
364 }
365
366 Vector top_left_corner(3,0.0);
367 if (Bottle *pB=bWriting.find("top_left_corner").asList())
368 {
369 int len=std::min(top_left_corner.length(),pB->size());
370 for (int i=0; i<len; i++)
371 top_left_corner[i]=pB->get(i).asFloat64();
372 }
373 top_left_corner.push_back(1.0);
374
375 H.resize(4,4);
376 H(0,1)=1.0; H(1,0)=1.0; H(2,2)=-1.0;
377 H.setCol(3,top_left_corner);
378
379 TiXmlDocument drawing(rf.findFile("drawing").c_str());
380 if (!drawing.LoadFile())
381 {
382 close();
383 return false;
384 }
385
386 Vector data_top_left_corner=parseDrawing(drawing);
387 for (size_t i=0; i<wayPoints.size(); i++)
388 {
389 ostringstream segment_tag;
390 segment_tag<<"writing_segment_"<<i;
391 Bottle &bSegment=config.findGroup(segment_tag.str().c_str());
392 if (!bSegment.isNull())
393 {
394 if (Bottle *pB=bSegment.find("orientation").asList())
395 {
396 int len=std::min(orientation.length(),pB->size());
397 for (int j=0; j<len; j++)
398 segParams[i].orientation[j]=pB->get(j).asFloat64();
399 }
400
401 segParams[i].delta_z=bSegment.check("delta_z",Value(segParams[i].delta_z)).asFloat64();
402 segParams[i].reach_above=bSegment.check("reach_above",Value(segParams[i].reach_above)).asFloat64();
403 segParams[i].segment_time=bSegment.check("segment_time",Value(segParams[i].segment_time)).asFloat64();
404 segParams[i].cartesian_time=bSegment.check("cartesian_time",Value(segParams[i].cartesian_time)).asFloat64();
405 segParams[i].cartesian_straightness=bSegment.check("cartesian_straightness",Value(segParams[i].cartesian_straightness)).asFloat64();
406
407 for (size_t j=0; j<wayPoints[i].size(); j++)
408 {
409 wayPoints[i][j].o=segParams[i].orientation;
410 wayPoints[i][j].trajTime=segParams[i].cartesian_time;
411 wayPoints[i][j].duration=segParams[i].segment_time;
412 if (segParams[i].type!="line")
413 wayPoints[i][j].duration/=wayPoints[i].size();
414 }
415 }
416 }
417
418 tranformPoints(data_top_left_corner);
419 printPoints();
420
421 yInfo()<<"***** Instantiating primitives for "<<partUsed;
422 action=new ActionPrimitives(option);
423 if (!action->isValid())
424 {
425 close();
426 return false;
427 }
428
429 setStraightness(cartesian_straightness);
430
431 impedanceOn=false;
432 Bottle &bImpedance=config.findGroup("impedance");
433 if (!bImpedance.isNull())
434 {
435 impedanceOn=bImpedance.check("enable",Value("off")).asString()=="on";
436 if (impedanceOn)
437 {
438 Vector stiffness(5,0.0);
439 if (Bottle *pB=bImpedance.find("stiffness").asList())
440 {
441 int len=std::min(stiffness.length(),pB->size());
442 for (int i=0; i<len; i++)
443 stiffness[i]=pB->get(i).asFloat64();
444 }
445
446 Vector damping(stiffness.length(),0.0);
447 if (Bottle *pB=bImpedance.find("damping").asList())
448 {
449 int len=std::min(damping.length(),pB->size());
450 for (int i=0; i<len; i++)
451 damping[i]=pB->get(i).asFloat64();
452 }
453
454 string robot=bGeneral.check("robot",Value("icub")).asString().c_str();
455 Property driverOption("(device remote_controlboard)");
456 driverOption.put("remote",("/"+robot+"/"+partUsed).c_str());
457 driverOption.put("local",("/"+name+"/impedance").c_str());
458 if (driverArm.open(driverOption))
459 {
460 IInteractionMode *imod;
461 IImpedanceControl *iimp;
462
463 driverArm.view(imod);
464 driverArm.view(iimp);
465
466 size_t len=std::min(stiffness.length(),damping.length());
467 stiffness_old.resize(len); damping_old.resize(len);
468 for (size_t i=0; i<len; i++)
469 {
470 iimp->getImpedance(i,&stiffness_old[i],&damping_old[i]);
471 iimp->setImpedance(i,stiffness[i],damping[i]);
472 imod->setInteractionMode(i,VOCAB_IM_COMPLIANT);
473 }
474 }
475 else
476 {
477 close();
478 return false;
479 }
480 }
481 }
482
483 Bottle &bGaze=config.findGroup("gaze");
484 if (!bGaze.isNull())
485 {
486 if (bGaze.check("enable",Value("off")).asString()=="on")
487 {
488 Vector offset(3,0.0);
489 if (Bottle *pB=bGaze.find("offset").asList())
490 {
491 int len=std::min(offset.length(),pB->size());
492 for (int i=0; i<len; i++)
493 offset[i]=pB->get(i).asFloat64();
494 }
495
496 Property driverOption("(device gazecontrollerclient)");
497 driverOption.put("remote","/iKinGazeCtrl");
498 driverOption.put("local",("/"+name+"/gaze").c_str());
499 if (driverGaze.open(driverOption))
500 gazer=new Gazer(driverGaze,action,offset);
501 else
502 {
503 close();
504 return false;
505 }
506 }
507 }
508
509 rpcPort.open(("/"+name+"/rpc").c_str());
510 attach(rpcPort);
511
512 return true;
513 }
514
515 /************************************************************************/
516 bool respond(const Bottle &command, Bottle &reply)
517 {
518 int ack=Vocab32::encode("ack");
519 int nack=Vocab32::encode("nack");
520
521 if (command.size()>0)
522 {
523 switch (command.get(0).asVocab32())
524 {
525 //-----------------
526 case createVocab32('g','o'):
527 {
528 if (doWriting())
529 reply.addVocab32(ack);
530 else
531 reply.addVocab32(nack);
532
533 return true;
534 }
535
536 //-----------------
537 default:
538 return RFModule::respond(command,reply);
539 }
540 }
541
542 reply.addVocab32(nack);
543 return true;
544 }
545
546 /************************************************************************/
547 double getPeriod()
548 {
549 return 0.1;
550 }
551
552 /************************************************************************/
553 bool updateModule()
554 {
555 return true;
556 }
557
558 /************************************************************************/
559 bool interruptModule()
560 {
561 interrupting=true;
562 action->syncCheckInterrupt(true);
563
564 return true;
565 }
566
567 /************************************************************************/
568 bool close()
569 {
570 if (action!=NULL)
571 delete action;
572
573 if (driverArm.isValid())
574 {
575 if (impedanceOn)
576 {
577 IInteractionMode *imod;
578 IImpedanceControl *iimp;
579
580 driverArm.view(imod);
581 driverArm.view(iimp);
582
583 for (size_t i=0; i<stiffness_old.length(); i++)
584 {
585 imod->setInteractionMode(i,VOCAB_IM_STIFF);
586 iimp->setImpedance(i,stiffness_old[i],damping_old[i]);
587 }
588 }
589
590 driverArm.close();
591 }
592
593 if (driverGaze.isValid())
594 {
595 gazer->stop();
596 delete gazer;
597 driverGaze.close();
598 }
599
600 rpcPort.close();
601 return true;
602 }
603};
604
605
606/************************************************************************/
607int main(int argc, char *argv[])
608{
609 Network yarp;
610 if (!yarp.checkNetwork())
611 {
612 yError()<<"YARP server not available!";
613 return 1;
614 }
615
616 ResourceFinder rf;
617 rf.setDefaultContext("funny-things");
618 rf.setDefaultConfigFile("iCubWriter.ini");
619 rf.setDefault("part","right_arm");
620 rf.setDefault("grasp_model_type","springy");
621 rf.setDefault("grasp_model_file","grasp_model.ini");
622 rf.setDefault("hand_sequences_file","hand_sequences.ini");
623 rf.setDefault("drawing","drawings/icub.svg");
624 rf.setDefault("name","iCubWriter");
625 rf.configure(argc,argv);
626
627 WriterModule mod;
628 return mod.runModule(rf);
629}
630
631