简介:这是一份面向控制理论与自动化初学者的LQR一阶倒立摆MATLAB源码包,聚焦倒立摆系统建模、非线性线性化与LQR最优控制器设计问题。压缩包共5个文件,以4个.m脚本和1个.asv辅助脚本为主,整体仅3KB;其中演示脚本提供完整可运行设计流程,平台与摆杆模型脚本分别刻画系统动力学,另有算法实现与数据辅助文件支撑二次开发。已有1724人学习使用。读者可通过演示示例逐步掌握状态空间模型构建、Riccati方程求解和控制器增益计算,直观理解LQR算法对不稳定平衡点的镇定作用;通过修改质量、杆长等模型参数,还能进一步观察控制输入与系统状态响应的动态变化,为后续鲁棒控制、约束优化等扩展研究打下基础。
1. 从 LQR 到一阶倒立摆:控制律设计、仿真与实物部署的完整闭环
倒立摆是控制理论里最经典的验证平台,而 LQR(线性二次型调节器)又是把倒立摆稳住的最短路径之一。这份「LQR 一阶倒立摆」资料,核心价值不在于给你一段能跑的代码,而在于它把建模、状态反馈、权重调参、Simulink 仿真到实物部署的完整链路串了起来。如果你正在做课程设计、毕业设计,或者刚接触状态空间控制想找个能落地的练手项目,这套东西能帮你少走大量弯路。我拆过几套类似的资源,坦白说,很多资料只给一个 .m 脚本和一张仿真截图,参数怎么来的、换了硬件还能不能稳、抗扰能力如何,全是黑匣子。这套资源至少把关键推导步骤和调参路径留出来了,下面我按自己的拆解顺序给你过一遍。
2. 一阶倒立摆的建模与 LQR 原理:先把状态方程写对,后面才不会翻车
2.1 从牛顿力学到状态空间方程:为什么一阶模型也要认真推导
倒立摆的物理模型看起来简单——一根摆杆装在电机驱动的滑块上,目标是让摆杆保持竖直。但真正动手建模时,第一个坑就是坐标系和符号约定。常见的一阶倒立摆(也叫一级直线倒立摆)包含小车质量 M、摆杆质量 m、摆杆长度 l、转动惯量 J、摩擦系数 b,以及小车驱动力 F。
我一般习惯按以下步骤推导:先单独分析小车水平方向受力,再分析摆杆绕质心的转动,联立后做小角度近似(sinθ≈θ,cosθ≈1),然后消除中间变量得到四个状态(小车位移 x、小车速度 dx、摆杆角度 θ、摆杆角速度 dθ)的状态方程。
推导结果的标准形式是:
dx/dt = Ax + Bu y = Cx + Du其中状态向量 x = [x; dx; θ; dθ]。资料里给出的 A 矩阵和 B 矩阵是经过小角度线性化后的结果,我把它整理成代码里可以直接用的形式。
2.2 LQR 核心公式与权重矩阵 Q、R 的物理意义
LQR 的目标是设计一个状态反馈增益 K,使得控制量 u = -Kx 能够最小化如下代价函数:
J = ∫(x'Qx + u'Ru) dt这里的 Q 矩阵是半正定状态权重矩阵,R 是正定控制权重矩阵。Q 的对角元素分别对应四个状态的重要性:Q11 对应小车位置、Q22 对应小车速度、Q33 对应摆杆角度、Q44 对应摆杆角速度。R 对应电机驱动力(控制量)的惩罚。
实际调参经验是:如果摆杆稳不住,优先加大 Q33(角度权重);如果小车位移漂移太远,加大 Q11;如果控制量饱和或电机抖动厉害,则加大 R。资料提供的初始权重一般是 Q = diag([100, 10, 100, 10])、R = 0.1 这种量级,但换一套硬件后必须重新调。
了解原理后直接去调参容易没有方向感,建议先跑通下面这段 MATLAB 脚本,把 K 算出来看看量级。
% 倒立摆状态空间模型参数(SI单位) M = 0.5; % 小车质量 kg m = 0.2; % 摆杆质量 kg b = 0.1; % 小车摩擦系数 N/(m/s) l = 0.3; % 摆杆质心到转轴距离 m(注意是半长) I = 0.006; % 摆杆转动惯量 kg*m^2 g = 9.8; % 重力加速度 % 线性化后的状态空间矩阵 % 状态: x1=小车位移, x2=小车速度, x3=摆杆角度, x4=摆杆角速度 p = I*(M+m)+M*m*l^2; A = [0 1 0 0; 0 -(I+m*l^2)*b/p (m^2*g*l^2)/p 0; 0 0 0 1; 0 -(m*l*b)/p m*g*l*(M+m)/p 0]; B = [0; (I+m*l^2)/p; 0; m*l/p]; C = [1 0 0 0; 0 0 1 0]; D = [0; 0]; % 检查可控性 co = ctrb(A,B); if rank(co) < size(A,1) error('系统不可控,检查建模参数'); end % LQR 权重矩阵 Q = diag([100, 10, 100, 10]); R = 0.1; % 求解状态反馈增益 K = lqr(A,B,Q,R); disp('LQR 增益 K ='); disp(K);这段代码的意图是先在 MATLAB 里把模型参数固化成变量,然后通过lqr函数直接求得状态反馈矩阵 K。ctrb可控性检查是非常容易被忽略的一步——很多资料直接跳过,但如果你改了模型参数后发现lqr报错或仿真发散,多半是系统在某个参数组合下不可控。
参数层面的注意点:摆杆长度 l 这里用的是质心到转轴的距离,也就是摆杆总长的一半左右。如果你用的摆杆是均匀杆,转动惯量 I 可以按 1/3 * m * L^2 估算,L 是摆杆总长。很多新手在这里用总长去代,导致模型参数和实物不一致,仿真能稳住、实物一上电就摔杆。
2.3 从 K 矩阵看 LQR 的控制律本质
求得 K 之后,控制量 u = -Kx 的物理意义就很直观了。假设 K = [k1, k2, k3, k4],那么实际输出到电机的电压或力矩为:
u = -k1*x - k2*dx - k3*θ - k4*dθ每一项都有明确的物理角色:-k1x 是位置反馈,把小车拉回原点;-k2dx 是速度阻尼,防止小车来回振荡;-k3θ 是角度反馈,这是稳定摆杆的核心项,当摆杆向右倾斜时输出反向力矩;-k4dθ 是角速度阻尼,抑制摆杆的快速摆动。
一个非常实用的观察方法是看 K 里各项的数量级。如果你发现 k3 比其他项小了 1 到 2 个数量级,说明摆杆角度的权重设置过小,抗扰动能力会很差。反之如果 k4 过大,控制量会频繁饱和,电机容易过热。
资料里给出的 Simulink 仿真模型通常把 K 封装成 Gain 模块,四个状态通过 Mux 汇总后乘以 K。这里我要强调一个常见错误:Simulink 里的状态顺序必须和 A 矩阵定义的状态顺序保持一致,否则 K 矩阵应用到错误的状态上,仿真结果看起来像随机噪声。
3. 仿真环境搭建与 LQR 参数整定:在 Simulink 里把系统跑稳
3.1 从零搭建 LQR 控制仿真框图:每个模块的作用和连接方式
拿到状态方程和 K 矩阵后,下一步就是把控制回路在 Simulink 里搭出来。常见做法是使用状态空间模块(State-Space)作为被控对象,前面接一个 Gain 模块实现反馈,再加上一个 Reference 输入用于给定目标位置。
一个最基本的 LQR 闭环框图包含以下模块:
- State-Space 模块:输入为 u(控制量),输出为状态向量 x。A、B、C、D 直接填入 2.2 节代码算出的矩阵。
- Gain 模块(反馈增益):增益值设为 K,输入为状态 x,输出为 -Kx。
- Sum 模块:将参考输入 r 与反馈量合并。注意这里不是直接把 r 和 -Kx 相加,而是根据控制目标决定是否引入前馈。
- Scope 模块:观察四个状态随时间的变化曲线。
我用文字描述一下典型连接关系:参考信号 r(比如方波,幅值 0.2m 的位移指令)通过一个 K_r 模块(参考前馈增益)进入 Sum,然后和 -Kx 汇合后作为 State-Space 的输入 u。State-Space 的输出端接一个 Demux 拆出四个状态,一路送到 Scope,另一路反馈回 Gain。
如果你对前馈增益 K_r 怎么算没把握,有个偷懒但有效的做法:直接把参考信号加在 x(小车位移)上,然后用 K 矩阵里的第一个元素做比例补偿。更严谨的推导是用零状态误差条件去解 K_r,但仿真阶段不需要做到这一步,只要保证系统能跟踪阶跃即可。
3.2 参数整定的三种路径:手动试错、自动寻优、经验公式
LQR 参数整定是倒立摆项目里最耗时间、也最容易让人血压飙升的环节。我给三条路径,按效率从低到高排列。
第一种是纯手动试错:先固定 R 不动,依次增大 Q33(角度权重)直到摆杆能稳定,然后再调 Q11 控制位移回中。每次改变权重后重新运行lqr函数求解 K,观察 Scope 波形。这个方法优点是直观、帮助理解权重作用,缺点是效率低,尤其是在参数交互影响明显时容易陷入局部调参怪圈。
第二种是脚本化批量仿真:用一个 MATLAB 脚本,把 Q 的候选值写成数组,循环求解 K 并运行 Simulink,最后自动提取超调量和调节时间,用表格或曲线对比。这段脚本虽然简单,但能大大减少手工重复劳动。
% 批量扫描 Q33 权重对系统响应的影响 Q33_list = [10, 50, 100, 200, 500]; results = zeros(length(Q33_list), 3); for i = 1:length(Q33_list) Q = diag([100, 10, Q33_list(i), 10]); K = lqr(A,B,Q,R); % 更新 Simulink 模型中的增益参数(假设模型名为 pendulum_lqr) set_param('pendulum_lqr/Feedback Gain', 'Gain', mat2str(K)); % 运行仿真并获取输出(假设输出到工作区变量 simout) simOut = sim('pendulum_lqr'); y = simOut.yout{1}.Values.Data; t = simOut.yout{1}.Values.Time; % 提取小车位移的峰值时间和稳态误差 % 这里用简单指标:角度最大偏差和调节时间 angle = y(:,2); % 假设输出中第一列是位移,第二列是角度 max_angle_dev = max(abs(angle)); % 找到调节时间(角度进入 ±5% 区间后不再超出) idx_settle = find(abs(angle) < 0.05*abs(angle(1)), 1, 'first'); if isempty(idx_settle) settle_time = inf; else settle_time = t(idx_settle); end results(i,:) = [Q33_list(i), max_angle_dev, settle_time]; end % 打印对比表 disp('Q33 最大角度偏差 调节时间'); disp(results);这段脚本的核心思路是通过set_param动态修改 Simulink 中的 Gain 参数,然后批量运行得到性能指标。我通常会额外记录控制量 u 的最大值,因为电机饱和往往是实物部署翻车的主要原因。如果simOut.yout结构和你模型里的输出配置不一致,需要先检查 To Workspace 模块的变量名和采样时间。
第三种是使用 MATLAB 的 Response Optimizer 或 Control System Tuner 工具,自动调整 Q 和 R 来满足超调量、稳定时间等设计约束。这个方法适合熟手,因为工具给出的中间解往往物理意义不清晰,你很难解释为什么某个权重是最优的,答辩时容易被老师问住。我建议新手至少完整手动调一次,再考虑自动寻优。
3.3 仿真结果判读:稳定、临界振荡、发散三种形态的信号特征
仿真跑完之后,最关键的是能读懂 Scope 波形。我把常见的几种波形形态和对应的调参建议列出来方便你对照:
| 波形形态 | 典型特征 | 调参方向 |
|---|---|---|
| 稳定收敛 | 摆角从初始偏移(比如 5 度)平滑衰减到 0,无振荡 | 当前参数可用,可继续优化性能 |
| 临界振荡 | 摆角持续等幅振荡,不衰减也不发散 | 加大 Q33 或 Q44,或减小 R |
| 发散 | 摆角单调增大或振荡幅度快速增大 | 检查系统可控性、K 符号、状态顺序 |
| 响应迟缓 | 摆角恢复很慢,像没吃饭一样 | 减小 R 或增大 Q33,提高控制力度 |
一个容易被忽视的指标是控制量的饱和程度。如果 u 的波形经常撞到 ±10V(或电机额定力矩),说明 LQR 求出的理想控制量在物理上根本不可达。这时无论你怎么调 Q 和 R,实物都会在剧烈抖动后倒下,因为执行器的输出饱和了。
我看到过很多人在这一步卡住,反复调 Q 但始终改不了波形发散的问题。后来发现是状态空间模块里的 C 矩阵设置不对,输出的是 [x, dx] 而不是 [x, θ]。这种低级错误通过检查模块内部的矩阵和观察波形形状就能快速定位——如果波形发散得毫无规律,优先怀疑矩阵填错而不是权重不合适。
4. 避坑指南:LQR 倒立摆从仿真到实物最常见的四个翻车点
4.1 现象:仿真波形完美,实物上电后摆杆直接倒下
原因:仿真中的模型参数与实物严重不符,尤其是摩擦系数 b 和转动惯量 I。仿真里 b=0.1 用得很顺手,但实物导轨的摩擦力可能明显更大,导致实际阻尼和模型不一致。
解决:拿到实物后先做开环测试,给电机一个已知的阶跃电压,记录小车的加速度曲线,反推实际摩擦系数和等效质量。不要直接沿用课件或资料给的模型参数,至少用 10 分钟把实物参数标定一遍。
4.2 现象:调参时 Q 和 R 反复修改,系统始终有低频抖动
原因:LQR 本身是连续时间控制器,但实物控制是离散采样,同时编码器反馈存在量化噪声。如果采样频率过低(比如 100Hz)或编码器分辨率不够,控制信号会带上明显的噪声成分。
解决:检查控制周期是否足够快,一般建议至少 500Hz 以上。编码器分辨率至少 1024 线以上,角度测量推荐用增量式编码器配合正交解码。若抖动明显,可在反馈通道上加一阶低通滤波,但要注意延迟对稳定性的影响。
4.3 现象:小车位移发散,但摆杆角度稳定
原因:这是一个非常经典的权重设置误区。Q 矩阵里小车位置权重 Q11 过小,LQR 认为让小车漂移比花力气把车推回原点更“划算”。从代价函数的角度看,控制量对位移几乎没有惩罚,系统放松了对位置约束。
解决:增大 Q11,让位置权重比角度权重高一个数量级。也可以把状态空间模型里的角度单位从弧度改为度,但我不推荐这种方式,因为它只改变数值尺度,不改变物理约束的实质。
4.4 现象:Simulink 仿真速度极慢,或者仿真结果不稳定
原因:模型中使用了连续状态空间模块,但仿真步长设置过大,导致数值积分不收敛,尤其在小角度近似失效的瞬间,模型会出现应急性发散。另外,如果你在模型中添加了非线性摩擦或限幅模块,步长过大会引入数值刚性。
解决:将求解器设置为ode45并限制最大步长为 1e-3 秒,或者使用固定的ode4步长 1ms。检查模型中是否有代数环——当反馈信号直接没有经过延迟或状态模块就回到输入端时,Simulink 会报代数环警告,实际仿真结果也不可靠。
这里我想单独提一句:很多人遇到实物倒立摆稳住后左右缓慢漂移,第一反应是继续调 Q,但其实问题已经不在 LQR 参数上,而是位置环没有积分作用。LQR 是比例状态反馈,对恒值扰动(比如导轨轻微倾斜、电机死区)存在稳态误差,需要引入积分型 LQR 或外环 PID 来消除。这个坑在资料里容易被忽略,因为纯仿真里不存在摩擦死区和导轨倾角的影响。
5. 进阶验证与部署技巧:从仿真到实物的最后一步
5.1 通过扰动测试验证 LQR 的鲁棒性边界
在仿真环境里,最有效的验证方法是加入脉冲扰动。比如在摆杆处于平衡点时,给角度状态一个突变的初值(模拟手推一下),或者在小车上施加一个短时外力(模拟绳子拉拽)。通过观察系统能否恢复到平衡位置,就能判断 LQR 的稳定裕量。
具体的操作是在气隙时刻用 MATLAB 直接修改状态空间模块的内部状态,或者加一个 Pulse Generator 信号叠加到控制输入端。我强烈建议你做一组不同扰动幅值的测试,记录系统从扰动到恢复的时间。如果你的摆杆在 10 度扰动下能 2 秒内回稳,但在 15 度扰动下发散,说明工作范围在 10 度附近,这在实际项目中是很有价值的信息。
5.2 前馈补偿与积分型 LQR 的实际结合
对于位置环稳态误差问题,我通常会在 LQR 反馈基础上再加一个外环积分器,将角度保持和位置跟踪分离。常见结构是:内环用 LQR 稳定摆杆,外环用 PI 控制小车位置。这样调试起来思路更清晰——先保证内环在任意小车位置都能稳定摆杆,再调外环让小车回中。
在代码层面,状态向量的维度需要从 4 维扩展到 5 维,加入积分状态 x_i = ∫(x - x_ref) dt。对应的扩展状态矩阵和 LQR 求解方式在控理论文里都有标准推导,核心是把积分状态也纳入 Q 矩阵中赋权重。
5.3 实物控制器参数核对清单
实物部署前如果条件允许,先用 MATLAB/Simulink Desktop Real-Time 或 xPC Target 这一类的中间层跑一下验证。我自己的习惯是整理一份参数核对表,确认每一项都与仿真设置一致再上电。核对表包括这几个关键项:
- 控制周期:与仿真的固定步长是否一致,实物控制器一般用 1ms 或 2ms。
- 状态量顺序:编码器读出的角度微分是否对应状态方程的第三、第四个状态。
- 输出限幅:控制量是否经过限幅,限幅方向和仿真中的 Saturation 模块是否一致。
- 反馈极性:基座标定的角速度方向与状态方程定义是否一致,很多人栽在这里,表现是角度能稳住但连续振荡。
在拉线调试之前,最好先用虚拟偏置测试控制方向逻辑:手动把摆杆推到一侧,观察控制量输出是否朝相反方向作用。这一步看似简单,却能避免上电后因为正负号错误导致摆杆加速倒下的尴尬。
从那以后,我每次搭倒立摆项目都强制要求自己先写完状态方程和参数标定表,再进入仿真和调参环节,最后拉实物时按核对表逐项确认。这套流程虽然看起来慢,但实际能帮你省下大量摔杆重试的时间。希望帮到你。
本文还有配套的精品资源,点击获取