8.4 KiB
CAN/里程计频率修改建议报告
1. 结论
建议采用以下组合修改,而不是单独只改一边:
- 下位机
FDR-Core将0x200 Odom Delta从当前约60ms提升到20ms固定发送。 - 上位机
ARES将0x200的消费与Odom_Update()从monitorTask(100ms)挪到navTask(20ms)。 0x182/0x183保持低频轮询即可,不需要跟着一起提到20ms。- 当前阶段不建议把
0x200进一步提到10ms,先做到20ms即可。
一句话概括:当前 odom 不够实时,不是总线带宽不够,而是“下位机发送慢 + 上位机消费慢”叠加导致的;最合适的修法是把两端都对齐到 20ms。
2. 本次核对到的事实
2.1 下位机当前真实行为
下位机工程:C:\Users\Falling_jasmine\CLionProjects\FDR-Core
实际实现文件:Core/Src/f4_can_app.c
关键实现如下:
CAN_Send_Telemetry_20ms()每20ms调一次。0x181状态帧固定每次都发。0x182 / 0x183 / 0x200通过s_telem_slot三选一轮询发送。- 所以
0x200实际发送周期约为60ms,不是20ms。 0x184通过s_comm_diag_divider每100ms发送一次。
对应代码位置:
C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:925-966C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:907-923
另外,下位机头文件注释和实际实现已经出现漂移:
f4_can_app.h注释写的是0x181/0x182/0x183/0x200都在20ms周期发送。- 但真实代码并不是这样,而是只有
0x181固定20ms。
对应位置:
C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Inc\f4_can_app.h:165-173C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:925-966
2.2 下位机 odom 数据源没有问题
下位机 motor.c 中,编码器增量在控制周期中持续累加到 s_odom_acc_ticks[]:
- 每次电机更新时都会把四轮增量累加到 odom 累加器。
CAN_Send_OdomFrame()发送0x200时,通过Motor_Get_And_Clear_Delta_Ticks()原子取走并清零。
这说明:
0x200本质是“自上次发送以来的积分增量”。- 如果把
0x200发送频率从60ms提高到20ms,语义仍然正确,只是每帧覆盖的时间窗变短、实时性更高。
对应位置:
C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\motor.c:225-245C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\motor.c:263-295C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:907-923
2.3 上位机当前真实行为
上位机工程:D:\ARES
当前 0x200 的消费模型是:
- CAN ISR 收到每帧
0x200后,不直接覆盖,而是累加到odom_accum。 monitorTask每100ms调用SNC_CAN_ConsumeOdomDelta()原子取走累计值。- 然后再调用
Odom_Update()推送黑板。 navTask本身跑在20ms,但它读到的board.odom_vx很多拍都是旧值。
对应位置:
D:\ARES\App\Can\snc_can_app.c:185-225D:\ARES\App\app_tasks.c:145-167D:\ARES\App\app_tasks.c:295-340
3. 问题本质
当前 odom 实时性差,来自两个串联环节:
- 下位机发送
0x200只有约60ms一次。 - 上位机又只在
100ms的monitorTask中消费一次。
所以当前 odom_vx 的有效刷新节拍,不是 navTask 的 20ms,而是被这两个环节一起拖慢了。
这会直接影响:
CorridorEKF_Predict()中odom_vx的实时性。- 沿程
s的连续性。 - 车体加减速或转向阶段时,状态传播的平滑度。
4. 是否需要把 CAN 提得更高频
当前不建议先追求高于 20ms 的 CAN 频率。
原因:
- 上位机
navTask/ EKF 当前就是20ms / 50Hz。 0x100速度命令协议推荐节拍也是20ms。0x200先做到20ms,就已经与主导航闭环对齐。- 再往
10ms提,边际收益明显变小,且会引入更多调度与验证成本。
在你当前系统中,更合理的目标是:
0x100保持20ms0x181保持20ms0x200提到20ms0x182/0x183/0x184维持低频
5. 总线负载是否会成为问题
基于你补充的信息:总线上只有两个单片机,且 CAN 速率为 1 Mbps。
在这个前提下,把 0x200 提到 20ms 是合理的,风险较低。
主要原因:
- 当前实时关键帧就只有
0x100、0x181、0x200。 - 即便这三类帧都在
20ms发送,总线占用通常仍远低于饱和。 - 下位机当前发送代码本身也把遥测帧视为“允许丢”的低优先级消息,不会因短时发不出去而阻塞主循环。
对应代码:
C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.c:808-821
6. 推荐修改方案
6.1 下位机修改建议
修改文件:
C:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Src\f4_can_app.cC:\Users\Falling_jasmine\CLionProjects\FDR-Core\Core\Inc\f4_can_app.h
修改目标:
0x181每20ms固定发送。0x200每20ms固定发送。0x182/0x183改成低频轮询发送。0x184继续100ms。
最小改法建议如下:
- 保留
CAN_Send_StatusFrame()每拍都发。 - 在
CAN_Send_Telemetry_20ms()中,每拍额外固定调用CAN_Send_OdomFrame()。 - 把原来的
s_telem_slot轮询从0x182/0x183/0x200三选一,改成只在0x182/0x183两者之间轮询。 - 更新头文件中的注释,避免文档/实现再次漂移。
推荐把 CAN_Send_Telemetry_20ms() 的逻辑改成:
- 先发
0x181 - 再发
0x200 - 再按 slot 发
0x182或0x183 - 每 5 拍发一次
0x184
这样改的优点:
0x200得到稳定20ms周期。0x182/0x183仍然保留,但不抢实时关键链路。- 代码改动很小,不需要碰控制内环和接收协议。
6.2 上位机修改建议
修改文件:
D:\ARES\App\app_tasks.c
修改目标:
SNC_CAN_ConsumeOdomDelta()不再由monitorTask(100ms)调用。- odom 消费与
Odom_Update()挪到navTask(20ms)。
具体建议:
- 删除
AppTasks_RunMonitorTask()中145-167这段 odom 消费代码。 - 在
AppTasks_RunNavTask_Impl()中、Blackboard_GetSnapshot(&board)之前插入同样的 odom 消费逻辑。 - 保持
SNC_CAN_ConsumeOdomDelta()全系统只有一个消费者。
推荐新顺序:
now_ms = HAL_GetTick()SNC_CAN_ConsumeOdomDelta(...)Odom_Update(...)或Odom_HandleTimeout(...)Blackboard_GetSnapshot(&board)CorridorPreproc_ExtractObs(...)CorridorFilter_Update(...)
这样可以保证:
navTask每一拍都能第一时间消费已到达的0x200。- 当下位机把
0x200提到20ms后,上位机不会再被100ms monitorTask卡住。
7. 不建议的修改方式
7.1 只改上位机,不改下位机
这样只能把 odom 的消费延迟从 100ms 降下来,但 0x200 源头仍是约 60ms,收益有限。
7.2 只改下位机,不改上位机
这样虽然 0x200 更快到达了,但上位机仍在 100ms 才取走一次,实时性改善不完整。
7.3 直接把 0x200 提到 10ms
现阶段不建议。原因:
- 上位机
navTask仍是20ms。 - EKF 和控制链路当前主频也是
20ms。 - 先把
20ms跑顺、验证完,再决定是否需要更高频更合理。
8. 推荐实施顺序
建议按下面顺序改:
- 先改下位机
f4_can_app.c,让0x200固定20ms发送。 - 同步修正下位机
f4_can_app.h注释。 - 再改上位机
app_tasks.c,把 odom 消费搬进navTask。 - 实车或日志确认
0x200到达间隔、odom_vx刷新节拍和 EKF 状态表现。
9. 验收建议
改完后至少验证以下几点:
- 上位机收到的
0x200时间戳间隔是否接近20ms。 SNC_CAN_ConsumeOdomDelta()是否只在navTask被调用一次。board.odom_vx是否不再长时间停留旧值。EKF的s和e_y传播是否更连续。s_can_tx_drop_total是否没有明显上升。0x181、0x184、0x100协议行为是否保持兼容。
10. 最终建议
最终建议如下:
- 下位机把
0x200改成20ms固定发送。 - 上位机把 odom 消费改到
navTask(20ms)。 0x182/0x183保持低频,不必提频。- 先不要把
0x200提到10ms。
这是当前这两套代码下,改动最小、收益最大、工程风险也最低的方案。