第四章:环境感知与建图
各位同学,欢迎来到第四章。这一章我们聊点硬核的——机器人怎么“看”世界,又怎么把看到的东西记下来。
说白了,环境感知与建图就是给机器人装上一双眼睛和一张草稿纸。眼睛负责看,草稿纸负责画。我做了这么多年AMR,最深的感触就是:建图搞不定,后面所有规划都是空中楼阁。
4.1 栅格地图:机器人的“像素世界”
先问个问题:机器人怎么表示它周围的环境?
你可能会想到CAD图纸,或者三维点云。但实际工程中,最常用的反而是最简单的——栅格地图。
栅格地图,就是把环境切成一个个小格子。每个格子要么是空的(可通行),要么是占着的(障碍物)。就像像素画一样,格子越小,地图越精细,但计算量也越大。
关键参数:
- 分辨率:每个格子代表的实际尺寸。我常用5cm或10cm。室内用5cm,室外用10cm,这是经验值。
- 尺寸:地图的总大小。比如100m×100m,对应2000×2000个格子。
- 坐标系:通常以机器人启动位置为原点。
栅格地图的好处是什么?简单、直观、好维护。我在项目里遇到过客户要求地图能实时更新,栅格地图改起来就特别方便——改一个格子就行,不用重建整个模型。
4.2 占据栅格地图构建
光有栅格还不够,我们得知道每个格子到底有没有东西。这就是占据栅格地图要做的事。
每个格子存一个概率值,0表示绝对空,1表示绝对占。初始状态是0.5——完全未知。
机器人每扫一次激光,就会更新这些概率。数学上用的是贝叶斯更新,但工程上我更喜欢用对数几率(log-odds)来算,避免概率值溢出。
// 伪代码:占据栅格更新
float log_odds = log(p / (1 - p));
// 激光命中:增加占据概率
log_odds += hit_increment; // 比如 +0.85
// 激光穿过:减少占据概率
log_odds += miss_increment; // 比如 -0.40
// 转回概率
p = 1 - 1 / (1 + exp(log_odds));
我的经验:hit_increment和miss_increment的比值很关键。我一般设成2:1左右。太大容易产生噪点,太小更新太慢。你可以在仿真里调一调,找到手感。
嗯,这里要注意:激光不是完美的。它可能打到玻璃上透过去,也可能被黑胶带吸收。所以每次更新都要带点“怀疑”,别太相信单次测量。
4.3 SLAM概念:边看边画
SLAM,全称是Simultaneous Localization and Mapping。中文叫“同步定位与建图”。
这名字起得挺绕,其实道理很简单:
- 机器人不知道自己在哪(定位问题)
- 机器人也不知道周围长啥样(建图问题)
- 两个问题互相依赖——不知道自己在哪就没法建图,没有图就没法定位
这就像你蒙着眼走进一个陌生房间,一边摸墙一边在脑子里画地图。你每走一步,都在同时更新“我在哪”和“墙在哪”。
SLAM的核心思想就是:用概率模型把这两个问题捆在一起解。说白了,就是“我猜我在这个位置,如果这个位置是对的,那地图应该长这样...嗯,跟传感器数据对上了,那我的猜测就是对的。”
避坑指南:我曾经在一个大仓库里做SLAM,结果跑了半小时地图全飘了。后来发现是地面太光滑,轮子打滑导致里程计误差累积。记住:SLAM对里程计质量要求很高,轮子打滑是头号杀手。
4.4 Gmapping算法原理
Gmapping是ROS里最经典的2D SLAM算法之一。它基于粒子滤波(Particle Filter),说白了就是用一堆“猜测”来逼近真实状态。
每个粒子代表一个可能的机器人位姿和地图。算法流程大致是:
- 初始化:撒一堆粒子,均匀分布在起始位置附近
- 预测:根据里程计数据,让每个粒子往前走一步
- 更新:用激光扫描数据,计算每个粒子的“靠谱程度”
- 重采样:淘汰不靠谱的粒子,复制靠谱的粒子
- 建图:用所有粒子的加权平均,更新栅格地图
Gmapping有个很聪明的优化:它不直接对全地图做粒子滤波,而是把定位和建图分开。定位用粒子滤波,建图用栅格更新。这样计算量小了很多。
Gmapping的优缺点:
| 优点 | 缺点 |
|---|---|
| 计算量小,适合嵌入式 | 不擅长闭环检测 |
| 对小场景效果好 | 大场景容易漂移 |
| 代码成熟,社区支持好 | 对激光频率要求高 |
我记得有一次在实验室里跑Gmapping,怎么调参数都建不好图。后来发现是激光雷达的帧率设得太低——10Hz以下基本没法用。建议至少20Hz,最好40Hz以上。
4.5 Cartographer算法简介
Cartographer是Google开源的一套SLAM方案。它比Gmapping更现代,解决了Gmapping的几个痛点。
核心思路是:用图优化(Graph Optimization)代替粒子滤波。什么意思呢?
- 把机器人的每个位姿当成一个“节点”
- 把传感器观测当成“边”
- 整个问题变成:调整所有节点的位置,让所有边的约束最一致
这就像拼拼图。每块拼图(节点)的位置可以微调,但相邻拼图之间的图案(边)必须对齐。最终目标是整幅图看起来最自然。
Cartographer的另一个亮点是:它内置了闭环检测。当机器人回到之前去过的地方,算法会自动识别并修正累积误差。这一点Gmapping做不到。
// Cartographer配置片段(简化)
TRAJECTORY_BUILDER_2D {
min_range = 0.3 // 最小测量距离
max_range = 30.0 // 最大测量距离
voxel_filter_size = 0.05 // 体素滤波大小
use_online_correlative_scan_matching = true
real_time_correlative_scan_matcher {
linear_search_window = 0.1
angular_search_window = math.rad(20.)
}
}
我的建议:如果你做室内小场景(1000平米以内),Gmapping完全够用,还省资源。但如果是大场景、长廊、或者需要长时间运行,直接上Cartographer。别犹豫,我吃过亏。
Cartographer也有缺点:配置参数多,调起来费劲。我第一次用的时候,光调那个“submaps”参数就花了两天。但一旦调好,效果是真的稳。
知识体系总览
下面这张图是我自己画的,把本章的知识结构串起来了。你可以把它当成一张“地图”,随时回来对照。
这张图把本章内容分成了三大块:栅格地图是基础,SLAM是核心思想,Gmapping和Cartographer是具体实现。你顺着这个结构往下学,思路会清晰很多。
好了,这一章的内容就到这里。环境感知与建图是AMR的“眼睛”和“记忆”,后面所有路径规划、避障、导航都依赖它。建议你动手跑一跑Gmapping和Cartographer的demo,亲手调一次参数,比看十遍文章都管用。
公众号:蓝海资料掘金营,微信deep3321