3、SLAM建图基础:Gmapping算法原理、参数详解、建图实战与地图保存
各位同学,欢迎来到SLAM建图实战环节。
今天咱们聊Gmapping。说实话,这算法有点年头了,但直到现在,很多量产扫地机器人、仓储AGV还在用。为什么?因为它够稳,够快,对算力要求低。我当年刚入行时,第一个落地的SLAM项目就是基于Gmapping做的,踩了不少坑,今天全部分享给你们。
3.1 Gmapping算法核心原理
Gmapping说白了,就是「粒子滤波 + 激光雷达 + 里程计」的组合。它解决的核心问题是:机器人一边动,一边猜自己在哪里,同时把地图画出来。
具体怎么做的?我简单拆解一下:
- 粒子滤波:每个粒子代表机器人可能的一个位姿(x, y, θ)。一开始撒一堆粒子,随着运动,不断更新粒子的权重。权重高的粒子留下,权重低的淘汰——这就是「重采样」。
- 激光观测模型:每个粒子会「预测」它看到的激光数据应该长什么样。如果和实际激光数据匹配得好,这个粒子的权重就高。
- 里程计运动模型:机器人动一步,所有粒子跟着动一步。但里程计有误差,所以粒子会加一点随机噪声。
嗯,这里要注意:Gmapping最聪明的地方在于,它改进了粒子滤波的提议分布。它没有傻傻地用里程计来撒粒子,而是把激光数据也融进去了。这样粒子更集中,需要的粒子数更少。我记得当年用200个粒子就能跑出不错的效果,而普通粒子滤波至少需要1000个。
核心公式(理解即可):
粒子权重 w = 激光观测似然 × 里程计预测概率
说白了就是:激光说「你在这」,里程计说「你在这」,两个都同意,那这个粒子就靠谱。
3.2 参数详解——这些坑我替你踩过了
Gmapping的参数都在一个叫 gmapping.launch 的文件里。我直接给你们列一张表,哪些参数最要命,我标出来。
| 参数名 | 默认值 | 我的建议值 | 说明 |
|---|---|---|---|
| particles | 30 | 80~200 | 粒子数。太少容易发散,太多跑不动。我一般先设100试试。 |
| minimumScore | 0.0 | 50~100 | 激光匹配的最低分数。设太低,错误匹配会毁掉地图。我曾经设0,结果地图全花了。 |
| delta | 0.05 | 0.05 | 地图分辨率(米/像素)。0.05就是5cm一格。别改太小,否则地图文件巨大。 |
| linearUpdate | 1.0 | 0.5 | 机器人走多少米更新一次地图。设小点,地图更精细,但计算量也大。 |
| angularUpdate | 0.5 | 0.2 | 机器人转多少弧度更新一次。转弯多的地方,这个值要小。 |
| maxUrange | 80.0 | 激光雷达最大测距 | 超过这个距离的激光点会被忽略。我建议设成雷达标称距离的80%。 |
| srr / srt / str / stt | 0.01 / 0.02 / 0.01 / 0.02 | 视底盘而定 | 里程计噪声模型参数。底盘差就设大点,底盘好就设小点。我调过最差的底盘,这些值要放大10倍。 |
⚠️ 我曾经踩过的坑:
有一次在工厂调试,地图总是歪的。我查了三天,最后发现是 minimumScore 设成了0。激光匹配到墙上也认为是对的,结果粒子全跑偏了。记住:minimumScore 一定要设一个正数,哪怕50都行。
3.3 建图实战——手把手带你跑起来
好,理论讲完了,咱们直接上手。你想想看,如果只看参数不看实战,那跟没学一样。
第一步:启动底盘和雷达
我假设你已经有了机器人底盘驱动和激光雷达驱动。先跑起来:
# 启动底盘(以差速轮为例)
roslaunch my_robot_base base.launch
# 启动激光雷达(以RPLIDAR为例)
roslaunch rplidar_ros rplidar.launch
# 检查话题
rostopic list | grep -E "scan|odom"
确保你能看到 /scan 和 /odom 这两个话题。没有的话,Gmapping没法干活。
第二步:启动Gmapping
创建一个launch文件,我习惯叫 gmapping_slam.launch:
<launch>
<node pkg="gmapping" type="slam_gmapping" name="slam_gmapping" output="screen">
<param name="base_frame" value="base_footprint"/>
<param name="odom_frame" value="odom"/>
<param name="map_frame" value="map"/>
<param name="map_update_interval" value="5.0"/>
<param name="maxUrange" value="8.0"/>
<param name="minimumScore" value="80"/>
<param name="particles" value="100"/>
<param name="linearUpdate" value="0.5"/>
<param name="angularUpdate" value="0.2"/>
<param name="delta" value="0.05"/>
</node>
</launch>
然后运行:
roslaunch gmapping_slam.launch
第三步:可视化建图过程
打开Rviz,添加 Map 显示,话题选 /map。再添加 LaserScan 和 RobotModel。你会看到地图一点点被画出来。
💡 我的小技巧:
建图时,别让机器人走太快。我一般把线速度控制在0.3m/s以内,角速度0.5rad/s以内。走太快,激光数据会变形,地图容易糊。
3.4 地图保存——别让辛苦白费
地图建好了,怎么存下来?ROS提供了一个工具叫 map_server。
保存命令很简单:
# 安装map_server(如果没装)
sudo apt install ros-noetic-map-server
# 保存地图
rosrun map_server map_saver -f ~/my_map
运行后,你会得到两个文件:
- my_map.pgm:图片格式的地图。白色是空地,黑色是障碍物,灰色是未知区域。
- my_map.yaml:地图的元数据文件,包含分辨率、原点坐标、占用阈值等。
打开 my_map.yaml 看看,内容大概长这样:
image: my_map.pgm
resolution: 0.050000
origin: [-10.000000, -10.000000, 0.000000]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196
这里有个坑:origin 是地图左下角在真实世界中的坐标。如果你建图时机器人起点不在原点,这个值会变。我建议建图前先把机器人放在一个固定起点,这样地图坐标好对齐。
⚠️ 注意:
保存地图时,确保Gmapping还在运行,并且地图已经稳定。我见过有人建到一半就保存,结果地图只有一半。等地图不再变化了再保存,一般走完整个区域后再等10秒。
好了,以上就是Gmapping从原理到实战的全流程。参数调优是个慢功夫,我建议你每次只改一个参数,看看地图变化。别一次改一堆,出了问题都不知道是哪个参数搞的鬼。
记住:建图就像画画,急不得。慢慢来,地图自然会漂亮。
总结一下今天的关键点:
- Gmapping = 粒子滤波 + 激光 + 里程计
- particles 和 minimumScore 是最重要的两个参数
- 建图时速度要慢,转弯要稳
- 地图保存用 map_saver,等地图稳定再存