diff --git a/README.md b/README.md new file mode 100644 index 0000000..a2cb67d --- /dev/null +++ b/README.md @@ -0,0 +1,431 @@ +# Simba-OmniInfantry + + + + + + +
Simba-gitELEC
+ +[![Author](https://img.shields.io/badge/Author-LSMushui-orange.svg)](https://gitee.com/LSMushui) +![language](https://img.shields.io/badge/language-C-blue.svg) +![license](https://img.shields.io/badge/license-GPLv3-green.svg) +![mcu](https://img.shields.io/badge/MCU-STM32F407IGH6-lightgrey.svg) + +> Simba 步兵机器人电控固件 —— 双板架构(云台板 + 底盘板),Keil + FreeRTOS + CMSIS-DSP。 + +--- + +## 目录 + +- [1. 项目概览](#1-项目概览) +- [2. 硬件与工具链](#2-硬件与工具链) +- [3. 快速开始](#3-快速开始) +- [4. 代码地图](#4-代码地图) +- [5. 运行架构](#5-运行架构) +- [6. 数据流与对外接口](#6-数据流与对外接口) +- [7. 模块清单](#7-模块清单) +- [8. 调试:USB CDC 遥测](#8-调试usb-cdc-遥测) +- [9. 调参与开关](#9-调参与开关) +- [10. 上电行为与灯语](#10-上电行为与灯语) +- [11. 已知陷阱与注意事项](#11-已知陷阱与注意事项) +- [12. 版本管理约定](#12-版本管理约定) +- [13. 致谢与联系](#13-致谢与联系) + +--- + +## 1. 项目概览 + +本仓库包含 **两套完整且结构对称的 Keil 工程**,分别烧录到步兵机器人的两块 C 型开发板上: + +| 工程 | 编译宏 | 角色 | +| --- | --- | --- | +| [`云台/`](./云台) | `ROBOT_TYPE_GIMBAL` | 云台(Yaw/Pitch)+ 发射机构 + 图传链路 + 板间通讯主控 | +| [`底盘/`](./底盘) | `ROBOT_TYPE_CHASSIS` | 麦轮底盘 + 跟随云台 + 功率管理 | + +设计要点: + +- **两板源码高度同构**。`Application/`、`Bsp/`、`modules/` 绝大多数文件在两棵树下是同一份拷贝,板级差异用 `ROBOT_TYPE_*` 宏在文件内条件编译(而不是拆成两套文件)。**因此改一处通常要同步改另一处**,详见 [§11](#11-已知陷阱与注意事项)。 +- **姿态由 QuaternionEKF 统一负责**。两板各有一颗板载 BMI088,跑同一套 Wang Hongxi 的 QuaternionEKF 四元数 EKF(陀螺积分预测 + 加速度重力观测 + 卡方检验),不再使用 legacy 的 Mahony 互补滤波,也不再依赖预编译的 `AHRS.lib`。 +- **跟随采用"双 INS 世界系"方案**。云台把自己解算出的世界系 yaw 通过 CAN 发给底盘,底盘用自身 INS 的 yaw 相减得到相对偏差。两板 INS 的上电零点任意但差值天然正确,因而绕开了皮带虚位与基准锁定时序的坑。 + +--- + +## 2. 硬件与工具链 + +| 项 | 说明 | +| --- | --- | +| MCU | STM32F407IGH6(Cortex-M4F,单精度硬浮点,168 MHz) | +| SDK | STM32CubeF4(HAL 库) | +| RTOS | FreeRTOS(CMSIS-RTOS v1 封装),`configTICK_RATE_HZ = 1000` | +| 数学库 | ARM CMSIS-DSP(`arm_cortexM4lf_math.lib`,卡尔曼滤波的矩阵运算全依赖它) | +| 工程 | CubeMX 生成 + Keil MDK-ARM(工程文件 `MDK-ARM/Simba-ELCT-FrameWork.uvprojx`) | +| 上位机 | VSCode 作为编辑器(配 `.clang-format`),**不要用 Keil 编辑器改代码** | + +> 强烈建议按社区教程把 Keil 切到 **AC6** 编译器(AC5 编译极慢)。切换方式见 RoboMaster 社区的 AC6 配置教程。 + +--- + +## 3. 快速开始 + +### 3.1 编译与烧录 + +1. 用 Keil 打开对应板子的工程: + - 云台:`云台/MDK-ARM/Simba-ELCT-FrameWork.uvprojx` + - 底盘:`底盘/MDK-ARM/Simba-ELCT-FrameWork.uvprojx` +2. 确认编译宏:Target → C/C++ → Define 中应含 `ROBOT_TYPE_GIMBAL` 或 `ROBOT_TYPE_CHASSIS`(两个工程已各自配好)。 +3. Rebuild → Download。 + +### 3.2 上电前置检查 + +- **上电后头 1.5 秒请把车体放稳别碰**。IMU 的 z 轴陀螺零偏要在这段时间内静止标定,标定窗口里混入运动会让 yaw 恒定自漂(见 [§11.3](#113-z-轴零偏标定必须静止))。 +- 云台板会做一次 **yaw 装配符号自检**(给 Yaw 电机一个小电压脉冲看陀螺往哪边转),此时云台会轻转几度,**不要扶住云台**;失败时回退到 `GIMBAL_YAW_SIGN_FALLBACK`。 + +### 3.3 看一眼运行状态 + +插上 USB 会出现虚拟串口(CDC),波特率随意,直接打开即可看到姿态与诊断输出,字段含义见 [§8](#8-调试usb-cdc-遥测)。 + +--- + +## 4. 代码地图 + +``` +Simba-OmniInfantry/ +├── README.md 本文 +├── doc/ +│ └── 已知问题与排障.md 踩坑记录与排障手册(强烈建议先读) +├── 云台/ ┐ +│ ├── Application/ │ 应用层 +│ │ ├── Task/Inc/ │ 任务头文件(app_tasks.h 汇总声明) +│ │ ├── Task/Src/ │ 各任务实现 +│ │ ├── robot_param.h │ ★ 整车唯一调参入口(含台架调试开关) +│ │ └── robot_typedef.h │ 应用层公共类型 +│ ├── Bsp/ │ 板级支持包(与具体外设寄存器打交道) +│ │ ├── Inc/ Src/ │ bsp_can(过滤器+按ID分发回调)、bsp_usart(DMA收发) +│ ├── Core/ │ CubeMX 生成的初始化与中断 +│ │ ├── Src/main.c │ 外设初始化顺序 +│ │ ├── Src/freertos.c │ ★ 任务创建与优先级/栈大小 +│ │ ├── Src/stm32f4xx_it.c │ 中断入口(含 USART 空闲中断调用) +│ │ └── Inc/FreeRTOSConfig.h │ 节拍/堆大小等 +│ ├── Drivers/ │ ST HAL + CMSIS(勿手改) +│ ├── Middlewares/ │ FreeRTOS / USB Device Library / CMSIS-DSP +│ ├── USB_DEVICE/ │ USB CDC 设备栈(usbd_cdc_if.c 为应用接口) +│ ├── modules/ │ ★ 按角色分层的功能模块(见下) +│ └── MDK-ARM/ │ Keil 工程与启动文件 +└── 底盘/ ┘ 结构同上 +``` + +### `modules/` 分层(2026-09 重排) + +``` +modules/ +├── algorithm/ 通用算法 pid, filter +├── imu/ 姿态与惯导封装 attitude(对外姿态 API)、ins(QEKF 封装) +│ └── qekf/ 第三方移植内核 QuaternionEKF、kalman_filter(移植自 Wang Hongxi INS 例程) +├── sensor/ 板载传感器驱动 bmi088(SPI+DMA)、ist8310(I2C 磁力计) +├── comms/ 通讯 dr16(遥控器)、referee(裁判/图传)、c_comm(板间) +├── motor/ 电机抽象 dji_motor(大疆电机统一接口) +├── control/ 整车控制逻辑 gimbal + shoot(云台板) / chassis(底盘板) +└── dev/ 板级指示与发声 led、buzzer +``` + +> `imu/qekf/` 里的两个文件是原样移植的第三方代码,**尽量不改**;要改先读 `imu/attitude.c` 与 `imu/ins.c` 的文件头注释(QEKF 内部 Pitch/Roll 命名与航空惯例互换)。 + +--- + +## 5. 运行架构 + +### 5.1 任务表 + +FreeRTOS 节拍 1 kHz。任务来自 `Core/Src/freertos.c`: + +| 任务 | 优先级 | 栈(words) | 分配方式 | 职责 | 板 | +| --- | --- | --- | --- | --- | --- | +| `IMU_Task` | High | 512 | 静态 | 1 kHz 姿态解算 + 磁力计轮询 + IMU 恒温 | 双板 | +| `gimbal_task` / `chassis_task` | AboveNormal | 512 | 动态 | 2 ms 控制环 | 各一板 | +| `CAN_Task` | Normal | 512 | 静态 | 全部硬件初始化,完成后置 `app_ready` | 双板 | +| `robot_cmd_task` | Normal | 384 | 动态 | 遥控/键鼠 → 统一控制指令 | 双板 | +| `c_comm_task` | Normal | 256 | 动态 | 2 ms 板间通讯收发 | 双板 | +| `shoot_task` | Normal | 384 | 动态 | 摩擦轮/拨弹 | 云台 | +| `referee_task` | Low | 256 | 动态 | 裁判系统解析 | 双板 | +| `debug_task` | Low | 384 | 动态 | USB CDC 姿态与诊断输出 | 双板 | +| `LED_Task`(monitor) | Low | 512 | 静态 | 心跳监控 + LED/蜂鸣报警 + 喂 IWDG | 双板 | + +**初始化顺序**:`CAN_Task` 先跑,依次 `led_init → buzzer_init → MX_USB_DEVICE_Init → can_start → 电机/发射/板间通讯初始化 → 串口初始化 → app_ready = 1`。其余任务在 `app_ready` 之前 `while` 等待。 + +### 5.2 控制周期 + +- 姿态解算 **1 kHz**(`IMU_Task`,`vTaskDelayUntil` 精确节拍,`dt` 固定 1 ms) +- 整车控制 **2 ms**(改周期需重调所有 PID) +- 板间通讯 **2 ms** + +### 5.3 看门狗 + +`LED_Task` 入口立即启动 IWDG(约 2.5 s 溢出)。**上电前 5 s 无条件喂狗**,之后仅当所有任务心跳都在 500 ms 内刷新过才喂 —— 任何任务卡死都会复位整车,不会失控。 + +> ⚠️ 因此**整个初始化必须在 5 s 内完成**。传感器初始化失败重试、IMU 零偏标定都在这个预算里,扩展时要算好(见 [§11.4](#114-初始化必须留在-5-s-内)。 + +--- + +## 6. 数据流与对外接口 + +### 6.1 CAN 总线分配 + +| 板 | CAN1 | CAN2 | +| --- | --- | --- | +| 云台板 | Pitch GM6020 `0x206`、摩擦轮 M3508 `0x201/0x202` | Yaw GM6020 `0x205`、底盘回传 `0x019` | +| 底盘板 | 四轮 M3508 `0x201~0x204` | 云台数据 `0x149/0x189/0x1A9` | + +### 6.2 串口分配 + +| 外设 | 用途 | 备注 | +| --- | --- | --- | +| USART3 | DR16 遥控器接收机 | 100000-8E1,需 9 位字长(`bsp_usart.c` 里重新初始化) | +| USART6 | 图传链路 / 裁判系统(3pin 口) | 变长帧 | +| USART1 | 视觉上位机(4pin 口) | 收发 DMA 已就绪,协议待接入 | + +三者都是 **循环 DMA + 空闲中断取整帧**,在中断上下文把整帧交给注册的回调。 + +### 6.3 板间通讯协议(CToC) + +帧 ID 与 legacy 一致,定义见 `modules/comms/c_comm.h`: + +| 帧 | 方向 | 内容 | +| --- | --- | --- | +| `0x149` | 云台 → 底盘 | 四路摇杆量(大端 16 bit) | +| `0x189` | 云台 → 底盘 | 遥控状态、S1/S2、Shift、启动标志、小陀螺使能、云台电机故障位 | +| `0x1A9` | 云台 → 底盘 | 云台世界系 yaw(float,LE)+ flags(att_ready / 编码器增向 / 自检完成) | +| `0x019` | 底盘 → 云台 | 发射机构上电状态、底盘电机故障位 | + +**故障位语义**:任一侧电机掉线即置位,对侧收到后必须停止自己的输出(整车安全)。 + +### 6.4 姿态数据流 + +``` +BMI088(SPI1 + DMA,EXTI 数据就绪) + └─> modules/sensor/bmi088.c 解析出 bmi088_accel[] / bmi088_gyro[] + └─> modules/imu/ins.c z 零偏补偿 + QEKF 更新(1 kHz) + └─> modules/imu/attitude.c 输出 att_deg_yaw / att_deg_pitch / att_deg_roll + ├─> control/gimbal.c Yaw/Pitch 环反馈 + └─> comms/c_comm.c 0x1A9 帧发给底盘 +``` + +### 6.5 视觉上位机(待接入) + +`usart1_tx_dma_init()` 已在 `CAN_Task` 中就绪,`bsp_usart.c` 提供 `usart1_tx_dma_enable()`。自瞄协议接入时直接用这套接口即可,无需改动 BSP。 + +--- + +## 7. 模块清单 + +| 模块 | 路径 | 职责 | +| --- | --- | --- | +| `pid` | `algorithm/` | 位置式/增量式 PID,双环共用 | +| `filter` | `algorithm/` | 通用滤波器(低通等) | +| `attitude` | `imu/` | 对外的姿态 API:初始化、1 kHz 更新、`att_deg_*`、磁力计轮询、IMU 加热控制 | +| `ins` | `imu/` | QEKF 封装 + z 轴零偏标定 + 机体系/导航系变换 + 运动加速度 | +| `QuaternionEKF` / `kalman_filter` | `imu/qekf/` | 第三方移植:四元数 EKF 与通用卡尔曼框架(**勿轻易改**) | +| `bmi088` | `sensor/` | 六轴 IMU 驱动(SPI1 模式 3 @5.25 MHz,INT 数据就绪触发 DMA,含数据路自恢复) | +| `ist8310` | `sensor/` | 三轴磁力计(硬件 I2C3,200 Hz 轮询) | +| `dr16` | `comms/` | DR16 遥控器帧解析 | +| `referee` | `comms/` | 裁判系统 / 图传链路解析 | +| `c_comm` | `comms/` | 板间通讯收发与故障位综合 | +| `dji_motor` | `motor/` | 大疆电机(CAN 反馈解析 + 电流/电压下发)统一抽象 | +| `gimbal` | `control/` | 云台 Yaw/Pitch 双环 + yaw 装配符号自检 | +| `shoot` | `control/` | 摩擦轮 + 拨弹 | +| `chassis` | `control/` | 麦轮解算 + 轮速环 + 跟随 + 功率限制 | +| `led` / `buzzer` | `dev/` | 三色 LED(TIM5 PWM)与无源蜂鸣器(TIM4_CH3/PD14) | +| `bsp_can` | `Bsp/` | CAN 过滤器、按 (总线, 标准 ID) 分发回调、发送封装 | +| `bsp_usart` | `Bsp/` | 三路串口的循环 DMA + 空闲中断整帧接收,以及 TX DMA | + +--- + +## 8. 调试:USB CDC 遥测 + +`Application/Task/Src/debug_task.c` 每 100 ms 输出一行(单位:角度 ° / 加速度 m/s² / 角速度 rad/s): + +``` +yaw=-0.03 pitch=-25.58 roll=-8.00 cvg=1 rdy=1 imu=1 an=9.80 gn=0.017 +gx=0.0012 gy=-0.0031 gz=0.0165 zo=0.0009 ck=1 ca=803 cg=1002 se=0 st=1 +``` + +> 实测是一行,上面为排版折行。 + +### 欧拉角 + +| 字段 | 含义 | +| --- | --- | +| `yaw` | 多圈连续偏航角(`INS.YawTotalAngle`)。**无绝对基准**(纯陀螺积分),上电静止时恒为该次上电的相对 0 点,所以"yaw=0.00"不是故障特征 | +| `pitch` | 绕 y 轴角(`= QEKF_INS.Roll`) | +| `roll` | 绕 x 轴角(`= QEKF_INS.Pitch`,云台 Pitch 环反馈用它) | + +> QEKF 内部 Pitch/Roll 命名与航空惯例**互换**,映射关系与原因见 `modules/imu/attitude.c` 文件头。 + +### 健康位与诊断位 + +| 字段 | 含义 | 怎么用 | +| --- | --- | --- | +| `cvg` | `INS.ConvergeFlag`,1 = 卡方检验通过、姿态可信 | **唯一"是否真收敛"的判据**,不要和别的量混淆 | +| `rdy` | `att_ready`,1 = 姿态更新至少跑过一次 | 只说明"在跑",不代表可信 | +| `imu` | `bmi088_online`,1 = IMU 初始化成功 | 0 则姿态必然全 0 | +| `an` | `\|bmi088_accel\|` | 静止应 ≈ 9.8;≈ 0 说明 IMU 没给数据 | +| `gn` | `\|bmi088_gyro\|`(**未减零偏**的原始模长) | 静止 ≈ 0;转动时明显变大 | +| `gx/gy/gz` | 原始陀螺三分量 | 与 `gn` 一起判断数据是否冻结 | +| `zo` | `ins_gyro_z_offset`,上电标定得到的 z 零偏 | 实际进滤波器的是 `gz - zo`。**若 `zo` 明显大于 `gz` 而 yaw 又匀速自漂 ⇒ 零偏标歪了** | +| `ck` | `ins_z_cal_ok`,1 = 标定时全程静止,`zo` 可信 | 0 说明三轮标定都没静下来 | +| `ca`/`cg` | 加速度/陀螺采样计数 | **判断"数据是否还在更新"的唯一可靠依据 —— 数值可能冻结在旧值上,计数不会** | +| `se` | SPI/DMA 出错累计次数 | 持续增长说明 SPI 出错频繁 | +| `st` | SPI 状态(1=READY) | **长期非 1 ⇒ SPI 卡死**;`st=1` 但 `ca/cg` 不涨 ⇒ 数据就绪中断丢失 | + +### 开关 + +`debug_task.c` 顶部: + +- `DEBUG_ATT_HEALTH = 0` → 只输出三个欧拉角 +- `DEBUG_ATT_DIAG = 0` → 去掉 `gx..st` 这些排障字段 + +--- + +## 9. 调参与开关 + +**所有可调参数集中在 `Application/robot_param.h`**(整车唯一调参入口),分区如下: + +| 分区 | 内容 | +| --- | --- | +| 云台 | Pitch 限位/零位、摩擦轮/拨弹转速、拨杆比例、Yaw 双环 PID、Pitch 双环 PID | +| 云台符号自检 | `GIMBAL_YAW_SIGN_AUTO`、检测脉冲电压与判定阈值 | +| 底盘 | 麦轮几何、转速换算系数、摇杆比例、轮速 PID、跟随 PID、功率限制 | +| CToC | 四个板间帧 ID | +| 掉线检测 | `DEVICE_OFFLINE_TIME_MS`、`CTOC_OFFLINE_TIME_MS` | +| IMU | 恒温目标/限值、温度 PID | +| **台架调试开关** | `DEBUG_SHOOT_WITHOUT_REFEREE`、`GIMBAL_RAMMER_INSTALLED`、`DEBUG_BUZZER_MELODY` | + +### 三个台架调试开关 + +| 宏 | 默认 | 作用 | 比赛前 | +| --- | --- | --- | --- | +| `DEBUG_SHOOT_WITHOUT_REFEREE` | 1 | 无裁判系统时也允许开摩擦轮 | 改 0 | +| `GIMBAL_RAMMER_INSTALLED` | 0 | 拨弹 M2006 是否已安装(不装则不参与掉线判定) | 按实际 | +| `DEBUG_BUZZER_MELODY` | 1 | CAN 掉线警告音换成循环旋律(避免台架调试时连续滴滴声)。**只换声音不换灯语**,故障信息不丢 | 改 0 | + +--- + +## 10. 上电行为与灯语 + +### 上电时序 + +1. `CAN_Task`:**蓝灯常亮**(调度器与任务栈正常的最直观证据)→ 蜂鸣器/USB/CAN/电机/串口逐个初始化 +2. `IMU_Task`:BMI088 + IST8310 初始化(有界重试)→ **z 零偏静止标定**(约 0.5~1.5 s)→ 启动 1 kHz 解算 +3. 云台板:**yaw 装配符号自检**(云台会轻转几度,勿扶) +4. `app_ready = 1` → 其余任务开始跑 → `LED_Task` 熄灭蓝灯,交由报警逻辑接管 + +### 灯语(LED) + +| 现象 | 含义 | +| --- | --- | +| 蓝灯每 2 s 短闪 | 系统健康心跳(区分"空闲"与"卡死") | +| 红灯 1 s 内双闪 | 遥控器掉线 | +| 红灯常亮 | CAN 设备掉线(同时蜂鸣报警) | +| 绿灯 1 s 内连闪两下 | **BMI088 失败** | +| 绿灯 1 s 周期慢闪 | IST8310 失败 | +| 绿灯常亮 | IMU 过温(已关加热)或双传感器都失败 | + +### 蜂鸣器 + +- **CAN 掉线报警**:按掉线设备序号 `n` 每 2 s 窗内响 `n` 下,只报**最先**掉线的那台设备。云台序号:`0=摩擦轮L 1=摩擦轮R 2=Pitch 3=Yaw 4=拨弹 5=底盘回传`;底盘:`0~3=四轮 4=云台数据`。所以**响三下 = Pitch 电机掉线**。 +- **遥控器连接音效**:遥控器上线瞬间两声上扬。 +- 调试模式下上述报警音可换成旋律,见 [§9](#9-调参与开关)。 + +--- + +## 11. 已知陷阱与注意事项 + +> 每一条都是实际踩过的坑。更详细的排障过程见 [doc/已知问题与排障.md](./doc/已知问题与排障.md)。 + +### 11.1 增删源文件必须同步改 `.uvprojx`(和 `.uvoptx`) + +新增/删除 `.c` 后必须同时在 Keil 工程里增删条目,并检查: + +- `.uvprojx` 的 `` 指向的文件真实存在 +- `.uvoptx` 的 `` 是**全局连续序号**,删条目后末项编号要跟着改,否则 Keil 每次保存都会重写该文件 +- **`.h` 不登记在工程里**(只登记 `.c`),头文件靠 `` 找到 + +### 11.2 libc 堆必须 ≥ 8 KB(QEKF 的矩阵内存靠 `malloc`) + +`modules/imu/qekf/kalman_filter.h` 的分配宏: + +```c +#ifdef _CMSIS_OS_H +#define user_malloc pvPortMalloc // ← 实际走不到这支 +#else +#define user_malloc malloc // ← 实际走这支 +#endif +``` + +`kalman_filter.c` 只 include 了 `kalman_filter.h`,**从未引入 `cmsis_os.h`**,所以 `user_malloc` 展开为 **libc `malloc`**,FreeRTOS 那 32 KB 堆完全用不上。而 `Kalman_Filter_Init(6, 0, 3)` 要发起 **25 次分配、合计约 1.6 KB**,全程无 NULL 检查。 + +因此 `MDK-ARM/startup_stm32f407xx.s` 里的 `Heap_Size` **必须为 `0x2000`(8 KB)**(与原始例程一致)。CubeMX 默认值是 `0x200`(512 B),会导致后半段分配返回 NULL、滤波器静默失效(角度恒定不动)。 + +### 11.3 z 轴零偏标定必须静止 + +QEKF 无法观测 z 偏置,只能上电静止标定。标定窗口里混入运动样本会把 `gyro_z_offset` 标成一个大常值,之后 **yaw 以该常值匀速自漂,与陀螺真实输出无关**。 + +`ins.c` 已有健壮性(等 50 ms 稳定 → 剔除 `|gyro| > 0.35 rad/s` 的离群样本 → 单轮有效样本占比 < 90% 判为"车体在动"整轮重测,最多 3 轮 → 均不静则置 `ins_z_cal_ok = 0`),但**根治手段仍然是上电后那 1.5 秒别碰车**。 + +判断方法:`yaw` 漂移率(rad/s)如果**大于**遥测里的 `gn`,就说明漂移来自被污染的 `zo`,不是陀螺本身。 + +### 11.4 初始化必须留在 5 s 内 + +IWDG 的上电宽限期只有 5 s,而 `IMU_Task` 在 `attitude_init()` 期间不刷新心跳。所以"整个初始化"必须留在 5 s 内 —— 这也是 `INS_Z_CAL_ATTEMPTS × INS_Z_CAL_SAMPLES` 没有放大的原因。要延长标定预算,得同时调整看门狗宽限期。 + +### 11.5 BMI088 的中断是低有效、必须配下降沿 + +INT1(加速度计)/INT3(陀螺仪)被配成推挽、低有效的数据就绪信号,`EXTI` 必须为**下降沿**。CubeMX 生成的 `gpio.c` 默认给的是 `GPIO_MODE_IT_RISING`,会落在电平恢复沿上、采样时序错位。已在 `.ioc` 里写入 `GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING`,但**重新生成工程后仍要复查 `gpio.c`**。 + +### 11.6 数据路可能静默冻结 + +BMI088 的 DRDY 是**电平型**信号:某次失败或被挡掉的读取没把数据寄存器读走,INT 电平就会保持住,之后**既无下降沿也无上升沿**,EXTI 永不触发;或者 `hspi1` 被卡在 BUSY,`start_dma_read()` 的 `HAL_SPI_GetState` 检查会让每次调用直接返回。 + +这两种情况下,**写在中断回调里的兜底都不会执行**,所以自恢复放在任务上下文:`bmi088_health_check()` 由 `attitude_update()` 每 1 ms 调用,采样计数 5 ms 不涨即判定停摆,重启中断路(必要时 `abort`/重建 SPI)并阻塞读一次;修不好则退化为约 200 Hz 轮询保底。 + +**排查姿态异常时永远先看 `ca`/`cg` 是否在涨。** + +### 11.7 CubeMX 重新生成会覆盖的改动 + +以下都是"手改过的 CubeMX 生成文件",重新生成工程会被改回去,**必须复查**: + +| 文件 | 被覆盖的内容 | +| --- | --- | +| `MDK-ARM/startup_stm32f407xx.s` | `Heap_Size`(需 `0x2000`) | +| `Core/Src/gpio.c` | INT1 触发沿(需 `FALLING`) | + +### 11.8 其他 + +- `arm_mat_*` 失败是**静默**的:尺寸不符或 `pData = NULL` 时只返回错误码、不修改输出。调用方不查返回码,滤波器就会"看起来在跑但状态不更新"。 +- `modules/imu/qekf/` 是第三方移植代码,改动前先读原例程与 `attitude.c` 的文件头约定。 +- `Middlewares/ST/ARM/DSP/Lib/*.lib` 是**源码依赖而非构建产物**,已纳入版本管理,不要把 `*.lib` 加进 `.gitignore`。 +- 无源蜂鸣器 `buzzer_on(BUZZER_P)` 即静音,旋律表里用它作断音。 + +--- + +## 12. 版本管理约定 + +- 仓库根为 git 仓库,内含两个子工程;`.gitignore` 排除 Keil 构建产物、`*.uvguix.*`、`DebugConfig/`、`.workbuddy/`。 +- **`core.autocrlf=false`**:固件源码是 LF,不要让 git 在检出时改成 CRLF。 +- 注意换行符风格并不统一:`Core/Src/*.c` 与 `.ioc` 是 CRLF,`modules/**` 等是 LF。批量脚本改文件时要按文件自动适配。 +- 两板同构:改动请**同步改两棵树**,并确认差异只出现在应当不同的文件上(`gimbal*`/`shoot*` 只在云台,`chassis*` 只在底盘)。 + +--- + +## 13. 致谢与联系 + +- 姿态解算移植自 RoboMaster-C-Board-INS-Example(Wang Hongxi)的 QuaternionEKF 与通用卡尔曼框架。 +- 感谢各战队开源代码,legacy 版本(`new-infantry-c-board-legacy`)是本项目的移植来源与重要参照。 + +**通讯信息** + +- 作者 `连山木水` 微信:18088745066 QQ:1194309310 + +## 参考 + +- 踩坑记录与排障手册:[`doc/已知问题与排障.md`](./doc/已知问题与排障.md) diff --git a/doc/已知问题与排障.md b/doc/已知问题与排障.md new file mode 100644 index 0000000..b5d4f20 --- /dev/null +++ b/doc/已知问题与排障.md @@ -0,0 +1,160 @@ +# 已知问题与排障手册 + +本文记录本项目实际踩过的坑、判断依据和处理方式。**遇到姿态/通讯异常时先读这里。** + +--- + +## 0. 排障总则 + +### 0.1 先看 `ca` / `cg`,再看数值 + +USB 遥测里的 `ca`(加速度采样计数)和 `cg`(陀螺采样计数)是**唯一能证明"数据还在更新"的指标**。 + +数值是**会骗人的** —— 数据路停摆时,`an`、`gn`、`gx/gy/gz`、`pitch/roll` 都会安静地停在最后一个样本上,看起来"挺正常"。 + +``` +ca/cg 在涨 → 数据路活着,问题在算法或标定 +ca/cg 不涨 → 数据路死了,先修数据路,别的都别管 +``` + +### 0.2 用算式交叉验证,别凭感觉 + +姿态异常时,把**观测到的现象**和**遥测里的量**做量级核算,往往能直接定位层次。例: + +- yaw 匀速自漂 → 算漂移率(rad/s) + - 若漂移率 **> `gn`** ⇒ 漂移来自被污染的 z 零偏 `zo`,不是陀螺本身 + - 若漂移率 **≈ `gz - zo`** ⇒ 算法没问题,是数据冻结了(EKF 在忠实积分冻结值) +- 角度恒定不动 → 看 `cvg`:`cvg=0` 说明量测一直被卡方检验拒绝;`cvg=1` 而角度不动 ⇒ 多半是 `ca/cg` 停了 + +### 0.3 症状速查表 + +| 症状 | 首先怀疑 | 去看 | +| --- | --- | --- | +| 欧拉角恒为 0.00 | IMU 没起来,或 EKF 内存分配失败 | `imu`、`an`、`cvg`;[§2.1](#21-三个欧拉角恒为-000) | +| 角度恒定不动(有值但不变) | 数据路停摆(数据冻结) | `ca`/`cg`;[§2.2](#22-数据路静默冻结) | +| yaw 匀速自漂 | z 零偏标定被运动污染 | `zo` vs `gz`,漂移率 vs `gn`;[§2.3](#23-yaw-匀速自漂) | +| 角度是垃圾值 / yaw≈180 | 矩阵运算静默失败 | `cq` 字段、`Heap_Size`;[§2.1](#21-三个欧拉角恒为-000) | +| 蜂鸣器连续滴滴响 | CAN 设备掉线报警(正常行为) | 响几下 = 第几号设备掉线;[§2.4](#24-蜂鸣器一直响) | +| 红灯常亮 | CAN 设备掉线 | 同上 | +| 绿灯连闪两下 | BMI088 失败 | `imu` | +| 反复重启(约 3~5 s 一次) | 初始化超时 / 任务卡死 | IWDG 5 s 预算;[§2.5](#25-反复重启) | +| 串口收不到整帧 | 空闲中断 / DMA 未重启 | `bsp_usart.c` | + +--- + +## 1. 工具与判据 + +### 1.1 USB CDC 遥测字段 + +完整字段说明见根 [README §8](../README.md#8-调试usb-cdc-遥测)。排障最常用的几个: + +| 字段 | 关键读法 | +| --- | --- | +| `ca`/`cg` | **是否在增长** = 数据路是否活着 | +| `cvg` | `INS.ConvergeFlag`,是否真收敛(不是"是否在跑") | +| `imu` | BMI088 是否初始化成功 | +| `an` | ≈9.8 正常;≈0 说明没数据 | +| `gn` | 原始陀螺模长(**未减零偏**) | +| `zo` | 实际减掉的 z 零偏;与 `gz` 量级对比 | +| `ck` | `zo` 是否可信(标定时是否静止) | +| `se`/`st` | SPI 出错次数 / SPI 状态(1=READY) | + +### 1.2 LED 与蜂鸣器 + +灯语见根 [README §10](../README.md#10-上电行为与灯语)。蜂鸣器的"响几下"直接对应掉线设备序号 + 1。 + +### 1.3 与参考工程对照 + +桌面上留有本项目的参照物,**遇到"应该能跑却跑不起来"时,优先和它们逐行对照**: + +| 参考 | 位置 | 用途 | +| --- | --- | --- | +| 原始 INS 例程 | `Desktop/新建文件夹/RoboMaster-C-Board-INS-Example-master` | QEKF / kalman_filter 的移植来源;**其 `Heap_Size = 0x2000`** | +| legacy 固件 | `Desktop/new-infantry-c-board-legacy - 副本` | StdPeriph 版、自带 `AHRS.lib`;引脚分配、EXTI 触发沿、寄存器序列的权威参照 | +| 本工程旧版 | `Desktop/Simba-OmniTest/Simba-ELCT-FrameWork` | 同一框架的历史快照 | + +--- + +## 2. 典型案例详解 + +### 2.1 三个欧拉角恒为 0.00 + +**两个不同原因都会长成这样**,用 `cvg` 和 `an` 区分: + +#### (a) EKF 矩阵内存分配失败 —— `cvg=1`、`an≈9.8`、角度恒 0 + +- **现象**:`yaw=pitch=roll=0.00` 且 `cvg=1`(注意 `cvg` 若是 `att_ready` 之类的量就永远看不出来) +- **原因**:`kalman_filter.c` 的 `user_malloc` 展开为 **libc `malloc`**(它不 include `cmsis_os.h`),而 libc 堆来自 `startup_stm32f407xx.s` 的 `Heap_Size`。CubeMX 默认 `0x200`(512 B),远小于 `Kalman_Filter_Init(6,0,3)` 需要的约 1.6 KB,且全程无 NULL 检查 +- **后果**:后半段矩阵 `pData = NULL`,`arm_mat_*` 只读写地址 0 附近、不报错也不改输出 ⇒ 滤波器不再更新状态,但 `UpdateCount` 照常自增 ⇒ 看起来"在跑"、"收敛了" +- **处理**:把 `Heap_Size` 改为 `0x2000`(与原始例程一致)。⚠️ 该行由 CubeMX 生成,重新生成工程会被改回 + +#### (b) IMU 没起来 —— `cvg=0`、`an≈0`、角度恒 0 + +- **现象**:`imu=0` 或 `an≈0`,且 `cvg=0`(卡方检验一直不过) +- 加速度全零 → 量测被拒绝 → 四元数停在初值 `[1,0,0,0]` 反解就是三个 0.00 +- **处理**:查 SPI 通路 / 片选 / 传感器供电;并把 `debug_task` 的 `imu`、`an` 和绿灯灯语一起看 + +### 2.2 数据路静默冻结 + +- **现象**:`pitch/roll/an/gx/gy/gz` 全部纹丝不动,`ca`/`cg` **停止增长**,而 `imu` 仍是 1;yaw 可能还在匀速漂(积分冻结值) +- **两类原因**: + 1. `hspi1` 卡在 BUSY(SPI/DMA 出错后 HAL 没回到 READY)⇒ `start_dma_read()` 里 `HAL_SPI_GetState` 检查让每次调用直接返回 + 2. BMI088 的 DRDY 是**电平型**信号,某次失败或被挡掉的读没把数据寄存器读走 ⇒ INT 电平保持住 ⇒ **既无下降沿也无上升沿,EXTI 永不触发** +- **为什么中断里的兜底没用**:两种情况都会让 EXTI 回调**压根不执行** +- **处理**:已实现任务上下文的 `bmi088_health_check()`(由 `attitude_update()` 每 1 ms 调用),计数 5 ms 不涨即重启中断路 + 阻塞读一次,修不好则退化为约 200 Hz 轮询保底 +- **继续深挖**:看 `st` 与 `se` + - `st` 长期非 1 ⇒ SPI 卡死(原因 1) + - `st` 恒为 1 但 `ca/cg` 不涨 ⇒ 数据就绪中断丢失(原因 2) + +### 2.3 yaw 匀速自漂 + +- **现象**:yaw 以**恒定**角速度漂移,`pitch/roll` 正常;移动板子时陀螺读数"不响应" +- **判定算式**: + ``` + 漂移率(rad/s) = Δyaw / Δt + 若 漂移率 > gn ⇒ 漂移来自被污染的 zo,不是陀螺 + 实际进滤波器的角速度 = gz - zo + ``` + 实例:实测 -3.85 °/s = -0.0672 rad/s,而 `gn = 0.017 rad/s` —— 漂移率比整个陀螺模长还大近 4 倍,只可能是假零偏 +- **原因**:z 轴零偏标定窗口(~1 s)里混入了运动样本。上电瞬间 SPI 路刚起步、且车体常正被摆弄 +- **处理**:`ins.c` 已加健壮性(稳定等待 + 离群剔除 + 整轮重测 + `ck` 标志);**根治办法是上电后那 1.5 秒别碰车** +- 注意 `gn` 是**未减零偏**的原始模长,所以 `gn` 小并不代表进滤波器的值小 + +### 2.4 蜂鸣器一直响 + +- 这是**正常报警**,不是故障:某台 CAN 设备掉线,`monitor_task` 按 legacy 语义每 2 s 窗内响 `n` 下,`n = 最先掉线的设备序号 + 1` +- 云台序号:`0=摩擦轮L 1=摩擦轮R 2=Pitch 3=Yaw 4=拨弹 5=底盘回传`;底盘:`0~3=四轮 4=云台数据` +- **响三下 ⇒ 第 3 号设备(云台板的 Pitch 电机 0x206)掉线** +- 台架调试嫌吵:把 `robot_param.h` 的 `DEBUG_BUZZER_MELODY` 置 1,警告音换成旋律;**灯语不变,故障信息不丢**。比赛前记得改回 0 + +### 2.5 反复重启 + +- **现象**:约 3~5 s 复位一次,USB 输出每隔几秒重来 +- **原因**:IWDG 约 2.5 s 溢出;上电 5 s 内无条件喂狗,之后要求**所有任务**心跳都在 500 ms 内刷新过。因此 + - 某个任务卡死(死循环 / 阻塞在无超时的等待) + - 或者**整个初始化超过 5 s**,`IMU_Task` 还没进主循环、心跳不刷新 +- **处理**:检查各初始化耗时(传感器重试次数、IMU 零偏标定轮数);`IMU_Task` 在 `attitude_init()` 期间不刷心跳,扩展初始化要算进这 5 s 预算 + +### 2.6 工程编译/链接相关的坑(非运行期) + +| 症状 | 原因 | 处理 | +| --- | --- | --- | +| 链接报找不到 `arm_mat_*` | `Middlewares/ST/ARM/DSP/Lib/*.lib` 丢失 | 该目录是源码依赖,已入库;确认文件在 | +| 新加的 `.c` 没被编译 | 没加进 `.uvprojx` | 同步加 `.uvprojx`(和 `.uvoptx`) | +| Keil 每次保存工程文件都在变 | `.uvoptx` 的 `` 断号 | 删除条目后把末尾编号改为连续值 | +| 移动目录后编译不过 | `` 没跟着改 | `.h` 不登记在工程里,靠 IncludePath 定位;移动目录时同步改 | +| CubeMX 重新生成后行为变了 | 手改过的生成文件被覆盖 | 复查 `startup_stm32f407xx.s` 的 `Heap_Size` 与 `Core/Src/gpio.c` 的 INT1 触发沿 | + +--- + +## 3. 改动本仓库时的检查清单 + +改完代码准备提交前,过一遍: + +- [ ] 两棵树都改了?(同构文件需要同步) +- [ ] 增删了 `.c`?→ 同步改 `.uvprojx` 与 `.uvoptx` +- [ ] 移动了目录?→ 同步改 `.uvprojx`/`.uvoptx` 的文件路径与 `` +- [ ] 工程引用的文件是否都真实存在?磁盘上的 `.c` 是否都被工程引用(没有掉出编译)? +- [ ] 动过 `modules/imu/qekf/`?→ 先读 `imu/attitude.c`、`imu/ins.c` 文件头约定 +- [ ] 姿态相关改动?→ 在 `README §8` 的字段里想清楚**怎么验证**(哪个字段能证明它对了) +- [ ] 改了 `robot_param.h` 里带"比赛请改 0"的开关?→ 记得改回来 diff --git a/云台/README.md b/云台/README.md index 714bf25..3066219 100644 --- a/云台/README.md +++ b/云台/README.md @@ -1,133 +1,59 @@ -# Simba-ELCT-FrameWork +# 云台板固件(Simba-ELCT-FrameWork) +> 步兵机器人**云台板**工程 · STM32F407IGH6 · Keil + FreeRTOS + CMSIS-DSP - - - - - -
Simba-gitELEC
+项目总览、代码地图、任务表、调试与注意事项请先读 **[根 README](../README.md)** 与 **[已知问题与排障](../doc/已知问题与排障.md)**。本文只讲这块板特有的东西。 -[![Author](https://img.shields.io/badge/Author-LSMushui-orange.svg)](https://gitee.com/LSMushui) -![language](https://img.shields.io/badge/language-C-blue.svg) -![license](https://img.shields.io/badge/license-GPLv3-green.svg) +--- +## 这块板负责什么 -## 简介 +- **云台控制**:Yaw(GM6020 `0x205`,CAN2)/ Pitch(GM6020 `0x206`,CAN1)双环 +- **发射机构**:摩擦轮 M3508 `0x201`/`0x202` + 拨弹 M2006 `0x207`(装与不装由 `GIMBAL_RAMMER_INSTALLED` 决定) +- **图传链路 / 裁判系统**:USART6(3pin 口) +- **DR16 遥控器**:USART3 +- **板间通讯主控**:云台把世界系 yaw(`0x1A9`)与摇杆/控制状态(`0x149`/`0x189`)发给底盘 +- **视觉上位机接口**:USART1(4pin 口),收发 DMA 已就绪,协议待接入 -> Simba自己的C板电控框架! +## 编译宏 -本项目的计划是基于 **DJI C型开发板** 的基础上打造一个更适合Simba同学们的代码框架 +``` +USE_HAL_DRIVER, STM32F407xx, ARM_MATH_CM4, ROBOT_TYPE_GIMBAL +``` -本框架致力于实现不同类型的机器人的代码通用化,只需要选择底盘云台的类型,修改一下对应物理参数即可实现对机器人的适配 +## 相对底盘板多出来的东西 -## 配套套件 +| 项 | 位置 | +| --- | --- | +| `gimbal` 云台双环 + 装配符号自检 | `modules/control/gimbal.c` | +| `shoot` 摩擦轮/拨弹 | `modules/control/shoot.c` | +| `gimbal_task` / `shoot_task` | `Application/Task/Src/` | +| DR16 遥控器、视觉串口 | `Bsp/bsp_usart.c` 的 `usart3_init` / `usart1_*` | +| 板间帧 0x149 / 0x189 / 0x1A9 的**发送**侧 | `modules/comms/c_comm.c` | +| IST8310 磁力计与本板 IMU 恒温 | `modules/imu/attitude.c`(双板都有,云台用于云台控制) | -> 上位机,ROS接口待开发 +底盘板有的 `control/chassis.c` 与 `chassis_task` 本工程没有(所以两棵树的 `modules/control/` 内容不同,属预期差异)。 -## 模块支持 +## 上电时本板特有的行为 -详细信息请参考 [Simba-ELCT-FrameWork文档](./doc/framework.md) +1. `led_init` 点亮蓝灯 → 各外设初始化 +2. IMU 初始化 + **z 轴零偏静止标定(约 0.5~1.5 s,这段时间别碰车)** +3. **Yaw 装配符号自检**:给 Yaw 电机一个正向小电压脉冲,看陀螺 z 轴往哪边转,自动定符号;**云台会轻转几度,不要扶住云台**。失败(被按住 / 电机离线)时回退到 `GIMBAL_YAW_SIGN_FALLBACK` +4. 自检结果经 `0x1A9` 的 flags 下发给底盘,与底盘自测的车身转向相乘完成跟随符号综合 -### 主要模块 +## 蜂鸣器序号(本板) -- **Robot cmd**\ - 机器人控制模块: - - [ ] 大疆电机 - - [ ] 达妙电机 - - [ ] 瓴控电机 - - [ ] 小米电机 - - [ ] 超级电容控制板 - - [ ] 板间通信(CAN) - - [ ] PWM 控制舵机 - - [ ] PWM 控制气泵 -- **Chassis**\ - 底盘模块: - - [ ] 麦轮底盘 - - [ ] 全向轮底盘 - - [ ] 舵轮底盘 - - [ ] 平衡底盘 -- **Gimbal**\ - 云台模块: - - [ ] yaw-pitch 直连云台 - - [ ] yaw直连-pitch丝杆 云台 - - [ ] yaw-pitch 丝杆云台 -- **Shoot**\ - 发射机构模块: - - [ ] 摩擦轮+拨弹盘 - - [ ] 摩擦轮+弹鼓+推杆 -- **Communication**\ - 通信模块: - - [ ] 板间通信(CAN2) - - [ ] 上下位机通信 -- **Music**\ - 音乐模块: - - [ ] 开机声 - - [ ] 报错音 - - [ ] 裁判系统接入提示音 - - [ ] 《卡农》 - - [ ] 《天空之城》 - - [ ] 《恭喜发财》 - - [ ] 《好运来》 - - [ ] 《See You Again》 - - [ ] 《Unity》 - - [ ] 《你》 +CAN 掉线报警按设备序号响 `n` 下: -## 开发工具 +``` +0 = 摩擦轮L(0x201) 1 = 摩擦轮R(0x202) 2 = Pitch(0x206) +3 = Yaw(0x205) 4 = 拨弹(0x207) 5 = 底盘回传(0x019) +``` -本项目使用HAL库编写,通过CubeMX生成项目,使用FreeRTOS +**响三下 = Pitch 电机掉线。** 台架调试嫌吵时把 `robot_param.h` 的 `DEBUG_BUZZER_MELODY` 置 1(只换声音不换灯语)。 -使用VSCode作为代码编辑器,Keil5作为IDE +## 构建 -Keil5编译器使用AC6版本 -> 虽然keil5老,但在嵌入式调试以及环境配置方面是非常简单易上手的。**千万不要用keil5来编辑代码!!!** -\ -\ -> VSCode作为现代化代码编辑器 ,通过各种插件即可实现各种提高效率的开发方式,**尤其是Github Copilot** -\ -\ -> AC6编译器相比古早AC5编译器效率更高,AC5编译空项目就要足足1min47s,非常不中,相比之下AC6只需要6s,遥遥领先 -\ -\ -> 但是CubeMX开启FreeRTOS无法直接使用AC6编译器 -\ -> 强烈建议通过此[教程](https://bbs.robomaster.com/article/18268)(From COD战队GrassFan Wang)配置好自己的环境 +用 Keil 打开 `MDK-ARM/Simba-ELCT-FrameWork.uvprojx`,确认 Define 里是 `ROBOT_TYPE_GIMBAL`,Rebuild → Download。 - - - -## 欢迎贡献 - -如果你发现了本项目中的问题和可优化的点,可用创建issue进行讨论 - -并且fork本项目后提交pr来贡献你的代码 - -我们的管理员审核后会将你的代码合并进来 - -> ***贡献代码时请参照 [注意事项](./doc/注意事项.md/#贡献代码) 中的贡献代码部分。*** -> -> 编写代码时参考[API](./doc/API.md) - -## 开发日志 - -[LOG.md](./doc/LOG.md) 记录了大家在开发过程中的各种奇思妙想和经验。多翻一翻或许能发现惊喜哦。大家有什么想法也都可以往里面写 - -[API.md](./doc/API.md) 为开发过程中所使用的模块接口标准,若在编写代码时发现代码与标准冲突,基于本标准修改代码 - -## 后续计划 - -具体要做的事情在[TODO](./doc/TODO.md)中 - -## 致谢 - -感谢各个战队的代码开源,所有本框架涉及到的主要的参考资料位于[reference.md](./doc/reference.md) - -## 附录 - -本文的详细补充内容写在 [附录](./doc/appendix.md) 中 - -如发现本项目中的问题,请添加至[问题列表](./doc/questions.md)并与相关负责人联系,如果有解决方案可以提交pull request - -## 通讯信息 - -- 作者 `连山木水` 微信:18088745066 QQ:1194309310 +> ⚠️ 本工程与底盘工程源码高度同构,改一处通常要同步改另一处。动手前请读根 README 的 [§11 已知陷阱](../README.md#11-已知陷阱与注意事项)。 diff --git a/云台/modules/comms/c_comm.h b/云台/modules/comms/c_comm.h index 8f6353a..996640d 100644 --- a/云台/modules/comms/c_comm.h +++ b/云台/modules/comms/c_comm.h @@ -12,11 +12,10 @@ * 底盘误判沿会误开小陀螺,勿再使用) * Data[6] bit0=键1 bit1=键2 bit2=小陀螺使能(本工程扩展) * bit7=云台电机故障(本工程扩展) - * 0x1A9 云台->底盘:Data[0..3]=云台世界系 yaw(float,LE) Data[4]=att_ready - * (双 INS 跟随方案的数据源,2026-09 新增) * 0x1A9 云台->底盘:Data[0..3]=云台世界系 yaw(float,LE) * Data[4] flags:bit0=att_ready bit1=编码器tick增向为CCW - * bit2=该位有效(自检完成) [跟随符号自动综合的数据源] + * bit2=该位有效(自检完成) + * (双 INS 跟随方案 + 跟随符号自动综合的数据源,2026-09) * 0x019 底盘->云台:Data[0]发射机构上电状态 Data[1] bit0=底盘电机故障(本工程扩展) * * 故障位语义:任一侧电机掉线即置位,对侧收到后必须停止自己的输出(整车安全) */ diff --git a/底盘/README.md b/底盘/README.md index 714bf25..bf5f878 100644 --- a/底盘/README.md +++ b/底盘/README.md @@ -1,133 +1,56 @@ -# Simba-ELCT-FrameWork +# 底盘板固件(Simba-ELCT-FrameWork) +> 步兵机器人**底盘板**工程 · STM32F407IGH6 · Keil + FreeRTOS + CMSIS-DSP - - - - - -
Simba-gitELEC
+项目总览、代码地图、任务表、调试与注意事项请先读 **[根 README](../README.md)** 与 **[已知问题与排障](../doc/已知问题与排障.md)**。本文只讲这块板特有的东西。 -[![Author](https://img.shields.io/badge/Author-LSMushui-orange.svg)](https://gitee.com/LSMushui) -![language](https://img.shields.io/badge/language-C-blue.svg) -![license](https://img.shields.io/badge/license-GPLv3-green.svg) +--- +## 这块板负责什么 -## 简介 +- **麦轮底盘**:四轮 M3508(`0x201~0x204`,CAN1)解算 + 轮速环 +- **跟随云台**:双 INS 世界系方案 —— 收云台的 `0x1A9`(世界系 yaw),与本板 INS 的 yaw 相减得相对偏差 +- **功率限制**:缓冲能量不足时按比例缩放轮电流 +- **裁判系统**:USART6 +- **板间通讯从侧**:解析云台发来的摇杆/控制状态(`0x149`/`0x189`),回传发射机构上电状态与故障位(`0x019`) -> Simba自己的C板电控框架! +底盘板**没有** DR16 遥控器串口:遥控数据由云台板解析后经板间帧转发过来,底盘侧表现为一个"虚拟遥控器"(`ctoc_remote_t`)。 -本项目的计划是基于 **DJI C型开发板** 的基础上打造一个更适合Simba同学们的代码框架 +## 编译宏 -本框架致力于实现不同类型的机器人的代码通用化,只需要选择底盘云台的类型,修改一下对应物理参数即可实现对机器人的适配 +``` +USE_HAL_DRIVER, STM32F407xx, ARM_MATH_CM4, ROBOT_TYPE_CHASSIS +``` -## 配套套件 +## 相对云台板多出来的东西 -> 上位机,ROS接口待开发 +| 项 | 位置 | +| --- | --- | +| `chassis` 麦轮解算 + 轮速环 + 跟随 + 功率限制 | `modules/control/chassis.c` | +| `chassis_task` | `Application/Task/Src/chassis_task.c` | +| 板间帧 0x149/0x189/0x1A9 的**接收**侧与 0x019 的发送侧 | `modules/comms/c_comm.c` | -## 模块支持 +云台板有的 `control/gimbal.c`、`control/shoot.c` 与对应任务本工程没有(所以两棵树的 `modules/control/` 内容不同,属预期差异)。 -详细信息请参考 [Simba-ELCT-FrameWork文档](./doc/framework.md) +## 上电时本板特有的行为 -### 主要模块 +1. `led_init` 点亮蓝灯 → 各外设初始化 +2. IMU 初始化 + **z 轴零偏静止标定(约 0.5~1.5 s,这段时间别碰车)** +3. 跟随符号综合:本板用小 `w` 脉冲 + INS 测出"w 正向对应的车身转向",与云台下发的编码器增向相乘;失败时回退 `CHASSIS_FOLLOW_SIGN` -- **Robot cmd**\ - 机器人控制模块: - - [ ] 大疆电机 - - [ ] 达妙电机 - - [ ] 瓴控电机 - - [ ] 小米电机 - - [ ] 超级电容控制板 - - [ ] 板间通信(CAN) - - [ ] PWM 控制舵机 - - [ ] PWM 控制气泵 -- **Chassis**\ - 底盘模块: - - [ ] 麦轮底盘 - - [ ] 全向轮底盘 - - [ ] 舵轮底盘 - - [ ] 平衡底盘 -- **Gimbal**\ - 云台模块: - - [ ] yaw-pitch 直连云台 - - [ ] yaw直连-pitch丝杆 云台 - - [ ] yaw-pitch 丝杆云台 -- **Shoot**\ - 发射机构模块: - - [ ] 摩擦轮+拨弹盘 - - [ ] 摩擦轮+弹鼓+推杆 -- **Communication**\ - 通信模块: - - [ ] 板间通信(CAN2) - - [ ] 上下位机通信 -- **Music**\ - 音乐模块: - - [ ] 开机声 - - [ ] 报错音 - - [ ] 裁判系统接入提示音 - - [ ] 《卡农》 - - [ ] 《天空之城》 - - [ ] 《恭喜发财》 - - [ ] 《好运来》 - - [ ] 《See You Again》 - - [ ] 《Unity》 - - [ ] 《你》 +> 车身自检时**整车会轻转**,确保周围安全。 -## 开发工具 +## 蜂鸣器序号(本板) -本项目使用HAL库编写,通过CubeMX生成项目,使用FreeRTOS +``` +0~3 = 四轮(0x201 右前 / 0x202 左前 / 0x203 左后 / 0x204 右后) +4 = 云台数据(0x149/0x189/0x1A9) +``` -使用VSCode作为代码编辑器,Keil5作为IDE +台架调试嫌吵时把 `robot_param.h` 的 `DEBUG_BUZZER_MELODY` 置 1(只换声音不换灯语)。 -Keil5编译器使用AC6版本 -> 虽然keil5老,但在嵌入式调试以及环境配置方面是非常简单易上手的。**千万不要用keil5来编辑代码!!!** -\ -\ -> VSCode作为现代化代码编辑器 ,通过各种插件即可实现各种提高效率的开发方式,**尤其是Github Copilot** -\ -\ -> AC6编译器相比古早AC5编译器效率更高,AC5编译空项目就要足足1min47s,非常不中,相比之下AC6只需要6s,遥遥领先 -\ -\ -> 但是CubeMX开启FreeRTOS无法直接使用AC6编译器 -\ -> 强烈建议通过此[教程](https://bbs.robomaster.com/article/18268)(From COD战队GrassFan Wang)配置好自己的环境 +## 构建 +用 Keil 打开 `MDK-ARM/Simba-ELCT-FrameWork.uvprojx`,确认 Define 里是 `ROBOT_TYPE_CHASSIS`,Rebuild → Download。 - - -## 欢迎贡献 - -如果你发现了本项目中的问题和可优化的点,可用创建issue进行讨论 - -并且fork本项目后提交pr来贡献你的代码 - -我们的管理员审核后会将你的代码合并进来 - -> ***贡献代码时请参照 [注意事项](./doc/注意事项.md/#贡献代码) 中的贡献代码部分。*** -> -> 编写代码时参考[API](./doc/API.md) - -## 开发日志 - -[LOG.md](./doc/LOG.md) 记录了大家在开发过程中的各种奇思妙想和经验。多翻一翻或许能发现惊喜哦。大家有什么想法也都可以往里面写 - -[API.md](./doc/API.md) 为开发过程中所使用的模块接口标准,若在编写代码时发现代码与标准冲突,基于本标准修改代码 - -## 后续计划 - -具体要做的事情在[TODO](./doc/TODO.md)中 - -## 致谢 - -感谢各个战队的代码开源,所有本框架涉及到的主要的参考资料位于[reference.md](./doc/reference.md) - -## 附录 - -本文的详细补充内容写在 [附录](./doc/appendix.md) 中 - -如发现本项目中的问题,请添加至[问题列表](./doc/questions.md)并与相关负责人联系,如果有解决方案可以提交pull request - -## 通讯信息 - -- 作者 `连山木水` 微信:18088745066 QQ:1194309310 +> ⚠️ 本工程与云台工程源码高度同构,改一处通常要同步改另一处。动手前请读根 README 的 [§11 已知陷阱](../README.md#11-已知陷阱与注意事项)。 diff --git a/底盘/modules/comms/c_comm.h b/底盘/modules/comms/c_comm.h index 8f6353a..996640d 100644 --- a/底盘/modules/comms/c_comm.h +++ b/底盘/modules/comms/c_comm.h @@ -12,11 +12,10 @@ * 底盘误判沿会误开小陀螺,勿再使用) * Data[6] bit0=键1 bit1=键2 bit2=小陀螺使能(本工程扩展) * bit7=云台电机故障(本工程扩展) - * 0x1A9 云台->底盘:Data[0..3]=云台世界系 yaw(float,LE) Data[4]=att_ready - * (双 INS 跟随方案的数据源,2026-09 新增) * 0x1A9 云台->底盘:Data[0..3]=云台世界系 yaw(float,LE) * Data[4] flags:bit0=att_ready bit1=编码器tick增向为CCW - * bit2=该位有效(自检完成) [跟随符号自动综合的数据源] + * bit2=该位有效(自检完成) + * (双 INS 跟随方案 + 跟随符号自动综合的数据源,2026-09) * 0x019 底盘->云台:Data[0]发射机构上电状态 Data[1] bit0=底盘电机故障(本工程扩展) * * 故障位语义:任一侧电机掉线即置位,对侧收到后必须停止自己的输出(整车安全) */