十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

STM32四轴飞控与遥控器设计:原理图、PCB与源代码全解析

STM32四轴飞控与遥控器设计:原理图、PCB与源代码全解析 简介这套基于STM32单片机的四轴飞行器与飞控遥控器设计资料面向嵌入式爱好者与无人机竞赛参与者可解决飞控硬件搭建、无线遥控通信和底层驱动开发等关键问题。方案以STM32为核心通过NRF24L01无线模块在飞行器与遥控器之间建立双向数据链路原理图、电路板布线和源码全部开放适合学习四轴飞行器姿态控制与无线协议。压缩包共204个文件大小约5.12MB文件类型以90个头文件和81个C源文件为主另有电路原理图、电路板文件、固件、工程文件、说明文档和批处理脚本等标准外设库源码覆盖定时器、时钟、模数转换和闪存等驱动可在开发环境中打开工程直接编译。目前已有438人学习下载目录按四轴飞行器和遥控器两大部分组织电路图、固件和源码一一对应便于快速定位读者可对照原理图理解传感器、电机驱动与无线模块的连接关系也可从C源码中把握遥控数据解析、姿态控制及脉宽调制输出流程对课程设计或电子竞赛项目很有参考价值。1. STM32四轴飞控与遥控器为什么一定要啃原理图、PCB图和源代码一个刚接触四轴的嵌入式工程师最容易犯的错是直接去下载开源的飞控固件刷进去发现飞机能飞但代码看不懂、电路也改不动。基于STM32单片机做的四轴飞行器和飞控遥控器同时给出原理图、PCB图和源代码本质上是一套可以完全自研的完整参考设计。它的价值不在于“抄”而在于让你同时看清三件事传感器数据怎么进MCU、控制算法怎么变成PWM、遥控器指令怎么穿过无线链路落到电机上。这个项目最适合两类人一类是做STM32相关毕业设计的学生需要一套能讲清楚原理的实物另一类是航模或嵌入式爱好者想从零攒一台自己画板、自己写代码的四轴。读懂这套东西你获得的不是一台能飞的玩具而是“从画板到调参”的全部能力往后的F4、F7飞控无非是这套框架的资源升级。2. STM32四轴飞控的系统架构与核心器件选型2.1 为什么飞控主控选STM32F103C8T6而不是直接上F4STM32F103C8T6是Cortex-M3内核主频72MHz64KB Flash20KB RAM。这个资源放在今天看并不富裕但恰好卡在飞控的甜点区跑姿态解算、PID和无线通信绰绰有余跑复杂的地面站逻辑就不够。它的外设配置非常适合四轴场景下面这张表是选型的核心逻辑外设数量在本项目中的用途USART3串口调试、可选GPS和数传SPI2nRF24L01无线模块、外部FlashI2C1MPU6050姿态传感器TIM1高级定时器1四路PWM输出驱动电机ADC110通道电池电压采样、遥控器摇杆采集定时器这里有个关键点TIM1自带四个通道正好对应X型四轴的四个电机不需要再用软件模拟PWM。F103没有FPU浮点运算偏慢所以姿态解算频率一般控制在200Hz到400Hz再高就要考虑定点运算或者换F4。这也是很多人在F103上跑DMP库时发现CPU占用率爆表的原因——不是MCU不行是你没给外设留够余量。2.1.1 MPU6050是入门四轴的事实标准MPU6050集成了三轴加速度计和三轴陀螺仪片内还有DMP运动处理器可以直接输出四元数省去在MCU上跑卡尔曼滤波的负担。I2C接口只需两根线但上拉电阻不能省常规做法是在SCL和SDA上各接一个4.7kΩ电阻到3.3V。如果飞控板上还有其他I2C设备共用总线每个设备的上拉都要保留否则信号沿变缓读出来的姿态数据会周期性跳变。气压计和磁力计在室内小四轴上可以先不加。等姿态环稳定之后再考虑加BMP280做定高、加磁力计做航向锁定这是典型的增量式开发路径一上来就搞九轴融合只会让问题排查难度翻倍。2.2 电机驱动方案MOS管直驱还是外接电调这个选择直接决定原理图画法和PWM代码写法。两种路线各有优劣对应的电路和代码差异很大对比项有刷空心杯电机 MOS管直驱无刷电机 电调整机重量轻适合100g以内小四轴重但可载重PWM信号频率1kHz~16kHz可调固定50Hz脉宽1~2ms额外电路4路MOS驱动电路电调模块自带代码复杂度低直接输出占空比低但脉宽精度要高学习价值高能看懂驱动电路一般电调是黑盒如果目标是学习飞控原理而不是做航拍机我一般推荐先用有刷方案。MOS管驱动电路简单故障点少炸机成本低精力可以全部放在姿态算法上。无刷方案后期再升级也不迟电调接口在PCB上预留一个排针位置即可。有刷方案里MOS管选型要注意逻辑电平STM32的GPIO输出高电平只有3.3V普通MOS管可能没法完全导通要选低栅极阈值电压的型号比如SI2302或者AOD4184。电机是感性负载MOS管D极和电源之间必须并一个SS34肖特基二极管做续流否则电机关断瞬间的反向电动势会把MOS管击穿这是原理图里最容易漏的元件。2.2.1 遥控器端硬件摇杆、按键与无线模块遥控器端同样用F103C8T6好处是固件底层驱动可以直接复用飞控端的代码。摇杆本质是两个电位器输出0~3.3V模拟电压直接进ADC油门摇杆不带弹簧回中俯仰、横滚、偏航带。nRF24L01模块是遥控链路的核心但它运行时峰值电流接近100mA直接挂在STM32的3.3V引脚上会导致电压跌落和复位。正确做法是给它独立的LDO供电并在模块电源脚旁边放一个10μF陶瓷电容加一个0.1μF高频退耦电容。提示nRF24L01的PCB天线要伸出主板边缘周围至少10mm净空区不能铺铜、不能走线否则遥控距离会从几十米缩水到几米。2.3 电源树设计从电池到每一颗芯片以一个1S锂电池供电的小四轴为例电源树是这样的电池3.7V直接给电机供电同时经过LDO稳压到3.3V给MCU、MPU6050和nRF24L01供电。LDO选型要留足余量整板电流在150mA左右选ME6211或RT9193这类最大输出300mA以上的型号别选只有100mA的LDO一上电就触发限流保护导致系统复位。电池电压检测用一个100kΩ和33kΩ的分压电阻把4.2V映射到1.0V附近再从ADC引脚进去换算。分压电阻选0603封装就行但电池主回路走线要加粗理想情况下电源线宽不小于1mm否则电机大电流会在导线上产生压降飞控会误判电池电压骤降。3. 飞控源代码核心互补滤波、串级PID与电机混控3.1 互补滤波算法没有DMP也能读准姿态外设初始化可以交给STM32CubeMX生成但姿态解算和控制环必须自己写。互补滤波是四轴最经典的姿态融合算法比卡尔曼滤波简单效果在F103上完全够用。核心思想是陀螺仪短期准确但会漂移加速度计长期准确但噪声大两者加权融合。#define RAD_TO_DEG 57.295779f #define LOOP_TIME 0.0025f // 2.5ms执行一次即400Hz float angle_pitch, angle_roll; float gyro_pitch, gyro_roll; // ax, ay, az为加速度计原始值gx, gy为陀螺仪角速度 void IMU_Update(float ax, float ay, float az, float gx, float gy, float gz) { float acc_pitch atan2f(-ax, az) * RAD_TO_DEG; float acc_roll atan2f(ay, az) * RAD_TO_DEG; float dt LOOP_TIME; angle_pitch 0.98f * (angle_pitch gx * dt) 0.02f * acc_pitch; angle_roll 0.98f * (angle_roll gy * dt) 0.02f * acc_roll; }代码分三步先用加速度计算出重力方向对应的横滚和俯仰角作为参考姿态再把陀螺仪角速度积分得到预测姿态最后用0.98和0.02这两个系数做加权。0.98是陀螺仪权重0.02是加速度计权重这个比例决定滤波器的“信任倾向”。如果机架振动大把0.02降到0.01角度会更平滑但响应变慢反之调大会出现高频抖动。加速度计对振动极其敏感传感器底部最好垫一块减震海绵这属于结构设计但直接影响滤波效果。不建议第一次就上官方DMP库。DMP虽然能直接读四元数但库本身耗RAM、耦合重在F103上还要处理中断优先级和I2C时序。自己写互补滤波30行代码就能覆盖同样需求还清楚每一步在算什么。3.2 串级PID控制环为什么角度外环要套角速度内环单级PID直接用角度误差算电机输出本质是在控制一个二阶系统增益稍大就震荡。工程上普遍用串级PID外环把角度误差换算成目标角速度内环再让陀螺仪测到的角速度去跟踪这个目标。外环100Hz内环400Hz内环响应快可以提前抑制扰动。float Kp_angle_roll 5.0f; // 外环角度P // 外环角度环输出目标角速度单位°/s float pid_angle_roll(float target_angle, float measure_angle) { float err target_angle - measure_angle; return Kp_angle_roll * err; } // 内环角速度环带积分限幅和微分 float pid_rate_roll(float target_rate, float measure_rate) { static float integral 0.0f; static float last_err 0.0f; float err target_rate - measure_rate; integral err * LOOP_TIME; integral CLAMP(integral, -10.0f, 10.0f); // 积分限幅 float output Kp_rate * err Ki_rate * integral Kd_rate * (err - last_err); last_err err; return output; }内环的积分项用于消除静差但悬停时积分容易越积越深必须限幅。微分项对噪声敏感如果陀螺仪波形不够干净Kd先设0飞稳了再加。外环不需要积分因为内环已经把静态误差吃掉了再加积分会让回中变得拖沓。调参顺序是铁律先调内环P让飞机响应角速度输入不振荡再加外环P让飞机能回中最后才碰内环I和D。反过来调基本调不出来。3.2.1 一组能用的PID初始值和调整方向网上的PID参考值永远只能当起点因为机架重心、电机响应速度、电池内阻都不一样。下面这份参数适合X型布局的有刷小四轴配2.5ms内环周期参数初始值调整方向P_angle外环P5.0回中慢→加大超调明显→减小P_rate内环P0.20自激振荡→减小打舵迟钝→加大I_rate内环I0.05悬停漂移→小步长加D_rate内环D0.00高频抖动→从0.02试探注意积分和微分没调之前都要保持小值。如果飞机悬停时往一个方向缓慢漂移先检查重心和摇杆中位不要急着加积分。3.3 电机混控把Roll、Pitch、Yaw输出分配到四个电机姿态环输出的Roll、Pitch、Yaw是三个力矩请求最终要转成四路PWM脉宽。X型四轴四个电机位置和旋转方向都不同混控公式必须与安装方向自洽#define PWM_MIN 1000 // 无刷电调方案单位μs #define PWM_MAX 2000 void mix_motor(float thr, float roll, float pitch, float yaw) { float m[4]; m[0] thr roll pitch yaw; // 右前逆时针 m[1] thr - roll pitch - yaw; // 左前顺时针 m[2] thr - roll - pitch yaw; // 左后逆时针 m[3] thr roll - pitch - yaw; // 右后顺时针 for (int i 0; i 4; i) { if (m[i] PWM_MIN) m[i] PWM_MIN; if (m[i] PWM_MAX) m[i] PWM_MAX; } TIM1-CCR1 (uint32_t)m[0]; TIM1-CCR2 (uint32_t)m[1]; TIM1-CCR3 (uint32_t)m[2]; TIM1-CCR4 (uint32_t)m[3]; }混控的核心是加减关系横滚正指令让右边电机加速、左边减速俯仰正指令让前方电机加速、后方减速偏航正指令让逆时针电机加速、顺时针电机减速。Yaw的符号取决于电机实际旋转方向第一次试飞发现飞机原地打转优先回来核对这一项。限幅要放在混控之后统一做不能在每个PID输出处单独限幅否则某个通道先饱和极限状态下姿态会失控。TIM1的PWM周期怎么配也影响代码无刷电调方案把定时器配成1ms周期72MHz主频下PSC71、ARR999CCR直接填微秒数省掉换算有刷方案把频率提到8kHz以上CCR填的是占空比计数混控输出的上下限要改成0至ARR。4. 遥控器源代码摇杆采集、nRF24L01数据帧与失控保护4.1 摇杆通道采集ADC多通道配合DMA遥控器端的四根操控杆输出模拟电压用ADC1扫描四个通道采集。强烈建议用DMA循环模式保证四个通道数据在同一个时间点被捕获否则飞控端会看到“油门没动、俯仰先跳”的错位数据。#define CH_NUM 4 uint16_t adc_buf[CH_NUM]; float ch_value[CH_NUM]; // 归一化到 0.0 ~ 1.0 void ADC1_Init_DMA(void) { // CubeMX配置ADC1扫描4通道DMA循环模式数据宽度半字 HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, CH_NUM); } // 把ADC原始值线性映射到0~1 float normalize(uint16_t raw) { return (float)(raw - 400) / (3200.0f - 400.0f); }摇杆电位器中点不一定等于ADC量程的中点机械回中位置有偏差。所以归一化之后要做死区俯仰和横滚通道当值在0.48到0.52之间时强制输出0.5防止飞机悬停时因为摇杆不回中而缓慢漂移。油门通道不做死区要能精确微调。摇杆电位器的供电要取自LDO稳压输出不能直接接电池电压否则旋钮输出的比例会随电池放电漂移遥控器在中位时飞控端看到的却是一边倒的角度命令。4.2 nRF24L01数据帧设计固定长度加校验nRF24L01工作在2.4GHzSPI接口支持Enhanced ShockBurst自动应答和重发。遥控器作为发送方飞控作为接收方两端必须配置相同的射频信道、空中速率和地址。建议把payload固定为8字节字节偏移01234567内容帧头0xAA帧头0x55油门俯仰横滚偏航按键状态校验和帧头用来快速定位一包的起点校验和用来发现被干扰破坏的数据。发送端打包代码非常直接uint8_t tx_buf[8]; void build_packet(void) { tx_buf[0] 0xAA; tx_buf[1] 0x55; for (int i 0; i 4; i) { tx_buf[2 i] (uint8_t)(ch_value[i] * 255.0f); } tx_buf[6] button_unlock_flag; // bit0为解锁 uint8_t sum 0; for (int i 0; i 7; i) { sum tx_buf[i]; } tx_buf[7] sum; }发送前先查帧头再加累加和校验通过才更新控制量失败的包直接丢弃绝不能用错数据去更新姿态目标。空中速率方面1Mbps在延迟和距离之间比较均衡250kbps距离最远但延迟偏高室内飞小四轴一般用不到。4.2.1 丢包与失控保护逻辑无线链路不可能保证不丢包飞控必须在丢包时执行安全动作。接收端维护一个超时计数每收到一包有效数据就清零超过50ms没收到新包就进入失控保护uint8_t link_lost 0; uint16_t packet_gap 0; // 在1ms定时器中断里调用 void Link_Check(void) { if (packet_gap 50) { link_lost 1; target_pitch 0.5f; target_roll 0.5f; target_yaw 0.5f; throttle_cmd 0.0f; // 油门归零 } }第一版失控保护只要求安全油门归零防止电机在丢失信号后继续狂转。后续想做得更稳可以区分“地面失控”和“空中失控”空中先保持30%油门缓慢下降等检测到接触地面再完全关停。但前提是飞控有可靠的定高数据否则不如直接归零。4.3 双机联调顺序先通链路再通控制联调最忌讳一上来就上电带桨。正确顺序是先把无线模块插在开发板上遥控器端每100ms发一组带递增序号的数据包飞控端通过串口打印收到的序号观察序号是否连续。有跳包说明丢包率偏高优先查NRF模块供电、天线净空区和信道干扰。链路稳定后飞控接上电调但拆掉桨叶用扎带把机架固定在桌面上手推油门观察四个电机转速横滚右打右侧电机应该加速俯仰前推前方两个电机应该加速。方向没验证之前千万不要松手试飞。5. 原理图与PCB图设计电源树、布局布线与打样参数5.1 原理图设计要点电源、晶振和下载接口一个不能少飞控原理图的难点不在MCU引脚怎么连而在电源网络能不能扛住电机大电流冲击。以1S电池为例电机堵转瞬间母线电流可能到5A以上电池线先到MOS管再分叉给LDO电源输入路径尽量短。电源树参考如下电源节点来源稳压方式负载VBAT 3.7V电池直连粗走线预留分压检测电机、MOS管VCC_3.3VVBAT经LDOME6211并10μF0.1μFMCU、MPU6050、nRF24L018MHz晶振的两个负载电容放在晶振与MCU引脚之间走线要短不要打过孔外壳接地。复位引脚接10kΩ上拉和100nF电容防止电机启动瞬间电压跌落导致复位。BOOT0接10kΩ下拉保证从Flash启动。SWD调试接口四根线SWDIO、SWCLK、GND、3.3V一定要引出来串口ISP烧录效率太低项目后期调试会非常痛苦。5.1.1 原理图常见错漏检查画原理图最容易漏的是MOS管的续流二极管和栅极下拉电阻。二极管用SS34栅极对地加10kΩ下拉防止单片机复位瞬间GPIO为高电平导致电机意外转动。另一个高频错误是nRF24L01的CE和CSN引脚没接上拉导致模块无法进入待机模式收发一直失败。5.2 PCB布局布线重心、干扰和散热一起考虑飞控PCB建议直接做四层板中间一层完整GND一层电源平面。四层板的回流路径短电机PWM大电流产生的干扰被约束在地平面内部MPU6050读数的毛刺会明显减少。遥控器端对干扰要求没那么高两层板也能用但底层一定要大面积铺地铜。布局顺序是固定套路电池座在机架尾部MOS管靠近电机输出端子MPU6050放在板子正中心且方向与机架对齐nRF24L01边缘伸出板边MCU在传感器与电源之间。这个顺序一旦错位重心偏移、IMU离电机太近、射频被遮挡的问题会同时出现后期极难纠正。走线有几条硬规矩电池电源线宽不小于1mmMOS管到电机端子直接用铺铜信号线短距离走完不要绕到电源平面下方MPU6050的I2C信号线要短且平行nRF24L01天线区域所有层都挖空四层板也不能在下面铺GND否则天线方向图被破坏。5.3 打样前必须确认的参数速查发板前的检查清单可以直接对着下面这张表逐项过项目常用参数说明板厚1.6mm飞控和遥控器统一铜厚1oz电流余量足够最小线宽/间距6mil/6milF103的LQFP48封装可以更细但没必要过孔内径0.3mm外径0.6mm太小会加钱表面处理沉金传感器引脚小喷锡易不平整天线净空区板边内侧≥10mm正下方所有层挖空下单前先把原理图的ERC电气规则检查跑完清掉所有未连接的飞线再确认MOS管的S极铺铜面积够大散热不足是返工最常见的原因。6. 程序烧录、串口调试与PID参数整定6.1 从CubeMX配置到Keil烧录运行F103开发环境建议用STM32CubeMX生成初始化代码再配合Keil MDK编译。在CubeMX里选好芯片型号时钟树配到72MHz外设按前面的分配表打开I2C1、SPI1、TIM1、ADC1和USART1。Keil里注意F1的Device Family Pack要装好如果电脑上之前装过C51开发环境MDK一定不要装到同一目录否则两个工具链互相覆盖最常见的现象是编译时找不到设备头文件。下载用ST-Link或DAP-Link接线四根。在Keil的Debug设置里选好下载器、SW口模式Flash Download勾上Reset and Run烧完自动复位运行。F103C8T6的Flash是64KB如果程序编译接近满了先去查是不是开了太多调试打印。6.2 printf重定向飞控调试的最小可行工具对着源码调四轴最痛的不是代码写不出来而是看不到飞机内部状态。把printf重定向到USART1是目前最轻量的调试通道int fputc(int ch, FILE *f) { while (!(USART1-SR USART_SR_TXE)); USART1-DR ch; return ch; }然后在主循环里周期输出角度值、角速度值和PID输出值。上位机可以用匿名飞控地面站也可以自己写一个简单的Python串口绘图脚本都能把波形画出来。一个我反复用的技巧把原始角度和滤波后角度同时打印两条曲线的吻合度能直接暴露互补滤波系数是否匹配振动环境。再打印内环积分项看它在悬停过程中有没有长期顶着限幅值。积分常年顶满说明重心或外环参数有系统性问题该回头检查机械结构而不是继续调Kd。6.3 从串口波形快速定位振荡的三个特征最后分享一个调试经验。角速度波形出现几百赫兹的高频正弦振荡基本是内环P或D太大角度波形出现两三赫兹的低频摆动是外环P太大、飞机在反复追目标角度悬停时角度缓慢朝一个方向漂移先查遥控器中位死区和机架重心再决定要不要加积分。串口数据永远比手感可靠记住这三个特征试飞时就不用盲调参数了。本文还有配套的精品资源点击获取
返回列表