Cartographer Map Building
Function Pack Introduction
Cartographer is an open-source SLAM (Simultaneous Localization and Mapping) library, which is for real-time map building and positioning for robots or mobile devices. It is developed by Google and is widely applied in ROS (Robot Operating System).
Cartographer utilizes multiple sensors, such as LiDAR, Inertial Measurement Units (IMU), and cameras, to gather perceptual data from the environment. Through SLAM algorithms, it fuses these data sources to achieve Simultaneous Localization and Mapping. Cartographer can dynamically generate high-quality maps in real-time in unknown environments, providing accurate localization information for robots.
Demo
Install cartographer
Using apt to install cartographer:
sudo apt install ros-humble-cartographer sudo apt install ros-humble-cartographer-ros
Check the installation:
ros2 pkg list | grep cartographer
When outputting the following content, it is successfully installed:
cartographer_ros cartographer_ros_msgs
Create Function Pack
Enter workspace:
cd */ugv02/src
Create the function pack:
ros2 pkg create ugv02_cartographer
Create the launch and config file folder:
cd ugv02_cartographer mkdir config launch
Compile cartographer Map Building
Create the cartographer_2d.lua file (configuration file) in the ugv02_cartographer/config directory:
include "map_builder.lua"
include "trajectory_builder.lua"
options = {
map_builder = MAP_BUILDER,
trajectory_builder = TRAJECTORY_BUILDER,
map_frame = "map", -- map frame name
tracking_frame = "laser_link", -- tracking frame name
published_frame = "base_link", -- published frame name
odom_frame = "odom", -- name of the odometer frame
provide_odom_frame = true, -- whether to provide the odometer frame
publish_frame_projected_to_2d = false, -- whether to publish 2d gesture
use_pose_extrapolator = false,
use_odometry = false, -- whether use odometry
use_nav_sat = false, -- whether use the navigation satellite
use_landmarks = false, -- whether use the landmark
num_laser_scans = 1, -- LiDAR number
num_multi_echo_laser_scans = 0, -- number of multi-echo LiDAR
num_subdivisions_per_laser_scan = 1, -- number of subdivisions for each laser scan
num_point_clouds = 0, -- number of cloud points
lookup_transform_timeout_sec = 0.2, -- timeout for finding transformations (seconds)
submap_publish_period_sec = 0.3, -- submap release cycle (seconds)
pose_publish_period_sec = 5e-3, -- attitude release period (seconds)
trajectory_publish_period_sec = 30e-3, -- trajectory release period (seconds)
rangefinder_sampling_ratio = 1., -- rangefinder sampling ratio
odometry_sampling_ratio = 1., -- odometer sampling rate
fixed_frame_pose_sampling_ratio = 1., -- fixed frame attitude sampling ratio
imu_sampling_ratio = 1., -- IMU sampling ratio
landmarks_sampling_ratio = 1., -- landmarks sampling ratio
}
MAP_BUILDER.use_trajectory_builder_2d = true -- whether use 2D SLAM
TRAJECTORY_BUILDER_2D.submaps.num_range_data = 35 -- Number of range data for submaps in the 2D track builder
TRAJECTORY_BUILDER_2D.min_range = 0.1 -- ignore anything smaller than the robot radius, limiting it to the minimum scan range of the lidar
TRAJECTORY_BUILDER_2D.max_range = 3.5 -- the maximum scanning range of the lidar
TRAJECTORY_BUILDER_2D.missing_data_ray_length = 5. -- Restricted to maximum LiDAR scanning range
TRAJECTORY_BUILDER_2D.use_imu_data = false -- whether use IMU data
TRAJECTORY_BUILDER_2D.use_online_correlative_scan_matching = true -- Whether to scan for matches using real-time loopback detection
TRAJECTORY_BUILDER_2D.motion_filter.max_angle_radians = math.rad(0.1) -- Modify 1.0 to 0.1, increased sensitivity to movement
POSE_GRAPH.constraint_builder.min_score = 0.65 -- Modify 0.55 to 0.65, the minium score of Fast csm, can be optimized above this score
POSE_GRAPH.constraint_builder.global_localization_min_score = 0.7 -- Modify 0.6 as 0.7, Minimum global positioning score below which global positioning is considered currently inaccurate
return options
Create cartographer.launch.py file under the path of src/ugv02_cartographer/launch/, and then you will start writing the launch file that starts the cartographer build node.
import os
from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
def generate_launch_description():
# Positioning function pack
pkg_share = FindPackageShare(package='ugv02_cartographer').find('ugv02_cartographer')
# Configure node launch information
use_sim_time = LaunchConfiguration('use_sim_time', default='true')
# Map resolution
resolution = LaunchConfiguration('resolution', default='0.05')
# Map publish period
publish_period_sec = LaunchConfiguration('publish_period_sec', default='1.0')
# Configuration file folder path
configuration_directory = LaunchConfiguration('configuration_directory',default= os.path.join(pkg_share, 'config') )
# Configuration file
configuration_basename = LaunchConfiguration('configuration_basename', default='cartographer_2d.lua')
#Nodes
cartographer_node = Node(
package='cartographer_ros',
executable='cartographer_node',
name='cartographer_node',
output='screen',
parameters=[{'use_sim_time': use_sim_time}],
arguments=['-configuration_directory', configuration_directory,
'-configuration_basename', configuration_basename])
cartographer_occupancy_grid_node = Node(
package='cartographer_ros',
executable='cartographer_occupancy_grid_node',
name='cartographer_occupancy_grid_node',
output='screen',
parameters=[{'use_sim_time': use_sim_time}],
arguments=['-resolution', resolution, '-publish_period_sec', publish_period_sec])
#Launch file
ld = LaunchDescription()
ld.add_action(cartographer_node)
ld.add_action(cartographer_occupancy_grid_node)
return ld
Open src/ugv02_cartographer/CmakeLists.txt, add the installation command, and the system can find these files after compiling.
install(
DIRECTORY config launch
DESTINATION share/${PROJECT_NAME}
)
Compile
Return the workspace and compile:
cd ~/ugv02 colcon build
Running Test
Open a new terminal, navigate to the workspace, source it, and start the radar as per the instructions in the tutorial "UGV02 Radar Tutorial" (ensure the serial port is authorized).
cd ~/ugv02 source ./install/setup.bash ros2 launch ldlidar_stl_ros2 ld19.launch.py
Open a new terminal, navigate to the workspace, source it, and launch the map building.
cd ~/ugv02 source ./install/setup.bash ros2 launch ugv02_cartographer cartographer.launch.py
In a computer (virtual machine) with Ubuntu and ros2, make sure that the computer is connected to the same network or wifi as the Raspberry Pi, and open a new terminal.
rviz2
Click on the add button in the bottom left corner of rviz to add a control to rviz to display the map:

The map effect is shown below:

Next, you can follow the Ugv02 Using LiDAR Tutorial to add LiDAR point cloud data display and vehicle coordinate frame in RViz. Then, refer to Chassis Control Tutorial to control the movement of the robot and observe the mapping process.
When you feel the map is OK, use the following command to save the map.
First, install the map management package.
sudo apt install ros-humble-nav2-map-server
Run the map-saving command with the last parameter being the path and name of the map.
ros2 run nav2_map_server map_saver_cli -f ./map