Nav2 Progress Checker:卡死要能失败,而不能永远「运行中」
用可解释的位移窗口触发恢复;与碰撞监测分工,避免误触与永不失败。

1. FollowPath 永远 RUNNING 的保险丝
机器人贴障空转、cmd_vel 仍有非零输出,但 30 秒位移不到 5 cm——bt_navigator 里 FollowPath 节点状态一直是 RUNNING,recovery 链从未触发,电池持续消耗。没有 progress checker,行为树缺少「卡住」这一可失败条件,恢复策略再漂亮也轮不到。Progress checker 是卡死的保险丝:把「是否在有效移动」变成硬失败,从而触发 BT 的 clear/spin/abort 分支。
2. 机制:SimpleProgressChecker
Nav2 默认用 nav2_controller::SimpleProgressChecker,在 controller_server 下配置:
controller_server:
ros__parameters:
progress_checker_plugin: "progress_checker"
progress_checker:
plugin: "nav2_controller::SimpleProgressChecker"
required_movement_radius: 0.5 # 窗口内至少移动 0.5 m
movement_time_allowance: 10.0 # 超过 10 s 未达则 FAILURE逻辑:在 movement_time_allowance 秒内,若机器人距上次有效位置未超过 required_movement_radius,控制器返回 FAILURE。BT 收到 FAILURE 后进入 recovery 或向上层报告——不再空转。
3. 参数标定:误触与漏检的权衡
| 参数 | 过紧 | 过松 |
|---|---|---|
required_movement_radius | 颠簸地面误触 FAILURE | 真卡死不触发 |
movement_time_allowance | 慢速合法导航误触 | 空转时间过长才失败 |
标定方法:在目标地面类型上,让机器人正常慢速跟路径,记录窗口内最小位移;required_movement_radius 取该值的 50–70%。movement_time_allowance 应大于「窄道减速通过」的合理耗时,但小于「空转可接受上限」(通常 10–30 s)。
4. 与碰撞监测、看门狗的分工
三者不可糊成一个参数:
| 组件 | 检测什么 | 触发后 |
|---|---|---|
| ProgressChecker | 窗口内无有效位移 | controller FAILURE → BT recovery |
| CollisionMonitor | 进入危险/致命区 | 减速、停、上报 |
| 执行器看门狗 | 节点无心跳 | 硬件急停 |
Progress 管「没动」,碰撞管「危险」,看门狗管「节点死了」。Progress 失败不应触发急停——那是碰撞监测的职责。日志字段应能区分三种原因。
5. 与 BT recovery 的接口
Progress 失败应是 BT 可区分的失败原因码,从而选择不同恢复策略:
- 卡住(有路径、无位移) → clear local costmap → spin → backup。
- 目标不可达(GoalChecker 超时) → 直接 FAILURE 给上层,不做 spin。
- 定位丢失(协方差超阈) → relocalization 分支。
区分「卡住」与「不可达」能少做很多无用旋转。在 BT XML 里用 ProgressChecker FAILURE 与 GoalChecker FAILURE 走不同 recovery 子树。
6. 验收
- 人为挡住机器人:在
movement_time_allowance内 controller 返回 FAILURE,日志写明 progress 原因。 - 正常慢速导航:误触发率 0(20 次重复)。
- 真卡死(贴障空转):必触发 FAILURE,不是永远 RUNNING。
- Progress 失败最终能触达安全停策略(经 BT 上限),不是无限 recovery 循环。
7. 案例:阈值过紧导致颠簸误触
某项目 required_movement_radius: 0.1、movement_time_allowance: 5.0,颠簸地面每 5 s 误触一次 recovery,BT 在 clear/spin 间振荡。放宽到 0.4 / 15.0 并单独测真卡死场景——误触归零,真卡死仍能在 15 s 内失败。改两个数,比加三个 recovery 节点有效。
7. 地面类型与速度联动
required_movement_radius 不是 universal 常数:光滑地面低速通过窄道时,合法位移可能只有 0.3 m/15 s;粗糙地面颠簸时,静止抖动可能误计为位移。标定时用同一 max_vel_x 与同一目标路径,分别测正常通过和真卡死两种场景,取交集作为阈值。改 max_vel_x 后应重验 progress 阈值——速度上限变了,合法位移窗口也变。
8. GoalChecker 与 ProgressChecker 配合
到点判定由 GoalChecker 负责,默认 SimpleGoalChecker:
goal_checker:
plugin: "nav2_controller::SimpleGoalChecker"
xy_goal_tolerance: 0.25
yaw_goal_tolerance: 0.25
stateful: trueProgress 管「动没动」,Goal 管「到没到」。机器人在目标附近微调时,progress 可能因位移小触发 FAILURE,但 goal 已 SUCCESS——BT 应正确处理这种边界。stateful: true 时到达后不再重复检查,避免到点后仍判 progress 失败。
PoseProgressChecker 同时看位移与转角,适合全向底盘;差速车通常 SimpleProgressChecker 足够。换 checker 插件时,BT recovery 分支不必改,但阈值要重标定。
9. 与录包复盘
导航事故袋应含 /controller_server/transition_event 或 BT 黑盒日志,才能区分「progress 失败」与「碰撞停止」。缺 progress 状态,复盘只能猜「为什么空转」——证据链不完整。
10. 地面标定窗口
阈值不是抄默认:用已知「故意卡住」与「慢速通过窄门」两段地面轨迹标定 required_movement_radius 与时间窗口。窗口过短会把合法微调当失败;过长会让真卡死拖太久。改足迹或最大速度后重标定,不要只改膨胀。
相关
也可以看看
johan's blog