Welcome to ROSMASTER A1 PRO repository
7.Slam-Toolbox Mapping
🗺️ Slam-Toolbox Mapping
1. Course Content
Master using SLAM-Toolbox (online synchronous mode) for 2D laser SLAM mapping.
Master remote controlling the A1 Pro robot for mapping and viewing laser scan matching and pose graph optimization process in RViz2.
Master methods for saving standard OccupancyGrid raster maps (
.yaml+.pgm) and SLAM-Toolbox pose graph files (.posegraph+.data).
2. SLAM-Toolbox Introduction
SLAM-Toolbox is an open-source 2D SLAM (Simultaneous Localization and Mapping) algorithm package officially recommended and deeply integrated by ROS 2, led by ROS navigation and localization working group expert Steve Macenski. It is based on Graph-based SLAM theoretical framework, designed for mapping and localization in long-cycle, large-scale dynamic environments.
Front-End Scan Matching: Through continuous scan buffer and correlative scan matching (CSM / Karto Scan Matcher), multiple frames of LaserScan lidar point cloud are quickly registered with odometry prior to generate continuous pose nodes.
Back-End Graph Optimization: Background constructs pose graph based on Google Ceres nonlinear optimization solver, and when loop closure is triggered, combines HuberLoss robust kernel function to perform global pose graph relaxation and optimization, eliminating accumulated drift.
Features and Advantages:
Lifelong/Continuing Mapping: Supports loading existing pose graph files and continuing to expand and correct on historical maps.
Map Serialization and Deserialization: Natively supports saving complete graph structure (pose nodes and original scan point cloud) as
.posegraphand.datafiles.Low CPU Usage and High Real-time Performance: Compared to traditional algorithms, multi-threaded architecture and sparse graph optimization mechanism greatly reduce computational overhead, very suitable for embedded edge computing platforms.

3. Preparation and Running
This example requires opening 3~4 terminals to start the following nodes in sequence:
3.1 Start SLAM-Toolbox Mapping Node
Run in Terminal 1 (automatically starts chassis driver, lidar driver, and SLAM-Toolbox core algorithm):
xxxxxxxxxxros2 launch yahboomcar_nav map_slam_toolbox_launch.py
3.2 Start RViz Map Visualization
Run in Terminal 2 (it is recommended to open RViz on the virtual machine if the VM and robot are on the same LAN):
xxxxxxxxxxros2 launch yahboomcar_nav display_map_launch.py
3.3 Start Keyboard Control to Move Robot for Mapping
Run in Terminal 3 the keyboard control node:
xxxxxxxxxxros2 run yahboomcar_ctrl yahboom_keyboard
3.4 Mapping Operation and Map Save Instructions
Mapping Driving Suggestions:
Remote control the robot to slowly and smoothly drive through the entire environment to be tested, observe the continuous matching of laser point cloud and real-time expansion of occupancy grid map in RViz.
Appropriately reduce speed at turns to allow the lidar sufficient frame rate to update the local buffer.
After driving one loop and returning near the starting point to form a loop closure, the system automatically triggers global loop closure detection and optimizes the entire pose graph, eliminating corridor accumulated error.

Save 2D Raster Map (.yaml + .pgm): After mapping is complete, run the raster map save command in Terminal 4:
xxxxxxxxxxros2 launch yahboomcar_nav save_map_launch.py map_name:=map
Map files will be saved in
~/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_nav/maps/directory, including:map.yaml: Map metadata configuration file (including resolution, origin pose, occupancy threshold, etc.).map.pgm: Grayscale raster image file (white for free traversable areas, black for obstacles, gray for unknown areas).
Save SLAM-Toolbox Pose Graph File (.posegraph + .data): The pose graph file contains complete topological graph nodes, loop closure constraints, and original laser scan data, which is the core data required for subsequent SLAM-Toolbox continuing mapping or pure localization navigation:
xxxxxxxxxxros2 launch yahboomcar_nav save_map_launch.py map_type:=posegraph map_name:=map
After successful saving, generated files:
map.posegraph: Pose graph topological structure and optimized node metadata.map.data: Binary file of original laser point cloud scan measurement data for each node.

Note
After saving is complete, press Ctrl+C in each terminal to stop the program.
4. Core Source Code and Algorithm Parameter Analysis
4.1 Mapping Launch File Analysis
Launch File Path:
xxxxxxxxxx$HOME/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_nav/launch/slam/map_slam_toolbox_launch.py
Launch Core Source
xxxxxxxxxxdef generate_launch_description(): package_dir = get_package_share_directory("yahboomcar_nav")
# 1. Declare Launch arguments declared_arguments = [] declared_arguments.append( DeclareLaunchArgument( "pose_graph", default_value="", description="Pose graph basename or absolute path, without .posegraph/.data extension. Empty starts a new map." ) ) declared_arguments.append( DeclareLaunchArgument( "slam_mode", default_value="sync", choices=["sync", "async"], description="SLAM mode selection. Sync is recommended for repeatable mapping." ) ) declared_arguments.append( DeclareLaunchArgument( "initial_pose_mode", default_value="rviz", choices=["rviz", "dock"], description="How to initialize an existing pose graph: select pose in RViz or start at dock." ) ) declared_arguments.append( DeclareLaunchArgument( "odom_source", default_value="wheel", choices=["wheel", "fused"], description="Odometry input: 'wheel' uses independent Ackermann wheel odometry; 'fused' uses RF2O/IMU EKF pipeline." ) )
pose_graph = LaunchConfiguration("pose_graph") slam_mode = LaunchConfiguration("slam_mode") initial_pose_mode = LaunchConfiguration("initial_pose_mode")
# 2. Chassis and lidar driver start (select independent wheel odometry or EKF fused odometry based on odom_source) wheel_bringup_launch = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(package_dir, "launch", "robot", "laser_bringup_launch.py") ), condition=LaunchConfigurationEquals("odom_source", "wheel"), )
fused_bringup_launch = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(package_dir, "launch", "robot", "laser_bringup_rf2o_launch.py") ), condition=LaunchConfigurationEquals("odom_source", "fused"), )
# 3. Introduce SLAM-Toolbox algorithm node and relocalization scheduling slam_toolbox_launch = IncludeLaunchDescription( PythonLaunchDescriptionSource( os.path.join(package_dir, "launch", "slam", "slam_toolbox_wit_launch.py") ), launch_arguments={ "pose_graph": pose_graph, "slam_mode": slam_mode, "initial_pose_mode": initial_pose_mode, }.items(), )
return LaunchDescription([ *declared_arguments, wheel_bringup_launch, fused_bringup_launch, slam_toolbox_launch, ])Launch Design Highlights
odom_sourceOdometry Source Selection: Defaults towheel(independent Ackermann wheel odometry). Since the lidar field of view is 235° forward, using independent wheel odometry avoids using the same limited FOV lidar data for both RF2O laser odometry and SLAM-Toolbox, preventing error positive feedback coupling.slam_modeSync/Async Mode: Defaults tosync(online synchronous mode), ensuring every lidar frame is strictly processed and pose graph node updated, with higher mapping consistency and boundary sharpness.Continuing Mapping and Relocalization Support: Through
pose_graphandinitial_pose_modeparameters, supports loading historical.posegraphfiles, and after giving initial pose in RViz viaslam_pose_initializernode, smoothly expands historical map.
4.2 SLAM-Toolbox Node Scheduling Analysis
File Path:
xxxxxxxxxx$HOME/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_nav/launch/slam/slam_toolbox_wit_launch.py
slam_toolbox_wit_launch.py as the SLAM core scheduling layer has the following core logic:
Pose Graph File Integrity Check: Automatically verifies whether the specified historical map
.posegraphand.datafiles are complete.Dynamic Node Loading: Dynamically executes
sync_slam_toolbox_nodeorasync_slam_toolbox_nodebased onslam_mode.Initial Pose Relocalization Access: When loading historical map and
initial_pose_mode == 'rviz', automatically startsslam_pose_initializernode, intercepts lidar point cloud and after RViz gives/initialposeinitial pose, calls/slam_toolbox/deserialize_mapservice to complete relocalization.
4.3 Map Save Mechanism Analysis
File Path:
xxxxxxxxxx$HOME/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_nav/launch/slam/save_map_launch.py
xxxxxxxxxx# 1. Save pose graph (map_type == 'posegraph')save_posegraph = GroupAction( condition=IfCondition(PythonExpression(["'", map_type, "' == 'posegraph'"])), actions=[ ExecuteProcess( cmd=[ 'ros2', 'service', 'call', '/slam_toolbox/serialize_map', 'slam_toolbox/srv/SerializePoseGraph', ['{filename: "', PathJoinSubstitution([map_save_dir, map_name]), '"}'] ], output='screen' ) ])
# 2. Save 2D raster map (map_type == 'gridmap')save_map = Node( package='nav2_map_server', executable='map_saver_cli', parameters=[{ 'map_subscribe_transient_local': False, 'save_map_timeout': 10.0, }], arguments=[ '-f', PathJoinSubstitution([map_save_dir, map_name]), '--free', '0.196', '--occ', '0.65' ], condition=IfCondition(PythonExpression(["'", map_type, "' == 'gridmap'"])))Raster Map Save: Calls
nav2_map_server'smap_saver_clinode, subscribes to/maptopic and marks grids with occupancy probability greater than 0.65 as obstacles, less than 0.196 as free, outputting.yamland.pgm.Pose Graph Save: Calls
/slam_toolbox/serialize_mapservice, SLAM-Toolbox internally serializes the pose graph and original laser frames in memory to disk files.
4.4 SLAM-Toolbox Algorithm Configuration and Core Parameter Interpretation
Configuration File Path:
xxxxxxxxxx$HOME/yahboomcar_ros2_ws/yahboomcar_ws/src/yahboomcar_nav/params/mapper_params_online_sync.yaml
Core Parameter Description Table
| Parameter Name | Current Config Value | Core Function and Physical Meaning |
|---|---|---|
solver_plugin | CeresSolver | Graph optimization back-end nonlinear least squares solver plugin (based on Google Ceres) |
ceres_loss_function | HuberLoss | Robust kernel function for optimization objective, preventing map distortion from edge incorrect loop closure constraints |
mode | mapping | Working mode: mapping / localization |
resolution | 0.05 | Occupancy grid map resolution (0.05 meters/pixel) |
min_laser_range / max_laser_range | 0.1 / 10.0 | Shortest and longest effective laser ranging distance for rasterization mapping (meters) |
minimum_travel_distance | 0.1 | Robot straight-line displacement threshold (meters), insert new pose graph node when moved beyond this value |
minimum_travel_heading | 0.01745 | Robot rotation displacement threshold (approximately 1°), insert node even for tiny rotations to ensure dense turn point cloud |
scan_buffer_size | 30 | Local sliding window scan buffer size, similar to Cartographer's Submap submap mechanism |
scan_buffer_maximum_scan_distance | 5.0 | Maximum spatial allowed distance between laser frames in scan buffer (meters) |
do_loop_closing | true | Whether to enable global loop closure detection and loop graph optimization |
loop_search_maximum_distance | 4.0 | Maximum candidate spatial search radius for triggering loop matching (meters) |
loop_match_minimum_chain_size | 12 | Minimum continuous matching frame chain length required for loop matching, strictly filtering occasional false positive matches |
loop_match_minimum_response_fine | 0.55 | Loop fine matching score threshold (0~1.0), only establishes loop edge when score exceeds this threshold |
distance_variance_penalty | 0.25 | Penalty factor for displacement variance when geometric features degrade (such as featureless long corridors), tending to trust wheel odometry |
angle_variance_penalty | 0.25 | Penalty factor for angular variance when geometric features degrade |
YAML Configuration File Complete Source
slam_toolbox ros__parameters
# 1. Ceres graph optimization back-end solver configuration solver_pluginsolver_pluginsCeresSolver ceres_linear_solverSPARSE_NORMAL_CHOLESKY ceres_preconditionerSCHUR_JACOBI ceres_trust_strategyLEVENBERG_MARQUARDT ceres_dogleg_typeTRADITIONAL_DOGLEG ceres_loss_functionHuberLoss
# 2. ROS coordinate frame and base topic parameters odom_frameodom map_framemap base_framebase_footprint scan_topic/scan use_map_savertrue modemapping
debug_loggingfalse throttle_scans1 transform_publish_period0.03 map_update_interval5.0 resolution0.05 min_laser_range0.1 max_laser_range10.0 minimum_time_interval0.5 transform_timeout0.2 tf_buffer_duration30. stack_size_to_use40000000 enable_interactive_modetrue
# 3. Front-end scan matching and pose graph node insertion strategy use_scan_matchingtrue use_scan_barycentertrue minimum_travel_distance0.1 minimum_travel_heading0.01745 # 1 degree scan_buffer_size30 scan_buffer_maximum_scan_distance5.0 link_match_minimum_response_fine0.2 link_scan_maximum_distance1.5 loop_search_maximum_distance4.0 do_loop_closingtrue
# 4. Loop closure detection (Loop Closure) and constraint construction thresholds loop_match_minimum_chain_size12 loop_match_maximum_variance_coarse1.5 loop_match_minimum_response_coarse0.45 loop_match_minimum_response_fine0.55
# 5. Correlation matching search space parameters correlation_search_space_dimension0.5 correlation_search_space_resolution0.01 correlation_search_space_smear_deviation0.1
# 6. Loop search space parameters loop_search_space_dimension6.0 loop_search_space_resolution0.05 loop_search_space_smear_deviation0.03
# 7. Scan matcher and odometry prior penalty factors distance_variance_penalty0.25 angle_variance_penalty0.25 fine_search_angle_offset0.00349 coarse_search_angle_offset0.2618 # 15 degrees coarse_angle_resolution0.01745 # 1 degree minimum_angle_penalty0.5 minimum_distance_penalty0.5 use_response_expansionfalse min_pass_through3 occupancy_threshold0.2