
从“系统摆烂”到精准跟踪MATLAB实现LQR轨迹跟踪的实战手记第一次在MATLAB里复现LQR轨迹跟踪时我盯着屏幕上那条始终差0.5个单位的位置曲线突然理解了什么叫“系统摆烂”——它明明有能力到达目标点却选择在距离终点一步之遥的地方躺平。这种令人哭笑不得的现象恰恰揭示了经典LQR控制器设计中最容易被忽视的关键细节。1. 初识LQR轨迹跟踪的“摆烂”现象那是个周二的深夜我的MATLAB工作区里运行着一个看似完美的弹簧阻尼系统模型。按照教科书上的标准流程我建立了系统状态方程m 1; % 质量块重量(kg) c 0.2; % 阻尼系数 k 0.5; % 弹簧系数 T 0.1; % 采样周期(s) A [1 T; -k*T/m 1-c*T/m]; % 状态矩阵 B [0; T/m]; % 输入矩阵期望状态设为Xd [1; 0]位置1米速度0代价函数权重矩阵Q和R都设置为单位矩阵。理论上这个配置应该让系统稳定在期望点。但实际仿真结果却显示时间(s)稳态位置控制输入0-50.50.255-100.50.25系统在距离目标点0.5米处就停止了努力控制输入也维持在最低水平。这就像让一个学生考试及格就行——他确实做到了60分但绝不会多花力气争取90分。关键发现当期望点不是系统自然稳定点时标准LQR会导致稳态误差。控制器在努力成本R权重和状态误差Q权重之间找到了一个偷懒的平衡点。2. 问题诊断为什么系统选择“躺平”通过代价函数分析我发现了系统摆烂的数学本质。原始LQR的代价函数J Σ(xᵀQx uᵀRu)当x0时系统确实能达到零代价。但在轨迹跟踪场景中我们需要的是x→xd≠0。直接套用原始公式相当于要求系统同时满足两个矛盾条件状态误差(x-xd)→0控制能量u→0当xd不是系统的自然稳定点时这两个条件无法同时满足。系统会找到一个使J最小的折中点——这就是我们看到的“摆烂”状态。三个关键验证步骤检查开环稳定性eig(A)显示系统本身只能在x0处稳定代价函数分解将J对x0.5和u0.25时的各项代价量化控制能量分析计算不同位置所需的维持力% 验证代码片段 x_steady 0.5; u_steady 0.25; J_steady x_steady^2 * Q(1,1) u_steady^2 * R结果显示系统确实找到了局部最优解——任何试图更接近xd1的操作都会导致总代价J上升。3. 解决方案增广状态空间建模破局之道在于重构问题形式。通过引入增广状态空间将误差动态转化为新的状态变量X_aug [x; xd] % 增广状态向量 e x - xd % 跟踪误差对应的增广系统矩阵变为A_aug [A, zeros(2); zeros(2), eye(2)]; % 4x4矩阵 B_aug [B; zeros(2,1)]; % 4x1矩阵在新的框架下代价函数重新定义为J Σ(eᵀQe uᵀRu) Σ(X_augᵀDᵀQDX_aug uᵀRu)其中D [I -I]是误差选择矩阵。这种形式将问题转化为标准的LQR问题但针对的是误差动态系统。实现细节中的三个陷阱权重矩阵维度需要适配增广系统初始状态必须包含期望轨迹信息离散积分环节需要特别注意实践提示增广后的Q矩阵应为4×4但实际只有前2×2块通过DᵀQD参与计算。一个常见错误是直接使用原始Q的维度。4. 调试实录从理论到实现的五个关键步骤4.1 构建增广系统% 原始系统 A [1 T; -k*T/m 1-c*T/m]; B [0; T/m]; % 增广系统 A_aug blkdiag(A, eye(2)); % 4x4 B_aug [B; zeros(2,1)]; % 4x1 Ca [eye(2), -eye(2)]; % 误差选择矩阵4.2 重新设计权重矩阵Q_original eye(2); % 原始Q矩阵 Q_aug Ca * Q_original * Ca; % 4x4增广Q R 1; % 控制权重保持不变4.3 求解Riccati方程[K_aug,~,~] dlqr(A_aug, B_aug, Q_aug, R);4.4 实现反馈控制for k 1:N e [x(k); v(k)] - xd; % 误差计算 u(k) -K_aug * [x(k); v(k); xd]; % 增广状态反馈 x(k1) A(1,:)*[x(k); v(k)] B(1)*u(k); v(k1) A(2,:)*[x(k); v(k)] B(2)*u(k); end4.5 调整权重比观察响应通过调整Q/R比值可以得到不同的系统行为Q/R比值稳态误差控制能量系统行为描述10.50.25典型摆烂状态100.10.8适度努力1000.012.5拼命三郎模式10000.0018.0过度消耗5. 完整可运行代码与避坑指南以下是一个经过验证的MATLAB脚本包含所有关键步骤和可视化% 参数设置 m 1; c 0.2; k 0.5; T 0.1; A [1 T; -k*T/m 1-c*T/m]; B [0; T/m]; xd [1; 0]; % 期望状态 % 增广系统构建 A_aug blkdiag(A, eye(2)); B_aug [B; zeros(2,1)]; Ca [eye(2), -eye(2)]; % 权重配置 Q_original 100*eye(2); % 加大状态权重 R 1; Q_aug Ca * Q_original * Ca; % 求解LQR增益 [K_aug, ~, ~] dlqr(A_aug, B_aug, Q_aug, R); % 仿真运行 N 100; x zeros(2,N1); x(:,1) [3;0]; % 初始状态 u zeros(1,N); for k 1:N u(k) -K_aug * [x(:,k); xd]; x(:,k1) A*x(:,k) B*u(k); end % 可视化 figure; subplot(2,1,1); plot(0:T:N*T, x(1,:)); xlabel(时间(s)); ylabel(位置(m)); grid on; subplot(2,1,2); plot(0:T:(N-1)*T, u); xlabel(时间(s)); ylabel(控制力(N)); grid on;五个必查的调试要点增广矩阵维度是否正确应为4×4和4×1权重矩阵Q_aug是否通过Ca转换初始状态是否包含物理状态和期望状态反馈增益K_aug的维度是否匹配1×4离散时间步长T是否与连续系统特性匹配当我把R从1降到0.01时系统终于不再摆烂——位置曲线坚决地指向了期望的1.0米标记。代价是控制输入峰值增加了15倍就像学生为了满分熬夜刷题。这让我想起导师常说的一句话“控制工程就是权衡的艺术你要决定系统应该多努力才算够。”