Swarm-SLAM  1.0.0
C-SLAM Framework
rgbd_handler.cpp
Go to the documentation of this file.
2 #include <rtabmap_conversions/MsgConversion.h>
3 
4 // For visualization
5 #include <pcl_conversions/pcl_conversions.h>
6 #include <pcl/PCLPointCloud2.h>
7 #include <pcl/point_types.h>
8 #include <pcl/filters/voxel_grid.h>
9 #include <pcl/filters/passthrough.h>
10 
11 using namespace rtabmap;
12 using namespace cslam;
13 
14 #define MAP_FRAME_ID(id) "robot" + std::to_string(id) + "_map"
15 
16 RGBDHandler::RGBDHandler(std::shared_ptr<rclcpp::Node> &node)
17  : node_(node)
18 {
19  node_->declare_parameter<std::string>("frontend.color_image_topic", "color/image");
20  node_->declare_parameter<std::string>("frontend.depth_image_topic", "depth/image");
21  node_->declare_parameter<std::string>("frontend.color_camera_info_topic",
22  "color/camera_info");
23  node->declare_parameter<std::string>("frontend.odom_topic", "odom");
24  node->declare_parameter<float>("frontend.keyframe_generation_ratio_threshold", 0.0);
25  node->declare_parameter<std::string>("frontend.sensor_base_frame_id", ""); // If empty we assume that the camera link is the base link
26  node->declare_parameter<bool>("evaluation.enable_logs", false);
27  node_->get_parameter("frontend.max_queue_size", max_queue_size_);
28  node_->get_parameter("frontend.keyframe_generation_ratio_threshold", keyframe_generation_ratio_threshold_);
29  node_->get_parameter("frontend.sensor_base_frame_id", base_frame_id_);
30  node_->get_parameter("visualization.enable",
32  node_->get_parameter("visualization.publishing_period_ms",
34  node_->get_parameter("visualization.voxel_size",
36  node_->get_parameter("visualization.max_range",
38 
39  node_->get_parameter("evaluation.enable_logs",
40  enable_logs_);
41  node->get_parameter("evaluation.enable_gps_recording",
43  node->get_parameter("evaluation.gps_topic",
44  gps_topic_);
45 
47  {
49  }
50  else
51  {
53  }
54 
56 
57  sub_odometry_.subscribe(node_.get(),
58  node_->get_parameter("frontend.odom_topic").as_string(),
59  rclcpp::QoS(max_queue_size_)
60  .reliability((rmw_qos_reliability_policy_t)2)
61  .get_rmw_qos_profile());
62 
63  // Service to extract and publish local image descriptors to another robot
64  send_local_descriptors_subscriber_ = node_->create_subscription<
65  cslam_common_interfaces::msg::LocalDescriptorsRequest>(
66  "cslam/local_descriptors_request", 100,
68  std::placeholders::_1));
69 
70  // Parameters
71  node_->get_parameter("frontend.max_queue_size", max_queue_size_);
72  node_->get_parameter("frontend.pnp_min_inliers", min_inliers_);
73  node_->get_parameter("max_nb_robots", max_nb_robots_);
74  node_->get_parameter("robot_id", robot_id_);
75 
76  // Publisher for global descriptors
78  node_->create_publisher<cslam_common_interfaces::msg::KeyframeRGB>(
79  "cslam/keyframe_data", 100);
80 
81  // Publisher for odometry with ID
83  node_->create_publisher<cslam_common_interfaces::msg::KeyframeOdom>(
84  "cslam/keyframe_odom", 100);
85 
86  // Local matches subscription
87  local_keyframe_match_subscriber_ = node->create_subscription<
88  cslam_common_interfaces::msg::LocalKeyframeMatch>(
89  "cslam/local_keyframe_match", 100,
91  std::placeholders::_1));
92 
93  // Publishers to other robots local descriptors subscribers
94  std::string local_descriptors_topic = "/cslam/local_descriptors";
95  local_descriptors_publisher_ = node_->create_publisher<
96  cslam_common_interfaces::msg::LocalImageDescriptors>(local_descriptors_topic, 100);
97 
99  {
101  cslam_common_interfaces::msg::LocalImageDescriptors>("/cslam/viz/local_descriptors", 100);
102 
103  keyframe_pointcloud_publisher_ = node_->create_publisher<cslam_common_interfaces::msg::VizPointCloud>(
104  "/cslam/viz/keyframe_pointcloud", 100);
105  }
106 
107  // Subscriber for local descriptors
108  local_descriptors_subscriber_ = node->create_subscription<
109  cslam_common_interfaces::msg::LocalImageDescriptors>(
110  "/cslam/local_descriptors", 100,
112  std::placeholders::_1));
113 
114  // Registration settings
115  rtabmap::ParametersMap registration_params;
116  registration_params.insert(rtabmap::ParametersPair(
117  rtabmap::Parameters::kVisMinInliers(), std::to_string(min_inliers_)));
118  registration_.parseParameters(registration_params);
119 
120  // Intra-robot loop closure publisher
121  intra_robot_loop_closure_publisher_ = node_->create_publisher<
122  cslam_common_interfaces::msg::IntraRobotLoopClosure>(
123  "cslam/intra_robot_loop_closure", 100);
124 
125  // Publisher for inter robot loop closure to all robots
126  inter_robot_loop_closure_publisher_ = node_->create_publisher<
127  cslam_common_interfaces::msg::InterRobotLoopClosure>(
128  "/cslam/inter_robot_loop_closure", 100);
129 
130  tf_buffer_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
131  tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
132 
133  // Subscriber for RGBD images
134  sub_image_color_.subscribe(
135  node_.get(), node_->get_parameter("frontend.color_image_topic").as_string(), "raw",
136  rclcpp::QoS(max_queue_size_)
137  .reliability((rmw_qos_reliability_policy_t)2)
138  .get_rmw_qos_profile());
139  sub_image_depth_.subscribe(
140  node_.get(), node_->get_parameter("frontend.depth_image_topic").as_string(), "raw",
141  rclcpp::QoS(max_queue_size_)
142  .reliability((rmw_qos_reliability_policy_t)2)
143  .get_rmw_qos_profile());
144  sub_camera_info_color_.subscribe(
145  node_.get(), node_->get_parameter("frontend.color_camera_info_topic").as_string(),
146  rclcpp::QoS(max_queue_size_)
147  .reliability((rmw_qos_reliability_policy_t)2)
148  .get_rmw_qos_profile());
149 
150  rgbd_sync_policy_ = new message_filters::Synchronizer<RGBDSyncPolicy>(
151  RGBDSyncPolicy(max_queue_size_), sub_image_color_, sub_image_depth_,
152  sub_camera_info_color_, sub_odometry_);
153  rgbd_sync_policy_->registerCallback(
154  std::bind(&RGBDHandler::rgbd_callback, this, std::placeholders::_1,
155  std::placeholders::_2, std::placeholders::_3,
156  std::placeholders::_4));
157 
159  {
160  gps_subscriber_ = node_->create_subscription<sensor_msgs::msg::NavSatFix>(
161  gps_topic_, 100,
162  std::bind(&RGBDHandler::gps_callback, this,
163  std::placeholders::_1));
164  }
165 
166  if (enable_logs_){
168  log_publisher_ = node_->create_publisher<diagnostic_msgs::msg::KeyValue>(
169  "cslam/log_info", 100);
170  }
171 }
172 
174  const sensor_msgs::msg::Image::ConstSharedPtr image_rect_rgb,
175  const sensor_msgs::msg::Image::ConstSharedPtr image_rect_depth,
176  const sensor_msgs::msg::CameraInfo::ConstSharedPtr camera_info_rgb,
177  const nav_msgs::msg::Odometry::ConstSharedPtr odom)
178 {
179  // If odom tracking failed, do not process the frame
180  if (odom->pose.covariance[0] > 1000)
181  {
182  RCLCPP_WARN(node_->get_logger(), "Odom tracking failed, skipping frame");
183  return;
184  }
185 
186  if (!(image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::TYPE_8UC1) == 0 ||
187  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::MONO8) == 0 ||
188  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0 ||
189  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::BGR8) == 0 ||
190  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::RGB8) == 0 ||
191  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::BGRA8) == 0 ||
192  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::RGBA8) == 0 ||
193  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::BAYER_GRBG8) == 0) ||
194  !(image_rect_depth->encoding.compare(sensor_msgs::image_encodings::TYPE_16UC1) == 0 ||
195  image_rect_depth->encoding.compare(sensor_msgs::image_encodings::TYPE_32FC1) == 0 ||
196  image_rect_depth->encoding.compare(sensor_msgs::image_encodings::MONO16) == 0))
197  {
198  RCLCPP_ERROR(node_->get_logger(), "Input type must be image=mono8,mono16,rgb8,bgr8,bgra8,rgba8 and "
199  "image_depth=32FC1,16UC1,mono16. Current rgb=%s and depth=%s",
200  image_rect_rgb->encoding.c_str(),
201  image_rect_depth->encoding.c_str());
202  return;
203  }
204 
205  rclcpp::Time stamp = rtabmap_conversions::timestampFromROS(image_rect_rgb->header.stamp) > rtabmap_conversions::timestampFromROS(image_rect_depth->header.stamp) ? image_rect_rgb->header.stamp : image_rect_depth->header.stamp;
206 
207  Transform local_transform(0,0,0,0,0,0);
208  if (base_frame_id_ != "")
209  {
210  local_transform = rtabmap_conversions::getTransform(base_frame_id_, image_rect_rgb->header.frame_id, stamp, *tf_buffer_, 0.1);
211  if (local_transform.isNull())
212  {
213  return;
214  }
215  }
216 
217  cv_bridge::CvImageConstPtr ptr_image = cv_bridge::toCvShare(image_rect_rgb);
218  if (image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::TYPE_8UC1) != 0 &&
219  image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::MONO8) != 0)
220  {
221  if (image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::MONO16) != 0)
222  {
223  ptr_image = cv_bridge::cvtColor(ptr_image, "bgr8");
224  }
225  else
226  {
227  ptr_image = cv_bridge::cvtColor(ptr_image, "mono8");
228  }
229  }
230 
231  cv_bridge::CvImageConstPtr ptr_depth = cv_bridge::toCvShare(image_rect_depth);
232 
233  CameraModel camera_model = rtabmap_conversions::cameraModelFromROS(*camera_info_rgb, local_transform);
234 
235  // copy data
236  cv::Mat rgb, depth;
237  ptr_image->image.copyTo(rgb);
238  ptr_depth->image.copyTo(depth);
239 
240  auto data = std::make_shared<rtabmap::SensorData>(
241  rgb, depth,
242  camera_model,
243  0,
244  rtabmap_conversions::timestampFromROS(stamp));
245 
246  received_data_queue_.push_back(std::make_pair(data, odom));
248  {
249  // Remove the oldest keyframes if we exceed the maximum size
250  received_data_queue_.pop_front();
251  RCLCPP_WARN(
252  node_->get_logger(),
253  "RGBD: Maximum queue size (%d) exceeded, the oldest element was removed.",
255  }
256 
257  if (enable_gps_recording_) {
260  {
261  received_gps_queue_.pop_front();
262  }
263  }
264 }
265 
267  std::shared_ptr<rtabmap::SensorData> &frame_data)
268 {
269  // Extract local descriptors
270  frame_data->uncompressData();
271  std::vector<cv::KeyPoint> kpts_from;
272  cv::Mat image = frame_data->imageRaw();
273  if (image.channels() > 1)
274  {
275  cv::Mat tmp;
276  cv::cvtColor(image, tmp, cv::COLOR_BGR2GRAY);
277  image = tmp;
278  }
279 
280  cv::Mat depth_mask;
281  if (!frame_data->depthRaw().empty())
282  {
283  if (image.rows % frame_data->depthRaw().rows == 0 &&
284  image.cols % frame_data->depthRaw().cols == 0 &&
285  image.rows / frame_data->depthRaw().rows ==
286  frame_data->imageRaw().cols / frame_data->depthRaw().cols)
287  {
288  depth_mask = rtabmap::util2d::interpolate(
289  frame_data->depthRaw(),
290  frame_data->imageRaw().rows / frame_data->depthRaw().rows, 0.1f);
291  }
292  else
293  {
294  UWARN("%s is true, but RGB size (%dx%d) modulo depth size (%dx%d) is "
295  "not 0. Ignoring depth mask for feature detection.",
296  rtabmap::Parameters::kVisDepthAsMask().c_str(),
297  frame_data->imageRaw().rows, frame_data->imageRaw().cols,
298  frame_data->depthRaw().rows, frame_data->depthRaw().cols);
299  }
300  }
301 
302  rtabmap::ParametersMap registration_params;
303  registration_params.insert(rtabmap::ParametersPair(
304  rtabmap::Parameters::kVisMinInliers(), std::to_string(min_inliers_)));
305  auto detector = rtabmap::Feature2D::create(registration_params);
306 
307  auto kpts = detector->generateKeypoints(image, depth_mask);
308  auto descriptors = detector->generateDescriptors(image, kpts);
309  auto kpts3D = detector->generateKeypoints3D(*frame_data, kpts);
310 
311  frame_data->setFeatures(kpts, kpts3D, descriptors);
312 }
313 
314 bool RGBDHandler::generate_new_keyframe(std::shared_ptr<rtabmap::SensorData> &keyframe)
315 {
316  // Keyframe generation heuristic
317  bool generate_new_keyframe = true;
319  {
320  if (nb_local_keyframes_ > 0)
321  {
322  try
323  {
324  rtabmap::RegistrationInfo reg_info;
325  rtabmap::Transform t = registration_.computeTransformation(
326  *keyframe, *previous_keyframe_, rtabmap::Transform(), &reg_info);
327  if (!t.isNull())
328  {
329  if (float(reg_info.inliers) >
331  float(previous_keyframe_->keypoints().size()))
332  {
333  generate_new_keyframe = false;
334  }
335  }
336  }
337  catch (std::exception &e)
338  {
339  RCLCPP_WARN(
340  node_->get_logger(),
341  "Exception: Could not compute transformation for keyframe generation: %s",
342  e.what());
343  }
344  }
346  {
347  previous_keyframe_ = keyframe;
348  }
349  }
350  return generate_new_keyframe;
351 }
352 
354 {
355  if (!received_data_queue_.empty())
356  {
357  auto sensor_data = received_data_queue_.front();
358  received_data_queue_.pop_front();
359 
360  sensor_msgs::msg::NavSatFix gps_fix;
361  if (enable_gps_recording_) {
362  gps_fix = received_gps_queue_.front();
363  received_gps_queue_.pop_front();
364  }
365 
366  if (sensor_data.first->isValid())
367  {
368  // Compute local descriptors
369  compute_local_descriptors(sensor_data.first);
370 
371  bool generate_keyframe = generate_new_keyframe(sensor_data.first);
372  if (generate_keyframe)
373  {
374  // Set keyframe ID
375  sensor_data.first->setId(nb_local_keyframes_);
377 
378  if (enable_gps_recording_) {
379  send_keyframe(sensor_data, gps_fix);
380  } else {
381  // Send keyframe for loop detection
382  send_keyframe(sensor_data);
383  }
384  }
385 
386  clear_sensor_data(sensor_data.first);
387 
388  if (generate_keyframe)
389  {
390  local_descriptors_map_.insert({sensor_data.first->id(), sensor_data.first});
391  }
392  }
393  }
394 }
395 
397  const std::shared_ptr<rtabmap::SensorData> sensor_data,
398  rtabmap_msgs::msg::RGBDImage &msg_data)
399 {
400  rtabmap_msgs::msg::RGBDImage data;
401  rtabmap_conversions::rgbdImageToROS(*sensor_data, msg_data, "camera");
402 }
403 
405  cslam_common_interfaces::msg::LocalDescriptorsRequest::
406  ConstSharedPtr request)
407 {
408  // Fill msg
409  cslam_common_interfaces::msg::LocalImageDescriptors msg;
410  clear_sensor_data(local_descriptors_map_.at(request->keyframe_id));
411  sensor_data_to_rgbd_msg(local_descriptors_map_.at(request->keyframe_id),
412  msg.data);
413  msg.keyframe_id = request->keyframe_id;
414  msg.robot_id = robot_id_;
415  msg.matches_robot_id = request->matches_robot_id;
416  msg.matches_keyframe_id = request->matches_keyframe_id;
417 
418  // Publish local descriptors
419  local_descriptors_publisher_->publish(msg);
420 
421  if (enable_logs_)
422  {
423  log_total_local_descriptors_cumulative_communication_ += msg.data.key_points.size()*28; // bytes
424  log_total_local_descriptors_cumulative_communication_ += msg.data.points.size()*12; // bytes
425  log_total_local_descriptors_cumulative_communication_ += msg.data.descriptors.size(); // bytes
426  diagnostic_msgs::msg::KeyValue log_msg;
427  log_msg.key = "local_descriptors_cumulative_communication";
428  log_msg.value = std::to_string(log_total_local_descriptors_cumulative_communication_);
429  log_publisher_->publish(log_msg);
430  }
431 }
432 
434  cslam_common_interfaces::msg::LocalKeyframeMatch::ConstSharedPtr
435  msg)
436 {
437  try
438  {
439  auto keyframe0 = local_descriptors_map_.at(msg->keyframe0_id);
440  keyframe0->uncompressData();
441  auto keyframe1 = local_descriptors_map_.at(msg->keyframe1_id);
442  keyframe1->uncompressData();
443  rtabmap::RegistrationInfo reg_info;
444  rtabmap::Transform t = registration_.computeTransformation(
445  *keyframe0, *keyframe1, rtabmap::Transform(), &reg_info);
446 
447  cslam_common_interfaces::msg::IntraRobotLoopClosure lc;
448  lc.keyframe0_id = msg->keyframe0_id;
449  lc.keyframe1_id = msg->keyframe1_id;
450  if (!t.isNull())
451  {
452  lc.success = true;
453  rtabmap_conversions::transformToGeometryMsg(t, lc.transform);
454  }
455  else
456  {
457  lc.success = false;
458  }
460  }
461  catch (std::exception &e)
462  {
463  RCLCPP_WARN(
464  node_->get_logger(),
465  "Exception: Could not compute local transformation between %d and %d: %s",
466  msg->keyframe0_id, msg->keyframe1_id,
467  e.what());
468  }
469 }
470 
472  const std::shared_ptr<
473  cslam_common_interfaces::msg::LocalImageDescriptors>
474  msg,
475  rtabmap::SensorData &sensor_data)
476 {
477  // Fill descriptors
478  rtabmap::CameraModel camera_model =
479  rtabmap_conversions::cameraModelFromROS(msg->data.rgb_camera_info,
480  rtabmap::Transform::getIdentity());
481  sensor_data = rtabmap::SensorData(
482  cv::Mat(), cv::Mat(), camera_model, 0,
483  rtabmap_conversions::timestampFromROS(msg->data.header.stamp));
484 
485  std::vector<cv::KeyPoint> kpts;
486  rtabmap_conversions::keypointsFromROS(msg->data.key_points, kpts);
487  std::vector<cv::Point3f> kpts3D;
488  rtabmap_conversions::points3fFromROS(msg->data.points, kpts3D);
489  auto descriptors = rtabmap::uncompressData(msg->data.descriptors);
490  sensor_data.setFeatures(kpts, kpts3D, descriptors);
491 }
492 
494  const std::shared_ptr<
495  cslam_common_interfaces::msg::LocalImageDescriptors>
496  msg)
497 {
498  std::deque<int> keyframe_ids;
499  for (unsigned int i = 0; i < msg->matches_robot_id.size(); i++)
500  {
501  if (msg->matches_robot_id[i] == robot_id_)
502  {
503  keyframe_ids.push_back(msg->matches_keyframe_id[i]);
504  }
505  }
506 
507  for (auto local_keyframe_id : keyframe_ids)
508  {
509  try
510  {
511  rtabmap::SensorData tmp_to;
513 
514  // Compute transformation
515  // Registration params
516  rtabmap::RegistrationInfo reg_info;
517  auto tmp_from = local_descriptors_map_.at(local_keyframe_id);
518  tmp_from->uncompressData();
519  rtabmap::Transform t = registration_.computeTransformation(
520  *tmp_from, tmp_to, rtabmap::Transform(), &reg_info);
521 
522  // Store using pairs (robot_id, keyframe_id)
523  cslam_common_interfaces::msg::InterRobotLoopClosure lc;
524  lc.robot0_id = robot_id_;
525  lc.robot0_keyframe_id = local_keyframe_id;
526  lc.robot1_id = msg->robot_id;
527  lc.robot1_keyframe_id = msg->keyframe_id;
528  if (!t.isNull())
529  {
530  lc.success = true;
531  rtabmap_conversions::transformToGeometryMsg(t, lc.transform);
533  }
534  else
535  {
536  RCLCPP_INFO(
537  node_->get_logger(),
538  "Could not compute transformation between (%d,%d) and (%d,%d): %s",
539  robot_id_, local_keyframe_id, msg->robot_id, msg->keyframe_id,
540  reg_info.rejectedMsg.c_str());
541  lc.success = false;
543  }
544  }
545  catch (std::exception &e)
546  {
547  RCLCPP_WARN(
548  node_->get_logger(),
549  "Exception: Could not compute transformation between (%d,%d) and (%d,%d): %s",
550  robot_id_, local_keyframe_id, msg->robot_id, msg->keyframe_id,
551  e.what());
552  }
553  }
554 }
555 
556 void RGBDHandler::send_keyframe(const std::pair<std::shared_ptr<rtabmap::SensorData>, std::shared_ptr<const nav_msgs::msg::Odometry>> &keypoints_data)
557 {
558  cv::Mat rgb;
559  keypoints_data.first->uncompressDataConst(&rgb, 0);
560 
561  // Image message
562  std_msgs::msg::Header header;
563  header.stamp = keypoints_data.second->header.stamp;
564  cv_bridge::CvImage image_bridge = cv_bridge::CvImage(
565  header, sensor_msgs::image_encodings::RGB8, rgb);
566  cslam_common_interfaces::msg::KeyframeRGB keyframe_msg;
567  image_bridge.toImageMsg(keyframe_msg.image);
568  keyframe_msg.id = keypoints_data.first->id();
569 
570  keyframe_data_publisher_->publish(keyframe_msg);
571 
572  // Odometry message
573  cslam_common_interfaces::msg::KeyframeOdom odom_msg;
574  odom_msg.id = keypoints_data.first->id();
575  odom_msg.odom = *keypoints_data.second;
576  keyframe_odom_publisher_->publish(odom_msg);
577 
579  {
580  send_visualization(keypoints_data);
581  }
582 }
583 
584 void RGBDHandler::send_keyframe(const std::pair<std::shared_ptr<rtabmap::SensorData>, std::shared_ptr<const nav_msgs::msg::Odometry>> &keypoints_data, const sensor_msgs::msg::NavSatFix& gps_data)
585 {
586  cv::Mat rgb;
587  keypoints_data.first->uncompressDataConst(&rgb, 0);
588 
589  // Image message
590  std_msgs::msg::Header header;
591  header.stamp = node_->now();
592  cv_bridge::CvImage image_bridge = cv_bridge::CvImage(
593  header, sensor_msgs::image_encodings::RGB8, rgb);
594  cslam_common_interfaces::msg::KeyframeRGB keyframe_msg;
595  image_bridge.toImageMsg(keyframe_msg.image);
596  keyframe_msg.id = keypoints_data.first->id();
597 
598  keyframe_data_publisher_->publish(keyframe_msg);
599 
600  // Odometry message
601  cslam_common_interfaces::msg::KeyframeOdom odom_msg;
602  odom_msg.id = keypoints_data.first->id();
603  odom_msg.odom = *keypoints_data.second;
604  odom_msg.gps = gps_data;
605  keyframe_odom_publisher_->publish(odom_msg);
606 
608  {
609  send_visualization(keypoints_data);
610  }
611 }
612 
613 void RGBDHandler::send_visualization(const std::pair<std::shared_ptr<rtabmap::SensorData>, std::shared_ptr<const nav_msgs::msg::Odometry>> &keypoints_data)
614 {
615  send_visualization_keypoints(keypoints_data);
616  send_visualization_pointcloud(keypoints_data.first);
617 }
618 
619 void RGBDHandler::clear_sensor_data(std::shared_ptr<rtabmap::SensorData>& sensor_data)
620 {
621  // Clear costly data
622  sensor_data->clearCompressedData();
623  sensor_data->clearRawData();
624 }
625 
626 void RGBDHandler::send_visualization_keypoints(const std::pair<std::shared_ptr<rtabmap::SensorData>, std::shared_ptr<const nav_msgs::msg::Odometry>> &keypoints_data)
627 {
628  // visualization message
629  cslam_common_interfaces::msg::LocalImageDescriptors features_msg;
630  sensor_data_to_rgbd_msg(keypoints_data.first,
631  features_msg.data);
632  features_msg.keyframe_id = keypoints_data.first->id();
633  features_msg.robot_id = robot_id_;
634  features_msg.data.key_points.clear();
635 
636  // Publish local descriptors
637  visualization_local_descriptors_publisher_->publish(features_msg);
638 }
639 
641  const sensor_msgs::msg::PointCloud2 &input_cloud)
642 {
643  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
644  pcl::fromROSMsg(input_cloud, *cloud);
645 
646  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);
647  pcl::VoxelGrid<pcl::PointXYZRGB> sor;
648  sor.setInputCloud(cloud);
650  sor.filter(*cloud_filtered);
651 
652  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered_clipped(new pcl::PointCloud<pcl::PointXYZRGB>);
653  pcl::PassThrough<pcl::PointXYZRGB> pass;
654  pass.setInputCloud (cloud_filtered);
655  pass.setFilterFieldName ("z");
656  pass.setFilterLimits (0.0, visualization_max_range_);
657  pass.filter(*cloud_filtered_clipped);
658 
659  sensor_msgs::msg::PointCloud2 output_cloud;
660  pcl::toROSMsg(*cloud_filtered_clipped, output_cloud);
661  output_cloud.header = input_cloud.header;
662  return output_cloud;
663 }
664 
665 void RGBDHandler::send_visualization_pointcloud(const std::shared_ptr<rtabmap::SensorData> & sensor_data)
666 {
667  cslam_common_interfaces::msg::VizPointCloud keyframe_pointcloud_msg;
668  keyframe_pointcloud_msg.robot_id = robot_id_;
669  keyframe_pointcloud_msg.keyframe_id = sensor_data->id();
670  std_msgs::msg::Header header;
671  header.stamp = node_->now();
672  header.frame_id = MAP_FRAME_ID(robot_id_);
673  auto pointcloud_msg = create_colored_pointcloud(sensor_data, header);
674 
675  if (visualization_voxel_size_ > 0.0)
676  {
677  pointcloud_msg = visualization_pointcloud_voxel_subsampling(pointcloud_msg);
678  }
679 
680  keyframe_pointcloud_msg.pointcloud = pointcloud_msg;
681  keyframe_pointcloud_publisher_->publish(keyframe_pointcloud_msg);
682 }
683 
684 void RGBDHandler::gps_callback(const sensor_msgs::msg::NavSatFix::ConstSharedPtr msg)
685 {
686  latest_gps_fix_ = *msg;
687 }
std::shared_ptr< rtabmap::SensorData > previous_keyframe_
Definition: rgbd_handler.h:219
void gps_callback(const sensor_msgs::msg::NavSatFix::ConstSharedPtr msg)
GPS data callback.
void send_keyframe(const std::pair< std::shared_ptr< rtabmap::SensorData >, std::shared_ptr< const nav_msgs::msg::Odometry >> &keypoints_data)
Function to send the image to the python node.
std::shared_ptr< rclcpp::Node > node_
Definition: rgbd_handler.h:223
rclcpp::Publisher< cslam_common_interfaces::msg::VizPointCloud >::SharedPtr keyframe_pointcloud_publisher_
Definition: rgbd_handler.h:246
rclcpp::Subscription< cslam_common_interfaces::msg::LocalImageDescriptors >::SharedPtr local_descriptors_subscriber_
Definition: rgbd_handler.h:254
bool generate_new_keyframe(std::shared_ptr< rtabmap::SensorData > &keyframe)
Generate a new keyframe according to the policy.
void sensor_data_to_rgbd_msg(const std::shared_ptr< rtabmap::SensorData > sensor_data, rtabmap_msgs::msg::RGBDImage &msg_data)
converts sensor data to descriptor msg
rclcpp::Subscription< sensor_msgs::msg::NavSatFix >::SharedPtr gps_subscriber_
Definition: rgbd_handler.h:286
rclcpp::Publisher< cslam_common_interfaces::msg::IntraRobotLoopClosure >::SharedPtr intra_robot_loop_closure_publisher_
Definition: rgbd_handler.h:264
void receive_local_keyframe_match(cslam_common_interfaces::msg::LocalKeyframeMatch::ConstSharedPtr msg)
Receives a local match and tries to compute a local loop closure.
rclcpp::Subscription< cslam_common_interfaces::msg::LocalDescriptorsRequest >::SharedPtr send_local_descriptors_subscriber_
Definition: rgbd_handler.h:232
unsigned int min_inliers_
Definition: rgbd_handler.h:225
unsigned int nb_local_keyframes_
Definition: rgbd_handler.h:226
void send_visualization_pointcloud(const std::shared_ptr< rtabmap::SensorData > &sensor_data)
Send colored pointcloud for visualizations.
std::shared_ptr< tf2_ros::TransformListener > tf_listener_
Definition: rgbd_handler.h:274
sensor_msgs::msg::PointCloud2 visualization_pointcloud_voxel_subsampling(const sensor_msgs::msg::PointCloud2 &input_cloud)
Subsample pointcloud to reduce size for visualization.
void compute_local_descriptors(std::shared_ptr< rtabmap::SensorData > &frame_data)
Computes local 3D descriptors from frame data and store them.
void rgbd_callback(const sensor_msgs::msg::Image::ConstSharedPtr image_rect_rgb, const sensor_msgs::msg::Image::ConstSharedPtr image_rect_depth, const sensor_msgs::msg::CameraInfo::ConstSharedPtr camera_info_rgb, const nav_msgs::msg::Odometry::ConstSharedPtr odom)
Callback receiving sync data from camera.
void send_visualization_keypoints(const std::pair< std::shared_ptr< rtabmap::SensorData >, std::shared_ptr< const nav_msgs::msg::Odometry >> &keypoints_data)
Send keypoints for visualizations.
rtabmap::RegistrationVis registration_
Definition: rgbd_handler.h:256
rclcpp::Publisher< diagnostic_msgs::msg::KeyValue >::SharedPtr log_publisher_
Definition: rgbd_handler.h:268
unsigned int max_queue_size_
Definition: rgbd_handler.h:225
sensor_msgs::msg::NavSatFix latest_gps_fix_
Definition: rgbd_handler.h:287
message_filters::Subscriber< nav_msgs::msg::Odometry > sub_odometry_
Definition: rgbd_handler.h:228
float visualization_max_range_
Definition: rgbd_handler.h:282
float keyframe_generation_ratio_threshold_
Definition: rgbd_handler.h:277
rclcpp::Publisher< cslam_common_interfaces::msg::InterRobotLoopClosure >::SharedPtr inter_robot_loop_closure_publisher_
Definition: rgbd_handler.h:260
std::string gps_topic_
Definition: rgbd_handler.h:285
std::map< int, std::shared_ptr< rtabmap::SensorData > > local_descriptors_map_
Definition: rgbd_handler.h:221
unsigned int log_total_local_descriptors_cumulative_communication_
Definition: rgbd_handler.h:269
std::string base_frame_id_
Definition: rgbd_handler.h:276
std::deque< std::pair< std::shared_ptr< rtabmap::SensorData >, nav_msgs::msg::Odometry::ConstSharedPtr > > received_data_queue_
Definition: rgbd_handler.h:217
std::deque< sensor_msgs::msg::NavSatFix > received_gps_queue_
Definition: rgbd_handler.h:289
bool generate_new_keyframes_based_on_inliers_ratio_
Definition: rgbd_handler.h:278
rclcpp::Publisher< cslam_common_interfaces::msg::KeyframeOdom >::SharedPtr keyframe_odom_publisher_
Definition: rgbd_handler.h:243
unsigned int robot_id_
Definition: rgbd_handler.h:225
rclcpp::Subscription< cslam_common_interfaces::msg::LocalKeyframeMatch >::SharedPtr local_keyframe_match_subscriber_
Definition: rgbd_handler.h:250
unsigned int max_nb_robots_
Definition: rgbd_handler.h:225
float visualization_voxel_size_
Definition: rgbd_handler.h:282
virtual void send_visualization(const std::pair< std::shared_ptr< rtabmap::SensorData >, std::shared_ptr< const nav_msgs::msg::Odometry >> &keypoints_data)
Send keypoints for visualizations.
rclcpp::Publisher< cslam_common_interfaces::msg::KeyframeRGB >::SharedPtr keyframe_data_publisher_
Definition: rgbd_handler.h:240
unsigned int visualization_period_ms_
Definition: rgbd_handler.h:280
void receive_local_image_descriptors(const std::shared_ptr< cslam_common_interfaces::msg::LocalImageDescriptors > msg)
Message callback to receive descriptors and compute.
rclcpp::Publisher< cslam_common_interfaces::msg::LocalImageDescriptors >::SharedPtr visualization_local_descriptors_publisher_
Definition: rgbd_handler.h:237
rclcpp::Publisher< cslam_common_interfaces::msg::LocalImageDescriptors >::SharedPtr local_descriptors_publisher_
Definition: rgbd_handler.h:236
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
Definition: rgbd_handler.h:273
void clear_sensor_data(std::shared_ptr< rtabmap::SensorData > &sensor_data)
Clear images and large data fields in sensor data.
virtual void local_descriptors_msg_to_sensor_data(const std::shared_ptr< cslam_common_interfaces::msg::LocalImageDescriptors > msg, rtabmap::SensorData &sensor_data)
converts descriptors to sensore data
void local_descriptors_request(cslam_common_interfaces::msg::LocalDescriptorsRequest::ConstSharedPtr request)
Service callback to publish local descriptors.
virtual void process_new_sensor_data()
Processes Latest received image.
Definition: __init__.py:1
sensor_msgs::msg::PointCloud2 create_colored_pointcloud(const std::shared_ptr< rtabmap::SensorData > &sensor_data, const std_msgs::msg::Header &header)
Create a colored pointcloud message.
#define MAP_FRAME_ID(id)