
1. 残影封窄门时,降 max_vel 没用
Planner 报无解、控制器在门洞前画圈——RViz 里 local_costmap 仍有一圈橙色残影,把 90 cm 门封成 60 cm。团队第一反应是降 controller_server 的 FollowPath.max_vel_x;通道仍过不去,因为世界观错了。Costmap 是 Nav2 唯一的世界模型:层叠顺序、障碍持久化、膨胀与足迹共同决定「门是否存在」。控制器再强,也只能在错误的栅格里找路。
2. 层职责与插件顺序
Nav2 costmap 是插件层叠加,典型顺序:静态层 → 障碍层 →(可选)体素层 → 膨胀层。每层只做一件事:
- StaticLayer:加载
map_server的 PGM/YAML,提供先验占用。 - ObstacleLayer / VoxelLayer:订阅
/scan或点云,标记与清除障碍;observation_sources决定传感器列表。 - InflationLayer:把占用格向外扩散代价,
inflation_radius与cost_scaling_factor决定势场形状。
重复启用同类层(两个 ObstacleLayer 吃同一 /scan)会双计代价,窄道凭空变 fatal。plugins 数组顺序即合成顺序——改顺序等于改语义,必须带截图验收。
local_costmap:
ros__parameters:
plugins: ["static_layer", "obstacle_layer", "inflation_layer"]
inflation_layer:
plugin: "nav2_costmap_2d::InflationLayer"
inflation_radius: 0.55
cost_scaling_factor: 3.03. 膨胀与足迹必须同审
膨胀不是装饰,是把占用距离变换成碰撞代价。有效通过宽度近似:
footprint 在 nav2_costmap_2d 里用 [[x,y], ...] 多边形定义;膨胀半径单独调大而不改 footprint,会出现「RViz 看起来能过、控制器判 fatal」的分裂。global_costmap 与 local_costmap 的膨胀可不同:全局保守(绕路)、局部略紧(贴障跟踪),但二者 footprint 必须一致。
4. 残影的时间学
残影常来自四类根因,调 obstacle_max_range 或缩短持久时间只能掩盖:
- stamp 错误:驱动用到达时间而非采集时间,clearing 射线几何与真实观测错位。
- TF 跳变:
map→odom跳变瞬间,旧障碍投影到新位姿留下幽灵格。 - clearing 不匹配:激光
raytrace_max_range小于obstacle_max_range,标记远、清近,残影累积。 - 双计:静态层已有墙,障碍层又标记同一反射点。
诊断顺序:ros2 topic echo /scan --field header.stamp 对比 /tf 最新 stamp;RViz 逐层开关看残影来自哪一层。修 TF 前后残影面积应下降——这是回归袋,不是手感。
5. global vs local 分工
| global_costmap | local_costmap | |
|---|---|---|
| 范围 | 全图或大范围 | 机器人周围滚动窗口 |
| 更新 | 可较慢(1–5 Hz) | 须匹配控制频率(≥10 Hz) |
| 用途 | 全局规划拓扑 | 实时避障与局部跟踪 |
局部窗口半径应大于制动距离 。高速下窗口太小,障碍刚进窗口就来不及减速——这是几何问题,不是 critics 权重问题。
6. 参数变更的验收
- RViz 分层可视化:静态/障碍/膨胀/合并四层截图,附 PR。
- 窄门袋:同一初始位姿重复 20 次,记录通过/无解/碰撞,改参数前后对比。
- 玻璃/反光场景袋:残影面积量化(占用格计数),不是「看起来还行」。
- 膨胀与 footprint 同审:改
inflation_radius必须同步检查 footprint 多边形。 - 无地图证据的「跟踪优化」PR 打回——先证明地图诚实。
代价地图诚实,控制器才是最后一公里;地图撒谎时,所有增益调整都只是在噪声上作画。
7. observation_sources 与 clearing 几何
ObstacleLayer 的 observation_sources 列出传感器名,每个 source 独立配置 topic、max_obstacle_height、raytrace_max_range、obstacle_max_range。常见错误:obstacle_max_range: 3.0 标记三米内障碍,但 raytrace_max_range: 2.0 只清除两米内——第三米格永不清除,形成环形残影。两者应相等或 raytrace 更大。inf_is_valid: false 时 NaN/Inf 点云会被丢弃;玻璃后的无效点若未滤,会随机标记。
obstacle_layer:
observation_sources: scan
scan:
topic: /scan
max_obstacle_height: 2.0
clearing: true
marking: true
raytrace_max_range: 4.0
obstacle_max_range: 3.58. 案例:双 ObstacleLayer 封死通道
某项目 local 与 global 各配 ObstacleLayer,又共用 voxel_layer 订阅同一点云——窄门通过率从 90% 跌到 40%。RViz 只看合并层,看不出双计;逐层关闭后障碍层代价翻倍才定位。合并为单一 ObstacleLayer + 独立 inflation 配置后,控制器参数未动,通过率恢复。层职责单一,比多拧三个 critic 权重有效。
相关
也可以看看
johan's blog