camera_nodelet.cpp
Go to the documentation of this file.
1 /*
2  * SPDX-License-Identifier: Apache-2.0
3  * Copyright (C) 2021 ifm electronic, gmbh
4  */
5 
7 
8 #include <cmath>
9 #include <cstdint>
10 #include <memory>
11 #include <mutex>
12 #include <sstream>
13 #include <stdexcept>
14 #include <string>
15 #include <vector>
16 
18 #include <nodelet/nodelet.h>
20 #include <ros/ros.h>
21 #include <sensor_msgs/CompressedImage.h>
22 #include <sensor_msgs/Image.h>
23 #include <sensor_msgs/PointCloud2.h>
25 
26 #include <ifm3d_ros_msgs/Config.h>
27 #include <ifm3d_ros_msgs/Dump.h>
28 #include <ifm3d_ros_msgs/Extrinsics.h>
29 #include <ifm3d_ros_msgs/SoftOff.h>
30 #include <ifm3d_ros_msgs/SoftOn.h>
31 #include <ifm3d_ros_msgs/Trigger.h>
32 
33 #include <ifm3d/contrib/nlohmann/json.hpp>
34 
35 sensor_msgs::Image ifm3d_to_ros_image(ifm3d::Image& image, // Need non-const image because image.begin(),
36  // image.end() don't have const overloads.
37  const std_msgs::Header& header, const std::string& logger)
38 {
39  static constexpr auto max_pixel_format = static_cast<std::size_t>(ifm3d::pixel_format::FORMAT_32F3);
40  static auto image_format_info = [] {
41  auto image_format_info = std::array<std::string, max_pixel_format + 1>{};
42 
43  {
44  using namespace ifm3d;
45  using namespace sensor_msgs::image_encodings;
46  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_8U)] = TYPE_8UC1;
47  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_8S)] = TYPE_8SC1;
48  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_16U)] = TYPE_16UC1;
49  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_16S)] = TYPE_16SC1;
50  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_32U)] = "32UC1";
51  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_32S)] = TYPE_32SC1;
52  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_32F)] = TYPE_32FC1;
53  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_64U)] = "64UC1";
54  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_64F)] = TYPE_64FC1;
55  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_16U2)] = TYPE_16UC2;
56  image_format_info[static_cast<std::size_t>(pixel_format::FORMAT_32F3)] = TYPE_32FC3;
57  }
58 
59  return image_format_info;
60  }();
61 
62  const auto format = static_cast<std::size_t>(image.dataFormat());
63 
64  sensor_msgs::Image result{};
65  result.header = header;
66  result.height = image.height();
67  result.width = image.width();
68  result.is_bigendian = 0;
69 
70  if (image.begin<std::uint8_t>() == image.end<std::uint8_t>())
71  {
72  return result;
73  }
74 
75  if (format >= max_pixel_format)
76  {
77  ROS_ERROR_NAMED(logger, "Pixel format out of range (%ld >= %ld)", format, max_pixel_format);
78  return result;
79  }
80 
81  result.encoding = image_format_info.at(format);
82  result.step = result.width * sensor_msgs::image_encodings::bitDepth(image_format_info.at(format)) / 8;
83  result.data.insert(result.data.end(), image.ptr<>(0), std::next(image.ptr<>(0), result.step * result.height));
84 
85  if (result.encoding.empty())
86  {
87  ROS_WARN_NAMED(logger, "Can't handle encoding %ld (32U == %ld, 64U == %ld)", format,
88  static_cast<std::size_t>(ifm3d::pixel_format::FORMAT_32U),
89  static_cast<std::size_t>(ifm3d::pixel_format::FORMAT_64U));
91  }
92 
93  return result;
94 }
95 
96 sensor_msgs::Image ifm3d_to_ros_image(ifm3d::Image&& image, const std_msgs::Header& header, const std::string& logger)
97 {
98  return ifm3d_to_ros_image(image, header, logger);
99 }
100 
101 sensor_msgs::CompressedImage ifm3d_to_ros_compressed_image(ifm3d::Image& image, // Need non-const image because
102  // image.begin(), image.end()
103  // don't have const overloads.
104  const std_msgs::Header& header,
105  const std::string& format, // "jpeg" or "png"
106  const std::string& logger)
107 {
108  sensor_msgs::CompressedImage result{};
109  result.header = header;
110  result.format = format;
111 
112  {
113  const auto dataFormat = image.dataFormat();
114  if (dataFormat != ifm3d::pixel_format::FORMAT_8S && dataFormat != ifm3d::pixel_format::FORMAT_8U)
115  {
116  ROS_ERROR_NAMED(logger, "Invalid data format for %s data (%ld)", format.c_str(),
117  static_cast<std::size_t>(dataFormat));
118  return result;
119  }
120  }
121 
122  result.data.insert(result.data.end(), image.ptr<>(0), std::next(image.ptr<>(0), image.width() * image.height()));
123  return result;
124 }
125 
126 sensor_msgs::CompressedImage ifm3d_to_ros_compressed_image(ifm3d::Image&& image, const std_msgs::Header& header,
127  const std::string& format, const std::string& logger)
128 {
129  return ifm3d_to_ros_compressed_image(image, header, format, logger);
130 }
131 
132 sensor_msgs::PointCloud2 ifm3d_to_ros_cloud(ifm3d::Image& image, // Need non-const image because image.begin(),
133  // image.end() don't have const overloads.
134  const std_msgs::Header& header, const std::string& logger)
135 {
136  sensor_msgs::PointCloud2 result{};
137  result.header = header;
138  result.height = image.height();
139  result.width = image.width();
140  result.is_bigendian = false;
141 
142  if (image.begin<std::uint8_t>() == image.end<std::uint8_t>())
143  {
144  return result;
145  }
146 
147  if (image.dataFormat() != ifm3d::pixel_format::FORMAT_32F3 && image.dataFormat() != ifm3d::pixel_format::FORMAT_32F)
148  {
149  ROS_ERROR_NAMED(logger, "Unsupported pixel format %ld for point cloud",
150  static_cast<std::size_t>(image.dataFormat()));
151  return result;
152  }
153 
154  sensor_msgs::PointField x_field{};
155  x_field.name = "x";
156  x_field.offset = 0;
157  x_field.datatype = sensor_msgs::PointField::FLOAT32;
158  x_field.count = 1;
159 
160  sensor_msgs::PointField y_field{};
161  y_field.name = "y";
162  y_field.offset = 4;
163  y_field.datatype = sensor_msgs::PointField::FLOAT32;
164  y_field.count = 1;
165 
166  sensor_msgs::PointField z_field{};
167  z_field.name = "z";
168  z_field.offset = 8;
169  z_field.datatype = sensor_msgs::PointField::FLOAT32;
170  z_field.count = 1;
171 
172  result.fields = {
173  x_field,
174  y_field,
175  z_field,
176  };
177 
178  result.point_step = result.fields.size() * sizeof(float);
179  result.row_step = result.point_step * result.width;
180  result.is_dense = true;
181  result.data.insert(result.data.end(), image.ptr<>(0), std::next(image.ptr<>(0), result.row_step * result.height));
182 
183  return result;
184 }
185 
186 sensor_msgs::PointCloud2 ifm3d_to_ros_cloud(ifm3d::Image&& image, const std_msgs::Header& header,
187  const std::string& logger)
188 {
189  return ifm3d_to_ros_cloud(image, header, logger);
190 }
191 
194 
196 {
197  std::string nn = this->getName();
198  NODELET_DEBUG_STREAM("onInit(): " << nn);
199 
200  this->np_ = getMTPrivateNodeHandle();
201  this->it_.reset(new image_transport::ImageTransport(this->np_));
202 
203  //
204  // parse data out of the parameter server
205  //
206  // NOTE: AFAIK, there is no way to get an unsigned int type out of the ROS
207  // parameter server.
208  //
209  int schema_mask;
210  int xmlrpc_port;
211  int pcic_port;
212  std::string frame_id_base;
213 
214  if ((nn.size() > 0) && (nn.at(0) == '/'))
215  {
216  frame_id_base = nn.substr(1);
217  }
218  else
219  {
220  frame_id_base = nn;
221  }
222 
223  this->np_.param("ip", this->camera_ip_, ifm3d::DEFAULT_IP);
224  NODELET_INFO("IP default: %s, current %s", ifm3d::DEFAULT_IP.c_str(), this->camera_ip_.c_str());
225 
226  this->np_.param("xmlrpc_port", xmlrpc_port, (int)ifm3d::DEFAULT_XMLRPC_PORT);
227  this->np_.param("pcic_port", pcic_port, (int)ifm3d::DEFAULT_PCIC_PORT);
228  NODELET_INFO("pcic port check: current %d, default %d", pcic_port, ifm3d::DEFAULT_PCIC_PORT);
229 
230  this->np_.param("password", this->password_, ifm3d::DEFAULT_PASSWORD);
231  this->np_.param("schema_mask", schema_mask, (int)ifm3d::DEFAULT_SCHEMA_MASK);
232  this->np_.param("timeout_millis", this->timeout_millis_, 500);
233  this->np_.param("timeout_tolerance_secs", this->timeout_tolerance_secs_, 5.0);
234  this->np_.param("assume_sw_triggered", this->assume_sw_triggered_, false);
235  this->np_.param("soft_on_timeout_millis", this->soft_on_timeout_millis_, 500);
236  this->np_.param("soft_on_timeout_tolerance_secs", this->soft_on_timeout_tolerance_secs_, 5.0);
237  this->np_.param("soft_off_timeout_millis", this->soft_off_timeout_millis_, 500);
238  this->np_.param("soft_off_timeout_tolerance_secs", this->soft_off_timeout_tolerance_secs_, 600.0);
239  this->np_.param("frame_latency_thresh", this->frame_latency_thresh_, 60.0f);
240  this->np_.param("frame_id_base", frame_id_base, frame_id_base);
241 
242  this->xmlrpc_port_ = static_cast<std::uint16_t>(xmlrpc_port);
243  this->schema_mask_ = static_cast<std::uint16_t>(schema_mask);
244  this->pcic_port_ = static_cast<std::uint16_t>(pcic_port);
245 
246  NODELET_DEBUG_STREAM("setup ros node parameters finished");
247 
248  this->frame_id_ = frame_id_base + "_link";
249  this->optical_frame_id_ = frame_id_base + "_optical_link";
250 
251  //-------------------
252  // Published topics
253  //-------------------
254  this->cloud_pub_ = this->np_.advertise<sensor_msgs::PointCloud2>("cloud", 1);
255  this->distance_pub_ = this->it_->advertise("distance", 1);
256  this->distance_noise_pub_ = this->it_->advertise("distance_noise", 1);
257  this->amplitude_pub_ = this->it_->advertise("amplitude", 1);
258  this->raw_amplitude_pub_ = this->it_->advertise("raw_amplitude", 1);
259  this->conf_pub_ = this->it_->advertise("confidence", 1);
260  this->gray_image_pub_ = this->it_->advertise("gray_image", 1);
261  this->rgb_image_pub_ = this->np_.advertise<sensor_msgs::CompressedImage>("rgb_image/compressed", 1);
262 
263  // we latch the unit vectors
264  this->uvec_pub_ = this->np_.advertise<sensor_msgs::Image>("unit_vectors", 1, true);
265 
266  this->extrinsics_pub_ = this->np_.advertise<ifm3d_ros_msgs::Extrinsics>("extrinsics", 1);
267  NODELET_DEBUG_STREAM("after advertising the publishers");
268  //---------------------
269  // Advertised Services
270  //---------------------
271  this->dump_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::Dump::Request, ifm3d_ros_msgs::Dump::Response>(
272  "Dump", std::bind(&CameraNodelet::Dump, this, std::placeholders::_1, std::placeholders::_2));
273 
274  this->config_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::Config::Request, ifm3d_ros_msgs::Config::Response>(
275  "Config", std::bind(&CameraNodelet::Config, this, std::placeholders::_1, std::placeholders::_2));
276 
277  this->trigger_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::Trigger::Request, ifm3d_ros_msgs::Trigger::Response>(
278  "Trigger", std::bind(&CameraNodelet::Trigger, this, std::placeholders::_1, std::placeholders::_2));
279 
280  this->soft_off_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::SoftOff::Request, ifm3d_ros_msgs::SoftOff::Response>(
281  "SoftOff", std::bind(&CameraNodelet::SoftOff, this, std::placeholders::_1, std::placeholders::_2));
282 
283  this->soft_on_srv_ = this->np_.advertiseService<ifm3d_ros_msgs::SoftOn::Request, ifm3d_ros_msgs::SoftOn::Response>(
284  "SoftOn", std::bind(&CameraNodelet::SoftOn, this, std::placeholders::_1, std::placeholders::_2));
285 
286  NODELET_DEBUG_STREAM("after advertise service");
287  //----------------------------------
288  // Fire off our main publishing loop
289  //----------------------------------
290  this->publoop_timer_ = this->np_.createTimer(
291  ros::Duration(.001), [this](const ros::TimerEvent& t) { this->Run(); },
292  true); // oneshot timer
293 }
294 
295 bool ifm3d_ros::CameraNodelet::Dump(ifm3d_ros_msgs::Dump::Request& req, ifm3d_ros_msgs::Dump::Response& res)
296 {
297  std::lock_guard<std::mutex> lock(this->mutex_);
298  res.status = 0;
299 
300  try
301  {
302  json j = this->cam_->ToJSON();
303  res.config = j.dump();
304  }
305  catch (const ifm3d::error_t& ex)
306  {
307  res.status = ex.code();
308  NODELET_WARN_STREAM(ex.what());
309  }
310  catch (const std::exception& std_ex)
311  {
312  res.status = -1;
313  NODELET_WARN_STREAM(std_ex.what());
314  }
315  catch (...)
316  {
317  res.status = -2;
318  }
319 
320  if (res.status != 0)
321  {
322  NODELET_WARN_STREAM("Dump: " << res.status);
323  }
324 
325  return true;
326 }
327 
328 bool ifm3d_ros::CameraNodelet::Config(ifm3d_ros_msgs::Config::Request& req, ifm3d_ros_msgs::Config::Response& res)
329 {
330  std::lock_guard<std::mutex> lock(this->mutex_);
331  res.status = 0;
332  res.msg = "OK";
333 
334  try
335  {
336  this->cam_->FromJSON(json::parse(req.json));
337  }
338  catch (const ifm3d::error_t& ex)
339  {
340  res.status = ex.code();
341  res.msg = ex.what();
342  }
343  catch (const std::exception& std_ex)
344  {
345  res.status = -1;
346  res.msg = std_ex.what();
347  }
348  catch (...)
349  {
350  res.status = -2;
351  res.msg = "Unknown error in `Config'";
352  }
353 
354  if (res.status != 0)
355  {
356  NODELET_WARN_STREAM("Config: " << res.status << " - " << res.msg);
357  }
358 
359  return true;
360 }
361 
362 bool ifm3d_ros::CameraNodelet::Trigger(ifm3d_ros_msgs::Trigger::Request& req, ifm3d_ros_msgs::Trigger::Response& res)
363 {
364  std::lock_guard<std::mutex> lock(this->mutex_);
365  res.status = 0;
366  res.msg = "Software trigger is currently not implemented";
367 
368  try
369  {
370  this->fg_->SWTrigger();
371  }
372  catch (const ifm3d::error_t& ex)
373  {
374  res.status = ex.code();
375  }
376 
377  NODELET_WARN_STREAM("Triggering a camera head is currently not implemented - will follow");
378  return true;
379 }
380 
381 // this is a dummy method for the moment: the idea of applications is not supported for the O3RCamera
382 // we keep this in to possibly keep it comparable / interoperable with the ROS wrappers for other ifm cameras
383 bool ifm3d_ros::CameraNodelet::SoftOff(ifm3d_ros_msgs::SoftOff::Request& req, ifm3d_ros_msgs::SoftOff::Response& res)
384 {
385  std::lock_guard<std::mutex> lock(this->mutex_);
386  res.status = 0;
387 
388  int port_arg = -1;
389 
390  try
391  {
392  port_arg = static_cast<int>(this->pcic_port_) % 50010;
393 
394  // Configure the device from a json string
395  this->cam_->FromJSONStr("{\"ports\":{\"port" + std::to_string(port_arg) + "\": {\"state\": \"IDLE\"}}}");
396 
397  this->assume_sw_triggered_ = false;
398  this->timeout_millis_ = this->soft_on_timeout_millis_;
399  this->timeout_tolerance_secs_ = this->soft_on_timeout_tolerance_secs_;
400  }
401  catch (const ifm3d::error_t& ex)
402  {
403  res.status = ex.code();
404  res.msg = ex.what();
405  return false;
406  }
407 
408  NODELET_WARN_STREAM("The concept of applications is not available for the O3R - we use IDLE and RUN states instead");
409  res.msg = "{\"ports\":{\"port" + std::to_string(port_arg) + "\": {\"state\": \"IDLE\"}}}";
410 
411  return true;
412 }
413 
414 // this is a dummy method for the moment: the idea of applications is not supported for the O3RCamera
415 // we keep this in to possibly keep it comparable / interoperable with the ROS wrappers for other ifm cameras
416 bool ifm3d_ros::CameraNodelet::SoftOn(ifm3d_ros_msgs::SoftOn::Request& req, ifm3d_ros_msgs::SoftOn::Response& res)
417 {
418  std::lock_guard<std::mutex> lock(this->mutex_);
419  res.status = 0;
420  int port_arg = -1;
421 
422  try
423  {
424  port_arg = static_cast<int>(this->pcic_port_) % 50010;
425 
426  // try getting a current configuration as an ifm3d dump
427  // this way a a-priori test before setting the state can be tested
428  // try
429  // {
430  // json j = this->cam_->ToJSON();
431  // }
432  // catch (const ifm3d::error_t& ex)
433  // {
434  // NODELET_WARN_STREAM(ex.code());
435  // NODELET_WARN_STREAM(ex.what());
436  // }
437  // catch (const std::exception& std_ex)
438  // {
439  // NODELET_WARN_STREAM(std_ex.what());
440  // }
441 
442  // Configure the device from a json string
443  this->cam_->FromJSONStr("{\"ports\":{\"port" + std::to_string(port_arg) + "\": {\"state\": \"RUN\"}}}");
444 
445  this->assume_sw_triggered_ = false;
446  this->timeout_millis_ = this->soft_on_timeout_millis_;
447  this->timeout_tolerance_secs_ = this->soft_on_timeout_tolerance_secs_;
448  }
449  catch (const ifm3d::error_t& ex)
450  {
451  res.status = ex.code();
452  res.msg = ex.what();
453  return false;
454  }
455 
456  NODELET_WARN_STREAM("The concept of applications is not available for the O3R - we use IDLE and RUN states instead");
457  res.msg = "{\"ports\":{\"port" + std::to_string(port_arg) + "\": {\"state\": \"RUN\"}}}";
458 
459  return true;
460 }
461 
462 bool ifm3d_ros::CameraNodelet::InitStructures(std::uint16_t mask, std::uint16_t pcic_port)
463 {
464  std::lock_guard<std::mutex> lock(this->mutex_);
465  bool retval = false;
466 
467  try
468  {
469  NODELET_INFO_STREAM("Running dtors...");
470  this->im_.reset();
471  this->fg_.reset();
472  this->cam_.reset();
473 
474  NODELET_INFO_STREAM("Initializing camera...");
475  this->cam_ = ifm3d::CameraBase::MakeShared(this->camera_ip_, this->xmlrpc_port_);
476  ros::Duration(1.0).sleep();
477 
478  NODELET_INFO_STREAM("Initializing framegrabber...");
479  this->fg_ = std::make_shared<ifm3d::FrameGrabber>(this->cam_, mask, this->pcic_port_);
480  NODELET_INFO("Nodelet arguments: %d, %d", (int)mask, (int)this->pcic_port_);
481 
482  NODELET_INFO_STREAM("Initializing image buffer...");
483  this->im_ = std::make_shared<ifm3d::StlImageBuffer>();
484 
485  retval = true;
486  }
487  catch (const ifm3d::error_t& ex)
488  {
489  NODELET_WARN_STREAM(ex.code() << ": " << ex.what());
490  this->im_.reset();
491  this->fg_.reset();
492  this->cam_.reset();
493  retval = false;
494  }
495 
496  return retval;
497 }
498 
499 // this is the helper function for retrieving complete pcic frames
501 {
502  std::lock_guard<std::mutex> lock(this->mutex_);
503  bool retval = false;
504  NODELET_DEBUG_STREAM("try receiving data via fg WaitForFrame");
505  try
506  {
507  retval = this->fg_->WaitForFrame(this->im_.get(), this->timeout_millis_);
508  }
509  catch (const ifm3d::error_t& ex)
510  {
511  NODELET_WARN_STREAM(ex.code() << ": " << ex.what());
512  retval = false;
513  }
514 
515  return retval;
516 }
517 
519 {
520  std::unique_lock<std::mutex> lock(this->mutex_, std::defer_lock);
521 
522  NODELET_DEBUG_STREAM("in Run");
523 
524  // We need to account for the case of when the nodelet is being started prior
525  // to the camera being plugged in.
526 
527  while (ros::ok() && (!this->InitStructures(ifm3d::IMG_UVEC, this->pcic_port_)))
528  {
529  NODELET_WARN_STREAM("Could not initialize pixel stream!");
530  ros::Duration(1.0).sleep();
531  }
532 
533  ifm3d::Image confidence_img;
534  ifm3d::Image distance_img;
535  ifm3d::Image distance_noise_img;
536  ifm3d::Image amplitude_img;
537  ifm3d::Image xyz_img;
538  ifm3d::Image raw_amplitude_img;
539  ifm3d::Image gray_img;
540  ifm3d::Image rgb_img;
541 
542  NODELET_DEBUG_STREAM("after initializing the opencv buffers");
543  std::vector<float> extrinsics(6);
544 
545  // XXX: need to implement a nice strategy for getting the actual times
546  // from the camera which are registered to the frame data in the image
547  // buffer.
548  ros::Time last_frame = ros::Time::now();
549  bool got_uvec = false;
550 
551  while (ros::ok())
552  {
553  if (!this->AcquireFrame())
554  {
555  if (!this->assume_sw_triggered_)
556  {
557  NODELET_WARN_STREAM("Timeout waiting for camera!");
558  }
559  else
560  {
561  ros::Duration(.001).sleep();
562  }
563 
564  if ((ros::Time::now() - last_frame).toSec() > this->timeout_tolerance_secs_)
565  {
566  NODELET_WARN_STREAM("Attempting to restart framegrabber...");
567  while (!this->InitStructures(got_uvec ? this->schema_mask_ : ifm3d::IMG_UVEC, this->pcic_port_))
568  {
569  NODELET_WARN_STREAM("Could not re-initialize pixel stream!");
570  ros::Duration(1.0).sleep();
571  }
572 
573  last_frame = ros::Time::now();
574  }
575 
576  continue;
577  }
578 
579  last_frame = ros::Time::now();
580 
581  NODELET_DEBUG_STREAM("prepare header");
582  std_msgs::Header head = std_msgs::Header();
583  head.frame_id = this->frame_id_;
584  head.stamp = ros::Time(std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1>>>(
585  this->im_->TimeStamp().time_since_epoch())
586  .count());
587  if ((ros::Time::now() - head.stamp) > ros::Duration(this->frame_latency_thresh_))
588  {
589  NODELET_INFO_ONCE("Camera's time and client's time are not synced");
590  head.stamp = ros::Time::now();
591  }
592  NODELET_DEBUG_STREAM("in header, before setting header to msgs");
593  std_msgs::Header optical_head = std_msgs::Header();
594  optical_head.stamp = head.stamp;
595  optical_head.frame_id = this->optical_frame_id_;
596 
597  // currently the unit vector calculation seems to be missing in the ifm3d state: therefore we don't publish anything
598  // to the uvec pubisher publish unit vectors once on a latched topic, then re-initialize the framegrabber with the
599  // user's requested schema mask
600  if (!got_uvec)
601  {
602  lock.lock();
603  sensor_msgs::Image uvec_msg = ifm3d_to_ros_image(this->im_->UnitVectors(), optical_head, getName());
604  NODELET_INFO_STREAM("uvec image size: " << uvec_msg.height * uvec_msg.width);
605  lock.unlock();
606  this->uvec_pub_.publish(uvec_msg);
607  got_uvec = true;
608  NODELET_INFO("Got unit vectors, restarting framegrabber with mask: %d", (int)this->schema_mask_);
609 
610  while (!this->InitStructures(this->schema_mask_, this->pcic_port_))
611  {
612  NODELET_WARN("Could not re-initialize pixel stream!");
613  ros::Duration(1.0).sleep();
614  }
615 
616  NODELET_INFO_STREAM("Start streaming data");
617  continue;
618  }
619 
620  //
621  // Pull out all the wrapped images so that we can release the "GIL"
622  // while publishing
623  //
624  lock.lock();
625 
626  NODELET_DEBUG_STREAM("start getting data");
627  try
628  {
629  xyz_img = this->im_->XYZImage();
630  confidence_img = this->im_->ConfidenceImage();
631  distance_img = this->im_->DistanceImage();
632  distance_noise_img = this->im_->DistanceNoiseImage();
633  amplitude_img = this->im_->AmplitudeImage();
634  raw_amplitude_img = this->im_->RawAmplitudeImage();
635  gray_img = this->im_->GrayImage();
636  extrinsics = this->im_->Extrinsics();
637  rgb_img = this->im_->JPEGImage();
638  }
639  catch (const ifm3d::error_t& ex)
640  {
641  NODELET_WARN_STREAM(ex.what());
642  }
643  catch (const std::exception& std_ex)
644  {
645  NODELET_WARN_STREAM(std_ex.what());
646  }
647  NODELET_DEBUG_STREAM("finished getting data");
648 
649  lock.unlock();
650 
651  //
652  // Now, do the publishing
653  //
654 
655  NODELET_DEBUG_STREAM("start publishing");
656  // Confidence image is invariant - no need to check the mask
657  this->conf_pub_.publish(ifm3d_to_ros_image(confidence_img, optical_head, getName()));
658  NODELET_DEBUG_STREAM("after publishing confidence image");
659 
660  if ((this->schema_mask_ & ifm3d::IMG_CART) == ifm3d::IMG_CART)
661  {
662  this->cloud_pub_.publish(ifm3d_to_ros_cloud(xyz_img, head, getName()));
663  NODELET_DEBUG_STREAM("after publishing xyz image");
664  }
665 
666  if ((this->schema_mask_ & ifm3d::IMG_RDIS) == ifm3d::IMG_RDIS)
667  {
668  this->distance_pub_.publish(ifm3d_to_ros_image(distance_img, optical_head, getName()));
669  NODELET_DEBUG_STREAM("after publishing distance image");
670  }
671 
672  if ((this->schema_mask_ & ifm3d::IMG_DIS_NOISE) == ifm3d::IMG_DIS_NOISE)
673  {
674  this->distance_noise_pub_.publish(ifm3d_to_ros_image(distance_noise_img, optical_head, getName()));
675  NODELET_DEBUG_STREAM("after publishing distance noise image");
676  }
677 
678  if ((this->schema_mask_ & ifm3d::IMG_AMP) == ifm3d::IMG_AMP)
679  {
680  this->amplitude_pub_.publish(ifm3d_to_ros_image(amplitude_img, optical_head, getName()));
681  NODELET_DEBUG_STREAM("after publishing amplitude image");
682  }
683 
684  if ((this->schema_mask_ & ifm3d::IMG_RAMP) == ifm3d::IMG_RAMP)
685  {
686  this->raw_amplitude_pub_.publish(ifm3d_to_ros_image(raw_amplitude_img, optical_head, getName()));
687  NODELET_DEBUG_STREAM("Raw amplitude image publisher is a dummy publisher - data will be added soon");
688  NODELET_DEBUG_STREAM("after publishing raw amplitude image");
689  }
690 
691  if ((this->schema_mask_ & ifm3d::IMG_GRAY) == ifm3d::IMG_GRAY)
692  {
693  this->gray_image_pub_.publish(ifm3d_to_ros_image(gray_img, optical_head, getName()));
694  NODELET_DEBUG_STREAM("Gray image publisher is a dummy publisher - data will be added soon");
695  NODELET_DEBUG_STREAM("after publishing gray image");
696  }
697 
698  // The 2D is not yet settable in the schema mask: publish all the time
699 
700  if (rgb_img.height() * rgb_img.width() > 0)
701  {
702  this->rgb_image_pub_.publish(ifm3d_to_ros_compressed_image(rgb_img, optical_head, "jpeg", getName()));
703  NODELET_DEBUG_STREAM("after publishing rgb image");
704  }
705 
706  //
707  // publish extrinsics
708  //
709  NODELET_DEBUG_STREAM("start publishing extrinsics");
710  ifm3d_ros_msgs::Extrinsics extrinsics_msg;
711  extrinsics_msg.header = optical_head;
712  try
713  {
714  extrinsics_msg.tx = extrinsics.at(0);
715  extrinsics_msg.ty = extrinsics.at(1);
716  extrinsics_msg.tz = extrinsics.at(2);
717  extrinsics_msg.rot_x = extrinsics.at(3);
718  extrinsics_msg.rot_y = extrinsics.at(4);
719  extrinsics_msg.rot_z = extrinsics.at(5);
720  }
721  catch (const std::out_of_range& ex)
722  {
723  NODELET_WARN("out-of-range error fetching extrinsics");
724  }
725  this->extrinsics_pub_.publish(extrinsics_msg);
726 
727  } // end: while (ros::ok()) { ... }
728 } // end: Run()
729 
#define NODELET_INFO_STREAM(...)
#define NODELET_INFO_ONCE(...)
#define NODELET_WARN(...)
sensor_msgs::CompressedImage ifm3d_to_ros_compressed_image(ifm3d::Image &image, const std_msgs::Header &header, const std::string &format, const std::string &logger)
#define ROS_WARN_NAMED(name,...)
f
bool Dump(ifm3d_ros_msgs::Dump::Request &req, ifm3d_ros_msgs::Dump::Response &res)
ROSCONSOLE_CONSOLE_IMPL_DECL std::string getName(void *handle)
const std::string TYPE_8UC1
#define NODELET_WARN_STREAM(...)
bool Trigger(ifm3d_ros_msgs::Trigger::Request &req, ifm3d_ros_msgs::Trigger::Response &res)
nlohmann::json json
sensor_msgs::Image ifm3d_to_ros_image(ifm3d::Image &image, const std_msgs::Header &header, const std::string &logger)
bool SoftOff(ifm3d_ros_msgs::SoftOff::Request &req, ifm3d_ros_msgs::SoftOff::Response &res)
bool InitStructures(std::uint16_t mask, std::uint16_t pcic_port)
const std::string TYPE_32FC1
sensor_msgs::PointCloud2 ifm3d_to_ros_cloud(ifm3d::Image &image, const std_msgs::Header &header, const std::string &logger)
ROSCPP_DECL bool ok()
bool SoftOn(ifm3d_ros_msgs::SoftOn::Request &req, ifm3d_ros_msgs::SoftOn::Response &res)
const std::string TYPE_16UC1
const std::string TYPE_8SC1
#define NODELET_DEBUG_STREAM(...)
const std::string TYPE_16UC2
const std::string TYPE_64FC1
#define NODELET_INFO(...)
#define ROS_ERROR_NAMED(name,...)
static Time now()
const std::string TYPE_32FC3
static int bitDepth(const std::string &encoding)
bool sleep() const
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
const std::string TYPE_32SC1
bool Config(ifm3d_ros_msgs::Config::Request &req, ifm3d_ros_msgs::Config::Response &res)
const std::string TYPE_16SC1


ifm3d_ros_driver
Author(s): CSR ifm sytron
autogenerated on Tue Feb 21 2023 03:13:25