Design & Selection · Module 09
Which SLAM algorithm should I select?
First eliminate what your sensors cannot feed. Then compare the remaining ones on ROS 2 support, loop closure and your environment.
Assumptions: Numbers in the examples are illustrative and the code is executed by the site’s tests. Facts taken from a cited source are marked; other statements are general engineering knowledge and must be confirmed on the datasheet of the part you use.
1. Engineering problem
There are many open-source SLAM packages and they differ most in what they need: a 2D LiDAR and odometry, a camera, or a 3D LiDAR with per-point time and an IMU. Choosing by popularity or by a benchmark number from a different sensor setup leads to a package that cannot run on your robot.
2. When is this needed?
- Starting a new robot’s localisation and mapping.
- When changing sensors.
- When a chosen package turns out to need an input you do not have.
3. Selection and design decisions
Input requirements stated in the READMEs (read 2026-11-06): slam_toolbox works from laser scans and odometry, supports synchronous and asynchronous mapping, a lifelong-mapping mode on a serialized pose graph and a localisation mode, and its README calls it the currently supported ROS 2 SLAM library. ORB-SLAM3 does visual, visual-inertial and multi-map SLAM with monocular, stereo and RGB-D cameras. LIO-SAM needs per-point time stamps and ring numbers in the point cloud and, per its README, works only with a 9-axis IMU. FAST-LIO is a tightly coupled iterated EKF lidar-inertial odometry package that supports spinning and solid-state LiDARs and needs per-point time stamps and a synchronised IMU. See also the SLAM selection tool.
| Package | Inputs | Stated capability | Verify yourself |
|---|---|---|---|
| slam_toolbox | 2D laser scan, odometry | Mapping, lifelong mapping, localisation; ROS 2 | Scan rate and range for your sensor |
| ORB-SLAM3 | Camera (mono, stereo, RGB-D), optional IMU | Visual and visual-inertial, multi-map | ROS 2 support; calibration files |
| LIO-SAM | 3D LiDAR with time and ring, 9-axis IMU | LiDAR-inertial smoothing and mapping | ROS 2 branch; IMU extrinsics |
| FAST-LIO | 3D LiDAR with per-point time, IMU | Tightly coupled LiDAR-inertial odometry | ROS 2 port; synchronisation |
4. Advantages and disadvantages
- 2D vs 3D: 2D LiDAR SLAM is light and works on flat floors; 3D handles ramps, multi-floor and open space and needs more compute.
- LiDAR vs visual: LiDAR is geometry-based and works in the dark; cameras give appearance and fail in low light or texture.
- Loop closure and map reuse exist in some packages and not others; check what you need.
5. Requirements and constraints
- Inputs match the stated requirements, including per-point time and ring where needed.
- ROS distribution support is confirmed in the current repository, not assumed.
- Compute fits (see the compute guides).
6. Architecture
sensors you have ─▶ filter by required inputs ─▶ filter by ROS 2 and loop closure ─▶ test the remaining candidates on your own recorded data7. Implementation
- List your sensors and their data fields (per-point time, ring, IMU axes).
- Filter the candidates by their stated inputs (below).
- Check ROS distribution support and the activity of the repository.
- Record a representative dataset on your robot.
- Run the remaining candidates on that dataset and compare drift and loop-closure gap (see the evaluation guide).
REQ = { # input requirements as stated in each project's README / documentation
"slam_toolbox": {"needs": {"lidar2d", "odom"}, "ros2": True},
"ORB-SLAM3": {"needs_any": [{"camera"}, {"camera", "imu"}], "ros2": False},
"LIO-SAM": {"needs": {"lidar3d_time_ring", "imu9"}, "ros2": False},
"FAST-LIO": {"needs": {"lidar3d_time", "imu"}, "ros2": False},
}
def applicable(have, want_ros2):
out = []
for name, r in REQ.items():
ok = r["needs"] <= have if "needs" in r else any(s <= have for s in r["needs_any"])
if ok:
out.append(name + ("" if r["ros2"] or not want_ros2 else " (README does not state ROS 2: verify)"))
return out or ["none of these"]
print("2D LiDAR + wheel odometry:", applicable({"lidar2d", "odom"}, True))
print("3D LiDAR with time+ring, 6-axis IMU:", applicable({"lidar3d_time_ring", "lidar3d_time", "imu"}, True))
print("3D LiDAR with time+ring, 9-axis IMU:", applicable({"lidar3d_time_ring", "lidar3d_time", "imu", "imu9"}, False))
print("camera only:", applicable({"camera"}, False))Printed (checked by the site’s tests):
2D LiDAR + wheel odometry: ['slam_toolbox']
3D LiDAR with time+ring, 6-axis IMU: ['FAST-LIO (README does not state ROS 2: verify)']
3D LiDAR with time+ring, 9-axis IMU: ['LIO-SAM', 'FAST-LIO']
camera only: ['ORB-SLAM3']Reading it: a 2D LiDAR with odometry leaves slam_toolbox; a 3D LiDAR with a 6-axis IMU leaves FAST-LIO (not LIO-SAM, which asks for a 9-axis IMU) and the ROS 2 note tells you to check the port; with a 9-axis IMU both qualify; a camera alone leaves ORB-SLAM3. The requirement table is a simplified summary of the READMEs and is illustrative of the method, not a ranking of quality.
8. Real examples
- Indoor AMR with a 2D LiDAR: slam_toolbox in asynchronous mapping mode, then localisation mode in service.
9. Failure scenarios
- Picking LIO-SAM and discovering the IMU has no orientation output.
- Reading a benchmark of a different sensor setup.
- Assuming ROS 2 support from a ROS 1 README.
10. Troubleshooting
- If the package will not start, check its input message fields first.
- If results differ from the README’s demo, compare sensor rate, time stamps and extrinsics.
11. Validation
- The filter prints the lines shown (executed by the site tests).
- The chosen package runs on your recorded data with drift below the requirement.
12. Engineering checklist
13. Further references
- READMEs of the projects, read 2026-11-06: slam_toolbox, ORB-SLAM3, LIO-SAM, FAST-LIO, VINS-Fusion.