iCub-main
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2010 RobotCub Consortium
3 * Author: Lorenzo Natale
4 * CopyPolicy: Released under the terms of the GNU GPL v2.0.
5 *
6 */
7
93#include <yarp/os/Network.h>
94#include <yarp/os/RFModule.h>
95#include <yarp/os/Time.h>
96#include <yarp/os/BufferedPort.h>
97#include <yarp/sig/Vector.h>
98#include <yarp/math/Math.h>
99
100#include <yarp/dev/ControlBoardInterfaces.h>
101#include <yarp/dev/PolyDriver.h>
102#include <yarp/os/PeriodicThread.h>
103#include <yarp/os/Thread.h>
104#include <yarp/os/LogStream.h>
105
107
108#include <mutex>
109#include <condition_variable>
110#include <fstream>
111#include <iostream>
112#include <iomanip>
113#include <string>
114#include <deque>
115#include <vector>
116
117using namespace std;
118using namespace yarp::os;
119using namespace yarp::sig;
120using namespace yarp::dev;
121using namespace yarp::math;
122using namespace iCub::ctrl;
123
124#define VCTP_TIME yarp::os::createVocab32('t','i','m','e')
125#define VCTP_OFFSET yarp::os::createVocab32('o','f','f')
126#define VCTP_CMD_NOW yarp::os::createVocab32('c','t','p','n')
127#define VCTP_CMD_QUEUE yarp::os::createVocab32('c','t','p','q')
128#define VCTP_CMD_FILE yarp::os::createVocab32('c','t','p','f')
129#define VCTP_POSITION yarp::os::createVocab32('p','o','s')
130#define VCTP_WAIT yarp::os::createVocab32('w','a','i','t')
131
132#define VEL_FILT_SIZE 10
133#define VEL_FILT_THRES 1.0
134
135// Class for position control
137{
138private:
139 int off;
140 Vector cmd;
141 double time;
142public:
143 const int &getOffset() const { return off; }
144 int &getOffset() { return off; }
145
146 const double &getTime() const { return time; }
147 double &getTime() {return time; }
148
149 const Vector &getCmd() const { return cmd; }
150
151 Vector &getCmd() { return cmd; }
152};
153
154typedef deque<ActionItem *> ActionList;
155
157{
158 ActionList actions;
159
160public:
163
164 int size()
165 {
166 return actions.size();
167 }
168
169 void clear()
170 {
171 for(unsigned int k=0; k<actions.size();k++)
172 {
173 ActionItem *ret=actions.at(k);
174 delete ret;
175 }
176 actions.clear();
177 }
178
180 {
181 if (actions.empty())
182 return 0;
183
184 ActionItem *ret=actions.at(0);
185 actions.pop_front();
186 return ret;
187 }
188
190 {
191 actions.push_back(v);
192 }
193};
194
196{
197public:
199protected:
202 Property drvOptions;
203 PolyDriver *drv;
204 IControlMode *mode;
205 IPositionControl *pos;
206 IEncoders *enc;
208 mutex mtx;
209
210 void _send(const ActionItem *x)
211 {
212 if (!connected)
213 {
214 cerr<<"Error: not connected to control board skipping"<<endl;
215 return;
216 }
217
218 int size=x->getCmd().size();
219 int offset=x->getOffset();
220 double time=x->getTime();
221 int nJoints=0;
222
223 enc->getAxes(&nJoints);
224 if ((offset+size)>nJoints)
225 {
226 cerr<<"Error: detected possible overflow, skipping"<<endl;
227 cerr<<"For debug --> joints: "<<nJoints<< " off: "<<offset<<" cmd length: "<<size<<endl;
228 return;
229 }
230
231 Vector disp(size);
232
233 if (time==0)
234 {
235 return;
236 }
237
238 for (size_t i=0; i<disp.length(); i++)
239 {
240 double q;
241
242
243 if (!enc->getEncoder(offset+i,&q))
244 {
245 cerr<<"Error: encoders timed out, cannot rely on encoder feedback, aborted"<<endl;
246 return;
247 }
248
249 disp[i]=x->getCmd()[i]-q;
250
251 if (disp[i]<0.0)
252 disp[i]=-disp[i];
253 }
254
255 // don't blend together the two "for"
256 // since we have to enforce the modes on the whole
257 // prior to commanding the joints
258 std::vector<int> joints;
259 std::vector<int> modes;
260 std::vector<double> speeds;
261 std::vector<double> positions;
262
263 for (size_t i=0; i<disp.length(); i++)
264 {
265 joints.push_back(offset+i);
266 speeds.push_back(disp[i]/time);
267 modes.push_back(VOCAB_CM_POSITION);
268 positions.push_back(x->getCmd()[i]);
269 }
270
272 {
273 mode->setControlModes(disp.length(), joints.data(), modes.data());
274 }
275
276 yarp::os::Time::delay(0.01); // give time to update control modes value
277 mode->getControlModes(disp.length(), joints.data(), modes.data());
278 for (size_t i=0; i<disp.length(); i++)
279 {
280 if(modes[i] != VOCAB_CM_POSITION)
281 {
282 yError() << "Joint " << i << " not in position mode";
283 }
284 }
285 pos->setRefSpeeds(disp.length(), joints.data(), speeds.data());
286 pos->positionMove(disp.length(), joints.data(), positions.data());
287
288 cout << "Script port: " << x->getCmd().toString() << endl;
289 }
290
291public:
293 {
294 drvOptions.clear();
295 drv=0;
296 verbose=1;
297 connected=false;
298 }
299
300 void send(ActionItem *tmp)
301 {
302 lock_guard<mutex> lck(mtx);
303 _send(tmp);
304 }
305
306 bool configure(const Property &options)
307 {
308 bool ret=true;
309 if (options.check("device"))
310 drvOptions.put("device", options.find("device").asString());
311 else
312 drvOptions.put("device","remote_controlboard");
313
314 string name=string(options.find("name").asString());
315
316 string remote=string("/")+string(options.find("robot").asString());
317 remote+=string("/")+string(options.find("part").asString());
318
319 string local=name;
320 local+=string("/local/")+string(options.find("part").asString());
321
322 drvOptions.put("remote",remote);
323 drvOptions.put("local",local);
324
325 if (verbose)
326 {
327 cout << "Driver options:\n" << drvOptions.toString();
328 }
329
330 return ret;
331 }
332
333 void queue(ActionItem *item)
334 {
335 lock_guard<mutex> lck(mtx);
336 actions.push_back(item);
337 }
338
339 void sendNow(ActionItem *item)
340 {
341 lock_guard<mutex> lck(mtx);
342 actions.clear();
343 _send(item);
344 }
345
347 {
348 lock_guard<mutex> lck(mtx);
349 ActionItem *ret=actions.pop();
350 return ret;
351 }
352
353 bool connect()
354 {
355 drv=new PolyDriver(drvOptions);
356
357 if (drv->isValid())
358 connected=drv->view(mode) &&
359 drv->view(pos) &&
360 drv->view(enc);
361 else
362 connected=false;
363
364 if (!connected)
365 {
366 delete drv;
367 drv=0;
368 }
369
370 return connected;
371 }
372
374 {
375 if (drv)
376 delete drv;
377 }
378};
379
380class WorkingThread: public PeriodicThread
381{
382private:
383 scriptPosPort *posPort;
384public:
385 WorkingThread(int period=100): PeriodicThread((double)period/1000.0)
386 {}
387
389 {
390 if (p)
391 posPort=p;
392 }
393
395 {
396 if (!posPort)
397 return false;
398 return true;
399 }
400
401 void run()
402 {
403 ActionItem *tmp=posPort->pop();
404 if (tmp)
405 {
406 posPort->send(tmp);
407 double time=tmp->getTime();
408 delete tmp;
409 Time::delay(time);
410 }
411 }
412};
413
414class VelocityThread: public Thread
415{
416private:
417 mutex mtx;
418 condition_variable cv;
419
420 AWLinEstimator linEst;
421 Port *velPort;
422 Port *velInitPort;
423 ResourceFinder *pRF;
424
425 ifstream fin;
426 char line[1024];
427 bool closing;
428 bool firstRun;
429 bool velInit;
430
431 unsigned int filtElemsCnt;
432
433 bool checkInitConnection(Port *p)
434 {
435
436 if(p->getOutputCount() > 0)
437 {
438 cout << "***** got a connection" << endl;
439 return true;
440 }
441 else
442 {
443 return false;
444 }
445 }
446
447 bool initVelCtrl(Port *p, ResourceFinder *rf)
448 {
449 int i = 0;
450 bool cont = true;
451 char numberId[64];
452 bool ret = true;
453
454 while(cont)
455 {
456 string gainStr = "gain";
457 sprintf(numberId, "%d", i);
458 gainStr = gainStr + numberId;
459
460 Bottle c,r;
461 c.addString("gain");
462 c.addInt32(i);
463 if (rf->check(gainStr))
464 {
465 c.addFloat64(rf->find(gainStr).asFloat64());
466 p->write(c,r);
467 i++;
468 }
469 else
470 cont = false;
471 }
472 if (i==0)
473 {
474 ret = false;
475 cout << " velCtrl: missing 'gain' parameters" << endl;
476 }
477
478 i = 0;
479 cont = true;
480 while(cont)
481 {
482 string svelStr = "svel";
483 sprintf(numberId, "%d", i);
484 svelStr = svelStr + numberId;
485
486 Bottle c,r;
487 c.addString("svel");
488 c.addInt32(i);
489 if (rf->check(svelStr))
490 {
491 c.addFloat64(rf->find(svelStr).asFloat64());
492 p->write(c,r);
493 i++;
494 }
495 else
496 cont = false;
497 }
498 if (i==0)
499 {
500 ret = false;
501 cout << " velCtrl: missing 'svel' parameters" << endl;
502 }
503
504 return ret;
505 }
506
507 bool readLine(Vector &v, double &time)
508 {
509 fin.getline(&line[0],sizeof(line),'\n');
510 string str(line);
511
512 if (str.length()!=0)
513 {
514 Bottle b;
515 b.fromString(str);
516
517 if (b.size()>2)
518 {
519 time=b.get(1).asFloat64();
520 v.resize(b.size()-2);
521
522 for (size_t i=0; i<v.length(); i++)
523 v[i]=b.get(i+2).asFloat64();
524
525 return true;
526 }
527 else
528 return false;
529 }
530 else
531 return false;
532 }
533
534 Vector formCommand(const Vector &p, const double t)
535 {
536 Vector res;
537
538 for (size_t i=0; i<p.length(); i++)
539 {
540 res.push_back(i);
541 res.push_back(p[i]);
542 }
543
544 AWPolyElement el;
545 el.data=p;
546 el.time=t;
547
548 Vector v=linEst.estimate(el);
549
550 if (++filtElemsCnt>VEL_FILT_SIZE)
551 {
552 for (size_t i=0; i<p.length(); i++)
553 {
554 res.push_back(1000.0+i);
555 res.push_back(v[i]);
556 }
557 }
558
559 return res;
560 }
561
562public:
564 {
565 velInit=false;
566 velPort=NULL;
567 velInitPort=NULL;
568 closing=false;
569 firstRun=true;
570 }
571
572 void attachRF(ResourceFinder *attachedRF)
573 {
574 pRF = attachedRF;
575 }
576
577 void attachVelPort(Port *p)
578 {
579 if (p)
580 velPort=p;
581 }
582
584 {
585 if (p)
586 velInitPort=p;
587 }
588
589 bool go(const string &fileName)
590 {
591 if (velPort==NULL)
592 return false;
593
594 if (fin.is_open())
595 fin.close();
596
597 fin.open(fileName.c_str());
598 if (fin.is_open())
599 {
600 fin.seekg(0,ios_base::beg);
601 // skip the first two lines
602 fin.getline(&line[0],sizeof(line),'\n');
603 fin.getline(&line[0],sizeof(line),'\n');
604 firstRun=true;
605 cout<<"File loaded"<<endl;
606 cv.notify_one();
607 return true;
608 }
609 else
610 {
611 cout<<"Unable to load file: "<<fileName<<endl;
612 return false;
613 }
614 }
615
616 void onStop()
617 {
618 closing=true;
619 cv.notify_one();
620 }
621
623 {
624 if (fin.is_open())
625 fin.close();
626 }
627
628 void run()
629 {
630 Vector p1,p2;
631 double time1,time2,t;
632 bool send=false;
633
634 while (!isStopping())
635 {
636 if (!velInit)
637 {
638 if (checkInitConnection(velInitPort))
639 {
640 bool b = initVelCtrl(velInitPort, pRF);
641 if (b)
642 {
643 cout << "velocity control initialized. gain, svel parameters loaded" << endl;
644 }
645 else
646 {
647 cout << "*** velocity control missing init parameters! (gain, svel)" << endl;
648 }
649 velInit = true;
650 }
651 else
652 Time::delay(1.0);
653 }
654 else
655 {
656 if (!closing)
657 {
658 unique_lock<mutex> lck(mtx);
659 cv.wait(lck);
660 }
661
662 if (firstRun)
663 {
664 Bottle c,r;
665 c.addString("run");
666 velInitPort->write(c,r);
667 send=readLine(p1,time1);
668 linEst.reset();
669 t=0.0;
670 filtElemsCnt=0;
671 firstRun=false;
672 }
673
674 if (send)
675 {
676 Vector cmd=formCommand(p1,t);
677 velPort->write(cmd);
678 send=false;
679 }
680
681 if (readLine(p2,time2))
682 {
683 double dt=time2-time1;
684 Time::delay(dt);
685 t+=dt;
686 p1=p2;
687 time1=time2;
688 send=true;
689 cv.notify_one();
690 }
691 else
692 {
693 fin.close();
694 Bottle c,r;
695 c.addString("susp");
696 velInitPort->write(c,r);
697 }
698 }
699 }
700 }
701};
702
703class scriptModule: public RFModule
704{
705protected:
706 ResourceFinder *rf;
708 string name;
715
716public:
718 {
719 verbose=true;
720 }
721
722 bool handlectpm(const Bottle &cmd, Bottle &reply)
723 {
724 ActionItem *action;
725 bool ret=parsePosCmd(cmd, reply, &action);
726 if (ret)
727 {
728 posPort.sendNow(action);
729 reply.addVocab32("ack");
730 }
731
732 return ret;
733 }
734
735 bool handle_ctp_queue(const Bottle &cmd, Bottle &reply)
736 {
737 ActionItem *action;
738 bool ret=parsePosCmd(cmd, reply, &action);
739 if (ret)
740 {
741 posPort.queue(action);
742 reply.addVocab32("ack");
743 }
744 return ret;
745 }
746
747 bool handle_ctp_file(const Bottle &cmd, Bottle &reply)
748 {
749 if (cmd.size()<2)
750 return false;
751
752 string fileName=rf->findFile(cmd.get(1).asString());
753 bool ret = velThread.go(fileName);
754 if (ret)
755 {
756 reply.addVocab32("ack");
757 }
758 else
759 {
760 reply.addVocab32("nack");
761 reply.addString("Unable to load file");
762 }
763 return ret;
764 }
765
766 bool handle_wait(const Bottle &cmd, Bottle &reply)
767 {
768 cerr<<"Warning command not implemented yet"<<endl;
769 reply.addVocab32("ack");
770 return true;
771 //ActionItem *action;
772 //bool ret=parseWaitCmd(cmd, reply, &action);
773 //if (ret)
774 // posPort.queue(action);
775 }
776
777 bool parsePosCmd(const Bottle &cmd, Bottle &reply, ActionItem **action)
778 {
779 const int expectedMsgSize=7;
780 bool parsed=false;
781 if (cmd.size()!=expectedMsgSize)
782 {
783 return false;
784 }
785
786 if (cmd.get(1).asVocab32()==VCTP_TIME)
787 {
788 double time=cmd.get(2).asFloat64();
789 int offset=0;
790 Bottle *posCmd=0;
791 if (cmd.get(3).asVocab32()==VCTP_OFFSET)
792 {
793 offset=cmd.get(4).asInt32();
794 if (cmd.get(5).asVocab32()==VCTP_POSITION)
795 {
796 posCmd=cmd.get(6).asList();
797 if (!posCmd)
798 return false;
799
800 //check posCmd!=0
801 parsed=true;
802 if (verbose)
803 {
804 cout<<"Received command:"<<endl;
805 cout<<"Time: " << time << "offset: " << offset <<" Cmd: " << posCmd->toString()<<endl;
806 }
807 *action=new ActionItem;
808 (*action)->getCmd().resize(posCmd->size());
809 for(int k=0;k<posCmd->size();k++)
810 (*action)->getCmd()[k]=posCmd->get(k).asFloat64();
811
812 (*action)->getOffset()=offset;
813 (*action)->getTime()=time;
814 return true;
815 }
816 }
817 }
818 return false;
819 }
820
821 virtual bool configure(ResourceFinder &rf)
822 {
823 this->rf=&rf;
824
825 if (rf.check("name"))
826 name=string("/")+rf.find("name").asString();
827 else
828 name="/ctpservice";
829
830 rpcPort.open(name+string("/")+rf.find("part").asString()+"/rpc");
831 attach(rpcPort);
832
833 Property portProp;
834 portProp.put("name", name);
835 portProp.put("robot", rf.find("robot"));
836 portProp.put("part", rf.find("part"));
837
838 if (!posPort.configure(portProp))
839 {
840 cerr<<"Error configuring position controller, check parameters"<<endl;
841 return false;
842 }
843
844 if (!posPort.connect())
845 {
846 cerr<<"Error cannot connect to remote ports"<<endl;
847 return false;
848 }
849
850 cout << "***** connect to rpc port and type \"help\" for commands list" << endl;
851
853 if (!thread.start())
854 {
855 cerr<<"Thread did not start, queue will not work"<<endl;
856 }
857
858 if (rf.check("autochange_control_mode_enable"))
859 {
860 //This value should be false by default.
861 //Otherwise it can be dangerous to activate idle joints (or in hw fault).
862 //The robot could eventually break something!
864 }
865 velPort.open(name+string("/")+rf.find("part").asString()+"/vc:o");
866 velInitPort.open(name+string("/")+rf.find("part").asString()+"/vcInit:o");
869 cout << "Using parameters:" << endl << rf.toString() << endl;
871 cout << "***** starting the thread" << endl;
872 velThread.start();
873
874 return true;
875 }
876
877 virtual bool respond(const Bottle &command, Bottle &reply)
878 {
879 bool ret;
880 if (command.size()!=0)
881 {
882 switch (command.get(0).asVocab32())
883 {
884 case yarp::os::createVocab32('h','e','l','p'):
885 {
886 cout << "Available commands:" << endl;
887 cout<<"Queue command:\n";
888 cout<<"[ctpq] [time] seconds [off] j [pos] (list)\n";
889 cout<<"New command, execute now (erase queue):\n";
890 cout<<"[ctpn] [time] seconds [off] j [pos] (list)\n";
891 cout<<"Load sequence from file:\n";
892 cout<<"[ctpf] filename\n";
893 reply.addVocab32("ack");
894 return true;
895 }
896 case VCTP_CMD_NOW:
897 {
898 ret=handlectpm(command, reply);
899 return ret;
900 }
901 case VCTP_CMD_QUEUE:
902 {
903 ret=handle_ctp_queue(command, reply);
904 return ret;
905 }
906 case VCTP_CMD_FILE:
907 {
908 ret=handle_ctp_file(command, reply);
909 return ret;
910 }
911 case VCTP_WAIT:
912 {
913 ret=handle_wait(command, reply);
914 }
915 default:
916 return RFModule::respond(command,reply);
917 }
918 }
919 else
920 {
921 reply.addVocab32("nack");
922 return false;
923 }
924 }
925
926 virtual bool close()
927 {
928 rpcPort.interrupt();
929 rpcPort.close();
930 thread.stop();
931
932 velThread.stop();
933 velPort.interrupt();
934 velPort.close();
935
936 velInitPort.interrupt();
937 velInitPort.close();
938
939 return true;
940 }
941
942 virtual double getPeriod() { return 1.0; }
943 virtual bool updateModule() { return true; }
944};
945
946
947int main(int argc, char *argv[])
948{
949 ResourceFinder rf;
950 rf.setDefaultContext("ctpService");
951 rf.configure(argc,argv);
952
953 if (rf.check("help"))
954 {
955 cout << "Options:" << endl << endl;
956 cout << "\t--name moduleName: set new module name" << endl;
957 cout << "\t--robot robotname: robot name" << endl;
958 cout << "\t--part partname: robot part name" << endl;
959 cout << "\t--from fileName: input configuration file" << endl;
960 cout << "\t--context dirName: resource finder context" << endl;
961 cout << "\t--autochange_control_mode_enable: sets the joints to position mode when trying to execute the command (default off)" << endl;
962
963 return 0;
964 }
965
966 Network yarp;
967 if (!yarp.checkNetwork())
968 return 1;
969
970 scriptModule mod;
971 return mod.runModule(rf);
972}
973
974
975
Vector & getCmd()
Definition main.cpp:151
const double & getTime() const
Definition main.cpp:146
double & getTime()
Definition main.cpp:147
const Vector & getCmd() const
Definition main.cpp:149
const int & getOffset() const
Definition main.cpp:143
int & getOffset()
Definition main.cpp:144
~Actions()
Definition main.cpp:162
ActionItem * pop()
Definition main.cpp:179
void clear()
Definition main.cpp:169
void push_back(ActionItem *v)
Definition main.cpp:189
Actions()
Definition main.cpp:161
int size()
Definition main.cpp:164
bool go(const string &fileName)
Definition main.cpp:589
void attachVelPort(Port *p)
Definition main.cpp:577
void onStop()
Definition main.cpp:616
void attachVelInitPort(Port *p)
Definition main.cpp:583
void run()
Definition main.cpp:628
void attachRF(ResourceFinder *attachedRF)
Definition main.cpp:572
void threadRelease()
Definition main.cpp:622
void attachPosPort(scriptPosPort *p)
Definition main.cpp:388
bool threadInit()
Definition main.cpp:394
WorkingThread(int period=100)
Definition main.cpp:385
void run()
Definition main.cpp:401
Adaptive window linear fitting to estimate the first derivative.
Basic element for adaptive polynomial fitting.
yarp::sig::Vector estimate()
Execute the algorithm upon the elements list, with the max deviation threshold given by D.
void reset()
Reinitialize the internal state.
scriptPosPort posPort
Definition main.cpp:710
Port velPort
Definition main.cpp:711
bool parsePosCmd(const Bottle &cmd, Bottle &reply, ActionItem **action)
Definition main.cpp:777
virtual bool updateModule()
Definition main.cpp:943
WorkingThread thread
Definition main.cpp:713
Port rpcPort
Definition main.cpp:707
bool handlectpm(const Bottle &cmd, Bottle &reply)
Definition main.cpp:722
Port velInitPort
Definition main.cpp:712
string name
Definition main.cpp:708
virtual double getPeriod()
Definition main.cpp:942
bool handle_ctp_file(const Bottle &cmd, Bottle &reply)
Definition main.cpp:747
bool handle_wait(const Bottle &cmd, Bottle &reply)
Definition main.cpp:766
virtual bool close()
Definition main.cpp:926
VelocityThread velThread
Definition main.cpp:714
virtual bool respond(const Bottle &command, Bottle &reply)
Definition main.cpp:877
ResourceFinder * rf
Definition main.cpp:706
virtual bool configure(ResourceFinder &rf)
Definition main.cpp:821
bool handle_ctp_queue(const Bottle &cmd, Bottle &reply)
Definition main.cpp:735
bool verbose
Definition main.cpp:709
void _send(const ActionItem *x)
Definition main.cpp:210
bool verbose
Definition main.cpp:200
PolyDriver * drv
Definition main.cpp:203
bool autochange_control_mode_enable
Definition main.cpp:198
IControlMode * mode
Definition main.cpp:204
void queue(ActionItem *item)
Definition main.cpp:333
void send(ActionItem *tmp)
Definition main.cpp:300
mutex mtx
Definition main.cpp:208
ActionItem * pop()
Definition main.cpp:346
Property drvOptions
Definition main.cpp:202
Actions actions
Definition main.cpp:207
IEncoders * enc
Definition main.cpp:206
bool connect()
Definition main.cpp:353
bool configure(const Property &options)
Definition main.cpp:306
void sendNow(ActionItem *item)
Definition main.cpp:339
bool connected
Definition main.cpp:201
IPositionControl * pos
Definition main.cpp:205
cmd
Definition dataTypes.h:30
#define VCTP_CMD_QUEUE
Definition main.cpp:127
#define VCTP_CMD_NOW
Definition main.cpp:126
#define VCTP_WAIT
Definition main.cpp:130
#define VEL_FILT_THRES
Definition main.cpp:133
#define VCTP_OFFSET
Definition main.cpp:125
#define VCTP_TIME
Definition main.cpp:124
deque< ActionItem * > ActionList
Definition main.cpp:154
#define VCTP_POSITION
Definition main.cpp:129
#define VEL_FILT_SIZE
Definition main.cpp:132
#define VCTP_CMD_FILE
Definition main.cpp:128
int main()
Definition main.cpp:67
Copyright (C) 2008 RobotCub Consortium.
degrees offset
Definition sine.m:4
degrees time
Definition sine.m:5