2. 机器人眼中的世界:传感器与栅格地图
2. 机器人眼中的世界:传感器与栅格地图
上一篇:1. SLAM是什么:盲人摸象与边走边画 | 下一篇:3. 粒子滤波:一千个分身猜位置
gmapping 只吃两种数据:激光(”我看到什么”)和里程计(”我动了多少”)。这一篇讲清楚这两种数据长什么样、各有什么脾气,以及最终要画出的栅格地图是什么。
一、激光雷达:机器人的一圈”声呐”
1.1 数据长什么样
2D 激光雷达(如 RPLIDAR、思岚 S2)水平旋转,每转一圈打出几百束激光,返回一个距离数组:
1 | angles: [-90°, -89.5°, ..., +89.5°] (均匀分布 360°/N 份) |
一帧激光 = N 个 (角度, 距离) 对,从雷达中心向外呈放射状的一圈点。
1.2 关键参数
| 参数 | 含义 | 对 gmapping 的影响 |
|---|---|---|
| 频率 | 每秒扫几圈(典型 5~12 Hz) | gmapping 依赖里程计先验,5Hz 也够用(Hector 需要 40Hz+) |
| 角分辨率 | 每束激光隔几度(典型 0.25°~1°) | 越密越利于扫描匹配 |
| 量程 | 最远测多远(典型 8~30 m) | maxUrange 参数通常设为量程的 80% |
1.3 激光的脾气:准,但”不知道自己是谁”
- ✅ 测距很准(厘米级),不受光照影响;
- ❌ 只告诉你”这个方向 X 米处有个东西”,不告诉你那是什么–两段长得一样的走廊,激光分不出来(这正是回环检测难的原因);
- ❌ 玻璃、镜面会”穿过去”或产生鬼影。
二、里程计:从轮子转数猜走了多远
2.1 原理
轮子电机带编码器:转一圈 = 走 2πR 米。左右轮转数差 -> 转了多少角度。里程计把这两者积分成位姿变化 $\Delta x, \Delta y, \Delta \theta$。
2.2 里程计的致命伤:误差累积
每一步的小误差(轮子打滑、轮径不准、地面不平)全部累加:
1 | flowchart LR |
但短时间内的”相对变化”很可靠。gmapping 的用法正是取其长避其短:用里程计提供短时位姿先验(”我这 0.1 秒大概动了这么点”),再用激光来修正长期漂移。这也解释了为什么 gmapping 对雷达频率要求低:两帧激光之间,里程计能大致告诉你机器人怎么动的。
注:Hector SLAM 不用里程计(为救灾地形设计,轮子可能悬空),所以它必须用高频激光硬扛;Cartographer 为手持设备设计,同样没里程计。gmapping 是”有轮子机器人”的菜。
三、栅格地图:把世界切成小格子
3.1 一张”灰度图”
gmapping 输出的地图,本质是一张 pgm 灰度图(ROS 里叫 /map,消息类型 nav_msgs/OccupancyGrid):
| 颜色 | 占用概率 | 含义 |
|---|---|---|
| ⬛ 黑 | ≈ 1 | 障碍物(有东西,撞不得) |
| ⬜ 白 | ≈ 0 | 空闲(激光穿过去了,没东西) |
| 🟫 灰 | 0.5 | 未知(从没扫到过这里) |
把环境切成边长 delta(分辨率,典型 5cm)的小格子,每个格子存一个”这里被占据的概率”。这就是 gmapping 每个粒子随身携带的地图。
3.2 关键问题:为什么激光能”点亮”格子?
一束激光从雷达到命中点,划过一条线段,信息量巨大:
1 | flowchart LR |
- 穿过没被挡 -> 沿途所有格子大概率是空的;
- 终点被挡住 -> 命中格子大概率是占用的。
这个”从激光射线反推格子占用概率”的经典模型叫 Bresenham 光线投射(第 8 篇实现时亲手写)。gmapping 底层用的改进版叫 Gmapping-Style Scan Matcher + 每粒子地图更新,本质相同。
3.3 地图怎么更新:还是贝叶斯
某个格子 $c$ 收到新激光证据后的更新,人话版:
新置信度 = 老置信度 × (这束激光说它占用/空闲的可能性)
| 情况 | 格子概率变化 |
|---|---|
| 激光穿过该格子 | 占用概率 ↓(乘一个 <1 的系数,如 0.4) |
| 激光正好打在该格子 | 占用概率 ↑(乘一个 >1 的系数,如 0.6+0.7) |
| 这次没涉及该格子 | 不变 |
多次观测反复修正,灰格子逐渐”变黑”或”变白” – 这就是你在 RViz 里看到地图一点点长出来的过程。
3.4 ROS 里的地图细节
/map话题采用 latched(锁存) 发布:地图不更新时不重发,新订阅者也能立刻收到最后一次的地图(地图变化慢,省带宽);- 地图原点、分辨率、尺寸由
map_metadata描述; - 每个粒子的地图在内存里,只有最优粒子的地图才会发布出来。
四、三个坐标系的”套娃”(TF 树)
gmapping 输出的定位结果,在 ROS 里表现为一条 TF 变换链:
1 | flowchart LR |
为什么要套娃? 分工明确:
odom -> base_link:里程计发布,短期平滑(适合控制),但长期漂移;map -> odom:gmapping 发布,本质是修正量(”里程计世界和真实地图世界差了多少”),跳变但不漂移。
gmapping 每帧做的事:拿最优粒子的位姿(地图坐标)和里程计位姿求差,更新 map -> odom(第 6 篇源码里对应 map_to_odom_ 那三行)。
五、本篇小结
| 角色 | 长处 | 短处 | gmapping 怎么用 |
|---|---|---|---|
| 激光雷达 | 测距准、不受光照 | 不识别物体、无差异场景 | 提供观测,修正漂移 |
| 里程计 | 短时相对运动准 | 误差累积 | 提供位姿先验,降低对雷达频率要求 |
| 栅格地图 | 直观、可导航 | 每粒子一张 -> 内存大户 | 每个粒子随身携带一份 |
📚 参考:源代码解析(栅格地图与 /map latched 机制)、ROS1系列(话题与参数)