Slam Toolbox: 2D SLAM that treats the pose graph as the real artifact
Slam Toolbox for lifelong mapping and localization in potentially massive maps with ROS
At a glance
- What is it?
- A ROS 2 SLAM package built around serializable pose graphs, so a mapping session can be resumed, refined, or reused as a localization map months later.
- Who is it for?
- Slam Toolbox makes a bet that most SLAM packages do not: the map is not the deliverable, the pose graph is. Keeping raw scans attached to nodes means you can reopen a session, add data to a building that has changed, or drop into localization mode on an existing graph, which is the difference between mapping once and mapping continuously.
- Can I use it commercially?
- Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 19 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why the pose graph is the important part
Most 2D SLAM packages treat the map as the output and the internal state as an implementation detail. Slam Toolbox inverts that. Its central artifact is a serialized pose graph, and the README lists continuing to refine, remap or continue mapping a saved graph among the headline capabilities alongside life-long mapping and optimization-based localization built on that same graph.
The distinction has practical consequences. A pose graph stores poses and the scan data associated with each pose, which means a session saved today can be reopened next month, extended with new scans while extraneous information is pruned, and reused as the basis for a localization run. A flat occupancy grid cannot do any of that.
The README describes the environment range in concrete terms rather than adjectives: retail, warehouses, libraries and research, with a video collected at Circuit Launch in Oakland, California, where Silicon Valley Robotics provided the testbed. It claims mapping at more than five times real time up to about 30,000 square feet and three times real time up to about 60,000 square feet, with a 200,000 square foot building as the largest synchronous-mode case the author is aware of, and much larger spaces in asynchronous mode.
The four-step pipeline from laser scan to map
The README walks through synchronous mode as four numbered steps, and the sequence is short enough to be genuinely useful when you are trying to work out where a problem lives.
First, the node subscribes to laser scan and odometry topics and publishes a map to odom transform plus a map. Second, a callback for the laser topic generates a pose using odometry and ties a laser scan to it, and these `PosedScan` objects form a queue. Third, that queue builds the pose graph, where odometry is refined through laser scan matching, the graph is used to compute robot pose, and loop closures are sought; when one is found the graph is optimized and pose estimates are updated. Fourth, the scans attached to each pose are used to construct and publish the map.
The useful thing about this description is where it locates the work. Scan matching improving odometry is step three, not a separate stage, and the map is a rendering of the graph rather than something refined directly. When a map looks wrong, the graph and the loop closures are where the explanation usually is.
Synchronous and asynchronous modes are both offered, and the difference is whether the algorithm processes all scans regardless of lag. That choice is the one that determines whether a large building gets mapped at all, and the README is clear that the 200,000 square foot figure came from synchronous mode.
Localization mode, lidar odometry, and multi-robot
Localization mode is an optimization-based mode built on the pose graph, and the README notes you can optionally run it without a prior map. That variant is described as lidar odometry mode with local loop closures, which is useful when you want drift correction over a single session without committing to a stored map.
Beyond that the package covers a set of capabilities the README lists as highlights: point-and-shoot 2D mapping with utilities for saving maps, kinematic map merging, plugin-based optimization solvers with an optimized Google Ceres plugin, an RViz plugin for interacting with the tools directly, and graph manipulation tools in RViz for adjusting nodes and connections while mapping is still running. The RViz editing capability is the underrated one, since correcting a pose graph by hand is otherwise not a practical option.
Multi-robot mapping has its own entry point. `decentralized_multirobot_slam_toolbox_node` extends slam_toolbox for multi-robot mapping, where each robot runs its own instance under a unique namespace and localized scans are exchanged to align the maps. The README describes an elastic graph manipulation merging technique as in the works, which is a candid way of saying the kinematic merging is the finished part and the elastic variant is not.
The repository tree backs up the plugin story with `solver_plugins.xml`, `rviz_plugins.xml`, `solvers/`, `rviz_plugin/`, `config/`, `launch/` and `srv/`, so solvers really are loadable rather than hardcoded.
The 2021 serialization break and how to recover
The most valuable section in this README is the oldest one. Dated 03/23/2021, it announces that serialized file contents changed, and it applies to anyone holding `.posegraph` sessions saved before that date rather than to new users.
The reason was a real bug: the frame storing scan data for the optimizer was incorrect, which caused maps to explode or flip for 360-degree and non-axially-mounted lidar systems when conservative loss functions were used. Fixing it required an ABI-breaking change, which in turn changed the reference frame that data is stored in.
The readme then separates the affected users from the unaffected ones. If your lidar is not a 360 unit and its frame is aligned with the robot base frame, you are unlikely to notice a problem. For everyone else, three options are offered: use the `<distro>-devel-unfixed` branch instead of `<distro>-devel`, convert serialized files into the new reference frame with an offline utility, or take the raw data and rerun the SLAM session. The author also links a Discourse thread and tickets #198 and #281, and apologises for the inconvenience in the same paragraph.
That structure is the part worth copying. A serialized artifact is a compatibility promise, and stating plainly that yours broke, why, and which cases were affected is rarer than it should be.
Building against ROS 2 rolling in a container
The `Dockerfile` at the root builds the package against `ros:rolling-ros-base`, which makes it the most concrete build instruction in the repository. It creates a `colcon_ws/src` directory, clones the `ros2` branch of the project into it, runs `rosdep install` for rolling, then builds and runs the tests:
RUN cd colcon_ws/src && git clone -b ros2 https://github.com/SteveMacenski/slam_toolbox.gitThe build itself passes `-DCMAKE_BUILD_TYPE=Release` and is followed by `colcon test`, so the image runs the test suite rather than just compiling. The package sets `SHELL ["/bin/bash", "-c"]` and pins a noninteractive debconf selection before any apt calls, which are two small details that stop a build from hanging on a prompt.
Two facts sit oddly next to each other and are worth reconciling yourself. The default branch is `ros2`, so cloning without `-b` gives you whatever that branch is, and the Dockerfile's explicit `-b ros2` is doing real work rather than restating the default. Separately, the release tags are version numbers like 2.10.0 and 2.8.5 whose bodies read as distribution syncs, with 2.8.5 labelled `Jazzy Sync April 29, 2026` and 2.10.0 released as `Lyrical initial release`.
The repository is MIT-licensed... in fact the license field reports LGPL-2.1, and `LICENSE` sits in the tree. Since SLAM Toolbox is linked into other ROS packages, the LGPL designation is the one that governs how you redistribute it.
Where to ask questions and what the tree does not tell you
The README routes support deliberately. Questions about use or configuration go to Robotics Stack Exchange with the `slam` and `ros2` tags rather than to GitHub issues, and tangible issues or feature requests go to the tracker. Contributors are asked to open a public issue for substantial patches before writing code, with sensitive work routed to maintainer email addresses in `package.xml`.
There is a real requirement attached to contributions: every pull request must pass CI and maintain ABI compatibility within released ROS distributions. That constraint explains a good deal about the release cadence, since an ABI-stable 2D SLAM package cannot take breaking changes on demand.
What the README does not cover is configuration. There is no parameter reference in it, no example launch file shown, and no explanation of the tuning knobs that decide between synchronous and asynchronous behaviour in practice. Those live in the `config/` directory, the `docs/` directory and the linked ROS 2 Nav2 tutorial, which the README points at for working with Slam Toolbox inside Nav2.
The project has a JOSS paper, `SLAM Toolbox: SLAM for the dynamic world`, by Macenski and Jambrecic, plus a ROSCon 2019 paper on using the package for mapping and localization in the dynamic world. The default branch saw a push on 2026-09-21, and 47 open issues sit against 2,649 stars and 722 forks.
Editorial conclusion
Slam Toolbox makes a bet that most SLAM packages do not: the map is not the deliverable, the pose graph is. Keeping raw scans attached to nodes means you can reopen a session, add data to a building that has changed, or drop into localization mode on an existing graph, which is the difference between mapping once and mapping continuously. The README is unusually willing to talk about its own history, including the 2021 serialization break that invalidated saved sessions for 360 and non-axially-mounted lidar users, and it offers three recovery paths rather than one. What the README does not settle is configuration depth, which lives in the `config/` directory and the wiki. Start by serializing a session, keep the raw bag alongside it, and read the `slam_toolbox` parameters page before you tune anything.
Frequently asked questions
What does SLAM stand for in robotics?
Simultaneous Localization and Mapping. The robot estimates where it is and builds a map of its surroundings at the same time, from the same sensor data. Slam Toolbox does the 2D version of this, taking laser scan and odometry input and publishing a map to odom transform along with a map.
What is ROS SLAM?
It is SLAM performed through the Robot Operating System, with the package subscribing and publishing on ROS topics. Slam Toolbox is described in its README as the currently supported ROS2 SLAM library, and there is a Nav2 tutorial covering working with it inside a navigation stack.
Can you explain the SLAM algorithm?
In the form Slam Toolbox implements it, the algorithm refines odometry with laser scan matching, accumulates results into a pose graph, and looks for loop closures that revisit earlier places. When a loop closure is found the pose graph is optimized and pose estimates are updated, then the scans attached to each pose are rendered into the published map.
What does SLAM mean in lidar?
It means building a map and fixing the sensor's position from lidar scans, with no other reference to compare against. Slam Toolbox supports this as lidar odometry mode, an optimization-based localization mode run without a prior map, using local loop closures to correct drift within the session rather than against a stored map.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/stevemacenski-slam-toolbox)