YARP
Yet Another Robot Platform
RgbdSensor_nws_ros.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 
6 #include "RgbdSensor_nws_ros.h"
7 #include "rosPixelCode.h"
8 
9 #include <yarp/os/LogComponent.h>
10 #include <yarp/os/LogStream.h>
11 #include <yarp/dev/GenericVocabs.h>
13 
14 #include <RGBDRosConversionUtils.h>
15 #include <cstdio>
16 #include <cstring>
17 #include <sstream>
18 
19 using namespace RGBDImpl;
20 using namespace yarp::sig;
21 using namespace yarp::dev;
22 using namespace yarp::os;
23 
24 YARP_LOG_COMPONENT(RGBDSENSORNWSROS, "yarp.devices.RgbdSensor_nws_ros")
25 
26 
29  m_node(nullptr),
30  nodeSeq(0),
31  period(DEFAULT_THREAD_PERIOD),
32  sensor_p(nullptr),
33  fgCtrl(nullptr),
34  sensorStatus(IRGBDSensor::RGBD_SENSOR_NOT_READY),
35  verbose(4),
36  forceInfoSync(true),
37  isSubdeviceOwned(false),
38  subDeviceOwned(nullptr)
39 {}
40 
42 {
43  close();
44  sensor_p = nullptr;
45  fgCtrl = nullptr;
46 }
47 
51 {
52  if(verbose >= 5)
53  {
54  yCTrace(RGBDSENSORNWSROS) << "\nParameters are: \n" << config.toString();
55  }
56  if (!config.check("period", "refresh period of the broadcasted values in s"))
57  {
58  if (verbose >= 3) {
59  yCInfo(RGBDSENSORNWSROS) << "Using default 'period' parameter of " << DEFAULT_THREAD_PERIOD << "s";
60  }
61  }
62  else
63  {
64  period = config.find("period").asFloat64();
65  }
66 
67  //check if param exist and assign it to corresponding variable.. if it doesn't, initialize the variable with default value.
68 
69  if (config.check("forceInfoSync"))
70  {
71  forceInfoSync = config.find("forceInfoSync").asBool();
72  }
73 
74  if(config.check("subdevice")) {
75  isSubdeviceOwned=true;
76  } else {
77  isSubdeviceOwned=false;
78  }
79 
80  setId("RGBDSensorWrapper for " + nodeName);
81 
82  if(!initialize_ROS(config))
83  {
84  return false;
85  }
86 
87  // check if we need to create subdevice or if they are
88  // passed later on through attachAll()
89  if(isSubdeviceOwned)
90  {
91  if(! openAndAttachSubDevice(config))
92  {
93  yCError(RGBDSENSORNWSROS, "Error while opening subdevice");
94  return false;
95  }
96  }
97  else
98  {
99  if (!openDeferredAttach(config)) {
100  return false;
101  }
102  }
103 
104  return true;
105 }
106 
107 bool RgbdSensor_nws_ros::openDeferredAttach(Searchable& prop)
108 {
109  // I dunno what to do here now...
110  isSubdeviceOwned = false;
111  return true;
112 }
113 
114 bool RgbdSensor_nws_ros::openAndAttachSubDevice(Searchable& prop)
115 {
116  Property p;
117  subDeviceOwned = new PolyDriver;
118  p.fromString(prop.toString());
119 
120  p.setMonitor(prop.getMonitor(), "subdevice"); // pass on any monitoring
121  p.unput("device");
122  p.put("device",prop.find("subdevice").asString()); // subdevice was already checked before
123 
124  // if errors occurred during open, quit here.
125  yCDebug(RGBDSENSORNWSROS, "Opening IRGBDSensor subdevice");
126  subDeviceOwned->open(p);
127 
128  if (!subDeviceOwned->isValid())
129  {
130  yCError(RGBDSENSORNWSROS, "Opening IRGBDSensor subdevice... FAILED");
131  return false;
132  }
133  isSubdeviceOwned = true;
134  if(!attach(subDeviceOwned)) {
135  return false;
136  }
137 
138  return true;
139 }
140 
142 {
143  yCTrace(RGBDSENSORNWSROS, "Close");
144  detach();
145 
146  // close subdevice if it was created inside the open (--subdevice option)
147  if(isSubdeviceOwned)
148  {
149  if(subDeviceOwned)
150  {
151  delete subDeviceOwned;
152  subDeviceOwned=nullptr;
153  }
154  sensor_p = nullptr;
155  fgCtrl = nullptr;
156  isSubdeviceOwned = false;
157  }
158 
159  if(m_node !=nullptr)
160  {
161  m_node->interrupt();
162  delete m_node;
163  m_node = nullptr;
164  }
165 
166  return true;
167 }
168 
169 /* Helper functions */
170 
171 bool RgbdSensor_nws_ros::initialize_ROS(yarp::os::Searchable &params)
172 {
173  // depth topic base name check
174  if (!params.check("depth_topic_name")) {
175  yCError(RGBDSENSORNWSROS) << "missing depth_topic_name parameter";
176  return false;
177  }
178  std::string depth_topic_name = params.find("depth_topic_name").asString();
179  if(depth_topic_name[0] != '/'){
180  yCError(RGBDSENSORNWSROS) << "depth_topic_name must begin with an initial /";
181  return false;
182  }
183 
184  // color topic base name check
185  if (!params.check("color_topic_name")) {
186  yCError(RGBDSENSORNWSROS) << "missing color_topic_name parameter";
187  return false;
188  }
189  std::string color_topic_name = params.find("color_topic_name").asString();
190  if(color_topic_name[0] != '/'){
191  yCError(RGBDSENSORNWSROS) << "color_topic_name must begin with an initial /";
192  return false;
193  }
194 
195  // node_name check
196  if (!params.check("node_name")) {
197  yCError(RGBDSENSORNWSROS) << "missing node_name parameter";
198  return false;
199  }
200  std::string node_name = params.find("node_name").asString();
201  if(node_name[0] != '/'){
202  yCError(RGBDSENSORNWSROS) << "node_name must begin with an initial /";
203  return false;
204  }
205 
206  // depth_frame_id check
207  if (!params.check("depth_frame_id")) {
208  yCError(RGBDSENSORNWSROS) << "missing depth_frame_id parameter";
209  return false;
210  }
211  m_depth_frame_id = params.find("depth_frame_id").asString();
212 
213  // m_color_frame_id check
214  if (!params.check("color_frame_id")) {
215  yCError(RGBDSENSORNWSROS) << "missing color_frame_id parameter";
216  return false;
217  }
218  m_color_frame_id = params.find("color_frame_id").asString();
219 
220  // open topics here if needed
221  m_node = new yarp::os::Node(nodeName);
222  nodeSeq = 0;
223 
224  if (!publisherPort_color.topic(color_topic_name))
225  {
226  yCError(RGBDSENSORNWSROS) << "Unable to publish data on " << color_topic_name.c_str() << " topic, check your yarp-ROS network configuration";
227  return false;
228  }
229 
230  if (!publisherPort_depth.topic(depth_topic_name))
231  {
232  yCError(RGBDSENSORNWSROS) << "Unable to publish data on " << depth_topic_name.c_str() << " topic, check your yarp-ROS network configuration";
233  return false;
234  }
235  std::string rgb_info_topic_name = color_topic_name.substr(0,color_topic_name.rfind('/')) + "/camera_info";
236  if (!publisherPort_colorCaminfo.topic(rgb_info_topic_name))
237  {
238  yCError(RGBDSENSORNWSROS) << "Unable to publish data on " << rgb_info_topic_name.c_str() << " topic, check your yarp-ROS network configuration";
239  return false;
240  }
241 
242  std::string depth_info_topic_name = depth_topic_name.substr(0,depth_topic_name.rfind('/')) + "/camera_info";
243  if (!publisherPort_depthCaminfo.topic(depth_info_topic_name))
244  {
245  yCError(RGBDSENSORNWSROS) << "Unable to publish data on " << depth_info_topic_name.c_str() << " topic, check your yarp-ROS network configuration";
246  return false;
247  }
248  return true;
249 }
250 
251 void RgbdSensor_nws_ros::setId(const std::string &id)
252 {
253  sensorId=id;
254 }
255 
257 {
258  return sensorId;
259 }
260 
266 {
269  }
270 
271  //check if we already instantiated a subdevice previously
272  if (isSubdeviceOwned) {
273  return false;
274  }
275 
276  sensor_p = nullptr;
277  return true;
278 }
279 
281 {
282  if(poly)
283  {
284  poly->view(sensor_p);
285  poly->view(fgCtrl);
286  }
287 
288  if(sensor_p == nullptr)
289  {
290  yCError(RGBDSENSORNWSROS) << "Attached device has no valid IRGBDSensor interface.";
291  return false;
292  }
293 
294  if(fgCtrl == nullptr)
295  {
296  yCWarning(RGBDSENSORNWSROS) << "Attached device has no valid IFrameGrabberControls interface.";
297  }
298 
299  PeriodicThread::setPeriod(period);
300  return PeriodicThread::start();
301 }
302 
303 /* IRateThread interface */
304 
306 {
307  // Get interface from attached device if any.
308  return true;
309 }
310 
312 {
313  // Detach() calls stop() which in turns calls this functions, therefore no calls to detach here!
314 }
315 
316 bool RgbdSensor_nws_ros::setCamInfo(yarp::rosmsg::sensor_msgs::CameraInfo& cameraInfo, const std::string& frame_id, const UInt& seq, const SensorType& sensorType)
317 {
318  double phyF = 0.0;
319  double fx = 0.0;
320  double fy = 0.0;
321  double cx = 0.0;
322  double cy = 0.0;
323  double k1 = 0.0;
324  double k2 = 0.0;
325  double t1 = 0.0;
326  double t2 = 0.0;
327  double k3 = 0.0;
328  double stamp = 0.0;
329 
330  std::string distModel;
331  std::string currentSensor;
332  UInt i;
333  Property camData;
334  std::vector<param<double> > parVector;
335  param<double>* par;
336  bool ok;
337 
338  currentSensor = sensorType == COLOR_SENSOR ? "Rgb" : "Depth";
339  ok = sensorType == COLOR_SENSOR ? sensor_p->getRgbIntrinsicParam(camData) : sensor_p->getDepthIntrinsicParam(camData);
340 
341  if (!ok)
342  {
343  yCError(RGBDSENSORNWSROS) << "Unable to get intrinsic param from" << currentSensor << "sensor!";
344  return false;
345  }
346 
347  if(!camData.check("distortionModel"))
348  {
349  yCWarning(RGBDSENSORNWSROS) << "Missing distortion model";
350  return false;
351  }
352 
353  distModel = camData.find("distortionModel").asString();
354  if (distModel != "plumb_bob")
355  {
356  yCError(RGBDSENSORNWSROS) << "Distortion model not supported";
357  return false;
358  }
359 
360  //std::vector<param<std::string> > rosStringParam;
361  //rosStringParam.push_back(param<std::string>(nodeName, "asd"));
362 
363  parVector.emplace_back(phyF,"physFocalLength");
364  parVector.emplace_back(fx,"focalLengthX");
365  parVector.emplace_back(fy,"focalLengthY");
366  parVector.emplace_back(cx,"principalPointX");
367  parVector.emplace_back(cy,"principalPointY");
368  parVector.emplace_back(k1,"k1");
369  parVector.emplace_back(k2,"k2");
370  parVector.emplace_back(t1,"t1");
371  parVector.emplace_back(t2,"t2");
372  parVector.emplace_back(k3,"k3");
373  parVector.emplace_back(stamp,"stamp");
374  for(i = 0; i < parVector.size(); i++)
375  {
376  par = &parVector[i];
377 
378  if(!camData.check(par->parname))
379  {
380  yCWarning(RGBDSENSORNWSROS) << "Driver has not the param:" << par->parname;
381  return false;
382  }
383  *par->var = camData.find(par->parname).asFloat64();
384  }
385 
386  cameraInfo.header.frame_id = frame_id;
387  cameraInfo.header.seq = seq;
388  cameraInfo.header.stamp = stamp;
389  cameraInfo.width = sensorType == COLOR_SENSOR ? sensor_p->getRgbWidth() : sensor_p->getDepthWidth();
390  cameraInfo.height = sensorType == COLOR_SENSOR ? sensor_p->getRgbHeight() : sensor_p->getDepthHeight();
391  cameraInfo.distortion_model = distModel;
392 
393  cameraInfo.D.resize(5);
394  cameraInfo.D[0] = k1;
395  cameraInfo.D[1] = k2;
396  cameraInfo.D[2] = t1;
397  cameraInfo.D[3] = t2;
398  cameraInfo.D[4] = k3;
399 
400  cameraInfo.K.resize(9);
401  cameraInfo.K[0] = fx; cameraInfo.K[1] = 0; cameraInfo.K[2] = cx;
402  cameraInfo.K[3] = 0; cameraInfo.K[4] = fy; cameraInfo.K[5] = cy;
403  cameraInfo.K[6] = 0; cameraInfo.K[7] = 0; cameraInfo.K[8] = 1;
404 
405  /*
406  * ROS documentation on cameraInfo message:
407  * "Rectification matrix (stereo cameras only)
408  * A rotation matrix aligning the camera coordinate system to the ideal
409  * stereo image plane so that epipolar lines in both stereo images are
410  * parallel."
411  * useless in our case, it will be an identity matrix
412  */
413 
414  cameraInfo.R.assign(9, 0);
415  cameraInfo.R.at(0) = cameraInfo.R.at(4) = cameraInfo.R.at(8) = 1;
416 
417  cameraInfo.P.resize(12);
418  cameraInfo.P[0] = fx; cameraInfo.P[1] = 0; cameraInfo.P[2] = cx; cameraInfo.P[3] = 0;
419  cameraInfo.P[4] = 0; cameraInfo.P[5] = fy; cameraInfo.P[6] = cy; cameraInfo.P[7] = 0;
420  cameraInfo.P[8] = 0; cameraInfo.P[9] = 0; cameraInfo.P[10] = 1; cameraInfo.P[11] = 0;
421 
422  cameraInfo.binning_x = cameraInfo.binning_y = 0;
423  cameraInfo.roi.height = cameraInfo.roi.width = cameraInfo.roi.x_offset = cameraInfo.roi.y_offset = 0;
424  cameraInfo.roi.do_rectify = false;
425  return true;
426 }
427 
428 bool RgbdSensor_nws_ros::writeData()
429 {
430  //colorImage.setPixelCode(VOCAB_PIXEL_RGB);
431  // depthImage.setPixelCode(VOCAB_PIXEL_MONO_FLOAT);
432 
433  // colorImage.resize(hDim, vDim); // Has this to be done each time? If size is the same what it does?
434  // depthImage.resize(hDim, vDim);
435  if (!sensor_p->getImages(colorImage, depthImage, &colorStamp, &depthStamp))
436  {
437  return false;
438  }
439 
440  static Stamp oldColorStamp = Stamp(0, 0);
441  static Stamp oldDepthStamp = Stamp(0, 0);
442  bool rgb_data_ok = true;
443  bool depth_data_ok = true;
444 
445  if (((colorStamp.getTime() - oldColorStamp.getTime()) > 0) == false)
446  {
447  rgb_data_ok=false;
448  //return true;
449  }
450  else { oldColorStamp = colorStamp; }
451 
452  if (((depthStamp.getTime() - oldDepthStamp.getTime()) > 0) == false)
453  {
454  depth_data_ok=false;
455  //return true;
456  }
457  else { oldDepthStamp = depthStamp; }
458 
459  // TBD: We should check here somehow if the timestamp was correctly updated and, if not, update it ourselves.
460  if (rgb_data_ok)
461  {
462  yarp::rosmsg::sensor_msgs::Image& rColorImage = publisherPort_color.prepare();
463  yarp::rosmsg::sensor_msgs::CameraInfo& camInfoC = publisherPort_colorCaminfo.prepare();
464  yarp::rosmsg::TickTime cRosStamp = colorStamp.getTime();
465  yarp::dev::RGBDRosConversionUtils::deepCopyImages(colorImage, rColorImage, m_color_frame_id, cRosStamp, nodeSeq);
466  publisherPort_color.setEnvelope(colorStamp);
467  publisherPort_color.write();
468  if (setCamInfo(camInfoC, m_color_frame_id, nodeSeq, COLOR_SENSOR))
469  {
470  if(forceInfoSync)
471  {camInfoC.header.stamp = rColorImage.header.stamp;}
472  publisherPort_colorCaminfo.setEnvelope(colorStamp);
473  publisherPort_colorCaminfo.write();
474  }
475  else
476  {
477  yCWarning(RGBDSENSORNWSROS, "Missing color camera parameters... camera info messages will be not sent");
478  }
479  }
480  if (depth_data_ok)
481  {
482  yarp::rosmsg::sensor_msgs::Image& rDepthImage = publisherPort_depth.prepare();
483  yarp::rosmsg::sensor_msgs::CameraInfo& camInfoD = publisherPort_depthCaminfo.prepare();
484  yarp::rosmsg::TickTime dRosStamp = depthStamp.getTime();
485  yarp::dev::RGBDRosConversionUtils::deepCopyImages(depthImage, rDepthImage, m_depth_frame_id, dRosStamp, nodeSeq);
486  publisherPort_depth.setEnvelope(depthStamp);
487  publisherPort_depth.write();
488  if (setCamInfo(camInfoD, m_depth_frame_id, nodeSeq, DEPTH_SENSOR))
489  {
490  if(forceInfoSync)
491  {camInfoD.header.stamp = rDepthImage.header.stamp;}
492  publisherPort_depthCaminfo.setEnvelope(depthStamp);
493  publisherPort_depthCaminfo.write();
494  }
495  else
496  {
497  yCWarning(RGBDSENSORNWSROS, "Missing depth camera parameters... camera info messages will be not sent");
498  }
499  }
500 
501  nodeSeq++;
502 
503  return true;
504 }
505 
507 {
508  if (sensor_p!=nullptr)
509  {
510  static int i = 0;
511  sensorStatus = sensor_p->getSensorStatus();
512  switch (sensorStatus)
513  {
514  case(IRGBDSensor::RGBD_SENSOR_OK_IN_USE) :
515  {
516  if (!writeData()) {
517  yCError(RGBDSENSORNWSROS, "Image not captured.. check hardware configuration");
518  }
519  i = 0;
520  }
521  break;
522  case(IRGBDSensor::RGBD_SENSOR_NOT_READY):
523  {
524  if(i < 1000) {
525  if((i % 30) == 0) {
526  yCInfo(RGBDSENSORNWSROS) << "Device not ready, waiting...";
527  }
528  } else {
529  yCWarning(RGBDSENSORNWSROS) << "Device is taking too long to start..";
530  }
531  i++;
532  }
533  break;
534  default:
535  {
536  if (verbose >= 1) { // better not to print it every cycle anyway, too noisy
537  yCError(RGBDSENSORNWSROS, "%s: Sensor returned error", sensorId.c_str());
538  }
539  }
540  }
541  }
542  else
543  {
544  if(verbose >= 6) {
545  yCError(RGBDSENSORNWSROS, "%s: Sensor interface is not valid", sensorId.c_str());
546  }
547  }
548 }
constexpr double DEFAULT_THREAD_PERIOD
const yarp::os::LogComponent & RGBDSENSORNWSROS()
rgbdSensor_nws_ros: A Network grabber for kinect-like devices. This device will produce two streams o...
bool close() override
Close the DeviceDriver.
void setId(const std::string &id)
void threadRelease() override
Release method.
bool attach(yarp::dev::PolyDriver *poly) override
Specify which sensor this thread has to read from.
bool open(yarp::os::Searchable &params) override
Device driver interface.
bool threadInit() override
Initialization method.
void run() override
Loop function.
bool detach() override
WrapperSingle interface.
bool view(T *&x)
Get an interface to the device driver.
Definition: DeviceDriver.h:74
A generic interface for cameras that have both color camera as well as depth camera sensor,...
Definition: IRGBDSensor.h:40
A container for a device driver.
Definition: PolyDriver.h:24
The Node class.
Definition: Node.h:24
An abstraction for a periodic thread.
bool isRunning() const
Returns true when the thread is started, false otherwise.
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
A class for storing options and configuration information.
Definition: Property.h:34
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Property.cpp:1051
void fromString(const std::string &txt, bool wipe=true)
Interprets a string as a list of properties.
Definition: Property.cpp:1063
void put(const std::string &key, const std::string &value)
Associate the given key with the given string.
Definition: Property.cpp:1015
bool check(const std::string &key) const override
Check if there exists a property of the given name.
Definition: Property.cpp:1041
void unput(const std::string &key)
Remove the association from the given key to a value, if present.
Definition: Property.cpp:1046
A base class for nested structures that can be searched.
Definition: Searchable.h:66
virtual Value & find(const std::string &key) const =0
Gets a value corresponding to a given keyword.
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.
An abstraction for a time stamp and/or sequence number.
Definition: Stamp.h:22
double getTime() const
Get the time stamp.
Definition: Stamp.cpp:34
virtual yarp::conf::float64_t asFloat64() const
Get 64-bit floating point value.
Definition: Value.cpp:222
virtual bool asBool() const
Get boolean value.
Definition: Value.cpp:186
virtual std::string asString() const
Get string value.
Definition: Value.cpp:234
bool write(yarp::os::ConnectionWriter &connection) const override
Write this object to a network connection.
Definition: TickTime.h:148
std::vector< yarp::conf::float64_t > R
Definition: CameraInfo.h:167
std::vector< yarp::conf::float64_t > K
Definition: CameraInfo.h:166
yarp::rosmsg::sensor_msgs::RegionOfInterest roi
Definition: CameraInfo.h:171
std::vector< yarp::conf::float64_t > P
Definition: CameraInfo.h:168
yarp::rosmsg::std_msgs::Header header
Definition: CameraInfo.h:161
std::vector< yarp::conf::float64_t > D
Definition: CameraInfo.h:165
yarp::rosmsg::std_msgs::Header header
Definition: Image.h:56
yarp::rosmsg::TickTime stamp
Definition: Header.h:45
#define yCInfo(component,...)
Definition: LogComponent.h:132
#define yCError(component,...)
Definition: LogComponent.h:154
#define yCTrace(component,...)
Definition: LogComponent.h:85
#define yCWarning(component,...)
Definition: LogComponent.h:143
#define yCDebug(component,...)
Definition: LogComponent.h:109
#define YARP_LOG_COMPONENT(name,...)
Definition: LogComponent.h:77
void deepCopyImages(const yarp::sig::FlexImage &src, yarp::rosmsg::sensor_msgs::Image &dest, const std::string &frame_id, const yarp::rosmsg::TickTime &timeStamp, const unsigned int &seq)
An interface for the device drivers.
An interface to the operating system, including Port based communication.
Signal processing.
Definition: Image.h:22