ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

四旋翼动力学建模与PID控制仿真复现:从公式到Simulink全流程解析

四旋翼动力学建模与PID控制仿真复现:从公式到Simulink全流程解析

复现一篇多旋翼飞行器的PID控制论文,听起来是个标准的毕业设计任务,但真正动手做过的人都知道,从论文公式到可运行的Simulink模型,中间隔着的不是代码量,而是几十个小时的调参、排错和对物理概念的理解。这篇我想把我自己完整复现一套四旋翼动力学建模与PID控制系统设计的过程整理出来,包括建模推导、Simulink模块搭建、控制器参数整定思路,以及我在这个过程中踩过的坑和校准方法。内容主要面向正在做类似课题、或者想深入了解四旋翼从公式到仿真全流程的读者,希望能帮你们少走一点弯路。

先交代一下背景。我复现的是某篇经典期刊论文中的四旋翼动力学模型与控制算法,论文核心是用牛顿-欧拉法建立六自由度刚体模型,再设计串级PID对姿态和位置进行控制。最初拿到论文时,我以为难点在PID,真正做起来才发现,建模环节的细节决定了一切——坐标系的定义、电机响应模型、参数量纲,任何一处含混,仿真结果都会和论文对不上,然后你就开始怀疑人生。

1. 复现前的准备工作:论文逻辑拆解与建模坐标系选择

1.1 从论文摘要到需求清单:先搞清楚复现什么

拿到一篇论文,别急着开Simulink。我第一步是把论文的模型部分和控制部分拆成两个独立的模块来理解:模型部分是"飞机怎么动",控制部分是"怎么让它按我想要的方式动"。把它们混在一起看,很容易被公式淹没。

我复现的这篇文章,建模用的是牛顿-欧拉方程,控制用的是内外环PID,外环控制位置,内环控制姿态。这个结构非常典型,但论文里有个容易被忽略的假设——它默认了电机响应可以用一阶惯性环节近似,而且忽略了旋翼之间的气动干扰。这两个简化在实际建模中意味着:电机推力不会突变,而是滞后于指令;小尺寸四旋翼在悬停状态下气动干扰对控制结果影响有限。这个理解直接决定了后面我建模时哪些项保留、哪些项可以合理忽略。

还有一个关键信息要从论文中提取:仿真用的物理参数。四旋翼的质量、臂长、转动惯量、推力系数、阻力系数,这些参数论文通常是以表格形式给出,但经常存在量纲不统一的情况。比如推力系数有的用 N/(rad/s)^2,有的用 N/(rad/s)^2,差别是电机转速的平方关系。我建议第一步先把论文中的参数表格逐项抄到一个独立的Excel或脚本文件里,统一单位,标注来源,这一步能让后续工作省很多事。

1.2 坐标系定约:大地系、机体系、欧拉角序列

坐标系是建模的第一步,也是整篇论文公式推导的基石。多旋翼建模一般涉及两个坐标系:大地坐标系(惯性系)和机体坐标系。

大地坐标系的原点通常选在地面某一点,X轴指向正北或某固定方向,Z轴垂直向下,符合右手定则。机体坐标系固定在飞机本体上,原点在质心,X轴指向机头方向,Z轴垂直机体平面向下,也和电机推力方向相关。这里最难的部分是欧拉角旋转序列。大多数论文采用Z-Y-X序列,也就是先偏航角,再俯仰角,最后横滚角。旋转矩阵的表达式会因为这个顺序而不同,你在复现时一定要先确认论文用的是哪个序列,否则后面姿态运动学方程会变形。

我踩过这个坑:一开始按Z-X-Y序列推导,导致仿真中飞机在纯俯仰输入时出现了不期望的横滚分量,波形明显异常。排查了很久才发现是欧拉角顺序的问题。所以强烈建议,第一步先把论文的旋转矩阵和运动学方程整理出来,和你的推导比对,确认无误再往下走。另一个值得注意的点是,欧拉角在俯仰角接近90度时会遇到奇异(万向锁),对仿真来说,如果不是做特技飞行动作,一般不会触发这个问题,但心里要有个数。

2. 四旋翼刚体动力学建模:Simulink里的推演过程

2.1 牛顿-欧拉方程在机体系下的展开

建模的核心是六自由度刚体运动方程。分成两部分:线运动方程描述飞机位置变化,角运动方程描述姿态变化。

线运动方程基于牛顿第二定律,表达为:

m * dV/dt = F_gravity + F_thrust + F_drag

其中F_gravity是重力在机体系下的投影,F_thrust是四个旋翼产生的总推力(沿机体Z轴,由于四旋翼布局推力方向一致),F_drag是空气阻力,通常简化为与速度线性相关的阻尼项。

角运动方程基于欧拉方程,表达为:

J * dOmega/dt + Omega × (J * Omega) = M

这里的J是转动惯量矩阵,Omega是机体角速度,M是外力矩。对于四旋翼,力矩来源主要是旋翼差速产生的滚转力矩、俯仰力矩和偏航力矩,还有旋翼转动带来的陀螺效应。陀螺效应在快速大角速度运动中明显,如果论文没提,仿真中可以视情况忽略,但最好在模型里保留这个输入接口,方便拓展。

在用Simulink实现这个部分时,我习惯把公式拆成三个模块:一个是线运动模块,一个是角运动模块,再加一个姿态更新模块(把角速度积成欧拉角)。线运动模块里需要注意,重力分解到机体系时用旋转矩阵,但位置积分是在大地坐标系做的,所以最后一步要把机体系下的加速度通过旋转矩阵再变换回大地系。这个来回变换特别容易搞错方向,我建议画一个信号流向图再动手布线。

2.2 电机与旋翼的力/力矩产生模型

电机模型是整个建模里看似简单、实则影响很大的环节。论文一般给出的是静态映射:转速平方乘以推力系数得到推力。但实际电机有响应延迟,所以需要在静态映射之前加一个一阶环节,模拟油门指令到转速输出的动态过程。一阶环节的时间常数论文里一般会给,如果没给,常见的值是0.02秒左右,对应100Hz左右的电机带宽。

我用的是这样的式子:

T_i = C_T * omega_i^2 M_i = C_M * omega_i^2

其中omega_i是第i个电机的转速。如果搭建了电机动态环节,那么omega_i不再是瞬时的指令值,而是经过低通滤波后的值,这让模型更接近真实情况。

力与力矩的组合逻辑也很关键。四旋翼的十字布局下,四个电机编号不同,产生的效果不同。假设1号、3号电机逆时针旋转,2号、4号顺时针旋转,那么:

  • 总推力 = T1 + T2 + T3 + T4
  • 滚转力矩 = L * (T2 - T4),其中L是力臂长度
  • 俯仰力矩 = L * (T1 - T3)
  • 偏航力矩 = C_M * (omega1^2 - omega2^2 + omega3^2 - omega4^2),考虑的是逆时针/顺时针电机转速差引发的反扭矩差。

在这个模块里,我强烈建议用Simulink的向量化信号而不是单一标量信号,把四个电机转速打包成一个四维向量,后续运算直接向量操作。这样不仅模型看起来整洁,后期调试某个电机时也能一眼看到问题。

还有一个容易忽略的细节是转动惯量。论文给的是Ixx、Iyy、Izz三个主对角线值,但实际四旋翼的重心不一定在几何中心。比如加了负载或者电池位置偏置,会导致惯性积项非零。论文模型通常假设惯量矩阵是对角的,这在中型四旋翼上误差不大,但在越障或重载场景下,非对角项的影响会显现出来。如果你做的是期刊复现,尽量沿用论文假设,但需要在报告里说明这个简化的合理性。

3. PID控制器结构与参数整定的工程实现

3.1 内外环级联结构:位置环与姿态环

带PID控制器的四旋翼系统,最典型的设计是内外环级联结构。外环是位置控制,内环是姿态控制。外环根据期望位置和当前位置解算出期望姿态角(主要是俯仰和横滚),然后将这个期望角度送入内环,由内环PID去控制姿态。偏航角通常在两个环里都直接控制。

为什么用级联结构而不是直接一个四维PID?因为内环姿态的响应带宽比外环位置高出很多。内环可能50Hz带宽,外环可能10Hz以内。如果内外环合并,很难协调这种带宽差异。级联结构的好处是内环可以先行整定,内环稳定后再整定外环,调参问题被分解成两个相对独立的步骤,物理直觉也更清晰。

位置环的PID我一般设计成PD形式就够用,因为位置控制里没有太强的稳态误差问题。期望位置是定值或斜坡信号时,PD控制器配合重力补偿就能做到无静差。这里有个细节点,外环输出的期望姿态角需要经过限幅,一般来说俯仰角和横滚角的期望值不要超过45度,否则在欧拉角描述下会出现奇异风险且电机推力饱和严重。

内环姿态PID才是整个控制系统设计的重头戏。每个姿态通道(横滚、俯仰、偏航)一套PID控制器,输入是期望角度与实际角度的误差,输出是期望角速度修正量,再经过混控矩阵分配到四个电机。很多论文里姿态内环会写成角速度环加角度环的双环结构,也就是把内环再细分一层,工程上这是更稳妥的做法,但参数整定复杂度更高。我复现的这篇论文只用了一层角度PID加前馈角速度项,对于飞行器悬停和小角度机动来说,精度足够。

3.2 增量式PID、抗积分饱和与输出限幅

PID参数的整定是我在复现中花时间最多的部分,也是决定仿真效果好不好看的关键环节。

先讲增量式PID和位置式PID的区别。位置式PID输出的是控制量的绝对值,比如期望油门量;增量式PID输出的是控制量的变化量,需要累加得到实际控制量。增量式的好处是执行器不动时输出不会漂移,而且当控制器输出越限后,累加值可以被强制限幅,不会出现积分项无限增长的问题。四旋翼的电调油门范围通常限制在0到1之间,如果用位置式PID且不处理积分,控制输出很容易在整定过程中越界,导致某个电机转速指令恒为0,飞机直接翻转。我复现时最终选了增量式PID,配合输出限幅,问题瞬间少了一半。

抗积分饱和也是必做的。PID控制器的积分项容易在启动阶段或大偏差阶段积累,等误差减小后,积分项释放缓慢,造成超调甚至振荡。工程上常用的方法有三种:

  • 积分分离:误差超过某一阈值时暂停积分;
  • 积分限幅:积分项单独限幅,不允许无限制增长;
  • 遇限消除:输出达到上下限时,如果积分方向与限幅方向相反,则暂停积分。

我在姿态内环用的是积分限幅加遇限消除的组合。积分限幅值一般取控制器满量程的10%左右,这样既能消除稳态误差,又不至于在快速变化时积分发力过猛。时间常数的选择给个参考:横滚和俯仰通道的积分时间一般取0.2到0.5秒,偏航通道因为响应慢,积分时间可以放宽到0.5到1秒。

参数整定时我的顺序是:先调P,再调D,最后调I。P给大了,响应快但会出现高频抖动;D能压制超调,但过大会放大测量噪声;I处理静态误差。在Simulink里第一步先只开P,让阶跃响应震荡但趋于稳定,然后加D消除超调,最后加I消除稳态误差。这个过程和真实飞行器调参的逻辑一脉相承,跑道通顺后,后续做实物试飞也会更从容。

4. Simulink模型架构与仿真参数设置细节

4.1 模块布局与信号线组织

Simulink模型的组织方式在很大程度上决定了调试效率。我的经验是,把模型分成四个功能区,用Subsystem封装并涂上不同颜色:

  • 参考轨迹模块:生成期望位置和期望偏航角,可以是阶跃、斜坡或正弦信号;
  • 控制器模块:接收期望值和反馈值,输出四路归一化油门指令;
  • 混控与电机模块:把油门指令映射为四个电机的转速,并加入一阶延迟;
  • 六自由度动力学模块:计算位置、速度、欧拉角、角速度,并作为反馈返回控制器。

信号线一定要命名,否则连线一多根本分不清谁是谁。Simulink会自动给信号生成名字,比如"demand_position",但手动改成有业务含义的名字(如pos_des, att_des, rpm_cmd)会更直观。另外,我建议用Bus对象统一打包反馈信号,把所有状态量放到一个总线里,控制器模块内部再从总线中取用。这样即使以后增加状态量,也不需要改模块接口,只需要改总线定义。

还有一件事值得做:把模型参数抽出来,写入一个独立的初始化脚本,所有参数在脚本里以变量的形式存在。模型里的增益模块填的是变量名而不是数字。这样调参不需要打开模块窗口改数值,改完脚本运行一下,仿真就会自动用新参数。我还会在脚本里写一些assert语句,例如参数不为零、转动惯量大于零等,防止参数输入错误导致仿真崩溃却半天找不出原因。

4.2 仿真步长、初始条件与数据记录

仿真步长对结果的影响非常大。四旋翼动力学是一个刚性相对较低的系统,但电机一阶环节带宽较高,如果仿真步长太大,会出现数值不稳定,表现为波形震荡发散,但模型本身是正确的。

我用的是变步长求解器,选ode45,最大步长设为0.001秒,相对误差1e-4。经过多次实验,这个设置在悬停控制仿真中既保证了收敛性,也控制了计算时间。需要注意的是控制器的采样时间。真实飞行器是离散控制器,每隔固定周期计算一次控制量,仿真里为了还原这个特性,我会在控制器输入处加一个采样保持模块,采样时间设为0.01秒(对应100Hz控制频率),这样比连续控制器更符合实际,也更接近论文中数字控制器的描述。

初始条件方面,有一个经常被忽视的细节:四旋翼悬停起飞时,初始状态应该是"静止在地面高度"还是"空中稳定悬停"?如果从地面开始,初始高度为0,推力从0开始增加,起飞过程需要比较复杂的推力规划,初学者很难调好。我复现时选择了直接设定初始高度为1米、初始速度为0、姿态角全为0,给定期望位置为(0, 0, 1),这样可以只关注控制器能不能保持稳定,而不用管起飞过程。论文里的仿真一般也都这么做。

数据记录我也是从一开始就安排的。Simulink里用To Workspace模块把关键信号导出,在仿真结束后用MATLAB脚本统一绘图。我会把期望轨迹、实际位置三轴分量、欧拉角三轴、四个电机转速、控制输出这几类数据全部记录。这样当仿真结果异常时,我能同时看到指令、响应和电机输出,定位问题快很多。

5. 复现对比、波形判读与常见偏差修正

5.1 如何判断模型复现是否成功:波形质量的量化指标

很多同学复现论文,纠结点在于"仿真曲线看起来差不多"。但差不多到底差多少,应该有量化标准。

我的判断指标有四个:

  • 上升时间:响应从10%到90%所需的时间,论文里通常会给出目标值;
  • 超调量:响应最大峰值与期望值的偏差百分比;
  • 稳态误差:响应稳定后的平均值与期望值的差值;
  • 调节时间:响应进入±5%误差带后不再超出的时间。

这四项指标在Simulink里用MATLAB脚本分析仿真数据就能算出。如果你复现的论文控制效果是上升时间约2秒、超调量小于10%,而你调出来的参数给出20%的超调,那就说明PID参数离论文原设置还有差距。整个复现过程本质上是不断调整参数、对比波形、压缩指标差距的过程。

当然,参数无法和论文完全一致的情况也常见。论文里有些参数是理想化的,甚至明显为了仿真效果而没有考虑测量噪声和扫气延迟。这时候需要判断,是调整模型让它更贴近论文,还是保留更真实的模型、牺牲部分波形相似度作为代价。我认为复现的第一目标是结构和机理对齐,第二目标是控制效果可比,只要控制器结构和模型方程一致,参数有偏差是合理的。

5.2 踩坑记录:微分冲击、噪声放大与离散化误差

最后分享我在复现过程中遇到的三个典型问题,每个都折腾了我不少时间。

第一个是微分冲击。在仿真开始时给定阶跃期望,误差信号会瞬间跳变,PID控制器里的微分项对这个跳变非常敏感,会产生巨大的控制输出,导致电机指令瞬间打到上边界,明显不符合物理直觉。解决办法是给误差信号加一个低通滤波器,或者把微分项改为对被控量而非误差求导。常用的做法是用"微分先行"结构,也就是只对测量值求导数,不对期望值求导数。这样在阶跃期望下不会出现微分冲击。仿真结果改进非常明显。

第二个是测量噪声放大。Simulink动力学模型输出的状态是理想值,但真实系统中的传感器存在噪声。我为了让仿真更有参考价值,在状态反馈中加入了一小段白噪声,结果发现不加噪声PID参数整定得好好的,加了噪声后姿态角通道出现了明显的高频抖动。说明D项增益偏大。处理方法是把D项增益降低,并且在D项前加一个截止频率约30Hz的低通滤波器,滤掉高频转折。这个步骤在做实飞前非常重要,因为真实传感器噪声比仿真噪声更复杂。

第三个是离散化误差。我在第4节提到控制器采样时间为0.01秒,但在Simulink里如果直接使用连续PID模块,一不小心就会忘记加采样保持,导致控制器以仿真步长(比如1e-4秒)运行,等效于一个超高频控制器,而实际物理系统根本达不到这么高的控制频率。由此调出的PID参数在离散控制器下必然失稳。把控制器模块改成离散化形式(z变换或写成差分方程)后,参数整定的结果才真正可移植到实物飞控上。

复盘整个复现流程,我认为核心收获不是"我学会了搭一个仿真",而是理解了论文里每个公式背后的物理假设、每个控制参数的实际作用边界,以及仿真结果与真实系统之间那条模糊的线。如果你也在做四旋翼的建模与PID控制仿真,我的建议很简单:先彻底理解论文的每一条公式,再动笔搭模型;模型里保留必要的物理细节,但不要过度追求还原;控制器设计优先保证结构正确,再花时间去打磨参数。仿真软件只是工具,对物理过程的理解才是你能带走的东西。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进