资讯动态

基于Simulink的倒立摆模糊控制仿真设计与实现

发布时间:2026/10/25 18:42:07 来源:尧图企业网站定制
简介面向初学者的倒立摆模糊控制Simulink仿真资料包围绕非线性倒立摆系统的稳定控制展开完整演示从模糊PID角度控制到位置与角度分段模糊控制的实现路径适合学习模糊逻辑与MATLAB/Simulink建模的控制类专业学生和工程技术人员。压缩包共140个文件约6.15MB以mat数据文件、m脚本、mdl模型、fis模糊规则文件、avi仿真录像及docx实验报告为主并配有png/jpg图片辅助查看曲线与结果。已有6455人学习下载。内容涵盖实验1-1的模糊PID控制器模型PID_pendulum.mdl以及实验1-2的位置模糊控制器position_fuzzy.fis与pendulum_pre.mdl联合控制方案模糊控制实验报告对设计思路和仿真结果做了详细说明。原始仿真.avi与改进仿真.avi可直观对比模糊控制前后的动态差异GetPendulum.m和Animation.m脚本支持提取倒立摆动态数据并生成动画便于复现实验和调整参数。整体结构清晰特别适合通过具体案例快速上手模糊控制设计与Simulink仿真验证。1. 倒立摆的模糊控制不靠精确模型也能把摆杆稳住被倒立摆支配过的控制专业学生多半都经历过这个场景老师说用状态空间法设计 LQR推导了一页草稿纸最后仿真里的摆杆还是像个醉汉一样左右打摆。而这个项目标题给出的路径完全反着来——倒立摆的模糊控制基于 Simulink 仿真适合初学者。模糊控制不依赖精确数学模型而是把人的操作经验翻译成几条“角度偏大且还在加速倒就用力顶回去”这类规则就能稳定住摆杆。你要做的不过是三件事搭一个能动的倒立摆模型、设计一张模糊规则表、在 Simulink 里把闭环接起来。这套方案适合正在学模糊控制、做课程设计、或者第一次碰 Simulink 仿真的人。但事先说清楚它参数比 PID 少却一点都不“傻瓜”真正开始调仿真时发散才是常态撑过那一步后面就是平地。2. 倒立摆动力学模型从运动方程到 Simulink 可跑的积分器结构2.1 为什么模糊控制不需要精确模型但还是得先搭一个模糊控制的设计过程确实可以完全绕开被控对象模型因为规则表直接建立在“角度大、角速度快”这类语言变量上不需要线性化状态矩阵 A 和 B也不需要解 Riccati 方程。但做闭环仿真时Simulink 里必须有一个被控对象的微分方程否则控制器输出找不到落点。倒立摆适合做模糊控制入门正是因为它非线性、自不稳定姿态一偏就指数级发散模糊控制要处理的恰恰是这种“一个线性模型描述不了全工况”的对象。我见过不少初学者直接双击资源包里的封装子系统就开始仿真跑通了也不知道里面是什么一旦发散就无从下手。做这个方向建议至少手动搭一遍动力学部分哪怕后面换成资源包里现成的模型你也能在信号线上看出哪一段是积分、哪一段是控制器。倒立摆的常见简化模型是忽略摩擦、把摆杆质量集中在质心这样只涉及四个物理量小车质量 M、摆杆质量 m、质心到转轴距离 l、重力加速度 g。2.2 用 MATLAB Function 写 cart-pole 动力学核心方程与参数小车-摆杆系统的运动方程可以由拉格朗日方程推出。设 x 为小车水平位移θ 为摆杆与竖直方向的夹角F 为作用在小车上的水平控制力则两个主方程是(M m) x m l θ cosθ - m l θ² sinθ F x cosθ l θ -g sinθ把 θ 从这两个方程里消掉就能得到适合在积分器里直接使用的加速度表达式。下面这段 MATLAB Function 是常见做法也是我建议初学者优先采用的方案输入状态量输出两个加速度交给 Simulink 积分器积分成速度和位移。function [x_dd, theta_dd] cart_pole_dynamics(x, theta, x_d, theta_d, F, M, m, l, g) % 输入x 小车位移theta 摆杆角度x_d 小车速度theta_d 摆杆角速度F 控制力 % 输出x_dd 小车加速度theta_dd 摆杆角加速度 % 单位角度用弧度力用牛顿长度用米 % 分母项当 theta 接近 ±90° 时分母会变小这是模型自身的非线性特性 den l * ((M m) - m * cos(theta)^2); % 摆杆角加速度 theta_dd -(F * cos(theta) (M m) * g * sin(theta) ... m * l * theta_d^2 * sin(theta) * cos(theta)) / den; % 小车加速度由第一个运动方程改写而来 x_dd (F - m * l * theta_dd * cos(theta) m * l * theta_d^2 * sin(theta)) / (M m); end这段代码的逻辑不复杂den 是消元后出现的分母项它跟摆杆质量在小车方向上的投影有关theta_dd 的分子里有重力项、控制力项和离心项分别对应摆杆自然倾倒、小车推力带来的惯性力、以及摆杆转动时的离心效应。注意 theta 必须用弧度如果你把角度值直接喂进来sin 函数的输入会完全错乱这是新手最容易忽略的一个单位陷阱。参数按课程设计的常见配置取即可不需要纠结精确值因为模糊控制对参数不敏感参数含义常见取值M小车质量1.0 kgm摆杆质量0.1 kgl摆杆质心到转轴距离0.5 mg重力加速度9.8 m/s²2.3 从方程到 Simulink积分器、常量和连接顺序有了加速度表达式剩下的工作就是积分。倒立摆仿真模型的被控对象部分通常由两组积分器构成theta_dd 积分成 theta_d再积分成 thetax_dd 积分成 x_d再积分成 x。MATLAB Function 模块放在控制器输出和积分器之间输入依次是 x、theta、x_d、theta_d、F输出是 x_dd 和 theta_dd。我一般先把参数写成独立脚本这样仿真前不用在模型里敲数字后面调参也方便。建模时增益模块和积分器初始值直接引用脚本里的变量名。% set_params.m 倒立摆仿真初始化脚本 M 1.0; % 小车质量, kg m 0.1; % 摆杆质量, kg l 0.5; % 摆杆质心到转轴距离, m g 9.8; % 重力加速度, m/s^2 theta0 0.2; % 初始摆角, rad约11.5度 x0 0; % 小车初始位移, m theta_d0 0; % 初始角速度, rad/s x_d0 0; % 初始速度, m/s % 量化因子把物理量映射到模糊论域 [-3,3] Ke 15; % 角度: 0.2 rad - 3 Kec 3; % 角速度: 1 rad/s - 3 Ku 6.67; % 控制力: 3 - 20 N % 加载模糊规则文件Simulink 通过工作区变量名访问它 fis readfis(cart_pole.fis);这里面 Ke、Kec、Ku 是模糊控制器最重要的三个数。角度实际范围是 ±0.2 rad映射到论域 ±3所以 Ke 取 15角速度一般不超过 ±1 rad/s所以 Kec 取 3输出力实际范围是 ±20 N所以 Ku 取 6.67。先按这个量级跑通再往大了或往小了调。Simulink 里连接时注意两点一是 MATLAB Function 模块的输入端口顺序必须跟你写的函数签名一致我把 x 排最前是因为后面接示波器时习惯先看位移二是 theta 积分器的初始条件一定在模块参数里设置为 theta0如果保持默认的 0摆杆一开始就是竖直的模糊控制根本没有机会展示纠偏过程仿真曲线也看不出控制效果。3. 模糊控制器设计输入输出、隶属度函数与规则表的制作3.1 模糊控制器的输入输出怎么选E 和 EC 的物理含义倒立摆模糊控制最常见的结构是双输入单输出输入取摆角角度 E 和角速度 EC输出取小车控制力 U。E 告诉你“偏了多少”EC 告诉你“正在往哪个方向偏、偏得多快”有了这两条信息就能像人一样判断该往哪边推、推多大力。位置 x 为什么不作为输入因为第一层控制目标是姿态稳定位置漂移属于外环问题初学者的方案通常只做姿态环把小车位置留到后续扩展否则规则表维度一上去设计难度立刻翻倍。输入输出选定后先要把物理量映射到一个统一论域。Fuzzy Logic Designer 里默认论域是 [-3, 3]但实际角度只有 ±0.2 rad角速度只有 ±1 rad/s直接喂给 FIS 会打到论域边缘控制精度很差。所以 Simulink 里在信号进 FIS 之前要加增益模块做尺度变换这就是 2.3 节里 Ke、Kec 的由来。输出端同理FIS 输出的论域值是抽象力度必须乘 Ku 换算成真实牛顿数再经过限幅模块才送给被控对象。3.2 用脚本创建 FIS隶属度函数与参数设置创建 FIS 有两种路径老式做法是在 MATLAB 命令窗口输入 fuzzy 打开图形界面手动添加输入输出、画隶属度函数、编辑规则表最后导出 .fis 文件新版本 MATLAB 更推荐用脚本方式可重复性更好改起来也快。% 创建倒立摆模糊控制器 FIS fis mamfis(Name, cart_pole_fis); % 输入1角度误差 E论域 [-3,3]5个语言值 fis addInput(fis, [-3 3], Name, E); fis addMF(fis, E, trimf, [-3 -3 -1.5], Name, NB); fis addMF(fis, E, trimf, [-3 -1.5 0], Name, NS); fis addMF(fis, E, trimf, [-1.5 0 1.5], Name, ZO); fis addMF(fis, E, trimf, [0 1.5 3], Name, PS); fis addMF(fis, E, trimf, [1.5 3 3], Name, PB); % 输入2角速度 EC论域 [-3,3]5个语言值 fis addInput(fis, [-3 3], Name, EC); fis addMF(fis, EC, trimf, [-3 -3 -1.5], Name, NB); fis addMF(fis, EC, trimf, [-3 -1.5 0], Name, NS); fis addMF(fis, EC, trimf, [-1.5 0 1.5], Name, ZO); fis addMF(fis, EC, trimf, [0 1.5 3], Name, PS); fis addMF(fis, EC, trimf, [1.5 3 3], Name, PB); % 输出控制力 U论域 [-3,3]7个语言值 fis addOutput(fis, [-3 3], Name, U); fis addMF(fis, U, trimf, [-3 -3 -2], Name, NB); fis addMF(fis, U, trimf, [-3 -2 -1], Name, NM); fis addMF(fis, U, trimf, [-2 -1 0], Name, NS); fis addMF(fis, U, trimf, [-1 0 1], Name, ZO); fis addMF(fis, U, trimf, [0 1 2], Name, PS); fis addMF(fis, U, trimf, [1 2 3], Name, PM); fis addMF(fis, U, trimf, [2 3 3], Name, PB); % 规则表25条规则格式为 [E索引 EC索引 U索引 权重 连接方式] % 连接方式1 表示 AND ruleList [ 1 1 1 1 1; 1 2 1 1 1; 1 3 2 1 1; 1 4 3 1 1; 1 5 4 1 1; 2 1 1 1 1; 2 2 2 1 1; 2 3 3 1 1; 2 4 4 1 1; 2 5 5 1 1; 3 1 2 1 1; 3 2 3 1 1; 3 3 4 1 1; 3 4 5 1 1; 3 5 6 1 1; 4 1 3 1 1; 4 2 4 1 1; 4 3 5 1 1; 4 4 6 1 1; 4 5 7 1 1; 5 1 4 1 1; 5 2 5 1 1; 5 3 6 1 1; 5 4 7 1 1; 5 5 7 1 1]; fis addRule(fis, ruleList); % 保存成 .fis 文件方便统一下发给其他人 writeFIS(fis, cart_pole.fis);addMF 的参数格式是“底左、顶点、底右”三个横坐标例如 [-3 -1.5 0] 表示一个三角形顶点落在 -1.5底边从 -3 延伸到 0。输入 E 的五个语言值均匀覆盖论域相邻三角形在中间点交叉这样任意输入值都会被两到三条规则同时触发输出曲线更平滑。输出 U 用了七个语言值比输入多两层是为了在规则输出端能表达“稍微推一点”和“用力推”之间的中间力度。3.3 5×5 模糊规则表的建立思路与实例规则表可以按人的直觉直接写摆杆向右倒E 为正而且倒的速度还在加快EC 为正那就用力向右推小车。注意不是向左推——向右推小车小车向右加速摆杆由于惯性会相对向左倾斜正好把右倒的趋势抵消。这个方向关系是倒立摆控制里最容易搞反的一点反了就是正反馈仿真直接爆炸。5×5 规则表如下行是角度 E列是角速度 EC表内是对应输出 U 的语言值E \ ECNBNSZOPSPBNBNBNBNMNSZONSNBNMNSZOPSZONMNSZOPSPMPSNSZOPSPMPBPBZOPSPMPBPB这张表有两个值得注意的地方。第一主对角线方向是“同向加力”角度和角速度同号时输出较强异号时输出减弱甚至为零。比如 E 为 PB向右倒、EC 为 NB正在回摆输出是 ZO说明这时候不需要再推让摆杆自己摆回来。第二边界处 NB 和 PB 区域有强饱和效果也就是角度已经非常大时无论角速度如何输出都顶到最大力度目的是尽快把摆杆拉回工作区。3.4 在 Simulink 中挂载 FIS 及量化因子的作用Simulink 里需要从 Fuzzy Logic Toolbox 库拖出 Fuzzy Logic Controller 块双击后把 FIS Name 填成 fis让它指向工作区变量。很多人在这里翻车模型里填的是 cart_pole.fis 这个字符串但那是文件名不是变量名。正确做法是先运行 2.3 节的 set_params.m让 fis 变量加载到工作区再在块参数里填 fis。信号顺序是theta 和 theta_d 分别经过 GainKe、Kec进入 FIS 块输出再经过 GainKu和 Saturation 限幅模块最后接到被控对象的 F 输入端。Ke 把实际角度压缩到论域内Kec 同理Ku 把论域力度还原成物理力。三者一旦设置不当症状差异很明显Ke 太小响应慢Ke 太大高频振荡Kec 太大系统僵硬Kec 太小回摆过冲Ku 则是全局力度太大发抖太小根本拉不回来。4. 在 Simulink 里搭闭环从零连线到跑出稳定波形4.1 闭环回路架构被控对象、控制器与反馈路径整体模型分成三块被控对象两组积分器加 MATLAB Function、控制器Ke/Kec 增益、FIS 块、Ku 增益、限幅、观测输出Scope 与 To Workspace 模块。连接关系是theta 和 theta_d 从积分器输出端引出经过控制器后生成 FF 进入 MATLAB Function 参与动力学计算新算出的 x_dd 和 theta_dd 再积分回状态量形成闭环。整个过程没有任何外部信号发生器参与完全靠初值起动。新建模型时模块清单和参数可以参照下面这张表模块库路径关键设置MATLAB FunctionSimulink / User-Defined Functions填入 cart_pole_dynamics 函数代码Integrator两组Simulink / Continuous角度链第一个 Initial condition 填 theta0Gain3 个Simulink / Math Operations分别填 Ke、Kec、KuFuzzy Logic ControllerFuzzy Logic ToolboxFIS name 填 fisSaturationSimulink / NonLinearLower-20Upper20ScopeSimulink / Sinks接 theta、x、F 三个信号To WorkspaceSimulink / Sinks变量名 theta_out方便后处理MATLAB Function 模块默认只显示一个输入端口和一个输出端口双击打开代码编辑器写上 2.2 节的函数后端口会自动变成五个输入两个输出。此时手动连线容易接错建议把信号线用标签标出来输入端口从左到右对应 x、theta、x_d、theta_d、F其中 F 来自控制器输出其余四个来自积分器。4.2 关键模块参数设置积分器初始值、仿真停时与限幅积分器初始值直接影响仿真的“开局难度”。theta 积分器的 Initial condition 填 theta00.2另外三个积分器填 0。车初始位置为 0摆杆从偏离竖直约 11.5° 的地方开始下落这个幅度对模糊控制器来说既看得出控制过程又不至于一上来就超出线性工作范围。如果想看控制器更强力的表现可以改成 0.3但超过 0.35 之后很多简单规则表会拉不回来仿真表现为摆杆直接倒下、输出饱和。仿真求解器默认的 ode45 通常够用但需要注意一点FIS 块本身是连续采样如果你希望模拟真实数字控制器的采样周期可以在 FIS 前加一个 Zero-Order Hold 模块采样时间填 0.01 s。这会让控制量离散化摆杆的稳定性会有所下降但更接近实际嵌入式实现属于进阶玩法。Saturation 限幅必须加在 Ku 增益之后、被控对象之前否则模糊控制器输出极端值时MATLAB Function 会收到一个不切实际的巨大力度积分步长会因此自适应缩小到极小仿真慢得像蜗牛。限幅取 ±20 N 与 Ku 的设计值匹配如果调大了 Ku记得同步放宽限幅。4.3 运行仿真初始化脚本、观察曲线与调参流程模型保存成 cart_pole_control.slx 后运行顺序是先执行 set_params.m 把参数、量化因子、FIS 变量全部加载进工作区再启动仿真。命令行方式如下% 命令行运行 set_params; sim(cart_pole_control.slx);仿真时间设 20 s 左右足够看到完整过程。正常情况下 theta 曲线应该在前 3 到 5 秒内收敛到 0 附近之后在 ±0.05 rad 以内小幅波动不再发散。如果 theta 像正弦波一样持续等幅振荡说明参数接近临界稳定如果振幅越来越大说明参数方向反了或者模型搭建有误。调参顺序我一般固定为“先 Ke再 Ku最后 Kec”每次只动一个变量不要同时改三个然后不知道是哪个起的作用。第一步把 Ke 从 15 往小调到 5会发现摆杆响应变慢、恢复时间拉长第二步把 Ku 从 6.67 往大调到 15会发现过冲变大、振荡加剧第三步把 Kec 从 3 往大调到 8振荡会被压住一些但太大会让摆杆像被冻住一样反应迟钝。最理想的一组参数是稳态误差小、超调量在 20% 以内、控制力曲线不持续贴住限幅。5. 初学者避坑模糊控制倒立摆仿真最常见的 5 个翻车点5.1 仿真直接发散曲线一个积分步就飞到 1e10 级别现象点击 Run 后 Scope 里 theta 立刻出现 1e10 量级的数值或者 MATLAB 报出 NaN、Inf仿真直接崩掉。原因八成是控制方向接反了。倒立摆模糊控制的输出符号和角度定义有严格对应关系向右倒theta 为正必须向右推小车F 为正如果 F 的符号接反控制器一直在把摆杆往倒的方向推就成了正反馈系统自然瞬间发散。另外初始角度太大也会发散模糊规则表的工作范围通常只有 ±0.2 rad 左右你非要设成 0.6超出规则有效覆盖区控制器一直输出极限力度也救不回来。解决先把 theta0 改成 0.05 验证模型本身是否稳定如果小角度还发散那就是符号问题。最简单的排查方法是在 Ku 增益前面加一个 -1 增益模块试试符号一翻仿真立刻收敛那就说明控制器方向反了把 Ku 的符号改掉即可。5.2 Fuzzy Logic Controller 提示找不到 FIS 变量现象双击 Fuzzy Logic Controller 块后模型图标变红运行时弹错 “Error evaluating parameter fis in ...”或者提示变量不存在。原因块参数里填的 FIS 名称和工作区里的变量名对不上。最常见的是读者把 .fis 文件名当成变量名填了进去比如填了 ’cart_pole.fis’ 而不是 fis。另一个常见原因是模型打开时 set_params.m 还没执行过工作区是空的变量自然不存在。解决先把块参数里的 FIS name 改成 fis然后运行一次 set_params.m。如果还报错在命令行单独执行一下 load 语句确认变量真的在fis readfis(cart_pole.fis); % 重新加载 whos fis % 检查是否存在于工作区5.3 摆杆一动不动theta 保持初始值不变控制输出恒为零现象Scope 里 theta 始终等于 theta0F 曲线一直是一条 0 直线。原因信号线没接对。常见情况是 MATLAB Function 模块的输入端口顺序和函数签名不一致把 theta 接到了 x 端或者 theta_d 接到了 theta 端导致控制器拿到的角度一直是 0规则表输出 ZO控制力永远为 0。还有一种情况是 F 信号没从控制器接出来直接悬空Simulink 会把悬空输入当 0 处理。解决打开 MATLAB Function 模块核对函数签名第一个输入是 x第二个是 theta第三个是 x_d第四个是 theta_d第五个是 F。对照 2.2 节的代码和模型连线逐一检查。也可以在 MATLAB Function 里临时加一行 fprintf(F%.3f\n, F); 看命令行有没有输出F 始终为 0 就说明上游控制器有问题。5.4 摆杆剧烈抖动theta 在零附近高频振荡像抽搐现象theta 最终没有发散但一直以明显的高频小幅振荡曲线毛刺很多控制力 F 也在快速正负切换。原因最常见的是 Ku 过大或 Kec 过大导致控制器在小误差区域输出增益太高系统在一个极小范围里反复超调其次是求解器步长问题MATLAB Function 里的非线性表达式在角度接近 0 时动态极快固定步长取得太大会引入数值误差。解决先把 Ku 减半再把 Kec 减半看振荡幅度是否下降。如果有效说明是增益过高逐步回调找一个临界值。如果减了增益没用把求解器从变步长 ode45 改成固定步长 ode4步长 1e-3排除数值刚性问题。另外注意模型里不要形成代数环MATLAB Function 的输入 F 如果直接来自它自己的输出Simulink 会画出一条红色虚线回路双击仿真信息窗口可以看到具体提示。5.5 小车一直朝一个方向跑theta 稳了但 x 越来越大现象摆杆角度控制得很好始终在零附近但小车位置 x 一直单向增大很快超出画面。原因这不是故障是结构缺陷。当前的模糊控制器只有角度和角速度两个输入它并不知道小车在哪里、在往哪跑。为了维持摆杆竖直控制器会不断朝一个方向推小车小车自然越走越远。这是单级倒立摆姿态控制的固有现象不是你模型搭错了。解决如果只是做课程设计演示接受这个现象把仿真时间控制在 10 s 内说明“完成了姿态稳定”即可。如果希望小车位置也稳住需要扩展控制器设计增加第三个输入 x 或小车速度 x_d把位置反馈引入规则表或者采用串级结构外环 PD 控制位置、输出作为内环角度给定值。这个升级方向适合把仿真做完之后进一步深挖属于这个项目标题之外的进阶内容。6. 从仿真到实物验证你的模糊控制到底可不可信6.1 先骗过仿真给模型加噪声、加延迟再看稳不稳很多人在干净模型上跑通之后就直接宣称“控制成功”但真实物理系统里传感器带噪声、执行器有延迟仿真里却什么都没有。验证模糊控制器是否真正可用第一步是主动往模型里“掺沙子”在 theta 反馈通道上加一个 Random Number 模块噪声功率设 0.001在 Ku 后面加一个 Transport Delay延迟 20 ms再把限幅换成带死区的 Saturation。如果这样改造之后系统还能收敛这块控制器才有上实物的资格。6.2 把 FIS 搬到硬件之前要做的三件事一个是把 .fis 文件转成可执行的代码。新版 MATLAB 的 Fuzzy Logic Toolbox 支持用命令直接导出 C 语言结构的初始化函数Simulink 模型也支持 C 代码生成生成的代码可以移植到嵌入式控制器里。另一个是参数标定量化因子 Ke、Kec、Ku 在实物上不能照搬仿真值需要根据实际传感器量程重新换算。第三个是加输入滤波实测角度信号里往往混有高频噪声一阶低通滤波或滑动平均都能明显改善抖动。我做过最蠢的一次是把仿真里调好的参数原封不动搬到小型实验台架上结果摆杆一上电就开始振铃整个台子像得了帕金森。问题出在仿真里我用的角度信号是理想值实物上角度传感器有噪声模糊规则里 ZO 区域内增益再被 Ku 放大噪声直接变成了控制抖动。后来在角度反馈前加了截止频率 30 Hz 的一阶低通并在规则表里把 ZO 区域改成输出死区才压住。这个坑几乎是每个做倒立摆的人都要踩一遍的记住一个原则仿真参数是起点不是终点。做这个方向建议不管你现在手里拿到的是哪个版本的资源包都抽出半天时间把模型完全拆开重新搭一遍重点放在规则表设计和信号方向检查上。你可能会发现搭模型比调规则快查方向比改参数要命。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑