四旋翼是典型的欠驱动系统,四个输入要控制六个自由度,位置和姿态天然耦合在一起。期刊论文里最常见的做法就是把控制器拆成内外两个环路:内环管姿态、外环管位置,然后用PID把每个通道单独伺候好。这篇就来拆解这种控制结构从论文到仿真的完整落地过程。
先说清楚我复现的是哪种结构。论文里的控制框图通常长这样:外环接收期望位置,解算出期望姿态角,内环再跟踪这个姿态角信号。整个控制链路是位置环在前、姿态环在后,姿态环的响应速度要明显快于位置环,两个环路才能解耦。很多人第一次看论文会困惑,为什么四旋翼不直接对位置做PID,非要绕一道姿态。答案很简单:四旋翼的推力方向必须靠倾斜机体来改变,想往东飞,得先把机头或者机身朝东倾,这个倾斜动作就是姿态环干的活。所以外环的输出不能直接是油门量,而必须是姿态指令。
1. 控制架构设计的核心思路
1.1 为什么内外环结构是四旋翼控制的主流方案
先说结论:内外环结构本质上是一种级联控制,它把耦合强、非线性明显的系统拆成了两个带宽不同的回路。内环频带高、响应快,专门处理角速度和角加速度这类快变量;外环频带低、响应慢,只负责位置变化这类慢变量。这样做的好处是内环可以先把飞行器“稳住”,外环才有条件去执行轨迹跟踪。
你可以把这种结构类比成开车时的驾驶员和导航的关系。导航告诉你在哪个路口拐弯,这是外环,输出的是方向指令;真正握着方向盘精确调整角度、对抗侧风的是驾驶员,这是内环。导航不需要精确知道路面有多滑、方向盘要打多少度,它只需要给出“方向目标”,剩下的动态补偿全部交给驾驶员。四旋翼的控制器设计就是这个思路:位置控制器当导航,姿态控制器当驾驶员。
从控制理论角度讲,级联结构还带来了一个额外的好处,就是抗干扰能力增强。风扰、桨叶振动这些扰动主要作用在姿态层面,内环的高带宽能迅速把扰动压下去,外环根本感觉不到太多波动。如果只做一个大环路直接对位置做PID,扰动信号要穿越整个控制链路才被修正,中间的时间延迟足够让飞行器偏出去很远了。
还有一个实际层面的原因:传感器能力不同。一般的飞控上,IMU(惯性测量单元)输出姿态和角速度的频率可以到500Hz甚至1000Hz,而GPS或视觉定位的位置更新频率通常只有5到20Hz。内外环结构天然匹配这种传感器频率差异,姿态环用高频率快响应,位置环用低频率慢响应,不需要人为做复杂的信号同步。
1.2 位置环与姿态环的职责划分和信号传递
在具体的控制器结构里,位置环有三个输入:期望位置(通常来自遥控器摇杆或轨迹规划器)、当前实际位置、当前实际速度。位置环的输出经过几何关系解算,变成期望的横滚角、俯仰角以及总推力指令。姿态环的输入则是这个期望角度、当前角度和当前角速度,输出是三个轴的力矩指令,最终混控成四个电机的转速指令。
这里有一个很多人容易忽略的细节:外环解算出来的期望角,不是简单的线性输出。以水平位置控制为例,X方向的期望加速度和目标横滚角的转换关系是:
phi_cmd = arcsin( mx_ddot / (m * g) )(做线化简化时直接取比例),实际上论文里常用的简化形式是:
theta_cmd = Kp_x * (x_cmd - x) + Kd_x * (vx_cmd - vx)
这个期望角再限幅,比如限制在30度以内,然后传给内环。如果不做限幅,外环在位置偏差很大的时候会解算出一个夸张的角度指令,内环就算响应再快也会被推到物理极限,飞机会直接翻过去。这是从论文到实际代码里必须补上的安全逻辑,很多论文正文不会写,但在附录的安全说明里会提到。
姿态环一般也做两层:外层角度环用P控制或PD控制,内层角速度环用PID控制。为什么角速度环要加I项,角度环通常只加PD?因为角速度环面对的扰动最直接,比如电机转速不一致、重心偏移产生的常值力矩干扰,I项可以把这个常值偏差消掉。而角度环在正常情况下没有常值输入偏差,加了I反而容易因为积分饱和造成超调和振荡。
2. 核心细节解析与实操要点
2.1 控制量的来源和含义
四旋翼控制的最终目的,本质上是算四个螺旋桨的转速。中间链路大概是:位置误差 -> 期望姿态角 -> 期望角速度 -> 期望力矩 -> 期望升力 -> 四个转速指令。
拿一个具体的时刻举例,假设飞行器悬停在高空,此时风把飞机向东吹了1米。外环位置控制器检测到X方向偏差为-1米,通过PD计算得到一个正的期望横滚角,比如5度。接着姿态环收到“滚转到5度”的指令,角度控制器输出期望横滚角速度,角速度控制器再根据当前角速度算出需要的滚转力矩,滚转力矩对应的是左右两侧电机的转速差。左侧电机加速、右侧电机减速,机体向右倾斜,推力方向改变,水平分量把飞机推回目标位置。整个过程从风扰出现到姿态开始响应,典型的响应时间在0.2到0.5秒之间,这就是内外环控制器最核心的工作机制。
2.2 内环外环增益差异的根本逻辑
飞控调参的圈子里流传一句话,“内环优先,外环跟进;先稳姿态,再谈位置”。这句话背后是带宽分离原则——内环闭环带宽通常是外环的3到5倍。位置环给出一个姿态指令后,内环必须迅速到位,外环才能感受到“指令被执行”的结果。如果内环带宽不够,外环看到姿态半天没动静,就会继续加大指令,指令越大幅值越大,内环越跟不上,最后两个环一起振荡。
在实际调试中,内环角速度环的P增益往往是外环位置环P增益的20到50倍量级。比如在仿真里,角速度环Kp可能取8到12,角速度环Kd取0.3到0.6,姿态角环Kp取6到8,位置环Kp取0.8到1.5,位置环Kd取0.3到0.8。这组参数在仿真里可以稳定悬停,上真机的话要根据飞机重量、机臂长度、电机响应特性重新标定。直接从仿真搬到真机几乎必炸,原因在于仿真里的模型参数和真实动力学差异很大,尤其是电机响应延迟和桨叶气动阻尼。
2.3 姿态环的PD与角速度环的PID组合策略
姿态角环和角速度环串在一起,其实是处理同一个物理量——机体旋转状态——的两级不同观测视角。角度是位置的积分,角速度是角度的微分,物理上天然构成一阶串级关系。
姿态角环的表达式是:
p_cmd = Kp_angle * (angle_cmd - angle) - Kd_angle * gyro_rate
注意这里的D项作用在角速度反馈上,而不是作用在角度误差的微分上。这个细节很关键,因为角度误差的微分会放大高频噪声,而直接用陀螺仪的角速度信号来做微分项,噪声水平低得多,还能提供天然的阻尼。这就引出了一个实操要点:姿态环的“D项”直接接在陀螺仪上,叫角速度反馈阻尼,而角速度环的PID中,D项也是同样直接作用在角速度信号上,只是这里的角速度信号其实已经是内回路的主反馈信号,D项主要用来抑制高频振荡,一般数值比较小。
角速度环的完整形式是:
tau_cmd = Kp_rate * (p_cmd - p) + Ki_rate * ∫(p_cmd - p)dt + Kd_rate * (p_dot_cmd - p_dot)
通常情况下p_dot_cmd设为零,因为期望角速度是一个缓变的指令信号,不期望它快速变化。所以D项实际就成了 -Kd_rate * angular_acceleration,提供角加速度阻尼,抑制转速噪声和结构谐振。
在仿真里,姿态环的采样F频率建议设成内环500Hz以上,外环100Hz以上。如果仿真步长太大,内外环的带宽分离就体现不出来,整个系统会变成慢速近似,PID的整定结果会和理论预期差很多。
2.4 位置控制解算中需要处理的坐标系问题
位置控制有一个经典坑:期望位置来自惯性坐标系(NED或ENU),而姿态指令要在机体坐标系执行。外环位置控制器算出的是惯性系下的期望加速度向量,需要通过旋转矩阵转换到机体坐标系才有物理意义。
这里给出常用的解算流程,假设在NED坐标系下(北东地):
- 位置误差 e_pos = pos_cmd - pos_actual
- 速度误差 e_vel = vel_cmd - vel_actual
- 期望加速度 a_cmd = Kp_pos e_pos + Kd_pos e_vel
- 期望总推力 T_cmd = m (g + a_z_cmd) / (cos(phi) cos(theta)),这里的a_z_cmd是惯性系z轴加速度期望
- 期望横滚角 phi_cmd = (a_x_cmd sin(psi) - a_y_cmd cos(psi)) / g(近似小角度版本)
- 期望俯仰角 theta_cmd = (a_x_cmd cos(psi) + a_y_cmd sin(psi)) / g
注意第4步里,期望横滚角和俯仰角是耦合在总推力计算里的。如果机体当前有倾斜角,垂直方向的推力分量会变小,所以总推力要除以cos(phi)cos(theta)。在仿真初期的悬停测试阶段,角度很小,这个修正项接近1,可以省略;但做大机动飞行的轨迹跟踪时,不除这个修正项会出现掉高现象。
第5、6步用的是小角度近似,严密的做法是用姿态矩阵反算欧拉角。论文里通常走严密路线,仿真代码里为了数值稳定往往取近似。我的建议是仿真阶段先用小角度近似,快速验证整体逻辑,等要上真机前再替换成严密的四元数解算。
3. 实操过程与核心环节实现
3.1 建立仿真环境的配置方案
我复现时用的环境是MATLAB/Simulink加R2023b自带的航天模块库,建了一个基本的四旋翼刚体动力学模型。也可以选Python环境,用numpy做矩阵运算配合matplotlib绘图,但Simulink在建模调试的直观性上确实有优势,尤其是中间信号可以直接接scope看曲线。
仿真模型分三层:
- 第一层是输入层:一个信号源模块,拉高保持模拟定点悬停指令,或者用正弦信号模拟轨迹跟踪。
- 第二层是控制器层:内部再切成外环位置控制器模块,内环姿态力矩分配模块。
- 第三层是动力学层:刚体六自由度运动方程和电机响应模型,电机用一阶惯性环节近似,时间常数取0.1秒。
电机模型在仿真里很容易被忽略,但它对参数整定的影响非常大。真实电机从接收PWM指令到转速稳定,大约需要几十到一两百毫秒,这个延迟直接限制了你内环增益能调多大。仿真里如果电机模型用理想阶跃,你调出的内环增益会虚高,真机上必定发散。
3.2 动力模型与PID控制器搭建的关键代码
在MATLAB里,我用了一个.m脚本初始化全部参数,然后Simulink模型引用这些参数。核心参数代码如下:
% 四旋翼物理参数 m = 1.2; % 质量 kg g = 9.81; Ixx = 0.012; % 转动惯量 kg*m^2 Iyy = 0.012; Izz = 0.024; L = 0.24; % 机臂长度 m ct = 8.8e-6; % 拉力系数 cq = 2.9e-7; % 扭矩系数 % 电机模型 tau_motor = 0.1; % 电机时间常数 s % 位置环PID Kp_pos_x = 1.2; Kd_pos_x = 0.6; Ki_pos_x = 0.02; Kp_pos_y = 1.2; Kd_pos_y = 0.6; Ki_pos_y = 0.02; Kp_pos_z = 1.8; Kd_pos_z = 1.2; % 姿态环PID Kp_phi = 6.5; Kd_phi = 0.35; Kp_theta = 6.5; Kd_theta = 0.35; Kp_psi = 3.0; Kd_psi = 0.15; % 角速度环PID Kp_p = 8.5; Ki_p = 0.15; Kd_p = 0.35; Kp_q = 8.5; Ki_q = 0.15; Kd_q = 0.35; Kp_r = 5.0; Ki_r = 0.10; Kd_r = 0.20; % 控制限幅 max_angle = deg2rad(30); max_rate = deg2rad(150); max_thrust = m * g * 2;这段参数可以当初始参考值,但不建议盲抄。不同飞机惯性参数不同,电机响应时间不同,实际最优参数会有明显偏移。正确流程是先根据论文给的理论模型参数算出控制器增益初值,再用仿真调到性能指标满足要求,最后真机微调。
3.3 控制器实现的Simulink信号链路
Simulink里的控制链路从右往左排布比较直观。最右侧是状态输入端口,接收惯性位置、速度、姿态角、角速度。中间是外环位置控制器:
- 位置误差经过增益模块得到期望加速度。
- 通过触发模块把X/Y方向加速度换算成期望横滚角和俯仰角,这一步用MATLAB Function模块写坐标变换逻辑,里面就两行atan2运算。
- Z方向加速度直接走到推力计算模块。
左侧内环姿态控制器,也用一个MATLAB Function模块做核心计算:
function [tau_x, tau_y, tau_z, thrust_total] = attitude_controller(...) % 角度环 p_cmd = Kp_phi * (phi_cmd - phi) - Kd_phi * p; q_cmd = Kp_theta * (theta_cmd - theta) - Kd_theta * q; r_cmd = Kp_psi * (psi_cmd - psi) - Kd_psi * r; % 角速度环 tau_x = Kp_p * (p_cmd - p) + Ki_p * integral_p - Kd_p * p_dot; tau_y = Kp_q * (q_cmd - q) + Ki_q * integral_q - Kd_q * q_dot; tau_z = Kp_r * (r_cmd - r) + Ki_r * integral_r - Kd_r * r_dot; % 推力解算:四个电机 F_total = m * (g + az_cmd) / (cos(phi)*cos(theta)); F_total = min(F_total, max_thrust); % 混控 w1_sq = F_total/(4*ct) - tau_x/(2*ct*L) - tau_y/(2*ct*L) - tau_z/(4*cq); w2_sq = F_total/(4*ct) - tau_x/(2*ct*L) + tau_y/(2*ct*L) + tau_z/(4*cq); w3_sq = F_total/(4*ct) + tau_x/(2*ct*L) + tau_y/(2*ct*L) - tau_z/(4*cq); w4_sq = F_total/(4*ct) + tau_x/(2*ct*L) - tau_y/(2*ct*L) + tau_z/(4*cq); % 限幅保护 w_sq = max(w_sq, 0); end这里的混控矩阵是标准的X型四旋翼布局,注意各个电机的正负号取决于你的机架定义。如果装错了符号,飞机的横滚响应会和控制器期望的相反,一推油门就直接翻转,这是真机上最惨烈的炸机方式,没有之一。
3.4 PID参数整定的实操方法
这部分是复现论文时最花时间的地方。我给出一套我实际使用的整定流程:
第一步,先把外环位置控制器去掉,只保留姿态环。给一个期望悬停姿态指令,比如零度横滚、零度俯仰,不放位置反馈,观察姿态环能不能稳。先调角速度环P,从小到大加,直到姿态出现等幅振荡或者明显高频抖动,然后回调60%到70%;再加D项消除高频抖动;最后加很小量的I项消稳态误差。
第二步,把位置环加进来。位置环P先给一个很小的值,比如0.2,观察飞行器能不能缓慢回中。位置环Kp太小了飞机会漂移,太大了会来回振荡。调整Kp让回中过程尽量不要有明显的超调,再加Kd增加阻尼。
第三步,联合调试。位置环带宽低于姿态环3到5倍的原则在这里体现:如果悬停时出现低频振荡,比如一两秒一个来回,优先降低位置环Kp,而不是去调姿态环。如果出现高频振荡,频率在10Hz以上,优先回退姿态环增益。
我在这套流程中实际踩过最深的一个坑是:位置环P给的过大。当时在仿真里调到位置环P有3.0,悬停响应极快,但姿态角指令频繁去顶限幅值,导致飞行器出现周期性的“点头”现象。降回1.2以后,姿态指令不再饱和,响应反而更干净。
4. 常见问题与排查技巧实录
4.1 外环响应太慢,飞机飘得厉害
这种问题最典型的特征是飞行器会缓慢漂移,位置环要好几秒才能拉回来。排查步骤是:先加位置环Kp,注意是加位置环不是加姿态环,同时观察位置曲线是否收敛;如果加了Kp之后开始来回抖动,回退到之前的60%左右,再加Kd。
还有一种可能是传感器反馈延迟造成的相位滞后。仿真里位置信号直接从模型接出来,没有延迟,但真实GPS信号更新频率低、延迟大,外环Kp会被迫调得偏小。可以试试在位置信号路径上串联一个低通滤波或者状态估计器,效果比盲目调增益好得多。
4.2 姿态环出现高频振荡,20Hz以上
高频振荡几乎都是角速度环增益过大或者D项过小。降低角速度环Kp是最直接的方案,但降太多会让响应变慢。更好的办法是同步微调Kd,Kd增大可以抑制高频,但过大的Kd会引入测量噪声放大。
仿真模型里的传感器噪声一般是按理想情况处理的,不会出现真机上陀螺仪的高频噪声问题。但Simulink里如果用了变步长求解器,局部步长太小会让导数计算产生数值噪声。可以试着固定步长用1e-4秒,通常能消除一部分数值抖动。
4.3 积分饱和导致的过冲
悬停时受风扰产生位置偏离,位置积分项会逐渐累积。当扰动消失后,积分项仍然存在,导致飞行器冲过头,然后反向再冲回来。经典的解决办法是抗积分饱和处理:在积分项输出限幅,或者在误差反向时清零积分。
我在仿真中用的是条件积分法,当位置误差大于设定阈值(比如0.5米)时暂停积分,误差回到阈值以内再恢复积分。这样大风扰下不会积累很大的积分量,同时静态误差还是能消除。代码实现很简单:
if abs(e_pos) < 0.5 integral = integral + e_pos * dt; else integral = 0; end4.4 偏航通道不稳定,机头乱转
偏航通道的问题往往出在力矩混控环节。四旋翼偏航力矩由四个电机的反扭矩差决定,如果推力通道的转速饱和,偏航力矩可能会同时被削弱,造成偏航响应迟缓。排查时先把偏航环增益降下来,观察偏航通道单通道响应。正常情况下偏航角应该平稳收敛,如果持续等幅振荡,检查一下偏航力矩的方向符号,这个在仿真里也很容易写反。
4.5 控制器参数与论文对不上
这是复现论文中最让人头疼的问题。论文里的PID参数是针对特定机型、特定质量、特定转动惯量的,你换了参数在另一台飞机上仿真,性能自然不一样。不要期望直接抄论文参数能跑得通,正确的做法是根据你自己的模型参数做归一化换算。
最常用的是把位置环Kp按质量归一化:Kp_new = Kp_old * (m_old / m_new)。这个近似在质量差异不大的情况下很有效。姿态环参数按转动惯量归一化,但是比值关系更复杂,建议直接用闭环特征根分析来求。我在复现时遇到过论文给的姿态角Kp是3,我用同样数值去跑完全发散的情况,后来发现是论文用了带惯量归一化的控制器形式,而我的模型没有做这个归一化。
4.6 复现时的调试方法论
最后分享一套完整的问题定位方法。可以在Simulink模型里加一个信号记录仪,把期望位置、实际位置、期望角度、实际角度、四个电机转速指令全部记录到一个数组里,仿真结束后统一画图分析。这个方法比在模型里放一个scope盯着看有效得多,因为四个电机转速指令、六个状态量同时变化,肉眼根本看不过来。
画图时主要观察几个内容:期望位置和实际位置曲线之间的delay和超调量;期望角度和实际角度之间的跟踪误差;电机转速指令是否频繁顶到饱和限幅。这三组曲线基本能告诉你问题是出在外环、内环还是混控末端。定位到具体模块以后,按上面几节的排查思路依次调整就行了。
写在最后的调试感悟
复现四旋翼PID控制论文这件事,难的不是公式推导,而是把理论公式变成仿真模型过程中那一堆不起眼的坑。电机响应延迟、混控矩阵符号、坐标系定义、积分饱和处理、限幅逻辑,每一处都可能让你的仿真结果和论文对不上。
我的经验是,复现论文务必先完全复现对方控制结构,用对方的思路和变量定义去搭建模型,确认了整体能稳定运行以后,再谈改进和调优。直接按自己的想法改结构再跟论文对比性能,出了问题你根本分不清是控制结构的问题还是参数整定的问题。
最常见的埋坑点:PID控制器的误差定义方向。论文里用的是期望减实际,还是实际减期望,这直接决定你增益的符号和混控矩阵的符号。仿真里炸机是最便宜的实验,炸一百次都能改,但如果你从仿真阶段就没有严谨的习惯,上真机那一天就会用真金白银来交学费。
PID控制看起来简单,但四旋翼这种强耦合、欠驱动、多回路串级的系统,直接暴露了PID调试中所有最容易被忽视的细节。把这篇复现做透了,以后再看其它控制方法论文,你会形成自己的调试方法论。