2025 电赛 E 题「简易自行瞄准装置」全流程复盘:STM32F103RCT6 + K230 + 双轴无刷云台 + 陀螺仪前馈
关键词:
2025电赛E题简易自行瞄准装置STM32F103RCT6K230视觉无刷云台PID陀螺仪前馈
适用人群:备赛 / 复盘 / 想快速搭一套“视觉闭环瞄准”系统的同学
主控工程:基于 STM32F103RCT6 标准库(Keil)
一、题目在考什么?先把需求拆开
2025 年 TI 杯全国大学生电子设计竞赛E 题:简易自行瞄准装置,本质是一道“视觉感知 + 两轴运动控制 + 实时闭环”的系统题。
把赛题抽象成工程语言,大致就是:
| 能力项 | 工程含义 |
|---|---|
| 识别目标 | 摄像头/视觉模组给出目标在图像中的坐标 |
| 指示落点 | 激光点也要能被识别,作为“当前瞄准点” |
| 二维瞄准 | 水平轴 + 俯仰轴联动,把激光点压到目标上 |
| 动态跟踪 | 目标移动时,系统仍能持续对准 |
| 可调可测 | 参数可改、状态可看,方便赛场调试 |
核心控制问题只有一句话:
让图像里的“激光点 (laser)”不断逼近“目标点 (target)”
这和传统“把电机转到某角度”不同——你控制的是图像坐标系里的误差,电机只是执行器。
二、总体方案:我们选了什么,为什么
2.1 硬件架构
┌─────────────┐ 目标/激光画面 → │ K230 视觉 │──USART1(115200)──┐ └─────────────┘ │ ▼ ┌──────────────┐ USART3(115200) ┌──────────────────────────┐ │ 单轴陀螺仪 │ ─────────────────► │ STM32F103RCT6 │ └──────────────┘ │ 视觉PID + 陀螺前馈 │ │ TIM3: 20ms 控制周期 │ ┌──────────────┐ UART4(9600) │ │ │ USB-TTL调参 │ ◄────────────────► │ 遥测/在线改 PID 参数 │ └──────────────┘ └────────────┬─────────────┘ │ USART2 115200 ┌────────────┴────────────┐ │ 串口协议无刷驱动器 │ │ Motor1(水平) Motor2(俯仰)│ └─────────────────────────┘2.2 选型理由(电赛场景更在意“稳、快、可调”)
| 模块 | 选型 | 理由 |
|---|---|---|
| 主控 | STM32F103RCT6 | 外设多(4 路串口很香)、资料多、调试成熟 |
| 视觉 | K230 | 算力够用,识别目标/激光后只发坐标,减轻 MCU 负担 |
| 执行 | 双轴无刷云台(串口协议型) | 驱动器内置换相/闭环,MCU 发速度指令即可 |
| 姿态 | 单轴 MEMS 陀螺仪 | 给水平轴做角速度前馈,改善“追不上/晃”的问题 |
| 人机 | OLED / 按键(可选)+ UART4 调参 | 赛场最快的调参方式是串口一行指令 |
2.3 控制策略总览(方案 A)
本工程采用:
[
v_x = \mathrm{PID}x(target_x, laser_x) + K{ff}\cdot S\cdot (-\omega_z)
]
[
v_y = \mathrm{PID}_y(target_y, laser_y)
]
- 视觉位置环:激光点当反馈,目标点当设定
- 陀螺角速度前馈:主要补偿水平方向上的扰动/机架旋转
- 速度模式驱动无刷:控制量直接是电机目标速度,响应比“位置层层嵌套”更直接
一句话总结:
闭环靠视觉,动态靠前馈,执行靠速度模式无刷。
三、软件工程结构(RCT6 工程怎么拆)
推荐按“硬件驱动 + 算法 + 应用”分层,本工程大致如下:
rct6_E/ ├─ User/ │ └─ main.c # 系统初始化、主循环、TIM3 控制中断 ├─ Hardware/ │ ├─ k230_parser.* # K230 串口协议解析 │ ├─ bldc_motor.* # 无刷串口驱动(组帧/使能/速度/位置) │ ├─ mems_sensor.* # 单轴陀螺协议解析 │ ├─ pid.* # 位置式 PID │ ├─ uart.* # USART1/3/4 │ ├─ timer.* # TIM3 20ms 节拍 │ └─ OLED / Key / LED # 调试辅助 ├─ Library/ Start/ System/ # 标准库与启动文件模块职责要清晰:
解析协议的别掺 PID,PID 别掺串口寄存器操作。后期改视觉协议或换电机时,改动面最小。
四、串口资源分配(RCT6 的关键一刀)
STM32F103RCT6 串口资源较富,正好把四类通信拆开:
| 串口 | 引脚 | 波特率 | 功能 |
|---|---|---|---|
| USART1 | PA9/PA10 | 115200 | K230 视觉坐标 |
| USART2 | PA2/PA3 | 115200 | 双无刷驱动总线 |
| USART3 | PB10/PB11 | 115200 | 单轴陀螺仪 |
| UART4 | PC10/PC11 | 9600 | 上位机调参 / 遥测 |
中断优先级建议(本工程实际配置思路):
- USART1(视觉)最高—— 坐标丢包直接等于“瞎了”
- USART2 / USART3 次之 —— 电机与陀螺
- UART4 最低 —— 调参可以慢一点
- TIM3 控制中断也要低于视觉接收,避免“算 PID 时把串口顶飞”
五、K230 视觉链路:只给 MCU 最需要的东西
5.1 设计原则
视觉端负责“看”,主控负责“追”。
K230 不要往 MCU 塞图像,只发:
- 目标点坐标 ((x_1, y_1))
- 激光点坐标 ((x_2, y_2))
- (可选)距离/深度 (z)
5.2 通信协议(状态机解析)
本工程k230_parser采用帧头 + 数据 + 帧尾的短帧:
| 类型 | 帧格式 | 含义 |
|---|---|---|
| 目标 | 0xFF + XH XL YH YL + 0xFE | 目标点 (x1,y1) |
| 激光 | 0xFD + XH XL YH YL + 0xFC | 激光点 (x2,y2) |
| Z 值 | 0xFB + ZH ZL + 0xFA | 可选深度 |
坐标均为大端 int16。
解析核心逻辑(概念伪码):
// type=1: 目标; type=2: 激光; type=3: Z// 收到完整合法帧后:g_rect_data.x1/y1 或 x2/y2 或 z 更新;g_rect_data.type=current_type;g_rect_data.is_updated=1;5.3 主循环如何消费视觉数据
主循环只做“取最新坐标 + 清标志 + 偶尔发遥测”,不在主循环里控电机:
if(g_rect_data.is_updated==1){s_vision_age_ticks=0;// 刷新“视觉新鲜度”if(g_rect_data.type==1){target_x=g_rect_data.x1;target_y=g_rect_data.y1;}elseif(g_rect_data.type==2){laser_x=g_rect_data.x2;laser_y=g_rect_data.y2;}// 降频遥测...g_rect_data.is_updated=0;}5.4 视觉丢失保护(非常重要)
TIM3 每 20ms 把s_vision_age_ticks++。
若连续约5 个周期(≈100ms)都没有新视觉帧:
PID_Reset清空积分,防止“瞎了还猛冲”- 双轴速度置 0,安全停车
赛场上灯光一变、识别丢几帧很常见,没有丢帧保护等于定时炸机。
六、无刷云台驱动:串口协议 + 速度模式
6.1 为什么选“串口一体无刷”
电赛四天三夜,时间极紧。串口协议型驱动器的好处:
- 换相、电流环/速度环很多已经在驱动板里
- MCU 侧更像“发指令的上位机”
- 双电机可挂同一 UART 总线,靠 ID 区分
6.2 帧格式
帧头 0x7A | ID | CMD | 数据区 | BCC(异或) | 帧尾 0x7B BCC = 从帧头到数据末字节逐字节 XOR常用指令(以本工程为准,具体仍以电机手册为准):
| CMD | 功能 |
|---|---|
| 0x00 | 设置模式 |
| 0x01 | 设置速度 |
| 0x02 | 设置位置 |
| 0x06 | 使能 |
| 0x07 | 设置加速度 |
| 0x0E | 请求位置反馈 |
接收侧可用DMA + USART 空闲中断(IDLE)抓完整反馈帧,解析出Current_Position。
6.3 上电初始化顺序(建议照这个来)
BLDC_Enable(id);BLDC_Set_Mode(id,0);// 本方案瞄准时用速度模式BLDC_Set_Acceleration(id,50);// 加速度别太大,云台更柔顺双电机(Motor1 / Motor2)分别对应水平轴与俯仰轴,ID 必须与驱动器拨码一致。
6.4 速度模式下发
控制周期里最终只做:
BLDC_Set_Speed(Motor1.ID,(int)out_speed_x);BLDC_Set_Speed(Motor2.ID,(int)out_speed_y);注意:两帧之间可加极短延时(如 2ms),避免总线抢发导致偶发丢指令。
七、核心算法:视觉 PID + 陀螺前馈
7.1 控制节拍:TIM3 = 20ms
// 72MHz, psc=7200-1, arr=200-1 → 20ms (50Hz)Timer3_Init(200-1,7200-1);固定周期是 PID 能复现、能调的前提。不要在主循环里随缘算 PID。
7.2 位置式 PID(带限幅)
位置式 PID 公式:
[
u(k)=K_p e(k)+K_i\sum e + K_d\bigl(e(k)-e(k-1)\bigr)
]
工程上必须有两道“保险丝”:
- 积分限幅(Anti-windup):防止卡死/丢目标后积分爆掉
- 输出限幅:把速度指令限制在驱动器可接受范围
本工程默认参数示例(一定要按你的云台/镜头重调):
| 轴 | Kp | Ki | Kd | 输出限幅 |
|---|---|---|---|---|
| X(水平) | 0.10 | 0.002 | 0 | ±150 |
| Y(俯仰) | -0.09 | 0 | 0 | ±150 |
Y 轴 Kp 为负,是因为图像坐标方向与电机正方向可能相反。
方向反了先改符号,再谈调参,不然会越追越远。
7.3 误差定义(别搞反)
PID_SetTarget(&pid_x,target_x);// 目标out_speed_x=PID_Calc(&pid_x,laser_x);// 反馈=激光点即:
[
e_x = target_x - laser_x
]
语义是:激光偏左就往右赶,偏上就往下赶(再叠加电机方向符号)。
7.4 陀螺仪前馈(方案 A 的加分项)
协议简述
单轴陀螺串口帧:
0x5A | TYPE | DataL | DataH | SUM TYPE=0xAA → 角速度 gyro_z (°/s),raw/32768*2000 TYPE=0xBB → 偏航角 yaw (°),raw/32768*180 SUM = 前面字节累加和低 8 位为什么要前馈?
纯视觉闭环有延迟:
曝光/推理 → 串口 → PID → 电机动作
当底座晃动、目标快速横向移动时,视觉环容易“慢半拍”。
陀螺测的是机体/云台水平旋转角速度,可以提前给出补偿速度:
gyro_rate=s_gyro_z_filt-s_gyro_bias;if(fabs(gyro_rate)<GYRO_DEADZONE_DPS)gyro_rate=0;// 死区去抖v_ff=GYRO_FF_GAIN*GYRO_FF_SIGN*gyro_rate;out_speed_x=clamp(out_speed_x+v_ff,-SPEED_OUT_LIMIT,SPEED_OUT_LIMIT);关键参数:
| 参数 | 示例 | 作用 |
|---|---|---|
GYRO_FF_GAIN | 0.10 | 前馈强度 |
GYRO_FF_SIGN | -1 | 方向匹配(装反就改符号) |
GYRO_DEADZONE_DPS | 8°/s | 静止噪声抑制 |
GYRO_LPF_ALPHA | 0.35 | 一阶低通,降噪 |
上电建议:
- 解锁陀螺
- 发送 Z 轴置零指令
- 静止采样约 800ms 估计零偏
s_gyro_bias
前馈不是越大越好:过大云台会“发飘”,应在视觉环基本稳后再微调 (K_{ff})。
八、调参与遥测:赛场救命功能
8.1 UART4 遥测格式
一行 ASCII(约每 N 帧视觉更新上报一次):
T,tx,ty,A,ax,ay,PX,0.100,IX,0.002,DX,0.000,PY,-0.090,IY,0.000,DY,0.000含义:
T,tx,ty:目标坐标A,ax,ay:激光(Aim)坐标PX/IX/DX、PY/IY/DY:当前 PID 六参数
8.2 在线改参
通过串口助手下发(示例):
PX=0.12 IX=0.003 PY=-0.10 LIST主循环里UART4_PollTune()解析即可,不必每次改参都重新编译烧录。
电赛调试效率,有时比算法本身更决定上限。
8.3 一套可复制的调参顺序
- 先对方向:手动拨目标,看激光是否朝正确方向追
- 只开 P:从小到大,直到响应够快但不剧烈震荡
- 加一点 I:消除稳态偏差(长期差几像素)
- D 慎用:视觉噪声大时 D 容易放大抖动
- 最后加陀螺前馈:先符号,后增益
- 加输出限幅与丢帧停车,保证安全
经验口诀:
先正方向,再调 P,I 消静差,D 看噪声,前馈补动态。
九、主程序时序(从开机到闭环)
上电 ├─ NVIC 分组、四路串口初始化 ├─ 陀螺解锁 / Z 轴置零 ├─ 双电机 Enable → Mode(速度) → Acceleration ├─ 陀螺零偏标定(静止采样) ├─ PID_Init(X/Y) ├─ TIM3 启动(20ms 控制中断) └─ while(1) ├─ 陀螺一阶低通 ├─ UART4 调参轮询 └─ 消费 K230 最新坐标 + 遥测 TIM3_IRQ (20ms) ├─ 视觉超时? → PID复位 + 双轴速度0 └─ 否则: ├─ PID_X / PID_Y ├─ 陀螺前馈叠加到 X └─ BLDC_Set_Speed(Motor1/2)十、关键代码片段(可直接对照工程)
10.1 控制中断核心
voidTIM3_IRQHandler(void){if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET){if(s_vision_age_ticks>=VISION_LOST_TICKS){PID_Reset(&pid_x);PID_Reset(&pid_y);BLDC_Set_Speed(Motor1.ID,0);BLDC_Set_Speed(Motor2.ID,0);TIM_ClearITPendingBit(TIM3,TIM_IT_Update);return;}PID_SetTarget(&pid_x,target_x);PID_SetTarget(&pid_y,target_y);out_speed_x=PID_Calc(&pid_x,laser_x);out_speed_y=PID_Calc(&pid_y,laser_y);gyro_rate=s_gyro_z_filt-s_gyro_bias;if(gyro_rate>-GYRO_DEADZONE_DPS&&gyro_rate<GYRO_DEADZONE_DPS)gyro_rate=0.0f;v_ff=GYRO_FF_GAIN*GYRO_FF_SIGN*gyro_rate;out_speed_x=clampf(out_speed_x+v_ff,-SPEED_OUT_LIMIT,SPEED_OUT_LIMIT);BLDC_Set_Speed(Motor1.ID,(int)out_speed_x);BLDC_Set_Speed(Motor2.ID,(int)out_speed_y);TIM_ClearITPendingBit(TIM3,TIM_IT_Update);}}10.2 PID 计算核心(位置式 + 双限幅)
floatPID_Calc(PID_TypeDef*pid,floatactual_val){pid->actual=actual_val;pid->error=pid->target-pid->actual;pid->integral+=pid->error;// 积分限幅 ...pid->output=pid->kp*pid->error+pid->ki*pid->integral+pid->kd*(pid->error-pid->last_error);pid->last_error=pid->error;// 输出限幅 ...returnpid->output;}十一、调试清单(建议打印贴桌上)
硬件
- 所有模块共地
- 电机驱动供电功率足够,避免电压塌陷
- 串口 TX/RX 交叉正确,波特率一致
- 云台机械无死点、激光与摄像头相对固定
视觉
- 固定曝光/白平衡(赛场灯光变化大)
- 目标与激光都能稳定出框,坐标不乱跳
- 图像中心与云台零位大致标定
控制
- 先单轴再双轴
- 确认 X/Y 方向符号
- 丢帧后能停
- 输出限幅生效,电机不狂转
- 陀螺静止时前馈≈0(零偏与死区)
系统
- 中断优先级:视觉 > 电机/陀螺 > 控制/调参
- 控制周期稳定(用示波器/GPIO 翻转看 TIM3)
- UART4 能看到 T/A 坐标随动
十二、常见问题与对策
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 越追越远 | 坐标轴/电机方向反了 | 改 Kp 符号或电机正方向 |
| 来回抖 | P 过大 / 视觉噪声 / D 过大 | 降 P,滤坐标,D 置 0 |
| 总差几像素 | I 不够或有机械间隙 | 略增 I,检查安装 |
| 快速跟丢 | 纯视觉延迟 | 加陀螺前馈、提高视觉帧率 |
| 偶发乱飞 | 丢帧未保护 / 积分饱和 | 丢帧停车 + 积分限幅 |
| 电机不转 | 未使能 / 模式不对 / ID 错 | 查 Enable、Mode、拨码 |
| 串口错乱 | 优先级/重入/缓冲不够 | 调 NVIC,缩短中断处理 |
十三、可扩展与加分方向(有余力再做)
- 坐标低通 / 中值滤波:抑制视觉毛刺
- 变结构 PID:大误差时主用 P,小误差时加 I
- 前馈自适应:根据 (|e|) 或目标速度调整 (K_{ff})
- 俯仰轴也做辅助传感(若有双轴 IMU)
- OLED 显示误差/模式,按键切换“校准 / 瞄准 / 锁定”
- 记录一帧“标定偏移”:补偿摄像头光轴与激光轴不重合
十四、总结
2025 电赛 E 题「简易自行瞄准装置」,并不是单纯的“电机题”或“视觉题”,而是:
用视觉建立误差,用固定周期 PID 消误差,用执行器把误差变成机械运动,用惯性传感补视觉延迟。
本方案的关键闭环是:
K230 输出目标/激光坐标 → STM32 做图像误差 PID → 速度模式驱动双轴无刷 → 陀螺对水平轴前馈补偿 → UART4 在线调参
如果你也在用STM32F103RCT6 + K230 + 串口无刷云台备赛,可以按本文的模块边界直接拆工程:
- 先打通四路串口与协议
- 再做单轴视觉闭环
- 再合双轴
- 最后上前馈和赛场保护
十五、参考与声明
- 赛题名称:2025 年全国大学生电子设计竞赛E 题:简易自行瞄准装置
- 本文基于作者备赛工程
rct6_E(STM32 标准库)整理,参数与引脚以实际硬件为准 - 电机协议字节、陀螺指令码请以对应模块手册最终确认为准
- 转载请注明出处;用于学习交流,注意遵守竞赛规则与学术诚信
如果这篇文章对你备赛有帮助,欢迎点赞收藏。
你在 E 题里卡在视觉、云台,还是 PID 调参?评论区一起讨论。