Files
ASER-NAV/Doc/code_review_report.md

6.2 KiB
Raw Permalink Blame History

导航代码审查报告

日期: 2026-04-03

范围:

  • App/nav/global_nav.c
  • App/nav/track_map.c
  • App/nav/track_map.h
  • App/robot_params.h
  • App/app_tasks.c
  • App/preproc/corridor_preproc.c

结论

当前版本的 S 型拓扑和左右转向表整体上与地图理解一致,没有再发现明显的左右方向写反问题。

主要风险集中在以下几类:

  • 时间基准过度依赖 IMU 时间戳
  • 连续确认逻辑复用了同一帧 VL53 数据
  • 入场段过度依赖固定起始摆放位置
  • 阶段切换存在 1 个控制周期的旧命令残留
  • 连接段提前转向策略较激进

Findings

1. 高: IMU 时间戳卡住时,超时与里程都会冻结

位置:

  • App/nav/global_nav.c:430-445
  • App/nav/global_nav.c:471
  • App/nav/global_nav.c:628-630
  • App/nav/global_nav.c:657-659

现象:

  • GlobalNav_Update()board->imu_wz.timestamp_ms 作为内部时间基准
  • odom_distance_accum 的积分和 elapsed_ms 的推进都依赖这个时间戳

风险:

  • 如果 IMU 仍被判定为在线,但时间戳停更,导航状态机会继续输出控制命令
  • 同时阶段超时保护不会推进
  • 里程积分也不会推进

可能后果:

  • ENTRY_STRAIGHTLINK_STRAIGHTEXIT_STRAIGHT 长时间不退出
  • 转向超时失效,机器人可能持续原地转

说明:

  • 这是行为级问题,不是单纯的调参问题
  • 文档中也提到了该项仍是 TODO但当前实现里确实已经构成运行风险

2. 高: “连续 N 拍确认”实际在重复消费同一帧 VL53 数据

位置:

  • App/app_tasks.c:285-286
  • App/app_tasks.c:299-347
  • App/nav/global_nav.c:516-523
  • App/nav/global_nav.c:615-620
  • App/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-495
  • App/robot_params.h:382-385
  • App/app_tasks.c:302-306
  • Doc/map.md:9
  • Doc/map.md:53-59

现象:

  • ENTRY_STRAIGHT 现在只用 里程 >= 0.30m 或 超时 进入第一次右转
  • 启动后直接 GlobalNav_Start(),没有专门的“出启动区口再开始计段”动作

风险:

  • 这要求机器人初始位置必须比较稳定,且接近你假设的起跑点

可能后果:

  • 如果车放在 100cm 深启动区内更靠后位置,可能在到达 C1 入口前就右转
  • 如果车放得更靠前,也可能转得偏晚

说明:

  • 当前实现修掉了“侧墙始终有效导致误触发”的问题
  • 但引入了“对起点一致性要求很高”的新假设

4. 中: 阶段切换发生后,本周期仍可能执行旧阶段指令

位置:

  • App/nav/global_nav.c:242-266
  • App/nav/global_nav.c:491-495
  • App/nav/global_nav.c:623-625
  • App/nav/global_nav.c:706-710

现象:

  • 若本周期内先生成了旧阶段控制命令,再满足切段条件并 transition_to()
  • out->stage 在函数末尾会更新成新阶段
  • 但本周期发出去的速度命令可能还是旧阶段的

风险:

  • 状态显示与实际执行在一个周期内不完全一致

可能后果:

  • 转向完成后多转一个控制周期
  • 直行段满足切换条件后,当拍仍会继续向前推进一小段

说明:

  • 这通常是 20ms 量级的小偏差
  • 但在靠近入口边缘、转向容差较紧时会放大几何误差

5. 中: 连接段允许仅凭前激光位移提前触发下一次转向

位置:

  • App/nav/global_nav.c:590-625
  • App/robot_params.h:406-409
  • App/nav/track_map.h:36-37

现象:

  • LINK_STRAIGHT 的逻辑是 B || (A && C)
  • 其中 AB 都采用 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-144
  • App/nav/global_nav.c:557-625

说明:

  • 你已经把“非围栏侧 VL53 沟口检测”显式建模出来
  • 同时结合前激光和里程计做联合判定

这比此前的 side_walls_detected() 直接触发要合理得多。

开放问题

  1. 比赛摆车是否保证机器人车头在启动区出口附近,而不是启动区任意位置?
  2. 传感器黑板中的 is_valid 是否有基于时间戳的失效机制,还是生产者停更后仍可能保持有效?
  3. 连接段的目标是“到下一沟中心线再转”,还是“进入下一沟开口就允许转”?当前 0.85 容差会显著影响这个定义。

总体评价

当前版本比前一版明显更接近真实场地几何,尤其是:

  • 地图方向理解正确
  • S 型左右转表正确
  • 连接段不再依赖错误的侧墙常亮判据

但如果从比赛稳定性角度看,当前还存在两个最值得优先处理的问题:

  • 时间基准不能完全绑死在 IMU 时间戳上
  • 连续确认不能重复消费同一帧侧向观测

如果这两点不处理,现场表现会比较依赖传感器健康状态与偶然时序,稳定性风险较高。