2. SLAM基础回顾
在进入“语义标签与地图标注联动”这一核心主题之前,我们必须先夯实SLAM(Simultaneous Localization and Mapping,同步定位与建图)的基础。SLAM解决的是“机器人在哪里”和“周围环境长什么样”这两个互为前提的问题——定位需要地图,建图需要位姿,二者必须同时求解。在ROS2生态中,Cartographer和SLAM Toolbox是两款主流的2D SLAM工具,它们各自代表了不同的算法流派与工程权衡。本章将系统梳理SLAM的基本原理、ROS2中的工具选型、地图的数据表示方式以及关键术语,为后续语义标签的叠加与联动建立共同的语言基础。
2.1 SLAM核心原理:从概率估计到图优化
SLAM的本质是一个状态估计问题。机器人携带传感器在未知环境中运动,我们需要同时估计两个未知量:机器人自身的轨迹(位姿序列)和环境的地图。在数学上,这可以建模为最大后验概率(MAP)估计问题:给定传感器观测数据 \( z_{1:t} \) 和控制输入 \( u_{1:t} \),求解最可能的机器人位姿 \( x_{1:t} \) 和地图 \( m \)。
现代SLAM系统普遍采用图优化(Graph-based SLAM)框架,将问题转化为一个稀疏图的优化问题。图中节点表示机器人的位姿或 landmark,边表示位姿之间的约束(来自里程计、扫描匹配或回环检测)。优化目标是调整所有节点的位姿,使所有约束的误差最小化。这种方法的优势在于:回环检测可以一次性修正历史轨迹的累积漂移,而不是像滤波方法(如EKF-SLAM)那样只能局部修正。
在ROS2中,SLAM工具链通常分为前端(Front-end)和后端(Back-end)两部分。前端负责处理传感器数据,进行帧间配准(scan-to-scan或scan-to-map),输出相对位姿约束;后端则维护位姿图,执行图优化和回环检测。以Cartographer为例,其前端使用Ceres Solver进行非线性最小二乘优化,后端则采用稀疏位姿图(SPA)方法,通过分支定界(Branch and Bound)算法加速回环搜索。
slam_toolbox和cartographer都遵循这一架构,但实现细节和参数调优差异显著。
2.2 地图表示:栅格地图与点云地图
地图是SLAM的输出,也是后续语义标注的载体。在ROS2中,最常用的两种地图表示是栅格地图(Occupancy Grid Map)和点云地图(Point Cloud Map)。它们各有优劣,适用于不同的任务场景。
| 维度 | 栅格地图 (OccupancyGrid) | 点云地图 (PointCloud2) |
|---|---|---|
| 数据结构 | 二维数组,每个格子存储占据概率(0-100) | 三维点集,每个点包含(x,y,z)坐标及可选属性(强度、RGB) |
| ROS2消息类型 | nav_msgs/msg/OccupancyGrid |
sensor_msgs/msg/PointCloud2 |
| 空间维度 | 2D(平面) | 2D或3D |
| 分辨率 | 固定分辨率(如0.05m/像素) | 点密度可变,无固定分辨率 |
| 内存占用 | 低(与地图面积成正比) | 高(与点数成正比) |
| 适用场景 | 2D导航、路径规划、成本地图 | 3D感知、语义分割、可视化、碰撞检测 |
| 语义标注难度 | 容易(每个格子可附加标签) | 中等(需要对点云进行分割/聚类) |
栅格地图是ROS2导航栈(Nav2)的标准输入。它通过贝叶斯更新维护每个格子的占据概率,值域为[0,100],其中0表示完全空闲,100表示完全占据,-1表示未知。栅格地图的优点是计算高效、便于路径规划(如A*、Dijkstra算法直接作用于栅格),缺点是丢失了高度信息和物体细节。
点云地图则保留了环境的几何细节,适合进行语义分割(如识别墙壁、地面、物体)。在ROS2中,点云通常由激光雷达或深度相机生成,通过sensor_msgs/msg/PointCloud2消息发布。点云地图的缺点是数据量大、处理复杂,且需要额外的配准算法(如ICP)来拼接多帧点云。
2.3 ROS2中的SLAM工具:Cartographer与SLAM Toolbox
ROS2生态中,Cartographer和SLAM Toolbox是两款最常用的2D SLAM工具。它们都支持实时建图与定位,但在设计哲学、算法细节和适用场景上存在显著差异。
2.3.1 Cartographer:多传感器融合的图优化SLAM
Cartographer由Google开发,支持2D和3D建图。其核心优势在于多传感器融合——可以同时接收激光雷达、IMU、里程计甚至GPS数据,通过图优化框架实现高精度建图。Cartographer引入了子图(Submap)概念:将连续帧激光数据配准到局部子图中,当子图不再变化时,将其加入全局位姿图进行回环检测。
在ROS2中使用Cartographer,需要配置三个文件:lua脚本(算法参数)、urdf(机器人模型)和launch文件。关键参数包括:map_frame(地图坐标系)、tracking_frame(跟踪坐标系)、num_range_data(子图包含的扫描帧数)等。Cartographer的调参较为复杂,但一旦调好,精度和鲁棒性都非常出色。
# Cartographer 2D 建图 launch 示例(ROS2)
ros2 launch cartographer_ros cartographer.launch.py \
configuration_basename:="backpack_2d.lua"
2.3.2 SLAM Toolbox:轻量高效的异步SLAM
SLAM Toolbox是Steve Macenski开发的轻量级SLAM工具,专为ROS2设计。它基于Karto SLAM算法,采用异步处理架构——前端扫描匹配与后端图优化在不同线程中运行,避免阻塞。SLAM Toolbox的优势在于:配置简单、资源占用低、支持串行化(Serialization)——可以将建好的地图和位姿图保存为文件,下次启动时直接加载,无需重新建图。
SLAM Toolbox的核心参数包括:scan_topic(激光话题)、map_update_interval(地图更新频率)、minimum_travel_distance(触发建图的最小移动距离)等。它还提供了生命周期节点(Lifecycle Node)支持,可以动态启停建图过程。
# SLAM Toolbox 建图 launch 示例(ROS2)
ros2 launch slam_toolbox online_async_launch.py \
slam_params_file:=./config/mapper_params_online_async.yaml
| 对比维度 | Cartographer | SLAM Toolbox |
|---|---|---|
| 算法基础 | 图优化 + 子图 + 分支定界回环 | Karto SLAM(图优化) |
| 传感器支持 | 激光 + IMU + 里程计 + GPS | 激光 + 里程计(可选IMU) |
| 3D支持 | 支持(Cartographer 3D) | 仅2D |
| 配置复杂度 | 高(Lua脚本 + URDF) | 低(YAML文件) |
| 回环检测 | 实时、全局搜索 | 基于栅格搜索 |
| 地图保存/加载 | 通过map_saver保存PGM/YAML |
支持串行化(.posegraph / .data) |
| 典型场景 | 复杂环境、多传感器融合、3D建图 | 简单环境、资源受限、快速部署 |
2.4 常用术语与坐标系约定
在SLAM和语义标注中,术语和坐标系的统一至关重要。以下是ROS2 SLAM中必须掌握的术语:
- 位姿(Pose):机器人在空间中的位置和朝向,通常表示为 (x, y, θ) 或 (x, y, z, qx, qy, qz, qw)。
- TF树(Transform Tree):ROS2中维护坐标系变换关系的树状结构,SLAM节点负责发布
map → odom → base_link的变换。 - 扫描匹配(Scan Matching):将当前激光帧与已有地图或上一帧进行配准,得到相对位姿变化。
- 回环检测(Loop Closure):识别机器人回到曾经访问过的位置,并修正累积漂移。
- 子图(Submap):Cartographer中的局部地图单元,由若干连续激光帧构成。
- 占据概率(Occupancy Probability):栅格地图中每个格子被占据的概率值。
- 成本地图(Costmap):在栅格地图基础上叠加膨胀层、障碍层等,用于导航规划。
坐标系约定方面,ROS2标准规定:map坐标系是全局固定坐标系,odom坐标系是里程计局部坐标系,base_link是机器人本体坐标系。SLAM节点负责维护 map → odom 的变换,而 odom → base_link 由里程计提供。语义标注时,必须确保标签数据在正确的坐标系下发布,通常使用 map 坐标系作为全局语义地图的参考系。
tf2 库进行坐标变换,不要假设坐标系固定不变。特别是在机器人运动过程中,base_link 相对于 map 的变换是持续更新的。
2.5 实战案例:使用SLAM Toolbox建图并导出栅格地图
下面通过一个完整的案例,演示如何在ROS2中使用SLAM Toolbox完成建图,并导出栅格地图供后续语义标注使用。假设我们有一个差速驱动机器人,搭载2D激光雷达,运行在室内走廊环境。
场景与约束:机器人需要构建一张50m × 30m的走廊地图,激光雷达扫描频率10Hz,最大测距30m。要求地图分辨率0.05m/像素,建图完成后保存地图文件。
操作步骤:
- 启动机器人驱动和激光雷达:确保
/scan话题正常发布 LaserScan 消息。 - 配置SLAM Toolbox参数文件(
mapper_params_online_async.yaml):
slam_toolbox:
ros__parameters:
use_sim_time: false
scan_topic: /scan
mode: mapping
map_frame: map
odom_frame: odom
base_frame: base_link
resolution: 0.05
max_laser_range: 30.0
minimum_time_interval: 0.5
minimum_travel_distance: 0.2
map_update_interval: 5.0
loop_match_minimum_chain_size: 10
loop_match_maximum_variance_coarse: 3.0
loop_match_minimum_response_coarse: 0.35
loop_match_minimum_response_fine: 0.45
- 启动SLAM Toolbox节点:
ros2 launch slam_toolbox online_async_launch.py \
slam_params_file:=./config/mapper_params_online_async.yaml
- 手动遥控机器人遍历环境:使用
teleop_twist_keyboard控制机器人缓慢移动,确保激光雷达覆盖所有区域,重点在走廊交叉口和转角处减速,便于回环检测。 - 观察建图效果:在RViz2中添加
Map显示,订阅/map话题,实时查看栅格地图构建情况。若发现地图漂移或错位,可调整minimum_travel_distance和loop_match_minimum_response_fine参数。 - 保存地图:使用
map_saver工具保存地图为PGM和YAML文件:
ros2 run nav2_map_server map_saver_cli -f corridor_map \
--ros-args -p map_topic:=/map
结果与复盘:建图完成后,我们得到了 corridor_map.pgm 和 corridor_map.yaml 文件。PGM文件是灰度图像,白色表示空闲,黑色表示占据,灰色表示未知。YAML文件包含地图元数据(分辨率、原点、坐标系等)。在后续语义标注中,我们可以加载这张栅格地图作为底图,通过图像坐标到地图坐标的变换,将语义标签(如“门”、“消火栓”、“安全出口”)叠加到对应位置。
风险与代价:建图过程中,如果机器人移动过快或激光雷达数据丢帧,可能导致地图出现“重影”或“断裂”。此时需要重新建图,或者使用Cartographer的多传感器融合来增强鲁棒性。此外,SLAM Toolbox的串行化功能可以保存位姿图,但需要额外配置 serialization_directory 参数。
2.6 常见误区与总结复盘
在SLAM工具的使用和地图表示的理解上,初学者常犯以下错误:
- 误区一:混淆栅格地图与点云地图的用途。栅格地图用于导航,点云地图用于感知和语义。不要试图在栅格地图上做精细的物体识别,也不要用点云地图直接做路径规划。
- 误区二:忽略TF树的重要性。SLAM建图失败,80%以上是TF配置错误。务必检查
map → odom → base_link → laser的变换是否完整且频率正常。 - 误区三:盲目追求高分辨率。栅格地图分辨率越高,内存占用和计算量越大。0.05m分辨率通常足够,过高的分辨率反而会导致地图噪声增大。
- 误区四:忽视回环检测的触发条件。回环检测需要机器人回到已探索区域,且视角相近。如果建图过程中机器人没有形成闭环,地图漂移将无法修正。
- 误区五:认为SLAM工具可以“开箱即用”。无论是Cartographer还是SLAM Toolbox,都需要根据机器人平台、传感器特性和环境特点进行参数调优。