4. SLAM建图:激光SLAM原理、Cartographer使用、地图保存

在机器人路径规划中,地图是决策的基础。没有一张可用的栅格地图,全局路径规划与局部避障都无从谈起。本章聚焦于激光SLAM建图,重点讲解其核心原理、Cartographer工具的实际使用流程,以及地图的保存与格式转换。

4.1 激光SLAM核心原理:从扫描到占据栅格

激光SLAM(Simultaneous Localization and Mapping)的核心任务可以概括为:机器人在未知环境中,一边利用激光雷达感知周围障碍物,一边估计自身位姿,同时增量式地构建环境地图。其本质是一个“先有鸡还是先有蛋”的循环问题——定位需要地图,建图需要位姿,因此SLAM算法必须联合求解。

在ROS2中,最常用的激光SLAM算法是Cartographer,它由Google开源,采用图优化(Graph-based SLAM)框架。其核心思想分为两个层级:

  • 局部匹配(前端):利用当前激光帧与最近一段时间的子图(Submap)进行扫描匹配,得到相对位姿。Cartographer采用非线性最小二乘优化(如Ceres Solver)来求解帧与子图间的刚体变换,从而获得高频、低精度的局部轨迹。
  • 全局闭环(后端):当机器人回到曾经访问过的区域时,通过分支定界(Branch and Bound)搜索算法在历史子图中寻找匹配,一旦检测到闭环,则触发一次全局的位姿图优化,消除累积漂移,得到全局一致的轨迹与地图。

最终生成的地图是占据栅格地图(Occupancy Grid Map)。每个栅格存储一个概率值,表示该位置被障碍物占据的可能性。在ROS2中,该值通常以0~100表示占据概率,-1表示未知区域。

关键概念区分:前端负责“短时准”,后端负责“长时稳”。如果只跑前端,地图会因累积误差而扭曲;只有后端闭环生效,才能保证大场景地图的全局一致性。
Cartographer 激光SLAM 核心数据流与优化闭环 激光雷达 /scan (LaserScan) IMU / 里程计 /imu /odom 前端:局部匹配 扫描匹配 + 位姿估计 Ceres 非线性优化 高频低精度 子图 Submap 局部栅格地图 累积多帧扫描 后端:闭环检测 分支定界搜索 全局位姿图优化 消除累积漂移 最终占据栅格地图 /map (OccupancyGrid) 闭环约束反馈优化 传感器输入 前端处理 中间表示 后端优化 最终输出

4.2 Cartographer在ROS2中的安装与配置

在ROS2环境中使用Cartographer,通常通过二进制安装或源码编译。以Humble版本为例,推荐使用apt安装:

sudo apt install ros-humble-cartographer
sudo apt install ros-humble-cartographer-ros

安装完成后,需要准备两个关键配置文件:Lua脚本(用于定义算法参数)和URDF模型(用于描述机器人底盘与雷达的外参)。一个典型的Lua配置片段如下:

include "map_builder.lua"
include "trajectory_builder.lua"

options = {
  map_builder = MAP_BUILDER,
  trajectory_builder = TRAJECTORY_BUILDER,
  map_frame = "map",
  tracking_frame = "base_link",
  published_frame = "odom",
  odom_frame = "odom",
  provide_odom_frame = true,
  use_odometry = true,
  num_laser_scans = 1,
  num_subdivisions_per_laser_scan = 1
}

return options

启动建图时,通常需要同时启动三个节点:激光雷达驱动、Cartographer节点以及可视化节点RViz2。可以使用如下命令:

ros2 launch cartographer_ros cartographer.launch.py \
  configuration_basename:="my_robot.lua"
常见坑:Cartographer对TF树要求严格。必须保证 map → odom → base_link → laser 的TF链路完整且频率稳定。如果雷达外参标定不准,会导致地图出现“重影”或“拖尾”现象。

4.3 实操案例:使用Cartographer构建室内地图

以下是一个典型的建图流程,假设你已有一个发布/scan话题的2D激光雷达,以及一个可遥控的差速底盘。

  1. 启动底盘与雷达驱动:确保/odom与/scan话题正常输出。
  2. 启动Cartographer:加载Lua配置,开始接收数据并构建子图。
  3. 遥控机器人运动:缓慢平移并旋转,避免原地高速旋转,确保激光帧有足够重叠。
  4. 观察RViz2中的实时地图:检查是否有明显错位或漂移。
  5. 触发闭环:让机器人回到起点附近,观察地图是否自动校正对齐。

下表总结了建图过程中的关键参数与建议值:

参数名 建议值 作用说明
use_odometry true 融合轮式里程计,提高短时精度
num_laser_scans 1 单雷达配置为1
map_resolution 0.05 栅格分辨率(米/像素)
tracking_frame base_link 机器人本体坐标系
loop_closure_automatic true 自动闭环检测

4.4 地图保存与格式转换

建图完成后,需要将Cartographer的当前地图快照保存为静态地图文件,供后续导航使用。Cartographer本身不直接保存pgm/yaml,而是通过map_saver节点来订阅/map话题并保存。

ros2 run nav2_map_server map_saver_cli -f ~/map/my_room

执行后,会生成两个文件:my_room.pgm(图像文件)和my_room.yaml(元数据文件)。其中yaml内容类似:

image: my_room.pgm
resolution: 0.050000
origin: [-10.0, -10.0, 0.0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196

在保存地图前,务必在RViz2中确认/map话题的显示正常,且地图边界完整。如果地图存在大量黑色噪点,可以先用map_editor工具或图像处理软件清理后再保存。

专业建议:保存地图时,机器人应停在起始点附近,且地图方向尽量与真实世界坐标轴对齐。这样后续在AMCL定位时,初始位姿估计会更准确。

4.5 常见误区与复盘

在实际建图过程中,初学者常犯以下错误,导致地图质量不佳:

  • 误区一:雷达频率过低。如果雷达扫描频率低于5Hz,机器人运动稍快就会造成帧间匹配失败,地图出现断裂。建议使用10Hz以上的雷达。
  • 误区二:忽略IMU的作用。对于不平坦地面或底盘打滑明显的情况,仅靠轮式里程计无法提供足够的运动约束,此时应配置IMU并设置use_imu = true。
  • 误区三:建图时速度过快。Cartographer虽然鲁棒,但过快的角速度会导致激光帧变形,建议线速度不超过0.5m/s,角速度不超过0.5rad/s。
  • 误区四:保存地图前未等待闭环完成。如果地图还在漂移中就保存,会导致导航时定位失败。正确做法是观察地图稳定后再保存。

复盘一个典型失败案例:某次建图时,地图在走廊尽头出现明显的“分叉”现象。排查后发现,原因是雷达的安装位置与URDF中描述的偏移量不一致,导致前端匹配时引入了系统性误差。修正外参后,重新建图,地图恢复正常。这提醒我们:外参标定是SLAM建图的前提,任何微小的安装偏差都会在长时间建图中被放大。

通过本章的学习,你已经掌握了激光SLAM的核心原理、Cartographer的配置与使用、地图保存方法以及常见问题的排查思路。在下一阶段,你将基于这张静态地图,开展机器人的自主定位与路径规划实验。