YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
RgbdSensor_nws_ros2.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2023 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
7
9#include <yarp/os/LogStream.h>
10
11#include <string>
12#include <vector>
13#include <iostream>
14#include <Ros2Utils.h>
15
16#include <sensor_msgs/image_encodings.hpp>
17
18using namespace std::chrono_literals;
19
20namespace
21{
22YARP_LOG_COMPONENT(RGBDSENSOR_NWS_ROS2, "yarp.ros2.rgbdSensor_nws_ros2", yarp::os::Log::TraceType);
23
24constexpr double DEFAULT_THREAD_PERIOD = 0.03; // s
25
26// FIXME should be possible to set different frame_id for rgb and depth
27const std::string frameId_param = "frame_Id";
28const std::string nodeName_param = "nodeName";
29const std::string colorTopicName_param = "colorTopicName";
30const std::string depthTopicName_param = "depthTopicName";
31const std::string depthInfoTopicName_param = "depthInfoTopicName";
32const std::string colorInfoTopicName_param = "colorInfoTopicName";
33
34
35
36std::string yarp2RosPixelCode(int code)
37{
38 switch (code)
39 {
40 case VOCAB_PIXEL_BGR:
41 return sensor_msgs::image_encodings::BGR8;
43 return sensor_msgs::image_encodings::BGRA8;
45 return sensor_msgs::image_encodings::BAYER_BGGR16;
47 return sensor_msgs::image_encodings::BAYER_BGGR8;
49 return sensor_msgs::image_encodings::BAYER_GBRG16;
51 return sensor_msgs::image_encodings::BAYER_GBRG8;
53 return sensor_msgs::image_encodings::BAYER_GRBG16;
55 return sensor_msgs::image_encodings::BAYER_GRBG8;
57 return sensor_msgs::image_encodings::BAYER_RGGB16;
59 return sensor_msgs::image_encodings::BAYER_RGGB8;
61 return sensor_msgs::image_encodings::MONO8;
63 return sensor_msgs::image_encodings::MONO16;
64 case VOCAB_PIXEL_RGB:
65 return sensor_msgs::image_encodings::RGB8;
67 return sensor_msgs::image_encodings::RGBA8;
69 return sensor_msgs::image_encodings::TYPE_32FC1;
70 default:
71 return sensor_msgs::image_encodings::RGB8;
72 }
73}
74
75} // namespace
76
77
82
83
84// DeviceDriver
86{
87 yCDebug(RGBDSENSOR_NWS_ROS2) << "Parameters are: " << config.toString();
88
89 if(!fromConfig(config)) {
90 yCError(RGBDSENSOR_NWS_ROS2) << "Failed to open, check previous log for error messages.";
91 return false;
92 }
93
94 if(!initialize_ROS2(config)) {
95 yCError(RGBDSENSOR_NWS_ROS2) << "Error initializing ROS topic";
96 return false;
97 }
98
99 return true;
100}
101
102
103
104bool RgbdSensor_nws_ros2::fromConfig(yarp::os::Searchable &config)
105{
106 parseParams(config);
107 if(m_node_name[0] == '/'){
108 yCError(RGBDSENSOR_NWS_ROS2) << "node_name cannot begin with an initial /";
109 return false;
110 }
111
112 if(m_depth_topic_name[0] != '/'){
113 yCError(RGBDSENSOR_NWS_ROS2) << "depth_topic_name must begin with an initial /";
114 return false;
115 }
116 m_depth_info_topic_name = m_depth_topic_name.substr(0, m_depth_topic_name.rfind('/')) + "/camera_info";
117
118 if(m_color_topic_name[0] != '/'){
119 yCError(RGBDSENSOR_NWS_ROS2) << "color_topic_name must begin with an initial /";
120 return false;
121 }
122 m_color_info_topic_name = m_color_topic_name.substr(0, m_color_topic_name.rfind('/')) + "/camera_info";
123
124 m_forceInfoSync = m_force_info_synch == 1;
125
126 return true;
127}
128
129
130bool RgbdSensor_nws_ros2::initialize_ROS2(yarp::os::Searchable &params)
131{
133 rosPublisher_color = m_node->create_publisher<sensor_msgs::msg::Image>(m_color_topic_name, 10);
134 rosPublisher_depth = m_node->create_publisher<sensor_msgs::msg::Image>(m_depth_topic_name, 10);
135 rosPublisher_colorCaminfo = m_node->create_publisher<sensor_msgs::msg::CameraInfo>(m_color_info_topic_name, 10);
136 rosPublisher_depthCaminfo = m_node->create_publisher<sensor_msgs::msg::CameraInfo>(m_depth_info_topic_name, 10);
137 return true;
138}
139
140
142{
143 yCTrace(RGBDSENSOR_NWS_ROS2, "Close");
144 detach();
145
146 sensor_p = nullptr;
147 fgCtrl = nullptr;
148
149 return true;
150}
151
152// PeriodicThread
153
155{
156 if (sensor_p!=nullptr) {
157 static int i = 0;
158 switch (sensor_p->getSensorStatus()) {
160 if (!writeData()) {
161 yCError(RGBDSENSOR_NWS_ROS2, "Image not captured.. check hardware configuration");
162 }
163 i = 0;
164 break;
166 if(i < 1000) {
167 if((i % 30) == 0) {
168 yCInfo(RGBDSENSOR_NWS_ROS2) << "Device not ready, waiting...";
169 }
170 } else {
171 yCWarning(RGBDSENSOR_NWS_ROS2) << "Device is taking too long to start..";
172 }
173 i++;
174 break;
175 default:
176 yCError(RGBDSENSOR_NWS_ROS2, "Sensor returned error");
177 }
178 } else {
179 yCError(RGBDSENSOR_NWS_ROS2, "Sensor interface is not valid");
180 }
181}
182
183
184/*
185 * WrapperSingle interface
186 */
187
189{
190 if(poly)
191 {
192 poly->view(sensor_p);
193 poly->view(fgCtrl);
194 }
195
196 if(sensor_p == nullptr)
197 {
198 yCError(RGBDSENSOR_NWS_ROS2) << "Attached device has no valid IRGBDSensor interface.";
199 return false;
200 }
201
202 if(fgCtrl == nullptr)
203 {
204 yCWarning(RGBDSENSOR_NWS_ROS2) << "Attached device has no valid IFrameGrabberControls interface.";
205 }
206
207 return PeriodicThread::start();
208}
209
210
212{
215
216 sensor_p = nullptr;
217 if (fgCtrl)
218 {
219 fgCtrl = nullptr;
220 }
221 return true;
222}
223
224bool RgbdSensor_nws_ros2::setCamInfo(sensor_msgs::msg::CameraInfo& cameraInfo,
225 const std::string& frame_id,
226 const yarp::os::Stamp& stamp,
227 const SensorType& sensorType)
228{
229 double phyF = 0.0;
230 double fx = 0.0;
231 double fy = 0.0;
232 double cx = 0.0;
233 double cy = 0.0;
234 double k1 = 0.0;
235 double k2 = 0.0;
236 double t1 = 0.0;
237 double t2 = 0.0;
238 double k3 = 0.0;
239
240 std::string distModel;
241 std::string currentSensor;
242 yarp::os::Property camData;
243 std::vector<param<double> > parVector;
244 bool ok;
245
246 currentSensor = sensorType == COLOR_SENSOR ? "Rgb" : "Depth";
247 ok = sensorType == COLOR_SENSOR ? sensor_p->getRgbIntrinsicParam(camData) : sensor_p->getDepthIntrinsicParam(camData);
248
249 if (!ok)
250 {
251 yCError(RGBDSENSOR_NWS_ROS2) << "Unable to get intrinsic param from" << currentSensor << "sensor!";
252 return false;
253 }
254
255 if(!camData.check("distortionModel"))
256 {
257 yCWarning(RGBDSENSOR_NWS_ROS2) << "Missing distortion model";
258 return false;
259 }
260
261 distModel = camData.find("distortionModel").asString();
262 if (distModel != "plumb_bob")
263 {
264 yCError(RGBDSENSOR_NWS_ROS2) << "Distortion model not supported";
265 return false;
266 }
267
268 parVector.emplace_back(phyF,"physFocalLength");
269 parVector.emplace_back(fx,"focalLengthX");
270 parVector.emplace_back(fy,"focalLengthY");
271 parVector.emplace_back(cx,"principalPointX");
272 parVector.emplace_back(cy,"principalPointY");
273 parVector.emplace_back(k1,"k1");
274 parVector.emplace_back(k2,"k2");
275 parVector.emplace_back(t1,"t1");
276 parVector.emplace_back(t2,"t2");
277 parVector.emplace_back(k3,"k3");
278
279 for(auto& par : parVector) {
280 if(!camData.check(par.parname)) {
281 yCWarning(RGBDSENSOR_NWS_ROS2) << "Driver has not the param:" << par.parname;
282 return false;
283 }
284 *(par.var) = camData.find(par.parname).asFloat64();
285 }
286
287 cameraInfo.header.frame_id = frame_id;
288 cameraInfo.header.stamp.sec = static_cast<int>(stamp.getTime()); // FIXME
289 cameraInfo.header.stamp.nanosec = static_cast<int>(1000000000UL * (stamp.getTime() - int(stamp.getTime()))); // FIXME
290 cameraInfo.width = sensorType == COLOR_SENSOR ? sensor_p->getRgbWidth() : sensor_p->getDepthWidth();
291 cameraInfo.height = sensorType == COLOR_SENSOR ? sensor_p->getRgbHeight() : sensor_p->getDepthHeight();
292 cameraInfo.distortion_model = distModel;
293
294 cameraInfo.d.resize(5);
295 cameraInfo.d[0] = k1;
296 cameraInfo.d[1] = k2;
297 cameraInfo.d[2] = t1;
298 cameraInfo.d[3] = t2;
299 cameraInfo.d[4] = k3;
300
301 cameraInfo.k[0] = fx; cameraInfo.k[1] = 0; cameraInfo.k[2] = cx;
302 cameraInfo.k[3] = 0; cameraInfo.k[4] = fy; cameraInfo.k[5] = cy;
303 cameraInfo.k[6] = 0; cameraInfo.k[7] = 0; cameraInfo.k[8] = 1;
304
305 /*
306 * ROS documentation on cameraInfo message:
307 * "Rectification matrix (stereo cameras only)
308 * A rotation matrix aligning the camera coordinate system to the ideal
309 * stereo image plane so that epipolar lines in both stereo images are
310 * parallel."
311 * useless in our case, it will be an identity matrix
312 */
313
314 cameraInfo.r[0] = 1; cameraInfo.r[1] = 0; cameraInfo.r[2] = 0;
315 cameraInfo.r[3] = 0; cameraInfo.r[4] = 1; cameraInfo.r[5] = 0;
316 cameraInfo.r[6] = 0; cameraInfo.r[7] = 0; cameraInfo.r[8] = 1;
317
318 cameraInfo.p[0] = fx; cameraInfo.p[1] = 0; cameraInfo.p[2] = cx; cameraInfo.p[3] = 0;
319 cameraInfo.p[4] = 0; cameraInfo.p[5] = fy; cameraInfo.p[6] = cy; cameraInfo.p[7] = 0;
320 cameraInfo.p[8] = 0; cameraInfo.p[9] = 0; cameraInfo.p[10] = 1; cameraInfo.p[11] = 0;
321
322 cameraInfo.binning_x = cameraInfo.binning_y = 0;
323 cameraInfo.roi.height = cameraInfo.roi.width = cameraInfo.roi.x_offset = cameraInfo.roi.y_offset = 0;
324 cameraInfo.roi.do_rectify = false;
325 return true;
326}
327
328
329bool RgbdSensor_nws_ros2::writeData()
330{
331 yarp::sig::FlexImage colorImage;
333 yarp::os::Stamp colorStamp;
334 yarp::os::Stamp depthStamp;
335
336 if (!sensor_p->getImages(colorImage, depthImage, &colorStamp, &depthStamp)) {
337 return false;
338 }
339
340 static yarp::os::Stamp oldColorStamp = yarp::os::Stamp(0, 0);
341 static yarp::os::Stamp oldDepthStamp = yarp::os::Stamp(0, 0);
342 bool rgb_data_ok = true;
343 bool depth_data_ok = true;
344
345 if (((colorStamp.getTime() - oldColorStamp.getTime()) > 0) == false) {
346 rgb_data_ok=false;
347 //return true;
348 } else {
349 oldColorStamp = colorStamp;
350 }
351
352 if (((depthStamp.getTime() - oldDepthStamp.getTime()) > 0) == false) {
353 depth_data_ok=false;
354 //return true;
355 } else {
356 oldDepthStamp = depthStamp;
357 }
358
359 // TBD: We should check here somehow if the timestamp was correctly updated and, if not, update it ourselves.
360 if (rgb_data_ok) {
361 sensor_msgs::msg::Image rColorImage;
362 rColorImage.data.resize(colorImage.getRawImageSize());
363 rColorImage.width = colorImage.width();
364 rColorImage.height = colorImage.height();
365 memcpy(rColorImage.data.data(), colorImage.getRawImage(), colorImage.getRawImageSize());
366 rColorImage.encoding = yarp2RosPixelCode(colorImage.getPixelCode());
367 rColorImage.step = colorImage.getRowSize();
368 rColorImage.header.frame_id = m_color_frame_id;
369 rColorImage.header.stamp.sec = static_cast<int>(colorStamp.getTime()); // FIXME
370 rColorImage.header.stamp.nanosec = static_cast<int>(1000000000UL * (colorStamp.getTime() - int(colorStamp.getTime()))); // FIXME
371 rColorImage.is_bigendian = 0;
372
373 rosPublisher_color->publish(rColorImage);
374
375 sensor_msgs::msg::CameraInfo camInfoC;
376 if (setCamInfo(camInfoC, m_color_frame_id, colorStamp, COLOR_SENSOR)) {
377 if(m_forceInfoSync) {
378 camInfoC.header.stamp = rColorImage.header.stamp;
379 }
380 rosPublisher_colorCaminfo->publish(camInfoC);
381 } else {
382 yCWarning(RGBDSENSOR_NWS_ROS2, "Missing color camera parameters... camera info messages will be not sent");
383 }
384 }
385
386 if (depth_data_ok)
387 {
388 sensor_msgs::msg::Image rDepthImage;
389 rDepthImage.data.resize(depthImage.getRawImageSize());
390 rDepthImage.width = depthImage.width();
391 rDepthImage.height = depthImage.height();
392 memcpy(rDepthImage.data.data(), depthImage.getRawImage(), depthImage.getRawImageSize());
393 rDepthImage.encoding = yarp2RosPixelCode(depthImage.getPixelCode());
394 rDepthImage.step = depthImage.getRowSize();
395 rDepthImage.header.frame_id = m_depth_frame_id;
396 rDepthImage.header.stamp.sec = static_cast<int>(depthStamp.getTime()); // FIXME
397 rDepthImage.header.stamp.nanosec = static_cast<int>(1000000000UL * (depthStamp.getTime() - int(depthStamp.getTime()))); // FIXME
398 rDepthImage.is_bigendian = 0;
399
400 rosPublisher_depth->publish(rDepthImage);
401
402 sensor_msgs::msg::CameraInfo camInfoD;
403 if (setCamInfo(camInfoD, m_depth_frame_id, depthStamp, DEPTH_SENSOR)) {
404 if(m_forceInfoSync) {
405 camInfoD.header.stamp = rDepthImage.header.stamp;
406 }
407 rosPublisher_depthCaminfo->publish(camInfoD);
408 } else {
409 yCWarning(RGBDSENSOR_NWS_ROS2, "Missing depth camera parameters... camera info messages will be not sent");
410 }
411 }
412
413 return true;
414}
#define DEFAULT_THREAD_PERIOD
@ VOCAB_PIXEL_ENCODING_BAYER_BGGR16
Definition Image.h:59
@ VOCAB_PIXEL_RGBA
Definition Image.h:45
@ VOCAB_PIXEL_MONO16
Definition Image.h:43
@ VOCAB_PIXEL_ENCODING_BAYER_BGGR8
Definition Image.h:58
@ VOCAB_PIXEL_BGRA
Definition Image.h:46
@ VOCAB_PIXEL_BGR
Definition Image.h:49
@ VOCAB_PIXEL_MONO_FLOAT
Definition Image.h:53
@ VOCAB_PIXEL_ENCODING_BAYER_RGGB8
Definition Image.h:62
@ VOCAB_PIXEL_ENCODING_BAYER_GRBG8
Definition Image.h:56
@ VOCAB_PIXEL_ENCODING_BAYER_GBRG16
Definition Image.h:61
@ VOCAB_PIXEL_ENCODING_BAYER_GRBG16
Definition Image.h:57
@ VOCAB_PIXEL_ENCODING_BAYER_GBRG8
Definition Image.h:60
@ VOCAB_PIXEL_MONO
Definition Image.h:42
@ VOCAB_PIXEL_ENCODING_BAYER_RGGB16
Definition Image.h:63
@ VOCAB_PIXEL_RGB
Definition Image.h:44
yarp::sig::ImageOf< yarp::sig::PixelFloat > depthImage
static rclcpp::Node::SharedPtr createNode(std::string name)
Definition Ros2Utils.cpp:9
bool parseParams(const yarp::os::Searchable &config) override
Parse the DeviceDriver parameters.
bool detach() override
Detach the object (you must have first called attach).
bool attach(yarp::dev::PolyDriver *poly) override
Attach to another object.
bool open(yarp::os::Searchable &config) override
Open the DeviceDriver.
void run() override
Loop function.
bool close() override
Close the DeviceDriver.
bool view(T *&x)
Get an interface to the device driver.
int getRgbWidth() override=0
Return the width of each frame.
bool getRgbIntrinsicParam(yarp::os::Property &intrinsic) override=0
Get the intrinsic parameters of the rgb camera.
int getDepthWidth() override=0
Return the height of each frame.
int getRgbHeight() override=0
Return the height of each frame.
virtual bool getImages(yarp::sig::FlexImage &colorFrame, yarp::sig::ImageOf< yarp::sig::PixelFloat > &depthFrame, yarp::os::Stamp *colorStamp=nullptr, yarp::os::Stamp *depthStamp=nullptr)=0
Get the both the color and depth frame in a single call.
virtual RGBDSensor_status getSensorStatus()=0
Get the surrent status of the sensor, using enum type.
int getDepthHeight() override=0
Return the height of each frame.
bool getDepthIntrinsicParam(yarp::os::Property &intrinsic) override=0
Get the intrinsic parameters of the depth camera.
A container for a device driver.
Definition PolyDriver.h:23
@ TraceType
Definition Log.h:92
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:33
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
bool check(const std::string &key) const override
Check if there exists a property of the given name.
A base class for nested structures that can be searched.
Definition Searchable.h:31
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:21
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 std::string asString() const
Get string value.
Definition Value.cpp:234
Image class with user control of representation details.
Definition Image.h:374
Typed image class.
Definition Image.h:616
int getPixelCode() const override
Gets pixel type identifier.
Definition Image.h:732
size_t width() const
Gets width of image in pixels.
Definition Image.h:163
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition Image.h:189
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition Image.cpp:542
size_t getRawImageSize() const
Access to the internal buffer size information (this is how much memory has been allocated for the im...
Definition Image.cpp:551
size_t height() const
Gets height of image in pixels.
Definition Image.h:169
virtual int getPixelCode() const
Gets pixel type identifier.
Definition Image.cpp:441
#define yCInfo(component,...)
#define yCError(component,...)
#define yCTrace(component,...)
#define yCWarning(component,...)
#define yCDebug(component,...)
#define YARP_LOG_COMPONENT(name,...)
const std::string depthInfoTopicName_param
const std::string depthTopicName_param
const std::string colorTopicName_param
const std::string nodeName_param
const std::string frameId_param
const std::string colorInfoTopicName_param
std::string yarp2RosPixelCode(int code)
The main, catch-all namespace for YARP.
Definition dirs.h:16