yarp-devices
exampleOfflineTrajectoryAsync.cpp

A constant-velocity, single-joint trajectory is generated with configurable final target, motion speed and period between consecutive points. The yarp::dev::IRemoteVariables interface is used to configure and switch to interpolated position (pi) mode on the real robot. Although prepared for remote execution, this application could be rewritten to connect to a local instance of CanBusBroker. The techniques showcased here are best aimed at trajectories fully available offline (e.g. loaded from file) that don't assume a constant period between points.

Usage (showing default option values):

 exampleOfflineTrajectoryAsync --remote /teo/leftArm --joint 5 --speed 2.0 --target -20.0 --period 50 --ip pt
See also
exampleOfflineTrajectorySync.cpp Assumes the period between points is fixed, thus allowing batched execution.
exampleOfflineTrajectoryAsync.py
Tutorial: Trajectory Execution (external)
Note
This application is not suitable for simulation.
1 // -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*-
2 
32 #include <cmath>
33 
34 #include <iostream>
35 
36 #include <yarp/os/LogStream.h>
37 #include <yarp/os/Network.h>
38 #include <yarp/os/Property.h>
39 #include <yarp/os/ResourceFinder.h>
40 #include <yarp/os/SystemClock.h>
41 #include <yarp/os/Timer.h>
42 
43 #include <yarp/dev/IControlMode.h>
44 #include <yarp/dev/IEncoders.h>
45 #include <yarp/dev/IPositionDirect.h>
46 #include <yarp/dev/IRemoteVariables.h>
47 #include <yarp/dev/PolyDriver.h>
48 
49 constexpr auto DEFAULT_REMOTE = "/teo/leftArm";
50 constexpr auto DEFAULT_JOINT = 5;
51 constexpr auto DEFAULT_SPEED = 2.0; // deg/s
52 constexpr auto DEFAULT_TARGET = (-20.0);
53 constexpr auto DEFAULT_PERIOD_MS = 50;
54 constexpr auto DEFAULT_IP_MODE = "pt";
55 
56 int main(int argc, char * argv[])
57 {
58  yarp::os::ResourceFinder rf;
59  rf.configure(argc, argv);
60 
61  auto remote = rf.check("remote", yarp::os::Value(DEFAULT_REMOTE), "remote port").asString();
62  auto joint = rf.check("joint", yarp::os::Value(DEFAULT_JOINT), "joint id").asInt32();
63  auto speed = rf.check("speed", yarp::os::Value(DEFAULT_SPEED), "trajectory speed (deg/s)").asFloat64();
64  auto target = rf.check("target", yarp::os::Value(DEFAULT_TARGET), "target position (deg)").asFloat64();
65  auto period = rf.check("period", yarp::os::Value(DEFAULT_PERIOD_MS), "command period (ms)").asInt32() * 0.001;
66  auto ipMode = rf.check("ip", yarp::os::Value(DEFAULT_IP_MODE), "interpolation submode [pt|pvt]").asString();
67 
68  if (speed <= 0)
69  {
70  yError() << "Illegal speed (deg/s):" << speed;
71  return 1;
72  }
73 
74  if (period <= 0)
75  {
76  yError() << "Illegal period (s):" << period;
77  return 1;
78  }
79 
80  if (ipMode != "pt" && ipMode != "pvt")
81  {
82  yError() << "Illegal ipMode:" << ipMode;
83  return 1;
84  }
85 
86  yarp::os::Network yarp;
87 
88  if (!yarp::os::Network::checkNetwork())
89  {
90  yError() << "Please start a yarp name server first";
91  return 1;
92  }
93 
94  yarp::os::Property options {{"device", yarp::os::Value("remote_controlboard")},
95  {"local", yarp::os::Value("/exampleOfflineTrajectoryAsync")},
96  {"remote", yarp::os::Value(remote)}};
97 
98  yarp::dev::PolyDriver dd(options);
99 
100  if (!dd.isValid())
101  {
102  yError() << "Remote device not available";
103  return 1;
104  }
105 
106  yarp::dev::IControlMode * mode;
107  yarp::dev::IEncoders * enc;
108  yarp::dev::IPositionDirect * posd;
109  yarp::dev::IRemoteVariables * var;
110 
111  if (!dd.view(mode) || !dd.view(enc) || !dd.view(posd) || !dd.view(var))
112  {
113  yError() << "Unable to acquire robot interfaces";
114  return 1;
115  }
116 
117  yarp::os::Bottle b;
118  yarp::os::Bottle & bb = b.addList(); // additional nesting because of controlboardremapper
119 
120  bb.addList() = {yarp::os::Value("ipMode"), yarp::os::Value(ipMode)};
121  bb.addList() = {yarp::os::Value("enableIp"), yarp::os::Value(true)}; // important: place this last
122 
123  if (!var->setRemoteVariable("all", b))
124  {
125  yError() << "Unable to set interpolation mode";
126  return 1;
127  }
128 
129  if (!mode->setControlMode(joint, VOCAB_CM_POSITION_DIRECT))
130  {
131  yError() << "Unable to set position direct mode";
132  return 1;
133  }
134 
135  double initialPos;
136  int retries = 0;
137 
138  while (!enc->getEncoder(joint, &initialPos) && retries++ < 10)
139  {
140  yarp::os::SystemClock::delaySystem(0.05);
141  }
142 
143  if (retries >= 10)
144  {
145  yError() << "getEncoders() failed";
146  return 1;
147  }
148 
149  yInfo() << "Current ENC value:" << initialPos;
150 
151  std::cin.get();
152 
153  yInfo() << "Moving joint" << joint << "to" << target << "degrees...";
154 
155  const double distance = target - initialPos;
156  const double increment = std::copysign(speed * period, distance);
157 
158  yarp::os::Timer::TimerCallback callback = [=](const auto & event)
159  {
160  auto newDistance = event.runCount * increment;
161  auto position = initialPos + newDistance;
162  yInfo("[%d] New target: %f", event.runCount, position);
163  posd->setPosition(joint, position);
164  return std::abs(distance) > std::abs(newDistance);
165  };
166 
167  yarp::os::TimerSettings settings(period); // alternative ctor supports stop conditions
168  yarp::os::Timer timer(settings, callback, true);
169 
170  if (!timer.start())
171  {
172  yError() << "Unable to start trajectory thread";
173  return 1;
174  }
175 
176  while (timer.isRunning())
177  {
178  yarp::os::SystemClock::delaySystem(0.1);
179  }
180 
181  return 0;
182 }