ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PSO优化PID双闭环:四旋翼轨迹跟踪仿真全流程

PSO优化PID双闭环:四旋翼轨迹跟踪仿真全流程 先把结论放前面纯手动调四旋翼的PID真的会调到你怀疑人生。姿态环这边刚把超调压下去位置环一加进来整个系统又开始抖位置环把Kp提上去想追轨迹追得快一点结果内环姿态指令稍微抖一下电机就开始啸叫。于是我把粒子群算法PSO和PID双闭环控制放到一起做了一套完整的仿真优化链路从动力学建模到适应度函数设计再到Simulink联调整套流程跑下来轨迹跟踪的效果比手动整定肉眼可见地高一个档次。这篇文章面向两类人一是正在做四旋翼控制课程设计或毕业设计的同学需要一套能写进论文、能复现的完整仿真研究方案二是已经在飞实物、但被PID参数折磨过想用更系统的方式把参数“搜”出来的工程师。文章核心是PSO优化PID双闭环控制围绕四旋翼轨迹跟踪仿真展开不扯玄乎的数学全部按我实际跑通的操作链路来讲。1. 先从控制架构说起为什么四旋翼轨迹跟踪离不开双闭环PID1.1 六自由度四个输入天然就需要内外环分级四旋翼在空间里有6个自由度位置是X、Y、Z姿态是滚转角、俯仰角、偏航角但执行机构只有四个电机转速。也就是说这是个典型的欠驱动系统——你想同时控制6个量手里却只有4个输入意味着没法对每个自由度独立分配一路反馈。唯一的办法就是分层控制用内环先把姿态稳住用外环再通过姿态变化间接控制位置。这个逻辑在地面机器人的思路上不太一样。两轮差速小车要往左走直接把轮子转速差改了就行转向和执行在同一个物理层面。四旋翼不一样它要往左平移必须先让机身向左倾斜推力方向发生偏斜推力的水平分量才能拉着机体往左走。也就是说位置的改变是姿态改变的结果中间隔了一层物理变换。这从根本上决定了控制位置的外环和控制姿态的内环必须分开设计再串起来。1.2 位置环和姿态环的时间尺度分离双闭环能成立前提是内外环的时间尺度差开。姿态环负责的角运动响应速度快通常控制频率做到100Hz以上位置环负责的平动是靠推力在某个方向上持续累积才发生的响应慢得多控制频率10到50Hz就够。内环先把期望姿态角快速跟上对外环来说这个姿态内环可以被近似成一个响应很快的“随动环节”外环则慢悠悠地算轨迹偏差输出姿态指令让内环去追。如果内外环采样时间不做区分全部塞在同一个仿真步长里跑名义上是双闭环实际等效成单速率强耦合系统。位置环刚给一个期望姿态角姿态环还没来得及收敛外环指令又变了整个回路会变得很难调。所以后面搭建仿真的时候内外环的采样时间分配是一件必须显式去做的事而不是靠默认设置。1.3 手动整定为什么总在“稳”和“快”之间挣扎手动整定PID最常见的问题就是姿态环单看不错连上位置环之后整体表现却很差。原因很简单位置环的等效被控对象里包含了姿态内环的闭环特性而这个特性会随飞行姿态变化。爬升的时候和悬停的时候推力方向不一样位置环看到的“对象增益”也不一样。手动调参你只能在一个飞行状态下调得比较准换个轨迹、换个速度参数马上就变得别扭。更头疼的是三个性能目标在打架。想让轨迹误差小位置环Kp要大但Kp一大外环给内环的姿态指令就容易产生阶跃式的突变内环跟不上就会抖想让响应快微分项加狠一点但Kd太大在仿真里看起来很好实际一遇到传感器延迟就振荡。这些矛盾靠手一个个试不是不行是效率太低。PSO解决的就是这么一个问题在一个高维、非线性、没有解析梯度、目标互相冲突的参数空间里用一群粒子的并行搜索把一组能平衡多个目标的PID参数找出来。2. 粒子群优化PID的原理拆解它搜索的到底是什么空间2.1 鸟群觅食的隐喻与现实中的速度—位置更新粒子群算法的灵感被讲得最多的是鸟群觅食一群鸟在一片区域里找食物每只鸟不知道自己附近哪里食物最多但它能记住自己飞过的位置里哪里最好也能知道整个群体目前发现的最好位置在哪里。于是每只鸟的下一步飞行方向大致是三个方向的折中沿着自己原来的惯性飞、朝自己找到过的最好位置飞、朝整个群体找到的最好位置飞。把它对应到PID参数优化上一粒粒子就是一组PID候选参数。比如我优化6个参数那每个粒子就是6维空间里的一个点这个点的坐标分别代表外环Kp、外环Ki、外环Kd、内环Kp、内环Ki、内环Kd。粒子群迭代的过程就是不断移动这些点、评估每个点对应的控制效果、然后更新的过程。速度更新公式是所有实现的核心V_new w * V_old c1 * r1 * (P_best - X) c2 * r2 * (G_best - X) X_new X_old V_new其中w是惯性权重控制粒子保持原有飞行方向的趋势c1、c2是学习因子控制粒子被个体经验和群体经验吸引的强度r1、r2是两个随机数让搜索带有随机性。每次更新完位置就要把新的PID参数放进仿真里跑一次算出一个适应度值用来判断这个粒子当前位置好不好。所谓“搜索”本质就是在6维参数空间里按这个规则不断采样和择优。2.2 权重、学习因子、种群规模的超参数选择逻辑PSO本身还有一层超参数这些超参数直接决定收敛速度和最终解的质量。我实际工程里常用的配置是种群规模N取20到40迭代次数T取30到60惯性权重w从0.9线性递减到0.4c1、c2都取1.5左右。w初始大、后期小是有讲究的。迭代初期需要粒子有大范围探索能力不容易一上来就扎进某个局部最优所以惯性权重给大迭代后期需要粒子围绕已经发现的较优区域精细开发所以权重减小让飞行速度慢下来。线性递减是个很省事又很稳的策略实测效果比固定权重好很多。c1和c2的作用是平衡个体经验和群体经验。c2太大所有粒子会很快被拉到全局最优附近搜索多样性下降c1太大每个粒子都忙着往自己历史最好位置跑群体的信息共享变弱。都取1.5是一个比较中庸的选择多数情况下表现稳定。种群规模N和迭代次数T要放在一起看。N太小粒子多样性不足N太大每轮要跑的仿真次数多到不现实。毕竟每一个粒子的一次位置更新都要完整跑一遍四旋翼轨迹跟踪仿真仿真模型稍微复杂一点一次sim就要好几秒N40、T50就意味着2000次仿真。所以种群规模不能盲目做大够用就行。2.3 放着一堆优化算法不用为什么偏偏选PSO做参数寻优摆在我面前的可选项不少网格搜索、贝叶斯优化、遗传算法、差分进化、甚至拿MPC直接替代PID。我最后还是选了PSO理由很实际。网格搜索在参数维度低的时候可以暴力枚举但6个参数的网格哪怕每个维度只取10个点就是10的6次方种组合在没法用解析梯度的仿真模型上完全不现实。贝叶斯优化在小规模调参上很有效但对高维参数空间和带随机噪声的仿真目标收敛速度并不比PSO有压倒性优势而且实现相对复杂。遗传算法和PSO同属群体智能方法效果也接近但遗传算法涉及编码、交叉、变异、选择好几套算子写起来比PSO繁琐得多。PSO最大的优势就是实现起来就是上面那两行更新公式只需要能算适应度不需要目标函数的梯度特别适合把Simulink当黑盒来调用。顺带提一句MPC。热搜里很多人搜过轨迹跟踪MPCMPC理论上控制效果的上限确实比PID高但它需要精确的预测模型还要在线滚动优化对算力和建模精度要求都不低。作为参数调优研究PSO加PID是性价比最高的一条路先把这条链路跑通后续想升级到MPC动力学模型和控制对象部分大部分可以复用。3. 仿真模型与执行器细节搭出能反映真实物理的虚拟四旋翼3.1 牛顿-欧拉方程与一套可直接替换的四旋翼参数四旋翼仿真模型的核心是牛顿-欧拉方程通俗讲就是两部分力决定线加速度力矩决定角加速度。在惯性坐标系下位置部分可以写成m * v_dot m * g * e_z R * [0; 0; T] - k_d * vR是机体坐标系到惯性系的旋转矩阵T是四个电机产生的总升力k_d是平动阻尼系数。姿态部分用机体系下的欧拉方程I * omega_dot -omega x (I * omega) tauI是转动惯量矩阵tau是三个轴上的控制力矩。由四个电机的转速差产生滚转、俯仰、偏航力矩。仿真模型里这套方程不算难写但要写对坐标系符号这往往是新手翻车最多的地方。建议统一用“机体坐标系定义力矩、惯性坐标系定义位移”的方式不要混着算。我用的参数是参考一架小型四旋翼的量级你可以直接替换成自己机架的参数质量m1.24 kg重力加速度g9.81 m/s²转动惯量IxxIyy0.0062 kg·m²Izz0.0112 kg·m²机臂长度L0.24 m推力系数CT1.11e-5 N·s²/rad²反扭矩系数CM2.4e-7 N·m·s²/rad²电机时间常数τ0.02 s最大转速820 rad/s这些数值只需要量级合理即可因为研究重点是控制器设计和参数优化不是气动辨识。不过执行器参数尽量不要随意拍脑袋尤其是电机时间常数和推力系数它们会直接影响Kd能取多大。3.2 Simulink建模的模块划分以及和Python/Gazebo的取舍我主仿真链路用的是MATLAB/Simulink但也不是非它不可。整理一下不同工具的取舍你按自己条件选方案优点缺点适合场景MATLAB/Simulink模块化程度高sim()方便脚本调用示波器方便观察需要License模型复杂时编译慢科研验证、课程设计、批量寻优Python scipy免费可控性强ODE积分逻辑透明控制器改动要重写代码教学、轻量实验Gazebo ROS有传感器模型、接近实物环境搭建成本高和PSO循环对接麻烦后续想部署到实机在Simulink里我建议按信号流把模型拆成几个清晰模块参考轨迹生成、外环位置PID、姿态指令反解、内环姿态PID、电机与动力学模型、传感器测量。每个模块单独封装成子系统PSO脚本通过工作区变量往PID模块里灌参数。这里有一个提升可维护性的关键习惯不要直接在PID模块对话框里写常数而是定义成xxx_kp这类工作区变量。每次粒子群迭代只需要更新工作区变量的值然后调用sim()不需要重新打开模型改参数也给后面做并行加速留了余地。3.3 执行器模型是优化结果的“照妖镜”我见过不少仿真研究直接把PID输出当力矩作用在刚体上完全跳过电机模型。这样做的后果是优化出来的Kd往往偏大因为仿真里没有执行器延迟控制器可以“凭空”立刻产生任意力矩但真实电机的转速变化需要时间。Kd一旦依赖了这种理想假设仿真里看起来很完美的参数放到实物上直接高频振荡。所以执行器模型不能省。最简单的做法是把每个电机的转速响应近似成一阶惯性环节再通过升力和反扭矩曲线换算成推力和力矩。电机饱和也要加上油门指令限幅在0到1之间转速限幅在最大转速以内。否则PSO可能搜出超出物理极限的控制量得到的只是一组在仿真里好看、实际根本飞不出来的参数。4. 双闭环轨迹跟踪回路的三个关键设计点姿态映射、限幅与多速率4.1 外环不直接给姿态而是先算期望加速度外环位置PID最常见的做法不是直接输出期望滚转角而是先输出三个轴的期望加速度再通过几何关系反解出期望姿态角。这个“中间层”特别关键它把位置和姿态之间的物理联系显式写出来了。具体推导可以这样理解水平方向的期望加速度a_x_ref、a_y_ref本质上要靠机体倾斜后推力的水平分量来提供。假设偏航角是ψ期望滚转角φ_des和期望俯仰角θ_des可以近似写成phi_des (a_x_ref * sin(psi) - a_y_ref * cos(psi)) / g 再取atan theta_des (a_x_ref * cos(psi) a_y_ref * sin(psi)) / g 再取atan总油门则由垂直通道的期望加速度决定T_des m * (a_z_ref g)。用生活化的类比你想让飞行器往左边滑光给位置环一个“往左”的指令不够你得告诉它“把机身往左倾斜多少度”推力方向偏了自然就滑过去了。这个反解模块干的就是这件事。这里顺便解释一下为什么标题里强调“双闭环”。整个回路是参考轨迹给到外环位置PID外环输出期望姿态角内环姿态PID再跟踪这个期望姿态角内环输出力矩驱动动力学模型最后回到位置积分。外环一个闭环、内环一个闭环两层串起来这才是双闭环的本意。4.2 内环姿态PID的简易化处理与串级扩展在我的仿真里内环姿态PID直接对期望姿态角和实际姿态角的误差做PID输出等效控制力矩。三个通道——滚转、俯仰、偏航——分别独立做PID但动力学方程里的姿态耦合已经在模型层面体现出来了所以控制器层面按三个单通道控制是成立的。如果你想让控制品质更接近真实飞控内环还可以再往下串一个角速率环也就是姿态角外环加角速率内环的串级结构。工程飞控大多这么做但标题只要求双闭环我为了把研究链路讲清楚就按位置环加姿态环的双闭环来搭。你后面想扩展成三闭环在姿态环内部把角速率PID补上即可PSO的搜索维度从6维变成9维其他流程完全复用。4.3 多速率采样、饱和限幅与积分抗饱和第四章开头提到的时间尺度分离在Simulink里要落地成具体设置。我的做法是位置环采样时间0.02秒姿态环采样时间0.005秒动力学模型用固定步长0.001秒。三者保持一个数量级的差异既符合物理直觉又不会让仿真步数多到跑不动。限幅环节有三个位置必须放外环PID输出端的期望加速度限幅、反解后的期望姿态角限幅、内环PID输出端的力矩限幅。期望加速度限幅我通常限制在0.5g以内因为前面反解公式的分母里有g如果加速度指令接近甚至超过1g期望姿态角会趋近90度欧拉角表示开始奇异。内环PID积分环节要加抗饱和否则前面一限幅积分项还在持续累积会造成很大超调。这几个设计点看着都是细节但PSO优化对细节极其敏感。限幅位置没放对搜出来的参数可能在某些极端状态触发限幅整个回路表现突变适应度曲线一片杂乱粒子群根本没法收敛。5. 适应度函数设计让PSO知道“什么样的PID才算好”5.1 用ITAE量化轨迹偏差公式与离散化实现适应度函数是PSO优化的指挥棒。它怎么定义直接决定粒子群往哪个方向搜索。对轨迹跟踪问题来说最自然的想法是把三维位置误差累积起来但简单的误差绝对值积分区分度不够容易被误差大但时间短的瞬态过程掩盖问题。我更推荐ITAE也就是时间乘以绝对误差再积分。它的好处在于给后面的误差更高的权重让优化器更关注“持续跟踪不上轨迹”的情况而不是一两个瞬间的大偏差。离散化后可以写成J_pos sum( t_k * sqrt((xd-x)^2 (yd-y)^2 (zd-z)^2) * dt )dt是采样步长t_k是当前时刻求和范围覆盖整个仿真周期。这个指标既包含了稳态误差信息又天然惩罚了收敛慢的轨迹段。5.2 量纲归一化与多目标加权轨迹跟踪仿真里同时存在好几类目标位置误差是米姿态角误差是弧度控制力矩变化率是牛·米每秒。如果直接把这几项加在一起量纲不同、数量级不同加权系数基本拍脑袋PSO的搜索结果也会被某一个量级大的项主导。我的做法是先各自归一化到同一量级再加权。位置误差项算出ITAE后除以一个参考值比如初始位置误差的积分量控制平滑项算出来后再除以它的典型量级。然后用一个总适应度J alpha1 * ITAE_pos alpha2 * overshoot_penalty alpha3 * control_smoothness其中alpha1对应轨迹跟踪精度是最主要的目标alpha2对应超调惩罚alpha3对应控制量平滑惩罚。为什么一定要加控制量平滑项因为不加它PSO会搜出一组高增益参数位置误差很小但控制指令在疯狂高频抖动。仿真里没有传感器延迟这种解看起来完美实际飞行根本不可用。加上平滑项优化器才会在“跟踪精度”和“控制量平稳”之间找平衡点。5.3 训练轨迹和验证轨迹必须分开PSO优化用的轨迹和一整轮优化结束后用来验证效果的轨迹一定要分开。如果你优化时用的是圆形轨迹最后验证也用同一条圆形轨迹等于拿训练集当测试集得到的结果大概率虚高。我在工程里优化阶段用圆形轨迹验证阶段换成“8”字形轨迹两条轨迹的最大速度、加速度量级保持一致但空间路径明显不同。另外为了让适应度函数有区分度我会在仿真模型里加一个常值风扰动的输入。比如在水平方向加一个1.5 m/s的横风这样不同PID参数之间的差异会被放大粒子群才能更清楚地判断哪个粒子更好。不加扰动的话很多参数在无风条件下表现接近适应度区分度不够搜索效率会明显变低。6. 从初始化到结果验证PSO与仿真联调的完整流程6.1 参数编码与初始化直接影响收敛速度的关键做法我优化的6维搜索空间是位置外环PID加姿态内环PID各一组增益。这里有个非常实用的经验不要在原始参数空间里直接搜索先做归一化或对数映射。原因很简单PID增益经常跨数量级外环Kp可能是0到几十内环Kp可能是0到几百Kd又可能只是零点几。如果你直接把原始数值放进搜索空间某个维度上粒子移动0.1可能毫无意义换个维度移动0.1可能已经天翻地覆。更稳的做法是把每个参数映射到[0,1]区间粒子群在这个超立方体里搜索评估时再反变换回真实增益。这样所有维度尺度一致粒子移动范围可控收敛速度快得多。初始化还有一个小技巧把一组手动整定的“能飞但不理想”的参数作为其中一个粒子的初始位置其余粒子在这个位置附近随机撒点。这样PSO一开始就站在一个相对不差的位置上搜索相当于在已有经验基础上做局部改进收敛速度快最终结果也更可靠。完全随机初始化不是不行但往往要浪费大量迭代去重新发现“哪些区域是可行的”。整个PSO主循环的伪代码长这样for i 1 to N: 初始化粒子位置X_i和速度V_i 评估X_i的适应度 初始化P_best_i X_i 更新G_best for t 1 to T: for i 1 to N: 更新V_i w * V_i c1*r1*(P_best_i-X_i) c2*r2*(G_best-X_i) 更新X_i X_i V_i 边界处理 将X_i映射为PID参数 跑一次四旋翼轨迹跟踪仿真 计算适应度 更新P_best_i和G_best 输出当前G_best6.2 用sim()和parfor把50个粒子跑完一轮在MATLAB里PSO脚本和Simulink模型的联调是这么做的模型里的PID参数指向工作区变量脚本每轮迭代更新这些变量的值再用sim()命令启动一次仿真。sim()跑完以后从模型的Outport或者日志里把位置误差曲线取出来脚本计算适应度。这里我要重点强调性能优化。普通模式下sim()加载模型一次再运行几十次还好2000次下来你会等到怀疑人生。我实际用的三个优化手段把Simulink模型设成Rapid Accelerator模式编译之后每次sim()的调用开销大幅下降使用parfor对粒子并行求适应度因为每个粒子的仿真相互独立这是天然可并行的仿真只保留必要的输出信号轨迹误差在模型内部算好再输出不要在脚本里从头对几十万行日志做后处理。性能这件事不是锦上添花。PSO是迭代式优化一轮跑得慢意味着整个研究周期被拉长你也就没有余力去跑多次随机初始化、换验证轨迹、加扰动场景这些必要的实验。6.3 收敛曲线怎么读典型优化结果长什么样每一轮PSO迭代结束把G_best对应的适应度记录下来画成收敛曲线。正常的曲线应该是前10代左右快速下降中期缓慢下降后期基本进入平台。如果前几代就收敛到平台大概率是适应度函数区分度不够回到第5章检查量纲和加权如果收敛曲线一直在跳动大概率是仿真数值不稳定回到第7章检查求解器步长设置。我在一次典型实验中优化前手动整定的参数跑圆形轨迹位置RMS误差大约0.16米最大轨迹偏差0.38米ITAE大约285PSO优化后的参数跑同样的轨迹位置RMS误差降到0.04米最大偏差0.11米ITAE降到52。姿态控制量的高频抖动也在加入平滑惩罚后明显减少。不同机架、不同轨迹下具体数值会变但这个量级的提升幅度是比较常见的。优化结束后还要用最优参数重新跑一次完整仿真把三维轨迹、姿态角曲线、四个电机转速曲线全部保存下来。因为PSO寻优过程里只记录了适应度标量很多中间细节没有留下最后这组“验证运行”的数据才是你写论文、画图、做对比分析的素材。7. 仿真中最容易翻车的五个细节一份实测避坑清单7.1 变步长求解器会让适应度变成随机数这是我认为最隐蔽、杀伤力最大的一个坑。Simulink默认的变步长求解器会根据误差容限自动调整步长这在普通仿真里是好事但在PSO循环里是灾难。因为你两次仿真之间只改了PID参数其他设置没变但变步长求解器在不同参数下积分轨迹不一样输出曲线会出现大量毛刺。这些毛刺反映到适应度上就是粒子之间的适应度差异里混入了数值噪声粒子群很难判断哪个参数真的更好收敛曲线一路乱跳。我的解决方案是把求解器强制设成固定步长离散求解器步长0.001秒整个仿真期间步数恒定。这样每次sim()的计算路径高度一致适应度差异只来自PID参数本身优化才稳定。7.2 期望姿态反解的分母出现g奇异点和限幅第4章提到过期望姿态角反解公式里出现了除以g的操作。这意味着当外环给出的期望加速度达到1g时期望姿态角会趋向90度欧拉角表示开始奇异。更危险的是如果某个粒子在搜索早期随机到一组不合理参数外环可能出现远超物理范围的加速度指令反解模块输出NaN整个仿真直接发散这一代粒子全部作废。我在实际过程中试过一次某个粒子搜出来的外环Kp特别大位置误差一上来就冲得很大期望加速度超过2g反解出来的姿态角变成NaNSimulink开始报错。从那以后我就在外环PID输出端加了硬限幅期望加速度绝对值限制在0.5g以内保证反解永远在合理工作区间。这个限幅同时也限制了姿态角的指令范围算是一举两得。7.3 先查适应度函数再谈“粒子群早熟”“粒子群早熟”是群里被问烂的话题。很多人一看收敛曲线前几代就平台了马上怀疑PSO实现有问题加变异、加混沌、加大种群。我排查这类问题的经验是先检查适应度函数有没有区分度再怀疑算法参数。怎么检查区分度很简单随机找两三个粒子分别跑完仿真打印各自的适应度。如果适应度差异在1%以内说明函数设计有问题——可能是ITAE没有覆盖完整时间范围、可能是没有加扰动导致大部分参数效果接近、也可能是量纲没归一化导致某个目标项主导了一切。这时候加再多的变异算子都没用因为算法再好也难以从几乎相同的适应度中判断方向。等适应度有了明确梯度早熟问题往往自动缓解。7.4 从Simulink到Gazebo/ROS的迁移思路以及别迷信最优参数热词里很多人搜Gazebo仿真环境和ROS机器人仿真说明大家不是只想停在MATLAB里。我的建议是先把Simulink这条PSO链路跑通再往Gazebo迁移。迁移的时候四旋翼刚体动力学可以换用Gazebo的插件但双闭环控制器、姿态反解、PSO脚本这三个部分几乎可以原样搬过来只需把PID接口从Simulink端口换成ROS话题。还有一件事必须说清楚PSO给出的所谓最优参数是在你的仿真模型、扰动场景、适应度函数定义下最优不是普适真理。我做完一轮优化后会刻意把最优参数上下浮动20%再分别跑仿真观察性能下降幅度。如果某个参数小范围变动就让轨迹误差急剧恶化说明这个解很脆实际飞行稍有一点模型误差就翻车。这时候我会回到适应度函数加大控制量平滑惩罚或者增加带噪声的传感器模型让算法主动去找更稳的解。最后再分享一个实际使用中很顺手的小技巧每次PSO迭代时把全局最优适应度曲线和每个粒子的当前位置一起存下来不要只存最终结果。粒子位置的历史分布可以画成一张二维投影图能直观看出搜索后期粒子是集中在某个区域还是仍然分散这对判断“是不是该加大变异强度”很有帮助。踩过几次坑之后我最大的体会是PSO不是调参魔法它只是把手动盲试变成有方向感的系统搜索但如果仿真模型和适应度函数本身不稳算法再先进也白搭。
返回列表