2 #include <rtabmap_conversions/MsgConversion.h>
4 using namespace rtabmap;
7 StereoHandler::StereoHandler(std::shared_ptr<rclcpp::Node> &
node)
9 node->declare_parameter<std::string>(
"frontend.left_image_topic",
"left/image_rect");
10 node->declare_parameter<std::string>(
"frontend.right_image_topic",
"right/image_rect");
11 node->declare_parameter<std::string>(
"frontend.left_camera_info_topic",
13 node->declare_parameter<std::string>(
"frontend.right_camera_info_topic",
17 sub_image_rect_left_.subscribe(
18 node_.get(),
node_->get_parameter(
"frontend.left_image_topic").as_string(),
"raw",
20 .reliability((rmw_qos_reliability_policy_t)2)
21 .get_rmw_qos_profile());
22 sub_image_rect_right_.subscribe(
23 node_.get(),
node_->get_parameter(
"frontend.right_image_topic").as_string(),
"raw",
25 .reliability((rmw_qos_reliability_policy_t)2)
26 .get_rmw_qos_profile());
27 sub_camera_info_left_.subscribe(
28 node_.get(),
node_->get_parameter(
"frontend.left_camera_info_topic").as_string(),
30 .reliability((rmw_qos_reliability_policy_t)2)
31 .get_rmw_qos_profile());
32 sub_camera_info_right_.subscribe(
33 node_.get(),
node_->get_parameter(
"frontend.right_camera_info_topic").as_string(),
35 .reliability((rmw_qos_reliability_policy_t)2)
36 .get_rmw_qos_profile());
38 stereo_sync_policy_ =
new message_filters::Synchronizer<StereoSyncPolicy>(
39 StereoSyncPolicy(
max_queue_size_), sub_image_rect_left_, sub_image_rect_right_,
40 sub_camera_info_left_, sub_camera_info_right_,
sub_odometry_);
41 stereo_sync_policy_->registerCallback(
43 std::placeholders::_2, std::placeholders::_3,
44 std::placeholders::_4, std::placeholders::_5));
49 const sensor_msgs::msg::Image::ConstSharedPtr image_rect_left,
50 const sensor_msgs::msg::Image::ConstSharedPtr image_rect_right,
51 const sensor_msgs::msg::CameraInfo::ConstSharedPtr camera_info_left,
52 const sensor_msgs::msg::CameraInfo::ConstSharedPtr camera_info_right,
53 const nav_msgs::msg::Odometry::ConstSharedPtr odom_ptr) {
55 if (odom_ptr->pose.covariance[0] > 1000)
57 RCLCPP_WARN(
node_->get_logger(),
"Odom tracking failed, skipping frame");
61 auto odom = std::make_shared<nav_msgs::msg::Odometry>(*odom_ptr);
62 odom->header.stamp = image_rect_left->header.stamp;
64 if (!(image_rect_left->encoding.compare(
65 sensor_msgs::image_encodings::TYPE_8UC1) == 0 ||
66 image_rect_left->encoding.compare(sensor_msgs::image_encodings::MONO8) ==
68 image_rect_left->encoding.compare(sensor_msgs::image_encodings::MONO16) ==
70 image_rect_left->encoding.compare(sensor_msgs::image_encodings::BGR8) ==
72 image_rect_left->encoding.compare(sensor_msgs::image_encodings::RGB8) ==
74 image_rect_left->encoding.compare(sensor_msgs::image_encodings::BGRA8) ==
76 image_rect_left->encoding.compare(sensor_msgs::image_encodings::RGBA8) ==
78 !(image_rect_right->encoding.compare(
79 sensor_msgs::image_encodings::TYPE_8UC1) == 0 ||
80 image_rect_right->encoding.compare(sensor_msgs::image_encodings::MONO8) ==
82 image_rect_right->encoding.compare(
83 sensor_msgs::image_encodings::MONO16) == 0 ||
84 image_rect_right->encoding.compare(sensor_msgs::image_encodings::BGR8) ==
86 image_rect_right->encoding.compare(sensor_msgs::image_encodings::RGB8) ==
88 image_rect_right->encoding.compare(sensor_msgs::image_encodings::BGRA8) ==
90 image_rect_right->encoding.compare(sensor_msgs::image_encodings::RGBA8) ==
94 "Input type must be image=mono8,mono16,rgb8,bgr8,rgba8,bgra8 (mono8 "
95 "recommended), received types are %s (left) and %s (right)",
96 image_rect_left->encoding.c_str(), image_rect_right->encoding.c_str());
101 rtabmap_conversions::timestampFromROS(image_rect_left->header.stamp) >
102 rtabmap_conversions::timestampFromROS(image_rect_right->header.stamp)
103 ? image_rect_left->header.stamp
104 : image_rect_right->header.stamp;
106 Transform localTransform(0,0,0,0,0,0);
109 localTransform = rtabmap_conversions::getTransform(
111 if (localTransform.isNull()) {
112 RCLCPP_INFO(
node_->get_logger(),
113 "Could not get transform from %s to %s after 0.1 s!",
114 base_frame_id_.c_str(), image_rect_left->header.frame_id.c_str());
119 if (image_rect_left->data.size() && image_rect_right->data.size()) {
120 bool alreadyRectified =
true;
121 rtabmap::Transform stereoTransform;
122 if (!alreadyRectified) {
123 stereoTransform = rtabmap_conversions::getTransform(
124 camera_info_right->header.frame_id, camera_info_left->header.frame_id,
125 camera_info_left->header.stamp, *
tf_buffer_, 0.1);
126 if (stereoTransform.isNull()) {
127 RCLCPP_ERROR(
node_->get_logger(),
128 "Parameter %s is false but we cannot get TF between the "
129 "two cameras! (between frames %s and %s)",
130 Parameters::kRtabmapImagesAlreadyRectified().c_str(),
131 camera_info_right->header.frame_id.c_str(),
132 camera_info_left->header.frame_id.c_str());
134 }
else if (stereoTransform.isIdentity()) {
135 RCLCPP_ERROR(
node_->get_logger(),
136 "Parameter %s is false but we cannot get a valid TF "
137 "between the two cameras! "
138 "Identity transform returned between left and right "
139 "cameras. Verify that if TF between "
140 "the cameras is valid: \"rosrun tf tf_echo %s %s\".",
141 Parameters::kRtabmapImagesAlreadyRectified().c_str(),
142 camera_info_right->header.frame_id.c_str(),
143 camera_info_left->header.frame_id.c_str());
148 rtabmap::StereoCameraModel stereoModel =
149 rtabmap_conversions::stereoCameraModelFromROS(*camera_info_left, *camera_info_right,
150 localTransform, stereoTransform);
152 if (stereoModel.baseline() == 0 && alreadyRectified) {
153 stereoTransform = rtabmap_conversions::getTransform(
154 camera_info_left->header.frame_id, camera_info_right->header.frame_id,
155 camera_info_left->header.stamp, *
tf_buffer_, 0.1);
157 if (!stereoTransform.isNull() && stereoTransform.x() > 0) {
158 static bool warned =
false;
162 "Right camera info doesn't have Tx set but we are assuming that "
163 "stereo images are already rectified (see %s parameter). While "
165 "recommended, we used TF to get the baseline (%s->%s = %fm) for "
166 "convenience (e.g., D400 ir stereo issue). It is preferred to "
168 "a valid right camera info if stereo images are already "
169 "rectified. This message is only printed once...",
170 rtabmap::Parameters::kRtabmapImagesAlreadyRectified().c_str(),
171 camera_info_right->header.frame_id.c_str(),
172 camera_info_left->header.frame_id.c_str(), stereoTransform.x());
175 stereoModel = rtabmap::StereoCameraModel(
176 stereoModel.left().fx(), stereoModel.left().fy(),
177 stereoModel.left().cx(), stereoModel.left().cy(),
178 stereoTransform.x(), stereoModel.localTransform(),
179 stereoModel.left().imageSize());
183 if (alreadyRectified && stereoModel.baseline() <= 0) {
186 "The stereo baseline (%f) should be positive (baseline=-Tx/fx). We "
187 "assume a horizontal left/right stereo "
188 "setup where the Tx (or P(0,3)) is negative in the right camera info "
190 stereoModel.baseline());
194 if (stereoModel.baseline() > 10.0) {
195 static bool shown =
false;
199 "Detected baseline (%f m) is quite large! Is your "
200 "right camera_info P(0,3) correctly set? Note that "
201 "baseline=-P(0,3)/P(0,0). This warning is printed only once.",
202 stereoModel.baseline());
207 cv_bridge::CvImagePtr ptrImageLeft = cv_bridge::toCvCopy(
208 image_rect_left, image_rect_left->encoding.compare(
209 sensor_msgs::image_encodings::TYPE_8UC1) == 0 ||
210 image_rect_left->encoding.compare(
211 sensor_msgs::image_encodings::MONO8) == 0
213 : image_rect_left->encoding.compare(
214 sensor_msgs::image_encodings::MONO16) != 0
217 cv_bridge::CvImagePtr ptrImageRight = cv_bridge::toCvCopy(
218 image_rect_right, image_rect_right->encoding.compare(
219 sensor_msgs::image_encodings::TYPE_8UC1) == 0 ||
220 image_rect_right->encoding.compare(
221 sensor_msgs::image_encodings::MONO8) == 0
225 auto data = std::make_shared<rtabmap::SensorData>(
226 ptrImageLeft->image, ptrImageRight->image, stereoModel,
227 0, rtabmap_conversions::timestampFromROS(stamp));
235 "Stereo: Maximum queue size (%d) exceeded, the oldest element was removed.",
247 RCLCPP_WARN(
node_->get_logger(),
"Odom: input images empty?!");
252 const std::shared_ptr<
253 cslam_common_interfaces::msg::LocalImageDescriptors>
255 rtabmap::SensorData &sensor_data) {
257 rtabmap::StereoCameraModel stereo_model =
258 rtabmap_conversions::stereoCameraModelFromROS(msg->data.rgb_camera_info,
259 msg->data.depth_camera_info,
260 rtabmap::Transform::getIdentity());
261 sensor_data = rtabmap::SensorData(
262 cv::Mat(), cv::Mat(), stereo_model, 0,
263 rtabmap_conversions::timestampFromROS(msg->data.header.stamp));
265 std::vector<cv::KeyPoint> kpts;
266 rtabmap_conversions::keypointsFromROS(msg->data.key_points, kpts);
267 std::vector<cv::Point3f> kpts3D;
268 rtabmap_conversions::points3fFromROS(msg->data.points, kpts3D);
269 auto descriptors = rtabmap::uncompressData(msg->data.descriptors);
270 sensor_data.setFeatures(kpts, kpts3D, descriptors);
std::shared_ptr< rclcpp::Node > node_
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.
unsigned int max_queue_size_
sensor_msgs::msg::NavSatFix latest_gps_fix_
message_filters::Subscriber< nav_msgs::msg::Odometry > sub_odometry_
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 enable_gps_recording_
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
void stereo_callback(const sensor_msgs::msg::Image::ConstSharedPtr image_rect_left, const sensor_msgs::msg::Image::ConstSharedPtr image_rect_right, const sensor_msgs::msg::CameraInfo::ConstSharedPtr camera_info_left, const sensor_msgs::msg::CameraInfo::ConstSharedPtr camera_info_right, const nav_msgs::msg::Odometry::ConstSharedPtr odom)
Callback receiving sync data from camera.
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
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.