SLAM Toolbox turns a lidar, a wheel odometry source and a ROS 2 launch file into a map you can navigate. It is the default mapping package for Nav2, and most “SLAM does not work” problems are missing transforms, not missing algorithms.
This tutorial covers the prerequisites, the launch commands, the parameters that matter, saving and reloading a map, and the failure modes you will actually see on a differential drive robot.
What SLAM Toolbox needs before it runs
- A lidar publishing
sensor_msgs/LaserScanon/scan. - Odometry published on
/odomand a transform fromodomtobase_link. - A static transform from
base_linkto the lidar frame. - A URDF that defines the frames consistently.
- Time synchronisation. Simulation time and wall time must not mix.
If ros2 run tf2_tools view_frames does not show a connected tree from map to the lidar frame, SLAM cannot work. Fix the transforms first, always.
Start mapping
sudo apt install ros-$ROS_DISTRO-slam-toolbox
ros2 launch slam_toolbox online_async_launch.py use_sim_time:=trueUse online_async on a normal laptop or Jetson. On a very low-power board, or when you want deterministic ordering, online_sync_launch.py processes scans in order instead of in a separate thread.
ros2 launch slam_toolbox online_sync_launch.py use_sim_time:=falseIn RViz, add the /map display and set the fixed frame to map. Drive the robot slowly and completely around the space, closing loops by returning to where you started.
Drive it properly
| Habit | Why it matters |
|---|---|
| Drive slowly | Fast rotation blurs scans and breaks matching |
| Turn in place at corners | Gives the matcher clean rotational constraints |
| Close the loop | Return to the start to trigger loop closure |
| Keep the lidar clear | Bags, coats and hands become permanent walls |
| Light the space consistently | Some lidars struggle with direct sunlight or glass |
| Do not teleport the robot | Jumping the base breaks the odometry chain |
Parameters worth tuning
| Parameter | Effect | Practical note |
|---|---|---|
| minimum_travel_distance | Distance before a new node is added | Lower for small indoor spaces |
| minimum_travel_heading | Rotation before a new node | Lower if the robot turns a lot |
| resolution | Map cell size in metres | 0.05 is typical for indoor robots |
| max_laser_range | Ignores returns beyond this | Cut glass reflections and outdoor noise |
| transform_publish_period | How often map to odom is published | 0.05 s is a reasonable start |
| map_update_interval | How often the map is rebuilt | Raise it on slow hardware |
| loop_search_maximum_distance | How far to look for loop closures | Raise for large buildings |
Change one parameter at a time and drive the same route. Tuning two at once makes it impossible to know what helped.
Save the map
The map saver writes a .pgm image and a .yaml metadata file, which is what Nav2’s map server reads later.
mkdir -p ~/maps
ros2 run nav2_map_server map_saver_cli -f ~/maps/workshopAlso save the pose graph, so you can resume mapping or run in localization mode with the full graph rather than just the image.
ros2 service call /slam_toolbox/serialize_map \
slam_toolbox/srv/SerializePoseGraph \
"{filename: '/home/user/maps/workshop'}"Mapping mode vs localization mode
| Mode | When to use | Behaviour |
|---|---|---|
| Mapping | First run in a new space | Builds and updates the map |
| Localization | Production, known building | Loads a saved graph and only localises |
| Lifelong | Changing environments | Updates an existing map over time |
For a delivery or cleaning robot in a fixed building, map once and run localization. Continuous remapping in production adds risk for no benefit.
Failure modes and fixes
| Symptom | Cause | Fix |
|---|---|---|
| Map drifts then snaps | Bad odometry calibration | Fix wheel radius and track width, re-tune |
| Walls doubled | Poor scan matching or fast driving | Slow down, lower travel thresholds |
| No map appears | Missing map to odom transform | Check TF tree and launch status |
| Map jumps on rotation | Lidar mounted off-centre without correct TF | Correct the static transform |
| Loop closure never triggers | Never revisited the start | Close the loop deliberately |
| CPU pegged | Async worker saturated or too many nodes | Raise travel distance, lower scan rate |
A mapping routine that produces usable maps
- Run TF checks and confirm
/scanrate is stable. - Start SLAM, then drive a slow perimeter loop.
- Cover corridors twice in opposite directions.
- Stop, save the pose graph, then save the image map.
- Restart in localization mode and drive the route again to test.
- Fix anything that fails before adding Nav2.
Related: SLAM for beginners, Nav2 tutorial, TF2 tutorial, lidar vs ultrasonic vs IR, Gazebo ROS 2 simulation.
What does SLAM Toolbox do?
It builds a 2D occupancy map from lidar scans and odometry while tracking the robot's pose, and can later localise the robot on a saved map. It is the standard mapping package used with Nav2.
What topics does SLAM Toolbox need?
A LaserScan on /scan, odometry on /odom, an odom to base_link transform, and a static transform from base_link to the lidar frame. Without a complete TF tree it will not run.
How do I save a map in ROS 2?
Run ros2 run nav2_map_server map_saver_cli -f ~/maps/name to write the .pgm and .yaml, then call the SerializePoseGraph service to save the graph for later localization.
Why is my SLAM map drifting?
Usually wheel odometry is miscalibrated, the robot is driving too fast, or the lidar transform is wrong. Fix odometry first, then slow down and lower the travel thresholds.
Should I run SLAM continuously on a production robot?
No. Map once, then run SLAM Toolbox in localization mode against the saved graph or use AMCL with the saved map. Continuous remapping adds risk without benefit in a fixed building.
When a mapping run goes wrong, a recorded bag lets you replay it without driving again.
Mapping improves when the odometry feeding SLAM is fused rather than raw.
A clean map helps, but costmap inflation decides how the robot drives it.
The prediction and correction steps are the same maths SLAM uses to fuse scans with odometry.
Set the environment up first; our WSL2 setup for ROS 2 gets RViz and the toolchain running before you tune SLAM.
Sources and further reading
- slam_toolbox — source, launch files and parameter reference.
- Nav2 documentation — map server and localization integration.
- ROS 2 documentation — TF2 and message definitions.
- Open Robotics — ROS ecosystem overview.


