YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
VirtualAnalogWrapper.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7// #include <iostream>
9#include <yarp/os/LogStream.h>
10
11using namespace yarp::os;
12using namespace yarp::dev;
13
14
15namespace {
16YARP_LOG_COMPONENT(VIRTUALANALOGSERVER, "yarp.device.virtualAnalogServer")
17constexpr int MAX_ENTRIES = 255;
18}
19
20
22{
23 detach();
24}
25
30
31bool AnalogSubDevice::configure(int map0, int map1, const std::string &key)
32{
33 mIsConfigured=false;
34
35 if (map1<map0)
36 {
37 yCError(VIRTUALANALOGSERVER) << "Check configuration file top<base.";
38 return false;
39 }
40
41 mMap0=map0;
42 mMap1=map1;
43
44 mKey=key;
45
47
48 mIsConfigured=true;
49
50 return true;
51}
52
53bool AnalogSubDevice::attach(yarp::dev::PolyDriver *device, const std::string &key)
54{
55 if (key!=mKey)
56 {
57 yCError(VIRTUALANALOGSERVER) << "Wrong device" << key.c_str();
58 return false;
59 }
60
61 //configure first
62 if (!mIsConfigured)
63 {
64 yCError(VIRTUALANALOGSERVER) << "'configure' should be called before you can attach any device";
65 return false;
66 }
67
68 if (!device)
69 {
70 yCError(VIRTUALANALOGSERVER) << "Invalid device (null pointer)";
71 return false;
72 }
73
74 mpDevice=device;
75
76 if (mpDevice->isValid())
77 {
79 }
80 else
81 {
82 yCError(VIRTUALANALOGSERVER) << "Invalid device " << key << " (isValid() returned false)";
83 return false;
84 }
85
86 if (mpSensor)
87 {
88 mIsAttached=true;
89 return true;
90 }
91
92 return false;
93}
94
96{
97 mMap0=mMap1=-1;
98
99 mpDevice=nullptr;
100 mpSensor=nullptr;
101
102 mIsConfigured=false;
103 mIsAttached=false;
104}
105
107{
108 yCDebug(VIRTUALANALOGSERVER) << config.toString().c_str();
109
110 mIsVerbose = (config.check("verbose","if present, give detailed output"));
111
112 if (mIsVerbose) {
113 yCDebug(VIRTUALANALOGSERVER) << "Running with verbose output\n";
114 }
115
116 //thus thread period is useful for output port... this input port has callback so maybe can skip it (?)
117 //thread_period = prop.check("threadrate", 20, "thread rate in ms. for streaming encoder data").asInt32();
118
119 yCDebug(VIRTUALANALOGSERVER) << "Using VirtualAnalogServer\n";
120
121 if (!config.check("networks", "list of networks merged by this wrapper"))
122 {
123 yCError(VIRTUALANALOGSERVER) << "Missing networks parameters";
124 return false;
125 }
126
127 Bottle *networks=config.find("networks").asList();
128 mNSubdevs=networks->size();
129 mSubdevices.resize(mNSubdevs);
130
131 mChan2Board.resize(MAX_ENTRIES);
132 mChan2BAddr.resize(MAX_ENTRIES);
133 for (int i = 0; i < MAX_ENTRIES; i++)
134 {
135 mChan2Board[i]=-1;
136 mChan2BAddr[i]=-1;
137 }
138
139 int totalJ=0;
140
141 for (size_t k=0; k<networks->size(); ++k)
142 {
143 auto parameters = config.findGroup(networks->get(k).asString());
144 int map0, map1, map2, map3;
145
146 if (parameters.size() == 2)
147 {
148 auto* bot = parameters.get(1).asList();
150 if (bot == nullptr)
151 {
152 // try to read data as a string in the last resort
153 tmpBot.fromString(parameters.get(1).asString());
154 if (tmpBot.size() != 4)
155 {
156 yCError(VIRTUALANALOGSERVER) << "Error: check network parameters in part description"
157 << "--> I was expecting" << networks->get(k).asString() << "followed by four integers between parentheses"
158 << "Got: " << parameters.toString();
159 return false;
160 }
161
162 bot = &tmpBot;
163 }
164
165 map0 = bot->get(0).asInt32();
166 map1 = bot->get(1).asInt32();
167 map2 = bot->get(2).asInt32();
168 map3 = bot->get(3).asInt32();
169 }
170 else if (parameters.size() == 5)
171 {
172 yCError(VIRTUALANALOGSERVER) << "Parameter networks use deprecated syntax";
173 map0 = parameters.get(1).asInt32();
174 map1 = parameters.get(2).asInt32();
175 map2 = parameters.get(3).asInt32();
176 map3 = parameters.get(4).asInt32();
177 }
178 else
179 {
180 yCError(VIRTUALANALOGSERVER) << "Error: check network parameters in part description"
181 << "--> I was expecting" << networks->get(k).asString() << "followed by four integers between parentheses"
182 << "Got: " << parameters.toString();
183 return false;
184 }
185
187 map0 <0 || map1 <0 || map2<0 || map3<0)
188 {
189 yCError(VIRTUALANALOGSERVER) << "Invalid map entries in networks section, failed initial check";
190 return false;
191 }
192
193 for (int j=map0; j<=map1; ++j)
194 {
195 mChan2Board[j]=k;
197 }
198
199 if (!mSubdevices[k].configure(map2,map3,networks->get(k).asString()))
200 {
201 yCError(VIRTUALANALOGSERVER) << "Configure of subdevice ret false";
202 return false;
203 }
204
205 totalJ+=map1-map0+1;
206 }
207
208 // Verify minimum set of parameters required
209 if(!config.check("robotName") ) // ?? qui dentro, da dove lo pesco ??
210 {
211 yCError(VIRTUALANALOGSERVER) << "Missing robotName, check your configuration file!";
212 return false;
213 }
214
215 if (config.check("deviceId"))
216 {
217 yCError(VIRTUALANALOGSERVER) << "The parameter 'deviceId' has been deprecated, please use parameter 'name' instead. \n"
218 << "e.g. In the VFT wrapper configuration files of your robot, replace '<param name=""deviceId""> left_arm </param>' \n"
219 << "with '/icub/joint_vsens/left_arm:i' ";
220 return false;
221 }
222
223 std::string port_name = config.check("name",Value("controlboard"),"Virtual analog wrapper port name, e.g. /icub/joint_vsens/left_arm:i").asString();
224 std::string robot_name = config.find("robotName").asString();
225
226 if (!mPortInputTorques.open(port_name))
227 {
228 yCError(VIRTUALANALOGSERVER) << "Can't open port " << port_name.c_str();
229 return false;
230 }
231
232 return true;
233}
234
236{
239 Thread::stop();
240 return true;
241}
242
244{
245 mMutex.lock();
246
247 for (int p=0; p<polylist.size(); ++p)
248 {
249 std::string key=polylist[p]->key;
250
251 // find appropriate entry in list of subdevices and attach
252 for (auto& mSubdevice : mSubdevices)
253 {
254 if (mSubdevice.getKey() == key)
255 {
256 if (!mSubdevice.attach(polylist[p]->poly,key))
257 {
258 mMutex.unlock();
259 return false;
260 }
261 }
262 }
263 }
264
265 //check if all devices are attached to the driver
266 for (auto& mSubdevice : mSubdevices)
267 {
268 if (!mSubdevice.isAttached())
269 {
270 mMutex.unlock();
271 return false;
272 }
273 }
274
275 mMutex.unlock();
276
278
279 return true;
280}
281
283{
284 mMutex.lock();
285
286 for(int k=0; k<mNSubdevs; ++k)
287 {
288 mSubdevices[k].detach();
289 }
290
291 mMutex.unlock();
292
293// close();
294
295 return true;
296}
297
299{
300 if (first_check) {
301 return true;
302 }
303
304 for (int i=0; i<elems; i++)
305 {
306 if (mChan2Board[i]==-1 || mChan2BAddr[i]==-1)
307 {
308 yCError(VIRTUALANALOGSERVER) << "Invalid map entries in networks section, failed runtime check"
309 << " i: " << i << "mChan2Board[i] is " << mChan2Board[i] << " chan2add is " << mChan2BAddr[i];
310 return false;
311 }
312 }
313
314 yCTrace(VIRTUALANALOGSERVER) << "perform_first_check() successfully completed";
315 first_check = true;
316 return true;
317}
318
320{
322 bool sendLastValueBeforeTimeout = false;
323 while (!Thread::isStopping())
324 {
326 double timeNow=Time::now();
327
328 if (pTorques)
329 {
331 mMutex.lock();
332
334 switch (pTorques->get(0).asInt32())
335 {
336 case 1: //arm torque message
337 if (perform_first_check(6) == false) {
338 break;
339 }
340 mSubdevices[mChan2Board[0]].setTorque(mChan2BAddr[0],pTorques->get(1).asFloat64()); //shoulder 1 pitch (0)
341 mSubdevices[mChan2Board[1]].setTorque(mChan2BAddr[1],pTorques->get(2).asFloat64()); //shoulder 2 roll (1)
342 mSubdevices[mChan2Board[2]].setTorque(mChan2BAddr[2],pTorques->get(3).asFloat64()); //shoulder 3 yaw (2)
343 mSubdevices[mChan2Board[3]].setTorque(mChan2BAddr[3],pTorques->get(4).asFloat64()); //elbow (3)
344 mSubdevices[mChan2Board[4]].setTorque(mChan2BAddr[4],pTorques->get(5).asFloat64()); //wrist pronosupination (4)
345 mSubdevices[mChan2Board[5]].setTorque(mChan2BAddr[5],0.0);
346 break;
347
348 case 2: //legs torque message
349 if (perform_first_check(6) == false) {
350 break;
351 }
352 mSubdevices[mChan2Board[0]].setTorque(mChan2BAddr[0],pTorques->get(1).asFloat64()); //hip pitch
353 mSubdevices[mChan2Board[1]].setTorque(mChan2BAddr[1],pTorques->get(2).asFloat64()); //hip roll
354 mSubdevices[mChan2Board[2]].setTorque(mChan2BAddr[2],pTorques->get(3).asFloat64()); //hip yaw
355 mSubdevices[mChan2Board[3]].setTorque(mChan2BAddr[3],pTorques->get(4).asFloat64()); //knee
356 mSubdevices[mChan2Board[4]].setTorque(mChan2BAddr[4],pTorques->get(5).asFloat64()); //ankle pitch
357 mSubdevices[mChan2Board[5]].setTorque(mChan2BAddr[5],pTorques->get(6).asFloat64()); //ankle roll
358 break;
359
360 case 3: //wrist torque message
361 if (perform_first_check(6) == false) {
362 break;
363 }
364 mSubdevices[mChan2Board[0]].setTorque(mChan2BAddr[0],pTorques->get(6).asFloat64()); //wrist yaw (6)
365 mSubdevices[mChan2Board[1]].setTorque(mChan2BAddr[1],pTorques->get(7).asFloat64()); //wrist pitch (7)
366 mSubdevices[mChan2Board[2]].setTorque(mChan2BAddr[2],0.0);
367 mSubdevices[mChan2Board[3]].setTorque(mChan2BAddr[3],0.0);
368 mSubdevices[mChan2Board[4]].setTorque(mChan2BAddr[4],0.0);
369 mSubdevices[mChan2Board[5]].setTorque(mChan2BAddr[5],0.0);
370 break;
371
372 case 4: // torso
373 if (perform_first_check(3) == false) {
374 break;
375 }
376 mSubdevices[mChan2Board[0]].setTorque(mChan2BAddr[0],pTorques->get(1).asFloat64()); //torso yaw (respect gravity)
377 mSubdevices[mChan2Board[1]].setTorque(mChan2BAddr[1],pTorques->get(2).asFloat64()); //torso roll (lateral movement)
378 mSubdevices[mChan2Board[2]].setTorque(mChan2BAddr[2],pTorques->get(3).asFloat64()); //torso pitch (front-back movement)
379// mSubdevices[mChan2Board[3]].setTorque(mChan2BAddr[3],0.0);
380// mSubdevices[mChan2Board[4]].setTorque(mChan2BAddr[4],0.0);
381// mSubdevices[mChan2Board[5]].setTorque(mChan2BAddr[5],0.0);
382 break;
383
384 default:
385 yCError(VIRTUALANALOGSERVER) << "Got unexpected " << pTorques->get(0).asInt32() << " message on virtualAnalogServer.";
386 }
387
388 for (int d=0; d<mNSubdevs; ++d)
389 {
390 mSubdevices[d].flushTorques();
391 }
392
393 mMutex.unlock();
394 }
395 else
396 {
397 // sending rate from wholeBody is 10ms, if nothing is got now, wait that much time
399 }
400
401 if(first_check)
402 {
403 if ((lastRecv+0.080 < timeNow) && (!sendLastValueBeforeTimeout))
404 {
405 /* If 80ms have passed since the last received message, reset values to zero (just once).
406 * Sending time will be 1ms due to the delay above (else case).
407 */
408 for (int d=0; d<mNSubdevs; ++d)
409 {
410 mSubdevices[d].resetTorque();
411 mSubdevices[d].flushTorques();
412
413 }
414 yCError(VIRTUALANALOGSERVER) << "Timeout!! No new value received for more than " << timeNow - lastRecv << " secs.";
416 }
417 }
418 }
419}
yarp::sig::Vector mTorques
yarp::dev::IVirtualAnalogSensor * mpSensor
yarp::dev::PolyDriver * mpDevice
bool configure(int map0, int map1, const std::string &key)
bool attach(yarp::dev::PolyDriver *driver, const std::string &key)
std::vector< AnalogSubDevice > mSubdevices
std::vector< int > mChan2Board
bool close() override
Close the DeviceDriver.
std::vector< int > mChan2BAddr
bool attachAll(const yarp::dev::PolyDriverList &p) override
Attach to a list of objects.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
bool detachAll() override
Detach the object (you must have first called attach).
void run() override
Main body of the new thread.
yarp::os::BufferedPort< yarp::os::Bottle > mPortInputTorques
bool perform_first_check(int elems)
bool view(T *&x)
Get an interface to the device driver.
A container for a device driver.
Definition PolyDriver.h:23
bool isValid() const
Check if device is valid.
A simple collection of objects that can be described and transmitted in a portable way.
Definition Bottle.h:64
A mini-server for performing network communication in the background.
void close() override
Stop port activity.
bool open(const std::string &name) override
Start port operation, with a specific name, with automatically-chosen network parameters.
void interrupt() override
Interrupt any current reads or writes attached to the port.
T * read(bool shouldWait=true) override
Read an available object from the port.
A base class for nested structures that can be searched.
Definition Searchable.h:31
virtual bool check(const std::string &key) const =0
Check if there exists a property of the given name.
virtual std::string toString() const =0
Return a standard text representation of the content of the object.
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
virtual Bottle & findGroup(const std::string &key) const =0
Gets a list corresponding to a given keyword.
bool stop()
Stop the thread.
Definition Thread.cpp:81
bool isStopping()
Returns true if the thread is stopping (Thread::stop has been called).
Definition Thread.cpp:99
bool start()
Start the new thread running.
Definition Thread.cpp:93
A single value (typically within a Bottle).
Definition Value.h:43
void resize(size_t size) override
Resize the vector.
Definition Vector.h:221
#define yCError(component,...)
#define yCTrace(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
For streams capable of holding different kinds of content, check what they actually have.
Definition jointData.cpp:13
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
void delay(double seconds)
Wait for a certain number of seconds.
Definition Time.cpp:111
An interface to the operating system, including Port based communication.