base_realsense_node.cpp
Go to the documentation of this file.
2 #include "assert.h"
3 #include <boost/algorithm/string.hpp>
4 #include <algorithm>
5 #include <cctype>
6 #include <mutex>
7 
8 #include <dynamic_reconfigure/IntParameter.h>
9 #include <dynamic_reconfigure/Reconfigure.h>
10 #include <dynamic_reconfigure/Config.h>
11 
12 using namespace realsense2_camera;
13 using namespace ddynamic_reconfigure;
14 
15 // stream_index_pair sip{stream_type, stream_index};
16 #define STREAM_NAME(sip) (static_cast<std::ostringstream&&>(std::ostringstream() << _stream_name[sip.first] << ((sip.second>0) ? std::to_string(sip.second) : ""))).str()
17 #define FRAME_ID(sip) (static_cast<std::ostringstream&&>(std::ostringstream() << "camera_" << STREAM_NAME(sip) << "_frame")).str()
18 #define OPTICAL_FRAME_ID(sip) (static_cast<std::ostringstream&&>(std::ostringstream() << "camera_" << STREAM_NAME(sip) << "_optical_frame")).str()
19 #define ALIGNED_DEPTH_TO_FRAME_ID(sip) (static_cast<std::ostringstream&&>(std::ostringstream() << "camera_aligned_depth_to_" << STREAM_NAME(sip) << "_frame")).str()
20 
21 SyncedImuPublisher::SyncedImuPublisher(ros::Publisher imu_publisher, std::size_t waiting_list_size):
22  _publisher(imu_publisher), _pause_mode(false),
23  _waiting_list_size(waiting_list_size)
24  {}
25 
27 {
29 }
30 
32 {
33  std::lock_guard<std::mutex> lock_guard(_mutex);
34  if (_pause_mode)
35  {
37  {
38  throw std::runtime_error("SyncedImuPublisher inner list reached maximum size of " + std::to_string(_pending_messages.size()));
39  }
40  _pending_messages.push(imu_msg);
41  }
42  else
43  {
44  _publisher.publish(imu_msg);
45  // ROS_INFO_STREAM("iid1:" << imu_msg.header.seq << ", time: " << std::setprecision (20) << imu_msg.header.stamp.toSec());
46  }
47  return;
48 }
49 
51 {
52  if (!_is_enabled) return;
53  std::lock_guard<std::mutex> lock_guard(_mutex);
54  _pause_mode = true;
55 }
56 
58 {
59  std::lock_guard<std::mutex> lock_guard(_mutex);
61  _pause_mode = false;
62 }
63 
65 {
66  // ROS_INFO_STREAM("publish imu: " << _pending_messages.size());
67  while (!_pending_messages.empty())
68  {
69  const sensor_msgs::Imu &imu_msg = _pending_messages.front();
70  _publisher.publish(imu_msg);
71  // ROS_INFO_STREAM("iid2:" << imu_msg.header.seq << ", time: " << std::setprecision (20) << imu_msg.header.stamp.toSec());
72  _pending_messages.pop();
73  }
74 }
75 
77 {
78  auto ns = ros::this_node::getNamespace();
79  ns.erase(std::remove(ns.begin(), ns.end(), '/'), ns.end());
80  return ns;
81 }
82 
84  ros::NodeHandle& privateNodeHandle,
85  rs2::device dev,
86  const std::string& serial_no) :
87  _is_running(true), _base_frame_id(""), _node_handle(nodeHandle),
88  _pnh(privateNodeHandle), _dev(dev), _json_file_path(""),
89  _serial_no(serial_no),
90  _is_initialized_time_base(false),
91  _namespace(getNamespaceStr())
92 {
93  // Types for depth stream
95  _image_format[RS2_STREAM_DEPTH] = CV_16UC1; // CVBridge type
97  _unit_step_size[RS2_STREAM_DEPTH] = sizeof(uint16_t); // sensor_msgs::ImagePtr row step size
98  _stream_name[RS2_STREAM_DEPTH] = "depth";
99 
100  // Types for confidence stream
101  _image_format[RS2_STREAM_CONFIDENCE] = CV_8UC1; // CVBridge type
103  _unit_step_size[RS2_STREAM_CONFIDENCE] = sizeof(uint8_t); // sensor_msgs::ImagePtr row step size
104  _stream_name[RS2_STREAM_CONFIDENCE] = "confidence";
105 
106  // Infrared stream
108 
109  _image_format[RS2_STREAM_INFRARED] = CV_8UC1; // CVBridge type
111  _unit_step_size[RS2_STREAM_INFRARED] = sizeof(uint8_t); // sensor_msgs::ImagePtr row step size
113 
114  // Types for color stream
115  _image_format[RS2_STREAM_COLOR] = CV_8UC3; // CVBridge type
117  _unit_step_size[RS2_STREAM_COLOR] = 3; // sensor_msgs::ImagePtr row step size
118  _stream_name[RS2_STREAM_COLOR] = "color";
120 
121  // Types for fisheye stream
122  _image_format[RS2_STREAM_FISHEYE] = CV_8UC1; // CVBridge type
124  _unit_step_size[RS2_STREAM_FISHEYE] = sizeof(uint8_t); // sensor_msgs::ImagePtr row step size
125  _stream_name[RS2_STREAM_FISHEYE] = "fisheye";
126 
127  // Types for Motion-Module streams
128  _stream_name[RS2_STREAM_GYRO] = "gyro";
129 
130  _stream_name[RS2_STREAM_ACCEL] = "accel";
131 
132  _stream_name[RS2_STREAM_POSE] = "pose";
133 
135 }
136 
138 {
139  // Kill dynamic transform thread
140  _is_running = false;
141  _cv_tf.notify_one();
142  if (_tf_t && _tf_t->joinable())
143  _tf_t->join();
144  if (_update_functions_t && _update_functions_t->joinable())
145  _update_functions_t->join();
146 
147  _cv_monitoring.notify_one();
148  if (_monitoring_t && _monitoring_t->joinable())
149  {
150  _monitoring_t->join();
151  }
152 
153  std::set<std::string> module_names;
154  for (const std::pair<stream_index_pair, std::vector<rs2::stream_profile>>& profile : _enabled_profiles)
155  {
156  try
157  {
158  std::string module_name = _sensors[profile.first].get_info(RS2_CAMERA_INFO_NAME);
159  std::pair< std::set<std::string>::iterator, bool> res = module_names.insert(module_name);
160  if (res.second)
161  {
162  _sensors[profile.first].stop();
163  _sensors[profile.first].close();
164  }
165  }
166  catch (const rs2::error& e)
167  {
168  ROS_ERROR_STREAM("Exception: " << e.what());
169  }
170  }
171 }
172 
174 {
175  if(enabled)
176  {
177  std::map<std::string, std::vector<rs2::stream_profile> > profiles;
178  std::map<std::string, rs2::sensor> active_sensors;
179  for (const std::pair<stream_index_pair, std::vector<rs2::stream_profile>>& profile : _enabled_profiles)
180  {
181  std::string module_name = _sensors[profile.first].get_info(RS2_CAMERA_INFO_NAME);
182  ROS_INFO_STREAM("insert " << rs2_stream_to_string(profile.second.begin()->stream_type())
183  << " to " << module_name);
184  profiles[module_name].insert(profiles[module_name].begin(),
185  profile.second.begin(),
186  profile.second.end());
187  active_sensors[module_name] = _sensors[profile.first];
188  }
189 
190  for (const std::pair<std::string, std::vector<rs2::stream_profile> >& sensor_profile : profiles)
191  {
192  std::string module_name = sensor_profile.first;
193  rs2::sensor sensor = active_sensors[module_name];
194  sensor.open(sensor_profile.second);
195  sensor.start(_sensors_callback[module_name]);
196  if (sensor.is<rs2::depth_sensor>())
197  {
199  }
200  }
201  }
202  else
203  {
204  std::set<std::string> module_names;
205  for (const std::pair<stream_index_pair, std::vector<rs2::stream_profile>>& profile : _enabled_profiles)
206  {
207  std::string module_name = _sensors[profile.first].get_info(RS2_CAMERA_INFO_NAME);
208  std::pair< std::set<std::string>::iterator, bool> res = module_names.insert(module_name);
209  if (res.second)
210  {
211  _sensors[profile.first].stop();
212  _sensors[profile.first].close();
213  }
214  }
215  }
216 }
217 
219 {
220  for (auto&& s : _dev.query_sensors())
221  {
222  s.set_notifications_callback([&](const rs2::notification& n)
223  {
224  std::vector<std::string> error_strings({"RT IC2 Config error",
225  "Left IC2 Config error"});
227  {
228  ROS_WARN_STREAM("Hardware Notification:" << n.get_description() << "," << n.get_timestamp() << "," << n.get_severity() << "," << n.get_category());
229  }
230  if (error_strings.end() != std::find_if(error_strings.begin(), error_strings.end(), [&n] (std::string err)
231  {return (n.get_description().find(err) != std::string::npos); }))
232  {
233  ROS_ERROR_STREAM("Performing Hardware Reset.");
235  }
236  });
237  }
238 }
239 
241 {
242  getParameters();
243  setupDevice();
244  setupFilters();
248  enable_devices();
249  setupPublishers();
250  setupStreams();
251  SetBaseStream();
255  startMonitoring();
256  publishServices();
257  ROS_INFO_STREAM("RealSense Node Is Up!");
258 }
259 
261 {
262  if (_is_first_frame[stream_type])
263  {
264  ROS_DEBUG_STREAM("runFirstFrameInitialization: " << _video_functions_stack.size() << ", " << rs2_stream_to_string(stream_type));
265  _is_first_frame[stream_type] = false;
266  if (!_video_functions_stack[stream_type].empty())
267  {
268  std::thread t = std::thread([=]()
269  {
270  while (!_video_functions_stack[stream_type].empty())
271  {
272  _video_functions_stack[stream_type].back()();
273  _video_functions_stack[stream_type].pop_back();
274  }
275  });
276  t.detach();
277  }
278  }
279 }
280 
282 {
283  rs2::option_range op_range = sensor.get_option_range(option);
284  return op_range.max == 1.0f &&
285  op_range.min == 0.0f &&
286  op_range.step == 1.0f;
287 }
288 
290 {
291  static const int MAX_ENUM_OPTION_VALUES(100);
292  static const float EPSILON(0.05);
293 
294  rs2::option_range op_range = sensor.get_option_range(option);
295  if (abs((op_range.step - 1)) > EPSILON || (op_range.max > MAX_ENUM_OPTION_VALUES)) return false;
296  for (auto i = op_range.min; i <= op_range.max; i += op_range.step)
297  {
298  if (sensor.get_option_value_description(option, i) == nullptr)
299  continue;
300  return true;
301  }
302  return false;
303 }
304 
306 {
307  rs2::option_range op_range = sensor.get_option_range(option);
308  return (op_range.step == 1.0);
309 }
310 
311 std::map<std::string, int> get_enum_method(rs2::options sensor, rs2_option option)
312 {
313  std::map<std::string, int> dict; // An enum to set size
314  if (is_enum_option(sensor, option))
315  {
316  rs2::option_range op_range = sensor.get_option_range(option);
317  const auto op_range_min = int(op_range.min);
318  const auto op_range_max = int(op_range.max);
319  const auto op_range_step = int(op_range.step);
320  for (auto val = op_range_min; val <= op_range_max; val += op_range_step)
321  {
322  if (sensor.get_option_value_description(option, val) == nullptr)
323  continue;
324  dict[sensor.get_option_value_description(option, val)] = val;
325  }
326  }
327  return dict;
328 }
329 
330 namespace realsense2_camera
331 {
332 
333 template <typename K, typename V>
334 std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m)
335 {
336  os << '{';
337  for (const auto& kv : m)
338  {
339  os << " {" << kv.first << ": " << kv.second << '}';
340  }
341  os << " }";
342  return os;
343 }
344 
345 }
346 
351 {
352  return std::isalnum(c) || c == '/' || c == '_';
353 }
354 
359 std::string create_graph_resource_name(const std::string &original_name)
360 {
361  std::string fixed_name = original_name;
362  std::transform(fixed_name.begin(), fixed_name.end(), fixed_name.begin(),
363  [](unsigned char c) { return std::tolower(c); });
364  std::replace_if(fixed_name.begin(), fixed_name.end(), [](const char c) { return !isValidCharInName(c); },
365  '_');
366  return fixed_name;
367 }
368 
369 void BaseRealSenseNode::set_auto_exposure_roi(const std::string option_name, rs2::sensor sensor, int new_value)
370 {
372  if (option_name == "left")
373  auto_exposure_roi.min_x = new_value;
374  else if (option_name == "right")
375  auto_exposure_roi.max_x = new_value;
376  else if (option_name == "top")
377  auto_exposure_roi.min_y = new_value;
378  else if (option_name == "bottom")
379  auto_exposure_roi.max_y = new_value;
380  else
381  {
382  ROS_WARN_STREAM("Invalid option_name: " << option_name << " while setting auto exposure ROI.");
383  return;
384  }
386 }
387 
389 {
390  const rs2::region_of_interest& auto_exposure_roi(_auto_exposure_roi[sensor.get_info(RS2_CAMERA_INFO_NAME)]);
391  try
392  {
393  sensor.as<rs2::roi_sensor>().set_region_of_interest(auto_exposure_roi);
394  }
395  catch(const std::runtime_error& e)
396  {
397  ROS_ERROR_STREAM(e.what());
398  }
399 }
400 
401 void BaseRealSenseNode::readAndSetDynamicParam(ros::NodeHandle& nh1, std::shared_ptr<ddynamic_reconfigure::DDynamicReconfigure> ddynrec,
402  const std::string option_name, const int min_val, const int max_val, rs2::sensor sensor,
403  int* option_value)
404 {
405  nh1.param(option_name, *option_value, *option_value); //param (const std::string &param_name, T &param_val, const T &default_val) const
406  if (*option_value < min_val) *option_value = min_val;
407  if (*option_value > max_val) *option_value = max_val;
408 
409  ddynrec->registerVariable<int>(
410  option_name, *option_value, [this, sensor, option_name](int new_value){set_auto_exposure_roi(option_name, sensor, new_value);},
411  "auto-exposure " + option_name + " coordinate", min_val, max_val);
412 }
413 
415 {
416  for (const std::pair<stream_index_pair, std::vector<rs2::stream_profile>>& profile : _enabled_profiles)
417  {
419  std::string module_base_name(sensor.get_info(RS2_CAMERA_INFO_NAME));
420  if (sensor.is<rs2::roi_sensor>() && _auto_exposure_roi.find(module_base_name) == _auto_exposure_roi.end())
421  {
422  int max_x(_width[profile.first]-1);
423  int max_y(_height[profile.first]-1);
424 
425  std::string module_name = create_graph_resource_name(module_base_name) +"/auto_exposure_roi";
426  ros::NodeHandle nh1(nh, module_name);
427  std::shared_ptr<ddynamic_reconfigure::DDynamicReconfigure> ddynrec = std::make_shared<ddynamic_reconfigure::DDynamicReconfigure>(nh1);
428 
429  _auto_exposure_roi[module_base_name] = {0, 0, max_x, max_y};
430  rs2::region_of_interest& auto_exposure_roi(_auto_exposure_roi[module_base_name]);
431  readAndSetDynamicParam(nh1, ddynrec, "left", 0, max_x, sensor, &(auto_exposure_roi.min_x));
432  readAndSetDynamicParam(nh1, ddynrec, "right", 0, max_x, sensor, &(auto_exposure_roi.max_x));
433  readAndSetDynamicParam(nh1, ddynrec, "top", 0, max_y, sensor, &(auto_exposure_roi.min_y));
434  readAndSetDynamicParam(nh1, ddynrec, "bottom", 0, max_y, sensor, &(auto_exposure_roi.max_y));
435 
436  ddynrec->publishServicesTopics();
437  _ddynrec.push_back(ddynrec);
438 
439  // Initiate the call to set_sensor_auto_exposure_roi, after the first frame arrive.
440  rs2_stream stream_type = profile.first.first;
441  _video_functions_stack[stream_type].push_back([this, sensor](){set_sensor_auto_exposure_roi(sensor);});
442  _is_first_frame[stream_type] = true;
443  }
444  }
445 }
446 
447 void BaseRealSenseNode::registerDynamicOption(ros::NodeHandle& nh, rs2::options sensor, std::string& module_name)
448 {
449  ros::NodeHandle nh1(nh, module_name);
450  std::shared_ptr<ddynamic_reconfigure::DDynamicReconfigure> ddynrec = std::make_shared<ddynamic_reconfigure::DDynamicReconfigure>(nh1);
451  for (auto i = 0; i < RS2_OPTION_COUNT; i++)
452  {
453  rs2_option option = static_cast<rs2_option>(i);
454  const std::string option_name(create_graph_resource_name(rs2_option_to_string(option)));
455  try
456  {
457  if (!sensor.supports(option) || sensor.is_option_read_only(option))
458  {
459  continue;
460  }
461  if (is_checkbox(sensor, option))
462  {
463  auto option_value = bool(sensor.get_option(option));
464  if (nh1.param(option_name, option_value, option_value))
465  {
466  sensor.set_option(option, option_value);
467  }
468  ddynrec->registerVariable<bool>(
469  option_name, option_value,
470  [option, sensor](bool new_value) { sensor.set_option(option, new_value); },
471  sensor.get_option_description(option));
472  continue;
473  }
474  const auto enum_dict = get_enum_method(sensor, option);
475  if (enum_dict.empty())
476  {
477  rs2::option_range op_range = sensor.get_option_range(option);
478  const auto sensor_option_value = sensor.get_option(option);
479  auto option_value = sensor_option_value;
480  if (nh1.param(option_name, option_value, option_value))
481  {
482  if (option_value < op_range.min || op_range.max < option_value)
483  {
484  ROS_WARN_STREAM("Param '" << nh1.resolveName(option_name) << "' has value " << option_value
485  << " outside the range [" << op_range.min << ", " << op_range.max
486  << "]. Using current sensor value " << sensor_option_value << " instead.");
487  option_value = sensor_option_value;
488  }
489  else
490  {
491  sensor.set_option(option, option_value);
492  }
493  }
494  if (option_value < op_range.min || op_range.max < option_value)
495  {
496  ROS_WARN_STREAM("Param '" << nh1.resolveName(option_name) << "' has value " << option_value
497  << " that is not in range [" << op_range.min << ", " << op_range.max << "]"
498  << ". Removing this parameter from dynamic reconfigure options.");
499  continue;
500  }
501  if (is_int_option(sensor, option))
502  {
503  ddynrec->registerVariable<int>(
504  option_name, int(option_value),
505  [option, sensor](int new_value) { sensor.set_option(option, new_value); },
506  sensor.get_option_description(option), int(op_range.min), int(op_range.max));
507  }
508  else
509  {
510  if (i == RS2_OPTION_DEPTH_UNITS)
511  {
512  if (ROS_DEPTH_SCALE >= op_range.min && ROS_DEPTH_SCALE <= op_range.max)
513  {
514  sensor.set_option(option, ROS_DEPTH_SCALE);
515  op_range.min = ROS_DEPTH_SCALE;
516  op_range.max = ROS_DEPTH_SCALE;
517 
519  }
520  }
521  else
522  {
523  ddynrec->registerVariable<double>(
524  option_name, option_value,
525  [option, sensor](double new_value) { sensor.set_option(option, new_value); },
526  sensor.get_option_description(option), double(op_range.min), double(op_range.max));
527  }
528  }
529  }
530  else
531  {
532  const auto sensor_option_value = sensor.get_option(option);
533  auto option_value = int(sensor_option_value);
534  if (nh1.param(option_name, option_value, option_value))
535  {
536  if (std::find_if(enum_dict.cbegin(), enum_dict.cend(),
537  [&option_value](const std::pair<std::string, int>& kv) {
538  return kv.second == option_value;
539  }) == enum_dict.cend())
540  {
541  ROS_WARN_STREAM("Param '" << nh1.resolveName(option_name) << "' has value " << option_value
542  << " that is not in the enum " << enum_dict
543  << ". Using current sensor value " << sensor_option_value << " instead.");
544  option_value = sensor_option_value;
545  }
546  else
547  {
548  sensor.set_option(option, option_value);
549  }
550  }
551  if (std::find_if(enum_dict.cbegin(), enum_dict.cend(),
552  [&option_value](const std::pair<std::string, int>& kv) {
553  return kv.second == option_value;
554  }) == enum_dict.cend())
555  {
556  ROS_WARN_STREAM("Param '" << nh1.resolveName(option_name) << "' has value " << option_value
557  << " that is not in the enum " << enum_dict
558  << ". Removing this parameter from dynamic reconfigure options.");
559  continue;
560  }
561  if (module_name == "stereo_module" && i == RS2_OPTION_SEQUENCE_ID)
562  {
563  ddynrec->registerEnumVariable<int>(
564  option_name, option_value,
565  [this, option, sensor, module_name](int new_value)
566  {
567  sensor.set_option(option, new_value);
568  _update_functions_v.push_back([this, module_name, sensor]()
569  {set_sensor_parameter_to_ros(module_name, sensor, RS2_OPTION_EXPOSURE);});
570  _update_functions_v.push_back([this, module_name, sensor]()
571  {set_sensor_parameter_to_ros(module_name, sensor, RS2_OPTION_GAIN);});
572  _update_functions_cv.notify_one();
573  },
574  sensor.get_option_description(option), enum_dict);
575  }
576  else
577  {
578  ddynrec->registerEnumVariable<int>(
579  option_name, option_value,
580  [option, sensor](int new_value) { sensor.set_option(option, new_value); },
581  sensor.get_option_description(option), enum_dict);
582  }
583  }
584  }
585  catch(const rs2::backend_error& e)
586  {
587  ROS_WARN_STREAM("Failed to set option: " << option_name << ": " << e.what());
588  }
589  catch(const std::exception& e)
590  {
591  std::cerr << e.what() << '\n';
592  }
593 
594  }
595  ddynrec->publishServicesTopics();
596  _ddynrec.push_back(ddynrec);
597 }
598 
600 {
601  ROS_INFO("Setting Dynamic reconfig parameters.");
602 
604  {
605  std::string module_name = create_graph_resource_name(sensor.get_info(RS2_CAMERA_INFO_NAME));
606  ROS_DEBUG_STREAM("module_name:" << module_name);
607  registerDynamicOption(nh, sensor, module_name);
608  }
609 
610  for (NamedFilter nfilter : _filters)
611  {
612  std::string module_name = nfilter._name;
613  auto sensor = *(nfilter._filter);
614  ROS_DEBUG_STREAM("module_name:" << module_name);
615  registerDynamicOption(nh, sensor, module_name);
616  }
617  ROS_INFO("Done Setting Dynamic reconfig parameters.");
618 }
619 
621 {
622  if (std::find_if(std::begin(_filters), std::end(_filters), [](NamedFilter f){return f._name == "hdr_merge";}) == std::end(_filters))
623  return;
624 
625  std::string module_name;
626  std::vector<rs2_option> options{RS2_OPTION_EXPOSURE, RS2_OPTION_GAIN};
628  {
629  if (!sensor.is<rs2::depth_sensor>()) continue;
630  std::string module_name = create_graph_resource_name(sensor.get_info(RS2_CAMERA_INFO_NAME));
631  // Read initialization parameters and initialize hdr_merge filter:
632  unsigned int seq_size = sensor.get_option(RS2_OPTION_SEQUENCE_SIZE);
633  for (unsigned int seq_id = 1; seq_id <= seq_size; seq_id++ )
634  {
635  sensor.set_option(RS2_OPTION_SEQUENCE_ID, seq_id);
636  for (rs2_option& option : options)
637  {
638  std::stringstream param_name_str;
639  param_name_str << module_name << "/" << create_graph_resource_name(rs2_option_to_string(option)) << "/" << seq_id;
640  std::string param_name(param_name_str.str());
641  ROS_INFO_STREAM("Reading option: " << param_name);
642  int option_value = sensor.get_option(option);
643 
644  int user_set_option_value;
645  _pnh.param(param_name, user_set_option_value, option_value);
646  _pnh.deleteParam(param_name);
647  if (option_value != user_set_option_value)
648  {
649  ROS_INFO_STREAM("Set " << rs2_option_to_string(option) << " to " << user_set_option_value);
650  sensor.set_option(option, user_set_option_value);
651  }
652  }
653  }
654  sensor.set_option(RS2_OPTION_SEQUENCE_ID, 0); // Set back to default.
655  sensor.set_option(RS2_OPTION_HDR_ENABLED, true);
656 
657  monitor_update_functions(); // Start parameters update thread
658 
659  break;
660  }
661 }
662 
664 {
665  dynamic_reconfigure::ReconfigureRequest srv_req;
666  dynamic_reconfigure::ReconfigureResponse srv_resp;
667  dynamic_reconfigure::IntParameter int_param;
668  dynamic_reconfigure::Config conf;
669 
670  int_param.name = create_graph_resource_name(rs2_option_to_string(option)); //"sequence_id"
671  int_param.value = sensor.get_option(option);
672  conf.ints.push_back(int_param);
673 
674  srv_req.config = conf;
675 
676  std::string service_name = module_name + "/set_parameters";
677  if (ros::service::call(service_name, srv_req, srv_resp)) {
678  ROS_INFO_STREAM( "call to set " << service_name << "/" << int_param.name << " to " << int_param.value << " succeeded");
679  } else {
680  ROS_ERROR_STREAM( "call to set " << service_name << "/" << int_param.name << " to " << int_param.value << " failed");
681  }
682 }
683 
685 {
686  int time_interval(1000);
687  std::function<void()> func = [this, time_interval](){
688  std::mutex mu;
689  std::unique_lock<std::mutex> lock(mu);
690  while(_is_running) {
691  _update_functions_cv.wait_for(lock, std::chrono::milliseconds(time_interval), [&]{return !_is_running || !_update_functions_v.empty();});
692  while (!_update_functions_v.empty())
693  {
694  _update_functions_v.back()();
695  _update_functions_v.pop_back();
696  }
697  }
698  };
699  _update_functions_t = std::make_shared<std::thread>(func);
700 }
701 
703 {
704  if (str == "RS2_STREAM_ANY")
705  return RS2_STREAM_ANY;
706  if (str == "RS2_STREAM_COLOR")
707  return RS2_STREAM_COLOR;
708  if (str == "RS2_STREAM_INFRARED")
709  return RS2_STREAM_INFRARED;
710  if (str == "RS2_STREAM_FISHEYE")
711  return RS2_STREAM_FISHEYE;
712  throw std::runtime_error("Unknown stream string " + str);
713 }
714 
716 {
717  ROS_INFO("getParameters...");
718 
719  // Setup system to use RGB image from the infra stream if configured by user
720  bool infra_rgb;
721  _pnh.param("infra_rgb", infra_rgb, false);
722  if (infra_rgb)
723  {
725  _image_format[RS2_STREAM_INFRARED] = CV_8UC3; // CVBridge type
727  _unit_step_size[RS2_STREAM_INFRARED] = 3 * sizeof(uint8_t); // sensor_msgs::ImagePtr row step size
728  ROS_INFO_STREAM("Infrared RGB stream enabled");
729  }
730 
731  _pnh.param("align_depth", _align_depth, ALIGN_DEPTH);
732  _pnh.param("enable_pointcloud", _pointcloud, POINTCLOUD);
733  std::string pc_texture_stream("");
734  int pc_texture_idx;
735  _pnh.param("pointcloud_texture_stream", pc_texture_stream, std::string("RS2_STREAM_COLOR"));
736  _pnh.param("pointcloud_texture_index", pc_texture_idx, 0);
737  _pointcloud_texture = stream_index_pair{rs2_string_to_stream(pc_texture_stream), pc_texture_idx};
738 
739  _pnh.param("filters", _filters_str, DEFAULT_FILTERS);
740  _pointcloud |= (_filters_str.find("pointcloud") != std::string::npos);
741 
742  _pnh.param("publish_tf", _publish_tf, PUBLISH_TF);
743  _pnh.param("tf_publish_rate", _tf_publish_rate, TF_PUBLISH_RATE);
744 
745  _pnh.param("enable_sync", _sync_frames, SYNC_FRAMES);
746  if (_pointcloud || _align_depth || _filters_str.size() > 0)
747  _sync_frames = true;
748 
749  _pnh.param("json_file_path", _json_file_path, std::string(""));
750 
751  for (auto& stream : IMAGE_STREAMS)
752  {
753  std::string param_name(_stream_name[stream.first] + "_width");
754  _pnh.param(param_name, _width[stream], IMAGE_WIDTH);
755  ROS_DEBUG_STREAM("parameter:" << param_name << " = " << _width[stream]);
756  param_name = _stream_name[stream.first] + "_height";
757  _pnh.param(param_name, _height[stream], IMAGE_HEIGHT);
758  ROS_DEBUG_STREAM("parameter:" << param_name << " = " << _height[stream]);
759  param_name = _stream_name[stream.first] + "_fps";
760  _pnh.param(param_name, _fps[stream], IMAGE_FPS);
761  ROS_DEBUG_STREAM("parameter:" << param_name << " = " << _fps[stream]);
762  param_name = "enable_" + STREAM_NAME(stream);
763  _pnh.param(param_name, _enable[stream], true);
764  ROS_DEBUG_STREAM("parameter:" << param_name << " = " << _enable[stream]);
765  }
766 
767  for (auto& stream : HID_STREAMS)
768  {
769  std::string param_name(_stream_name[stream.first] + "_fps");
770  ROS_DEBUG_STREAM("reading parameter:" << param_name);
771  _pnh.param(param_name, _fps[stream], IMU_FPS);
772  param_name = "enable_" + STREAM_NAME(stream);
773  _pnh.param(param_name, _enable[stream], ENABLE_IMU);
774  ROS_DEBUG_STREAM("_enable[" << _stream_name[stream.first] << "]:" << _enable[stream]);
775  }
776  _pnh.param("base_frame_id", _base_frame_id, DEFAULT_BASE_FRAME_ID);
777  _pnh.param("odom_frame_id", _odom_frame_id, DEFAULT_ODOM_FRAME_ID);
778 
779  std::vector<stream_index_pair> streams(IMAGE_STREAMS);
780  streams.insert(streams.end(), HID_STREAMS.begin(), HID_STREAMS.end());
781  for (auto& stream : streams)
782  {
783  std::string param_name(static_cast<std::ostringstream&&>(std::ostringstream() << STREAM_NAME(stream) << "_frame_id").str());
784  _pnh.param(param_name, _frame_id[stream], FRAME_ID(stream));
785  ROS_DEBUG_STREAM("frame_id: reading parameter:" << param_name << " : " << _frame_id[stream]);
786  param_name = static_cast<std::ostringstream&&>(std::ostringstream() << STREAM_NAME(stream) << "_optical_frame_id").str();
787  _pnh.param(param_name, _optical_frame_id[stream], OPTICAL_FRAME_ID(stream));
788  ROS_DEBUG_STREAM("optical: reading parameter:" << param_name << " : " << _optical_frame_id[stream]);
789  }
790 
791  std::string unite_imu_method_str("");
792  _pnh.param("unite_imu_method", unite_imu_method_str, DEFAULT_UNITE_IMU_METHOD);
793  if (unite_imu_method_str == "linear_interpolation")
794  _imu_sync_method = imu_sync_method::LINEAR_INTERPOLATION;
795  else if (unite_imu_method_str == "copy")
796  _imu_sync_method = imu_sync_method::COPY;
797  else
798  _imu_sync_method = imu_sync_method::NONE;
799 
800  if (_imu_sync_method > imu_sync_method::NONE)
801  {
802  _pnh.param("imu_optical_frame_id", _optical_frame_id[GYRO], DEFAULT_IMU_OPTICAL_FRAME_ID);
803  }
804 
805  {
807  std::string param_name(static_cast<std::ostringstream&&>(std::ostringstream() << "aligned_depth_to_" << STREAM_NAME(stream) << "_frame_id").str());
808  _pnh.param(param_name, _depth_aligned_frame_id[stream], ALIGNED_DEPTH_TO_FRAME_ID(stream));
809  }
810 
811  _pnh.param("allow_no_texture_points", _allow_no_texture_points, ALLOW_NO_TEXTURE_POINTS);
812  _pnh.param("ordered_pc", _ordered_pc, ORDERED_POINTCLOUD);
813  _pnh.param("clip_distance", _clipping_distance, static_cast<float>(-1.0));
814  _pnh.param("linear_accel_cov", _linear_accel_cov, static_cast<double>(0.01));
815  _pnh.param("angular_velocity_cov", _angular_velocity_cov, static_cast<double>(0.01));
816  _pnh.param("hold_back_imu_for_frames", _hold_back_imu_for_frames, HOLD_BACK_IMU_FOR_FRAMES);
817  _pnh.param("publish_odom_tf", _publish_odom_tf, PUBLISH_ODOM_TF);
818 }
819 
821 {
822  ROS_INFO("setupDevice...");
823  try{
824  if (!_json_file_path.empty())
825  {
827  {
828  std::stringstream ss;
829  std::ifstream in(_json_file_path);
830  if (in.is_open())
831  {
832  ss << in.rdbuf();
833  std::string json_file_content = ss.str();
834 
835  auto adv = _dev.as<rs2::serializable_device>();
836  adv.load_json(json_file_content);
837  ROS_INFO_STREAM("JSON file is loaded! (" << _json_file_path << ")");
838  }
839  else
840  ROS_WARN_STREAM("JSON file provided doesn't exist! (" << _json_file_path << ")");
841  }
842  else
843  ROS_WARN("Device does not support advanced settings!");
844  }
845  else
846  ROS_INFO("JSON file is not provided");
847 
848  ROS_INFO_STREAM("ROS Node Namespace: " << _namespace);
849 
850  auto camera_name = _dev.get_info(RS2_CAMERA_INFO_NAME);
851  ROS_INFO_STREAM("Device Name: " << camera_name);
852 
853  ROS_INFO_STREAM("Device Serial No: " << _serial_no);
854 
855  auto camera_id = _dev.get_info(RS2_CAMERA_INFO_PHYSICAL_PORT);
856 
857  ROS_INFO_STREAM("Device physical port: " << camera_id);
858 
860  ROS_INFO_STREAM("Device FW version: " << fw_ver);
861 
863  ROS_INFO_STREAM("Device Product ID: 0x" << pid);
864 
865  ROS_INFO_STREAM("Enable PointCloud: " << ((_pointcloud)?"On":"Off"));
866  ROS_INFO_STREAM("Align Depth: " << ((_align_depth)?"On":"Off"));
867  ROS_INFO_STREAM("Sync Mode: " << ((_sync_frames)?"On":"Off"));
868 
870 
871 
872  std::function<void(rs2::frame)> frame_callback_function, imu_callback_function;
873  if (_sync_frames)
874  {
875  frame_callback_function = _syncer;
876 
877  auto frame_callback_inner = [this](rs2::frame frame){
878  frame_callback(frame);
879  };
880  _syncer.start(frame_callback_inner);
881  }
882  else
883  {
884  frame_callback_function = [this](rs2::frame frame){frame_callback(frame);};
885  }
886 
887  if (_imu_sync_method == imu_sync_method::NONE)
888  {
889  imu_callback_function = [this](rs2::frame frame){imu_callback(frame);};
890  }
891  else
892  {
893  imu_callback_function = [this](rs2::frame frame){imu_callback_sync(frame, _imu_sync_method);};
894  }
895  std::function<void(rs2::frame)> multiple_message_callback_function = [this](rs2::frame frame){multiple_message_callback(frame, _imu_sync_method);};
896 
897  ROS_INFO_STREAM("Device Sensors: ");
898  for(auto&& sensor : _dev_sensors)
899  {
900  for (auto& profile : sensor.get_stream_profiles())
901  {
902  auto video_profile = profile.as<rs2::video_stream_profile>();
903  stream_index_pair sip(video_profile.stream_type(), video_profile.stream_index());
904  if (_sensors.find( sip ) != _sensors.end())
905  continue;
906  _sensors[sip] = sensor;
907  }
908 
909  std::string module_name = sensor.get_info(RS2_CAMERA_INFO_NAME);
910  if (sensor.is<rs2::depth_sensor>())
911  {
912  _sensors_callback[module_name] = frame_callback_function;
913  }
914  else if (sensor.is<rs2::color_sensor>())
915  {
916  _sensors_callback[module_name] = frame_callback_function;
917  }
918  else if (sensor.is<rs2::fisheye_sensor>())
919  {
920  _sensors_callback[module_name] = frame_callback_function;
921  }
922  else if (sensor.is<rs2::motion_sensor>())
923  {
924  _sensors_callback[module_name] = imu_callback_function;
925  }
926  else if (sensor.is<rs2::pose_sensor>())
927  {
928  _sensors_callback[module_name] = multiple_message_callback_function;
929  }
930  else
931  {
932  ROS_ERROR_STREAM("Module Name \"" << module_name << "\" isn't supported by LibRealSense! Terminating RealSense Node...");
933  ros::shutdown();
934  exit(1);
935  }
936  ROS_INFO_STREAM(module_name << " was found.");
937  }
938 
939  // Update "enable" map
940  for (std::pair<stream_index_pair, bool> const& enable : _enable )
941  {
942  const stream_index_pair& stream_index(enable.first);
943  if (enable.second && _sensors.find(stream_index) == _sensors.end())
944  {
945  ROS_INFO_STREAM("(" << rs2_stream_to_string(stream_index.first) << ", " << stream_index.second << ") sensor isn't supported by current device! -- Skipping...");
946  _enable[enable.first] = false;
947  }
948  }
949  }
950  catch(const std::exception& ex)
951  {
952  ROS_ERROR_STREAM("An exception has been thrown: " << ex.what());
953  throw;
954  }
955  catch(...)
956  {
957  ROS_ERROR_STREAM("Unknown exception has occured!");
958  throw;
959  }
960 }
961 
963 {
964  ROS_INFO("setupPublishers...");
966 
967  for (auto& stream : IMAGE_STREAMS)
968  {
969  if (_enable[stream])
970  {
971  std::stringstream image_raw, camera_info, topic_metadata;
972  bool rectified_image = false;
973  if (stream == DEPTH || stream == CONFIDENCE || stream == INFRA1 || stream == INFRA2)
974  rectified_image = true;
975 
976  std::string stream_name(STREAM_NAME(stream));
977  image_raw << stream_name << "/image_" << ((rectified_image)?"rect_":"") << "raw";
978  camera_info << stream_name << "/camera_info";
979  topic_metadata << stream_name << "/metadata";
980 
981  std::shared_ptr<FrequencyDiagnostics> frequency_diagnostics(new FrequencyDiagnostics(_fps[stream], stream_name, _serial_no));
982  _image_publishers[stream] = {image_transport.advertise(image_raw.str(), 1), frequency_diagnostics};
983  _info_publisher[stream] = _node_handle.advertise<sensor_msgs::CameraInfo>(camera_info.str(), 1);
984  _metadata_publishers[stream] = std::make_shared<ros::Publisher>(_node_handle.advertise<realsense2_camera::Metadata>(topic_metadata.str(), 1));
985 
986  if (_align_depth && stream == COLOR)
987  {
988  std::stringstream aligned_image_raw, aligned_camera_info;
989  aligned_image_raw << "aligned_depth_to_" << stream_name << "/image_raw";
990  aligned_camera_info << "aligned_depth_to_" << stream_name << "/camera_info";
991 
992  std::string aligned_stream_name = "aligned_depth_to_" + stream_name;
993  std::shared_ptr<FrequencyDiagnostics> frequency_diagnostics(new FrequencyDiagnostics(_fps[stream], aligned_stream_name, _serial_no));
994  _depth_aligned_image_publishers[stream] = {image_transport.advertise(aligned_image_raw.str(), 1), frequency_diagnostics};
995  _depth_aligned_info_publisher[stream] = _node_handle.advertise<sensor_msgs::CameraInfo>(aligned_camera_info.str(), 1);
996  }
997 
998  if (stream == DEPTH && _pointcloud)
999  {
1001  }
1002  }
1003  }
1004 
1005  _synced_imu_publisher = std::make_shared<SyncedImuPublisher>();
1006  if (_imu_sync_method > imu_sync_method::NONE && _enable[GYRO] && _enable[ACCEL])
1007  {
1008  ROS_INFO("Start publisher IMU");
1009  _synced_imu_publisher = std::make_shared<SyncedImuPublisher>(_node_handle.advertise<sensor_msgs::Imu>("imu", 5));
1010  _synced_imu_publisher->Enable(_hold_back_imu_for_frames);
1011  }
1012  else
1013  {
1014  if (_enable[GYRO])
1015  {
1017  _metadata_publishers[GYRO] = std::make_shared<ros::Publisher>(_node_handle.advertise<realsense2_camera::Metadata>("gyro/metadata", 1));
1018  }
1019 
1020  if (_enable[ACCEL])
1021  {
1022  _imu_publishers[ACCEL] = _node_handle.advertise<sensor_msgs::Imu>("accel/sample", 100);
1023  _metadata_publishers[ACCEL] = std::make_shared<ros::Publisher>(_node_handle.advertise<realsense2_camera::Metadata>("accel/metadata", 1));
1024  }
1025  }
1026  if (_enable[POSE])
1027  {
1028  _imu_publishers[POSE] = _node_handle.advertise<nav_msgs::Odometry>("odom/sample", 100);
1029  _metadata_publishers[POSE] = std::make_shared<ros::Publisher>(_node_handle.advertise<realsense2_camera::Metadata>("odom/metadata", 1));
1030  }
1031 
1032 
1033  if (_enable[FISHEYE] &&
1034  _enable[DEPTH])
1035  {
1036  _depth_to_other_extrinsics_publishers[FISHEYE] = _node_handle.advertise<Extrinsics>("extrinsics/depth_to_fisheye", 1, true);
1037  }
1038 
1039  if (_enable[COLOR] &&
1040  _enable[DEPTH])
1041  {
1042  _depth_to_other_extrinsics_publishers[COLOR] = _node_handle.advertise<Extrinsics>("extrinsics/depth_to_color", 1, true);
1043  }
1044 
1045  if (_enable[INFRA1] &&
1046  _enable[DEPTH])
1047  {
1048  _depth_to_other_extrinsics_publishers[INFRA1] = _node_handle.advertise<Extrinsics>("extrinsics/depth_to_infra1", 1, true);
1049  }
1050 
1051  if (_enable[INFRA2] &&
1052  _enable[DEPTH])
1053  {
1054  _depth_to_other_extrinsics_publishers[INFRA2] = _node_handle.advertise<Extrinsics>("extrinsics/depth_to_infra2", 1, true);
1055  }
1056 }
1057 
1059 {
1060  for (auto& elem : IMAGE_STREAMS)
1061  {
1062  if (_enable[elem])
1063  {
1064  auto& sens = _sensors[elem];
1065  auto profiles = sens.get_stream_profiles();
1066  rs2::stream_profile default_profile, selected_profile;
1067  for (auto& profile : profiles)
1068  {
1069  auto video_profile = profile.as<rs2::video_stream_profile>();
1070  ROS_DEBUG_STREAM("Sensor profile: " <<
1071  "stream_type: " << rs2_stream_to_string(video_profile.stream_type()) << "(" << video_profile.stream_index() << ")" <<
1072  "Format: " << video_profile.format() <<
1073  ", Width: " << video_profile.width() <<
1074  ", Height: " << video_profile.height() <<
1075  ", FPS: " << video_profile.fps());
1076 
1077  if (profile.stream_type() == elem.first && profile.stream_index() == elem.second)
1078  {
1079  if (profile.is_default())
1080  {
1081  default_profile = profile;
1082  }
1083  if ((_width[elem] == 0 || video_profile.width() == _width[elem]) &&
1084  (_height[elem] == 0 || video_profile.height() == _height[elem]) &&
1085  (_fps[elem] == 0 || video_profile.fps() == _fps[elem]) &&
1086  (_format.find(elem.first) == _format.end() || video_profile.format() == _format[elem.first] ))
1087  {
1088  selected_profile = profile;
1089  break;
1090  }
1091  }
1092 
1093  }
1094  if (!selected_profile)
1095  {
1096  ROS_WARN_STREAM_COND((_width[elem]!=-1 || _height[elem]!=-1 || _fps[elem]!=-1), "Given stream configuration is not supported by the device! " <<
1097  " Stream: " << rs2_stream_to_string(elem.first) <<
1098  ", Stream Index: " << elem.second <<
1099  ", Width: " << _width[elem] <<
1100  ", Height: " << _height[elem] <<
1101  ", FPS: " << _fps[elem] <<
1102  ", Format: " << ((_format.find(elem.first) == _format.end())? "None":rs2_format_to_string(rs2_format(_format[elem.first]))));
1103  if (default_profile)
1104  {
1105  ROS_WARN_STREAM_COND((_width[elem]!=-1 || _height[elem]!=-1 || _fps[elem]!=-1), "Using default profile instead.");
1106  selected_profile = default_profile;
1107  }
1108  }
1109  if (selected_profile)
1110  {
1111  auto video_profile = selected_profile.as<rs2::video_stream_profile>();
1112  _width[elem] = video_profile.width();
1113  _height[elem] = video_profile.height();
1114  _fps[elem] = video_profile.fps();
1115  _enabled_profiles[elem].push_back(selected_profile);
1116  _image[elem] = cv::Mat(_height[elem], _width[elem], _image_format[elem.first], cv::Scalar(0, 0, 0));
1117  ROS_INFO_STREAM(STREAM_NAME(elem) << " stream is enabled - width: " << _width[elem] << ", height: " << _height[elem] << ", fps: " << _fps[elem] << ", " << "Format: " << video_profile.format());
1118  }
1119  else
1120  {
1121  _enable[elem] = false;
1122  }
1123  }
1124  }
1125  if (_align_depth)
1126  {
1127  for (auto& profiles : _enabled_profiles)
1128  {
1129  _depth_aligned_image[profiles.first] = cv::Mat(_height[DEPTH], _width[DEPTH], _image_format[DEPTH.first], cv::Scalar(0, 0, 0));
1130  _depth_scaled_image[profiles.first] = cv::Mat(_height[DEPTH], _width[DEPTH], _image_format[DEPTH.first], cv::Scalar(0, 0, 0));
1131  }
1132  }
1133 
1134  // Streaming HID
1135  for (auto& elem : HID_STREAMS)
1136  {
1137  if (_enable[elem])
1138  {
1139  auto& sens = _sensors[elem];
1140  auto profiles = sens.get_stream_profiles();
1141  rs2::stream_profile default_profile, selected_profile;
1142  ROS_DEBUG_STREAM("Available profiles:");
1144  {
1145  ROS_DEBUG_STREAM("type:" << rs2_stream_to_string(profile.stream_type()) <<
1146  " fps: " << profile.fps() << ". format: " << profile.format());
1147  }
1148  for (rs2::stream_profile& profile : profiles)
1149  {
1150  if (profile.stream_type() == elem.first)
1151  {
1152  if (profile.is_default())
1153  default_profile = profile;
1154  if (_fps[elem] == 0 || profile.fps() == _fps[elem])
1155  {
1156  selected_profile = profile;
1157  break;
1158  }
1159  }
1160  }
1161  if (!selected_profile)
1162  {
1163  std::string stream_name(STREAM_NAME(elem));
1164  ROS_WARN_STREAM_COND((_fps[elem]!=-1), "No mathcing profile found for " << stream_name << " with fps=" << _fps[elem]);
1165  if (default_profile)
1166  {
1167  ROS_WARN_STREAM_COND((_fps[elem]!=-1), "Using default profile instead.");
1168  selected_profile = default_profile;
1169  }
1170  }
1171  if(selected_profile)
1172  {
1173  _fps[elem] = selected_profile.fps();
1174  _enabled_profiles[elem].push_back(selected_profile);
1175  ROS_INFO_STREAM(STREAM_NAME(elem) << " stream is enabled - fps: " << _fps[elem]);
1176  }
1177  else
1178  {
1179  _enable[elem] = false;
1180  }
1181  }
1182  }
1183 }
1184 
1186 {
1187  std::vector<std::string> filters_str;
1188  boost::split(filters_str, _filters_str, [](char c){return c == ',';});
1189  bool use_disparity_filter(false);
1190  bool use_colorizer_filter(false);
1191  bool use_decimation_filter(false);
1192  bool use_hdr_filter(false);
1193  for (std::vector<std::string>::iterator s_iter=filters_str.begin(); s_iter!=filters_str.end(); s_iter++)
1194  {
1195  (*s_iter).erase(std::remove_if((*s_iter).begin(), (*s_iter).end(), isspace), (*s_iter).end()); // Remove spaces
1196 
1197  if ((*s_iter) == "colorizer")
1198  {
1199  use_colorizer_filter = true;
1200  }
1201  else if ((*s_iter) == "disparity")
1202  {
1203  use_disparity_filter = true;
1204  }
1205  else if ((*s_iter) == "spatial")
1206  {
1207  ROS_INFO("Add Filter: spatial");
1208  _filters.push_back(NamedFilter("spatial", std::make_shared<rs2::spatial_filter>()));
1209  }
1210  else if ((*s_iter) == "temporal")
1211  {
1212  ROS_INFO("Add Filter: temporal");
1213  _filters.push_back(NamedFilter("temporal", std::make_shared<rs2::temporal_filter>()));
1214  }
1215  else if ((*s_iter) == "hole_filling")
1216  {
1217  ROS_INFO("Add Filter: hole_filling");
1218  _filters.push_back(NamedFilter("hole_filling", std::make_shared<rs2::hole_filling_filter>()));
1219  }
1220  else if ((*s_iter) == "decimation")
1221  {
1222  use_decimation_filter = true;
1223  }
1224  else if ((*s_iter) == "pointcloud")
1225  {
1226  assert(_pointcloud); // For now, it is set in getParameters()..
1227  }
1228  else if ((*s_iter) == "hdr_merge")
1229  {
1230  use_hdr_filter = true;
1231  }
1232  else if ((*s_iter).size() > 0)
1233  {
1234  ROS_ERROR_STREAM("Unknown Filter: " << (*s_iter));
1235  throw;
1236  }
1237  }
1238  if (use_disparity_filter)
1239  {
1240  ROS_INFO("Add Filter: disparity");
1241  _filters.insert(_filters.begin(), NamedFilter("disparity_start", std::make_shared<rs2::disparity_transform>()));
1242  _filters.push_back(NamedFilter("disparity_end", std::make_shared<rs2::disparity_transform>(false)));
1243  ROS_INFO("Done Add Filter: disparity");
1244  }
1245  if (use_hdr_filter)
1246  {
1247  ROS_INFO("Add Filter: hdr_merge");
1248  _filters.insert(_filters.begin(),NamedFilter("hdr_merge", std::make_shared<rs2::hdr_merge>()));
1249  ROS_INFO("Add Filter: sequence_id_filter");
1250  _filters.insert(_filters.begin(),NamedFilter("sequence_id_filter", std::make_shared<rs2::sequence_id_filter>()));
1251  }
1252  if (use_decimation_filter)
1253  {
1254  ROS_INFO("Add Filter: decimation");
1255  _filters.insert(_filters.begin(),NamedFilter("decimation", std::make_shared<rs2::decimation_filter>()));
1256  }
1257  if (_align_depth)
1258  {
1259  _filters.push_back(NamedFilter("align_to_color", std::make_shared<rs2::align>(RS2_STREAM_COLOR)));
1260  }
1261  if (use_colorizer_filter)
1262  {
1263  ROS_INFO("Add Filter: colorizer");
1264  _colorizer = std::make_shared<rs2::colorizer>();
1265  _filters.push_back(NamedFilter("colorizer", _colorizer));
1266  // Types for depth stream
1267  _image_format[DEPTH.first] = _image_format[COLOR.first]; // CVBridge type
1268  _encoding[DEPTH.first] = _encoding[COLOR.first]; // ROS message type
1269  _unit_step_size[DEPTH.first] = _unit_step_size[COLOR.first]; // sensor_msgs::ImagePtr row step size
1270  _depth_aligned_encoding[RS2_STREAM_COLOR] = _encoding[COLOR.first]; // ROS message type
1271 
1272  _width[DEPTH] = _width[COLOR];
1273  _height[DEPTH] = _height[COLOR];
1274  _image[DEPTH] = cv::Mat(std::max(0, _height[DEPTH]), std::max(0, _width[DEPTH]), _image_format[DEPTH.first], cv::Scalar(0, 0, 0));
1275  }
1276  if (_pointcloud)
1277  {
1278  ROS_INFO("Add Filter: pointcloud");
1279  _pointcloud_filter = std::make_shared<rs2::pointcloud>(_pointcloud_texture.first, _pointcloud_texture.second);
1280  _filters.push_back(NamedFilter("pointcloud", _pointcloud_filter));
1281  }
1282  ROS_INFO("num_filters: %d", static_cast<int>(_filters.size()));
1283 }
1284 
1285 cv::Mat& BaseRealSenseNode::fix_depth_scale(const cv::Mat& from_image, cv::Mat& to_image)
1286 {
1287  static const float meter_to_mm = 0.001f;
1288  if (fabs(_depth_scale_meters - meter_to_mm) < 1e-6)
1289  {
1290  to_image = from_image;
1291  return to_image;
1292  }
1293 
1294  if (to_image.size() != from_image.size())
1295  {
1296  to_image.create(from_image.rows, from_image.cols, from_image.type());
1297  }
1298 
1299  CV_Assert(from_image.depth() == _image_format[RS2_STREAM_DEPTH]);
1300 
1301  int nRows = from_image.rows;
1302  int nCols = from_image.cols;
1303 
1304  if (from_image.isContinuous())
1305  {
1306  nCols *= nRows;
1307  nRows = 1;
1308  }
1309 
1310  int i,j;
1311  const uint16_t* p_from;
1312  uint16_t* p_to;
1313  for( i = 0; i < nRows; ++i)
1314  {
1315  p_from = from_image.ptr<uint16_t>(i);
1316  p_to = to_image.ptr<uint16_t>(i);
1317  for ( j = 0; j < nCols; ++j)
1318  {
1319  p_to[j] = p_from[j] * _depth_scale_meters / meter_to_mm;
1320  }
1321  }
1322  return to_image;
1323 }
1324 
1325 void BaseRealSenseNode::clip_depth(rs2::depth_frame depth_frame, float clipping_dist)
1326 {
1327  uint16_t* p_depth_frame = reinterpret_cast<uint16_t*>(const_cast<void*>(depth_frame.get_data()));
1328  uint16_t clipping_value = static_cast<uint16_t>(clipping_dist / _depth_scale_meters);
1329 
1330  int width = depth_frame.get_width();
1331  int height = depth_frame.get_height();
1332 
1333  #ifdef _OPENMP
1334  #pragma omp parallel for schedule(dynamic) //Using OpenMP to try to parallelise the loop
1335  #endif
1336  for (int y = 0; y < height; y++)
1337  {
1338  auto depth_pixel_index = y * width;
1339  for (int x = 0; x < width; x++, ++depth_pixel_index)
1340  {
1341  // Check if the depth value is greater than the threashold
1342  if (p_depth_frame[depth_pixel_index] > clipping_value)
1343  {
1344  p_depth_frame[depth_pixel_index] = 0; //Set to invalid (<=0) value.
1345  }
1346  }
1347  }
1348 }
1349 
1351 {
1352  sensor_msgs::Imu imu_msg;
1353  ros::Time t(gyro_data.m_time);
1354  imu_msg.header.seq = 0;
1355  imu_msg.header.stamp = t;
1356 
1357  imu_msg.angular_velocity.x = gyro_data.m_data.x();
1358  imu_msg.angular_velocity.y = gyro_data.m_data.y();
1359  imu_msg.angular_velocity.z = gyro_data.m_data.z();
1360 
1361  imu_msg.linear_acceleration.x = accel_data.m_data.x();
1362  imu_msg.linear_acceleration.y = accel_data.m_data.y();
1363  imu_msg.linear_acceleration.z = accel_data.m_data.z();
1364  return imu_msg;
1365 }
1366 
1367 template <typename T> T lerp(const T &a, const T &b, const double t) {
1368  return a * (1.0 - t) + b * t;
1369 }
1370 
1371 void BaseRealSenseNode::FillImuData_LinearInterpolation(const CimuData imu_data, std::deque<sensor_msgs::Imu>& imu_msgs)
1372 {
1373  static std::deque<CimuData> _imu_history;
1374  _imu_history.push_back(imu_data);
1375  stream_index_pair type(imu_data.m_type);
1376  imu_msgs.clear();
1377 
1378  if ((type != ACCEL) || _imu_history.size() < 3)
1379  return;
1380 
1381  std::deque<CimuData> gyros_data;
1382  CimuData accel0, accel1, crnt_imu;
1383 
1384  while (_imu_history.size())
1385  {
1386  crnt_imu = _imu_history.front();
1387  _imu_history.pop_front();
1388  if (!accel0.is_set() && crnt_imu.m_type == ACCEL)
1389  {
1390  accel0 = crnt_imu;
1391  }
1392  else if (accel0.is_set() && crnt_imu.m_type == ACCEL)
1393  {
1394  accel1 = crnt_imu;
1395  const double dt = accel1.m_time - accel0.m_time;
1396 
1397  while (gyros_data.size())
1398  {
1399  CimuData crnt_gyro = gyros_data.front();
1400  gyros_data.pop_front();
1401  const double alpha = (crnt_gyro.m_time - accel0.m_time) / dt;
1402  CimuData crnt_accel(ACCEL, lerp(accel0.m_data, accel1.m_data, alpha), crnt_gyro.m_time);
1403  imu_msgs.push_back(CreateUnitedMessage(crnt_accel, crnt_gyro));
1404  }
1405  accel0 = accel1;
1406  }
1407  else if (accel0.is_set() && crnt_imu.m_time >= accel0.m_time && crnt_imu.m_type == GYRO)
1408  {
1409  gyros_data.push_back(crnt_imu);
1410  }
1411  }
1412  _imu_history.push_back(crnt_imu);
1413  return;
1414 }
1415 
1416 void BaseRealSenseNode::FillImuData_Copy(const CimuData imu_data, std::deque<sensor_msgs::Imu>& imu_msgs)
1417 {
1418  stream_index_pair type(imu_data.m_type);
1419 
1420  static CimuData _accel_data(ACCEL, {0,0,0}, -1.0);
1421  if (ACCEL == type)
1422  {
1423  _accel_data = imu_data;
1424  return;
1425  }
1426  if (_accel_data.m_time < 0)
1427  return;
1428 
1429  imu_msgs.push_back(CreateUnitedMessage(_accel_data, imu_data));
1430 }
1431 
1433 {
1435  imu_msg.orientation.x = 0.0;
1436  imu_msg.orientation.y = 0.0;
1437  imu_msg.orientation.z = 0.0;
1438  imu_msg.orientation.w = 0.0;
1439 
1440  imu_msg.orientation_covariance = { -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
1441  imu_msg.linear_acceleration_covariance = { _linear_accel_cov, 0.0, 0.0, 0.0, _linear_accel_cov, 0.0, 0.0, 0.0, _linear_accel_cov};
1443 }
1444 
1446 {
1447  static std::mutex m_mutex;
1448  static int seq = 0;
1449 
1450  m_mutex.lock();
1451 
1452  auto stream = frame.get_profile().stream_type();
1453  auto stream_index = (stream == GYRO.first)?GYRO:ACCEL;
1454  double frame_time = frame.get_timestamp();
1455 
1456  bool placeholder_false(false);
1457  if (_is_initialized_time_base.compare_exchange_strong(placeholder_false, true) )
1458  {
1460  }
1461 
1462  seq += 1;
1463 
1464  if (0 != _synced_imu_publisher->getNumSubscribers())
1465  {
1466  auto crnt_reading = *(reinterpret_cast<const float3*>(frame.get_data()));
1467  Eigen::Vector3d v(crnt_reading.x, crnt_reading.y, crnt_reading.z);
1468  CimuData imu_data(stream_index, v, frameSystemTimeSec(frame));
1469  std::deque<sensor_msgs::Imu> imu_msgs;
1470  switch (sync_method)
1471  {
1472  case NONE: //Cannot really be NONE. Just to avoid compilation warning.
1473  case COPY:
1474  FillImuData_Copy(imu_data, imu_msgs);
1475  break;
1476  case LINEAR_INTERPOLATION:
1477  FillImuData_LinearInterpolation(imu_data, imu_msgs);
1478  break;
1479  }
1480  while (imu_msgs.size())
1481  {
1482  sensor_msgs::Imu imu_msg = imu_msgs.front();
1483  imu_msg.header.seq = seq;
1484  ImuMessage_AddDefaultValues(imu_msg);
1485  _synced_imu_publisher->Publish(imu_msg);
1486  ROS_DEBUG("Publish united %s stream", rs2_stream_to_string(frame.get_profile().stream_type()));
1487  imu_msgs.pop_front();
1488  }
1489  }
1490  m_mutex.unlock();
1491 }
1492 
1494 {
1495  auto stream = frame.get_profile().stream_type();
1496  double frame_time = frame.get_timestamp();
1497  bool placeholder_false(false);
1498  if (_is_initialized_time_base.compare_exchange_strong(placeholder_false, true) )
1499  {
1501  }
1502 
1503  ROS_DEBUG("Frame arrived: stream: %s ; index: %d ; Timestamp Domain: %s",
1505  frame.get_profile().stream_index(),
1507 
1508  auto stream_index = (stream == GYRO.first)?GYRO:ACCEL;
1509  ros::Time t(frameSystemTimeSec(frame));
1510  if (0 != _imu_publishers[stream_index].getNumSubscribers())
1511  {
1512  auto imu_msg = sensor_msgs::Imu();
1513  ImuMessage_AddDefaultValues(imu_msg);
1514  imu_msg.header.frame_id = _optical_frame_id[stream_index];
1515 
1516  auto crnt_reading = *(reinterpret_cast<const float3*>(frame.get_data()));
1517  if (GYRO == stream_index)
1518  {
1519  imu_msg.angular_velocity.x = crnt_reading.x;
1520  imu_msg.angular_velocity.y = crnt_reading.y;
1521  imu_msg.angular_velocity.z = crnt_reading.z;
1522  }
1523  else if (ACCEL == stream_index)
1524  {
1525  imu_msg.linear_acceleration.x = crnt_reading.x;
1526  imu_msg.linear_acceleration.y = crnt_reading.y;
1527  imu_msg.linear_acceleration.z = crnt_reading.z;
1528  }
1529  _seq[stream_index] += 1;
1530  imu_msg.header.seq = _seq[stream_index];
1531  imu_msg.header.stamp = t;
1532  _imu_publishers[stream_index].publish(imu_msg);
1533  ROS_DEBUG("Publish %s stream", rs2_stream_to_string(frame.get_profile().stream_type()));
1534  }
1535  publishMetadata(frame, t, _optical_frame_id[stream_index]);
1536 }
1537 
1539 {
1540  double frame_time = frame.get_timestamp();
1541  bool placeholder_false(false);
1542  if (_is_initialized_time_base.compare_exchange_strong(placeholder_false, true) )
1543  {
1545  }
1546 
1547  ROS_DEBUG("Frame arrived: stream: %s ; index: %d ; Timestamp Domain: %s",
1549  frame.get_profile().stream_index(),
1551  const auto& stream_index(POSE);
1552  rs2_pose pose = frame.as<rs2::pose_frame>().get_pose_data();
1553  ros::Time t(frameSystemTimeSec(frame));
1554 
1555  geometry_msgs::PoseStamped pose_msg;
1556  pose_msg.pose.position.x = -pose.translation.z;
1557  pose_msg.pose.position.y = -pose.translation.x;
1558  pose_msg.pose.position.z = pose.translation.y;
1559  pose_msg.pose.orientation.x = -pose.rotation.z;
1560  pose_msg.pose.orientation.y = -pose.rotation.x;
1561  pose_msg.pose.orientation.z = pose.rotation.y;
1562  pose_msg.pose.orientation.w = pose.rotation.w;
1563 
1566  msg.header.stamp = t;
1568  msg.child_frame_id = _frame_id[POSE];
1569  msg.transform.translation.x = pose_msg.pose.position.x;
1570  msg.transform.translation.y = pose_msg.pose.position.y;
1571  msg.transform.translation.z = pose_msg.pose.position.z;
1572  msg.transform.rotation.x = pose_msg.pose.orientation.x;
1573  msg.transform.rotation.y = pose_msg.pose.orientation.y;
1574  msg.transform.rotation.z = pose_msg.pose.orientation.z;
1575  msg.transform.rotation.w = pose_msg.pose.orientation.w;
1576 
1577  if (_publish_odom_tf) br.sendTransform(msg);
1578 
1579  if (0 != _imu_publishers[stream_index].getNumSubscribers())
1580  {
1581  double cov_pose(_linear_accel_cov * pow(10, 3-(int)pose.tracker_confidence));
1582  double cov_twist(_angular_velocity_cov * pow(10, 1-(int)pose.tracker_confidence));
1583 
1585  v_msg.vector.x = -pose.velocity.z;
1586  v_msg.vector.y = -pose.velocity.x;
1587  v_msg.vector.z = pose.velocity.y;
1588  tf::Vector3 tfv;
1589  tf::vector3MsgToTF(v_msg.vector,tfv);
1591  tfv=tf::quatRotate(q,tfv);
1592  tf::vector3TFToMsg(tfv,v_msg.vector);
1593 
1595  om_msg.vector.x = -pose.angular_velocity.z;
1596  om_msg.vector.y = -pose.angular_velocity.x;
1597  om_msg.vector.z = pose.angular_velocity.y;
1598  tf::vector3MsgToTF(om_msg.vector,tfv);
1599  tfv=tf::quatRotate(q,tfv);
1600  tf::vector3TFToMsg(tfv,om_msg.vector);
1601 
1602 
1603  nav_msgs::Odometry odom_msg;
1604  _seq[stream_index] += 1;
1605 
1606  odom_msg.header.frame_id = _odom_frame_id;
1607  odom_msg.child_frame_id = _frame_id[POSE];
1608  odom_msg.header.stamp = t;
1609  odom_msg.header.seq = _seq[stream_index];
1610  odom_msg.pose.pose = pose_msg.pose;
1611  odom_msg.pose.covariance = {cov_pose, 0, 0, 0, 0, 0,
1612  0, cov_pose, 0, 0, 0, 0,
1613  0, 0, cov_pose, 0, 0, 0,
1614  0, 0, 0, cov_twist, 0, 0,
1615  0, 0, 0, 0, cov_twist, 0,
1616  0, 0, 0, 0, 0, cov_twist};
1617  odom_msg.twist.twist.linear = v_msg.vector;
1618  odom_msg.twist.twist.angular = om_msg.vector;
1619  odom_msg.twist.covariance ={cov_pose, 0, 0, 0, 0, 0,
1620  0, cov_pose, 0, 0, 0, 0,
1621  0, 0, cov_pose, 0, 0, 0,
1622  0, 0, 0, cov_twist, 0, 0,
1623  0, 0, 0, 0, cov_twist, 0,
1624  0, 0, 0, 0, 0, cov_twist};
1625  _imu_publishers[stream_index].publish(odom_msg);
1626  ROS_DEBUG("Publish %s stream", rs2_stream_to_string(frame.get_profile().stream_type()));
1627  }
1628  publishMetadata(frame, t, _frame_id[POSE]);
1629 }
1630 
1632 {
1633  _synced_imu_publisher->Pause();
1634 
1635  try{
1636  double frame_time = frame.get_timestamp();
1637 
1638  // We compute a ROS timestamp which is based on an initial ROS time at point of first frame,
1639  // and the incremental timestamp from the camera.
1640  // In sync mode the timestamp is based on ROS time
1641  bool placeholder_false(false);
1642  if (_is_initialized_time_base.compare_exchange_strong(placeholder_false, true) )
1643  {
1645  }
1646 
1647  ros::Time t(frameSystemTimeSec(frame));
1648  if (frame.is<rs2::frameset>())
1649  {
1650  ROS_DEBUG("Frameset arrived.");
1651  auto frameset = frame.as<rs2::frameset>();
1652  ROS_DEBUG("List of frameset before applying filters: size: %d", static_cast<int>(frameset.size()));
1653  for (auto it = frameset.begin(); it != frameset.end(); ++it)
1654  {
1655  auto f = (*it);
1656  auto stream_type = f.get_profile().stream_type();
1657  auto stream_index = f.get_profile().stream_index();
1658  auto stream_format = f.get_profile().format();
1659  auto stream_unique_id = f.get_profile().unique_id();
1660 
1661  ROS_DEBUG("Frameset contain (%s, %d, %s %d) frame. frame_number: %llu ; frame_TS: %f ; ros_TS(NSec): %lu",
1662  rs2_stream_to_string(stream_type), stream_index, rs2_format_to_string(stream_format), stream_unique_id, frame.get_frame_number(), frame_time, t.toNSec());
1663  runFirstFrameInitialization(stream_type);
1664  }
1665  // Clip depth_frame for max range:
1666  rs2::depth_frame original_depth_frame = frameset.get_depth_frame();
1667  bool is_color_frame(frameset.get_color_frame());
1668  if (original_depth_frame && _clipping_distance > 0)
1669  {
1670  clip_depth(original_depth_frame, _clipping_distance);
1671  }
1672 
1673  ROS_DEBUG("num_filters: %d", static_cast<int>(_filters.size()));
1674  for (std::vector<NamedFilter>::const_iterator filter_it = _filters.begin(); filter_it != _filters.end(); filter_it++)
1675  {
1676  ROS_DEBUG("Applying filter: %s", filter_it->_name.c_str());
1677  if ((filter_it->_name == "pointcloud") && (!original_depth_frame))
1678  continue;
1679  if ((filter_it->_name == "align_to_color") && (!is_color_frame))
1680  continue;
1681  frameset = filter_it->_filter->process(frameset);
1682  }
1683 
1684  ROS_DEBUG("List of frameset after applying filters: size: %d", static_cast<int>(frameset.size()));
1685  bool sent_depth_frame(false);
1686  for (auto it = frameset.begin(); it != frameset.end(); ++it)
1687  {
1688  auto f = (*it);
1689  auto stream_type = f.get_profile().stream_type();
1690  auto stream_index = f.get_profile().stream_index();
1691  auto stream_format = f.get_profile().format();
1692  stream_index_pair sip{stream_type,stream_index};
1693 
1694  ROS_DEBUG("Frameset contain (%s, %d, %s) frame. frame_number: %llu ; frame_TS: %f ; ros_TS(NSec): %lu",
1695  rs2_stream_to_string(stream_type), stream_index, rs2_format_to_string(stream_format), f.get_frame_number(), frame_time, t.toNSec());
1696  if (f.is<rs2::video_frame>())
1697  ROS_DEBUG_STREAM("frame: " << f.as<rs2::video_frame>().get_width() << " x " << f.as<rs2::video_frame>().get_height());
1698 
1699  if (f.is<rs2::points>())
1700  {
1701  publishPointCloud(f.as<rs2::points>(), t, frameset);
1702  continue;
1703  }
1704  if (stream_type == RS2_STREAM_DEPTH)
1705  {
1706  if (sent_depth_frame) continue;
1707  sent_depth_frame = true;
1708  if (_align_depth && is_color_frame)
1709  {
1710  publishFrame(f, t, COLOR,
1714  false,
1718  continue;
1719  }
1720  }
1721  publishFrame(f, t,
1722  sip,
1723  _image,
1726  true,
1727  _seq,
1728  _camera_info,
1729  _encoding);
1730  }
1731  if (original_depth_frame && _align_depth)
1732  {
1733  rs2::frame frame_to_send;
1734  if (_colorizer)
1735  frame_to_send = _colorizer->process(original_depth_frame);
1736  else
1737  frame_to_send = original_depth_frame;
1738 
1739  publishFrame(frame_to_send, t,
1740  DEPTH,
1741  _image,
1744  true,
1745  _seq,
1746  _camera_info,
1747  _encoding);
1748  }
1749  }
1750  else if (frame.is<rs2::video_frame>())
1751  {
1752  auto stream_type = frame.get_profile().stream_type();
1753  auto stream_index = frame.get_profile().stream_index();
1754  ROS_DEBUG("Single video frame arrived (%s, %d). frame_number: %llu ; frame_TS: %f ; ros_TS(NSec): %lu",
1755  rs2_stream_to_string(stream_type), stream_index, frame.get_frame_number(), frame_time, t.toNSec());
1756  runFirstFrameInitialization(stream_type);
1757 
1758  stream_index_pair sip{stream_type,stream_index};
1759  if (frame.is<rs2::depth_frame>())
1760  {
1761  if (_clipping_distance > 0)
1762  {
1764  }
1765  }
1766  publishFrame(frame, t,
1767  sip,
1768  _image,
1771  true,
1772  _seq,
1773  _camera_info,
1774  _encoding);
1775  }
1776  }
1777  catch(const std::exception& ex)
1778  {
1779  ROS_ERROR_STREAM("An error has occurred during frame callback: " << ex.what());
1780  }
1781  _synced_imu_publisher->Resume();
1782 } // frame_callback
1783 
1785 {
1786  auto stream = frame.get_profile().stream_type();
1787  switch (stream)
1788  {
1789  case RS2_STREAM_GYRO:
1790  case RS2_STREAM_ACCEL:
1791  if (sync_method > imu_sync_method::NONE) imu_callback_sync(frame, sync_method);
1792  else imu_callback(frame);
1793  break;
1794  case RS2_STREAM_POSE:
1795  pose_callback(frame);
1796  break;
1797  default:
1798  frame_callback(frame);
1799  }
1800 }
1801 
1802 bool BaseRealSenseNode::setBaseTime(double frame_time, rs2_timestamp_domain time_domain)
1803 {
1804  ROS_WARN_ONCE(time_domain == RS2_TIMESTAMP_DOMAIN_SYSTEM_TIME ? "Frame metadata isn't available! (frame_timestamp_domain = RS2_TIMESTAMP_DOMAIN_SYSTEM_TIME)" : "");
1805  if (time_domain == RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK)
1806  {
1807  ROS_WARN("frame's time domain is HARDWARE_CLOCK. Timestamps may reset periodically.");
1809  _camera_time_base = frame_time;
1810  return true;
1811  }
1812  return false;
1813 }
1814 
1816 {
1818  {
1819  double elapsed_camera_ms = (/*ms*/ frame.get_timestamp() - /*ms*/ _camera_time_base) / 1000.0;
1820  return (_ros_time_base.toSec() + elapsed_camera_ms);
1821  }
1822  else
1823  {
1824  return (frame.get_timestamp() / 1000.0);
1825  }
1826 }
1827 
1829 {
1830  ROS_INFO("setupStreams...");
1831  try{
1832  // Publish image stream info
1833  for (auto& profiles : _enabled_profiles)
1834  {
1835  for (auto& profile : profiles.second)
1836  {
1838  {
1839  auto video_profile = profile.as<rs2::video_stream_profile>();
1840  updateStreamCalibData(video_profile);
1841  }
1842  }
1843  }
1844 
1845  // Streaming IMAGES
1846  std::map<std::string, std::vector<rs2::stream_profile> > profiles;
1847  std::map<std::string, rs2::sensor> active_sensors;
1848  for (const std::pair<stream_index_pair, std::vector<rs2::stream_profile>>& profile : _enabled_profiles)
1849  {
1850  std::string module_name = _sensors[profile.first].get_info(RS2_CAMERA_INFO_NAME);
1851  ROS_DEBUG_STREAM("insert " << rs2_stream_to_string(profile.second.begin()->stream_type())
1852  << " to " << module_name);
1853  profiles[module_name].insert(profiles[module_name].begin(),
1854  profile.second.begin(),
1855  profile.second.end());
1856  active_sensors[module_name] = _sensors[profile.first];
1857  }
1858 
1859  for (const std::pair<std::string, std::vector<rs2::stream_profile> >& sensor_profile : profiles)
1860  {
1861  std::string module_name = sensor_profile.first;
1862  rs2::sensor sensor = active_sensors[module_name];
1863  sensor.open(sensor_profile.second);
1864  sensor.start(_sensors_callback[module_name]);
1865  if (sensor.is<rs2::depth_sensor>())
1866  {
1868  }
1869  }
1870  }
1871  catch(const std::exception& ex)
1872  {
1873  ROS_ERROR_STREAM("An exception has been thrown: " << ex.what());
1874  throw;
1875  }
1876  catch(...)
1877  {
1878  ROS_ERROR_STREAM("Unknown exception has occured!");
1879  throw;
1880  }
1881 }
1882 
1884 {
1885  stream_index_pair stream_index{video_profile.stream_type(), video_profile.stream_index()};
1886  auto intrinsic = video_profile.get_intrinsics();
1887  _stream_intrinsics[stream_index] = intrinsic;
1888  _camera_info[stream_index].width = intrinsic.width;
1889  _camera_info[stream_index].height = intrinsic.height;
1890  _camera_info[stream_index].header.frame_id = _optical_frame_id[stream_index];
1891 
1892  _camera_info[stream_index].K.at(0) = intrinsic.fx;
1893  _camera_info[stream_index].K.at(2) = intrinsic.ppx;
1894  _camera_info[stream_index].K.at(4) = intrinsic.fy;
1895  _camera_info[stream_index].K.at(5) = intrinsic.ppy;
1896  _camera_info[stream_index].K.at(8) = 1;
1897 
1898  _camera_info[stream_index].P.at(0) = _camera_info[stream_index].K.at(0);
1899  _camera_info[stream_index].P.at(1) = 0;
1900  _camera_info[stream_index].P.at(2) = _camera_info[stream_index].K.at(2);
1901  _camera_info[stream_index].P.at(3) = 0;
1902  _camera_info[stream_index].P.at(4) = 0;
1903  _camera_info[stream_index].P.at(5) = _camera_info[stream_index].K.at(4);
1904  _camera_info[stream_index].P.at(6) = _camera_info[stream_index].K.at(5);
1905  _camera_info[stream_index].P.at(7) = 0;
1906  _camera_info[stream_index].P.at(8) = 0;
1907  _camera_info[stream_index].P.at(9) = 0;
1908  _camera_info[stream_index].P.at(10) = 1;
1909  _camera_info[stream_index].P.at(11) = 0;
1910 
1911  // Set Tx, Ty for right camera
1912  if (stream_index.second == 2)
1913  {
1914  stream_index_pair sip1{stream_index.first, 1};
1915  if (_enable[sip1])
1916  {
1917  const auto& ex = getAProfile(stream_index).get_extrinsics_to(getAProfile(sip1));
1918  _camera_info[stream_index].header.frame_id = _optical_frame_id[sip1];
1919  _camera_info[stream_index].P.at(3) = -intrinsic.fx * ex.translation[0] + 0.0; // Tx - avoid -0.0 values.
1920  _camera_info[stream_index].P.at(7) = -intrinsic.fy * ex.translation[1] + 0.0; // Ty - avoid -0.0 values.
1921  }
1922  }
1923 
1924  // set R (rotation matrix) values to identity matrix
1925  _camera_info[stream_index].R.at(0) = 1.0;
1926  _camera_info[stream_index].R.at(1) = 0.0;
1927  _camera_info[stream_index].R.at(2) = 0.0;
1928  _camera_info[stream_index].R.at(3) = 0.0;
1929  _camera_info[stream_index].R.at(4) = 1.0;
1930  _camera_info[stream_index].R.at(5) = 0.0;
1931  _camera_info[stream_index].R.at(6) = 0.0;
1932  _camera_info[stream_index].R.at(7) = 0.0;
1933  _camera_info[stream_index].R.at(8) = 1.0;
1934 
1935  int coeff_size(5);
1936  if (intrinsic.model == RS2_DISTORTION_KANNALA_BRANDT4)
1937  {
1938  _camera_info[stream_index].distortion_model = "equidistant";
1939  coeff_size = 4;
1940  } else {
1941  _camera_info[stream_index].distortion_model = "plumb_bob";
1942  }
1943  _camera_info[stream_index].D.resize(coeff_size);
1944  for (int i = 0; i < coeff_size; i++)
1945  {
1946  _camera_info[stream_index].D.at(i) = intrinsic.coeffs[i];
1947  }
1948 
1949  if (stream_index == DEPTH && _enable[DEPTH] && _enable[COLOR])
1950  {
1951  _camera_info[stream_index].P.at(3) = 0; // Tx
1952  _camera_info[stream_index].P.at(7) = 0; // Ty
1953  }
1954 
1955  if (_align_depth)
1956  {
1957  for (auto& profiles : _enabled_profiles)
1958  {
1959  for (auto& profile : profiles.second)
1960  {
1961  auto video_profile = profile.as<rs2::video_stream_profile>();
1962  stream_index_pair stream_index{video_profile.stream_type(), video_profile.stream_index()};
1963  _depth_aligned_camera_info[stream_index] = _camera_info[stream_index];
1964  }
1965  }
1966  }
1967 }
1968 
1970 {
1971  Eigen::Matrix3f m;
1972  // We need to be careful about the order, as RS2 rotation matrix is
1973  // column-major, while Eigen::Matrix3f expects row-major.
1974  m << rotation[0], rotation[3], rotation[6],
1975  rotation[1], rotation[4], rotation[7],
1976  rotation[2], rotation[5], rotation[8];
1977  Eigen::Quaternionf q(m);
1978  return tf::Quaternion(q.x(), q.y(), q.z(), q.w());
1979 }
1980 
1982  const float3& trans,
1983  const tf::Quaternion& q,
1984  const std::string& from,
1985  const std::string& to)
1986 {
1988  msg.header.stamp = t;
1989  msg.header.frame_id = from;
1990  msg.child_frame_id = to;
1991  msg.transform.translation.x = trans.z;
1992  msg.transform.translation.y = -trans.x;
1993  msg.transform.translation.z = -trans.y;
1994  msg.transform.rotation.x = q.getX();
1995  msg.transform.rotation.y = q.getY();
1996  msg.transform.rotation.z = q.getZ();
1997  msg.transform.rotation.w = q.getW();
1998  _static_tf_msgs.push_back(msg);
1999 }
2000 
2002 {
2003  // Transform base to stream
2004  tf::Quaternion quaternion_optical;
2005  quaternion_optical.setRPY(-M_PI / 2, 0.0, -M_PI / 2);
2006  float3 zero_trans{0, 0, 0};
2007 
2008  ros::Time transform_ts_ = ros::Time::now();
2009 
2010  rs2_extrinsics ex;
2011  try
2012  {
2013  ex = getAProfile(stream).get_extrinsics_to(base_profile);
2014  }
2015  catch (std::exception& e)
2016  {
2017  if (!strcmp(e.what(), "Requested extrinsics are not available!"))
2018  {
2019  ROS_WARN_STREAM("(" << rs2_stream_to_string(stream.first) << ", " << stream.second << ") -> (" << rs2_stream_to_string(base_profile.stream_type()) << ", " << base_profile.stream_index() << "): " << e.what() << " : using unity as default.");
2020  ex = rs2_extrinsics({{1, 0, 0, 0, 1, 0, 0, 0, 1}, {0,0,0}});
2021  }
2022  else
2023  {
2024  throw e;
2025  }
2026  }
2027 
2029  Q = quaternion_optical * Q * quaternion_optical.inverse();
2030 
2031  float3 trans{ex.translation[0], ex.translation[1], ex.translation[2]};
2032  publish_static_tf(transform_ts_, trans, Q, _base_frame_id, _frame_id[stream]);
2033 
2034  // Transform stream frame to stream optical frame
2035  publish_static_tf(transform_ts_, zero_trans, quaternion_optical, _frame_id[stream], _optical_frame_id[stream]);
2036 
2037  if (_align_depth && _depth_aligned_frame_id.find(stream) != _depth_aligned_frame_id.end())
2038  {
2039  publish_static_tf(transform_ts_, trans, Q, _base_frame_id, _depth_aligned_frame_id[stream]);
2040  publish_static_tf(transform_ts_, zero_trans, quaternion_optical, _depth_aligned_frame_id[stream], _optical_frame_id[stream]);
2041  }
2042 }
2043 
2045 {
2046  const std::vector<stream_index_pair> base_stream_priority = {DEPTH, POSE};
2047 
2048  std::vector<stream_index_pair>::const_iterator base_stream(base_stream_priority.begin());
2049  while( (_sensors.find(*base_stream) == _sensors.end()) && (base_stream != base_stream_priority.end()))
2050  {
2051  base_stream++;
2052  }
2053  if (base_stream == base_stream_priority.end())
2054  {
2055  throw std::runtime_error("No known base_stream found for transformations.");
2056  }
2057  ROS_INFO_STREAM("SELECTED BASE:" << base_stream->first << ", " << base_stream->second);
2058 
2059  _base_stream = *base_stream;
2060 }
2061 
2063 {
2065  // Publish static transforms
2066  if (_publish_tf)
2067  {
2068  for (std::pair<stream_index_pair, bool> ienable : _enable)
2069  {
2070  if (ienable.second)
2071  {
2072  calcAndPublishStaticTransform(ienable.first, base_profile);
2073  }
2074  }
2075  // Static transform for non-positive values
2076  if (_tf_publish_rate > 0)
2077  _tf_t = std::shared_ptr<std::thread>(new std::thread(boost::bind(&BaseRealSenseNode::publishDynamicTransforms, this)));
2078  else
2080  }
2081 
2082  // Publish Extrinsics Topics:
2083  if (_enable[DEPTH] &&
2084  _enable[FISHEYE])
2085  {
2086  static const char* frame_id = "depth_to_fisheye_extrinsics";
2087  const auto& ex = base_profile.get_extrinsics_to(getAProfile(FISHEYE));
2088 
2091  }
2092 
2093  if (_enable[DEPTH] &&
2094  _enable[COLOR])
2095  {
2096  static const char* frame_id = "depth_to_color_extrinsics";
2097  const auto& ex = base_profile.get_extrinsics_to(getAProfile(COLOR));
2100  }
2101 
2102  if (_enable[DEPTH] &&
2103  _enable[INFRA1])
2104  {
2105  static const char* frame_id = "depth_to_infra1_extrinsics";
2106  const auto& ex = base_profile.get_extrinsics_to(getAProfile(INFRA1));
2109  }
2110 
2111  if (_enable[DEPTH] &&
2112  _enable[INFRA2])
2113  {
2114  static const char* frame_id = "depth_to_infra2_extrinsics";
2115  const auto& ex = base_profile.get_extrinsics_to(getAProfile(INFRA2));
2118  }
2119 
2120 }
2121 
2123 {
2124  // Publish transforms for the cameras
2125  ROS_WARN("Publishing dynamic camera transforms (/tf) at %g Hz", _tf_publish_rate);
2126 
2127  std::mutex mu;
2128  std::unique_lock<std::mutex> lock(mu);
2129  while (ros::ok() && _is_running)
2130  {
2131  _cv_tf.wait_for(lock, std::chrono::milliseconds((int)(1000.0/_tf_publish_rate)), [&]{return (!(_is_running));});
2132  {
2134  for(auto& msg : _static_tf_msgs)
2135  msg.header.stamp = t;
2136  _dynamic_tf_broadcaster.sendTransform(_static_tf_msgs);
2137  }
2138  }
2139 }
2140 
2142 {
2143  if (_enable[GYRO])
2144  {
2145  _info_publisher[GYRO] = _node_handle.advertise<IMUInfo>("gyro/imu_info", 1, true);
2146  IMUInfo info_msg = getImuInfo(GYRO);
2147  _info_publisher[GYRO].publish(info_msg);
2148  }
2149 
2150  if (_enable[ACCEL])
2151  {
2152  _info_publisher[ACCEL] = _node_handle.advertise<IMUInfo>("accel/imu_info", 1, true);
2153  IMUInfo info_msg = getImuInfo(ACCEL);
2154  _info_publisher[ACCEL].publish(info_msg);
2155  }
2156 }
2157 
2158 void reverse_memcpy(unsigned char* dst, const unsigned char* src, size_t n)
2159 {
2160  size_t i;
2161 
2162  for (i=0; i < n; ++i)
2163  dst[n-1-i] = src[i];
2164 
2165 }
2166 
2168 {
2170  return;
2171  ROS_INFO_STREAM_ONCE("publishing " << (_ordered_pc ? "" : "un") << "ordered pointcloud.");
2172 
2173  rs2_stream texture_source_id = static_cast<rs2_stream>(_pointcloud_filter->get_option(rs2_option::RS2_OPTION_STREAM_FILTER));
2174  bool use_texture = texture_source_id != RS2_STREAM_ANY;
2175  static int warn_count(0);
2176  static const int DISPLAY_WARN_NUMBER(5);
2177  rs2::frameset::iterator texture_frame_itr = frameset.end();
2178  if (use_texture)
2179  {
2180  std::set<rs2_format> available_formats{ rs2_format::RS2_FORMAT_RGB8, rs2_format::RS2_FORMAT_Y8 };
2181 
2182  texture_frame_itr = std::find_if(frameset.begin(), frameset.end(), [&texture_source_id, &available_formats] (rs2::frame f)
2183  {return (rs2_stream(f.get_profile().stream_type()) == texture_source_id) &&
2184  (available_formats.find(f.get_profile().format()) != available_formats.end()); });
2185  if (texture_frame_itr == frameset.end())
2186  {
2187  warn_count++;
2188  std::string texture_source_name = _pointcloud_filter->get_option_value_description(rs2_option::RS2_OPTION_STREAM_FILTER, static_cast<float>(texture_source_id));
2189  ROS_WARN_STREAM_COND(warn_count == DISPLAY_WARN_NUMBER, "No stream match for pointcloud chosen texture " << texture_source_name);
2190  return;
2191  }
2192  warn_count = 0;
2193  }
2194 
2195  int texture_width(0), texture_height(0);
2196  int num_colors(0);
2197 
2198  const rs2::vertex* vertex = pc.get_vertices();
2199  const rs2::texture_coordinate* color_point = pc.get_texture_coordinates();
2200 
2201  rs2_intrinsics depth_intrin = pc.get_profile().as<rs2::video_stream_profile>().get_intrinsics();
2202 
2204  modifier.setPointCloud2FieldsByString(1, "xyz");
2205  modifier.resize(pc.size());
2206  if (_ordered_pc)
2207  {
2208  _msg_pointcloud.width = depth_intrin.width;
2209  _msg_pointcloud.height = depth_intrin.height;
2210  _msg_pointcloud.is_dense = false;
2211  }
2212 
2213  vertex = pc.get_vertices();
2214  size_t valid_count(0);
2215  if (use_texture)
2216  {
2217  rs2::video_frame texture_frame = (*texture_frame_itr).as<rs2::video_frame>();
2218  texture_width = texture_frame.get_width();
2219  texture_height = texture_frame.get_height();
2220  num_colors = texture_frame.get_bytes_per_pixel();
2221  uint8_t* color_data = (uint8_t*)texture_frame.get_data();
2222  std::string format_str;
2223  switch(texture_frame.get_profile().format())
2224  {
2225  case RS2_FORMAT_RGB8:
2226  format_str = "rgb";
2227  break;
2228  case RS2_FORMAT_Y8:
2229  format_str = "intensity";
2230  break;
2231  default:
2232  throw std::runtime_error("Unhandled texture format passed in pointcloud " + std::to_string(texture_frame.get_profile().format()));
2233  }
2237 
2242  color_point = pc.get_texture_coordinates();
2243 
2244  float color_pixel[2];
2245  for (size_t point_idx=0; point_idx < pc.size(); point_idx++, vertex++, color_point++)
2246  {
2247  float i(color_point->u);
2248  float j(color_point->v);
2249  bool valid_color_pixel(i >= 0.f && i <=1.f && j >= 0.f && j <=1.f);
2250  bool valid_pixel(vertex->z > 0 && (valid_color_pixel || _allow_no_texture_points));
2251  if (valid_pixel || _ordered_pc)
2252  {
2253  *iter_x = vertex->x;
2254  *iter_y = vertex->y;
2255  *iter_z = vertex->z;
2256 
2257  if (valid_color_pixel)
2258  {
2259  color_pixel[0] = i * texture_width;
2260  color_pixel[1] = j * texture_height;
2261  int pixx = static_cast<int>(color_pixel[0]);
2262  int pixy = static_cast<int>(color_pixel[1]);
2263  int offset = (pixy * texture_width + pixx) * num_colors;
2264  reverse_memcpy(&(*iter_color), color_data+offset, num_colors); // PointCloud2 order of rgb is bgr.
2265  }
2266  ++iter_x; ++iter_y; ++iter_z;
2267  ++iter_color;
2268  ++valid_count;
2269  }
2270  }
2271  }
2272  else
2273  {
2274  std::string format_str = "intensity";
2277 
2281 
2282  for (size_t point_idx=0; point_idx < pc.size(); point_idx++, vertex++)
2283  {
2284  bool valid_pixel(vertex->z > 0);
2285  if (valid_pixel || _ordered_pc)
2286  {
2287  *iter_x = vertex->x;
2288  *iter_y = vertex->y;
2289  *iter_z = vertex->z;
2290 
2291  ++iter_x; ++iter_y; ++iter_z;
2292  ++valid_count;
2293  }
2294  }
2295  }
2299  if (!_ordered_pc)
2300  {
2301  _msg_pointcloud.width = valid_count;
2302  _msg_pointcloud.height = 1;
2303  _msg_pointcloud.is_dense = true;
2304  modifier.resize(valid_count);
2305  }
2307 }
2308 
2309 
2310 Extrinsics BaseRealSenseNode::rsExtrinsicsToMsg(const rs2_extrinsics& extrinsics, const std::string& frame_id) const
2311 {
2312  Extrinsics extrinsicsMsg;
2313  for (int i = 0; i < 9; ++i)
2314  {
2315  extrinsicsMsg.rotation[i] = extrinsics.rotation[i];
2316  if (i < 3)
2317  extrinsicsMsg.translation[i] = extrinsics.translation[i];
2318  }
2319 
2320  extrinsicsMsg.header.frame_id = frame_id;
2321  return extrinsicsMsg;
2322 }
2323 
2325 {
2326  const std::vector<rs2::stream_profile> profiles = _sensors[stream].get_stream_profiles();
2327  return *(std::find_if(profiles.begin(), profiles.end(),
2328  [&stream] (const rs2::stream_profile& profile) {
2329  return ((profile.stream_type() == stream.first) && (profile.stream_index() == stream.second));
2330  }));
2331 }
2332 
2334 {
2335  IMUInfo info{};
2336  auto sp = _enabled_profiles[stream_index].front().as<rs2::motion_stream_profile>();
2337  rs2_motion_device_intrinsic imuIntrinsics;
2338  try
2339  {
2340  imuIntrinsics = sp.get_motion_intrinsics();
2341  }
2342  catch(const std::runtime_error &ex)
2343  {
2344  ROS_DEBUG_STREAM("No Motion Intrinsics available.");
2345  imuIntrinsics = {{{1,0,0,0},{0,1,0,0},{0,0,1,0}}, {0,0,0}, {0,0,0}};
2346  }
2347 
2348  auto index = 0;
2349  info.frame_id = _optical_frame_id[stream_index];
2350  for (int i = 0; i < 3; ++i)
2351  {
2352  for (int j = 0; j < 4; ++j)
2353  {
2354  info.data[index] = imuIntrinsics.data[i][j];
2355  ++index;
2356  }
2357  info.noise_variances[i] = imuIntrinsics.noise_variances[i];
2358  info.bias_variances[i] = imuIntrinsics.bias_variances[i];
2359  }
2360  return info;
2361 }
2362 
2364  const stream_index_pair& stream,
2365  std::map<stream_index_pair, cv::Mat>& images,
2366  const std::map<stream_index_pair, ros::Publisher>& info_publishers,
2367  const std::map<stream_index_pair, ImagePublisherWithFrequencyDiagnostics>& image_publishers,
2368  const bool is_publishMetadata,
2369  std::map<stream_index_pair, int>& seq,
2370  std::map<stream_index_pair, sensor_msgs::CameraInfo>& camera_info,
2371  const std::map<rs2_stream, std::string>& encoding,
2372  bool copy_data_from_frame)
2373 {
2374  ROS_DEBUG("publishFrame(...)");
2375  unsigned int width = 0;
2376  unsigned int height = 0;
2377  auto bpp = 1;
2378  if (f.is<rs2::video_frame>())
2379  {
2380  auto image = f.as<rs2::video_frame>();
2381  width = image.get_width();
2382  height = image.get_height();
2383  bpp = image.get_bytes_per_pixel();
2384  }
2385  auto& image = images[stream];
2386 
2387  if (copy_data_from_frame)
2388  {
2389  if (images[stream].size() != cv::Size(width, height))
2390  {
2391  image.create(height, width, image.type());
2392  }
2393  image.data = (uint8_t*)f.get_data();
2394  }
2395  if (f.is<rs2::depth_frame>())
2396  {
2398  }
2399 
2400  ++(seq[stream]);
2401  auto& info_publisher = info_publishers.at(stream);
2402  auto& image_publisher = image_publishers.at(stream);
2403 
2404  image_publisher.second->tick();
2405  if(0 != info_publisher.getNumSubscribers() ||
2406  0 != image_publisher.first.getNumSubscribers())
2407  {
2408  auto& cam_info = camera_info.at(stream);
2409  if (cam_info.width != width)
2410  {
2412  }
2413  cam_info.header.stamp = t;
2414  cam_info.header.seq = seq[stream];
2415  info_publisher.publish(cam_info);
2416 
2418  img = cv_bridge::CvImage(std_msgs::Header(), encoding.at(stream.first), image).toImageMsg();
2419  img->width = width;
2420  img->height = height;
2421  img->is_bigendian = false;
2422  img->step = width * bpp;
2423  img->header.frame_id = cam_info.header.frame_id;
2424  img->header.stamp = t;
2425  img->header.seq = seq[stream];
2426 
2427  image_publisher.first.publish(img);
2428  ROS_DEBUG("%s stream published", rs2_stream_to_string(f.get_profile().stream_type()));
2429  }
2430  if (is_publishMetadata)
2431  {
2432  auto& cam_info = camera_info.at(stream);
2433  publishMetadata(f, t, cam_info.header.frame_id);
2434  }
2435 }
2436 
2437 void BaseRealSenseNode::publishMetadata(rs2::frame f, const ros::Time& header_time, const std::string& frame_id)
2438 {
2440  if (_metadata_publishers.find(stream) != _metadata_publishers.end())
2441  {
2442  auto& md_publisher = _metadata_publishers.at(stream);
2443  if (0 != md_publisher->getNumSubscribers())
2444  {
2445  realsense2_camera::Metadata msg;
2446  msg.header.frame_id = frame_id;
2447  msg.header.stamp = header_time;
2448  std::stringstream json_data;
2449  const char* separator = ",";
2450  json_data << "{";
2451  // Add additional fields:
2452  json_data << "\"" << "frame_number" << "\":" << f.get_frame_number();
2453  json_data << separator << "\"" << "clock_domain" << "\":" << "\"" << create_graph_resource_name(rs2_timestamp_domain_to_string(f.get_frame_timestamp_domain())) << "\"";
2454  json_data << separator << "\"" << "frame_timestamp" << "\":" << std::fixed << f.get_timestamp();
2455 
2456  for (auto i = 0; i < RS2_FRAME_METADATA_COUNT; i++)
2457  {
2459  {
2463  {
2464  name = "hw_timestamp";
2465  }
2467  json_data << separator << "\"" << name << "\":" << val;
2468  }
2469  }
2470  json_data << "}";
2471  msg.json_data = json_data.str();
2472  md_publisher->publish(msg);
2473  }
2474  }
2475 }
2476 
2478 {
2479  // Assuming that all D400 SKUs have depth sensor
2480  auto profiles = _enabled_profiles[stream_index];
2481  auto it = std::find_if(profiles.begin(), profiles.end(),
2482  [&](const rs2::stream_profile& profile)
2483  { return (profile.stream_type() == stream_index.first); });
2484  if (it == profiles.end())
2485  return false;
2486 
2487  profile = *it;
2488  return true;
2489 }
2490 
2492 {
2494  {
2495  _temperature_nodes.push_back({option, std::make_shared<TemperatureDiagnostics>(rs2_option_to_string(option), _serial_no )});
2496  }
2497 
2498  int time_interval(1000);
2499  std::function<void()> func = [this, time_interval](){
2500  std::mutex mu;
2501  std::unique_lock<std::mutex> lock(mu);
2502  while(_is_running) {
2503  _cv_monitoring.wait_for(lock, std::chrono::milliseconds(time_interval), [&]{return !_is_running;});
2504  if (_is_running)
2505  {
2508  }
2509  }
2510  };
2511  _monitoring_t = std::make_shared<std::thread>(func);
2512 }
2513 
2515 {
2517  for (OptionTemperatureDiag option_diag : _temperature_nodes)
2518  {
2519  rs2_option option(option_diag.first);
2520  if (sensor.supports(option))
2521  {
2522  try
2523  {
2524  auto option_value = sensor.get_option(option);
2525  option_diag.second->update(option_value);
2526  }
2527  catch(const std::exception& e)
2528  {
2529  ROS_DEBUG_STREAM("Failed checking for temperature." << std::endl << e.what());
2530  }
2531  }
2532  }
2533 }
2534 
2536 {
2537  std::chrono::milliseconds timespan(1);
2538  for (auto &image_publisher : _image_publishers)
2539  {
2540  image_publisher.second.second->update();
2541  std::this_thread::sleep_for(timespan);
2542  }
2543 }
2544 
2545 TemperatureDiagnostics::TemperatureDiagnostics(std::string name, std::string serial_no)
2546  {
2547  _updater.add(name, this, &TemperatureDiagnostics::diagnostics);
2548  _updater.setHardwareID(serial_no);
2549  }
2550 
2552 {
2553  status.summary(0, "OK");
2554  status.add("Index", _crnt_temp);
2555 }
2556 
2558 {
2559  _device_info_srv = std::make_shared<ros::ServiceServer>(_pnh.advertiseService("device_info", &BaseRealSenseNode::getDeviceInfo, this));
2560 }
2561 
2562 bool BaseRealSenseNode::getDeviceInfo(realsense2_camera::DeviceInfo::Request&,
2563  realsense2_camera::DeviceInfo::Response& res)
2564 {
2570 
2571  std::stringstream sensors_names;
2572  for(auto&& sensor : _dev_sensors)
2573  {
2574  sensors_names << create_graph_resource_name(sensor.get_info(RS2_CAMERA_INFO_NAME)) << ",";
2575  }
2576 
2577  res.sensors = sensors_names.str().substr(0, sensors_names.str().size()-1);
2578  return true;
2579 }
std::map< stream_index_pair, cv::Mat > _depth_aligned_image
void FillImuData_Copy(const CimuData imu_data, std::deque< sensor_msgs::Imu > &imu_msgs)
std::map< stream_index_pair, int > _seq
RS2_OPTION_COUNT
msg
iterator begin() const
RS2_LOG_SEVERITY_ERROR
int get_bytes_per_pixel() const
RS2_OPTION_PROJECTOR_TEMPERATURE
std::map< rs2_stream, int > _image_format
BaseRealSenseNode(ros::NodeHandle &nodeHandle, ros::NodeHandle &privateNodeHandle, rs2::device dev, const std::string &serial_no)
bool is() const
const std::vector< stream_index_pair > IMAGE_STREAMS
GLboolean GLboolean GLboolean b
const std::string DEFAULT_BASE_FRAME_ID
Definition: constants.h:71
GLint y
void load_json(const std::string &json_content) const
void clip_depth(rs2::depth_frame depth_frame, float clipping_dist)
bool supports(rs2_option option) const
cv::Mat & fix_depth_scale(const cv::Mat &from_image, cv::Mat &to_image)
void registerAutoExposureROIOptions(ros::NodeHandle &nh)
TemperatureDiagnostics(std::string name, std::string serial_no)
tf2_ros::StaticTransformBroadcaster _static_tf_broadcaster
RS2_CAMERA_INFO_PHYSICAL_PORT
Quaternion inverse() const
U1 type
const bool ALIGN_DEPTH
Definition: constants.h:45
std::vector< sensor > query_sensors() const
const char * get_info(rs2_camera_info info) const
rs2_option
_linear_acceleration_type linear_acceleration
const std::string DEFAULT_ODOM_FRAME_ID
Definition: constants.h:72
void ImuMessage_AddDefaultValues(sensor_msgs::Imu &imu_msg)
unsigned int tracker_confidence
GLdouble s
const std::string DEFAULT_IMU_OPTICAL_FRAME_ID
Definition: constants.h:87
RS2_TIMESTAMP_DOMAIN_HARDWARE_CLOCK
def info(args)
rs2_format format() const
void start(T callback) const
void publishPointCloud(rs2::points f, const ros::Time &t, const rs2::frameset &frameset)
const GLfloat * m
std::map< stream_index_pair, ros::Publisher > _info_publisher
RS2_CAMERA_INFO_SERIAL_NUMBER
RS2_OPTION_SEQUENCE_SIZE
float translation[3]
tf2_ros::TransformBroadcaster _dynamic_tf_broadcaster
void summary(unsigned char lvl, const std::string s)
std::map< stream_index_pair, rs2_intrinsics > _stream_intrinsics
const bool PUBLISH_ODOM_TF
Definition: constants.h:68
RS2_OPTION_SEQUENCE_ID
RS2_CAMERA_INFO_PRODUCT_ID
double dt
RS2_OPTION_HDR_ENABLED
void reverse_memcpy(unsigned char *dst, const unsigned char *src, size_t n)
bool call(const std::string &service_name, MReq &req, MRes &res)
RS2_STREAM_FISHEYE
RS2_FORMAT_Z16
void set_sensor_parameter_to_ros(const std::string &module_name, rs2::options sensor, rs2_option option)
rs2_vector translation
const std::string DEFAULT_UNITE_IMU_METHOD
Definition: constants.h:94
#define OPTICAL_FRAME_ID(sip)
_orientation_type orientation
virtual void registerDynamicReconfigCb(ros::NodeHandle &nh) override
RS2_STREAM_POSE
Publisher advertise(const std::string &base_topic, uint32_t queue_size, bool latch=false)
GLenum GLenum dst
RS2_DISTORTION_KANNALA_BRANDT4
RS2_OPTION_ASIC_TEMPERATURE
Extrinsics rsExtrinsicsToMsg(const rs2_extrinsics &extrinsics, const std::string &frame_id) const
_angular_velocity_covariance_type angular_velocity_covariance
struct Vertex vertex[VERTEXNUM]
std::shared_ptr< rs2::filter > _pointcloud_filter
unsigned short uint16_t
RS2_FRAME_METADATA_COUNT
const stream_index_pair INFRA2
double get_timestamp() const
RS2_CAMERA_INFO_NAME
static void vector3TFToMsg(const Vector3 &bt_v, geometry_msgs::Vector3 &msg_v)
virtual void toggleSensors(bool enabled) override
bool is() const
_orientation_type orientation
size_t size() const
std::shared_ptr< std::thread > _update_functions_t
const char * get_option_description(rs2_option option) const
GLuint GLuint stream
GLenum src
IMUInfo getImuInfo(const stream_index_pair &stream_index)
RS2_STREAM_GYRO
RS2_OPTION_DEPTH_UNITS
std::map< rs2_stream, bool > _is_first_frame
GLdouble n
unsigned char uint8_t
const char * rs2_stream_to_string(rs2_stream stream)
rs2_vector angular_velocity
std::map< stream_index_pair, ImagePublisherWithFrequencyDiagnostics > _image_publishers
e
bool deleteParam(const std::string &key) const
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
rs2_notification_category get_category() const
float rotation[9]
#define ROS_WARN(...)
void registerDynamicOption(ros::NodeHandle &nh, rs2::options sensor, std::string &module_name)
GLenum GLenum GLsizei void * image
void imu_callback_sync(rs2::frame frame, imu_sync_method sync_method=imu_sync_method::COPY)
std::queue< sensor_msgs::Imu > _pending_messages
std::pair< rs2_option, std::shared_ptr< TemperatureDiagnostics > > OptionTemperatureDiag
status
GLuint index
std::map< stream_index_pair, sensor_msgs::CameraInfo > _depth_aligned_camera_info
RS2_STREAM_COLOR
rs2_extrinsics get_extrinsics_to(const stream_profile &to) const
GLdouble t
std::vector< OptionTemperatureDiag > _temperature_nodes
GLboolean GLboolean GLboolean GLboolean a
T as() const
_position_type position
GLuint GLfloat * val
RS2_FORMAT_RGB8
float get_option(rs2_option option) const
std::map< stream_index_pair, rs2::sensor > _sensors
tf::Quaternion rotationMatrixToQuaternion(const float rotation[9]) const
not_this_one begin(...)
std::map< stream_index_pair, int > _width
bool getDeviceInfo(realsense2_camera::DeviceInfo::Request &req, realsense2_camera::DeviceInfo::Response &res)
bool is_checkbox(rs2::options sensor, rs2_option option)
GLdouble f
double get_timestamp() const
void open(const stream_profile &profile) const
void publishMetadata(rs2::frame f, const ros::Time &header_time, const std::string &frame_id)
std::pair< rs2_stream, int > stream_index_pair
Definition: constants.h:99
void updateStreamCalibData(const rs2::video_stream_profile &video_profile)
std::map< std::string, int > get_enum_method(rs2::options sensor, rs2_option option)
GLfloat GLfloat GLfloat alpha
const stream_index_pair CONFIDENCE
const bool PUBLISH_TF
Definition: constants.h:51
sensor_msgs::PointCloud2 _msg_pointcloud
#define STREAM_NAME(sip)
rs2_vector velocity
dictionary streams
GLsizeiptr size
bool is_enum_option(rs2::options sensor, rs2_option option)
T lerp(const T &a, const T &b, const double t)
std::shared_ptr< rs2::filter > _colorizer
const char * rs2_option_to_string(rs2_option option)
D const & i
std::map< stream_index_pair, std::shared_ptr< ros::Publisher > > _metadata_publishers
const GLubyte * c
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::map< stream_index_pair, rs2_extrinsics > _depth_to_other_extrinsics
void publish(const boost::shared_ptr< M > &message) const
TFSIMD_FORCE_INLINE const tfScalar & getW() const
GLdouble x
std::map< rs2_stream, std::string > _encoding
static void vector3MsgToTF(const geometry_msgs::Vector3 &msg_v, Vector3 &bt_v)
ROSCPP_DECL const std::string & getNamespace()
_point_step_type point_step
std::map< stream_index_pair, bool > _enable
RS2_CAMERA_INFO_USB_TYPE_DESCRIPTOR
const stream_index_pair GYRO
void hardware_reset()
T
std::map< stream_index_pair, cv::Mat > _image
RS2_STREAM_CONFIDENCE
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)
std::shared_ptr< std::thread > _tf_t
GLint GLsizei GLsizei height
#define ROS_WARN_ONCE(...)
std::map< rs2_stream, std::vector< std::function< void()> > > _video_functions_stack
#define ROS_INFO(...)
const stream_index_pair DEPTH
_child_frame_id_type child_frame_id
rs2_quaternion rotation
rs2_timestamp_domain get_frame_timestamp_domain() const
std::shared_ptr< SyncedImuPublisher > _synced_imu_publisher
profiles
const char * rs2_format_to_string(rs2_format format)
T as() const
std::string create_graph_resource_name(const std::string &original_name)
GLenum GLenum GLsizei const GLuint GLboolean enabled
const char * get_option_value_description(rs2_option option, float val) const
ROSCPP_DECL bool ok()
GLint j
const std::string TYPE_16UC1
RS2_OPTION_GAIN
T as() const
rs2_format
float get_depth_scale(rs2::device dev)
std::map< rs2_stream, std::string > _stream_name
std::shared_ptr< ros::ServiceServer > _device_info_srv
#define ROS_WARN_STREAM_COND(cond, args)
RS2_CAMERA_INFO_FIRMWARE_VERSION
TFSIMD_FORCE_INLINE Vector3 quatRotate(const Quaternion &rotation, const Vector3 &v)
std::string resolveName(const std::string &name, bool remap=true) const
void start(S on_frame)
GLint void * img
void publishFrame(rs2::frame f, const ros::Time &t, const stream_index_pair &stream, std::map< stream_index_pair, cv::Mat > &images, const std::map< stream_index_pair, ros::Publisher > &info_publishers, const std::map< stream_index_pair, ImagePublisherWithFrequencyDiagnostics > &image_publishers, const bool is_publishMetadata, std::map< stream_index_pair, int > &seq, std::map< stream_index_pair, sensor_msgs::CameraInfo > &camera_info, const std::map< rs2_stream, std::string > &encoding, bool copy_data_from_frame=true)
sensor
int stream_index() const
std::map< stream_index_pair, ImagePublisherWithFrequencyDiagnostics > _depth_aligned_image_publishers
std::map< stream_index_pair, cv::Mat > _depth_scaled_image
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void multiple_message_callback(rs2::frame frame, imu_sync_method sync_method)
const texture_coordinate * get_texture_coordinates() const
rs2_stream rs2_string_to_stream(std::string str)
RS2_STREAM_DEPTH
GLenum func
const int IMU_FPS
Definition: constants.h:58
rs2_stream
#define ROS_WARN_STREAM(args)
void sendTransform(const geometry_msgs::TransformStamped &transform)
#define ROS_DEBUG_STREAM(args)
int get_height() const
bool is() const
const bool ALLOW_NO_TEXTURE_POINTS
Definition: constants.h:47
RS2_FRAME_METADATA_FRAME_TIMESTAMP
RS2_STREAM_INFRARED
unsigned long long get_frame_number() const
bool getEnabledProfile(const stream_index_pair &stream_index, rs2::stream_profile &profile)
RS2_STREAM_ACCEL
rs2_format format
iterator end() const
const bool POINTCLOUD
Definition: constants.h:46
_angular_velocity_type angular_velocity
std::map< stream_index_pair, std::vector< rs2::stream_profile > > _enabled_profiles
#define ROS_INFO_STREAM_ONCE(args)
const int IMAGE_FPS
Definition: constants.h:56
const int IMAGE_WIDTH
Definition: constants.h:54
bpp
GLdouble GLdouble GLdouble q
int get_width() const
rs2_log_severity get_severity() const
const void * get_data() const
bool is_option_read_only(rs2_option option) const
std::map< stream_index_pair, ros::Publisher > _imu_publishers
virtual void calcAndPublishStaticTransform(const stream_index_pair &stream, const rs2::stream_profile &base_profile)
bool supports(rs2_camera_info info) const
GLboolean enable
void diagnostics(diagnostic_updater::DiagnosticStatusWrapper &status)
#define ROS_INFO_STREAM(args)
RS2_STREAM_ANY
std::map< stream_index_pair, ros::Publisher > _depth_to_other_extrinsics_publishers
GLuint in
long long rs2_metadata_type
std::vector< rs2_option > _monitor_options
std::vector< std::function< void()> > _update_functions_v
const char * rs2_frame_metadata_to_string(rs2_frame_metadata_value metadata)
std::map< stream_index_pair, std::string > _frame_id
std::map< stream_index_pair, int > _height
option_range get_option_range(rs2_option option) const
void set_option(rs2_option option, float value) const
const stream_index_pair ACCEL
const stream_index_pair POSE
void set_sensor_auto_exposure_roi(rs2::sensor sensor)
std::map< stream_index_pair, sensor_msgs::CameraInfo > _camera_info
const bool SYNC_FRAMES
Definition: constants.h:49
_orientation_covariance_type orientation_covariance
void readAndSetDynamicParam(ros::NodeHandle &nh1, std::shared_ptr< ddynamic_reconfigure::DDynamicReconfigure > ddynrec, const std::string option_name, const int min_val, const int max_val, rs2::sensor sensor, int *option_value)
RS2_OPTION_EXPOSURE
std::map< rs2_stream, int > _unit_step_size
_frame_id_type frame_id
const double TF_PUBLISH_RATE
Definition: constants.h:52
std::shared_ptr< std::thread > _monitoring_t
str(const bytes &b)
void publish_static_tf(const ros::Time &t, const float3 &trans, const tf::Quaternion &q, const std::string &from, const std::string &to)
static Time now()
_linear_acceleration_covariance_type linear_acceleration_covariance
std::vector< geometry_msgs::TransformStamped > _static_tf_msgs
const bool ORDERED_POINTCLOUD
Definition: constants.h:48
std::map< rs2_stream, std::string > _depth_aligned_encoding
ROSCPP_DECL void shutdown()
const std::vector< stream_index_pair > HID_STREAMS
std::map< stream_index_pair, int > _fps
const bool HOLD_BACK_IMU_FOR_FRAMES
Definition: constants.h:67
_translation_type translation
std::map< std::string, std::function< void(rs2::frame)> > _sensors_callback
std::vector< rs2::sensor > _dev_sensors
RS2_CAMERA_INFO_FIRMWARE_UPDATE_ID
void runFirstFrameInitialization(rs2_stream stream_type)
std::vector< std::shared_ptr< ddynamic_reconfigure::DDynamicReconfigure > > _ddynrec
GLuint res
void add(const std::string &key, const T &val)
std::map< stream_index_pair, int > _depth_aligned_seq
_stamp_type stamp
const stream_index_pair FISHEYE
std::condition_variable _update_functions_cv
std::string get_description() const
const stream_index_pair COLOR
#define ROS_ERROR_STREAM(args)
rs2_metadata_type get_frame_metadata(rs2_frame_metadata_value frame_metadata) const
std::map< std::string, rs2::region_of_interest > _auto_exposure_roi
bool isValidCharInName(char c)
sensor_msgs::Imu CreateUnitedMessage(const CimuData accel_data, const CimuData gyro_data)
const stream_index_pair INFRA1
rs2_format format
void sendTransform(const geometry_msgs::TransformStamped &transform)
bool setBaseTime(double frame_time, rs2_timestamp_domain time_domain)
uint32_t getNumSubscribers() const
rs2::stream_profile getAProfile(const stream_index_pair &stream)
void setPointCloud2FieldsByString(int n_fields,...)
const char * rs2_timestamp_domain_to_string(rs2_timestamp_domain info)
bool supports_frame_metadata(rs2_frame_metadata_value frame_metadata) const
::sensor_msgs::Imu_< std::allocator< void > > Imu
rs2_stream stream_type() const
rs2_intrinsics get_intrinsics() const
std::map< stream_index_pair, ros::Publisher > _depth_aligned_info_publisher
std::map< stream_index_pair, std::string > _optical_frame_id
#define ALIGNED_DEPTH_TO_FRAME_ID(sip)
const float ROS_DEPTH_SCALE
Definition: constants.h:98
bool is_int_option(rs2::options sensor, rs2_option option)
const bool ENABLE_IMU
Definition: constants.h:66
GLdouble v
_header_type header
const char * get_info(rs2_camera_info info) const
RS2_TIMESTAMP_DOMAIN_SYSTEM_TIME
void set_auto_exposure_roi(const std::string option_name, rs2::sensor sensor, int new_value)
const int IMAGE_HEIGHT
Definition: constants.h:55
rs2_frame_metadata_value
const std::string DEFAULT_FILTERS
Definition: constants.h:95
std::map< stream_index_pair, std::string > _depth_aligned_frame_id
void FillImuData_LinearInterpolation(const CimuData imu_data, std::deque< sensor_msgs::Imu > &imu_msgs)
GLint GLsizei width
RS2_FORMAT_Y8
std::shared_ptr< ::sensor_msgs::Image > ImagePtr
Q
GLintptr offset
stream_profile get_profile() const
#define ROS_DEBUG(...)
std::map< rs2_stream, int > _format
const vertex * get_vertices() const
std::string to_string(T value)
#define FRAME_ID(sip)
rs2_timestamp_domain


realsense2_camera
Author(s): Sergey Dorodnicov , Doron Hirshberg
autogenerated on Thu Mar 24 2022 02:12:40