Replays a recorded RTAB-Map database as live sensor topics.
Point it at a `.db` file and it publishes the images, scans, odometry and transforms that were recorded into it, at the rate they were captured. Everything downstream sees a running robot.
That makes it the tool for offline work: re-run SLAM with different parameters on the same data, debug a failure you cannot reproduce on the robot, or develop a node without hardware. Unlike a rosbag, the database is what RTAB-Map itself wrote, so it is always available after a mapping session.
> **The executable is named `data_player`**, not `db_player`. The composable node is `rtabmap_util::DbPlayer`.
**Which topics exist depends on what the database contains.** The node inspects the first frame and only advertises what it can actually publish, so a lidar-only database has no image topics at all.
| `global_pose` | [`PoseWithCovarianceStamped`](https://docs.ros.org/en/jazzy/p/geometry_msgs/msg/PoseWithCovarianceStamped.html) | A prior pose was recorded. |
| `gps/fix` | [`NavSatFix`](https://docs.ros.org/en/jazzy/p/sensor_msgs/msg/NavSatFix.html) | GPS was recorded. |
| `env_sensor` | [`EnvSensor`](https://docs.ros.org/en/jazzy/p/rtabmap_msgs/msg/EnvSensor.html) | Environmental sensors were recorded. |
| `/clock` | [`Clock`](https://docs.ros.org/en/jazzy/p/rosgraph_msgs/msg/Clock.html) | `publish_clock` is set. See [Simulated time](#simulated-time). |
Everything except `/tf` and `/clock` is published only when it has a subscriber.
## Published Transforms
Broadcast on every frame unless `publish_tf` is false.
| Transform | Published when |
|---|---|
| `odom_frame_id` → `frame_id` | Odometry is available. |
| `frame_id` → `camera_frame_id` | A camera is calibrated. Multi-camera setups get a numeric suffix; stereo gets `left_`/`right_` prefixes, with the right frame offset by the baseline. |
| `frame_id` → `scan_frame_id` | A scan is present. |
| `frame_id` → `imu_frame_id` | An IMU is present. |
| `ground_truth_frame_id` → `ground_truth_base_frame_id` | Ground truth was recorded. |
When run as the standalone executable, the **space bar** toggles pause as well.
## Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| `database` | `string` | `""` | **Required.** Path to the `.db` file. `~` is expanded, relative paths resolve against the working directory. The node throws on start-up if it is unset or unreadable. |
| `rate` | `double` | `1.0` | Playback speed as a multiple of the recorded rate. `2.0` is twice as fast, `0.5` half. |
| `start_id` | `int` | `0` | Skip to this node id. `0` starts at the beginning. |
| `ignore_odom` | `bool` | `false` | Do not publish odometry or its transform, so you can run your own odometry against the raw sensor data. |
| `publish_tf` | `bool` | `true` | Broadcast the transforms above. Turn it off if a robot state publisher already provides them. |
| `qos` | `int` | `0` | Reliability of all publishers unless overridden below. |
| `qos_camera_info`, `qos_odom`, `qos_scan`, `qos_scan_cloud`, `qos_global_pose`, `qos_gps`, `qos_imu`, `qos_env_sensor` | `int` | value of `qos` | Per-topic overrides. |
**2D scan geometry** — only used when the recorded scan has no angle metadata of its own, which happens for scans converted from a 3D lidar.
| Parameter | Type | Default | Description |
|---|---|---|---|
| `scan_angle_min` | `double` | `-π` | |
| `scan_angle_max` | `double` | `π` | |
| `scan_angle_increment` | `double` | `π/720` | |
| `scan_range_min` | `double` | `0.0` | |
| `scan_range_max` | `double` | `60.0` | |
## Simulated time
With `publish_clock` the node publishes `/clock` from the recorded stamps. Start every other node with `use_sim_time:=true` and the whole system runs on the database's timeline instead of the wall clock, so playback speed no longer affects behavior — a good idea when replaying faster than real time, and essential for reproducible runs.
```bash
ros2 run rtabmap_util data_player --ros-args -p database:=map.db -p publish_clock:=true