Skip to content

自动驾驶卡丁车 — 控制板/FOC/刹车板 CAN 集成 Review 与计划

本文为本 session 的交付总览:以 控制板 DlaBoard_A 为核心,梳理它经 CAN 总线FOC 驱动板 FOC_double刹车板 DlaCart_v2.1 的对接,列出从工程化角度需要修改、 完善、标准化的项,并给出实施计划。

范围内子项目:DlaBoard_A(控制板,可重构)、FOC_double(FOC,仅功能层对接)、 DlaCart_v2.1(刹车板,临时)。其余目录不在本 session。

日期:2026-05-31


1. 系统拓扑(实测代码梳理)

                          CAN1 总线 (经典帧, 1 Mbps)
  ┌─────────────┐  0x210 驱动请求 →   ┌──────────────┐
  │             │  ← 0x211 状态        │  FOC_double  │  双电机 FOC
  │             │                      │  (FDCAN, 经典帧) │  本地油门/RC 仅在无 CAN 时生效
  │ DlaBoard_A  │  0x220 刹车命令 →    ├──────────────┤
  │  控制板核心  │ ───────────────────→ │ DlaCart_v2.1 │  电动刹车 (脉冲驱动)
  │ (bxCAN hcan1)│                      │   刹车板      │
  │             │  0x64+id 转向伺服 ↔  ├──────────────┤
  │             │ ───────────────────→ │ 转向伺服电机   │  绝对位置闭环
  └─────┬───────┘                      └──────────────┘
        │ USART1 22B 二进制帧 (115200) ↔ Jetson Orin Nano (训练/跟随)
        │ USART2 VGUS 串口屏 (9600)        手动/遥控/训练/跟随、档位、速度档、电量、车速
        │ RC(TIM3) 油门踏板(ADC1) PRND(GPIOD) 刹车开关(PE2/PE3)

1.1 CAN ID 分配表(新建,原先无统一表

ID方向含义DLC实现位置
0x64 + node_id控制板 ↔ 伺服转向伺服(使能/定位/反馈)8servo_can.c / 伺服固件
0x210控制板 → FOC驱动请求(油门‰/转向‰/flags/档位/seq/timeout)8foc_can.cbsp_can.c
0x211FOC → 控制板状态(health/seq/双轮 rpm/echo/valid+gear)8vehicle.cfoc_can.c
0x220控制板 → 刹车板刹车命令(apply/seq/timeout/0x42 魔数)8board_relays.cDlaCart_v2.1/main.c
0x212 (建议新增)FOC → 控制板母线遥测(VBUS 电压 + 母线电流),用于屏显8待实现(见 §4.1)

2. 对接现状结论(已验证一致)

逐字节核对了三块板的收发代码,以下链路 协议层已对齐、可工作

  • 驱动链路 0x210foc_can.c::FocCAN_SendDriveRequest() 的 8 字节布局 与 FOC bsp_can.c::bsp_can_poll_rx() 解析 完全一致(油门 u16LE / 转向 s16LE / flags bit0=allow bit1=brake / gear 0N1F2R / seq / timeout_10ms)。
  • 状态链路 0x211:FOC vehicle.c::vehicle_status_tx() 发送,控制板 FocCAN_OnRxFrame() 解析一致;车速显示已用 FOC 轮 rpm,轮速传感器作回退FocCAN_GetSpeed_01kmh())。
  • 刹车链路 0x220:控制板 Board_Relay_BrakeCylinder() 发送 (apply / seq / timeout_10ms / 0x42)与刹车板 Brake_CAN_ApplyFrame() 校验 (DLC≥4、data[3]==0x42、timeout=data[2]×10、apply=data[0].bit0)完全一致
  • FOC 端仲裁vehicle.c::vehicle_arbitrate() 已实现「CAN 新鲜帧优先、否则本地油门」, 满足需求第 8 条。CAN 超时(默认 300ms)自动失效、800ms 无源撤防停机。

结论:核心驾驶 + 转向 + 状态回读链路工程上已经打通。本 session 的工作集中在 「不一致 / 不工程化 / 文档过时」的修正,以及两个新功能(VBUS 屏显、采集按键)。


3. 需要修改 / 完善的项(按优先级)

P0 — 工程化正确性 / 一致性

  1. Board_Relay_BrakeCylinder() 命名与归属误导

    • 现状:函数名带 “Relay”、文件 board_relays.c 文档称「继电器占位」,但它 实际是 向 0x220 发 CAN 帧给刹车板,与“本地继电器”毫无关系。
    • 处理:拆出独立模块 brake_can.c/hBrakeCAN_Send(apply)),board_relays.c 回归真正的本地继电器占位(MotorStop/Revert)。同步更新文档。
  2. 自动刹车未接入(仅链路测试) ⚠️ 需你确认(见 §5 Q1)

    • 现状:dla_cart_loop.inc:171-175 明确「刹车板仅链路测试,0x220 只由 UART BRAKE 1/0/OFF 触发」。P 档 / 刹车开关 / 跟随刹车 / 撤防 都不会驱动物理刹车板, 只让 FOC foc_brake=1(电机停转)。
    • 工程隐患:自动驾驶/跟随模式下上位机发 brake=1,车辆只松油门滑行,不会物理刹车。
    • 处理:把刹车板纳入正式刹车仲裁(与 foc_brake 同源),保留 UART 测试旁路。
  3. CAN 接收每轮只取一帧

    • 现状:dla_cart_loop.inc:250if 而非 while 排空 FIFO0,且只查 FIFO0。 总线上同时有 伺服回读 / 0x211 / (未来 0x212),高负载下可能丢帧 / 串口屏车速滞后。
    • 处理:改 while 循环排空,分发给 Servo / Foc。
  4. 文档过时与缺口(详见 §3-文档)

P1 — 新功能(功能先做,屏地址后补)

  1. VBUS 母线电压 + 母线电流 屏显(需求第 6 条)

    • 现状:FOC 有 g_vbus(电压)与每相 g_foc[i].ibus(母线电流估计),但 未经 CAN 上报; 0x211 帧 8 字节已满。
    • 处理:FOC 新增 0x212 遥测帧(VBUS mV + 母线电流),控制板接收缓存, 屏地址确定后写 Screen_SendData()。先做 CAN 管路 + 缓存,屏地址留 TODO。
  2. 采集按键与训练按键分离(需求第 7 条)⚠️ 需你确认(见 §5 Q2)

    • 现状:采集功能寄生在「训练」模式(MODE_TRAINING,20ms 上报 TRAIN_TYPE_CTRL)。
    • 目标:训练 = 上报行驶数据给 Jetson 做自动驾驶训练;采集 = 上报 IMU+速度+方向给 Jetson 做 SLAM。两者分开。
    • 阻塞点:控制板 当前无 IMU(文档 §8 已移除 SPI IMU)。采集所需 IMU 数据来源需定。

P2 — 文档标准化

  1. DlaBoard_A 文档补全/纠错
    • 补 0x210/0x211 FOC 驱动+状态协议章节(现仅有伺服 CAN)。
    • 补 0x220 刹车板协议 + 与 DlaCart_v2.1 的接线/收发约定。
    • 新增 CAN ID 分配总表(本文 §1.1)。
    • 改:文档引用的是旧 ../DlaCart(F103),应指向 DlaCart_v2.1
    • 改:foc_can.h 注释「FOC2 尚未正式上行」已过时(FOC 现已周期发 0x211)。
    • 改:board_relays 文档「占位」描述(见 P0-1)。
  2. 三板统一的《CAN 接口规范》单文档,作为对接唯一真源(control/FOC/brake 共用)。

4. 建议的新增 CAN 帧定义(待你确认即可落地)

4.1 0x212 FOC → 控制板 母线遥测(DLC=8)

字节字段类型说明
[0:1]vbus_mVu16 LE母线电压,毫伏(如 38000 = 38.0 V)
[2:3]ibus_cAs16 LE母线总电流,厘安(10 mA/LSB,±327 A 量程;双电机 ibus 求和)
[4]sequ8心跳计数
[5:7]rsvd预留(可放温度/故障字)

控制板侧:新增缓存 + FocCAN_GetVbus_mV()/GetIbus_cA();屏地址确定后周期写屏。


5. 需要你确认的问题(实施前)

  • Q1 自动刹车策略:刹车板是否纳入正式刹车(P 档 / 刹车开关 / 跟随 brake / 撤防 都驱动 0x220)? 还是维持「仅 UART 测试」?
  • Q2 采集 IMU 来源:控制板已无 IMU。采集功能的 IMU 数据从哪来? (重新加板载 IMU / IMU 在 Jetson 侧、控制板只发速度方向 / IMU 在 FOC 经 CAN / 暂缓)
  • Q3 VBUS 遥测:是否按 §4.1 的 0x212 方案先把 CAN 管路与缓存做好(屏地址你后补)?

6. 实施进展(2026-06-01)

决策:Q1=纳入正式刹车、Q3=按 0x212 做;屏地址已补(VBUS 电压 0x05EC、电流 0x05F0、 采集模式键值 0x0020)。

#状态说明
1重构刹车 brake_can.c/h✅ 完成board_relays.c 复位为本地继电器占位;foc_can/CLI 改调 BrakeCAN_Send;已加入 subdir.mk
2接入正式自动刹车✅ 完成foc_brake 统一「跟随brake / 刹车开关PE2-PE3 / P档 / 撤防」,FOC(0x210)与刹车板(0x220)同源;UART 测试期间 FocCAN_BrakeTestActive 让位。
3CAN RX 排空健壮化✅ 完成主循环 ifwhile 排空 FIFO0 逐帧分发。
4VBUS 遥测 0x212 + 屏显✅ 完成FOC bsp_can_send_telemetry+vehicle_telem_tx(10Hz);控制板缓存 + GetVbus_mV/GetIbus_cA;屏写电压→0x05EC、电流→0x05F0,已接通。
5采集/训练分离🟡 结构完成,IMU 待补新增 MODE_COLLECT(屏键 0x0020):行为同训练(伺服不使能、读转向角、可驾驶),20ms 上报 TYPE_COLLECT(0x07) 帧给 Jetson 做 SLAM,与训练 TYPE_CTRL(0x01) 分流。IMU 字段未带(见下)。
6文档标准化✅ 完成新建 01_CAN接口规范_CN.md(唯一真源);主文档补 CAN 概览/模块表/模式键值/VBUS 地址/采集说明/§8 IMU;纠正过时注释。

编译核对:改动文件经 CubeIDE 自带 GCC -fsyntax-only 全部通过 (控制板 F407 / FOC G473)。未动 FOC 底层算法,仅功能层对接。

硬件联调记录(2026-06-01)

烧录:FOC(G473) 走 STLINK;控制板(F407) STLINK 损坏,走 Debug/ISP.py(DTR/RTS 自动进 bootloader)@ COM10(CH340)。诊断工具:Debug/cli_test.pyDebug/drive_test.py (经控制板 CLI 的 ST?/IMU?/FOC D 等)。

全链路硬件验证通过(悬空轮台架):

  • IMU LSM6DSVETR:IMU? → ok=1 who=0x70,6 轴数据合理(Z≈1g)。
  • 控制板→FOC 驱动(0x210):FOC D 15双电机起转 health=0x73(两路 run)、 rpm≈277..533echo=0x01(allow=1,brake=0)、valid=1gear=1
  • FOC→控制板 状态(0x211)+遥测(0x212):VBUS≈31.7V,空载 I=0、驱动时 I≈1.78A
  • 控制板→刹车板(0x220):BRAKE 1/0 → 刹车板 RAM g_brake_apply_cmd 1/0 跟随; 修复后刹车板 rx≈11帧/sbad=0、不再抖动。
  • 油门 ADC = IN8MX_ADC1_Initboard_battery.c 均用 CHANNEL_8,与接线一致; 文档旧述 IN9 作废)。整车使能 PD10 ven=1
  • 手动模式:踏板(IN8)油门,D 档前进 / R 档倒车,正反转均 OK。
  • 遥控模式:RC 转向=CH3(PC8)、油门摇杆=CH4(PC9);轮子与转向均 OK (RC 捕获逻辑/标定无误,文档通道号 CH1/CH2→CH3/CH4 已改正)。
  • FOC 健康自检:误判"故障"实为 2Hz 正常心跳;SWD 直读 g_foc[].mode/faultg_veh.state 均 IDLE/0,无闩锁故障。

联调发现并修复的 3 个真实 bug:

  1. FOC main.c MX_FDCAN1_InitStdFiltersNbr=0(→ 改 1)。标准过滤器元素未分配, bsp_can 的 0x210 接收过滤器不生效 + 全局 REJECT → FOC 丢弃所有收帧(只发不收,控制板 health=0x30/rx 不增)。G4 的 RX FIFO 固定可用,只需过滤器数≥1。
  2. 控制板 dla_cart_app.c Board_VehicleEnableRead:锁存翻转(点动)语义(→ 改去抖电平)。 保持型使能开关上电即闭合时无"按下边沿"→ 永不使能(ven=0/echo=0x02)。改电平后接通即使能。
  3. 刹车板 DlaCart_v2.1/main.c SYS_RUNNINGHAL_Delay(500)×2(→ 改非阻塞 LED 翻转)。 主循环被 LED 闪烁卡死 1 秒/轮 → Brake_CAN_Task 每秒才跑一次 → CAN FIFO 溢出(每秒仅收 3 帧)+ 超时判断滞后 → 继电器 ~1Hz「超时→复位→re-pulse」抖动。修复后 11 帧/s、稳定。

台架诊断工具(保留): 控制板 CLI 新增 ST?(FOC状态/VBUS) IMU? BRK?(刹车仲裁输入); Debug/cli_test.pyDebug/drive_test.py;刹车板经 STLINK hotplug 读 0x200003C0 起的诊断变量。烧录:FOC/刹车走 STLINK,控制板走 Debug/ISP.py <COM> <hex>

#5 采集功能:已完成与剩余

已完成(结构分离):采集模式 MODE_COLLECT(屏键 0x0020)从训练彻底分出,独立 TYPE_COLLECT(0x07) 上报流,携带速度/方向(转向角)/档位/刹车等基础行驶数据。

剩余(IMU,需你确认)

  1. IMU 数据源/驱动:代码核实控制板 main.c 仅有 MX_SPI1_Init()+片选 PA4(硬件就绪), 应用层无 IMU 读取代码。确认型号/接线后新增 imu_spi.c/h 主循环定周期读取。
  2. 帧加长:当前 22 字节帧 [18:19] 仅 2 字节预留,容不下 IMU(加速度+陀螺≥12 字节)。 需与 Jetson 约定加长后的 TYPE_COLLECT 帧布局,再把 IMU 填入。

→ 给定 IMU 型号 + Jetson 帧格式后即可补齐这两步。全程不动 FOC 底层,控制板按需重构。


附:关键源码索引

关注点文件:行
控制板主循环编排DlaBoard_A/Core/Src/dla_cart_loop.inc
FOC 驱动请求发送DlaBoard_A/Core/Src/foc_can.c:323
刹车 CAN 发送(误名)DlaBoard_A/Core/Src/board_relays.c:19
FOC 端 CAN 收发FOC_double/Bsp/Src/bsp_can.c
FOC 端输入仲裁FOC_double/App/Src/vehicle.c:129
FOC VBUS/母线电流FOC_double/Bsp/Src/bsp_vbus.cFoc/Src/foc_core.c:150
刹车板 CAN 解析DlaCart_v2.1/Core/Src/main.c:222
屏地址/键值定义DlaBoard_A/Core/Inc/screen.h
Jetson 帧协议DlaBoard_A/Core/Inc/train_uart.h