/* Copyright (c) 2010-2026, Mathieu Labbe - IntRoLab - Universite de Sherbrooke All rights reserved. (BSD-3-Clause, see the repository root.) */ #ifndef RTABMAP_SYNC_MSG_BUILDERS_HPP_ #define RTABMAP_SYNC_MSG_BUILDERS_HPP_ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PRE_ROS_IRON #include #else #include #endif #include #include namespace rtabmap_sync_test { /// A ROS time from a double, the way sensor stamps are written throughout these tests. inline rclcpp::Time stampOf(double seconds) { return rclcpp::Time( int32_t(seconds), uint32_t((seconds - int32_t(seconds)) * 1e9), RCL_ROS_TIME); } /// A rectified pinhole CameraInfo; @p tx is P(0,3), non-zero for a stereo right camera. inline sensor_msgs::msg::CameraInfo makeCameraInfo( const std::string & frameId, double stamp, int width = 8, int height = 8, double tx = 0.0, double fx = 100.0) { sensor_msgs::msg::CameraInfo info; info.header.frame_id = frameId; info.header.stamp = stampOf(stamp); info.width = width; info.height = height; info.distortion_model = "plumb_bob"; info.d = {0.0, 0.0, 0.0, 0.0, 0.0}; info.k = {fx, 0.0, width/2.0, 0.0, fx, height/2.0, 0.0, 0.0, 1.0}; info.r = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0}; info.p = {fx, 0.0, width/2.0, tx, 0.0, fx, height/2.0, 0.0, 0.0, 0.0, 1.0, 0.0}; return info; } inline sensor_msgs::msg::Image makeImage( const std::string & frameId, double stamp, const cv::Mat & image, const std::string & encoding) { std_msgs::msg::Header header; header.frame_id = frameId; header.stamp = stampOf(stamp); sensor_msgs::msg::Image msg; cv_bridge::CvImage(header, encoding, image).toImageMsg(msg); return msg; } /// A bgr8 color image of a single flat color. inline sensor_msgs::msg::Image makeRgbImage( const std::string & frameId, double stamp, int width = 8, int height = 8, const cv::Scalar & color = cv::Scalar(10, 20, 30)) { return makeImage(frameId, stamp, cv::Mat(height, width, CV_8UC3, color), "bgr8"); } /// A 16UC1 depth image in millimeters, the encoding the RGB-D drivers publish. inline sensor_msgs::msg::Image makeDepthImage( const std::string & frameId, double stamp, int width = 8, int height = 8, uint16_t millimeters = 1500) { return makeImage(frameId, stamp, cv::Mat(height, width, CV_16UC1, cv::Scalar(millimeters)), "16UC1"); } /// A mono8 image, used as a stereo left or right frame. inline sensor_msgs::msg::Image makeMonoImage( const std::string & frameId, double stamp, int width = 8, int height = 8, uint8_t value = 60) { return makeImage(frameId, stamp, cv::Mat(height, width, CV_8UC1, cv::Scalar(value)), "mono8"); } /// An RGB-D message with raw bgr8 color and 16UC1 depth, as rgbd_sync publishes it. inline rtabmap_msgs::msg::RGBDImage makeRGBDImage( const std::string & frameId, double stamp, int width = 8, int height = 8, const cv::Scalar & rgbColor = cv::Scalar(10, 20, 30), uint16_t depthValue = 1500) { rtabmap_msgs::msg::RGBDImage msg; msg.header.frame_id = frameId; msg.header.stamp = stampOf(stamp); msg.rgb = makeRgbImage(frameId, stamp, width, height, rgbColor); msg.depth = makeDepthImage(frameId, stamp, width, height, depthValue); msg.rgb_camera_info = makeCameraInfo(frameId, stamp, width, height); msg.depth_camera_info = makeCameraInfo(frameId, stamp, width, height); return msg; } /// A flat LaserScan of @p count equal ranges over 180 degrees. inline sensor_msgs::msg::LaserScan makeLaserScan( const std::string & frameId, double stamp, size_t count = 10, float range = 2.0f) { sensor_msgs::msg::LaserScan scan; scan.header.frame_id = frameId; scan.header.stamp = stampOf(stamp); scan.angle_min = -M_PI_2; scan.angle_max = M_PI_2; scan.angle_increment = count > 1 ? float(M_PI / double(count - 1)) : float(M_PI); scan.time_increment = 0.0f; scan.scan_time = 0.1f; scan.range_min = 0.1f; scan.range_max = 10.0f; scan.ranges.assign(count, range); return scan; } /// A dense unorganized XYZ float cloud, the shape a 3D lidar driver publishes. inline sensor_msgs::msg::PointCloud2 makeXYZCloud( const std::string & frameId, double stamp, const std::vector & points) { sensor_msgs::msg::PointCloud2 cloud; cloud.header.frame_id = frameId; cloud.header.stamp = stampOf(stamp); cloud.height = 1; cloud.width = points.size(); cloud.is_bigendian = false; cloud.is_dense = true; cloud.fields.resize(3); const char * names[3] = {"x", "y", "z"}; for(int i=0; i<3; ++i) { cloud.fields[i].name = names[i]; cloud.fields[i].offset = 4 * i; cloud.fields[i].datatype = sensor_msgs::msg::PointField::FLOAT32; cloud.fields[i].count = 1; } cloud.point_step = 12; cloud.row_step = cloud.point_step * cloud.width; cloud.data.resize(cloud.row_step * cloud.height); for(size_t i=0; i(&cloud.data[i * cloud.point_step]); p[0] = points[i].x; p[1] = points[i].y; p[2] = points[i].z; } return cloud; } /// A small cloud on a line, enough to tell one scan from another. inline sensor_msgs::msg::PointCloud2 makeScanCloud( const std::string & frameId, double stamp, size_t count = 4) { std::vector points; points.reserve(count); for(size_t i=0; i(base + xOffset), *reinterpret_cast(base + yOffset), *reinterpret_cast(base + zOffset)); } } // namespace rtabmap_sync_test #endif /* RTABMAP_SYNC_MSG_BUILDERS_HPP_ */