手把手教你用Matlab/Simulink搭建小车倒立摆模型(附动画脚本)
手把手教你用Matlab/Simulink搭建小车倒立摆模型(附动画脚本)
倒立摆系统作为控制理论中的经典案例,不仅在教学演示中具有重要地位,更是工程实践中验证控制算法的理想平台。本文将带你从零开始,一步步完成小车倒立摆的物理建模、Simulink仿真实现以及运动动画生成,无需任何前置经验,只需跟随操作即可获得直观的可视化结果。
1. 环境准备与基础建模
1.1 系统参数定义
首先在Matlab脚本中定义系统物理参数,建议使用.m脚本统一管理:
% 系统物理参数 M = 0.5; % 小车质量(kg) m = 0.2; % 摆杆质量(kg) b = 0.1; % 小车摩擦系数(N/m/s) l = 0.3; % 摆杆长度(m) g = 9.8; % 重力加速度(m/s^2)1.2 动力学方程推导
采用拉格朗日法建立系统动力学方程。关键推导步骤如下:
建立系统动能表达式:
- 小车平动动能:$T_c = \frac{1}{2}M\dot{x}^2$
- 摆杆复合动能:$T_p = \frac{1}{2}m(\dot{x}_p^2 + \dot{y}_p^2)$
建立系统势能表达式:
- $V = mgl\cosθ$
构造拉格朗日函数:
- $L = T - V = (T_c + T_p) - V$
最终得到的非线性微分方程:
$$ \begin{cases} (M+m)\ddot{x} + ml\ddotθ\cosθ - ml\dotθ^2\sinθ + b\dot{x} = F \ ml\ddot{x}\cosθ + ml^2\ddotθ - mgl\sinθ = 0 \end{cases} $$
2. Simulink模型搭建
2.1 非线性模型实现
在Simulink中按照以下结构搭建模型:
[F] → [Sum] → [1/(M+m)] → [Integrator] → [Velocity] ↑ ↑ └── [Feedback Terms] ← [Theta Calculation]具体操作步骤:
新建Blank Model,从Library Browser添加以下模块:
Integrator×4(分别对应x, dx, θ, dθ)Gain(设置质量参数)Trigonometric Function(处理sin/cos项)Product(处理耦合项)
关键配置参数:
% 在Model Properties → Callbacks中添加初始化代码 set_param(gcs, 'Solver', 'ode45'); set_param(gcs, 'StopTime', '10');
2.2 线性化模型对比
在工作空间生成线性化模型:
% 在平衡点附近线性化 [A,B,C,D] = linmod('InvertedPendulum_Nonlinear'); sys_linear = ss(A,B,C,D);通过以下命令验证线性化效果:
% 对比非线性与线性响应 initial_angle = 0.1; % 小角度验证 simOut = sim('InvertedPendulum_Nonlinear'); figure; plot(simOut.tout, simOut.theta); hold on; [y,t] = initial(sys_linear, [0;0;initial_angle;0]); plot(t, y(:,2), '--'); legend('Nonlinear','Linearized');3. 控制系统设计
3.1 LQR控制器实现
设计状态反馈控制器:
% 权重矩阵设置 Q = diag([10 1 100 10]); % 重点控制角度偏差 R = 0.01; % 控制输入权重 % LQR求解 [K, S, e] = lqr(A, B, Q, R); % 闭环系统验证 sys_cl = ss(A-B*K, B, C, D); step(sys_cl);典型调试经验:
- 若小车位移响应过慢,增加Q矩阵中x的权重
- 若控制力过大,减小R值
- 角度振荡时可调整dθ的权重
3.2 状态观测器设计
当只有角度可测量时,设计Kalman滤波器:
% 观测矩阵调整(假设仅测量角度) C_obs = [0 0 1 0]; D_obs = 0; % 噪声协方差矩阵 Vd = diag([0.1 0.1 0.5 0.5]); % 过程噪声 Vn = 0.01; % 测量噪声 % Kalman增益计算 [Kf,P,E] = lqe(A, eye(4), C_obs, Vd, Vn);4. 动画可视化实现
4.1 实时动画脚本
创建animate_pendulum.m脚本:
function animate_pendulum(t, x, theta) figure; h1 = plot([0], [0], 'k-', 'LineWidth', 2); % 小车 hold on; h2 = plot([0], [0], 'r-o', 'LineWidth', 2); % 摆杆 axis([-2 2 -0.5 1.5]); for k = 1:length(t) % 小车位置更新 car_x = [x(k)-0.2 x(k)+0.2]; car_y = [0 0]; set(h1, 'XData', car_x, 'YData', car_y); % 摆杆位置更新 pend_x = [x(k) x(k)+l*sin(theta(k))]; pend_y = [0 l*cos(theta(k))]; set(h2, 'XData', pend_x, 'YData', pend_y); drawnow; pause(0.01); end end4.2 仿真结果可视化
在Simulink模型最后添加To Workspace模块,导出仿真数据后调用动画函数:
% 运行仿真 simOut = sim('InvertedPendulum_Full'); % 提取数据 t = simOut.tout; x = simOut.x.Data; theta = simOut.theta.Data; % 生成动画 animate_pendulum(t, x, theta); % 保存为视频(需要Image Processing Toolbox) writerObj = VideoWriter('pendulum_animation.mp4', 'MPEG-4'); open(writerObj); for k = 1:10:length(t) frame = getframe(gcf); writeVideo(writerObj, frame); end close(writerObj);5. 常见问题排查
调试过程中可能遇到的典型问题及解决方案:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 仿真发散 | 初始角度过大 | 限制初始角度<0.3rad |
| 小车跑出视野 | 位移未限制 | 在LQR中增加x权重 |
| 动画卡顿 | 步长过大 | 减小Simulink Max Step Size |
| 观测器偏差大 | 噪声参数不匹配 | 调整Vd和Vn矩阵 |
实际项目中发现,当摆杆长度超过0.5m时,需要重新调整控制器参数。一个实用的调试技巧是先用PID稳定角度,再切换为LQR控制。
