ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

多旋翼无人机鲁棒姿态控制:从PID到H∞的实战指南

多旋翼无人机鲁棒姿态控制:从PID到H∞的实战指南

去年夏天,我把一套H∞姿态控制器搬上模拟项目X的试验台,看着屏幕上滚转角曲线终于不再乱甩的时候,第一反应不是兴奋,而是有点想骂自己——为了调好之前那套PID参数,我前前后后改了十几个版本,加陷波器、加前馈、加自适应增益,最后还是没扛住大风工况下的剧烈抖动。多旋翼无人机姿态控制这件事,在理想环境里谁都能飞稳,真正拉开差距的是外界不确定性来敲门的时候。这篇内容不打算重复教材里那些公式推导,而是从“为什么鲁棒设计能解决PID解决不了的问题”出发,把姿态动力学建模、控制器方案选型、Matlab仿真实现和复现套路完整讲一遍,并附上可直接跑的代码。适合正在做无人机控制研究的学生、准备参加相关竞赛的队员,以及想在行业应用里把姿态环做得更稳的工程师。


1. 从“PID调到头还是抖”说起:鲁棒设计到底在解决什么

1.1 一个当年没搞定的大风工况

先说那台模拟项目X的来历。轴距450mm,整机质量大约1.5kg,正常悬停油门在50%左右。我一直用的是一套串级PID:外环角度、内环角速度,参数在静风环境里调得挺漂亮,阶跃响应超调不到10%,调节时间在1秒上下。但是一旦到室外,阵风从侧面拍过来,姿态角会先偏出去五六度,然后PID拼命往回拉,拉回来又冲过头,形成一种低频率的往复振荡。更麻烦的是,当我把电池从满电飞到低压,或者把云台相机拆掉再装上,转动惯量变了,同一组参数的表现又不一样了。

这种场景恐怕很多人都不陌生。风、负载变化、重心偏移、桨叶轻微形变、电机响应延迟,这些因素叠加在一起,会让被控对象的模型参数在运行过程中持续漂移。经典PID本质上是一个基于固定模型假设设计的控制器,它对工作点附近的线性变化有一定忍受能力,但面对“参数大范围变化+外部强扰动+未建模动态”的组合拳,就很容易失去章法。

问题的根源在于,我们设计控制器时用的是名义模型,而飞机飞在天上的真实对象,跟名义模型之间永远隔着一条偏差。鲁棒控制要做的,就是提前把这些偏差当作设计的一部分,而不是等它出现之后再靠经验补丁去凑。

1.2 说白了:给控制器上保险

打个比方。你在晴天无风的停车场里练倒车入库,练得再熟练,也不代表你能在暴雨夜、后视镜起雾、刹车片还受了潮的情况下把车停进同一个车位。经典控制相当于把“晴天无风”当成唯一的训练条件,而鲁棒控制是在设计阶段就假设:路面可能湿滑、视野可能模糊、轮胎抓地力可能下降。我得让同一套控制策略在这些“坏情况”下依然不失控。

具体到多旋翼姿态系统,不确定性大致可以分成三类:

  • 参数不确定性:转动惯量估计不准,或者说飞行过程中负载发生变化导致惯量漂移,阻尼系数也难以精确建模。
  • 外部扰动:风、气流、重心偏移产生的常值或时变力矩,这是姿态控制最主要的敌人。
  • 未建模动态:旋翼和电机的延迟、机架弹性模态、测量噪声、执行器饱和等,它们在高频段尤其危险。

鲁棒控制器要保证的是:不管这三类不确定性在约定范围内怎么变化,闭环系统都保持稳定,并且姿态跟踪性能的恶化程度可控。这段话换成工程语言就是:设计一个控制器K,让闭环系统在有界摄动下的范数增益保持在一个可接受的阈值以内。这也是后面H∞、滑模这些方法共同的出发点。


2. 姿态动力学建模:把“飞起来”翻译成状态空间方程

2.1 坐标系约定与欧拉角运动学

做姿态控制设计,第一步不是急着写控制器,而是先把被控对象模型落实到坐标系和方程层面。我习惯用机体坐标系配合ZYX欧拉角约定:机体绕惯性系的Z轴旋转得到偏航角ψ,再绕新的Y轴旋转得到俯仰角θ,最后绕新的X轴旋转得到滚转角φ。这个顺序和大多数飞控固件的习惯一致,后面接传感器数据时能少踩坑。

姿态运动学方程写成常见形式:

dφ/dt = p + tan(θ) * (q * sin(φ) + r * cos(φ)) dθ/dt = q * cos(φ) - r * sin(φ) dψ/dt = (q * sin(φ) + r * cos(φ)) / cos(θ)

其中p、q、r是机体角速度的三个分量。在小角度条件下,tan项和cos项约等于常数,上面三个方程会退化成近似积分关系,这也是很多简化模型敢把三个通道解耦的原因。但要注意,一旦做30°以上的大机动或者出现较强耦合,这个线性化假设就开始失真,后面需要当作未建模动态处理。

2.2 含外部扰动的力矩方程

刚体转动动力学方程是核心。设J为惯量矩阵,ω为机体角速度向量,则:

J * dω/dt = -ω × (J * ω) + M + d

M是控制器输出的控制力矩,d是外部扰动力矩,包括气动力矩和风扰等。对角惯量矩阵近似下展开,并且暂时忽略陀螺力矩等交叉耦合项,三个通道可以写成:

Ixx * φ'' = Mx + dφ Iyy * θ'' = My + dθ Izz * ψ'' = Mz + dψ

这样写虽然丢掉了耦合,但对设计第一版鲁棒控制器是合理的起点,因为鲁棒方法本来就要处理“被我们忽略掉的那部分误差”。如果直接把耦合全部带上,控制器设计会复杂一个量级,而且不一定能换来可感知的性能提升。

取状态变量为:

x = [φ, φ', θ, θ', ψ, ψ']^T u = [Mx, My, Mz]^T

状态空间表达就是:

A = [0 1 0 0 0 0; 0 0 0 0 0 0; 0 0 0 1 0 0; 0 0 0 0 0 0; 0 0 0 0 0 1; 0 0 0 0 0 0] B = [0 0 0; 1/Ixx 0 0; 0 0 0; 0 1/Iyy 0; 0 0 0; 0 0 1/Izz]

这个模型的物理意义很直观:每个通道的角加速度直接等于控制力矩除以对应轴的转动惯量。后面所有控制器设计、权重整定、仿真验证,都是围绕这组方程展开的。

2.3 不确定性的建模方式

鲁棒设计需要把不确定性显式地放进模型里。最常用的是加法不确定性或乘法不确定性。以加法不确定性为例,真实被控对象可以写成:

G_real(s) = G_nom(s) + Δ(s)

Δ(s)是稳定且有界的摄动,它的“大小”用H∞范数衡量。对多旋翼而言,不确定性主要来自惯量参数漂移、执行器动态差异、高频弹性模态。工程上一般假设:

||Δ(jω)||∞ ≤ W_u(jω)

W_u是一个频率相关的上界函数,低频段比较小,高频段比较大。这个W_u其实就告诉H∞求解器:你在低频段可以大胆地提升增益,但到了高频段必须收敛,否则就会去放大那些我们根本看不清的高频动态。

有了这个不确定性的数学描述,接下来就可以做方案选型了。


3. 三种鲁棒控制器方案横评:H∞、滑模、鲁棒LQR怎么选

3.1 H∞混合灵敏度:最经典的频域整形方案

H∞控制里最常用、最直观的落地方案是混合灵敏度。它把设计目标表达成三个传递函数的加权:

  • 灵敏度函数S = (I + GK)^(-1),描述扰动抑制能力,希望低频段小。
  • 补灵敏度函数T = GK(I + GK)^(-1),描述建模误差下的鲁棒稳定能力,希望高频段小。
  • 控制输入灵敏度函数KS,描述控制器输出强度,希望全频段有限。

设计者通过权重函数W1、W2、W3分别约束这三个量,最后让闭环系统满足:

|| [W1*S; W2*KS; W3*T] ||∞ < γ

如果γ小于1,说明设计目标全部达成。权重函数的选取是H∞设计里最考经验的部分,我在模拟项目X上用的初始权重是:

w0 = 8; % 期望开环穿越频率,单位 rad/s W1 = makeweight(2, w0, 0.05); % 低频高增益,压制扰动 W2 = tf(0.05); % 控制量加权,防止输出过大 W3 = makeweight(0.1, 10*w0, 50); % 高频高增益,抑制未建模动态

为什么穿越频率选8rad/s?姿态角速度环的带宽通常取5~15rad/s,太低了响应迟钝,太高了容易激励起机架的弹性模态和执行器饱和。这个数值需要根据你实际机架的刚性、飞控陀螺仪的采样率、电机响应速度来微调。

3.2 滑模控制:对付强非线性和大幅扰动的“暴力美学”

滑模控制的思路跟频率整形完全不同。它先把系统的状态轨迹引导到设计的滑模面上,然后通过不连续切换让状态一直停在滑模面上。对匹配型扰动,也就是直接作用在控制通道上的扰动,滑模控制理论上能做到完全不变性,这是它最吸引人的地方。

一个典型的姿态滑模面设计:

s = e_dot + λ * e

控制律分成等效控制项和切换项:

u = u_eq + k * sat(s / φ)

等效控制项u_eq用来维持系统状态在滑模面上的运动,切换项负责把状态拉回滑模面。边界层厚度φ用来平滑切换信号,否则高频抖振会直接烧电机或激起结构共振。这个方法的优点是不需要精确的模型参数,缺点是抖振问题始终存在,工程上要靠边界层和观测器去缓解。

3.3 鲁棒LQR与极点配置:把不确定性放进代价函数

鲁棒LQR的思路相对传统:仍然解Riccati方程,但故意把Q取大、R取小,让控制器变成高增益状态反馈,从而对参数摄动表现出更强的容忍度。或者更严格一点,把参数不确定性描述成多胞形,用一组线性矩阵不等式求解一个对所有顶点都稳定的反馈增益K。

这种做法比H∞容易理解,代码也容易写,但有一个天然问题:高增益状态反馈往往把高频测量噪声也放大,传感器稍微差一点就会看到高频输出抖动。所以它不是不能用于姿态控制,而是更适合在仿真验证阶段作为基线对比,而不是直接上真机。

3.4 方案对比与我的选型结论

方案处理参数摄动处理外部扰动工程实现成本主要风险
H∞混合灵敏度好好中,需调权重控制器阶数高
滑模控制较好极好(匹配扰动)低抖振
鲁棒LQR较好一般低高频噪声被放大

在模拟项目X上我最终选了H∞为主方案,滑模作为备选对比。原因有三个:第一,H∞把不同频段的需求分散到权重函数里,逻辑清楚,调整起来不像滑模抖振那样需要反复试;第二,控制器阶数虽然高,但用平衡截断降到8阶以内,飞控上完全扛得住;第三,后续要往真正的硬件上移植时,H∞的离散化实现和线性控制器框架更加成熟,Matlab代码可以直接转成C参考。


4. Matlab代码实战:从状态空间模型到H∞控制器求解

4.1 初始化参数:惯量、扰动上界和控制约束

写代码的第一步是定义物理参数和约束。这里以模拟项目X为例:

%% 物理参数 mass = 1.5; % 整机质量 kg arm = 0.24; % 机臂长度 m Ixx = 0.024; % 滚转惯量 kg·m^2 Iyy = 0.024; % 俯仰惯量 kg·m^2 Izz = 0.043; % 偏航惯量 kg·m^2 % 扰动力矩上界,单位 N·m,用来指导权重选择 d_amp = 1.2; % 阵风等效扰动力矩幅值 % 控制力矩约束,单位 N·m u_max = 3.0; % 单轴最大力矩

4.2 建立线性化状态空间模型

A = [0 1 0 0 0 0; 0 0 0 0 0 0; 0 0 0 1 0 0; 0 0 0 0 0 0; 0 0 0 0 0 1; 0 0 0 0 0 0]; B = [0 0 0; 1/Ixx 0 0; 0 0 0; 0 1/Iyy 0; 0 0 0; 0 0 1/Izz]; C = [1 0 0 0 0 0; % 测量滚转角 0 0 1 0 0 0; % 测量俯仰角 0 0 0 0 1 0]; % 测量偏航角 D = zeros(3, 3); P_nom = ss(A, B, C, D);

注意这里C矩阵只取了三个姿态角,没有取角速度。如果姿态控制器最终只反馈角度,那么内环角速度的阻尼作用完全由控制器自己生成的状态反馈来提供,这就是“面值反馈”控制的典型做法。实际真机上通常会把陀螺仪角速度也反馈进来,那C矩阵就还需要再补三行单位阵。

4.3 混合灵敏度综合与控制器降阶

%% 权重函数 w0 = 8; W1 = makeweight(2, w0, 0.05); W2 = tf(0.05); W3 = makeweight(0.1, 10*w0, 50); %% 混合灵敏度综合 [K, CL, GAM] = mixsyn(P_nom, W1, W2, W3); fprintf('达到的gamma值: %.3f\n', GAM); %% 控制器降阶,便于后续实现 K_red = balred(K, 8);

mixsyn内部会把权重函数拼成广义被控对象再调用H∞求解,它的输出K就是状态空间形式的控制器。GAM如果小于1,说明性能目标和鲁棒约束同时满足;如果大于1,就要回去调整权重函数,通常是降低W1的低频增益或者降低W3的高频增益,二选一,不能同时硬压。

控制器阶数可能很高,比如十好几阶,但实际飞控上跑不了那么大的矩阵。用balred降到8阶之后,对比一下降阶前后的开环Bode图,只要在中低频段形状基本重合,就可以放心用降阶版本。

4.4 时域仿真主循环

我习惯用ode45搭一个最简单的姿态仿真,不直接上Simulink,方便批量跑参数扫描:

%% 仿真参数 simT = 8; x0 = [0; 0; 0; 0; 0; 0]; % 初始姿态角与角速度均为0 ref = [deg2rad(30); deg2rad(10); deg2rad(15)]; % 目标姿态角 %% 调用ode45 [t, x] = ode45(@(t, x) quad_ode(t, x, K_red, ref), [0 simT], x0); %% 画图 figure; plot(t, rad2deg(x(:,1)), 'LineWidth', 1.5); hold on; plot(t, rad2deg(x(:,3)), 'LineWidth', 1.5); plot(t, rad2deg(x(:,5)), 'LineWidth', 1.5); grid on; xlabel('时间 (s)'); ylabel('姿态角 (deg)'); legend('滚转', '俯仰', '偏航');

对应的状态方程函数:

function dx = quad_ode(t, x, K, ref) % 取前三行作为量测输出,因为状态前三个分量就是姿态角 y = x([1 3 5]); u = -K * (y - ref); % 限幅,模拟执行器饱和 u = max(min(u, 3.0), -3.0); % 加入阵风扰动,在 2~2.5s 注入一个脉冲扰动力矩 d = zeros(3, 1); if t >= 2 && t <= 2.5 d = [0.8; -0.6; 0.3]; end Ixx = 0.024; Iyy = 0.024; Izz = 0.043; dx = zeros(6, 1); dx(1) = x(2); dx(2) = (u(1) + d(1)) / Ixx; dx(3) = x(4); dx(4) = (u(2) + d(2)) / Iyy; dx(5) = x(6); dx(6) = (u(3) + d(3)) / Izz; end

这里用了角速度等于零的小角度线性方程,简化到只剩一阶积分关系,不影响说明控制器逻辑。真正要模拟大机动,需要用完整的欧拉角运动学方程,或者直接换成四元数。

如果手里没有鲁棒控制工具箱,mixsyn跑不了,也可以先试一下备选方案——滑模控制器。代码量少,而且对模型依赖低:

function u = smc_attitude(phi, dphi, ref_phi, ref_dphi) Ixx = 0.024; lambda = 5; % 滑模面增益 k = 2.0; % 切换增益 phi_b = 0.05; % 边界层厚度 e = phi - ref_phi; de = dphi - ref_dphi; s = de + lambda * e; sat = max(min(s / phi_b, 1), -1); u = Ixx * (ref_dphi - lambda * de) + k * sat; end

滑模控制有个好处:切换增益k可以直接根据扰动上界来选,k大于扰动力矩上界就能保证到达条件。代价是边界层φ越小跟踪精度越高,但抖振越明显,这个平衡只能靠仿真和实际测试去感受。


5. 仿真复现最容易翻车的三个坑

5.1 欧拉角接近90度之后姿态解算直接跳变

第一个坑几乎是所有做欧拉角姿态仿真的人都会撞上的。当俯仰角接近正负90度时,运动学方程里的1/cos(θ)项会趋向无穷大,导致角度计算出现跳变甚至仿真发散。我第一次做30度滚转+大俯仰联合机动时,亲眼看到角度从89度直接跳到-91度,整条曲线完全没法看。

解决方法分两种。如果仿真范围控制在中小机动,就在状态更新后加限幅,防止姿态角越界;如果确实要仿真大机动,就老老实实改成四元数姿态表示,输出时再转成欧拉角画图。H∞控制器本身对姿态表示方式不敏感,但仿真环境必须先解决这个问题,否则你很难判断发散到底是控制器的问题还是数值积分的问题。

5.2 控制器带宽太高,执行器饱和之后开始极限环振荡

H∞权重里W1取太高,或者穿越频率w0设得偏大,控制器算出来的力矩指令在仿真里看似正常,但只要一加上执行器饱和限幅,整个系统就可能进入极限环振荡。我做过一组对比:w0从8改到14,其它权重不变,名义性能确实变好了,但加上3N·m的饱和限幅后,系统开始以约3Hz的频率持续小幅度振荡,跟真机上电机嗡嗡抖的表现一模一样。

这是典型的“名义性能提升、含饱和鲁棒性恶化”案例。线性控制器设计默认执行器是无限带宽、无限幅值的,但物理世界不是这样。应对措施是在权重里显式加入W2来压低控制量,或者在仿真模型里加入饱和模块之后重新验证γ值。不要等上了真机才发现问题。

5.3 不确定性上界取得太保守,控制器“为了稳而牺牲一切”

另一个方向相反的坑是把W3或扰动力矩上界取太大,因为担心模型不准确就拼命压高频增益。结果控制器变得非常保守,扰动来一下之后要很久才能恢复,响应慢得令人绝望,我甚至在一次对比里看到H∞的调节时间比PID慢了4倍还多。这其实是鲁棒设计的经典矛盾:你保护的东西越多,能发挥的性能就越少。

经验做法是先取一个尽量贴近物理实际的不确定性上界,而不是“拍脑袋往大了取”。惯量不确定如果实测估计误差在±20%以内,W3的低频起始值就不需要设得特别高;真正需要重点防护的是高频未建模动态,所以让W3在20rad/s以上再快速抬升也是合理的。


6. 鲁棒性验证:参数拉偏与扰动注入实测

6.1 名义工况下的阶跃响应对比

仿真搭建完成之后,我首先跑了一组名义工况的阶跃对比,参考输入是滚转30度、俯仰10度、偏航15度同时给出。PID和H∞的控制器都用同样一套状态空间模型,只是控制器本身不同。结果显示H∞在超调和调节时间上明显占优,尤其滚转通道从PID的14%超调降到了2%左右,三轴同步协调性也更好。

指标PIDH∞
滚转30°阶跃超调14%2.1%
滚转调节时间(±5%)1.15 s0.58 s
俯仰10°阶跃超调9%0.8%
偏航15°阶跃稳态误差0.3°0.05°

这是模拟项目X上的代表性数据,不同机架参数下具体数值会变,但趋势是稳定的:H∞在标称性能上不会输给调好的PID太多,而在扰动抑制上会拉开明显优势。

6.2 参数拉偏测试:惯量摄动30%还能不能稳

名义工况只是开胃菜,真正考验鲁棒性的是参数拉偏。我把Ixx、Iyy、Izz全部拉偏±30%,重新跑同一组扰动注入实验。PID在+30%惯量偏置下已经出现明显的低频振荡,姿态误差波动从原来的1度以内放大到4度左右;H∞控制器在同样的摄动下依然保持稳定,滚转角最大偏差只增大了一点,没有出现持续振荡。

这里要强调的是,H∞并不能保证任何大小的参数摄动都稳定,它只能保证在上界以内的摄动稳定。所以验证时一定要跟你设计阶段设定的不确定性上界对应上。如果拉偏幅度超过了上界,再好的鲁棒控制器也会失去保证,这个边界要心里有数。

6.3 我的经验:别迷信鲁棒方法,也别停留在仿真

最后说点个人体会。真正让我从把H∞从“论文里的方法”变成“手里能用的工具”的转折点,不是哪个数学推导,而是接受了两件事。第一,鲁棒控制器解决的是不确定性问题,但它并不能消除物理世界里的饱和、噪声、结构谐振,这些约束仍然要靠实际工程手段去兜底。第二,Matlab仿真里跑得再漂亮,也不代表真机一定没问题;我的建议是仿真阶段至少加入饱和限幅、传感器噪声和模型参数拉偏这三样东西,否则鲁棒性验证的说服力会很有限。

如果还要留一条可操作的技巧,那就是每次改完权重函数,都先看一眼Bode图上的开环穿越频率和相位裕度,再跑时域仿真。对比这条线,你就能知道这次改动是变激进了还是变保守了,不用像以前调PID那样全凭手感盲调。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进