四旋翼飞行器MATLAB仿真:Simulink模型、PID控制与调参实战

发布时间:2026/8/31 18:14:45
四旋翼飞行器MATLAB仿真:Simulink模型、PID控制与调参实战
简介本资源是一套面向高校自动化、航空航天及控制工程专业师生的四旋翼飞行器MATLAB/Simulink控制系统仿真学习包聚焦于无人机动力学建模、姿态控制算法实现与闭环仿真验证。压缩包共17个文件42KB含15个.m脚本文件如控制器设计alt_control.m、动力学求解dinamica.m、传感器滤波sam5_filter.m、三维可视化draw_results_3D.m等和2个.mdl Simulink模型文件systema2.mdl与untitled.mdl完整覆盖物理建模、PID/反向旋转控制策略、姿态解算、数据可视化及仿真结果分析全流程。已有1790人学习下载用户可直接运行仿真系统观察滚转、俯仰、偏航响应曲线调试控制器参数理解多输入多输出非线性系统的建模难点与实时控制逻辑是开展课程设计、毕业设计或科研入门的理想实践素材。 一个.rar压缩包里面装着一整套四旋翼飞行器的 MATLAB 仿真程序包含 Simulink 仿真系统和配套脚本——这就是我这次要聊的主角。做无人机控制、写飞控算法、做毕业设计或者单纯想看看别人怎么把四旋翼动力学放进 Simulink 里跑起来的人都应该会需要这份内容。我先坦白一下我自己拿到的这份程序并不是什么“论文级别的豪华货”但它胜在完整——模型、控制器、初始化脚本、结果绘图都在同一个文件包里。打开就能跑跑完能出曲线曲线能帮你理解四旋翼是怎么飞起来的。这比你自己从零开始在 Simulink 里搭一个模型省下太多时间但也正因为它是别人整理好的拿到手之后第一件事不是兴奋地点运行而是先把文件结构和依赖关系摸清楚。1. 拿到压缩包以后先花十分钟摸清家底1.1 压缩包里“大概率”会出现哪些文件很多刚接触 MATLAB 仿真的人都有一个共同习惯双击.slx文件看到模块图之后直接点那个绿色的小三角。结果十有八九是先报错报错之后又一脸懵。所以我建议你拿到这个压缩包之后先别急着解压到桌面然后双击先看一下文件清单。按我见过的大多数“四旋翼飞行器 MATLAB 仿真程序”类资源解压之后通常会是这样一套结构quadrotor_sim/ ├── readme.txt ├── init_quadrotor.m ├── quadrotor_param.m ├── quadrotor_main.slx ├── attitude_control.slx ├── position_control.slx ├── plot_results.m └── data/ └── results.mat这个结构不是绝对标准但八九不离十。readme 文件里通常写的是“怎么跑、需要什么工具箱、注意事项”.m文件负责把模型里所有变量加载到工作区.slx文件是真正能看到的仿真模型plot_results.m则是把仿真结果画成图的脚本。你可以先用文本编辑器打开 readme 看看再看一下各个.m文件头部注释。整个过程花不了太久但能给你省下后面大量排查时间。1.2 解压和路径处理中文路径是最大的坑解压这一步听起来没什么技术含量但坑恰恰在这里。如果你把压缩包解压到一个带中文的路径下比如C:\Users\张三\桌面\四旋翼仿真\后面 Simulink 模型里那些init_quadrotor.m的调用、数据文件读写、甚至 MATLAB Function 模块里的临时文件名都有可能踩到编码兼容问题。尤其要注意的是Simulink 的模型文件在加载时会自动去找工作区变量。如果路径中有中文一个很常见的现象是脚本能运行但模型里的 Gain、Constant 等模块显示不出数值或者运行几秒后报出文件读写类错误。所以我的建议是统一放到英文字符路径下比如D:\quadrotor_sim\。另外有些 rar 压缩包在 Windows 下用右键自带解压是没问题的但如果压缩包文件名带特殊符号或者解压软件版本太老可能导致文件损坏。解压完成后最好对照一下压缩包里的文件大小至少确认那几个关键文件不是 0 字节。2. 仿真程序的核心四旋翼模型是怎么进 Simulink 的2.1 先把动力学方程捋一遍这个仿真包做得再怎么花哨核心一定是四旋翼动力学模型。如果你只是想拿来跑个曲线不关心模型也能出图但如果后面要改控制器、调参数、甚至自己重新搭一遍那动力学方程这部分就必须看懂。四旋翼是一个典型的六自由度刚体系统但只有四个输入所以它是个欠驱动系统。简化建模时通常把四个电机产生的升力叠加成总升力u1把电机差速产生的滚转、俯仰、偏航力矩分别记作u2、u3、u4。忽略空气阻力、忽略电机动态延迟的简化模型可以写成下面这个样子x_ddot (cosφ sinθ cosψ sinφ sinψ) * u1 / m y_ddot (cosφ sinθ sinψ - sinφ cosψ) * u1 / m z_ddot cosφ cosθ * u1 / m - g φ_ddot (u2 (Iy - Iz) * q * r) / Ix θ_ddot (u3 (Iz - Ix) * p * r) / Iy ψ_ddot (u4 (Ix - Iy) * p * q) / Iz这里的x, y, z是机体在地面坐标系下的位置φ, θ, ψ是滚转、俯仰、偏航角p, q, r是机体角速度。看到这个方程你会发现四旋翼平移运动主要靠倾斜姿态来改变水平方向的推力分量所以“位置控制”本质上是通过“控制姿态”实现的这也是后面控制器要分成内环和外环的根本原因。2.2 从方程到 Simulink 模块的映射很多朋友看到上面一串公式就有点头大但落到 Simulink 里其实并不复杂。一般仿真包里的模型结构会是这样reference trajectory → position controller → attitude setpoint → attitude controller → motor mixing → quadrotor dynamics → 12 state outputs模型里每一条通道基本都能在模块图上找到对应关系。积分器用来累积加速度得到速度、累积速度得到位置Fcn 模块或者 MATLAB Function 模块用来算那个比较长的三角函数表达式Bus Creator 作用是把所有状态收拢成一根总线方便后续控制器引用。如果你打开quadrotor_main.slx发现里面看不到这种干净的分层结构而是密密麻麻一堆模块叠在一起那大概率是原作者把所有子系统都展开到了顶层。这种情况不用慌你只需要找到几个关键点输入端在哪里、输出端在哪里、中间那个和飞行器动力学相关的子系统在哪。定位到动力学子系统后我的经验是“只看端口不看内部”先看它输入几个量、输出几个量。输入通常是四个控制量[u1, u2, u3, u4]输出是 12 个状态量。如果你要验证模型对不对可以给一个固定不变的[mg, 0, 0, 0]输入看 z 轴会不会保持着高度不变。如果能稳住说明模型的基本力和重力关系是对的。2.3 为什么控制器一定要分内外环四旋翼只有四个电机飞起来靠的是倾转机体方向产生水平加速度。想从 A 点飞到 B 点你不能直接说“往东飞一点”只能告诉姿态系统“把机头朝某个方向倾斜一个角度”。这个逻辑决定了控制器天然要分成位置环和姿态环两层。内环是姿态环它负责让当前姿态快速逼近期望姿态响应速度要快通常 20Hz 甚至 50Hz 以上才有比较好的效果。外环是位置环它负责根据当前位置和期望位置计算出“需要多大的水平加速度”再换算成期望俯仰角和滚转角。这类程序一般在position_control.slx或attitude_control.slx里做了集成。一个典型的做法是外环用 PD 控制器把位置误差映射成期望姿态角内环用 PID 控制器把姿态角误差映射成力矩指令。如果你拿到手的是已经封装好的模型别急着删掉外面的黑色子系统边框先把里面的串级结构找出来理解了“位置环在前、姿态环在后”之后你后面调参才不会像无头苍蝇一样乱试。3. 控制回路怎么搭从 PID 到完整闭环3.1 内环姿态控制器姿态环是整个控制系统的核心它直接决定飞机的稳定能力。Simulink 里姿态环通常长这样输入是期望姿态角[phi_d, theta_d, psi_d]和当前姿态角[phi, theta, psi]误差进 PID输出是三个力矩指令。姿态环的难点在于大多数 PID 算法对“角速度阻尼”有依赖。很多资料喜欢直接在角度误差后面接一个 PID但实际调试时会发现光有角度环不够容易造成机体来回振荡。更常见的做法是角度环加角速度环的双环结构类似于一个串级 PID外环角度误差生成期望角速度内环角速度误差生成力矩。在这个仿真包里可能会用 Transfer Fcn 或 Discrete PID Controller 模块。模块参数一般放在 init 脚本里比如Kp_phi、Ki_phi、Kd_phi这类变量名。用变量而不是常量有一个好处你不需要每次改完参数都去模型里双击模块再点确认直接在 MATLAB 工作区改一次重新运行初始化脚本即可。这里我强烈建议你先看清楚模块里填的是变量名还是具体数字。如果看到模块里填的是Kp_phi而不是20说明变量来自初始化脚本运行模型前必须先跑一遍那个.m文件否则模型会报“未定义变量”的错。3.2 外环位置控制器位置环相对姿态环要慢一个档次它关注的不是“飞机现在平不平”而是“飞机在空间里的位置对不对”。典型位置环的做法是把期望轨迹和当前位置的差值送入 PD 控制器得到期望加速度。水平方向再将期望加速度除以重力加速度再取一个三角函数关系换算成期望的滚转角和俯仰角。垂直方向则直接输出总升力指令用于抵消重力和修正高度误差。在这个程序包中如果你看到“position controller”子系统里有一个写着atan2或asin的 MATLAB Function说明作者已经做了角度换算而不是直接把 x 方向控制量当作 φ 角指令。这是一个好习惯因为大角度情况下线性关系“加速度 重力 × 角度”会失真用三角函数换算会更贴近真实模型。3.3 一个可以直接用的 PID 初始化脚本不管程序包里原作者的脚本是什么样的我给一个常见的初始化脚本示例你拿到别人模型的时候也能套用% init_quadrotor.m m 1.2; % 飞行器质量 kg g 9.81; % 重力加速度 m/s^2 Ix 0.015; % 滚转转动惯量 kg*m^2 Iy 0.015; % 俯仰转动惯量 kg*m^2 Iz 0.025; % 偏航转动惯量 kg*m^2 % 内环姿态 PID Kp_phi 18; Ki_phi 0.1; Kd_phi 2.5; Kp_theta 18; Ki_theta 0.1; Kd_theta 2.5; Kp_psi 12; Ki_psi 0.05; Kd_psi 1.5; % 外环位置 PD Kp_x 2.0; Kd_x 1.2; Kp_y 2.0; Kd_y 1.2; Kp_z 8.0; Kd_z 3.0;这里只是初始参考值具体数值要结合你模型里的质量和转动惯量重新调。把脚本保存成.m文件后直接在 MATLAB 命令窗口运行一次让这些变量进入工作区再回到 Simulink 界面点开始仿真基本就能正常跑起来。4. 参数整定与仿真结果分析4.1 仿真求解器设置固定步长还是变步长很多人拿到仿真包后仿真跑起来慢得像幻灯片于是怀疑是电脑不行。其实很多时候是 Solver 设置的问题。Simulink 默认通常用变步长求解器比如ode45遇到快速变化的动力学响应会自动缩小步长导致仿真时间很长。如果你的模型是纯连续模型、没有需要严格等步长采样的算法用变步长ode45是可以的。但如果你想做后续代码生成、或者想和真实飞控一样按固定时间片执行那就需要改成固定步长求解器比如选择od4四阶龙格-库塔或odt梯形规则。改法很简单菜单栏选择 Simulation 模型配置参数找到 Solver 选项把 Solver options 里的 Type 改成Fixed-stepFixed-step size 填0.001或0.005。步长选0.001仿真更精确但耗时更长选0.005速度更快但误差会明显一些。对于四旋翼这种有高频姿态动态的系统我个人建议固定步长不要大于0.005。你拿到的程序如果已经在初始化脚本里写好了t_sim和dt那你就先按照脚本设置来跑一遍再根据自己的需求调整。4.2 用脚本批量扫参别在 Simulink 里手动点调 PID 最忌讳的就是一遍遍在 Simulink 里点运行、看曲线、停掉、改参数、再点运行。这种方法一次只能试一组参数而且你对“上一组为什么发散”的记忆很快会模糊。正确姿势是用一个 MATLAB 脚本批量跑参数把每次仿真结果保存下来再统一画图。基本框架如下% batch_test.m kp_list [10, 15, 20, 25]; results cell(length(kp_list), 2); for i 1:length(kp_list) Kp_phi kp_list(i); sim(quadrotor_main.slx); results{i, 1} Kp_phi; results{i, 2} phi_theta_psi.signals.values(:, 1); % 滚转角曲线 end figure; for i 1:length(kp_list) plot(tout, results{i, 2}, LineWidth, 1.5); hold on; end legend(cellstr(num2str(kp_list)));注意sim()这个命令会直接启动模型仿真运行前需要保证模型未处于调试状态、初始化脚本已执行过。跑完后再用plot把不同 Kp 对应的滚转角响应画在一起你就能直观看到增益太小导致响应慢、增益太大导致振荡的变化过程。4.3 三种典型仿真场景下的输出判读拿这类四旋翼仿真程序最常跑的三种场景就是悬停、阶跃响应、轨迹跟踪。它们本质上是在验证三个层面的东西。悬停仿真一般把期望位置设成[0, 0, 1]期望偏航角设成 0。跑完重点看 z 轴高度曲线能不能稳定在 1 米附近俯仰和滚转角是否在 0 附近小幅波动。如果高度曲线是平的但姿态角抖动很剧烈说明姿态阻尼不足或仿真步长过大。阶跃响应常用在俯仰角或高度通道上。给一个阶跃指令后看响应曲线有没有超调、有多少次振荡、稳态误差有多大。正常的一组 PID 参数应该是响应快、超调小、不振荡但这三个指标本质上是矛盾的所以实际调参时要根据设计任务取舍。轨迹跟踪则更接近应用常见的有圆形轨迹、8 字轨迹或螺旋轨迹。跑完后除了看姿态曲线还要看三维位置曲线。程序包里的plot_results.m如果自带轨迹绘图功能你会看到一条期望轨迹和一条实际轨迹两者贴合程度就是控制器性能最直观的体现。5. 常见问题与排查技巧实录5.1 打开模型就报“变量未定义”怎么办我远程帮别人看 Simulink 模型时遇到过最多的报错就是Undefined function or variable Kp_phi.这个报错文本本身已经说得很清楚了模型里某个模块用了Kp_phi这个变量但 MATLAB 工作区里没有这个变量。解决方案不是去模型里把Kp_phi改成数字而是把定义这些变量的初始化脚本先跑一遍。如果你拿到的程序包里有init_quadrotor.m或quadrotor_param.m在命令窗口执行run(init_quadrotor.m);然后去工作区检查一下变量是否存在who如果变量列表里出现了Kp_phi、Ix这些名字再回 Simulink 点运行。另外某些模型会在Model Properties Callbacks InitFcn里自动调用初始化脚本打开这个页面看一眼能帮你判断是不是每次运行模型前都会自动加载变量。5.2 仿真一发散先查这三个地方仿真曲线直接冲向Inf或者剧烈振荡这是四旋翼仿真里最劝退人的问题。排查时不要一股脑怀疑 PID 参数先从三个地方入手。第一是看推力方向有没有接反。很多初始化脚本里总升力u1直接以牛顿值作为输入但动力学模块里接收的是“四个电机推力之和”。如果你输入的是总升力却乘了个电机数量高度就会失控。第二是看 PID 符号有没有接反。最典型的例子是角度误差e phi_d - phi被写成了e phi - phi_d相当于一个负反馈变成了正反馈。第三是看积分项是否饱和尤其是姿态环 Ki 设置太大时积分项会在几秒内迅速累积导致大幅超调。我调试的时候习惯先关闭积分项只用 PD 把系统稳住再加入 Ki 消除稳态误差。如果只加 PD 就发散那通常不是积分问题而是符号或者模型结构问题。5.3 输出结果和论文对不上的排查思路还有一个非常常见的情况你明明照着某个教程或论文里的参数填进去了结果跑出来的曲线跟论文里的完全不一样。这不一定是教程写错了更可能是“初始化条件不一致”或者“坐标系定义不一致”。坐标系的坑尤其隐蔽。有的程序里 z 轴沿重力方向向下有的程序里 z 轴向上有的偏航角在转换矩阵里用的旋转顺序是 ZYX有的是 XYZ。你用同一个 PID 参数在不同坐标系定义下跑出来的姿态趋势可能完全相同但符号有正负差异。排查思路是给一个特殊输入验证符号。比如给u1 mg, u2 0, u3 0模型应该保持悬停。如果此时位置输出依然上下乱跳那大概率是整流罩坐标系和重力方向处理反了。再比如给一个正的俯仰力矩看机体绕 y 轴转动的方向是否符合右手定则不符合就把力矩或者角度符号取反。我建议你在分析结果之前先把初始化脚本里的坐标系定义、状态向量顺序、单位这三样东西全部确认一遍。这个确认过程虽然朴实但能直接避免因为“单位是克还是千克”这种低级错误导致整套仿真白跑。5.4 一个常见问题速查表现象可能原因处理方式模型打不开提示缺工具箱没有安装 Aerospace 或 Simulink Control Design在附加功能中安装对应工具箱点运行后报变量未定义初始化脚本未执行运行init_quadrotor.m或检查 InitFcn高度曲线下降后冲出 NaN重力单位、质量单位不一致检查m、g的数值量纲姿态角快速振荡PID 增益过大或符号反了先改小 Kp再检查误差定义运行非常慢变步长求解器步长过小改固定步长步长设为 0.001~0.0053D 轨迹图没有显示输出变量名与绘图脚本不一致查看plot_results.m里引用的信号名打开模型后显示版本较新MATLAB 版本低于模型保存版本使用模型导出为旧版本或升级 MATLAB6. 这个仿真程序还能怎么接着玩6.1 把 PID 换成滑模控制或 ADRC如果你已经跑通了原程序里的 PID 控制下一步很自然的想法就是换控制器。四旋翼是强耦合、欠驱动的非线性系统PID 在悬停和小角度机动下效果不错但遇到大角度机动或外界扰动时鲁棒性就不太够了。滑模控制是很多论文里的常见替换方案。它的核心思想是设计一个滑模面比如s e_dot lambda * e然后通过切换控制项把状态“压住”在滑模面上。在 Simulink 里实现时你只需要把姿态控制器子系统里的 PID 模块替换成一个 MATLAB Function输入仍然是角度误差和角速度误差输出换成力矩指令。我试过在一套现成的四旋翼模型里做这个替换做法其实不复杂function tau att_smc(e, e_dot, lambda, eta) s e_dot lambda * e; tau -lambda * e_dot - eta * sign(s); end当然这只是示意真正的滑模控制还要考虑模型项补偿。你可以先保持原模型的动力学模块不动只换控制器然后对比同样的圆形轨迹跟踪效果。这样你就能直观看到滑动模态控制在大角度情况下到底比 PID 强在哪里。换成 ADRC自抗扰控制也是类似逻辑。把模型内部参数不确定性和外部扰动统一当成“总扰动”用扩张状态观测器观测并补偿。四旋翼模型里每个通道的扰动项都可以用一个 ESO 模块去估计然后把估计值前馈到控制量里。6.2 从 Simulink 直接生成 C 代码很多做飞控的人拿这个仿真程序不只是为了看曲线而是想把控制算法部署到真实飞控硬件上。Simulink 的 C 代码生成功能这时候就能派上用场。要生成代码你的模型必须满足几个条件求解器要改成固定步长模型里的连续积分器要改成离散模块输入输出要明确标成 Inport 和 Outport最好把控制器单独拉出来做成一个独立子系统。生成代码时选择菜单栏里的 C 代码生成勾选嵌入式实时目标Simulink 会自动帮你生成.c、.h文件。我实际操作中的经验是不要指望生成的代码能直接刷进飞控板。更合理的做法是把姿态控制子系统单独抽出来接口定义成“期望姿态角、当前姿态角、当前角速度”作为输入“四个电机 PWM 占空比”作为输出然后再在飞控主循环里读取传感器数据、调用这个控制函数。代码生成不是点击就完事它涉及很多工程细节比如数据类型的定标、代码生成模板的选择、中断服务函数的集成方式。一开始用这个仿真包练习时先保证代码能成功编译、没有未定义变量就是很大的一步了。6.3 向硬件在环和真机移植延伸继续往前走一步你可以把这套 Simulink 仿真接到硬件在环测试里面。基本思路是真实的飞控板运行控制器代码Simulink 里的四旋翼动力学模型代替真实飞机通过串口或者以太网把传感器数据发送给飞控再把飞控输出的 PWM 信号读回 Simulink。这样做的最大价值在于你可以不用冒摔机的风险就把真实飞控板上的参数、故障保护逻辑、电机响应延迟都验证一遍。很多基于 Simulink 的四旋翼程序包已经预留了这种接口比如在模型里有一个 Serial Receive 模块或 UDP Receive 模块你只需要把控制器输出和模型输出接到这些模块上。如果你暂时用不到硬件也可以做“模型一致性验证”把同一个 PID 控制算法分别用连续模块和离散模块实现对比它们在相同轨迹下的输出差看看离散化步长对控制性能的影响。我做这种对比的时候固定控制周期从 0.001 秒放宽到 0.01 秒能明显看到姿态跟踪误差变大这对理解“飞控为什么不能写得太太太慢”很有帮助。我个人在实际操作中的体会是这类“四旋翼飞行器 MATLAB 仿真程序包括 simulink 仿真系统和程序”的压缩包真正的价值不在于你能立刻跑出几条漂亮的曲线而在于它给了你一个完整的“模型—控制器—可视化”闭环。你可以从这个闭环出发替换模型、换控制器、调整坐标系、接硬件接口每一步都能学到东西。拿到程序后先老老实实跑通原版再开始拆这个节奏是最稳的。本文还有配套的精品资源点击获取