☰
四旋翼轨迹跟踪实践:从PID局限到MPC模型预测控制设计
2026/10/21 19:03:18 网站建设 项目流程

1. 轨迹跟踪这件事,为什么要从PID换到MPC

1.1 四旋翼控制的本质难点:欠驱动、强耦合、约束硬

四旋翼飞行器的控制问题在初学者眼里往往是"遥控航模"这个级别的难度,真正上手做轨迹跟踪研究才会发现,它其实是控制理论里相当有代表性的一个战场。12个状态量(位置、速度、姿态角、角速度各3个),却只有4个控制输入(总推力加三个轴力矩),典型的欠驱动系统。这意味着你没法直接命令飞行器"向左走",只能通过改变姿态来间接产生水平方向的推力分量。位置和姿态之间是强耦合的,姿态变化会立刻改变加速度方向,而位置误差又会反过来要求姿态做出响应。

更麻烦的是约束问题。电机的推力不是无限制的,它是单向的(只能往上推,不能往下拉),而且有上下限;姿态角也不能随便翻——你不可能让飞行器为了追轨迹倒扣过来。这些都是硬约束,实实在在限制着控制器的输出空间。做轨迹跟踪的时候,参考轨迹一旦走得比较激进,比如高速转弯、急停加速,控制器就必须在满足这些约束的前提下找到最优输入。这套约束处理能力,恰恰是传统线性控制器最不擅长的部分。

1.2 PID方案在轨迹跟踪上的三个硬伤

我不否认PID在四旋翼上的统治地位,姿态内环用PID是非常成熟的方案,但把它直接用于高精度轨迹跟踪,你会碰到几个绕不开的问题。

第一是没有预测能力。PID是纯被动的,它看的是当前误差,最多加个微分项看误差变化趋势。当轨迹在前方拐弯时,PID并不知道下一步会发生什么,只能等误差真正出现了再去纠正。结果是每个拐弯处都会出现明显的相位滞后和超调,误差曲线永远是"滞后-纠正-超调-再纠正"的循环。

第二是约束无法显式处理。你把PID算出来的期望推力量化到电机指令时,如果超过了饱和限幅,只能硬截。截断之后内环的姿态指令和实际输出不一致,整个回路就处于一种"失控但看起来还在工作"的状态。更隐蔽的是积分项,饱和时积分还在累积,恢复后会出现长时间的振荡,这就是经典的积分饱和问题。

第三是串级结构下的调参冲突。位置外环跟姿态内环串在一起,带宽必须拉开才能稳定,但拉得越开,位置环响应越慢,跟踪性能越差。你调外环增益想跟得更紧,内环一抖动,整个系统就开始振荡,最后只能在"稳"和"准"之间妥协。

1.3 MPC到底做了什么不一样的事

模型预测控制(Model Predictive Control)的思路完全换了方向:不靠反馈增益去应对误差,而是每一个采样周期都基于系统的数学模型,向前预测未来一段时间(预测时域)的状态走向,以跟踪误差最小为目标,在满足约束的前提下解一个优化问题,得到一串最优控制序列,然后只执行第一个控制量,下一个周期再滚动重复。

打个比方。PID像一个只看眼前三步的司机,看到弯了才打方向盘;MPC像一个能预演整条赛道的车手,弯道前就开始规划转向、油门和刹车的配合。这个"预演"的能力来自模型,来自优化,也来自约束条件里对未来潜在风险(比如推力饱和、姿态超限)的提前规避。

从研究的角度看,MPC在无人机轨迹跟踪上的价值有三点:一是天然的约束处理,推力、力矩、甚至飞行走廊限制都可以直接写进优化问题;二是多变量协同优化,位置和姿态的权重可以在同一个目标函数里平衡,不需要像串级那样强行分带宽;三是滚动优化带来的鲁棒性,模型不完美没关系,每个周期都会用最新状态重新求解,持续修正偏差。

这篇博客会沿着"建模→控制器设计→Matlab实现→参数整定→排坑"的完整链路来展开,重点给出可以直接复用的代码和调参思路。整个过程我都在Matlab环境里跑,模型是非线性仿真,控制器用的是线性MPC,这个方案组合在工程研究中是最常见的,也最容易出效果。

2. 建模是MPC的地基:动力学方程与离散化处理

2.1 完整非线性模型怎么简化才合理

MPC的性能上限直接取决于预测模型的准确度,模型不能太复杂(否则求解太慢),也不能太粗糙(否则预测失真)。我用的是一套经典的三维刚体模型:地面坐标系描述位置,机体坐标系描述姿态,状态向量取为

x = [x, y, z, vx, vy, vz, φ, θ, ψ, p, q, r]ᵀ

其中前三项是地面系位置,接着三项是地面系速度,再是三个欧拉角(滚转φ、俯仰θ、偏航ψ),最后是体轴系角速度。控制输入取为 u = [U1, τφ, τθ, τψ]ᵀ,即总推力和三个轴的力矩。

位置环的动力学可以写成这种形式:

m * ẍ = U1 * (cosφ sinθ cosψ + sinφ sinψ) m * ÿ = U1 * (cosφ sinθ sinψ − sinφ cosψ) m * z̈ = U1 * (cosφ cosθ) − m*g

姿态运动学用欧拉角微分方程,角加速度则用刚体欧拉方程。在学术研究和工程预研阶段,通常都会忽略气动阻力、电机动态延迟、螺旋桨陀螺力矩这些次要因素,把它们留到后续更精细化建模时再补。这个"留白"很重要——模型复杂度每上升一个档次,求解耗时和实现难度都会跟着上一个台阶,先让控制器框架跑通,再逐步加细节才是务实路径。

2.2 悬停点线性化得到状态空间模型

直接对非线性模型做非线性MPC(NMPC)当然可以,但NMPC每一步要解非线性优化,Matlab里实现起来慢而且容易出数值问题。对轨迹跟踪这个场景,如果机动幅度不是特别大(滚转角、俯仰角控制在20°以内),完全可以在悬停平衡点做线性化,得到线性时不变状态空间模型,然后用二次规划(QP)轻松求解,速度快、收敛可靠。

在Matlab里,最稳妥的做法是用符号工具箱推导雅可比矩阵,而不是手算(手算很容易因为符号约定出错)。代码大概是这样的:

syms x y z vx vy vz phi theta psi p q r real syms U1 tau_phi tau_theta tau_psi real syms m g Ixx Iyy Izz real % 定义非线性系统 f(x,u) f = [ vx; vy; vz; U1/m*(cos(phi)*sin(theta)*cos(psi) + sin(phi)*sin(psi)); U1/m*(cos(phi)*sin(theta)*sin(psi) - sin(phi)*cos(psi)); U1/m*(cos(phi)*cos(theta)) - g; p + sin(phi)*tan(theta)*q + cos(phi)*tan(theta)*r; cos(phi)*q - sin(phi)*r; sin(phi)/cos(theta)*q + cos(phi)/cos(theta)*r; (Iyy-Izz)/Ixx*q*r + tau_phi/Ixx; (Izz-Ixx)/Iyy*p*r + tau_theta/Iyy; (Ixx-Iyy)/Izz*p*q + tau_psi/Izz; ]; states = [x y z vx vy vz phi theta psi p q r]; inputs = [U1 tau_phi tau_theta tau_psi]; % 在悬停点 (姿态角为零、角速度为零、推力等于重力) 处求雅可比 hover = [zeros(1,9), 0, 0, 0]; u_hover = [m*g, 0, 0, 0]; A = double(subs(jacobian(f, states), [states inputs], [hover u_hover])); B = double(subs(jacobian(f, inputs), [states inputs], [hover u_hover]));

跑完你会发现,A矩阵里最重要的耦合项就是那几项重力加速度。位置方程里出现了 vẋ = g·θ、v̇y = −g·φ(符号约定取决于旋转顺序,具体以你定义的欧拉角转序为准),这就是"倾斜产生水平加速度"这个物理过程在线性模型里的体现。z方向则是 vż = ΔU1/m,推力的变化直接改变垂直加速度。姿态角部分在悬停点处线性化后只剩下简单的积分关系,角加速度则完全由力矩除以转动惯量决定。

2.3 离散化方法与采样周期怎么选

MPC是离散控制器,预测模型必须写成离散状态空间的形式。工程上我强烈建议用零阶保持器(ZOH)离散化,而不是简单的一阶欧拉近似,因为控制器在每个采样周期内会保持控制量不变,这个行为恰好符合ZOH的假设:

Ts = 0.02; % 采样周期 20ms sysC = ss(A, B, eye(12), zeros(12,4)); sysD = c2d(sysC, Ts, 'zoh'); Ad = sysD.A; Bd = sysD.B;

采样周期的选择是第一个需要拍板的关键参数。针对轨迹跟踪这种外环控制场景,我建议取20ms(50Hz)到50ms(20Hz)之间。太小时域就要拉长很多步才能覆盖同样的前瞻时间,求解负担大;太大则控制器反应迟钝,跟踪快速轨迹时会明显丢精度。我做这个项目用的20ms,配合预测时域30步,等效前瞻0.6秒,对常规机动轨迹已经非常够用了。

这里要区分一个概念:控制器用的线性离散模型和仿真用的非线性微分方程不是一回事。仿真里我强烈不建议用欧拉法积分,一步20ms的欧拉积分会引入明显的数值误差,四阶龙格库塔(RK4)才是基础配置。这条我在第4章的具体代码里会再展开。

3. MPC控制器设计:从预测模型到优化问题

3.1 目标函数怎么定:误差权重与控制代价的权衡

MPC的核心是一个带约束的最优化问题。每一拍要做的事就是:给定当前状态x₀,以预测模型推算未来Np步的状态轨迹,选择一组未来Nc步的控制输入序列,使目标函数最小。我使用的目标函数是经典二次型:

J = Σᵢ₌₁ᴺᵖ (xₖ₊ᵢ − x_ref,ₖ₊ᵢ)ᵀ Q (xₖ₊ᵢ − x_ref,ₖ₊ᵢ) + Σᵢ₌₀ᴺᶜ⁻¹ uₖ₊ᵢᵀ R uₖ₊ᵢ

第一项衡量预测状态跟参考轨迹之间的偏差,第二项惩罚控制量的大小。Q矩阵里面的对角线权重分别对应位置误差、速度误差、姿态误差和角速度误差。R矩阵则控制操纵的"积极程度"。

权重设置的大方向是这样:位置误差最优先,权重最大;速度次之;姿态和角速度的权重相对小,因为它们本质上是实现位置跟踪的"手段",不是"目的"。我的一组可复用的初始值:

Q = diag([80, 80, 80, % 位置权重 10, 10, 10, % 速度权重 1, 1, 1, % 姿态角权重 0.1, 0.1, 0.1]);% 角速度权重 R = diag([0.1, 0.01, 0.01, 0.01]);

R的第一个元素对应总推力,权重取大一点是合理的——推力的强烈抖动会直接导致整个机体颠簸。三个力矩通道的权重可以小一些,让姿态回路更灵敏。注意:跟踪误差的核心理念是让"预测轨迹"逼近"参考轨迹",所以参考轨迹本身必须是完整的状态参考,而不只是位置。实际做法是把参考位置、参考速度(以及参考姿态角,通常偏航给恒定值)组装成12维的参考状态向量。

3.2 约束条件写进优化问题才是MPC的灵魂

约束是MPC区别于LQR等线性最优控制的最大卖点。这个项目里至少要考虑三类约束。

第一是执行机构饱和约束。推力有上下限(下限通常是0或一个小正数,保证不会倒推力),力矩各轴有最大幅值。这些直接写成决策变量的上下界:

umax = [14.0, 0.6, 0.6, 0.3]; % 对应 [最大推力N, 最大滚转力矩N·m, 最大俯仰力矩, 最大偏航力矩] umin = [0.5, -0.6, -0.6, -0.3]; lb = repmat(umin', Nc, 1); ub = repmat(umax', Nc, 1);

第二是控制增量约束。如果你的执行机构无论硬件上还是电调响应上都不允许控制量瞬间突变,就要对相邻两个控制步的差值加限制。这个约束在Matlab里也很好构造,差分矩阵乘以控制序列即可。

第三是状态约束。比如为了保证安全限制最大倾斜角、限制飞行高度走廊。状态约束会牵涉到预测状态跟控制序列的线性映射关系,写起来比输入约束复杂一些,但对飞行安全意义重大。我的经验是先用输入约束跑通,再逐步加入状态约束,一次引入太多约束很容易出现"不可行解"问题。

3.3 QP标准化与求解器选择

把预测模型展开、带入目标函数,二次规划问题的标准形式就出来了一大半。先构建预测矩阵:

function [Psi, Gamma] = predictionMatrices(Ad, Bd, Np, Nc) nx = size(Ad, 1); nu = size(Bd, 2); Psi = zeros(Np*nx, nx); for i = 1:Np Psi((i-1)*nx+1 : i*nx, :) = Ad^i; end Gamma = zeros(Np*nx, Nc*nu); for i = 1:Np for j = 1:min(i, Nc) Gamma((i-1)*nx+1 : i*nx, (j-1)*nu+1 : j*nu) = Ad^(i-j) * Bd; end end end

于是所有预测状态可以写成紧凑形式:Y_pred = Psix₀ + GammaU_seq。代入目标函数后,整理成标准QP:

min ½ Uᵀ H U + fᵀ U

其中:

Qbar = kron(eye(Np), Q); Rbar = kron(eye(Nc), R); H = Gamma' * Qbar * Gamma + Rbar; f = Gamma' * Qbar * (Psi*x0 - ref_vec);

求解我推荐先用Matlab自带的quadprog,算法选'interior-point-convex',考试和仿真完全够用。如果后面要考虑实时性能(或者硬件部署),再换OSQP或者Matlab MPC工具箱的mpcqpsolver。这里说清楚一个观点:不要一上来就用重型工具箱,把QP问题的H、f矩阵亲手拼一遍,你对MPC的理解会扎实很多——这步拼矩阵的过程就是帮你理清预测模型与目标函数之间关系的绝佳训练。

4. Matlab代码实现:从搭建仿真到跑通轨迹

4.1 代码框架总览

整个工程我按功能拆成五个文件,各自的职责清清楚楚:

quad_params.m % 系统参数、采样时间、控制器参数 linear_model.m % 非线性模型线性化 + ZOH离散化 reference_traj.m % 参考轨迹生成(位置、速度、加速度) mpc_solve.m % 单步MPC求解(拼QP + 调用quadprog) main_tracking.m % 主仿真循环(非线性RK4 + 结果显示)

这个拆法适合一个人维护,也方便后续把mpc_solve.m单独替换成其他求解器或部署版本。主仿真循环里有一个关键原则:控制器用的是线性离散模型,但仿真对象必须是非线性模型,否则就变成了"自己预测自己"的假闭环验证,毫无价值。

4.2 核心模块的实现细节

先看主循环,重点在RK4积分这一步。非线性模型函数单独写一个quadrotor_dynamics.m,主循环里通过函数句柄传给RK4积分器:

% main_tracking.m 核心循环 X = zeros(12, N_steps+1); X(:,1) = x0; U = zeros(4, N_steps); for k = 1:N_steps xk = X(:,k); % 组装从当前时刻起 Np 步的参考状态 ref_vec = buildRefVector(refState, k, Np); % 求解MPC,得到最优控制序列,只取第一项 [uk, info] = mpc_solve(xk, ref_vec, Ad, Bd, Q, R, Np, Nc, ... lb, ub, Aineq, bineq); U(:,k) = uk; % 用非线性模型 + RK4 推进系统状态 X(:,k+1) = rk4step(@(x,u) quadrotor_dynamics(x, u, params), ... xk, uk, Ts); end

mpc_solve.m里做的就是第3章讲的拼矩阵加quadprog:

function [u_opt, info] = mpc_solve(x0, ref_vec, Ad, Bd, Q, R, Np, Nc, lb, ub, Aineq, bineq) [Psi, Gamma] = predictionMatrices(Ad, Bd, Np, Nc); nx = size(Ad, 1); nu = size(Bd, 2); Qbar = kron(eye(Np), Q); Rbar = kron(eye(Nc), R); H = Gamma' * Qbar * Gamma + Rbar; H = (H + H') / 2; % 对称化,避免数值误差 f = Gamma' * Qbar * (Psi * x0 - ref_vec); options = optimoptions('quadprog', 'Algorithm', 'interior-point-convex', ... 'Display', 'off', 'MaxIterations', 400); [u_seq, ~, exitflag] = quadprog(H, f, Aineq, bineq, ... [], [], lb, ub, [], options); if exitflag < 0 warning('MPC求解失败,exitflag=%d,使用上一次控制量', exitflag); u_seq = zeros(Nc*nu, 1); end u_opt = u_seq(1:nu); info.exitflag = exitflag; end

这段代码里有几个实操细节值得注意。一是H矩阵对称化,quadprog对非对称H的容忍度时好时坏,对称化只多花一行的功夫,能省一堆排查时间。二是exitflag的判断,求解失败时不能直接拿垃圾解去控制,我这里的处理是退化为上一拍的控制量(实际可改成保持悬停输出),仿真里加上这个保护机制,后面排查不可行问题时会轻松很多。

再补充一下参考轨迹的生成。我的参考轨迹是一组直线加转弯的轨迹段,速度规划用梯形速度曲线,保证参考速度和加速度连续:

% reference_traj.m 示意:梯形速度轨迹 t_seg = tf - t0; v_max = 2.0; % 最大速度 a_max = 3.0; % 最大加速度 % 三段式:匀加速-匀速-匀减速 pos = ...; % 分段积分得到位置 vel = ...; % 分段速度 acc = ...; % 分段加速度

轨迹连续性对MPC非常重要。很多人做仿真时参考轨迹只给位置点,让控制器去追一串不连续的目标,结果误差波动大还赖控制器不好——其实问题出在参考本身,位置连续但速度不连续的轨迹,会迫使控制器在切换点输出突变。用梯形速度或更高阶的多项式轨迹平滑掉速度和加速度跳跃,MPC的性能会立刻上一个档次。

4.3 结果展示:3D轨迹、误差曲线、控制量曲线

仿真跑完后要输出三组图,分别对应轨迹、误差和控制量:

figure; plot3(X(1,:), X(2,:), X(3,:), 'b-', 'LineWidth', 1.5); hold on; plot3(ref_pos(1,:), ref_pos(2,:), ref_pos(3,:), 'r--', 'LineWidth', 1.5); xlabel('x (m)'); ylabel('y (m)'); zlabel('z (m)'); legend('实际轨迹', '参考轨迹'); grid on; axis equal; figure; subplot(3,1,1); plot(t, X(1,:)-ref_pos(1,:)); ylabel('x误差 (m)'); subplot(3,1,2); plot(t, X(2,:)-ref_pos(2,:)); ylabel('y误差 (m)'); subplot(3,1,3); plot(t, X(3,:)-ref_pos(3,:)); ylabel('z误差 (m)'); figure; subplot(4,1,1); plot(t, U(1,:)); ylabel('U1 (N)'); subplot(4,1,2); plot(t, U(2,:)); ylabel('τφ (N·m)'); subplot(4,1,3); plot(t, U(3,:)); ylabel('τθ (N·m)'); subplot(4,1,4); plot(t, U(4,:)); ylabel('τψ (N·m)');

跑通了你会看到这样的结果:初始位置偏移较大时,MPC会先以较大加速度纠正误差,前0.5秒左右误差快速收敛;进入匀速段后稳态误差趋近于零;在转弯处会出现小幅滞后,但不会像PID那样明显超调,控制量始终被限制在约束范围内。这个表现就是MPC"预判+约束"两个特性共同作用的结果。

5. 参数整定实战与效果分析

5.1 权重矩阵的调节逻辑与顺序

参数整定是这个项目里最花时间、也最考经验的部分。我的核心建议是:别一上来就均匀扫参数,按照"先可行性,后跟踪精度,再平滑性"的顺序来。

第一梯队是Q_pos和R的比例关系。如果你发现跟踪响应慢、误差收敛迟钝,优先调大位置权重Q_pos,或者调小R;如果你发现控制量抖动厉害、姿态频繁振荡,就反着调。记住一个经验:Q_pos和R的比值才是关键,单独调大Q_pos而不动R,往往只是把系统推往更激进的方向。我的初始值里Q_pos取80、R取0.01~0.1,这个量级对质量在1kg左右的四旋翼是比较稳的起点。

第二梯队是速度权重Q_vel。它起阻尼作用。Q_vel太小,位置误差会转化为过大的速度指令,系统像没阻尼的弹簧,振荡明显;Q_vel太大,系统响应变肉,转弯处滞后加重。我调试时的经验是Q_vel取Q_pos的十分之一到八分之一。

姿态权重和角速度权重排在最后,它们对中低机动幅度的影响不明显,但会显著影响控制量曲线的平滑度。姿态权重太小,控制器会为了追位置而让姿态指令疯狂跳动;姿态权重太大,位置跟踪的快速性又会被拖累。可以先给一个保守值(1和0.1),基本不用频繁动。

5.2 预测时域Np与控制时域Nc的搭配

预测时域决定了控制器"看得多远"。调这个参数有个很直观的感受:Np太小(比如10步,相当于0.2秒),控制器近乎短视,轨迹有转弯它反应不过来,误差在拐点处明显变大;Np增大到30步左右,提前0.6秒就能看到转弯,开始"提前准备",误差曲线平滑很多。但Np也不是越大越好,超过50步之后改善非常有限,反而大幅增加QP规模,求解时间成倍上涨。

控制时域Nc的逻辑不同。Nc决定控制量的自由度。从我的实测看,Nc从3到8之间的差异不大,超过8之后基本上就是浪费算力——因为对多数轨迹,后面几步的控制量自由度对目标函数的边际贡献已经微乎其微。我推荐Nc=5,计算量和性能的平衡点。下面这个表格是我整理出的调参方向速查表:

参数现象:偏小现象:偏大推荐方向
Q_pos跟踪滞后、误差大过冲明显、输入波动与R联动调整
Q_vel位置振荡、收敛慢响应迟钝、拐弯滞后Q_pos的1/10~1/8
Q_att姿态指令跳动位置响应变慢先设1再微调
R控制量抖动剧烈响应迟缓、误差偏大0.01~0.1起步
Np拐弯滞后、短视求解慢、无额外收益20~40步
Nc控制自由度不足算力浪费3~8,推荐5
Ts计算压力大控制延迟高外环20~50ms

5.3 仿真结果怎么解读才算调到位

判断参数是否调好,不能只看3D轨迹贴合度,要同时看三条曲线:跟踪误差是否收敛、控制量是否在约束内、控制量是否平滑。

误差曲线看两点:稳态误差和瞬态超调。匀速直线段误差应该稳定在一个很小的值(我实测能到厘米级),转弯或机动段短暂增大但能快速回落,这就合格了。控制量曲线看两点:不能频繁顶到饱和度,不能有高频抖振。如果U1曲线像锯齿一样密集抖动,基本可以断定R太小或Np太短,先调这两个。

我调参过程中一个比较典型的案例:初始参数Np=15、R=0.001时,控制量U1高频振荡,幅度不大但频率接近采样率,这种振荡在真实硬件上会直接导致电调过热和机体抖动。把R提到0.05,Np拉到30后,振荡消失,跟踪误差反而因为控制平稳而下降了30%。这个案例很能说明问题:MPC不是权重越大越好,让控制量平稳下来,系统的实际表现往往会更好。

6. 实际部署中容易踩的坑

6.1 计算延迟:QP求解时间会悄悄吃掉你的稳定性

这是从Matlab仿真走向任何实时平台都要面对的第一关。每个采样周期内,必须完成建模、拼QP、求解、输出控制量这一整套流程。用quadprog在普通电脑上跑Np=30、Nc=5的问题,单步求解时间我测过大约在3~5ms,对20ms的采样周期压力不大;但如果把Np抬到60、Nc加到15,单步直接到20ms以上,这就意味着控制器还没算完,采样时刻已经过去了。

永远在仿真里加一行计时代码:

tSolve = tSolve + toc(tStart);

跑完看平均求解时间和最大求解时间,最大求解时间必须明显小于采样周期。超时的话,按优先级排序的处理方案是:先压缩Nc(从5降到3),再压缩Np(从30降到20),最后才考虑换求解器(OSQP的MEX版本比quadprog快一个量级)。不要一开始就上重型求解器,先把时域压缩到合理范围。

6.2 线性化模型的适用范围是硬边界

线性MPC的预测模型是悬停点附近的近似。这意味着当实际轨迹要求持续的大姿态角(比如大于25°~30°)时,预测和真实系统之间会出现系统性偏差。偏差积累到一定程度,MPC仍然能稳住(因为有滚动反馈),但控制品质会明显下降,甚至出现振荡。

应对办法有两种,取决于你的场景。如果轨迹机动幅度大但不频繁,可以采用增益调度:在几个不同姿态角(比如0°、15°、30°)处分别线性化并预计算预测矩阵,运行时根据当前状态在线切换。如果机动范围覆盖整个姿态空间,那就要考虑非线性MPC或反馈线性化结合MPC的混合方案,不过复杂度会跳升不止一个量级。我的建议是:做轨迹跟踪研究,绝大多数场景线性MPC就够用,先把机动幅度控制在合理范围内,把该做好的轨迹精度和约束处理做扎实。

6.3 从仿真到现实的差距集中在哪几个环节

如果项目要走向真机,最典型的坑有三个。

一是模型失配。仿真里几乎不会考虑气动阻力、电机响应延迟、电池电压跌落带来的推力下降。在仿真里加一组干扰(比如模拟突风、给模型加一个未被建模的电机一阶延迟),就能看到MPC的鲁棒性边界在哪。对突风这类持续扰动,线性MPC会留下稳态误差,解决思路是在预测模型里增广一个扰动状态做估计,或者加入积分作用。

二是延迟补偿。从"MPC解出控制量"到"该控制量真正作用在机体上",要经过状态估计、结果传递和电调响应,至少一个采样周期的延迟不可避免。在仿真阶段如果你完全不考虑这一步,真机上会突然发现控制器比想象中"急"。实现延迟补偿的一个简单办法:用当前状态加动量模型预测一步,把预测到的状态当作"当前状态"送入MPC求解。

三是状态估计质量。MPC是模型驱动的,喂给它的状态如果带噪声或者延迟,预测结果就会"带病"。真机场景下,位置和速度通常来自融合了加速度计、视觉或RTK的估计器,而不是直接微分。仿真里如果只用理想的微分速度,也要明确意识到这和实际系统之间的差距。

从仿真到研究项目的收尾体会

我自己把整个链路走下来,最大的感触是:MPC的"算法光环"再强,最终决定成败的还是建模和约束的细节。模型线性化精度不够、参考轨迹不平滑、约束设置不合理、求解超时没有保护,任何一个环节出问题,控制器都会以非常微妙的方式"失灵",而且排查起来比PID时代复杂得多——因为问题可能出在模型、目标函数、约束、求解器任意一层。

如果让我给正在做类似方向的同学一个起步建议:第一轮仿真千万不要追求复杂轨迹,先用简单的悬停点跟踪把控制器跑通,确认误差收敛、控制量平稳;第二轮加入匀速直线轨迹,调Q和Np让性能达标;第三轮才上带转弯的完整轨迹,这时你手里已经有一套可信的基线参数,后面每一步改动都有对照。每改一个参数就存一组曲线,慢慢积累起来,你就有了属于自己的参数整定手感。这套思路,比我一开始盲目堆复杂轨迹、参数乱扫的效率高出太多了。

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

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

立即咨询