占据栅格:导航可用的几何契约
log-odds 占据更新、逆传感器模型与分辨率取舍,以及 SLAM 位姿误差如何变成 Nav2 上的重影与窄门失效。

1. .pgm 直接丢给 Nav2 的代价
SLAM 跑完把 .pgm 交给 AMCL 和 costmap,窄门被膨胀堵死、人走过的区域永久是障碍——占据栅格不是 SLAM 副产品,是导航栈的第一道几何契约。每个 cell 回答「这里能不能走」;分辨率、逆传感器模型、位姿误差如何画进格子,决定 planner 能不能过门。
我在部署 Nav2 前常忽略这层——直到现场窄道规划失败,才发现 SLAM 输出的地图分辨率与 costmap inflation 根本没一起定过。占据栅格把连续世界离散成格子——格子边界上的墙会「锯齿化」,膨胀层再外扩时,锯齿尖角会先堵住通道;这和 planner 参数无关,是建图分辨率与导航图层未联合设计的结果。
2. log-odds 更新
直接用概率相乘会下溢,工程维护 log-odds:
观测更新是加减:
hit 增占据、miss 降占据,clamping 到 [\ell_\min, \ell_\max] 防过度自信。多传感器融合只需加各自 inverse sensor model 的 log-odds 增量——,适合实时。
3. 逆传感器模型
2D 激光典型约定:命中点之前 free(miss)、命中点 occupied(hit)、之后 unknown。参数 z_hit, z_short, z_max, z_rand 与 AMCL beam model 同源。模型太激进 → 动态物体留永久障碍;太保守 → 新障碍反应迟。Cartographer TSDF + 子地图刷新、RTAB-Map memory management 是 SLAM 侧应对动态的长期方案;纯 2D 栅格 SLAM 需定期重定位 + 局部更新。
4. 分辨率不是越细越好
| 分辨率 | 内存(相对 0.1m) | 窄门 | 更新 |
|---|---|---|---|
| 0.05m | ×4 | 更精确 | 射线 ×4 慢 |
| 0.1m | 基准 | 2m 门 ≈ 20 cell | 常用默认 |
| 0.2m+ | 省 | 窄门失真 | 快但不准 |
100m×100m 仓库 0.05m 分辨率 ≈ 400 万 cell。室内 AGV 常用 0.05–0.1m;大仓 0.1m;室外 coarse 0.2m 配局部高分辨率。10m×10m、0.05m = 160K cells——移动端要算内存与更新频率。
5. 膨胀与 SLAM 输出的关系
占据栅格只有 occ/free/unknown。Nav2 costmap 的 inflation layer 把障碍外扩 inflation_radius:
SLAM 0.2m 分辨率的墙在 0.05m costmap 上阶梯化,膨胀后窄门通过率不可预测——建图分辨率与导航图层要一起定,不是 SLAM 组跑完扔给导航组。
6. 位姿错 → 重影
定位漂移 0.5m 时,同墙画在两处,中间出现假自由空间——AMCL 似然场多峰,可能「收敛」到错误位姿。诊断:看重影区墙厚度、lidar scan 与 map overlay。先修定位/回环,再调 Nav2;重影地图上调 inflation 是徒劳。
重影区域的墙厚度往往接近两倍真实墙厚——overlay 时 scan 与 map 在两侧各贴一条边。若此时只调 AMCL 粒子数或 inflation,规划器会在假自由空间里找路,表现为「明明地图能过、车却不敢进」。
7. slam_toolbox 现场经验
长期跑 slam_toolbox 时,minimum_travel_distance 和 scan_buffer_size 直接影响地图「脏不脏」。部署前先录 30min 典型工况 bag,离线试两档分辨率 + 清除参数,看重影和幽灵障碍哪个先出现,再定 live 参数——比现场逐个拧快得多。
人走过的区域若永久是障碍,多半是 miss 射线没打到、或定位偏了把 hit 画错格——先查 scan 与 pose 再查 z_rand。门开关这类结构变化,静态地图永远跟不上,要在 Nav2 侧用实时层或语义策略,不能指望一次 SLAM 跑完管一年。
8. 验收
- 典型工况 30min bag:重影与幽灵障碍哪个先出现
- scan-map overlay 误差 vs 定位 RPE
- 窄门有效宽度 vs robot footprint + inflation
- 动态场景 free space 清除延迟
- 地图文件大小与加载时间
占据栅格把 SLAM 位姿误差翻译成导航几何;这层契约不稳,后面控制器只是在错误地图上算路。导出 .pgm 时一并记录分辨率、原点与覆盖范围,Nav2 map_server 参数与 SLAM 输出不一致时,表现是「全局定位总偏一格」而非 AMCL 粒子不够。
相关
也可以看看
johan's blog