15 KiB
15 KiB
项目架构分析报告:Basic_Framework_MC02 (RoboMaster 云台机器人)
概览
这是一个基于 STM32H723 (Cortex-M7) 的 RoboMaster 竞赛机器人控制项目。项目采用 FreeRTOS 实时操作系统,目前配置为单板控制整车(ONE_BOARD 模式),代码组织呈分层架构。项目由 湖南大学岳麓电气 (HNU YueLu EC) 开发。
一、硬件与通信总览
| 资源 | 用途 |
|---|---|
| FDCAN1/2/3 | 电机控制总线(DJI 电机、达妙电机等) |
| USART1 | 板间通信 (BoardComm) |
| USART5 | 遥控器 (DBUS/DR16) |
| USART7 | VoFA 调试输出 |
| USART10 | 视觉/上位机 (OpenCV 通信) |
| SPI1/2 | BMI088 IMU 传感器、OLED |
| I2C2 | 通用 I2C |
| OCTOSPI2 | 外部 Flash (W25Qxx) |
| TIM1/2/3/12 | PWM 输出、编码器输入、DWT 时钟基准 |
| USB Device | 虚拟串口 (CDC) |
| ADC1 | 模拟量采集 |
| GPIO | 电源控制、激光器等 |
二、分层架构
项目采用 4 层架构:
┌──────────────────────────────────────────────────────────┐
│ application/ 应用层 │
│ robot.c → robot_cmd → gimbal / chassis / shoot │
├──────────────────────────────────────────────────────────┤
│ modules/ 模块层 │
│ motor, imu, referee, remote, vision, algorithm, ... │
├──────────────────────────────────────────────────────────┤
│ bsp/ 板级支持包 │
│ can, usart, spi, iic, pwm, dwt, log, gpio │
├──────────────────────────────────────────────────────────┤
│ Drivers/ HAL 驱动层 (CubeMX 生成) │
│ STM32H7xx_HAL, CMSIS, FreeRTOS, USB, SEGGER RTT │
└──────────────────────────────────────────────────────────┘
三、启动与初始化流程
3.1 main() 启动序列
HAL_Init() → SystemClock_Config() → MX_GPIO_Init() → MX_DMA_Init()
→ MX_ADC1_Init() → MX_USB_DEVICE_Init() → MX_TIM/SPI/USART/UART/FDCAN/..._Init()
→ RobotInit() ← 唯一的用户初始化入口
→ while(1) {} ← 空循环,所有逻辑在 RTOS 任务中
3.2 RobotInit() 初始化链
RobotInit()
├── __disable_irq() // 关中断,保证初始化原子性
├── BSPInit()
│ ├── DWT_Init(480) // 时钟周期计数器 (CPU=480MHz)
│ └── BSPLogInit() // 日志系统(SEGGER RTT + 串口)
├── RobotCMDInit() // 核心命令任务初始化
│ ├── RemoteControlInit(&huart5) // 遥控器 (DBUS)
│ ├── PubRegister() x6 // 注册 6 个消息话题:
│ │ gimbal_cmd / gimbal_feed // 云台控制/反馈
│ │ shoot_cmd / shoot_feed // 发射控制/反馈
│ │ chassis_cmd / chassis_feed // 底盘控制/反馈
│ ├── PIDInit() x2 (yaw + pitch 跟踪PID) // 视觉跟踪 PID 初始化
│ ├── VisionKalmanFilterInit() // 视觉误差卡尔曼滤波器
│ ├── Vision_Uart_Init(&huart10) // 视觉串口通信
│ └── BoardCommInit(&huart1) // 板间通信
├── GimbalInit() // 云台电机初始化
│ ├── INS_Init() → BMI088 SPI 初始化 // IMU 惯导
│ ├── PubRegister("gimbal_feed") / SubRegister("gimbal_cmd")
│ ├── DJIMotorInit(GM6020) → yaw 电机 // Yaw: GM6020 直驱
│ └── DMMotorInit() → pitch 电机 // Pitch: 达妙电机
├── OSTaskInit() // 创建 RTOS 任务
│ ├── INS Task (1kHz, AboveNormal) // 姿态解算最高优先级
│ ├── Motor Task (1kHz, Normal) // 电机控制
│ ├── Daemon Task (100Hz, Normal) // 看门狗/蜂鸣器
│ ├── Robot Task (500Hz, Normal) // 机器人核心控制
│ └── DMMotorControlInit() // 达妙大电机初始化
└── __enable_irq() // 开中断
四、FreeRTOS 任务架构
| 任务 | 频率 | 优先级 | 功能 |
|---|---|---|---|
| INS Task | 1kHz | AboveNormal | 阻塞读取 BMI088,进行四元数 EKF 姿态解算 |
| Motor Task | 1kHz | Normal | DJI/LK/HT 电机 PID 闭环计算与 CAN 发送 |
| Robot Task | 500Hz | Normal | 调用 RobotTask() 串联各应用层任务 |
| Daemon Task | 100Hz | Normal | 模块看门狗喂狗检查 + 蜂鸣器控制 |
五、消息中心 (Pub-Sub)
位于 modules/message_center/,这是应用层内部的核心通信机制:
- 发布者 (Publisher):以话题名 (topic name) 标识,通过链表管理订阅者
- 订阅者 (Subscriber):每个订阅者维护一个长度为 1 的 FIFO 队列
- 支持最多 12 个话题,话题名最长 32 字符
当前消息流:
robot_cmd (CMD) ──→ gimbal_cmd ──→ gimbal 应用
├── chassis_cmd → chassis 应用
└── shoot_cmd ──→ shoot 应用
gimbal ──→ gimbal_feed ──→ robot_cmd (CMD)
chassis ──→ chassis_feed ──→ robot_cmd (CMD)
shoot ──→ shoot_feed ──→ robot_cmd (CMD)
六、应用层模块
6.1 RobotCMD (application/cmd/) — 机器人大脑
核心决策模块,集成以下功能:
| 功能 | 说明 |
|---|---|
| 遥控器解析 | DBUS 协议,摇杆/开关/键鼠 |
| 视觉跟踪 | OpenCV 视觉数据 → 卡尔曼滤波 → PID 跟踪 → 云台角度控制 |
| 画圆模式 | 遥控器拨轮控制画圆轨迹跟踪 |
| 题号状态机 | 竞赛自动任务状态机,支持 6 种题号,含转向/搜索/跟踪子状态 |
| 急停处理 | 遥控器右侧开关拨下 → 所有电机零力输出 |
| 激光控制 | GPIO 控制激光笔开关 |
RobotCMDTask() 执行流程(500Hz):
读取底盘/发射/云台反馈消息 → 判断控制模式(手动/自动/视觉)
→ EmergencyHandler(急停检测) → 推送控制消息给各应用
题号状态机 (YunTaiState):
YUNT_IDLE
→ NO1: 零力模式
→ NO2: 视觉跟踪 + 激光 (等待1.5s后开启激光)
→ NO3: 转向0度 → 视觉跟踪/搜索 → 激光 (3.5s后)
→ NO4_1: 转向-45度 → 视觉跟踪 + 前馈
→ NO4_3: 转向-45度 → 视觉跟踪 (error=60) + 画圆前馈
6.2 Gimbal (application/gimbal/) — 云台控制
- Yaw 轴:GM6020 (DJI 直驱电机),CAN1 ID=0x01,IMU 反馈替代电机编码器
- Pitch 轴:达妙电机 (DM Motor),CAN1 ID=0x06/0x16,IMU 反馈
- 控制模式:
GIMBAL_ZERO_FORCE:零力GIMBAL_GYRO_MODE:陀螺仪姿态闭环 (使用 IMU Pitch + YawTotalAngle)
- 特点:角度/角速度反馈均来自 IMU(替代电机编码器),带有速度和电流前馈
6.3 Chassis (application/chassis/) — 底盘控制
- 麦克纳姆轮底盘 (Mecanum),4x GM6020 电机
- 运动学解算:正逆运动学,云台→底盘坐标系变换
- 支持裁判系统功率限制和超级电容管理
6.4 Shoot (application/shoot/) — 发射控制
- 摩擦轮:2x M3508 (CAN2 ID=1,2),速度串联电流闭环
- 拨盘电机:M2006 (CAN2 ID=3),多模式:
LOAD_STOP:停止LOAD_1_BULLET:单发(角度闭环,加减角度 = ONE_BULLET_DELTA_ANGLE)LOAD_3_BULLET:三连发LOAD_BURSTFIRE:连发(速度闭环,可调射频)LOAD_REVERSE:反转
- 弹速模式:15m/s / 18m/s / 30m/s
- 弹舱盖开关控制
七、模块层 (modules/)
| 分类 | 模块 | 功能 |
|---|---|---|
| 电机 | dji_motor |
DJI GM6020/M3508/M2006 标准电机驱动,串级 PID (角度→速度→电流) |
DMMotor |
达妙电机 (DM Motor) 驱动 | |
LKmotor (LK9025) |
LK 电机驱动 | |
HTmotor (HT04) |
HT04 电机驱动 | |
step_motor |
步进电机 (含 X_V2 变体) | |
servo_motor |
舵机控制 | |
motor_task |
电机控制统一调度 (MotorControlTask) |
|
| 姿态 | imu/ins_task |
惯导解算:四元数 EKF,BMI088 传感器 |
imu/BMI088driver |
BMI088 SPI 底层读取 | |
imu/BMI088Middleware |
BMI088 数据换算 | |
| 算法 | controller |
通用 PID 控制器(支持变积分、梯形积分、微分先行、输出滤波等改进) |
kalman_filter |
标准卡尔曼滤波器 + 自适应 (UseAutoAdjustment) |
|
QuaternionEKF |
四元数扩展卡尔曼滤波 | |
crc8/crc16 |
CRC 校验 | |
user_lib |
通用数学/工具函数 | |
| 通信 | remote/remote_control |
DJI DBUS 遥控器解析 (位域优化) |
master_machine |
视觉上位机通信 (SeaSky 协议) | |
referee |
裁判系统 (RM Referee Protocol, UI 绘制) | |
can_comm |
CAN 通信抽象层(双板情况下的数据转发) | |
board_comm |
板间通信(固定帧格式: 帧头 + 2x int32 + 2x float + 校验) | |
bluetooth/HC05 |
HC05 蓝牙模块 | |
opencv |
OpenCV 视觉数据处理 | |
| 辅助 | message_center |
Pub-Sub 消息中间件(伪发布订阅,仅做应用间隔离) |
daemon |
看门狗守护进程(在线检测 + 异常回调) | |
alarm/buzzer |
蜂鸣器告警 | |
vofa |
调试数据可视化 (VoFA+ FireWater) | |
oled |
OLED 显示屏 | |
super_cap |
超级电容管理 |
八、BSP 驱动层
所有 BSP 驱动采用实例化注册模式(不注册不初始化):
| 模块 | 功能 |
|---|---|
bsp_dwt |
DWT 时钟周期计数器(精确延时 μs/ms,时间戳获取) |
bsp_can |
CAN 总线收发封装(FIFO+中断,实例化注册) |
bsp_usart |
串口收发封装(DMA+环形缓冲区,实例化注册) |
bsp_spi |
SPI 通信封装 |
bsp_iic |
I2C 通信封装 |
bsp_pwm |
PWM 输出(支持 DMA 传输) |
bsp_gpio |
GPIO 管理 |
bsp_log |
SEGGER RTT + 串口日志输出(LOGINFO/LOGERROR/LOGWARNING) |
bsp_tools |
RTOS 任务创建工具 (CreateCallbackTask) |
九、数据流与控制流总结
┌─────────────┐
│ 遥控器DBUS │
│ (USART5) │
└──────┬──────┘
↓
┌────────────────────────┐
│ RobotCMD │
│ ┌─────────────────┐ │
│ │ RemoteControlSet│ │ ← 手动模式 (遥控器调试)
│ │ AutoSet (题号) │ │ ← 自动模式 (竞赛任务)
│ └───────┬─────────┘ │
│ ↓ │
│ 发布: gimbal_cmd │──→ Gimbal (云台 PID → IMU 反馈)
│ chassis_cmd │──→ Chassis (运动学 → 麦轮)
│ shoot_cmd │──→ Shoot (摩擦轮/拨盘)
└────────────────────────┘
↑
┌────────────┴───────────┐
│ 反馈: gimbal_feed │ ← 云台姿态 + 电机角度
│ chassis_feed │ ← 底盘速度 + 热量
│ shoot_feed │ ← 发射状态
└────────────────────────┘
视觉/OpenCV (USART10) ──→ 卡尔曼滤波 ──→ PID ──→ 云台角度控制
板间通信 (USART1) ──→ BoardComm ──→ 题号/坐标数据
裁判系统 ──→ 热量/弹速/UI 绘制
十、关键设计特点
- IMU 替代电机反馈:云台 Yaw/Pitch 使用陀螺仪角度/角速度替代编码器,实现更高精度姿态闭环
- 伪 Pub-Sub 模式:应用间通过
message_center解耦,支持单板/双板条件编译切换(ONE_BOARD/GIMBAL_BOARD/CHASSIS_BOARD) - Daemon 看门狗:每个外设模块注册独立的
DaemonInstance(重载计数 + 离线回调),模块离线时自动触发异常处理 - BSP 实例化注册:CAN/串口等外设不注册不初始化,避免资源浪费
- 竞赛状态机:完整的题号自动任务流程(转向→搜索→跟踪→激光打击)
- 卡尔曼滤波 + PID 级联:视觉误差经过 KF 平滑后由 PID 计算输出,带前馈补偿
- 位域优化:遥控器键盘状态使用位域 (
Key_t),空间减少 8 倍 - 条件编译:单板/双板/电机类型/视觉通信方式均通过宏定义切换
十一、项目规模统计
| 类别 | 数量 |
|---|---|
| C 源文件 | 115 个 |
| ASM 源文件 | 2 个 |
| 应用层模块 | 4 (robot_cmd, gimbal, chassis, shoot) |
| 模块层子模块 | 20+ (电机×6, 姿态×3, 算法×5, 通信×7, 辅助×5) |
| BSP 驱动模块 | 10 |
| FreeRTOS 任务 | 4 (默认) |
| 最高控制频率 | 1kHz |
| CPU 频率 | 480MHz (PLL = HSE 8MHz / 2 × 40 / 2) |
| FLASH 使用 | 161,556 B / 1 MB (15.41%) |
| DTCMRAM 使用 | 60,920 B / 128 KB (46.48%) |
十二、电机配置速查
| 电机 | 类型 | CAN 总线 | TX ID | 控制闭环 | PID 级联 |
|---|---|---|---|---|---|
| Yaw (云台) | GM6020 | CAN1 | 0x01 | 角度+速度 | Angle → Speed (IMU 反馈) |
| Pitch (云台) | DM Motor | CAN1 | 0x06/0x16 | 角度+速度 | Angle → Speed (IMU 反馈) |
| 摩擦轮 左 | M3508 | CAN2 | 0x01 | 速度+电流 | Speed → Current |
| 摩擦轮 右 | M3508 | CAN2 | 0x02 | 速度+电流 | Speed → Current (反转) |
| 拨盘 | M2006 | CAN2 | 0x03 | 角度/速度+电流 | Angle/Speed → Current |
十三、关键配置宏 (robot_def.h)
#define ONE_BOARD // 单板控制整车
#define VISION_USE_UART // 使用串口发送视觉数据
#define YAW_CHASSIS_ALIGN_ECD 2711 // 云台底盘对齐编码器值
#define PITCH_HORIZON_ECD 3412 // 云台水平位置编码器值
#define ONE_BULLET_DELTA_ANGLE 36 // 单发弹丸拨盘转动角度
#define WHEEL_BASE 350 // 纵向轴距 (mm)
#define TRACK_WIDTH 300 // 横向轮距 (mm)
#define RADIUS_WHEEL 60 // 轮子半径 (mm)