2、地图构建基础:SLAM原理、常用SLAM算法、地图表示方法
各位同学,咱们今天聊聊地图构建。说白了,机器人要在未知环境里溜达,得先知道自己在哪,还得知道周围长啥样。这就是SLAM要干的事——同时定位与地图构建。
我刚开始接触这玩意儿的时候,觉得挺玄乎的。后来自己动手调过几回参数,踩过坑,才慢慢摸到门道。今天我把这些经验掰开揉碎了讲给你听。
2.1 SLAM到底在解决什么问题?
想象一下:你蒙上眼睛走进一个陌生房间,一边走一边用手摸墙。你每走一步,都在猜「我现在在哪」,同时也在记「墙的走向是什么样的」。这就是SLAM的直觉。
从数学上讲,SLAM要同时估计两件事:
- 机器人的位姿(位置 + 朝向)
- 环境的地图(障碍物在哪、路在哪)
这两者是互相依赖的。你想想看:不知道地图,就没法准确定位;不知道位置,就没法构建准确地图。这就是个「先有鸡还是先有蛋」的问题。
核心难点:传感器有噪声,里程计会漂移,激光雷达扫描也有误差。SLAM的本质,就是用概率方法把这些不确定性给「拧」在一起。
2.2 常用SLAM算法:Gmapping vs Cartographer
市面上SLAM算法不少,但做Nav2导航,最常用的就两个:Gmapping和Cartographer。我个人的习惯是:小场景用Gmapping,大场景或者要求高精度时上Cartographer。
2.2.1 Gmapping——轻量级的老将
Gmapping是基于粒子滤波的2D SLAM算法。它的思路很简单:用一堆粒子去猜机器人的可能位置,然后根据激光观测数据给每个粒子打分,留下靠谱的,淘汰不靠谱的。
优点:
- 计算量小,跑起来快
- 对计算资源要求低,树莓派都能跑
- 小场景(比如几十平米室内)效果很好
缺点:
- 粒子数量有限,大场景容易发散
- 没有回环检测,走回头路时不会修正之前的地图
我的经验:Gmapping的粒子数别设太多,我一般设30~50个。多了反而容易发散,而且计算量上去了。另外,记得把激光雷达的帧率调高一点,10Hz以上比较稳。
2.2.2 Cartographer——精度优先的现代方案
Cartographer是Google开源的,它用了图优化的思路。说白了,就是把每一帧激光数据当成一个节点,节点之间的约束关系当成边,然后整体优化,让所有约束都尽量满足。
优点:
- 自带回环检测,走回头路能自动修正地图
- 大场景(几百米甚至几公里)也能稳定建图
- 支持2D和3D
缺点:
- 计算量大,需要比较好的CPU
- 参数多,调起来比较费劲
避坑指南:我曾经在Cartographer上栽过跟头——回环检测的阈值设得太低了,结果机器人每次经过同一个地方都触发回环,地图反而越建越乱。后来我把阈值调到0.6左右,才稳定下来。嗯,这里要注意,回环检测不是越灵敏越好。
2.3 地图表示方法:占用栅格地图
地图怎么存?最常用的就是占用栅格地图(Occupancy Grid Map)。
它的思路特别朴素:把环境划分成一个个小格子,每个格子存一个概率值,表示这个格子被占用的可能性。
- 0:表示空闲(肯定能走)
- 100:表示占用(肯定是墙或障碍物)
- -1:表示未知(还没探测到)
你想想看,这种表示方法多直观。每个格子独立存储,更新也简单——激光打到的格子,占用概率增加;激光穿过的格子,占用概率降低。
下面这张图,就是占用栅格地图的核心逻辑:
在ROS2里,占用栅格地图用 nav_msgs/msg/OccupancyGrid 消息来传递。你订阅这个话题,就能拿到地图数据。每个格子对应一个int8值,范围从0到100。
关键点:占用栅格地图的分辨率决定了地图的精细程度。分辨率越高(比如0.05米/格),地图越精细,但内存占用也越大。我一般室内用0.05米,室外用0.1米,够用了。
2.4 三种地图表示方法对比
| 地图类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 占用栅格地图 | 直观、更新简单、支持概率 | 分辨率固定、大场景内存大 | 2D导航、室内机器人 |
| 特征地图 | 紧凑、适合大场景 | 特征提取依赖环境 | 视觉SLAM、室外 |
| 拓扑地图 | 抽象、适合路径规划 | 丢失细节信息 | 高层任务规划 |
做Nav2导航,我们主要用占用栅格地图。它跟代价地图(Costmap)是直接打通的——代价地图就是在占用栅格地图的基础上,给每个格子加上「膨胀层」,让机器人知道哪些地方不能去。
小技巧:建图的时候,记得让机器人走「回」字形路线,把环境边界都扫一遍。我见过不少新手,建图时只走中间,结果地图边缘全是未知区域,导航时机器人直接撞墙。
好了,地图构建的基础就聊到这儿。下一节咱们会深入讲代价地图的配置和优化,到时候再细聊。