ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

STM32+MPU6050四旋翼飞控实战:从电路到串级PID整定

STM32+MPU6050四旋翼飞控实战:从电路到串级PID整定 简介基于STM32F103C8T6与MPU6050的四旋翼飞控完整工程面向刚接触无人机开发的初学者与爱好者通过串级PID控制实现俯仰、滚转、偏航的姿态稳定不依赖过多附加功能适合系统学习飞控原理与PID整定。压缩包共431个文件大小11.1MB以C语言源码41个.c文件、45个.h文件为核心并包含Keil工程配置文件、编译生成的.o/.crf/.d中间文件、可烧录的.hex固件以及少量示例文件清晰呈现从编写代码到生成固件的完整链路。已有1716人学习下载可作为飞控入门的实用参考。工程结构经过整理从MPU6050数据读取、卡尔曼/互补滤波到串级PID算法与电机PWM驱动均有完整的代码实现配合MDK工程可快速编译调试还能直接烧录hex验证效果适合在此基础上二次开发深入理解姿态解算、控制参数整定与嵌入式实时系统的协作有助于快速上手飞控开发。目录一、整体设计思路与硬件选型二、MPU6050从电路到数据读取三、定时器与PWM输出链路四、串级PID控制核心五、调试实录与避坑建议一、整体设计思路与硬件选型做四旋翼飞控这件事说难不难但说简单也真不简单。我刚入门那会儿也纠结过要不要上树莓派之类的“高性能平台”后来发现STM32MPU6050这套组合才是真正适合个人玩家从零开始搞飞控的黄金搭档便宜、资料多、实时性有保障。当时我的目标是做一个能稳定悬停的迷你四旋翼不带GPS、不带光流纯靠IMU自稳最后也确实飞起来了。这篇文章就围绕这套方案把从MPU6050外围电路到PID控制整条链路讲明白给同样想从零上手的朋友一条可以直接抄的路径。为什么是STM32MPU6050先说结论这套组合几乎就是为入门级飞控量身定制的。STM32的定时器资源丰富4个电机需要4路带死区补偿的PWM它轻松驾驭主频72MHzF103系列跑姿态解算和PID控制还有富余不像51那样算不过来。而MPU6050是当时市面上最成熟的六轴IMU之一把三轴陀螺仪和三轴加速度计集成在一个QFN小封装里I2C接口直接接STM32就能读数不像一些老传感器还需要额外ADC电路。选型时我对比过几套方案方案优点缺点适合场景STM32 MPU6050资料多、性价比高、实时性好姿态解算需自己写或移植DMP入门到进阶的完整学习链路STM32 高精度IMU如BMI088/ICM20602温漂小、噪声低价格贵、电路复杂需要更稳的飞行或竞速ESP32 MPU6050WiFi调试方便实时性稍弱、ADC精度有限追求无线调试的DIY我最终还是回归STM32原因很简单飞控是硬实时系统中断延迟和PWM精度比花哨的无线调试重要得多。ESP32跑飞控不是不行但折腾WiFi协议栈调度时电机的PWM波形可能就抖了这在真机上很致命。系统架构与模块划分整个飞控系统可以拆成六个核心模块主控STM32、姿态传感器MPU6050、电机驱动电调无刷电机或空心杯电机、遥控接收PPM/SBUS、电源管理稳压电路、调试接口SWD串口。单看任何一个模块都不难难的是让它们协同工作。传感器采集姿态数据 → 主控读取并解算出欧拉角 → 串级PID计算电机控制量 → 定时器输出PWM → 电机响应这就是一次完整的控制循环。这个循环的执行频率非常关键我建议至少做到入环频率1kHz、控制环频率500Hz以上否则自稳效果会很差。MPU6050的I2C读取频率和数据融合频率需要仔细匹配读取太快容易遇到数据不更新读取太慢则姿态滞后后面我会专门讲这个问题。二、MPU6050从电路到数据读取外围电路设计要点MPU6050的硬件连接看着简单其实有几个隐藏的坑。第一是供电它标称3.3V供电但特别注意别用LDO直接供3.3V然后和电机共用电源——电机一启动电压跌落那一下就会导致MPU6050复位。我当时在面包板上用AMS1117-3.3单独从锂电池取电给传感器和电机供电完全分开数据稳定很多。I2C上拉电阻必须有。MPU6050的SCL和SDA引脚是开漏输出不加上拉电阻通讯时电平拉不上去表现就是OneWire读不到数据或读出的数据全是0xFF。上拉电阻选4.7kΩ比较稳有时候为了兼容多个I2C设备我习惯用2.2kΩ。这个阻值不能太小太小会增加功耗且拉低信号边沿的上升速度。AD0引脚决定I2C从机地址。AD0接低电平时地址是0x68接高电平是0x69。如果你后面想用SPI接口比如MPU6500/ICM20602用SPI还要注意把CS引脚的电平在初始化之前配置好。对于MPU6050默认I2C就够用四旋翼对它要求不高I2C 400kHz速率足够。另外还有VLOGIC引脚它决定了I2C逻辑电平一般直接接3.3V。别忘了给MPU6050加一个100nF的电源去耦电容最好靠近VDD引脚放。很多朋友喜欢把所有元件密密麻麻挤在一起结果传感器电源噪声大加速度计波形跟心电图一样。这个电容能让情况好很多。I2C通信与原始数据读取STM32和MPU6050之间用I2C通信常用的是软件I2C或硬件I2C。我刚上手时直接用STM32的硬件I2CI2C1结果发现F103系列硬件I2C有坑——如果不加超时处理卡在EV5事件上是常事。后来我把总线换成软件模拟I2C用两个GPIO口来回翻转时钟和数据线反而稳定得多。虽然软件I2C更占用CPU时间但飞控循环里就读取一个IMU这部分开销完全可接受。读取MPU6050的步骤大致是初始化I2C引脚和时钟。向0x68写入配置寄存器设置陀螺仪量程如±2000dps和加速度计量程如±2g把DLPF数字低通滤波器设置在20Hz左右。等待数据就绪读取0x3B开始的14个寄存器依次为加速度计X、Y、Z温度陀螺仪X、Y、Z。代码模板大致如下void MPU6050_Read_Accel_And_Gyro(int16_t* accel, int16_t* gyro) { uint8_t buf[14]; I2C_ReadRegs(MPU6050_ADDR, 0x3B, buf, 14); accel[0] (int16_t)(buf[0] 8 | buf[1]); accel[1] (int16_t)(buf[2] 8 | buf[3]); accel[2] (int16_t)(buf[4] 8 | buf[5]); gyro[0] (int16_t)(buf[8] 8 | buf[9]); gyro[1] (int16_t)(buf[10] 8 | buf[11]); gyro[2] (int16_t)(buf[12] 8 | buf[13]); }读回来的原始值是带符号的16位值需要除以对应量程的灵敏度才能换算成物理单位。±2000dps陀螺仪灵敏度是16.4 LSB/dps±2g加速度计灵敏度是16384 LSB/g。换句话说gyro_dps raw_gyro / 16.4。注意MPU6050还有一个自由落体中断功能FF_INT可以在检测到自由落体时产生中断。这个功能在四旋翼上意义不大但如果你打算做跌落检测或穿戴设备就很有用。它的原理是加速度计三轴合成幅值低于阈值并且持续一段时间就会触发中断。配置寄存器主要在INT_ENABLE和MOT_THR、MOT_DUR等需要自己仔细算阈值我当时调了很久才找到合适的值。姿态解算从原始数据到欧拉角光有加速度计和陀螺仪的原始数据是不够的必须做数据融合才能得到稳定的姿态角。两个传感器各有优劣陀螺仪短时间积分准确但长时间会漂移。加速度计在静止或匀速时能准确测量重力方向但动态时抖动大、噪声大。最经典的方案是互补滤波它相当于给陀螺仪一个高通滤波给加速度计一个低通滤波再合成。公式大体是俯仰角 α × (俯仰角 角速度×dt) (1 - α) × 加速度计计算角α一般取0.98dt是采样周期。另一个方案是直接用MotionDriver库里的DMP引擎让MPU6050内部硬件处理四元数转换主控直接读取四元数再转成欧拉角。这个方案代码简单很多而且还带自校准。但代价是DMP会占用MPU6050一部分内部资源而且除非你有原厂的MotionDriver库否则从零移植会比较折腾。我建议新手先从互补滤波入手——代码短、逻辑清楚、利于理解原理等真正飞起来再考虑DMP优不优化。如果你已经知道DMP解算的代码模板大概是这样初始化之后调用mpu_dmp_get_data(pitch, roll, yaw)它内部已经封装好fifo读取和四元数转欧拉角。不过要提醒的是你在使用DMP之前最好先做一次加速度计和陀螺仪的校准否则初始数据就有偏差后面解算出来的姿态就带着固定偏置。三、定时器与PWM输出链路STM32定时器配置与PWM生成四旋翼用的电机有两大类一类是带ESC的空心杯电机输入是50Hz~500Hz的PWM另一类是无刷电机加电调ESC输入也是PWM。STM32做这件事非常简单用定时器的PWM输出模式就可以。我当时用TIM1的CH1~CH4分别控制四个电机因为TIM1是高级定时器自带互补输出和刹车功能。不过对普通自稳四轴来说不需要互补输出用TIM2/3/4的四个通道也完全够。关键参数是PWM频率和占空比更新频率也就是方向控制更新频率这决定了飞控的响应速度。以空心杯电机为例PWM频率一般选在16kHz~32kHz这样可以避开人耳可听噪声范围电子调速器和电机的效率也更高。普通电调则常用400Hz。配置时注意时钟树的预分频设置先算好PSC和ARR// 假设主频72MHzPWM频率16kHz PSC 1; // 预分频72MHz / 2 36MHz ARR 36MHz / 16000Hz - 1; // 也就是2249改了PSC和ARR之后脉冲宽度就是占空比。实际控制量用百分比或者0~1000的数值都能映射到这个定时器代码逻辑要提前设计好。我习惯最小油门为5%占空比最大油门为90%留出两端余量防止全油门失控或者油门过低导致电机堵转。配置时还有一个细节有些定时器通道默认的GPIO复用功能要手动开启比如TIM1的CH1是PA8、CH2是PA9。别忘了在GPIO_InitTypeDef里设置GPIO_Mode_AF_PP不然PWM波形死活出不来。与电调和电机的连接电流路径上要特别注意驱动四旋翼的电机电流能达到几安培甚至几十安培STM32的GPIO是推不动电机的所以中间一定有电调或电机驱动芯片。使用空心杯电机时常见方案是直接用MOS管驱动用STM32的PWM去控制MOS管栅极使用无刷电机时则是把PWM信号输出给电调电调再去驱动电机。一个常见误区用STM32直接驱动四路MOS管给无刷电机换相这是不对的。无刷电机必须靠电调完成电子换相STM32只负责输出转速指令。我在调试时有个朋友为了省电调钱想用STM32直接驱动ESC的三相桥结果连烧了两块板子最后老老实实买了电调。如果使用带BEC的电调务必检查电调供电有没有给飞控板提供5V电源同时还要做好电源去耦高速PWM开关会让母线电压出现毛刺处理不好飞控会疯狂复位。我的经验是电机电源和逻辑电源完全分开只在总输入端并联一个足够大容量的电解电容1000μF或以上再在逻辑电源入口加一个LC滤波或至少一个100Ω电阻串联。这样数字部分基本不会受电机启停的影响。PWM更新与遥控信号的协同除了PWM输出遥控接收机信号PPM或SBUS也在处理。PPM信号是一串宽度调制脉冲SBUS则是串口数字信号两者都需要定时器输入捕获配合中断来解析。我建议用定时器的输入捕获通道比如TIM2_CH1来捕获PPM信号解析出各个通道的遥控值。解析出遥控值后再和PID控制量叠加或切换构成完整的控制链路。这里有个很容易被忽略的点PWM输出更新频率和遥控信号解析频率要错开避免在解析PPM的下降沿中断里直接对电机输出占空比做大幅度修改否则飞机会抽搐。我是用两个标志位来协调的rc_updated_flag和control_loop_flag在控制循环里读取最新的遥控值再计算新的PWM输出值在下一个PWM周期更新。四、串级PID控制核心为什么需要串级PID四旋翼姿态控制最经典的结构是串级PID外环控制角度内环控制角速度。外环输入是期望角度和当前角度的误差输出是期望角速度。内环输入是期望角速度和当前角速度的误差输出是电机控制量。为什么要这么套因为直接用角度误差做PID控制会出现响应迟缓和振荡。我自己试过只做单环角度控制结果飞机就像喝醉了一样左右晃很难稳下来。角速度内环相当于给系统增加了一个“阻尼”让角度环能更平稳地收敛。举一个生活化的例子外环是“导航员”告诉你该往哪偏转多少角度内环是“执行者”负责把角速度调到导航员要求的转速。如果导航员直接跳过执行者去指挥马达动作就会过头。这样一想串级结构的必要性就很清楚了。串级PID还带来另一个好处抗扰动能力强。有风突然吹过来时角度瞬间发生变化内环角速度会先响应比外环角度响应快将近一个数量级。所以即使外环还未察觉内环已经在压制扰动飞行稳定性明显提升。PID参数整定从内环到外环参数整定是我折腾最久的部分中间还炸过一次桨。后来总结出了一套稳妥的流程零基础也能跟着做把飞机固定在支架上或者只测试单个轴比如只允许俯仰自由度确保不会真的飞起来。有条件的话用这种单轴测试架是最安全的。先调内环P把期望角速度设为一个固定值观察实际角速度响应。慢慢增大P直到出现轻微振荡然后退回比临界值小20%左右。比如P在0.08时开始振那就用0.065。加内环DD的作用是阻尼振荡逐步增加直到系统响应变快且不振荡。D过大会引入噪声感觉像电机高频抖动。调内环I如果发现目标角速度和实际角速度长期有稳态误差再逐渐加I。如果系统能快速逼近期望角速度I可以先不加。外环P外环P相对简单因为内环已经相对稳定只需根据角度误差给目标角速度。一般从0.01开始尝试看看飞机角度能否稳定在期望值附近。这只是一个大方向。不同机架、不同电调响应速度、不同电池电压下PID参数都会有差异。我见过有人把同一套PID参数直接复制到另一台机上结果严重振荡。这种事只能自己重新调。调参时还需要一个参数可视化的工具不用高大上串口打印到上位机即可。我把角度、角速度、PWM输出值用DMA发送到串口然后用电脑上的VOFA或匿名上位机画波形边调边看曲线走向效率高得多。强烈建议不要盲调只看感觉没有波形累死也调不好。实时性约束与循环频率串级PID对实时性要求很高整个控制周期必须严格稳定。如果主循环里混入了一些耗时操作比如LCD刷新或者DMP库的长阻塞循环周期就会抖动PID输出也就不稳定了。我调试时遇到过飞行中偶尔抽搐的情况定位后发现是LCD刷新和DMP读取冲突导致主循环卡顿了几毫秒。解决方案是把控制任务放在定时器中断里比如TIM3定时500us触发一次中断在中断里完成传感器读取、姿态解算和PID计算。主循环只负责显示、通信和状态机切换。这样即使主循环卡住控制周期依然稳定。定时器中断的优先级也要设置得比串口中断高防止串口调试数据刷屏时打断控制。五、调试实录与避坑建议常见问题速查表我把自己和周围几个朋友在STM32MPU6050四旋翼飞控项目里遇到的典型问题整理成了表格方便大家排查现象可能原因解决方向I2C读不到MPU6050AD0地址不对上拉电阻缺失接线错误确认地址0x68/0x69测量SCL/SDA对地电阻传感器数据全是0x00或0xFFI2C从机未使能供电不稳检查VDD电压和时序先用某个通道单独测试电机不转PWM频率/占空比不对电机线序接反用逻辑分析仪看PWM输出检查接线电机转但转速不一致电调的校准不一致PWM信号线干扰重新校准所有电调检查信号线排布飞机上电后瞬间反转电机相序接反螺旋桨装反按照对角电机旋转方向重新接线检查正反桨姿态角抖得厉害传感器噪声PWM干扰DLPF设置不对检查去耦电容调低DLPF截止频率增加滤波悬停时缓慢漂移传感器零偏未校准重心不在对称轴重新校准调整电池位置PID加大后就自激振荡内环D过小PWM更新频率过低提高控制频率增大D检查PWM频率调试工具与方法心得工欲善其事必先利其器。飞控调试的调试工具基本是STM32 ST-LINK Utility或者Keil的调试器一个USB转TTL串口模块一个逻辑分析仪或示波器。逻辑分析仪对排查I2C时序和PWM输出特别有用可以直观看到哪个通道卡在电平上。我买过一个几十块钱的8通道逻辑分析仪配合PulseView软件能满足四旋翼项目的大部分调试场景。还有一个经验飞机螺旋桨不离地测试时一定要固定牢靠。我第一次只是把飞机放在一个纸箱上调PID结果P值加大后飞机直接翻起来把纸箱撕了吓出一身冷汗。后来专门买了铝合金的测试架飞机用扎带固定手也离得远远的安全多了。遥控器失控保护Failsafe也是必修课。我用的是带PPM输出的接收机在代码里做了个超时检测如果接收机信号超过500ms没有更新就执行自动油门降落并锁定电机防止飞机失控乱飞伤人。这个逻辑很简单就是个计时器状态机但在真机飞行里能救命。关于后续扩展现在这套基础飞控已经能稳定悬停和手动飞行了后面的扩展方向很多。比如增加光流传感器实现室内定点增加超声波或激光测距实现定高接入ESP8266或蓝牙模块实现手机调参和航迹规划。我还见过有人把视觉模块K210和STM32通过串口通讯在飞控上做简单的颜色追踪和Apriltag降落玩得很花。但无论如何先把姿态控制这层地基打牢后面的功能才有意义。我个人的体会是一个简单的、稳定的、能让人理解每一行代码的飞控比一个功能堆砌但飞起来胆战心惊的“黑盒”有价值得多。这套STM32MPU6050方案正好就是那个能让你真正理解飞控内部逻辑的起点。本文还有配套的精品资源点击获取
返回列表