STM32四旋翼飞控实战:从动力学建模到串级PID调参
2026/9/19 17:01:49 网站建设 项目流程

简介:这份PDF文档面向无人机控制、嵌入式开发方向的学习者与工程人员,围绕四旋翼无人机受干扰时姿态控制效果差的问题,给出了一套基于STM32与深度学习的控制系统设计方案。内容涵盖系统总体设计、软件功能模块划分、电机驱动、电源管理、无线通信等环节,并引入MEMS传感器采集姿态数据、NRF51822芯片实现远距避障,同时提出区域卷积神经网络(R-CNN)用于控制算法设计,配合仿真实验验证控制效果。资源包共1个PDF文件,约301KB,下载后可直接查阅完整设计思路与模块实现细节。目前已有294人学习浏览,适合希望了解四旋翼飞控架构、深度学习姿态控制方法及硬件选型思路的读者参考,对军事侦察、环境监测、森林防火、农业植保等应用场景的控制系统设计具有一定借鉴价值。

1. 从一份 PDF 标题说起:四旋翼控制系统到底在控什么

很多人第一次接触四旋翼,是从一份《四旋翼无人机控制系统设计分析.pdf》这类文档开始的。翻开来满屏是欧拉角、PID、卡尔曼滤波,合上文档却不知道从哪下手。问题不在数学,而在于没搞清楚控制系统的边界:它要控的不是“飞机”,而是四个电机转速的协同关系,通过改变四个旋翼的升力差,间接控制姿态和位置。

四旋翼是欠驱动系统,六个自由度只有四个独立控制量,俯仰、横滚、偏航、高度耦合在一起。所以控制系统的核心任务分两层:内环用姿态控制把机体稳住,外环用位置控制让它飞到该去的地方。内环跑得慢一点,外环就发散;内环噪声大一点,外环就抖。这套分层结构决定了后面所有代码和参数的写法。

适合读这篇的人有三类:正在做基于 STM32 的四旋翼毕业设计的学生、想从零搭一架能悬停的机架的工程师、以及手上有飞控板但调不出稳定姿态的开发者。下面按“建模—姿态环—位置环—调参排错”的顺序,把一份设计分析文档里该有的东西落到能跑的命令和参数上。

2. 四旋翼动力学建模与 STM32 控制框架搭建

2.1 从牛顿-欧拉方程到可编程的简化模型

四旋翼的完整动力学模型包含刚体运动方程和旋翼气动模型,直接搬进 STM32 不现实。常见做法是保留姿态动力学,把气动效应简化为升力系数和反扭矩系数。姿态角加速度与电机转速平方差的关系可以写成:

Ixx * p_dot = L * kf * (w2^2 + w3^2 - w1^2 - w4^2) Iyy * q_dot = L * kf * (w1^2 + w3^2 - w2^2 - w4^2) Izz * r_dot = kd * (w1^2 - w2^2 + w3^2 - w4^2)

其中L是机臂长度,kf是升力系数,kd是反扭矩系数,w1~w4是四个电机的转速。这个模型的意义在于:它把控制问题变成了“给定目标力矩,反解四个电机转速”的分配问题。实际写代码时不会真的解这个方程,而是用混控矩阵把 PID 输出的三个力矩和油门映射到四个 PWM 通道。

注意:kfkd随桨叶和电压变化,不要照抄别人的数值。用拉力计测一组“油门-PWM-拉力”数据,拟合出系数,比任何仿真都准。

2.2 STM32 最小系统与外设分配

选 STM32F4 系列做飞控是常见方案,主频够跑 1kHz 的姿态环,浮点单元省去定点换算的麻烦。外设分配上,四个电机 PWM 用同一个定时器的四个通道,保证更新同步;IMU 走 SPI 或 I2C,MPU6000/ ICM20602 这类六轴是主流;遥控接收机用 UART 或 PPM 输入。

下面是一个用 HAL 库初始化 TIM3 四通道 PWM 的片段,频率设 400Hz,对应电调的标准协议:

// TIM3 四通道 PWM 初始化,400Hz,分辨率 2000 步 TIM_HandleTypeDef htim3; htim3.Instance = TIM3; htim3.Init.Prescaler = 84 - 1; // 84MHz / 84 = 1MHz 计数时钟 htim3.Init.Period = 2500 - 1; // 1MHz / 2500 = 400Hz htim3.Init.CounterMode = TIM_COUNTERMODE_UP; HAL_TIM_PWM_Init(&htim3); TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 1000; // 初始 1ms,电调解锁最低值 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1); // 通道 2/3/4 同样配置,对应四个电机 HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

逻辑说明:预分频把 84MHz 降到 1MHz,周期值 2500 得到 400Hz 的 PWM 频率,脉宽 1000~2000 对应电调的 1ms~2ms 行程。参数上,Pulse的初始值必须设在电调解锁范围的下限,否则上电瞬间电机会转。四个通道用同一个定时器,是为了让四路 PWM 的更新时刻严格对齐,避免混控输出时产生相位差。

2.3 传感器数据读取与姿态解算的落地方式

姿态解算不用一上来就上卡尔曼。工程上先用互补滤波把陀螺仪和加速度计融合,代码短、参数直观,跑通了再换 Mahony 或 Madgwick。互补滤波的核心是一行:

// 互补滤波:陀螺积分 + 加速度计修正 angle = 0.98 * (angle + gyro * dt) + 0.02 * accel_angle;

0.98是信任陀螺的权重,dt是采样周期。这个系数不是随便定的:它决定了高通和低通的截止频率,0.98对应大约 0.5Hz 的交叉点,适合大多数机架。如果飞机在悬停时缓慢漂移,说明加速度计权重太低;如果电机振动一大角度就跳,说明陀螺权重太高,需要先做机械减振再调这个数。

3. 姿态控制环的 PID 实现与参数整定

3.1 串级 PID 的结构与代码骨架

姿态控制用串级 PID:外环角度环,输入是目标角度和当前角度,输出是目标角速度;内环角速度环,输入是目标角速度和陀螺仪读数,输出是力矩。串级的好处是内环把扰动吃掉,外环只管跟踪角度,两个环的参数可以分开调。

// 串级 PID 姿态控制,1kHz 调用 float angle_pid(float target, float current, float gyro, float dt) { static float integral = 0; float err = target - current; integral += err * dt; // 外环:角度误差 -> 目标角速度 float target_rate = KP_ANGLE * err + KI_ANGLE * integral; // 内环:角速度误差 -> 力矩 float rate_err = target_rate - gyro; return KP_RATE * rate_err; }

逻辑说明:外环的积分项用来消除角度静差,内环只用比例项,因为角速度环的积分容易和陀螺零偏打架。参数上,KP_ANGLE决定回中力度,一般从 4.0 开始试;KP_RATE决定阻尼,太小会震荡,太大响应迟钝。dt必须用实际循环周期,不能用标称值,否则积分项会累积错误。

3.2 三个必调参数与整定顺序

姿态环有三个参数必须现场调:角度环 P、角速度环 P、角速度环 I。整定顺序是先把角度环 P 设 0,只调角速度环 P,用手拨动机架感受反作用力,直到松手后机架能快速停住但不来回摆。然后加角速度环 I,消除匀速转动时的角速度误差。最后加角度环 P,让机架能回到水平。

参数作用起始值调大后果调小后果
KP_ANGLE回中力度4.0高频抖动回中无力
KP_RATE角速度阻尼0.15响应迟钝震荡发散
KI_RATE消除角速度静差0.02低频摆动匀速漂移

注意:调参必须在解锁但不起飞的条件下做,桨叶拆掉或电机不转。带桨调参一旦参数发散,机架会直接翻掉。

3.3 混控矩阵与电机输出限幅

PID 算出三个力矩后,要通过混控矩阵分配到四个电机。X 型机架的混控关系是:

// X 型混控:roll/pitch/yaw 力矩 + 油门 -> 四电机 motor[0] = throttle - roll + pitch + yaw; // 右前 motor[1] = throttle - roll - pitch - yaw; // 右后 motor[2] = throttle + roll - pitch + yaw; // 左后 motor[3] = throttle + roll + pitch - yaw; // 左前 // 限幅到 1000~2000 for (int i = 0; i < 4; i++) { if (motor[i] > 2000) motor[i] = 2000; if (motor[i] < 1000) motor[i] = 1000; }

逻辑说明:混控矩阵的符号取决于电机转向和桨叶正反,装反一个电机,飞机就会往反方向翻。限幅是必须的,否则某个电机饱和后,另外三个电机的补偿量会失真,姿态直接失控。参数上,throttle是遥控油门映射到 1000~2000 的值,roll/pitch/yaw是 PID 输出经过缩放后的力矩量,缩放系数决定了最大修正力度。

4. 位置环、定高与 STM32 上的资源分配

4.1 高度控制的气压计融合与油门补偿

定高用气压计,但气压计噪声大、受气流影响明显。常见做法是把气压计高度和加速度计积分高度做互补滤波,再用一个单环 PID 控制油门。气压计的数据不能直接用,要先做滑动平均,窗口取 10~20 个采样点。

// 气压计滑动平均 + 高度 PID #define WIN 15 static float baro_buf[WIN]; static int idx = 0; baro_buf[idx] = baro_raw; idx = (idx + 1) % WIN; float baro_avg = 0; for (int i = 0; i < WIN; i++) baro_avg += baro_buf[i]; baro_avg /= WIN; // 高度误差 -> 油门补偿 float alt_err = target_alt - baro_avg; throttle_comp = KP_ALT * alt_err + KD_ALT * (alt_err - last_alt_err) / dt;

逻辑说明:滑动平均抑制气压计的高频噪声,但会引入相位滞后,所以WIN不能太大。高度环用 PD 不用 I,因为油门本身有积分特性,再加积分会振荡。参数上,KP_ALT从 0.5 开始,KD_ALT从 0.2 开始,调的时候观察飞机是缓慢下沉还是上下窜。

4.2 位置环与光流/ GPS 的接口预留

位置环在室内用光流,室外用 GPS。STM32 上不需要跑复杂的视觉算法,光流模块通过 UART 输出速度,GPS 通过 UART 输出经纬度。位置环的输入是水平速度,输出是目标俯仰角和横滚角,交给姿态环执行。

// 位置环:速度误差 -> 目标角度 float vel_err_x = target_vel_x - flow_vel_x; target_pitch = KP_POS * vel_err_x; // 限幅,防止目标角度过大导致姿态环饱和 if (target_pitch > 15.0f) target_pitch = 15.0f; if (target_pitch < -15.0f) target_pitch = -15.0f;

逻辑说明:位置环的输出是角度,所以必须限幅。15度是经验值,对应最大水平加速度约 2.5m/s²,再大姿态环就跟不上了。参数上,KP_POS决定速度跟踪的快慢,太大飞机会前后冲,太小位置漂移压不住。

4.3 STM32 上的任务调度与 CPU 占用

1kHz 的姿态环、100Hz 的位置环、50Hz 的遥控解析,这三个任务不能放在同一个循环里顺序执行。常见做法是用定时器中断触发姿态环,主循环跑位置环和遥控,中间用标志位同步。STM32F4 跑 1kHz 浮点 PID 加混控,CPU 占用大约 30%,留出的余量给日志和通信。

注意:不要在中断里做浮点除法或打印,中断服务函数只置标志位,实际计算放到主循环。否则中断执行时间过长,PWM 更新会抖动。

5. 试飞排错与参数微调的实战技巧

5.1 从地面测试到悬停的检查清单

第一次试飞前,先做三项地面测试:电机转向和混控方向是否一致、姿态解算的角度是否跟手转动方向一致、失控保护是否在遥控断连时把油门降到最低。这三项任何一项错了,起飞就是炸机。地面测试通过后,第一次悬停把油门缓慢推到刚好离地,观察飞机是往哪边偏,用微调修正,不要急着改 PID。

5.2 震荡、漂移、翻跟头的故障定位

震荡分高频和低频。高频震荡是角速度环 P 太大,降 20% 再试;低频摆动是角速度环 I 太大,降一半。漂移分角度漂移和位置漂移,角度漂移是陀螺零偏没校准,上电时保持静止重新校准;位置漂移是光流或气压计受气流干扰,加海绵减振或换安装位置。翻跟头只有两种可能:电机转向错或混控符号错,对照混控矩阵逐个检查。

5.3 用日志回放定位参数问题

STM32 的 Flash 或 SD 卡记录姿态环的输入输出,试飞后把数据导出来画曲线。目标角度和实际角度的相位差超过 90 度,说明角速度环带宽不够;实际角速度有周期性尖峰,说明电机振动耦合进了陀螺。日志不用记太多,姿态角、角速度、四个电机输出,四个量足够定位大部分问题。

# 用 Python 画姿态日志,快速看跟踪效果 import matplotlib.pyplot as plt import numpy as np data = np.loadtxt('flight_log.csv', delimiter=',') plt.plot(data[:,0], data[:,1], label='target_roll') plt.plot(data[:,0], data[:,2], label='actual_roll') plt.legend() plt.show()

逻辑说明:flight_log.csv每行是时间、目标角度、实际角度、角速度、电机输出。画出来看两条曲线的重合度和相位差,比盯着飞机猜参数快得多。参数上,采样率至少 200Hz,否则角速度的细节会被混叠掉。

5.4 从 PID 到 LQR 的过渡时机

PID 调到头,跟踪效果还是上不去,再考虑 LQR。LQR 需要状态空间模型,把姿态角和角速度作为状态量,解黎卡提方程得到反馈增益。STM32 上跑 LQR 不是问题,问题是模型不准,增益算出来还不如 PID。常见做法是先用 PID 飞稳,采集实际数据辨识模型参数,再用辨识结果算 LQR 增益。这一步没有捷径,模型辨识的激励信号和数据处理比 LQR 本身更花时间。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询