2 #include <rtabmap_conversions/MsgConversion.h>
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>
11 using namespace rtabmap;
12 using namespace cslam;
14 #define MAP_FRAME_ID(id) "robot" + std::to_string(id) + "_map"
16 RGBDHandler::RGBDHandler(std::shared_ptr<rclcpp::Node> &
node)
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",
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",
"");
26 node->declare_parameter<
bool>(
"evaluation.enable_logs",
false);
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",
39 node_->get_parameter(
"evaluation.enable_logs",
41 node->get_parameter(
"evaluation.enable_gps_recording",
43 node->get_parameter(
"evaluation.gps_topic",
58 node_->get_parameter(
"frontend.odom_topic").as_string(),
60 .reliability((rmw_qos_reliability_policy_t)2)
61 .get_rmw_qos_profile());
65 cslam_common_interfaces::msg::LocalDescriptorsRequest>(
66 "cslam/local_descriptors_request", 100,
68 std::placeholders::_1));
78 node_->create_publisher<cslam_common_interfaces::msg::KeyframeRGB>(
79 "cslam/keyframe_data", 100);
83 node_->create_publisher<cslam_common_interfaces::msg::KeyframeOdom>(
84 "cslam/keyframe_odom", 100);
88 cslam_common_interfaces::msg::LocalKeyframeMatch>(
89 "cslam/local_keyframe_match", 100,
91 std::placeholders::_1));
94 std::string local_descriptors_topic =
"/cslam/local_descriptors";
96 cslam_common_interfaces::msg::LocalImageDescriptors>(local_descriptors_topic, 100);
101 cslam_common_interfaces::msg::LocalImageDescriptors>(
"/cslam/viz/local_descriptors", 100);
104 "/cslam/viz/keyframe_pointcloud", 100);
109 cslam_common_interfaces::msg::LocalImageDescriptors>(
110 "/cslam/local_descriptors", 100,
112 std::placeholders::_1));
115 rtabmap::ParametersMap registration_params;
116 registration_params.insert(rtabmap::ParametersPair(
117 rtabmap::Parameters::kVisMinInliers(), std::to_string(
min_inliers_)));
122 cslam_common_interfaces::msg::IntraRobotLoopClosure>(
123 "cslam/intra_robot_loop_closure", 100);
127 cslam_common_interfaces::msg::InterRobotLoopClosure>(
128 "/cslam/inter_robot_loop_closure", 100);
134 sub_image_color_.subscribe(
135 node_.get(),
node_->get_parameter(
"frontend.color_image_topic").as_string(),
"raw",
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",
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(),
147 .reliability((rmw_qos_reliability_policy_t)2)
148 .get_rmw_qos_profile());
150 rgbd_sync_policy_ =
new message_filters::Synchronizer<RGBDSyncPolicy>(
153 rgbd_sync_policy_->registerCallback(
155 std::placeholders::_2, std::placeholders::_3,
156 std::placeholders::_4));
163 std::placeholders::_1));
169 "cslam/log_info", 100);
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)
180 if (odom->pose.covariance[0] > 1000)
182 RCLCPP_WARN(
node_->get_logger(),
"Odom tracking failed, skipping frame");
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))
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());
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;
207 Transform local_transform(0,0,0,0,0,0);
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())
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)
221 if (image_rect_rgb->encoding.compare(sensor_msgs::image_encodings::MONO16) != 0)
223 ptr_image = cv_bridge::cvtColor(ptr_image,
"bgr8");
227 ptr_image = cv_bridge::cvtColor(ptr_image,
"mono8");
231 cv_bridge::CvImageConstPtr ptr_depth = cv_bridge::toCvShare(image_rect_depth);
233 CameraModel camera_model = rtabmap_conversions::cameraModelFromROS(*camera_info_rgb, local_transform);
237 ptr_image->image.copyTo(rgb);
238 ptr_depth->image.copyTo(depth);
240 auto data = std::make_shared<rtabmap::SensorData>(
244 rtabmap_conversions::timestampFromROS(stamp));
253 "RGBD: Maximum queue size (%d) exceeded, the oldest element was removed.",
267 std::shared_ptr<rtabmap::SensorData> &frame_data)
270 frame_data->uncompressData();
271 std::vector<cv::KeyPoint> kpts_from;
272 cv::Mat image = frame_data->imageRaw();
273 if (image.channels() > 1)
276 cv::cvtColor(image, tmp, cv::COLOR_BGR2GRAY);
281 if (!frame_data->depthRaw().empty())
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)
288 depth_mask = rtabmap::util2d::interpolate(
289 frame_data->depthRaw(),
290 frame_data->imageRaw().rows / frame_data->depthRaw().rows, 0.1f);
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);
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);
307 auto kpts = detector->generateKeypoints(image, depth_mask);
308 auto descriptors = detector->generateDescriptors(image, kpts);
309 auto kpts3D = detector->generateKeypoints3D(*frame_data, kpts);
311 frame_data->setFeatures(kpts, kpts3D, descriptors);
324 rtabmap::RegistrationInfo reg_info;
329 if (
float(reg_info.inliers) >
337 catch (std::exception &e)
341 "Exception: Could not compute transformation for keyframe generation: %s",
360 sensor_msgs::msg::NavSatFix gps_fix;
366 if (sensor_data.first->isValid())
372 if (generate_keyframe)
388 if (generate_keyframe)
397 const std::shared_ptr<rtabmap::SensorData> sensor_data,
398 rtabmap_msgs::msg::RGBDImage &msg_data)
400 rtabmap_msgs::msg::RGBDImage data;
401 rtabmap_conversions::rgbdImageToROS(*sensor_data, msg_data,
"camera");
405 cslam_common_interfaces::msg::LocalDescriptorsRequest::
406 ConstSharedPtr request)
409 cslam_common_interfaces::msg::LocalImageDescriptors msg;
413 msg.keyframe_id = request->keyframe_id;
415 msg.matches_robot_id = request->matches_robot_id;
416 msg.matches_keyframe_id = request->matches_keyframe_id;
426 diagnostic_msgs::msg::KeyValue log_msg;
427 log_msg.key =
"local_descriptors_cumulative_communication";
434 cslam_common_interfaces::msg::LocalKeyframeMatch::ConstSharedPtr
440 keyframe0->uncompressData();
442 keyframe1->uncompressData();
443 rtabmap::RegistrationInfo reg_info;
445 *keyframe0, *keyframe1, rtabmap::Transform(), ®_info);
447 cslam_common_interfaces::msg::IntraRobotLoopClosure lc;
448 lc.keyframe0_id = msg->keyframe0_id;
449 lc.keyframe1_id = msg->keyframe1_id;
453 rtabmap_conversions::transformToGeometryMsg(t, lc.transform);
461 catch (std::exception &e)
465 "Exception: Could not compute local transformation between %d and %d: %s",
466 msg->keyframe0_id, msg->keyframe1_id,
472 const std::shared_ptr<
473 cslam_common_interfaces::msg::LocalImageDescriptors>
475 rtabmap::SensorData &sensor_data)
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));
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);
494 const std::shared_ptr<
495 cslam_common_interfaces::msg::LocalImageDescriptors>
498 std::deque<int> keyframe_ids;
499 for (
unsigned int i = 0; i < msg->matches_robot_id.size(); i++)
501 if (msg->matches_robot_id[i] ==
robot_id_)
503 keyframe_ids.push_back(msg->matches_keyframe_id[i]);
507 for (
auto local_keyframe_id : keyframe_ids)
511 rtabmap::SensorData tmp_to;
516 rtabmap::RegistrationInfo reg_info;
518 tmp_from->uncompressData();
520 *tmp_from, tmp_to, rtabmap::Transform(), ®_info);
523 cslam_common_interfaces::msg::InterRobotLoopClosure lc;
525 lc.robot0_keyframe_id = local_keyframe_id;
526 lc.robot1_id = msg->robot_id;
527 lc.robot1_keyframe_id = msg->keyframe_id;
531 rtabmap_conversions::transformToGeometryMsg(t, lc.transform);
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());
545 catch (std::exception &e)
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,
556 void RGBDHandler::send_keyframe(
const std::pair<std::shared_ptr<rtabmap::SensorData>, std::shared_ptr<const nav_msgs::msg::Odometry>> &keypoints_data)
559 keypoints_data.first->uncompressDataConst(&rgb, 0);
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();
573 cslam_common_interfaces::msg::KeyframeOdom odom_msg;
574 odom_msg.id = keypoints_data.first->id();
575 odom_msg.odom = *keypoints_data.second;
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)
587 keypoints_data.first->uncompressDataConst(&rgb, 0);
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();
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;
622 sensor_data->clearCompressedData();
623 sensor_data->clearRawData();
629 cslam_common_interfaces::msg::LocalImageDescriptors features_msg;
632 features_msg.keyframe_id = keypoints_data.first->id();
634 features_msg.data.key_points.clear();
641 const sensor_msgs::msg::PointCloud2 &input_cloud)
643 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZRGB>);
644 pcl::fromROSMsg(input_cloud, *cloud);
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);
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");
657 pass.filter(*cloud_filtered_clipped);
659 sensor_msgs::msg::PointCloud2 output_cloud;
660 pcl::toROSMsg(*cloud_filtered_clipped, output_cloud);
661 output_cloud.header = input_cloud.header;
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();
680 keyframe_pointcloud_msg.pointcloud = pointcloud_msg;
std::shared_ptr< rtabmap::SensorData > previous_keyframe_
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_
rclcpp::Publisher< cslam_common_interfaces::msg::VizPointCloud >::SharedPtr keyframe_pointcloud_publisher_
rclcpp::Subscription< cslam_common_interfaces::msg::LocalImageDescriptors >::SharedPtr local_descriptors_subscriber_
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_
rclcpp::Publisher< cslam_common_interfaces::msg::IntraRobotLoopClosure >::SharedPtr intra_robot_loop_closure_publisher_
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_
unsigned int min_inliers_
unsigned int nb_local_keyframes_
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_
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_
rclcpp::Publisher< diagnostic_msgs::msg::KeyValue >::SharedPtr log_publisher_
unsigned int max_queue_size_
sensor_msgs::msg::NavSatFix latest_gps_fix_
message_filters::Subscriber< nav_msgs::msg::Odometry > sub_odometry_
float visualization_max_range_
float keyframe_generation_ratio_threshold_
rclcpp::Publisher< cslam_common_interfaces::msg::InterRobotLoopClosure >::SharedPtr inter_robot_loop_closure_publisher_
std::map< int, std::shared_ptr< rtabmap::SensorData > > local_descriptors_map_
unsigned int log_total_local_descriptors_cumulative_communication_
std::string base_frame_id_
std::deque< std::pair< std::shared_ptr< rtabmap::SensorData >, nav_msgs::msg::Odometry::ConstSharedPtr > > received_data_queue_
std::deque< sensor_msgs::msg::NavSatFix > received_gps_queue_
bool generate_new_keyframes_based_on_inliers_ratio_
rclcpp::Publisher< cslam_common_interfaces::msg::KeyframeOdom >::SharedPtr keyframe_odom_publisher_
bool enable_gps_recording_
rclcpp::Subscription< cslam_common_interfaces::msg::LocalKeyframeMatch >::SharedPtr local_keyframe_match_subscriber_
unsigned int max_nb_robots_
float visualization_voxel_size_
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_
unsigned int visualization_period_ms_
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_
rclcpp::Publisher< cslam_common_interfaces::msg::LocalImageDescriptors >::SharedPtr local_descriptors_publisher_
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
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.
bool enable_visualization_
virtual void process_new_sensor_data()
Processes Latest received image.
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.