/* Copyright (c) 2010-2026, Mathieu Labbe - IntRoLab - Universite de Sherbrooke All rights reserved. (BSD-3-Clause, see the repository root.) */ #ifndef RTABMAP_SLAM_MSG_BUILDERS_HPP_ #define RTABMAP_SLAM_MSG_BUILDERS_HPP_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PRE_ROS_IRON #include #else #include #endif #include #include #include #include #include namespace rtabmap_slam_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 planar pose as a TF: @p x, @p y in meters and @p yaw in radians. inline geometry_msgs::msg::TransformStamped makeTransform( const std::string & parent, const std::string & child, double stamp, double x = 0.0, double y = 0.0, double yaw = 0.0) { geometry_msgs::msg::TransformStamped tf; tf.header.frame_id = parent; tf.header.stamp = stampOf(stamp); tf.child_frame_id = child; tf.transform.translation.x = x; tf.transform.translation.y = y; tf.transform.rotation.z = std::sin(yaw/2.0); tf.transform.rotation.w = std::cos(yaw/2.0); return tf; } /** * @brief An odometry message at (@p x, @p y, @p yaw), with a small valid covariance. * * The covariance matters to rtabmap: 9999 on both diagonals, or an identity pose after a * non-identity one, is read as an odometry reset and starts a new map. */ inline nav_msgs::msg::Odometry makeOdometry( double stamp, double x = 0.0, double y = 0.0, double yaw = 0.0, double variance = 0.001, const std::string & frameId = "odom", const std::string & childFrameId = "base_link") { nav_msgs::msg::Odometry msg; msg.header.frame_id = frameId; msg.header.stamp = stampOf(stamp); msg.child_frame_id = childFrameId; msg.pose.pose.position.x = x; msg.pose.pose.position.y = y; msg.pose.pose.orientation.z = std::sin(yaw/2.0); msg.pose.pose.orientation.w = std::cos(yaw/2.0); for(int i=0; i<6; ++i) { msg.pose.covariance[i*7] = variance; msg.twist.covariance[i*7] = variance; } return msg; } /// What an odometry node publishes when it is lost or has just been reset. inline nav_msgs::msg::Odometry makeResetOdometry(double stamp) { nav_msgs::msg::Odometry msg = makeOdometry(stamp, 0.0, 0.0, 0.0, 9999.0); return msg; } /** * @name The room the tests' robot drives in * * A rectangle fixed in the world (the odom and map frames coincide in these tests), with * walls 1 m high. Scans and clouds are generated from the sensor's actual pose in it, so * every node sees the same walls wherever the robot is -- which is what makes the * assembled map, and the occupancy grid in particular, comparable to the room. * @{ */ constexpr double kRoomXMin = -1.5; constexpr double kRoomXMax = 3.5; constexpr double kRoomYMin = -2.0; constexpr double kRoomYMax = 2.0; constexpr double kRoomHeight = 1.0; /// Distance from (@p x, @p y), inside the room, to its walls along direction @p theta. inline double rayToRoom(double x, double y, double theta) { const double dx = std::cos(theta); const double dy = std::sin(theta); double t = std::numeric_limits::infinity(); if(dx > 1e-9) { t = std::min(t, (kRoomXMax - x) / dx); } else if(dx < -1e-9) { t = std::min(t, (kRoomXMin - x) / dx); } if(dy > 1e-9) { t = std::min(t, (kRoomYMax - y) / dy); } else if(dy < -1e-9) { t = std::min(t, (kRoomYMin - y) / dy); } return t; } /// A 360 degree LaserScan of the room from a laser at (@p x, @p y, @p yaw) in the world. inline sensor_msgs::msg::LaserScan makeRoomScan( const std::string & frameId, double stamp, double x, double y = 0.0, double yaw = 0.0, size_t count = 720) { sensor_msgs::msg::LaserScan scan; scan.header.frame_id = frameId; scan.header.stamp = stampOf(stamp); scan.angle_increment = float(2.0 * M_PI / double(count)); scan.angle_min = float(-M_PI); scan.angle_max = scan.angle_min + scan.angle_increment * float(count - 1); scan.time_increment = 0.0f; scan.scan_time = 0.1f; scan.range_min = 0.1f; scan.range_max = 10.0f; scan.ranges.resize(count); for(size_t i=0; i points; for(double fx=kRoomXMin + 0.025; fx