# COD_RoboCore **Repository Path**: Xalve/COD_RoboCore ## Basic Information - **Project Name**: COD_RoboCore - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-30 - **Last Updated**: 2026-10-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # COD RoboCore COD 战队的 RoboMaster 电控通用模板:用普通 C11 写成,分层清楚,可以在电脑上测试,并内置失效安全机制。 单板车复制一份仓库、改 `01_applic/config/`;支持两种主控:达妙 DM-MC02(STM32H723)和大疆 C 板(STM32F407)。 > **当前状态(2026-10-17):** 电机、遥控、IMU、图传、视觉通信、电池、四轮底盘、硬件看门狗与故障复位已完成, > 功率 / 发射算法已写好(未接线),裁判系统解析等官方协议文档;电脑侧单元测试共 36 个测试程序。 > 正在 DM-MC02 上逐项验证(进度见 `docs/VERIFICATION_TODO.md`),底盘和看门狗还没上板。大疆 C 板(F407)平台已接入 `c-debug`,尚未上板;当前选择四麦轮,尺寸为待实测的占位值。 ## 设计原则 - **明了易懂**:结构体 + 函数,不用宏生成代码,不用函数指针表模拟多态,新队员能顺着目录读懂。 - **分层单向依赖**:app → devices → platform,算法层(algorithm)是纯计算,可以在 PC 上测试。 - **只写必要的安全机制**:安全门只分“全车停”和“机构停”,每个机构有自己规定的安全动作,而不是简单地“输出 0”;同一个故障只在一处处理。 - **静态内存**:初始化之后不再分配内存。 - **单一时间基准**:所有时间戳、超时判断都读同一个时钟。 ## 模板特色 **能在电脑上测试** - 硬件相关的代码只在 `05_platform/` 一层;其余各层是普通 C,电脑上用假 CAN / SPI / PWM / 时钟替换硬件, 电机协议、遥控解析、姿态解算、安全门等都有单元测试(Unity,36 个测试程序)。 - 平台抽象就是“同名函数、链接时选实现”,没有函数指针表,调试时可以一路跳进具体实现。 **只写必要、但一定写对的安全机制** - 赛场上优先保证车能继续跑:**全车停**只有急停和未解锁;遥控丢失 200 ms 时减速到 0,恢复后直接继续;底盘少一个轮子时降级限速继续。 - 停机不是简单地“输出 0”:每个电机在配置里规定自己的停机动作(DJI 零力矩 / 失能,达妙阻尼),在发送出口统一改写。 - 上电默认安全状态,必须按规定的拨杆顺序才解锁;急停后要重新拨杆。 - 设备“在线”只由**收到合法数据**决定(校验通过才喂狗),离线判断在读取时按时间戳当场计算。 **一个时钟、带时间戳的数据** - 全工程只有一个时间基准 `rm_time_now_us()`:DWT 周期计数(初始化时清零)扩展成 64 位微秒;前提是每次读取间隔小于约 7.8 s(1 kHz 任务保证)。 - 数据由产生它的模块保存(连同时间戳),别人用 `dr16_read()`、`ins_read()` 这类函数整份拷贝;超过时限没更新就返回 false,当作没有数据。 **统一的设备接口** - 电机接口用输出轴的国际单位(rad、rad/s、N·m);DJI(M3508、M2006、GM6020)和达妙(MIT 模式、CAN FD)用同一套接口。 - 板上资源按用途命名(`SPI_DEV_IMU_ACCEL`、`PWM_IMU_HEATER`、`ADC_BATTERY`),换板子只改映射表。 **姿态解算** - BMI088 + 四元数 EKF,用实测的更新间隔积分;芯片安装方向用旋转矩阵配置。 - 上电静止标定陀螺零偏(按标准差判断是否静止),运行中静止时在线修正航向零偏,抵消升温带来的漂移。 - IMU 恒温加热闭环。 **面向 STM32H7 的细节** - DMA 缓冲区放在不经过缓存的专用内存段(`.dma_buf`),避免 Cortex-M7 的缓存一致性问题。 - CAN FD 只在“全 FD 总线”上使用;FreeRTOS 由 CubeMX 生成,其余任务由框架静态创建,重新生成 CubeMX 代码有核对清单。 **可追溯** - 每个设计决定和它的原因都记在 `docs/ADR.md` 里。 - 严格区分“编译通过”“电脑测试通过”“上板验证”“台架实测”,未上板的结论不写成事实。 ## 已支持的功能 验证状态:✅ 已在 DM-MC02 上验证 🧪 编译 + 电脑单元测试通过、还没上板 📝 规划中。每一项的上板步骤和结果见 `docs/VERIFICATION_TODO.md`。 | 类别 | 功能 | 状态 | 说明 | | --- | --- | --- | --- | | 外设接口 | CAN / CAN FD(FDCAN1–3) | ✅ | 收 M3508 反馈、拔线离线与恢复已验证;FD 总线待接达妙电机 | | | SPI(BMI088) | ✅ | | | | PWM:IMU 加热 · 蜂鸣器 | ✅ · 🧪 | 加热闭环已稳在约 40 °C;蜂鸣器待听 | | | ADC:电池电压 | ✅ | 读数正常;分压比 11 待万用表核对 | | | CAN bus-off 自动恢复 | 🧪 | comm_rx_task 检测到后重启控制器,待上板验证 | | | 串口(循环 DMA) | 🧪 | 等接 DR16 / 图传 | | | USB 虚拟串口 | 🧪 | | | | 64 位微秒时钟 · RTT 日志 · 状态灯 | ✅ | 时钟跨过多次 32 位回绕仍连续 | | 电机 | DJI M3508 / M2006 / GM6020 | ✅ 反馈 · 🧪 控制 | 让电机转起来的验证要先把电机固定在台架上 | | | 达妙(MIT 模式,CAN FD) | 🧪 | | | 传感与遥控 | BMI088 + 四元数 EKF + 零偏在线修正 | ✅ | 热态静止航向约 0.006 °/s;冷启动待测 | | | DR16 遥控器 · VT13 图传链路 · 图传键鼠 | 🧪 | | | 通信 | 视觉 USB 帧层(0x5A) | 🧪 | 消息内容等视觉组协议 | | | 裁判系统 | 🧪 帧检查 · 📝 解析 | 解析等官方 V2.0.0 文档 | | 安全 | 安全门(全车停)、每个电机的停机动作 | 🧪 | 上板只看过“一直安全停机”;急停、遥控丢失的停机时间要台架实测 | | | 硬件看门狗 IWDG(50 ms)· 致命故障复位 | 🧪 | control_task 卡死或 HardFault / 栈溢出时复位,复位后自动恢复 | | 算法 | PID · 斜坡 · 低通 · 卡尔曼 · 矩阵 | 🧪 | EKF 用到的部分已随 IMU 上板 | | | 底盘运动学:全向轮 · 麦轮 · 舵轮 · 半舵半全向 | 🧪 | 四种轮组均可由配置选择 | | | 功率模型 + RLS 辨识 · 功率分配 | 🧪 | 未接进底盘(等裁判系统) | | | 发射:热量限频 · 卡弹 · 弹速自适应 | 🧪 | 未接线(发射机构还没有) | | 子系统 | 底盘(四轮全向 / 麦轮 / 舵轮 / 半舵半全向,轮子离线降级) | 🧪 | 当前选四麦轮,轮径 / 轴距 / 轮距暂用 152 / 400 / 440 mm;舵轮找零未上板 | | | 云台 · 发射 · 轮腿 | 📝 | 见下方路线图 | | 通信 | 板间通信 board_link(CAN FD) | 🧪 | 单板车用不到,未接线 | | 主控 | 大疆 C 板(STM32F407) | 🧪 编译 | 平台已接入,硬件未验证 | ## 文档 | 文档 | 内容 | | --- | --- | | `docs/CONTRIBUTING.md` | **协作与上手指南**:必须做 / 禁止做、第一天跑通环境、“想改什么去哪里”、分支与 PR 流程、验证层级、报 bug | | `docs/READING_GUIDE.md` | **代码阅读指南**:按什么顺序读、读到哪里可以停、跟着一份数据把整套代码串起来(第一次看代码先看这个) | | `docs/LOGIC_PSEUDOCODE.md` | **中文逻辑伪代码**:从上电到发电机指令,每个任务做什么,每段标出对应的文件和函数(新队员先看这个) | | `docs/FREERTOS_GUIDE.md` | **FreeRTOS 入门与新增任务**:上电后怎么进到任务、任务怎么轮流、照模板 4 步加一个新任务、常见错误 | | `docs/CALL_FLOW.md` | 调用关系地图:老模板对照、每个任务的函数调用树、怎么在 IDE 里跳转 | | `docs/ARCHITECTURE.md` | 架构设计:分层、核心机制、运行时契约、约定表、硬件与协议事实表 | | `docs/ADR.md` | 决策记录(ADR 0001–0084):每条决策的原因和未决项 | | `docs/IMPLEMENTATION_PLAN.md` | **实施计划**:分阶段清单、验收标准、风险 | | `docs/CODING_STANDARD.md` | 编码规范:命名、格式、注释、错误处理、安全相关代码,“必须 / 应该 / 可以”三级 | | `docs/FORMATTING.md` | 代码格式化:一条命令 `python3 tools/format.py`,clang-format 18 的安装,CLion / VS Code 设置,CI 怎么查 | | `docs/DEV_ENVIRONMENT.md` | 开发环境搭建:WSL、工具链、Ozone 烧录调试、CLion,每步带验证状态;推送到 GitHub 和 Gitee | | `docs/CHANGES_FROM_COD_H7_TEMPLATE.md` | 与 COD-H7-Template 的差异:新旧对照、原因和验证层级 | | `docs/VERIFICATION_TODO.md` | 待验证清单:代码已写好、需要上板或台架确认的项目,每项写明接线、操作和期望 | ## 文件结构 目录前的编号就是从上到下的层次,依赖只能从编号小的指向编号大的: `01_applic` → `02_devices` → `05_platform`;`03_algorithm`、`04_core` 可被各层使用,`03_algorithm` 是纯计算。 代码里 include 也带编号,如 `#include "05_platform/can/can.h"`。标“(规划)”的目录还没有代码。 第一次读代码按 `docs/READING_GUIDE.md` 的顺序走。 ![分层结构图](docs/images/architecture.svg) ```text COD_RoboCore/ ├── 01_applic/ 业务:这台车要做什么 │ ├── system/ 通用框架:app_main.c(上电顺序)、安全门 │ ├── tasks/ 全部 6 个任务:ins、control、comm_rx、detect、indicator、log │ ├── modules/ 机构(可复用) │ │ ├── chassis/ 底盘(全向轮 / 麦轮 / 舵轮 / 半舵半全向) │ │ ├── ins/ 惯性导航(标定、零偏在线修正、EKF、发布姿态) │ │ └── gimbal/ shooter/ leg/ arm/ (规划)云台、发射、轮腿、机械臂 │ └── config/ 这台车:robot.h(参数 + 对象声明)、robot.c(对象 + robot_init + 任务表);目前是四麦轮底盘(尺寸待实测) ├── 02_devices/ 具体设备驱动:把字节解析成有单位的数据,把指令编码成字节 │ ├── motor/ 统一电机接口、DJI、达妙、电机组发送 │ ├── imu/ BMI088(含恒温加热) │ ├── remote/ DR16 遥控器、VT13 图传链路 │ ├── referee/ 裁判系统帧检查(协议解析等官方文档) │ ├── vision/ 视觉 USB 通信帧层 │ ├── battery/ buzzer/ 电池电压、蜂鸣器提示音 │ ├── board_link/ 板间 CAN 通信(已写好,未接线) │ ├── supercap/ 超级电容通信(草案协议,未接板) │ └── actuator/ (规划)PWM 执行器 ├── 03_algorithm/ 纯计算,电脑上可测 │ ├── control/ PID、斜坡 │ ├── filter/ 低通、卡尔曼 │ ├── attitude/ 四元数 EKF、陀螺零偏估计 │ ├── kinematics/ 全向轮、麦轮、舵轮、半舵半全向运动学 │ ├── math/ 矩阵运算 │ ├── power/ 功率模型与分配、RLS │ ├── shoot/ 发射:热量、卡弹、弹速 │ └── ballistic/ (规划)弹道解算 ├── 04_core/ 与业务无关的基础设施 │ ├── watchdog/ 设备在线判断(软件看门狗,不是 IWDG) │ ├── log/ RTT 日志(含 SEGGER RTT 源码) │ ├── os/ 临界区、延时、静态任务创建 │ ├── util/ CRC │ └── error/ param/ (规划)断言与故障记录、Flash 参数 ├── 05_platform/ 外设接口(唯一直接调用 HAL 的一层):一个外设一个目录,接口 + 芯片实现 + 辅助代码 │ ├── can/ can.h、can.c(DLC、接收环形缓冲)、can_stm32h7.c / can_stm32f4.c │ ├── uart/ usb_cdc/ 串口(DMA 循环接收)、USB 虚拟串口 │ ├── time/ status_led/ DWT 时钟、WS2812 状态灯 │ ├── spi/ pwm/ adc/ gpio/ │ ├── iwdg/ 硬件看门狗、致命故障复位 │ ├── flash/ (规划)片内 Flash │ └── stm32h7/ H7 各外设共用的 DMA 缓冲段(.dma_buf);F407 实现在各外设目录的 *_stm32f4.c ├── 06_boards/ 每块板一个目录(CubeMX 生成代码,只改 USER CODE 区) │ ├── dm_mc02_h723/ 达妙 DM-MC02:.ioc、链接脚本 dm_mc02.ld / Keil 的 dm_mc02.sct、MDK-ARM/(Keil 工程)、REGEN_CHECKLIST.md │ └── dji_c_f407/ 大疆 C 板:.ioc、生成代码、板级映射、重新生成核对清单 ├── tests/ │ ├── host/ 电脑侧单元测试(Unity);fakes/ 是假 CAN / SPI / PWM / GPIO / 时钟 / OS │ └── target/ hil/ data/ (规划)板上自测、硬件在环、录制数据 ├── cmake/ 交叉编译工具链、板级编译选项、警告设置 ├── tools/ format.py(格式化)、keil_sync.py(整理 Keil 工程)、gen_readme_diagrams.py(生成本页的图)、mujoco/(底盘仿真) ├── docs/ 架构设计与实施计划、编码规范、开发环境、与旧模板的差异、待验证清单;images/ 放本页的图 ├── CMakePresets.json 三个预设:host-tests(电脑测试)、h723-debug、c-debug;构建目录 build/<系统>/<预设>/ └── LICENSE MIT ``` 各层目录(platform、core、algorithm……)都有自己的 `README.md`,说明这一层放什么、不放什么。 ## 运行时怎么工作 ![启动顺序](docs/images/startup.svg) ### 任务 | 任务 | 周期 | 优先级 | 做什么 | | --- | --- | --- | --- | | `ins_task` | 1 kHz | 6(最高) | 读 BMI088,零偏标定与在线修正,四元数 EKF 算姿态,IMU 恒温加热,保存最新姿态(`ins_read()` 读) | | `comm_rx_task` | 有数据就运行 | 5 | 中断收到 CAN 帧 / 串口字节 / USB 数据后被唤醒,交给对应设备解析;CAN bus-off 恢复 | | `control_task` | 1 kHz | 4 | 读实测 → 算目标(安全门、各机构目标)→ 算输出(全车停改写、发电机指令)(下图 ①–⑤) | | `detect_task` | 100 Hz | 3 | 报告设备上线 / 离线(只报告,不参与安全判断);看 control_task 的心跳喂硬件看门狗 IWDG | | `indicator_task` | 40 Hz | 2 | 状态灯、蜂鸣器、低电量检查 | | `log_task` | 1 Hz | 1 | 通过 RTT 打印这台车的状态和 control_task 的实时性统计 | 中断只收数据并唤醒 `comm_rx_task`,所有协议解析都在任务里做;1 kHz 的任务里不打日志。 ![一个控制周期里的数据流](docs/images/runtime.svg) 判断“丢失 / 离线”在读取时当场做(按写入时刻算数据有多旧),不需要另外的定时器。 ![安全门状态图](docs/images/safety_gate.svg) ## 快速开始 **需要的工具**(安装步骤和验证记录见 `docs/DEV_ENVIRONMENT.md`): | 工具 | 版本 | | --- | --- | | 系统 | Windows 原生,或 Linux / WSL 2(Ubuntu 24.04) | | 交叉编译器 | `arm-none-eabi-gcc`:Arm GNU Toolchain 15.2.Rel1,或 STM32CubeCLT 自带的(已验证 1.22 / GCC 14.3) | | 构建 | CMake ≥ 3.25、Ninja(CLion 自带) | | 测试 | 电脑上的 gcc(Windows 用 CLion 自带的 MinGW)+ Unity,外设用手写的假实现替换 | | 代码格式 | clang-format 18(`python3 tools/format.py`,见 `docs/FORMATTING.md`);clang-tidy、cppcheck(规划) | | 烧录与调试 | SEGGER J-Link + Ozone(烧录、RTT 日志、实时看变量);CLion(编辑、构建、断点) | | 板级配置 | STM32CubeMX 6.18(改完按 `06_boards/dm_mc02_h723/REGEN_CHECKLIST.md` 核对) | **CLion(推荐,Windows 原生)**:打开仓库根目录 → CLion 自动读取 `CMakePresets.json`,包含三个配置: | 配置 | 用途 | 怎么用 | | --- | --- | --- | | `h723-debug` | DM-MC02 固件 | 运行配置选 `COD_RoboCore`,按 **Ctrl+F9** 构建(不要按 ▶,ELF 不能在电脑上运行) | | `host-tests` | 电脑侧单元测试 | 运行配置选 `All CTest`,按 ▶ | | `c-debug` | 大疆 C 板固件 | 构建 `COD_RoboCore`;不能用 H723 的 Keil 工程烧录 C 板 | 工具链用 CLion 默认的 MinGW 即可;交叉编译器由 `cmake/toolchain-arm-gcc.cmake` 自动查找 (环境变量 `ARM_TOOLCHAIN_BIN` → PATH → `C:/ST/STM32CubeCLT_*` 等默认安装位置),找不到时 CMake 会提示怎么做。 **命令行**(仓库根目录,Windows 和 Linux / WSL 相同): ```bash cmake --preset host-tests && cmake --build --preset host-tests && ctest --preset host-tests # 单元测试 cmake --preset h723-debug && cmake --build --preset h723-debug # DM-MC02 cmake --preset c-debug && cmake --build --preset c-debug # 大疆 C 板 ``` 构建目录按系统分开:`build/Windows/<预设>/`、`build/Linux/<预设>/`,同一份代码在 Windows 和 WSL 里轮流编译不会互相弄坏缓存。 固件是 `build/<系统>/<预设>/COD_RoboCore.elf`,编译必须 0 警告。 CMake 报“CMakeCache.txt directory is different”时,删掉对应的 `build/` 子目录(或 CLion 里 **Reset Cache and Reload Project**)再来。 **3. 烧录并看日志**:Ozone 打开这个 ELF → **Download & Reset** → F5 运行 → **View → Terminal** 看 RTT 日志。 上电后约 2 s 内不要动板子(陀螺零偏标定)。看到 `startup done`、每秒一行 `alive N, mode safe` 就是跑起来了。当前麦轮尺寸仍为占位值,电机方向也待核对。 > 习惯 Keil 的可以直接用 Keil 编译、烧录、调试:打开 `06_boards/dm_mc02_h723/MDK-ARM/dm_mc02.uvprojx`(Keil 自己的编译器 AC6,和 CMake 编同一组文件,见 `06_boards/dm_mc02_h723/README.md`“Keil”)。 > 目前请用 Ozone 烧录:经 J-Link GDB 服务器(CLion)烧录会显示成功但实际没写入,原因还在查,见 `docs/DEV_ENVIRONMENT.md` 11.2 节。 ## 做一台具体的车 本仓库是通用模板,`01_applic/config/` 是“这台车”。做英雄、工程、哨兵等具体的车时复制整个仓库,然后: 1. 改 `config/robot.h`:电机表(CAN 总线、ID、方向、停机动作)、PID、尺寸、解锁拨杆、IMU 安装方向。 2. 改 `config/robot.c`:定义对象、在 `robot_init()` 里初始化设备和机构,`robot.h` 同步声明;加任务时改同一文件的 `task_table[]`,入口声明在 `tasks/tasks.h`。电机 `motor_init()` 时就进了电机组,CAN 接收不用改。 3. 改 `01_applic/tasks/control_task.c`:每个控制周期做什么(读实测 → 算目标 → 算输出,三步各一个函数)、遥控满杆速度; `tasks/comm_rx_task.c` 改接线,`tasks/log_task.c` 改打印内容。各任务的调用关系见 `docs/CALL_FLOW.md`。 4. 需要新机构(云台、发射……)时在 `01_applic/modules/` 里加,再在第 2、3 步里接上。 5. 加了新的 `.c` 文件:在 CMake 里加,Keil 里拖进对应分组(或运行 `python3 tools/keil_sync.py`)。 多板车按 ADR 0083 在同一仓库放各板配置和任务、用不同预设构建,消息表共用;这部分尚未实现。 `02_devices/board_link/` 收发已写好,双板心跳和解锁互锁尚未接入。 分层规则、命名和安全相关代码的写法见 `docs/CODING_STANDARD.md`。 ## 注意事项 - **固件会给电机发指令。** 未解锁时持续发零电流,解锁后按遥控转动。接电机前先把电机固定在台架上、输出轴不带负载、断电开关放在手边;只看反馈时手扶即可,让电机转起来时不行。 - **不要随手暂停正在控制电机的程序。** 调试器暂停后 CAN 指令停发,电调怎么反应还没有实测。 - **未上板的功能不要直接上车。** 以上表的验证状态为准,“🧪”只代表电脑测试通过。 ## 路线图 | 阶段 | 内容 | 状态 | | --- | --- | --- | | 0 骨架 | 目录、构建、CubeMX 工程、时钟、日志、单元测试 | ✅ 完成并上板 | | 基础设备 | 电机、遥控、IMU、图传、视觉通信、电池等 | 🧪 代码完成(裁判系统等文档),上板验证进行中 | | 1 最小完整链路 | 一台电机 + 遥控 + 安全停机,停机时间台架实测;硬件看门狗(🧪 已写)、故障记录、指令层 | 进行中 | | 2 C 板移植 | 每个外设目录加 `*_stm32f4.c`,跑同一条最小链路 | 📝 | | 3 设备层补全 | 电机停发后的行为实测、分类发送队列 | 📝 | | 4 姿态 + 云台 | 云台控制、`GimbalState` | 📝 | | 5 步兵整车 | 底盘(功率控制)、发射(热量、卡弹)、裁判系统、键鼠、UI、自瞄通信 | 📝 | | 6 参数存储 | Flash 双区保存标定值 | 📝 | | 7–9 | 轮腿、多板 / 哨兵、工程 | 📝 | 每个阶段的清单和验收标准见 `docs/IMPLEMENTATION_PLAN.md`。 ## 仓库约定 - 所有文本文件为 **UTF-8 编码、LF 换行**,由 `.gitattributes` 和 `.editorconfig` 保证。 - 提交说明的格式是 `类型: 做了什么`,类型包括 `feat` 新功能、`fix` 修复、`docs` 文档、`build` 构建、`test` 测试、`chore` 杂项。 - 编译必须 **0 警告**。推送到 GitHub 后,`.github/workflows/ci.yml` 自动做格式检查、电脑侧单元测试和固件编译。 ## 参考与致谢 设计时参考了以下项目: - [COD-H7-Template](https://github.com/GrassFanWang/COD-H7-Template)(COD,MIT) - [COD_UniCFramework](https://github.com/fakeSkyy/COD_UniCFramework)(COD,MIT) - [basic_framework](https://github.com/HNUYueLuRM/basic_framework)(湖南大学跃鹿战队,MIT) - 其他开源项目的思路:taproot(GPL-3.0,只借鉴思路,未使用其代码)、StandardRobot++、RM2024-PowerModule 等 从 COD-H7-Template、COD_UniCFramework 移植的代码,原作者的版权声明统一列在 `LICENSE` 末尾。 ## 许可证 [MIT](LICENSE)。`06_boards/` 下的 ST HAL、CMSIS、FreeRTOS、USB 库和 `04_core/log/segger_rtt/` 保留各自的许可证(见各目录的 LICENSE)。 本软件按“原样”提供,不保证接上电机、上车后的安全;使用者自行负责台架验证和人身、设备安全。