e1a01e6b5359df8a9b808d00c7bc0cfb1528d653
- host 0xA9 frame → master_machine decode → robot_cmd publish via gimbal_feedforward topic → gimbal subscribe → yaw_motor.feed_input - add DM_Feedforward_Controller_s with Kp and feed_input fields - add feedforward term (Kp * feed_input) to motor control output - add DM_Feedforward_Kp to motor init config
项目架构: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) │
│ │
│ AUTO: 上位机 0xA5 帧 → measure_x/y, ref_x/y → KF → vision PID│
│ → 角度增量 → 累计 angle ref │
│ MANUAL: 上位机 0xA6 帧 → yaw/pitch 角速度 → 角度增量积分 │
│ DEBUG: 上位机 0xA8 帧 → 实时更新 PID 参数 │
│ │
│ ProcessCommand() 处理模式切换 / 激光控制 │
└──────────────────────┬───────────────────────────────┘
│ gimbal_cmd (pub-sub)
▼
┌──────────────────────────────────────────────────────┐
│ application/gimbal/gimbal.c (传递, 500Hz) │
│ │
│ DMMotorSetRef(yaw, cmd.yaw) │
│ DMMotorSetRef(pitch, cmd.pitch) │
│ 电机使能/失能订阅: motor_enable │
│ 电机角 PID 调参订阅: motor_pid │
│ 反馈: gimbal_feed → gimbal_IMU_data 指针 │
└──────────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ modules/motor/DMmotor/ (内环, 1kHz) │
│ │
│ IMU 角度反馈 → angle PID → velocity output │
│ → DMMotorSendVelocity() → CAN 速度模式 │
│ DISABLE 时自动清零 PID + 发送零速指令 │
│ output_reverse 控制输出方向 │
└──────────────────────────────────────────────────────┘
五、上位机串口协议
位于 modules/master_machine/。四种帧类型,通过帧头区分。详细说明见 docs/host_comm_guide.md。
帧类型总览
| 帧头 | 长度 | 用途 |
|---|---|---|
| 0xA5 | 18 | 自动/视觉追踪数据帧 (measure_x, ref_x, measure_y, ref_y) |
| 0xA6 | 10 | 手动控制数据帧 (yaw_velocity, pitch_velocity) |
| 0xA7 | 3 | 命令帧 (模式切换, 激光) |
| 0xA8 | 50 | 调试调参帧 (12 个 float PID 参数) |
命令码
| cmd | 含义 |
|---|---|
| 0x01 | 切换到自动/视觉追踪模式 |
| 0x02 | 切换到手动模式 |
| 0x03 | 激光开 |
| 0x04 | 激光关 |
| 0x05 | 切换到调试模式 |
工作模式
| 模式 | 值 | 说明 |
|---|---|---|
| AUTO | 0 | 视觉测量值 → KF → vision PID(measure, ref) → 角度增量 |
| MANUAL | 1 | 上位机下发角速度,固件积分累加角度参考 |
| DEBUG | 2 | 失能电机,接收 PID 参数实时调参 |
数据流
上位机 USART10 → DecodeVision() → vision_data (全局结构体)
├── 0xA5 → auto_updated=1, measure_x/y, ref_x/y
├── 0xA6 → manual_updated=1, yaw/pitch velocity
├── 0xA7 → cmd_pending=1, cmd
└── 0xA8 → debug_updated=1, 12 个 PID 参数
robot_cmd 每轮:
ProcessCommand() → 模式切换 / 激光
AUTO: vision_data.measure_x/y → KF → vision PID(measure, ref) → 角度增量
MANUAL: vision_data.yaw/pitch velocity → 角度增量积分
DEBUG: vision_data PID 参数 → 直接写入 vision PID, 发布 motor_pid 话题
PubPushMessage(gimbal_cmd) → gimbal 执行
六、Pub-Sub 话题
| 话题名 | 发布者 | 订阅者 | 数据类型 |
|---|---|---|---|
gimbal_cmd |
robot_cmd | gimbal | Gimbal_Ctrl_Cmd_s (yaw, pitch) |
gimbal_feed |
gimbal | robot_cmd | Gimbal_Upload_Data_s (INS 指针) |
motor_enable |
robot_cmd | gimbal | Motor_Enable_s (enable: 0/1) |
motor_pid |
robot_cmd | gimbal | Motor_PID_Tune_s (yaw/pitch Kp,Ki,Kd) |
七、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() |
发送命令 (使能/停止/清零/清除错误), DISABLE 时自动清零 PID+零速 |
DMMotorSendVelocity() |
速度模式 CAN 发送 |
DMMotorSendMIT() |
MIT 模式 CAN 发送 |
DMMotorSendPosVel() |
位置-速度模式 CAN 发送 |
DISABLE 保护
调用 DMMotorSetMode(DM_CMD_DISABLE_MODE, motor) 时:
- 先发送零速指令 (
DMMotorSendVelocity(can, 0.0f)) 让电机停止转动 - 清理 angle_PID 全部状态 (积分/微分/误差)
- 清零 pid_ref
- 发送失能 CAN 命令 (0xFD)
防止切回 ENABLE 时因 PID 残余积分项或位置跳变导致的突变。
八、模块层
| 分类 | 模块 | 功能 |
|---|---|---|
| 电机 | 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/0xA8 协议, 接收+解析) |
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 / 0xA8
▼
┌────────────────────────┐
│ RobotCMD │
│ ProcessCommand() │ ← 模式切换/激光
│ VisionTracking() │ ← KF → vision PID → 角度增量
│ ManualMode() │ ← 角速度积分
│ DebugMode() │ ← 实时 PID 调参
│ PubPushMessage() │
└───────┬───────┬────────┘
│ gimbal_cmd │ motor_pid / motor_enable
▼ ▼
┌────────────────────────────┐
│ Gimbal │
│ DMMotorSetRef() │
│ 电机使能/失能控制 │
│ 电机角 PID 在线更新 │
│ 反馈: gimbal_feed │ ← INS_t* 指针
└───────────┬────────────────┘
│ angle ref
▼
┌────────────────────────┐
│ DMMotor │ (1kHz Motor Task)
│ IMU angle → PID │
│ → Velocity mode CAN │
└────────────────────────┘
│
┌───────────┴────────────┐
│ DM-G6220 DM-J4310 │
│ (Yaw) (Pitch) │
└────────────────────────┘
十一、关键设计
- IMU 反馈替代编码器 — 云台 Yaw/Pitch 使用 INS_t 中的 YawTotalAngle/Pitch 和 Gyro[]
- 速度模式控制 — MCU 跑角度 PID,电机内部处理速度闭环
- 伪 Pub-Sub — 应用间通过 message_center 解耦
- Daemon 看门狗 — 每个外设模块独立 DaemonInstance,离线自动回调
- BSP 实例化注册 — CAN/串口不注册不初始化
- KF + PID 级联 — 视觉测量值经 KF 平滑 → vision PID(measure, ref) → 角度增量 → 内环角度 PID
- 模式切换重置 — 切换到自动模式时重置 KF 状态 (x=0, P=diag(5,5)) 和 PID 积分项
- 串口命令控制 — 模式切换、激光控制均通过 0xA7 命令帧触发
- output_reverse — PID 输出方向统一通过单标志位控制
- 调试模式 — 上位机可实时调整视觉环和电机角度环 PID 参数,无需重新编译
- DISABLE 保护 — 电机失能时自动发送零速指令并清理 PID,防止切回使能时突变
十二、核心数据类型
// 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 measure_x, ref_x, measure_y, ref_y; // 自动模式: 测量值和参考值
uint8_t auto_updated;
float yaw_degree_velocity, pitch_degree_velocity; // 手动模式: 角速度
uint8_t manual_updated;
// 调试模式数据
float vision_yaw_Kp, vision_yaw_Ki, vision_yaw_Kd;
float vision_pitch_Kp, vision_pitch_Ki, vision_pitch_Kd;
float motor_yaw_Kp, motor_yaw_Ki, motor_yaw_Kd;
float motor_pitch_Kp, motor_pitch_Ki, motor_pitch_Kd;
uint8_t debug_updated;
uint8_t cmd, cmd_pending; // 命令
float frequency;
} VisionData_t;
十三、项目规模
| 类别 | 数量 |
|---|---|
| C 源文件 | ~96 |
| 应用层模块 | 3 (robot, robot_cmd, gimbal) |
| 模块层子模块 | 12 |
| BSP 驱动模块 | 8 |
| FreeRTOS 任务 | 4 |
| Pub-Sub 话题 | 4 |
| 最高控制频率 | 1kHz |
| CPU 频率 | 480MHz |
| FLASH 使用 | ~132 KB / 1 MB (13%) |
| DTCMRAM 使用 | ~44 KB / 128 KB (34%) |
Description
Languages
C
97.7%
Assembly
1.8%
C++
0.2%
CMake
0.2%