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 SensorType& sensorType)
227{
228 double phyF = 0.0;
229 double fx = 0.0;
230 double fy = 0.0;
231 double cx = 0.0;
232 double cy = 0.0;
233 double k1 = 0.0;
234 double k2 = 0.0;
235 double t1 = 0.0;
236 double t2 = 0.0;
237 double k3 = 0.0;
238
239 std::string distModel;
240 std::string currentSensor;
241 yarp::os::Property camData;
242 std::vector<param<double> > parVector;
243 bool ok;
244
245 currentSensor = sensorType == COLOR_SENSOR ? "Rgb" : "Depth";
246 ok = sensorType == COLOR_SENSOR ? sensor_p->getRgbIntrinsicParam(camData) : sensor_p->getDepthIntrinsicParam(camData);
247
248 if (!ok)
249 {
250 yCError(RGBDSENSOR_NWS_ROS2) << "Unable to get intrinsic param from" << currentSensor << "sensor!";
251 return false;
252 }
253
254 if(!camData.check("distortionModel"))
255 {
256 yCWarning(RGBDSENSOR_NWS_ROS2) << "Missing distortion model";
257 return false;
258 }
259
260 distModel = camData.find("distortionModel").asString();
261
262 parVector.emplace_back(phyF,"physFocalLength");
263 parVector.emplace_back(fx,"focalLengthX");
264 parVector.emplace_back(fy,"focalLengthY");
265 parVector.emplace_back(cx,"principalPointX");
266 parVector.emplace_back(cy,"principalPointY");
267
268 if (distModel != "none")
269 {
270 parVector.emplace_back(k1,"k1");
271 parVector.emplace_back(k2,"k2");
272 parVector.emplace_back(t1,"t1");
273 parVector.emplace_back(t2,"t2");
274 parVector.emplace_back(k3,"k3");
275 }
276
277 for(auto& par : parVector) {
278 if(!camData.check(par.parname)) {
279 yCWarning(RGBDSENSOR_NWS_ROS2) << "Driver has not the param:" << par.parname;
280 return false;
281 }
282 *(par.var) = camData.find(par.parname).asFloat64();
283 }
284
285 cameraInfo.header.frame_id = frame_id;
286 cameraInfo.width = sensorType == COLOR_SENSOR ? sensor_p->getRgbWidth() : sensor_p->getDepthWidth();
287 cameraInfo.height = sensorType == COLOR_SENSOR ? sensor_p->getRgbHeight() : sensor_p->getDepthHeight();
288 cameraInfo.distortion_model = distModel;
289
290 if (distModel != "none")
291 {
292 cameraInfo.d.resize(5);
293 cameraInfo.d[0] = k1;
294 cameraInfo.d[1] = k2;
295 cameraInfo.d[2] = t1;
296 cameraInfo.d[3] = t2;
297 cameraInfo.d[4] = k3;
298 }
299
300 cameraInfo.k[0] = fx; cameraInfo.k[1] = 0; cameraInfo.k[2] = cx;
301 cameraInfo.k[3] = 0; cameraInfo.k[4] = fy; cameraInfo.k[5] = cy;
302 cameraInfo.k[6] = 0; cameraInfo.k[7] = 0; cameraInfo.k[8] = 1;
303
304 /*
305 * ROS documentation on cameraInfo message:
306 * "Rectification matrix (stereo cameras only)
307 * A rotation matrix aligning the camera coordinate system to the ideal
308 * stereo image plane so that epipolar lines in both stereo images are
309 * parallel."
310 * useless in our case, it will be an identity matrix
311 */
312
313 cameraInfo.r[0] = 1; cameraInfo.r[1] = 0; cameraInfo.r[2] = 0;
314 cameraInfo.r[3] = 0; cameraInfo.r[4] = 1; cameraInfo.r[5] = 0;
315 cameraInfo.r[6] = 0; cameraInfo.r[7] = 0; cameraInfo.r[8] = 1;
316
317 cameraInfo.p[0] = fx; cameraInfo.p[1] = 0; cameraInfo.p[2] = cx; cameraInfo.p[3] = 0;
318 cameraInfo.p[4] = 0; cameraInfo.p[5] = fy; cameraInfo.p[6] = cy; cameraInfo.p[7] = 0;
319 cameraInfo.p[8] = 0; cameraInfo.p[9] = 0; cameraInfo.p[10] = 1; cameraInfo.p[11] = 0;
320
321 cameraInfo.binning_x = cameraInfo.binning_y = 0;
322 cameraInfo.roi.height = cameraInfo.roi.width = cameraInfo.roi.x_offset = cameraInfo.roi.y_offset = 0;
323 cameraInfo.roi.do_rectify = false;
324 return true;
325}
326
327
328bool RgbdSensor_nws_ros2::writeData()
329{
330 yarp::sig::FlexImage colorImage;
332 yarp::os::Stamp colorStamp;
333 yarp::os::Stamp depthStamp;
334
335 if (!sensor_p->getImages(colorImage, depthImage, &colorStamp, &depthStamp)) {
336 return false;
337 }
338
339 static yarp::os::Stamp oldColorStamp = yarp::os::Stamp(0, 0);
340 static yarp::os::Stamp oldDepthStamp = yarp::os::Stamp(0, 0);
341 bool rgb_data_ok = true;
342 bool depth_data_ok = true;
343
344 if (((colorStamp.getTime() - oldColorStamp.getTime()) > 0) == false) {
345 rgb_data_ok=false;
346 //return true;
347 } else {
348 oldColorStamp = colorStamp;
349 }
350
351 if (((depthStamp.getTime() - oldDepthStamp.getTime()) > 0) == false) {
352 depth_data_ok=false;
353 //return true;
354 } else {
355 oldDepthStamp = depthStamp;
356 }
357
358 // Call setCamInfo only the first time
359 if (m_firstTime) {
360 setCamInfo(m_camInfoData.colorCamInfo, "color_frame", COLOR_SENSOR);
361 setCamInfo(m_camInfoData.depthCamInfo, "depth_frame", DEPTH_SENSOR);
362 m_firstTime = false;
363 }
364
365 // Use m_camInfoData for subsequent calls
366 if (rgb_data_ok) {
367 sensor_msgs::msg::Image rColorImage;
368 rColorImage.data.resize(colorImage.getRawImageSize());
369 rColorImage.width = colorImage.width();
370 rColorImage.height = colorImage.height();
371 memcpy(rColorImage.data.data(), colorImage.getRawImage(), colorImage.getRawImageSize());
372 rColorImage.encoding = yarp2RosPixelCode(colorImage.getPixelCode());
373 rColorImage.step = colorImage.getRowSize();
374 rColorImage.header.frame_id = m_color_frame_id;
375 rColorImage.header.stamp.sec = static_cast<int>(colorStamp.getTime()); // FIXME
376 rColorImage.header.stamp.nanosec = static_cast<int>(1000000000UL * (colorStamp.getTime() - int(colorStamp.getTime()))); // FIXME
377 rColorImage.is_bigendian = 0;
378
379 rosPublisher_color->publish(rColorImage);
380
381 if (m_forceInfoSync) {
382 m_camInfoData.colorCamInfo.header.stamp = rColorImage.header.stamp;
383 }
384 rosPublisher_colorCaminfo->publish(m_camInfoData.colorCamInfo);
385 }
386
387 if (depth_data_ok)
388 {
389 sensor_msgs::msg::Image rDepthImage;
390 rDepthImage.data.resize(depthImage.getRawImageSize());
391 rDepthImage.width = depthImage.width();
392 rDepthImage.height = depthImage.height();
393 memcpy(rDepthImage.data.data(), depthImage.getRawImage(), depthImage.getRawImageSize());
394 rDepthImage.encoding = yarp2RosPixelCode(depthImage.getPixelCode());
395 rDepthImage.step = depthImage.getRowSize();
396 rDepthImage.header.frame_id = m_depth_frame_id;
397 rDepthImage.header.stamp.sec = static_cast<int>(depthStamp.getTime()); // FIXME
398 rDepthImage.header.stamp.nanosec = static_cast<int>(1000000000UL * (depthStamp.getTime() - int(depthStamp.getTime()))); // FIXME
399 rDepthImage.is_bigendian = 0;
400
401 rosPublisher_depth->publish(rDepthImage);
402
403 if (m_forceInfoSync) {
404 m_camInfoData.depthCamInfo.header.stamp = rDepthImage.header.stamp;
405 }
406 rosPublisher_depthCaminfo->publish(m_camInfoData.depthCamInfo);
407 }
408
409 return true;
410}
#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:363
Typed image class.
Definition Image.h:605
int getPixelCode() const override
Gets pixel type identifier.
Definition Image.h:721
size_t width() const
Gets width of image in pixels.
Definition Image.h:171
size_t getRowSize() const
Size of the underlying image buffer rows.
Definition Image.h:197
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition Image.cpp:479
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:488
size_t height() const
Gets height of image in pixels.
Definition Image.h:177
virtual int getPixelCode() const
Gets pixel type identifier.
Definition Image.cpp:390
#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
sensor_msgs::msg::CameraInfo depthCamInfo
sensor_msgs::msg::CameraInfo colorCamInfo