Files
Gimbal/ARCHITECTURE.md
T
SkyLiCoder 8763b25839 chore: upgrade FreeRTOS to v2 (CMSIS-RTOS_V2), update CubeMX project config
- Remove CMSIS-RTOS v1 (cmsis_os.h/cmsis_os.c), add CMSIS-RTOS v2 (cmsis_os2.c/freertos_os2.h/mpool.h)
- Update FreeRTOS kernel, port, and headers to match v2 integration
- Remove unused heap implementations, keep heap_4
- Update CubeMX project config (.mxproject, .ioc, CMakeLists.txt)
- Update FreeRTOSConfig.h, freertos.c, main.c, stm32h7xx_it.c
- Update application modules (master_machine, dmmotor)
- Add CMSIS-RTOS2 headers, mpu_syscall_numbers.h, newlib/picolibc support
2026-05-30 20:40:00 +08:00

311 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 项目架构:Basic_Framework_MC02 (DM 云台控制系统)
## 概览
基于 **STM32H723** (Cortex-M7, 480MHz) 的达妙电机云台控制系统。采用 FreeRTOS,通过 IMU 反馈实现角度闭环,通过串口接收上位机指令实现视觉追踪。项目源自 HNU YueLu EC RoboMaster 项目,经重构精简为纯云台控制。
---
## 一、硬件与通信
| 资源 | 用途 |
|------|------|
| **FDCAN1** | 电机控制总线 (DM-G6220 yaw, DM-J4310-2EC pitch) |
| **USART10** | 上位机通信 (master_machine 协议) |
| **USART7** | VoFA 调试输出 |
| **USART1** | 板间通信 (BoardComm) |
| **SPI2** | BMI088 IMU 传感器 |
---
## 二、分层架构
```
┌──────────────────────────────────────────────┐
│ application/ 应用层 │
│ robot.c → robot_cmd → gimbal │
├──────────────────────────────────────────────┤
│ modules/ 模块层 │
│ motor, imu, master_machine, algorithm, ... │
├──────────────────────────────────────────────┤
│ bsp/ 板级支持包 │
│ can, usart, spi, dwt, log, gpio │
├──────────────────────────────────────────────┤
│ Drivers/ HAL 驱动层 (CubeMX 生成) │
│ STM32H7xx_HAL, CMSIS, FreeRTOS │
└──────────────────────────────────────────────┘
```
---
## 三、启动流程
```
main()
├── HAL_Init() → SystemClock_Config() → MX_*_Init() // CubeMX 外设初始化
└── RobotInit()
├── BSPInit() // DWT + Log
├── RobotCMDInit() // pub-sub, 视觉PID, 串口初始化
├── GimbalInit() // IMU + DM 电机初始化
└── OSTaskInit() // 创建 4 个 RTOS 任务
```
### FreeRTOS 任务
| 任务 | 频率 | 优先级 | 功能 |
|------|------|--------|------|
| **INS Task** | 1kHz | AboveNormal | BMI088 读取 → 四元数 EKF 姿态解算 |
| **Motor Task** | 1kHz | Normal | DM 电机角度 PID → CAN 速度指令发送 |
| **Robot Task** | 500Hz | Normal | 上位机命令处理 + 模式切换 + 控制执行 |
| **Daemon Task** | 100Hz | Normal | 模块看门狗 + 蜂鸣器 |
---
## 四、PID 双环架构
```
┌──────────────────────────────────────────────────────┐
│ application/cmd/robot_cmd.c (外环, 500Hz) │
│ │
│ 上位机 0xA5 帧 → error_x/y → KF → vision PID │
│ → 角度增量 → 累计 angle ref │
│ 上位机 0xA6 帧 → yaw_ref/pitch_ref 直接设定 │
│ │
│ ProcessCommand() 处理模式切换 / 激光控制 │
└──────────────────────┬───────────────────────────────┘
│ gimbal_cmd (pub-sub)
▼
┌──────────────────────────────────────────────────────┐
│ application/gimbal/gimbal.c (传递, 500Hz) │
│ │
│ DMMotorSetRef(yaw, cmd.yaw) │
│ DMMotorSetRef(pitch, cmd.pitch) │
│ 反馈: gimbal_feed → gimbal_IMU_data 指针 │
└──────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ modules/motor/DMmotor/ (内环, 1kHz) │
│ │
│ IMU 角度反馈 → angle PID → velocity output │
│ → DMMotorSendVelocity() → CAN 速度模式 │
│ output_reverse 控制输出方向 │
└──────────────────────────────────────────────────────┘
```
---
## 五、上位机串口协议
位于 `modules/master_machine/`。三种帧类型,通过帧头区分。
### 自动/视觉追踪数据帧 `0xA5` (10 字节)
| 字节 | 0 | 1-4 | 5-8 | 9 |
|------|---|-----|-----|---|
| 内容 | 0xA5 | error_x (float) | error_y (float) | checksum |
### 手动控制数据帧 `0xA6` (11 字节)
| 字节 | 0 | 1 | 2-5 | 6-9 | 10 |
|------|---|-----|-----|-----|----|
| 内容 | 0xA6 | zero_force | yaw_ref (float) | pitch_ref (float) | checksum |
### 命令帧 `0xA7` (3 字节)
| 字节 | 0 | 1 | 2 |
|------|---|-----|----|
| 内容 | 0xA7 | cmd | checksum |
命令码:`0x01` 切换到自动模式, `0x02` 切换到手动模式, `0x03` 激光开, `0x04` 激光关
### 数据流
```
上位机 USART10 → DecodeVision() → vision_data (全局结构体)
├── 0xA5 → auto_updated=1, error_x/y
├── 0xA6 → manual_updated=1, zero_force, yaw_ref/pitch_ref
└── 0xA7 → cmd_pending=1, cmd
robot_cmd 每轮:
ProcessCommand() → 模式切换 / 激光
AUTO: vision_data.error_x/y → KF → vision PID → 角度增量
MANUAL: vision_data.yaw_ref/pitch_ref → 直接设定
PubPushMessage(gimbal_cmd) → gimbal 执行
```
---
## 六、DM 电机驱动
位于 `modules/motor/DMmotor/`。基于 DM_6220 参考协议。
### 速度模式 (当前默认)
CAN ID = motor_id + 0x200,发送 float velocity (4 bytes)。
```
DMMotorControl() @ 1kHz:
PIDCalculate(angle_PID, IMU_angle, pid_ref) → velocity
output_reverse? → DMMotorSendVelocity() → CAN
```
### 电机配置
| 电机 | CAN ID | 反馈 ID | 模式 | MIT KP/KD |
|------|--------|---------|------|-----------|
| DM-G6220 (Yaw) | 0x01 | 0xF1 | Velocity | — |
| DM-J4310-2EC (Pitch) | 0x02 | 0xF2 | Velocity | — |
### API
| 函数 | 说明 |
|------|------|
| `DMMotorInit()` | 初始化电机实例 (CAN 注册, PID 初始化, daemon) |
| `DMMotorSetRef()` | 设定角度参考值 (degrees) |
| `DMMotorControl()` | 1kHz 控制循环 (所有电机) |
| `DMMotorSetMode()` | 发送命令 (使能/停止/清零/清除错误) |
| `DMMotorSendVelocity()` | 速度模式 CAN 发送 |
| `DMMotorSendMIT()` | MIT 模式 CAN 发送 |
| `DMMotorSendPosVel()` | 位置-速度模式 CAN 发送 |
---
## 七、模块层
| 分类 | 模块 | 功能 |
|------|------|------|
| **电机** | `motor/DMmotor` | 达妙电机驱动 (MIT/PosVel/Velocity 三模式) |
| | `motor/motor_task` | 电机控制统一调度 (`DMMotorControl`) |
| **姿态** | `imu/ins_task` | 惯导解算 (四元数 EKF, 返回 INS_t 指针) |
| | `imu/BMI088driver` | BMI088 SPI 读取 |
| | `imu/BMI088Middleware` | BMI088 数据换算 |
| **算法** | `algorithm/controller` | PID 控制器 (梯形积分/变速积分/微分先行/输出滤波) |
| | `algorithm/kalman_filter` | 卡尔曼滤波器 (自适应) |
| | `algorithm/QuaternionEKF` | 四元数 EKF (陀螺零偏估计/卡方检验) |
| | `algorithm/crc8/crc16` | CRC 校验 |
| | `algorithm/user_lib` | 数学/工具函数 |
| **通信** | `master_machine` | 上位机通信 (0xA5/0xA6/0xA7 协议, 接收+解析) |
| | `timachine/board_comm` | 板间通信 |
| | `message_center` | Pub-Sub 消息中间件 (链表, FIFO) |
| **系统** | `daemon` | 看门狗 (重载计数+离线回调) |
| | `alarm/buzzer` | 蜂鸣器 |
| | `vofa` | VoFA+ 调试输出 |
---
## 八、BSP 驱动层
实例化注册模式 (不注册不初始化):
| 模块 | 功能 |
|------|------|
| `bsp_dwt` | DWT 周期计数器 (μs/ms 延时, 时间戳) |
| `bsp_can` | FDCAN 收发 (FIFO+中断) |
| `bsp_usart` | 串口收发 (DMA+环形缓冲区) |
| `bsp_spi` | SPI 通信 |
| `bsp_log` | SEGGER RTT + 串口日志 |
| `bsp_pwm` | PWM 输出 |
---
## 九、数据流
```
┌──────────────┐
│ 上位机 │
│ (USART10) │
└──────┬───────┘
│ 0xA5 / 0xA6 / 0xA7
▼
┌────────────────────────┐
│ RobotCMD │
│ ProcessCommand() │ ← 模式切换/激光
│ VisionTrackingSet() │ ← KF → vision PID → 角度增量
│ ManualModeSet() │ ← 直接角度参考
│ PubPushMessage() │
└───────────┬────────────┘
│ gimbal_cmd
▼
┌────────────────────────┐
│ Gimbal │
│ DMMotorSetRef() │
│ 反馈: gimbal_feed │ ← INS_t* 指针
└───────────┬────────────┘
│ angle ref
▼
┌────────────────────────┐
│ DMMotor │ (1kHz Motor Task)
│ IMU angle → PID │
│ → Velocity mode CAN │
└────────────────────────┘
│
┌───────────┴────────────┐
│ DM-G6220 DM-J4310 │
│ (Yaw) (Pitch) │
└────────────────────────┘
```
---
## 十、关键设计
1. **IMU 反馈替代编码器** — 云台 Yaw/Pitch 使用 INS_t 中的 YawTotalAngle/Pitch 和 Gyro[]
2. **速度模式控制** — MCU 跑角度 PID,电机内部处理速度闭环
3. **伪 Pub-Sub** — 应用间通过 message_center 解耦
4. **Daemon 看门狗** — 每个外设模块独立 DaemonInstance,离线自动回调
5. **BSP 实例化注册** — CAN/串口不注册不初始化
6. **KF + PID 级联** — 视觉误差经 KF 平滑 → vision PID → 角度增量 → 内环角度 PID
7. **模式切换重置** — 切换到自动模式时重置 KF 状态 (x=0, P=diag(5,5)) 和 PID 积分项
8. **串口命令控制** — 模式切换、激光控制均通过 0xA7 命令帧触发
9. **output_reverse** — PID 输出方向统一通过单标志位控制
---
## 十一、项目规模
| 类别 | 数量 |
|------|------|
| C 源文件 | 96 |
| ASM 源文件 | 2 |
| 应用层模块 | 3 (robot, robot_cmd, gimbal) |
| 模块层子模块 | 10 (motor, imu, algorithm, master_machine, message_center, daemon, buzzer, vofa, board_comm) |
| BSP 驱动模块 | 8 |
| FreeRTOS 任务 | 4 |
| 最高控制频率 | 1kHz |
| CPU 频率 | 480MHz |
| FLASH 使用 | ~133 KB / 1 MB (13%) |
| DTCMRAM 使用 | ~59 KB / 128 KB (46%) |
---
## 十二、核心数据类型
```c
// INS 惯导实例 (ins_task.h)
typedef struct {
float q[4]; // 四元数
float Gyro[3]; // 角速度 (rad/s)
float Accel[3]; // 加速度 (m/s²)
float Roll, Pitch, Yaw;
float YawTotalAngle; // 多圈 yaw (degrees)
} INS_t;
// 云台控制指令 (robot_def.h)
typedef struct {
float yaw; // yaw 目标角度 (degrees)
float pitch; // pitch 目标角度 (degrees)
} Gimbal_Ctrl_Cmd_s;
// 上位机数据 (master_machine.h)
typedef struct {
float error_x, error_y; // 自动模式: 归一化误差
uint8_t auto_updated;
uint8_t zero_force; // 手动模式: 零力标志
float yaw_ref, pitch_ref; // 手动模式: 角度参考
uint8_t manual_updated;
uint8_t cmd, cmd_pending; // 命令
float frequency;
} VisionData_t;
```