Files
ASER/修改建议报告.md
2026-04-08 07:38:46 +08:00

8.4 KiB
Raw Blame History

CAN/里程计频率修改建议报告

1. 结论

建议采用以下组合修改,而不是单独只改一边:

  1. 下位机 FDR-Core0x200 Odom Delta 从当前约 60ms 提升到 20ms 固定发送。
  2. 上位机 ARES0x200 的消费与 Odom_Update()monitorTask(100ms) 挪到 navTask(20ms)
  3. 0x182/0x183 保持低频轮询即可,不需要跟着一起提到 20ms
  4. 当前阶段不建议把 0x200 进一步提到 10ms,先做到 20ms 即可。

一句话概括:当前 odom 不够实时,不是总线带宽不够,而是“下位机发送慢 + 上位机消费慢”叠加导致的;最合适的修法是把两端都对齐到 20ms

2. 本次核对到的事实

2.1 下位机当前真实行为

下位机工程:C:\Users\Falling_jasmine\CLionProjects\FDR-Core

实际实现文件:Core/Src/f4_can_app.c

关键实现如下:

  1. CAN_Send_Telemetry_20ms()20ms 调一次。
  2. 0x181 状态帧固定每次都发。
  3. 0x182 / 0x183 / 0x200 通过 s_telem_slot 三选一轮询发送。
  4. 所以 0x200 实际发送周期约为 60ms,不是 20ms
  5. 0x184 通过 s_comm_diag_divider100ms 发送一次。

对应代码位置:

  1. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:925-966
  2. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:907-923

另外,下位机头文件注释和实际实现已经出现漂移:

  1. f4_can_app.h 注释写的是 0x181/0x182/0x183/0x200 都在 20ms 周期发送。
  2. 但真实代码并不是这样,而是只有 0x181 固定 20ms

对应位置:

  1. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Inc\f4_can_app.h:165-173
  2. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:925-966

2.2 下位机 odom 数据源没有问题

下位机 motor.c 中,编码器增量在控制周期中持续累加到 s_odom_acc_ticks[]

  1. 每次电机更新时都会把四轮增量累加到 odom 累加器。
  2. CAN_Send_OdomFrame() 发送 0x200 时,通过 Motor_Get_And_Clear_Delta_Ticks() 原子取走并清零。

这说明:

  1. 0x200 本质是“自上次发送以来的积分增量”。
  2. 如果把 0x200 发送频率从 60ms 提高到 20ms,语义仍然正确,只是每帧覆盖的时间窗变短、实时性更高。

对应位置:

  1. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\motor.c:225-245
  2. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\motor.c:263-295
  3. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:907-923

2.3 上位机当前真实行为

上位机工程:D:\ARES

当前 0x200 的消费模型是:

  1. CAN ISR 收到每帧 0x200 后,不直接覆盖,而是累加到 odom_accum
  2. monitorTask100ms 调用 SNC_CAN_ConsumeOdomDelta() 原子取走累计值。
  3. 然后再调用 Odom_Update() 推送黑板。
  4. navTask 本身跑在 20ms,但它读到的 board.odom_vx 很多拍都是旧值。

对应位置:

  1. D:\ARES\App\Can\snc_can_app.c:185-225
  2. D:\ARES\App\app_tasks.c:145-167
  3. D:\ARES\App\app_tasks.c:295-340

3. 问题本质

当前 odom 实时性差,来自两个串联环节:

  1. 下位机发送 0x200 只有约 60ms 一次。
  2. 上位机又只在 100msmonitorTask 中消费一次。

所以当前 odom_vx 的有效刷新节拍,不是 navTask20ms,而是被这两个环节一起拖慢了。

这会直接影响:

  1. CorridorEKF_Predict()odom_vx 的实时性。
  2. 沿程 s 的连续性。
  3. 车体加减速或转向阶段时,状态传播的平滑度。

4. 是否需要把 CAN 提得更高频

当前不建议先追求高于 20ms 的 CAN 频率。

原因:

  1. 上位机 navTask / EKF 当前就是 20ms / 50Hz
  2. 0x100 速度命令协议推荐节拍也是 20ms
  3. 0x200 先做到 20ms,就已经与主导航闭环对齐。
  4. 再往 10ms 提,边际收益明显变小,且会引入更多调度与验证成本。

在你当前系统中,更合理的目标是:

  1. 0x100 保持 20ms
  2. 0x181 保持 20ms
  3. 0x200 提到 20ms
  4. 0x182/0x183/0x184 维持低频

5. 总线负载是否会成为问题

基于你补充的信息:总线上只有两个单片机,且 CAN 速率为 1 Mbps

在这个前提下,把 0x200 提到 20ms 是合理的,风险较低。

主要原因:

  1. 当前实时关键帧就只有 0x1000x1810x200
  2. 即便这三类帧都在 20ms 发送,总线占用通常仍远低于饱和。
  3. 下位机当前发送代码本身也把遥测帧视为“允许丢”的低优先级消息,不会因短时发不出去而阻塞主循环。

对应代码:

  1. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:808-821

6. 推荐修改方案

6.1 下位机修改建议

修改文件:

  1. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c
  2. C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Inc\f4_can_app.h

修改目标:

  1. 0x18120ms 固定发送。
  2. 0x20020ms 固定发送。
  3. 0x182/0x183 改成低频轮询发送。
  4. 0x184 继续 100ms

最小改法建议如下:

  1. 保留 CAN_Send_StatusFrame() 每拍都发。
  2. CAN_Send_Telemetry_20ms() 中,每拍额外固定调用 CAN_Send_OdomFrame()
  3. 把原来的 s_telem_slot 轮询从 0x182/0x183/0x200 三选一,改成只在 0x182/0x183 两者之间轮询。
  4. 更新头文件中的注释,避免文档/实现再次漂移。

推荐把 CAN_Send_Telemetry_20ms() 的逻辑改成:

  1. 先发 0x181
  2. 再发 0x200
  3. 再按 slot 发 0x1820x183
  4. 每 5 拍发一次 0x184

这样改的优点:

  1. 0x200 得到稳定 20ms 周期。
  2. 0x182/0x183 仍然保留,但不抢实时关键链路。
  3. 代码改动很小,不需要碰控制内环和接收协议。

6.2 上位机修改建议

修改文件:

  1. D:\ARES\App\app_tasks.c

修改目标:

  1. SNC_CAN_ConsumeOdomDelta() 不再由 monitorTask(100ms) 调用。
  2. odom 消费与 Odom_Update() 挪到 navTask(20ms)

具体建议:

  1. 删除 AppTasks_RunMonitorTask()145-167 这段 odom 消费代码。
  2. AppTasks_RunNavTask_Impl() 中、Blackboard_GetSnapshot(&board) 之前插入同样的 odom 消费逻辑。
  3. 保持 SNC_CAN_ConsumeOdomDelta() 全系统只有一个消费者。

推荐新顺序:

  1. now_ms = HAL_GetTick()
  2. SNC_CAN_ConsumeOdomDelta(...)
  3. Odom_Update(...)Odom_HandleTimeout(...)
  4. Blackboard_GetSnapshot(&board)
  5. CorridorPreproc_ExtractObs(...)
  6. CorridorFilter_Update(...)

这样可以保证:

  1. navTask 每一拍都能第一时间消费已到达的 0x200
  2. 当下位机把 0x200 提到 20ms 后,上位机不会再被 100ms monitorTask 卡住。

7. 不建议的修改方式

7.1 只改上位机,不改下位机

这样只能把 odom 的消费延迟从 100ms 降下来,但 0x200 源头仍是约 60ms,收益有限。

7.2 只改下位机,不改上位机

这样虽然 0x200 更快到达了,但上位机仍在 100ms 才取走一次,实时性改善不完整。

7.3 直接把 0x200 提到 10ms

现阶段不建议。原因:

  1. 上位机 navTask 仍是 20ms
  2. EKF 和控制链路当前主频也是 20ms
  3. 先把 20ms 跑顺、验证完,再决定是否需要更高频更合理。

8. 推荐实施顺序

建议按下面顺序改:

  1. 先改下位机 f4_can_app.c,让 0x200 固定 20ms 发送。
  2. 同步修正下位机 f4_can_app.h 注释。
  3. 再改上位机 app_tasks.c,把 odom 消费搬进 navTask
  4. 实车或日志确认 0x200 到达间隔、odom_vx 刷新节拍和 EKF 状态表现。

9. 验收建议

改完后至少验证以下几点:

  1. 上位机收到的 0x200 时间戳间隔是否接近 20ms
  2. SNC_CAN_ConsumeOdomDelta() 是否只在 navTask 被调用一次。
  3. board.odom_vx 是否不再长时间停留旧值。
  4. EKFse_y 传播是否更连续。
  5. s_can_tx_drop_total 是否没有明显上升。
  6. 0x1810x1840x100 协议行为是否保持兼容。

10. 最终建议

最终建议如下:

  1. 下位机把 0x200 改成 20ms 固定发送。
  2. 上位机把 odom 消费改到 navTask(20ms)
  3. 0x182/0x183 保持低频,不必提频。
  4. 先不要把 0x200 提到 10ms

这是当前这两套代码下,改动最小、收益最大、工程风险也最低的方案。