从零开始:用STM32F103C8T6和HAL库打造你的第一台四轴无人机飞控(附完整原理图与代码)
从零开始:用STM32F103C8T6和HAL库打造你的第一台四轴无人机飞控(附完整原理图与代码)
在创客圈子里,四轴无人机始终是令人着迷的项目——它融合了嵌入式开发、自动控制理论和硬件设计三大领域。但大多数教程要么停留在理论层面,要么直接给出成品代码让人无从下手。本文将用一台基于STM32F103C8T6的飞控,带你完整走通从元器件选型到PID调参的全流程。不同于市面上常见的F4系列方案,这个"蓝色药丸"(STM32F103的昵称)方案成本更低,更能锻炼底层开发能力。
1. 硬件选型与成本控制
1.1 为什么选择STM32F103C8T6?
这款被戏称为"中国芯"的MCU有着令人惊讶的性价比优势:
| 参数 | STM32F103C8T6 | STM32F405RG | 对比分析 |
|---|---|---|---|
| 主频 | 72MHz | 168MHz | 飞控算法不需要超高主频 |
| Flash | 64KB | 1MB | 精简代码足够存放 |
| SRAM | 20KB | 192KB | 需注意内存优化 |
| 单价(2023) | ¥12-15 | ¥35-40 | 成本降低60%以上 |
实战建议:购买时注意区分"正品丝印"和国产兼容芯片,后者可能出现ADC精度不足的问题。实测发现某些国产型号的MPU6050数据读取会有±0.5°的偏差。
1.2 关键外设配置清单
// HAL库外设初始化优先级配置示例 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); // MPU6050中断 HAL_NVIC_SetPriority(TIM1_UP_IRQn, 4, 0); // PWM生成 HAL_NVIC_SetPriority(USART1_IRQn, 3, 0); // 调试串口必备元器件清单:
- 动力系统:8520空心杯电机 ×4(带正反桨)
- 传感单元:MPU6050六轴传感器(务必选择带AUX_CLK引脚的版本)
- 驱动电路:SI2302 MOS管 + FR107二极管组成H桥
- 电源模块:BL8530升压芯片 + XC6206稳压芯片
2. 开发环境搭建与HAL库魔改
2.1 CubeMX工程配置技巧
在Clock Configuration中开启PLL倍频时,建议采用8MHz外部晶振→PLL×9→72MHz的方案。这个配置下ADC采样时钟不要超过14MHz,否则会出现数据抖动。
关键配置步骤:
- 在Pinout视图启用I2C1(MPU6050通信)
- 配置TIM1为PWM Generation模式
- 开启USART1异步通信(115200bps)
2.2 内存优化实战
由于F103的20KB内存限制,需要修改HAL库的默认配置:
// 修改stm32f1xx_hal_conf.h #define HAL_MODULE_ENABLED #define HAL_GPIO_MODULE_ENABLED #define HAL_I2C_MODULE_ENABLED // 仅启用必要模块注意:禁用不用的HAL模块可节省约8KB Flash空间。建议使用
-Os优化等级编译。
3. 传感器驱动与姿态解算
3.1 MPU6050的硬件陷阱
市面上常见的MPU6050模块存在两个版本:
- 标准版:仅支持I2C通信
- 增强版:额外引出AUX_CLK(可用于同步采样)
接线时特别注意:
VCC → 3.3V SCL → PB6 SDA → PB7 INT → PB5(配置为下降沿触发)3.2 卡尔曼滤波实现
简化版的姿态解算算法:
void Kalman_Update(float *angle, float *bias, float rate, float accel, float dt) { float Pdot[4] = {0}; Pdot[0] = Q_angle - P[0][1] - P[1][0]; Pdot[1] = -P[1][1]; Pdot[2] = -P[1][1]; Pdot[3] = Q_bias; // 预测协方差 P[0][0] += Pdot[0] * dt; P[0][1] += Pdot[1] * dt; P[1][0] += Pdot[2] * dt; P[1][1] += Pdot[3] * dt; // 更新卡尔曼增益 float S = R_measure + P[0][0]; float K[2] = {P[0][0]/S, P[1][0]/S}; // 更新状态估计 float y = accel - *angle; *angle += K[0] * y; *bias += K[1] * y; // 更新协方差 float P00_temp = P[0][0]; P[0][0] -= K[0] * P00_temp; P[0][1] -= K[0] * P[0][1]; P[1][0] -= K[1] * P00_temp; P[1][1] -= K[1] * P[0][1]; }4. 电机控制与PID调参
4.1 PWM驱动电路设计
采用N沟道MOS管SI2302搭建的驱动电路需要注意:
- 栅极电阻选用100Ω(过大导致开关损耗,过小引起振荡)
- 续流二极管FR107的反向恢复时间要<50ns
- 电机两端并联104瓷片电容吸收尖峰
实测PWM频率建议设置在8-12kHz:
// TIM1 PWM初始化代码片段 htim1.Instance = TIM1; htim1.Init.Prescaler = 72-1; // 1MHz计数频率 htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 100-1; // 10kHz PWM htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;4.2 PID参数整定经验
采用试凑法时的起调参数建议:
| 控制环 | P | I | D | 说明 |
|---|---|---|---|---|
| 角度环 | 3.5 | 0.02 | 18 | 先调P至轻微振荡 |
| 角速度 | 0.8 | 0 | 4.5 | 再调D抑制超调 |
| 高度环 | 1.2 | 0.01 | 0 | 最后微调I消除静差 |
调试时务必先断开电机,用串口打印实时曲线。我在实验室摔坏过三套桨叶才找到这组黄金参数。
5. 飞行测试与故障排查
5.1 校准流程清单
- 水平校准:将飞控平放在桌面,持续发送
CALIB_ACC命令 - 陀螺校准:保持静止发送
CALIB_GYRO约5秒 - 磁力计校准(如有):在空中画"8"字
5.2 常见故障代码表
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 起飞后剧烈抖动 | PID参数过冲 | 降低D值,增加I值 |
| 向一侧倾斜 | 电机推力不平衡 | 重新校准ESC或更换电机 |
| 高度无法保持 | 气压计受气流干扰 | 加装海绵减震,优化算法 |
| 遥控信号丢失 | NRF24L01天线接触不良 | 改用IPEX外接天线 |
最后分享一个血泪教训:永远在第一次室外试飞时系上安全绳。我的第一台原型机就是因为没做这个防护,现在还在小区梧桐树上挂着。
