简介:面向电子信息、自动化及嵌入式方向学生的STM32四旋翼飞行控制系统毕业设计报告,较为系统地覆盖从方案论证到软硬件联调的全流程内容。文档从前言与国内外研究现状切入,详细介绍飞行器结构原理,以及电源模块、STM32F407最小系统、下载电路、飞控姿态模块、无刷电机驱动和串口接口等硬件电路设计,层次清晰、便于对照学习。软件部分则包括串口/外部中断/主程序流程图、姿态传感器数据分析与解算、数据中断、PID姿态控制及飞控系统PID调试,同时配有部分程序、硬件电路图、PCB图,能帮助读者理解四旋翼的完整实现思路、关键算法与调参方法,并给出系统功能与指标参数。资源为单个doc文件,压缩包约35.48MB,内容紧凑完整;已有341人学习下载,适合正在开展飞控类毕业设计或嵌入式项目开发的读者参考。 每年到了毕业设计季,总有一批学弟学妹带着“基于STM32的四旋翼飞行控制系统”这个题目找过来。这个题听着高大上,网上的模板确实一抓一大把,但真能把飞机调稳、能悬停不抽风的,我见得并不多。STM32作为主控芯片,跑这套系统的姿态解算和PID控制,资源上刚刚好,资料也成熟,答辩时也容易讲出深度,所以它成了四旋翼毕设里最主流的选择之一。这篇文章把我们做这套系统时踩过的坑、必须理清的技术脉络,以及答辩时高频追问的点,一次讲透。
1. 毕设选题思路:为什么是STM32四旋翼
1.1 四旋翼毕设的“水分”有多大?先看核心难点
这个题目看起来简单,其实真正的门槛不在写代码,而在两方面:一是姿态解算的实时性与稳定性,二是PID参数整定的工程手感。很多论文里放了一堆公式,代码也跑通了,但飞机就是“点头、摇摆、起飞即翻”。原因基本都是这两块没有闭环验证。
四旋翼的控制链路其实很清晰:传感器采集数据 -> 姿态解算 -> 姿态误差计算 -> PID控制 -> 电机转速控制 -> 飞行姿态变化。在这个链路里,传感器数据不干净,姿态就解不准;姿态解算有延迟,PID就很难收敛;PID参数不合适,飞机就算在地面上也会抖得像抽风。所以选这个题目,不能只盯着“飞起来”这一个结果,还得把每个环节都拆出来做验证,这样论文里才有干货,答辩时才不会被问倒。
1.2 拆解系统需求:这些模块一个都不能少
我建议在动手写代码之前,先列一张系统需求表,按模块把硬件、接口、控制目标都定下来。下面这张表是我当时做设计时的整理,你可以直接拿来参考:
| 功能模块 | 推荐器件/方案 | 关键接口 | 作用 |
|---|---|---|---|
| 主控MCU | STM32F103C8T6或F405RGT6 | I2C/SPI、USART、PWM | 运行控制算法、处理遥控信号、输出电机控制量 |
| 姿态传感器 | MPU6050(六轴IMU) | I2C | 提供加速度计和陀螺仪原始数据 |
| 电机驱动 | 4路无刷电调 + 2212无刷电机 | PWM信号 | 驱动四旋翼产生升力和力矩 |
| 遥控链路 | 2.4G接收机(SBUS或PPM) | USART/定时器输入捕获 | 接收油门、横滚、俯仰、偏航指令 |
| 供电系统 | 3S锂电池 + 5V稳压模块 | 电源引脚 | 给电机供电,同时稳压给MCU和传感器 |
| 无线数传/上位机 | HC-05/HC-06蓝牙或NRF24L01 | USART/SPI | 实时查看姿态角、PID输出波形 |
| 调试接口 | ST-Link + SWD | SWDIO/SWCLK | 下载程序、在线调试变量 |
这张表看起来简单,但每一个模块都有坑。比如MPU6050的I2C上拉电阻没接好,数据读出来全是0;电调的油门行程没校准,电机一上电就猛转;接收机的信号线接错引脚,遥控通道死活没反应。这些在后续章节里我都会展开讲。
2. 飞控硬件选型与系统架构
2.1 主控选型:STM32F103还是F405
很多人在选型上纠结,其实逻辑很简单。STM32F103C8T6的频率是72MHz,片上有USART、I2C、SPI、定时器,跑一个单环或串级PID、配合MPU6050的DMP解算,完全够用。我自己最开始用的就是F103C8T6,裸机代码,主循环跑姿态解算和控制输出,实测一帧控制周期能稳定在2-4ms,对于毕设级别的悬停控制足够了。
如果后续想加FreeRTOS、贪吃蛇式地把SD卡日志、无线数传、光流定位都往上叠,那F103的资源就会紧张,这时候换STM32F405RGT6更从容,主频168MHz,FPU也带上了,浮点运算快很多。可以用一张表对比:
| 维度 | STM32F103C8T6 | STM32F405RGT6 |
|---|---|---|
| 主频 | 72MHz | 168MHz |
| FPU | 无 | 有(硬件浮点加速) |
| Flash/RAM | 64KB/20KB | 1MB/192KB+64KB CCM |
| 定时器数量 | 4个16位定时器 | 更多,且带32位定时器 |
| 适合场景 | 基础四旋翼、资源紧张可控 | 多任务、日志、更复杂算法 |
我的建议是:如果纯以毕业设计为目标,F103足够;如果你想把系统做得更像开源飞控、加一些“进阶功能”,直接上F405,省得到时候换芯片重画板子。
2.2 传感器组合:IMU选型与安装要点
姿态传感器是四旋翼控制的核心输入,最常见的是MPU6050,它内部集成了三轴加速度计和三轴陀螺仪,通过I2C或者SPI与STM32通信。有些方案还会加HMC5883L磁力计组成九轴,用于偏航角的长时间稳定,但对毕设来说,六轴配合软件滤波已经能解决大部分问题。
安装上面有个很容易被忽略的点:MPU6050一定要尽量安装在飞控板的几何中心。如果装偏了,飞行器做横滚或俯仰机动时,传感器会额外感受到旋转带来的向心加速度,姿态解算结果就会失真。另外,飞控板最好加一点减震泡棉,电机转动带来的高频振动会让陀螺仪数据产生“毛刺”,直接影响到姿态环的稳定性。我的习惯是在MPU6050底部贴一层3M双面胶,再压一块小PCB板,实测振动干扰能明显减小。
接线方面,MPU6050的I2C引脚要注意接上拉电阻,一般开发板上已经集成了,如果自己画板子,SCL和SDA分别接4.7k电阻到3.3V。电源要单独用LDO稳压,不要直接吃电机供电的纹波,否则飞控会出现间歇性复位。
2.3 动力系统与执行机构:电调、电机、桨叶
动力系统决定了飞机的响应速度和负载能力。四旋翼每个机臂上有一个无刷电机和一个电子调速器(电调)。电调的PWM信号频率常见的有50Hz、400Hz甚至更高,信号线接到STM32的定时器PWM输出引脚,通过改变PWM占空比来控制电机转速。
这里有一个关键点:电调第一次上电时需要做“油门行程校准”,也就是让电调知道你的遥控器或飞控输出的最小和最大PWM占空比范围。如果不校准,电调的油门响应会不均匀,低油门时电机可能停转,高油门时突然猛转,这在调试时非常危险。校准流程一般是:先给电调上电,听到提示音后,把油门拉到最大,再拉到最小,让电调自动记录范围。具体步骤每个电调品牌略有差异,但大逻辑一样。
电机和桨叶的选型也要匹配。常见的2212电机配合1045桨,配3S电池,单轴拉力大约在400-500g,四轴总拉力大概1.6kg,能带起800g左右的机架和飞控板。选大了浪费电,选小了飞不起来。在做动力计算时可以用一个简单公式估算:总升力至少是整机重量的1.5倍以上,这样PID才有足够的调节余量。
注意:所有电机联调时,务必先把桨叶拆掉。我见过太多人因为忘记拆桨,一推油门手指被桨叶划伤。调试电机转向和PID响应,完全不需要装桨,装桨只会放大危险性。
3. 姿态解算与数据滤波:飞控的“大脑”
3.1 姿态表示:欧拉角还是四元数
姿态解算就是利用加速度计和陀螺仪的数据,算出飞行器当前的横滚角、俯仰角和偏航角。姿态的表示方式有两种常用方案:欧拉角和四元数。
欧拉角直观,但它有一个绕不开的问题:万向锁。当俯仰角接近正负90度时,横滚和偏航会耦合在一起,无法独立表示旋转,计算也会出现奇异。四旋翼正常飞行时俯仰角一般不会到90度,但PID输出或外部扰动可能瞬间让姿态角过大,一旦触发万向锁,姿态解算就会飞掉。
所以工程上更推荐用四元数。四元数不会出现万向锁问题,而且只做四个数的乘法运算,计算效率高,非常适合单片机。MPU6050的DMP库可以直接输出四元数,再转换出欧拉角,省去了自己去跑互补滤波或卡尔曼滤波的麻烦。当然,如果你想在论文里写算法细节,自主实现一套四元数互补滤波也不是不行,我会在下面讲思路。
3.2 MPU6050数据读取与预处理
无论用DMP还是自己写解算,第一步都是准确读取传感器原始数据。我在HAL库环境下常用的读取流程是:初始化I2C -> 配置MPU6050寄存器 -> 循环读取加速度计和陀螺仪原始值。下面给一个简化版的HAL读取代码示例:
// 读取6轴原始数据 void MPU6050_Read_Raw(int16_t *ax, int16_t *ay, int16_t *az, int16_t *gx, int16_t *gy, int16_t *gz) { uint8_t buf[14]; HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, MPU6050_ACCEL_XOUT_H, 1, buf, 14, 100); *ax = (int16_t)((buf[0] << 8) | buf[1]); *ay = (int16_t)((buf[2] << 8) | buf[3]); *az = (int16_t)((buf[4] << 8) | buf[5]); *gx = (int16_t)((buf[8] << 8) | buf[9]); *gy = (int16_t)((buf[10] << 8) | buf[11]); *gz = (int16_t)((buf[12] << 8) | buf[13]); }读到的原始数据不能直接用。加速度计和陀螺仪都有零偏,上电后保持飞机静止,连续读取几百个样本取平均,作为零偏值保存下来,后续每次读取都减去这个零偏。这一步不做,悬停时飞机会朝一个方向缓慢漂移。
另外,陀螺仪数据的高频噪声建议做低通滤波,我常用一阶低通:filtered = alpha * raw + (1 - alpha) * filtered,alpha取0.2-0.4。这个滤波能很大程度上减轻电机振动带来的毛刺,但不要滤得太狠,否则姿态解算的延迟变大,飞控会“反应慢半拍”。
3.3 互补滤波与卡尔曼滤波的选择
如果不用DMP,自己写姿态解算,互补滤波是最容易落地的方式。核心思想是:陀螺仪短期准确但会积分漂移,加速度计长期稳定但动态响应差,所以把两者融合,公式大概是:
angle = 0.98 * (angle + gyro_rate * dt) + 0.02 * accel_angle
这里的0.98和0.02就是互补系数,表示对陀螺仪积分的信任度更高,同时用加速度计不断修正漂移。互补滤波原理简单、运算量小,在STM32上跑一毫秒都用不了,对毕设而言完全够用。
卡尔曼滤波在理论上更“高级”,它通过建立状态方程和观测方程,在噪声模型比较准确的情况下,能得到更平滑的姿态估计。但代价是矩阵运算复杂、需要调噪声协方差矩阵Q和R,初学者很容易调出“滤波后数据反而乱了”的效果。我的建议是:论文里可以讲讲卡尔曼的原理,工程实现优先用互补滤波或DMP,把精力留给PID,这才是真正影响飞机能不能悬停的关键。
4. PID闭环控制与整定实操
4.1 单环PID还是串级PID:先搞清控制结构
四旋翼的姿态控制,直接决定飞机能不能站稳。最基础的控制方案是单环PID,也就是直接用遥控目标角度与当前姿态角的误差计算PID输出。单环结构简单,但对飞机这种欠驱动、强耦合的动力学系统来说,控制带宽不够,抗扰动能力弱,稍有风力就会明显摇摆。
更可靠的是串级PID结构:外环是角度环,负责把“目标角度-当前角度”的误差算成“目标角速度”;内环是角速度环,负责把“目标角速度-当前角速度”的误差算成电机输出量。内环直接抑制角速度的变化,响应快,外环负责纠偏,响应稍慢。这样两级串联,飞机被风吹歪后能在极短时间内自动稳住。
立一个直观的类比:外环像是公司定目标,内环像是执行层干活。目标定得再准,执行层动作慢,整体就飘;执行层反应快,目标偏差才能被快速拉回来。所以我强烈建议毕设直接用串级PID,这也是开源飞控里最普及的方案。
4.2 PID参数初值与整定流程
串级PID一共有两组参数:角度环的P、I、D和角速度环的P、I、D。手动整定一定要讲顺序,如果上来就乱调,飞机只会越来越疯。
我的流程是:先把飞机的桨叶拆掉,用支架把飞机固定在地面上,只通电让飞控正常运行。第一步先只调内环角速度环的P,从小到大慢慢加,观察飞机在给一个角速度指令后能否快速回弹而不振荡。第二步加上内环I,消除静差。第三步再调外环角度环的P,让飞机在收到角度指令时能到位且不超调。下表是我当时在F103+MPU6050上实测可用的初始参数,单位是标准PWM输出范围下按比例计算的值:
| 控制环 | P | I | D |
|---|---|---|---|
| 内环角速度环 | 2.0-4.0 | 0.01-0.05 | 0.05-0.15 |
| 外环角度环 | 3.0-6.0 | 0.005-0.02 | 0.01-0.05 |
D参数要格外小心。D的作用是阻尼,能抑制振荡,但同时对噪声非常敏感,调太大会导致电机高频抖动,反而让姿态更差。如果你的传感器数据滤波不够干净,D宁可不加,或者给得非常小。
4.3 油门、偏航、翻滚的控制量分配
这里要清楚四旋翼不是四个电机独立控制姿态,而是通过不同的电机转速组合实现横滚、俯仰、偏航和上下运动。以常见的X型布局为例,四个电机分布在机架的对角线上,分别记为M1、M2、M3、M4。M1和M3逆时针旋转,M2和M4顺时针旋转,这样正反桨的扭转力矩才能相互抵消。
控制量的分配可以简化为四个通道的叠加:
- 油门通道:四个电机同时增大或减小,控制垂直升力;
- 横滚通道:左右两个对角电机一个增一个减,产生翻滚力矩;
- 俯仰通道:前后两个对角电机一个增一个减,产生俯仰力矩;
- 偏航通道:让两组旋转方向相反的电机转速差异,产生偏航力矩。
在代码里,一般先算出一个基础油门值,再在基础值上叠加三个姿态通道的输出。要注意最终输出不能超过电调允许的范围,我通常会做限制,把各通道输出限制在0-1000之间,避免“一个通道叠太多,另一个通道直接饱和”。
5. 调试排障实录:从“炸机”到稳定悬停
5.1 上电必检:电调校准与解锁逻辑
每次上电前,我都要按固定流程走一遍,顺序不能乱。先接电池给飞控供电,等电调自检完成,听到提示音后再打开遥控器或者发送电调解锁信号。很多新手一上电就推油门,结果电机没反应或者乱转,其实是电调的“解锁”逻辑没满足。
所谓解锁,是指飞控在接收到足够低的油门信号、且系统自检正常之后,才会允许电机响应PWM输出。这是一种安全保护。在代码里实现时,我通常在main函数里加一个状态标志:程序上电后先读取MPU6050,确认传感器数据正常,再检测遥控器油门通道处于最低位,最后飞控才会输出PWM信号到电调,并伴随一个LED变亮提示解锁成功。
注意:电调校准和日常上电是两个不同阶段。电调校准是让电调记录油门范围,通常要在飞控程序禁用PWM输出时进行;日常飞行阶段不要再重复校准,否则油门响应会乱套。
5.2 常见故障排查速查表
调试过程中我遇到最多的问题,整理成一张速查表,方便你对照:
| 现象 | 可能原因 | 排查方法 |
|---|---|---|
| 电机不转 | 电调未解锁、PWM接线错误、定时器通道配置不对 | 先用示波器/逻辑分析仪检查PWM波形,再检查解锁标志 |
| 电机上电即猛转 | 电调油门行程未校准或校准错误 | 重新按流程校准电调,确认最小油门信号正确 |
| 飞机起飞后剧烈翻滚 | 电机转向错误、桨叶装反、姿态解算方向不对 | 检查电机旋转方向、螺旋桨正反装,逐个检查飞控各轴方向 |
| 悬停时缓慢朝一个方向漂移 | 传感器零偏未校正、重心偏置 | 重新做零偏标定,调整电池位置使重心居中 |
| 机身持续高频抖动 | PID参数过高或传感器噪声大 | 先降低内环P值,检查MPU6050滤波是否开启 |
| 遥控器没有反应 | 接收机接线错误、协议解析不对 | 用串口打印接收机原始值,确认每个通道数据 |
每一个故障背后,几乎都能对应到一个具体的技术细节。如果电机转向装反,飞机起飞瞬间直接翻车,这时候不要急着调PID,先掰掉桨叶,用胶带标记每个电机,逐个给油门测试转向,确保对角线电机同向、相邻电机反向,再往下排查。
最后再分享一点个人体会
我一趟做下来最大的感受是:四旋翼毕设的真正价值不在于“飞得多炫”,而在于把姿态解算、系统建模、闭环控制这些嵌入式核心知识真正串起来。答辩时老师问你PID是什么、为什么用串级、四元数为什么能避免万向锁,你能不能脱口而出,这比飞机悬停那几秒钟重要得多。
如果你时间紧张,建议把调试顺序固定成:传感器数据校准确认 -> 姿态角输出稳定 -> 固定支架上调PID -> 最后再装桨试飞。每一步都留出可以回滚的验证点,不要一上来就想着“整机起飞”。这个方法帮我少摔了不少桨,希望你也能稳稳落地。
本文还有配套的精品资源,点击获取