31. 激光雷达与二维建图¶
本章默认读者已经完成第 29 章的传感器话题检查和第 30 章的里程计、TF、时间检查。接下来只解决两个问题:底层驱动送上来的数据,能不能按二维 SLAM 需要的格式被正确解释;不同二维 SLAM 算法有什么区别,应该怎样选择和迁移。最后用一次短路线实测验证输入和算法结果。
本章讨论单线或已经转换为二维扫描的激光雷达,以及使用 ROS 2 话题进行数据交换的二维建图算法。多线雷达的三维建图、视觉建图和后续导航规划不属于本章主线。
31.1 从雷达话题到 SLAM 输入¶
第 29、30 章确认的是“设备和 ROS 2 链路在运行”。本章还要确认“上层算法收到的数据含义和格式正确”。驱动节点与 SLAM 节点通常通过 ROS 2 话题交换消息,常见输入契约如下:
| 输入 | 常见话题名称 | 消息类型或接口 | 用途 |
|---|---|---|---|
| 二维扫描 | /scan、/lidar/scan |
sensor_msgs/msg/LaserScan |
角度数组和距离数组;header.stamp、header.frame_id 必须有效 |
| 轮式里程计 | /odom、/odometry/filtered |
nav_msgs/msg/Odometry |
车体短时位姿和速度;frame_id、child_frame_id 要与 TF 一致 |
| 动态坐标变换 | /tf |
tf2_msgs/msg/TFMessage |
随时间变化的关系,例如 odom → base_link |
| 静态坐标变换 | /tf_static |
tf2_msgs/msg/TFMessage |
固定安装关系,例如 base_link → laser |
这些字段不是“有值就行”:ranges[i] 必须对应 angle_min + i × angle_increment 的测量方向,距离单位通常是米,无效值要符合消息约定;时间戳要能让算法把扫描和同一时刻的 TF 对上。不同算法对里程计、IMU 等辅助输入的要求不同,但二维 SLAM 至少要能获得有效的 LaserScan 和从雷达坐标系到机器人机体坐标系的 TF。只存在 /scan,没有 TF 或时间信息,不能直接视为满足建图条件。
先检查话题和数据格式是否匹配¶
先查看当前系统实际存在的节点和话题:
ros2 node list
ros2 topic list -t
再分别检查雷达和里程计:
ros2 topic info /scan --verbose
ros2 topic echo --once /scan
ros2 topic info /odom --verbose
ros2 topic echo --once /odom
第 29、30 章已经介绍了命令和检查方法,本章只强调与 SLAM 输入契约直接相关的结果:
- 话题名称和消息类型能否与目标算法的订阅参数对应;
LaserScan的角度、量程、距离单位、无效值、时间戳和frame_id是否符合消息语义;- 里程计的
frame_id、child_frame_id、速度方向和频率是否与odom → base_link一致; /tf、/tf_static是否能在扫描时间戳处提供完整变换,发布端 QoS 是否兼容;- 算法需要的附加输入(连续里程计或 IMU)是否真的存在,而不是只在参数文件中填写了名称。
可以用下面的命令确认 TF 是否连通:
ros2 run tf2_ros tf2_echo base_link laser
其中 base_link 和 laser 只是常见示例,实际名称必须替换成消息和 TF 中使用的坐标名。若机器人使用 base_footprint 或其他雷达坐标名,应按实际系统替换。
31.2 输入不匹配时怎样调整¶
发现雷达有数据但 SLAM 不工作时,不要先盲目调整地图参数。先判断不匹配发生在哪一层:
| 现象 | 常见原因 | 优先处理方式 |
|---|---|---|
SLAM 订阅 /scan,驱动实际发布 /lidar/scan |
只有话题名称不同 | 在 Launch 或参数中修改扫描话题,或使用重映射 |
消息类型不是 LaserScan |
驱动发布点云或厂商自定义消息 | 使用厂家 ROS 2 驱动的二维扫描输出,或增加转换/适配节点,例如把点云转换为 LaserScan |
frame_id 与 TF 中的名称不同 |
坐标命名或静态 TF 配置不一致 | 修正驱动参数、静态 TF 或 SLAM 的 frame 参数,不要随意改写真实安装方向 |
| 有扫描但提示找不到变换 | 缺少 base_link → laser 或 odom → base_link |
补充正确的静态或动态 TF,并确认每条变换只有一个发布者 |
| 话题存在但 SLAM 收不到 | QoS 不兼容、节点未真正订阅或命名空间不同 | 用 ros2 topic info --verbose 检查端点和 QoS,再修改订阅端配置或重映射 |
| 地图出现跳变或撕裂 | 时间戳停滞、时间基准不同、里程计方向错误或车轮打滑 | 先修复时间、TF 和里程计,再调整 SLAM 参数 |
话题重映射¶
如果只是发布的话题名称不同,所需的数据无需改动,可以保持驱动不变,在启动 SLAM 时重映射:
ros2 run <slam_package> <slam_executable> --ros-args \
-r scan:=/lidar/scan
重映射只改变 ROS 2 图中的名称,不会改变消息内容。若消息类型、单位或坐标含义不一致,单纯重映射不能解决问题。
数据转换和适配¶
如果新雷达只发布 sensor_msgs/msg/PointCloud2,而二维 SLAM 只接受 sensor_msgs/msg/LaserScan,需要使用支持的转换节点或编写适配节点。适配节点至少要明确:投影平面、角度范围、量程、无效值、时间戳和输出 frame_id。如果里程计是厂商自定义消息,也要先转换成算法能够订阅的标准或约定接口。适配完成后,仍要重新执行第 29 章的节点、话题、频率、时间和坐标检查。
31.3 常见二维建图算法¶
二维 SLAM 的共同原理可以分成两步:前端根据相邻扫描(以及可选的里程计、IMU)估计机器人移动了多少,后端把这些位姿和扫描组织起来,逐步生成地图,并在回到旧区域时做闭环修正。不同算法的差别,主要在于怎样做扫描匹配、怎样表示和优化位姿、对里程计依赖多大,以及是否方便在 ROS 2 中维护。下面比较常见方案的工程差异,不把某一种算法宣传成所有场景的最佳答案。
| 算法 | 主要估计方法 | 对输入的典型要求 | 工程取舍 |
|---|---|---|---|
slam_toolbox |
扫描匹配 + 位姿图优化;支持在线建图、继续建图和序列化地图 | LaserScan、雷达 TF;通常配合连续里程计 |
ROS 2 集成直接,参数和保存流程清晰,适合作为首个验证方案 |
| GMapping | Rao-Blackwellized 粒子滤波;每个粒子代表一条可能的轨迹和地图 | LaserScan、雷达 TF;较依赖里程计质量 |
经典资料多,但 ROS 2 可用性依发行版和移植包而定,不能直接照搬 ROS 1 命令 |
| Cartographer | 局部扫描匹配 + 子地图 + 全局位姿图优化,可扩展到三维 | LaserScan,按配置使用里程计、IMU 等辅助输入 |
闭环和大场景能力较强,但配置项多、资源开销和调参成本较高 |
| Hector SLAM | 主要依靠高频激光扫描做实时匹配,弱化对轮式里程计的依赖 | 高频、时间稳定的 LaserScan 和正确雷达 TF |
适合里程计质量有限但雷达频率高的场景;ROS 2 支持和维护状态需按发行版确认 |
可以这样理解四种方案的侧重点:slam_toolbox 重视 ROS 2 工程集成和位姿图维护;GMapping 用粒子表示轨迹不确定性,对里程计更敏感;Cartographer 把局部子地图和全局闭环结合起来,适合更复杂场景但配置更重;Hector SLAM 尽量依靠高频雷达本身,里程计要求相对低,但对扫描频率、时间稳定性和环境特征更敏感。
选择时先看三个条件:当前 ROS 2 发行版是否有可安装的驱动包、机器人能否提供算法所需的输入、团队是否能维护其参数和故障排查流程。首次建图优先选择输入要求明确、日志可读、保存和重新加载流程已验证的方案。
31.4 迁移或替换建图算法¶
从一种二维 SLAM 换成另一种时,通常不需要更换雷达硬件或雷达驱动。只要新算法仍接受相同的 LaserScan、TF 和里程计接口,就可以保留第 29、30 章已经验证的底层链路,主要替换 SLAM 节点及其配置。真正需要重新确认的是“新算法如何解释这些接口”,而不是重新制作一套传感器数据。迁移按以下顺序进行:
- 确认 ROS 2 支持:核对目标发行版、安装包、依赖和可执行节点,不要直接使用 ROS 1 的 Launch 或参数文件;
- 列出输入契约:记录扫描话题、消息类型、需要的 TF、里程计/IMU 输入、QoS 和最低频率,并写清每个字段的单位和坐标含义;
- 建立参数映射:将旧算法的
base_frame、odom_frame、map_frame、扫描话题和量程参数,逐项映射到新算法的参数名;不要只复制同名参数; - 检查 TF 发布权:通常由底盘或里程计提供
odom → base_link,SLAM 负责估计map → odom,传感器安装关系由静态 TF 提供,不能让两个节点同时发布同一段动态 TF; - 确认输出接口:核对地图话题、地图元数据、保存服务或序列化文件格式。若下游导航仍订阅
/map,必要时使用重映射或增加适配; - 先用短路线回放或低速实测:在相同场地比较扫描是否贴合墙面、闭环是否重合、地图比例和 CPU/内存占用;
- 重新验收并归档:保存新算法的 Launch、参数、ROS 2 发行版、驱动版本、地图文件和日志,不要沿用旧算法“看起来能用”的配置。
31.5 建图操作步骤¶
- 启动底盘、雷达驱动和必要的 TF,确认
/scan、/odom和 TF 已通过输入检查。 - 只启动一套 SLAM,不要同时运行两个会订阅同一雷达并发布地图或
map → odom的建图节点。 - 在 RViz 中显示扫描、TF 和地图,先原地缓慢转动,确认扫描随机器人姿态变化且没有明显错位。
- 低速沿场地边缘行驶,避免急转、长时间原地打滑和遮挡雷达视场。
- 回到已经经过的区域,观察墙线是否基本重合。若闭环处出现重影,先回到输入匹配和里程计检查。
- 建图完成后停止运动,再使用当前算法或导航框架提供的保存工具保存地图。
- 记录地图文件、分辨率、原点、算法名称、参数、Launch、驱动版本和建图日志。
31.6 故障排查¶
排查顺序保持为:输入话题 → 消息类型和 QoS → 时间戳 → TF → 里程计 → SLAM 参数 → 保存流程。前一层没有证据时,不要直接调整后一层。
| 现象 | 优先检查 |
|---|---|
| SLAM 启动但没有地图 | 扫描话题名称、消息类型、QoS、节点订阅关系和启动参数 |
| 地图整体旋转或倾斜 | 雷达安装方向、frame_id 和静态 TF |
| 地图重影或闭环错位 | 时间戳、odom → base_link、轮速方向、打滑和扫描频率 |
| 转弯处撕裂 | 机器人速度、角速度、扫描频率和里程计延迟 |
| RViz 看不到地图 | 地图话题、固定坐标系、map → odom 发布者和 QoS |
| 保存后文件为空或无法加载 | 保存时机、地图话题、输出路径、文件权限和算法的保存格式 |