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