6.2 KiB
6.2 KiB
导航代码审查报告
日期: 2026-04-03
范围:
App/nav/global_nav.cApp/nav/track_map.cApp/nav/track_map.hApp/robot_params.hApp/app_tasks.cApp/preproc/corridor_preproc.c
结论
当前版本的 S 型拓扑和左右转向表整体上与地图理解一致,没有再发现明显的左右方向写反问题。
主要风险集中在以下几类:
- 时间基准过度依赖 IMU 时间戳
- 连续确认逻辑复用了同一帧 VL53 数据
- 入场段过度依赖固定起始摆放位置
- 阶段切换存在 1 个控制周期的旧命令残留
- 连接段提前转向策略较激进
Findings
1. 高: IMU 时间戳卡住时,超时与里程都会冻结
位置:
App/nav/global_nav.c:430-445App/nav/global_nav.c:471App/nav/global_nav.c:628-630App/nav/global_nav.c:657-659
现象:
GlobalNav_Update()用board->imu_wz.timestamp_ms作为内部时间基准odom_distance_accum的积分和elapsed_ms的推进都依赖这个时间戳
风险:
- 如果 IMU 仍被判定为在线,但时间戳停更,导航状态机会继续输出控制命令
- 同时阶段超时保护不会推进
- 里程积分也不会推进
可能后果:
ENTRY_STRAIGHT、LINK_STRAIGHT、EXIT_STRAIGHT长时间不退出- 转向超时失效,机器人可能持续原地转
说明:
- 这是行为级问题,不是单纯的调参问题
- 文档中也提到了该项仍是 TODO,但当前实现里确实已经构成运行风险
2. 高: “连续 N 拍确认”实际在重复消费同一帧 VL53 数据
位置:
App/app_tasks.c:285-286App/app_tasks.c:299-347App/nav/global_nav.c:516-523App/nav/global_nav.c:615-620App/robot_params.h:398-399
现象:
- 导航循环周期约为
20ms - VL53 任务推送周期约为
100ms REACQUIRE的连续5拍确认和LINK_STRAIGHT的连续2拍确认,都是按导航循环计数
风险:
- 同一帧 VL53 观测会被导航层重复读取多次
- 于是“连续确认”并不等于“连续多个独立观测确认”
可能后果:
REACQUIRE可能只靠 1 帧侧向数据就进入CORRIDOR_TRACK- 沟口检测的 2 拍确认也可能只是一帧瞬时失效被重复消费
说明:
- 这会削弱你现在新设计的联合判定可靠性
- 当前问题核心不是阈值,而是采样独立性不足
3. 中: 入场段强依赖起始摆放位置,缺少几何确认
位置:
App/nav/global_nav.c:484-495App/robot_params.h:382-385App/app_tasks.c:302-306Doc/map.md:9Doc/map.md:53-59
现象:
ENTRY_STRAIGHT现在只用里程 >= 0.30m 或 超时进入第一次右转- 启动后直接
GlobalNav_Start(),没有专门的“出启动区口再开始计段”动作
风险:
- 这要求机器人初始位置必须比较稳定,且接近你假设的起跑点
可能后果:
- 如果车放在 100cm 深启动区内更靠后位置,可能在到达
C1入口前就右转 - 如果车放得更靠前,也可能转得偏晚
说明:
- 当前实现修掉了“侧墙始终有效导致误触发”的问题
- 但引入了“对起点一致性要求很高”的新假设
4. 中: 阶段切换发生后,本周期仍可能执行旧阶段指令
位置:
App/nav/global_nav.c:242-266App/nav/global_nav.c:491-495App/nav/global_nav.c:623-625App/nav/global_nav.c:706-710
现象:
- 若本周期内先生成了旧阶段控制命令,再满足切段条件并
transition_to() out->stage在函数末尾会更新成新阶段- 但本周期发出去的速度命令可能还是旧阶段的
风险:
- 状态显示与实际执行在一个周期内不完全一致
可能后果:
- 转向完成后多转一个控制周期
- 直行段满足切换条件后,当拍仍会继续向前推进一小段
说明:
- 这通常是 20ms 量级的小偏差
- 但在靠近入口边缘、转向容差较紧时会放大几何误差
5. 中: 连接段允许仅凭前激光位移提前触发下一次转向
位置:
App/nav/global_nav.c:590-625App/robot_params.h:406-409App/nav/track_map.h:36-37
现象:
LINK_STRAIGHT的逻辑是B || (A && C)- 其中
A和B都采用0.70m * 0.85 = 0.595m作为触发阈值 - 也就是前激光变化量到达约
59.5cm就可直接触发转向
风险:
- 机器人可能在标称
70cm沟间距之前约10.5cm就开始转向
可能后果:
- 若前激光初值记录稍晚、转出后航向略偏、或前激光看到的并非理想正对围栏面,可能提前转向
- 提前量叠加转向半径误差后,可能更接近垄背边缘而非下一条沟中心
说明:
- 这不是硬 bug,更像策略上偏激进
- 若实车转向余量很大,可能仍可工作;若几何余量小,则风险会明显上升
正向观察
1. 转向拓扑表当前与地图理解一致
位置:
App/nav/track_map.c:34-47
说明:
C1右转入、左转出C2左转入、右转出- 奇偶沟交替
C6左转出场
这一版没有再看到此前那种第一条沟转向方向写反的问题。
2. 连接段已经避免把“贴围栏侧 VL53 常亮”当作入口触发
位置:
App/nav/global_nav.c:108-144App/nav/global_nav.c:557-625
说明:
- 你已经把“非围栏侧 VL53 沟口检测”显式建模出来
- 同时结合前激光和里程计做联合判定
这比此前的 side_walls_detected() 直接触发要合理得多。
开放问题
- 比赛摆车是否保证机器人车头在启动区出口附近,而不是启动区任意位置?
- 传感器黑板中的
is_valid是否有基于时间戳的失效机制,还是生产者停更后仍可能保持有效? - 连接段的目标是“到下一沟中心线再转”,还是“进入下一沟开口就允许转”?当前 0.85 容差会显著影响这个定义。
总体评价
当前版本比前一版明显更接近真实场地几何,尤其是:
- 地图方向理解正确
- S 型左右转表正确
- 连接段不再依赖错误的侧墙常亮判据
但如果从比赛稳定性角度看,当前还存在两个最值得优先处理的问题:
- 时间基准不能完全绑死在 IMU 时间戳上
- 连续确认不能重复消费同一帧侧向观测
如果这两点不处理,现场表现会比较依赖传感器健康状态与偶然时序,稳定性风险较高。