FixTheRobot Explore Robotics / Systems Engineering / Design & Selection / Module 09

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.

  • Intermediate
  • Module 09: SLAM Selection, Configuration & Troubleshooting
  • Written for ROS 2 Jazzy where ROS 2 is used
  • Sources checked 2026-11-06

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.

Overview
PackageInputsStated capabilityVerify yourself
slam_toolbox2D laser scan, odometryMapping, lifelong mapping, localisation; ROS 2Scan rate and range for your sensor
ORB-SLAM3Camera (mono, stereo, RGB-D), optional IMUVisual and visual-inertial, multi-mapROS 2 support; calibration files
LIO-SAM3D LiDAR with time and ring, 9-axis IMULiDAR-inertial smoothing and mappingROS 2 branch; IMU extrinsics
FAST-LIO3D LiDAR with per-point time, IMUTightly coupled LiDAR-inertial odometryROS 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 data

7. Implementation

  1. List your sensors and their data fields (per-point time, ring, IMU axes).
  2. Filter the candidates by their stated inputs (below).
  3. Check ROS distribution support and the activity of the repository.
  4. Record a representative dataset on your robot.
  5. 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

  1. If the package will not start, check its input message fields first.
  2. 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

Related on FixTheRobot