ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

无人机飞控PID算法实战:从炸机到稳定悬停的调参指南

2026/10/8 12:18:18 拓冰建站 浏览量
无人机飞控PID算法实战:从炸机到稳定悬停的调参指南 1. 从一次炸机说起为什么PID是飞控的灵魂去年秋天我带着自己组的一架450轴距的四旋翼去郊外试飞。那天风不大GPS定位也稳悬停的时候看着挺像那么回事。结果我手一抖切了定高模式飞机突然像喝醉了酒一样上下窜动越窜越猛最后直接翻扣砸在草地上桨叶断了两根机架裂了一道缝。捡回来分析日志姿态曲线在定高通道上画出了一条标准的发散振荡——典型的PID参数没调好P太大D几乎没起作用。这件事让我重新把飞控里的PID算法从头到尾捋了一遍。很多人玩无人机飞控直接买现成的参数用默认值能飞就行。但只要你稍微想飞得稳一点、想挂个相机拍点东西、想在大一点的风里不炸机PID就绕不过去。它不是什么高深莫测的数学本质上就是一套“根据偏差来修正”的规则只不过这套规则被写进了代码每秒执行几百上千次控制着四个电机的转速让飞机在空中保持你想要的姿态。这篇文章我想聊的就是无人机飞控里PID算法到底怎么工作、姿态控制是怎么实现的、参数怎么调、代码怎么写、遇到问题怎么排查。不管你是刚入门的飞控小白还是已经能飞但想搞明白底层逻辑的爱好者或者正在用Pixhawk做二次开发的工程师都能从里面找到能直接用的东西。我会尽量少堆公式多用实际调试中遇到的场景来解释把那些文档里不会写的坑和技巧都摊开来讲。2. 飞控PID的整体设计思路与方案选型2.1 为什么是PID而不是别的控制算法飞控的姿态控制算法有很多选择比如LQR、MPC、滑模控制、模糊控制等等。但在消费级和开源飞控里PID占据了绝对主导地位。原因很直接计算量小、参数物理意义明确、调试方法成熟、对模型精度要求不高。无人机是一个典型的欠驱动系统——四个电机控制六个自由度姿态和位置是耦合的。你不可能用一套精确的动力学模型去算每个时刻该给多少油门因为模型误差、电机响应差异、电池电压下降、风扰这些因素随时在变。PID的好处是它不依赖精确模型它只看“当前姿态和目标姿态差多少”然后根据这个差值去修正。P管当前误差I管累积误差D管误差变化趋势三个环节各司其职配合起来就能把姿态稳住。我试过用LQR做仿真理论上性能确实好但一到实机上电机死区、桨叶不平衡、IMU振动这些非理想因素一进来效果反而不如调好的PID。所以对于绝大多数飞控场景PID是性价比最高的选择。2.2 串级PID姿态控制的标准架构飞控里的PID不是简单的一层。以常见的Pixhawk为例姿态控制用的是串级PID结构外环是角度环内环是角速度环。外环输入是目标角度比如遥控器打杆给出的期望横滚角和IMU解算出的当前角度输出是期望角速度。内环输入是期望角速度和陀螺仪测得的当前角速度输出是电机混控的修正量。为什么要串两级因为角度环响应慢角速度环响应快。如果只用角度环当飞机受到扰动时角度变化需要一段时间才能被检测到修正就滞后了。加上角速度环之后陀螺仪能瞬间感知到旋转趋势在角度还没明显变化之前就开始修正响应速度提升一个数量级。这就像开车角度环是看后视镜判断车偏了多少角速度环是看方向盘转了多少度后者更灵敏。2.3 位置式PID与增量式PID的选择在代码实现层面PID有两种常见形式位置式和增量式。位置式PID的输出直接对应执行器的绝对量公式是u(k) Kp*e(k) Ki*Σe(i) Kd*(e(k)-e(k-1))增量式PID输出的是执行器的增量Δu(k) Kp*(e(k)-e(k-1)) Ki*e(k) Kd*(e(k)-2e(k-1)e(k-2))飞控里用哪种我实测下来姿态角速度环用增量式更稳。原因是增量式不需要累加历史误差积分饱和问题更容易处理而且当遥控器回中时增量式能自然回到零输出不会因为积分项残留导致飞机缓慢漂移。位置式在定高和位置控制里用得更多因为需要输出绝对高度或位置对应的油门/角度。Pixhawk的AC_AttitudeControl库用的是位置式PID但做了积分限幅和抗饱和处理。而很多自研飞控为了代码简洁角速度环直接用增量式。两种都能飞关键看你怎么处理积分和限幅。2.4 采样频率与实时性要求PID控制器的执行频率直接影响控制效果。飞控主循环一般跑在400Hz到1kHz姿态控制内环至少400Hz外环可以降到100Hz到250Hz。为什么内环要这么快因为陀螺仪的采样率可以到8kHz电机响应时间在毫秒级。如果控制频率太低比如只有50Hz那么两次控制之间飞机已经转了好几度修正就会变成“过冲-振荡”的循环。我试过把内环降到100Hz悬停时飞机就开始有肉眼可见的低频晃动恢复到400Hz后立刻平稳。所以如果你自己写飞控代码姿态内环的循环周期最好控制在2.5ms以内外环5ms到10ms。用RTOS的话把姿态任务优先级设到最高确保不被其他任务打断。3. 姿态控制核心细节与实操要点3.1 姿态解算PID的输入从哪来PID需要知道当前姿态这个姿态来自IMU。IMU包含加速度计和陀螺仪加速度计测重力方向陀螺仪测角速度。但加速度计噪声大、动态响应差陀螺仪有零漂单独用都不行。所以飞控里一般用互补滤波或卡尔曼滤波把两者融合。互补滤波简单说就是高频信任陀螺仪低频信任加速度计。公式大概是angle 0.98*(angle gyro*dt) 0.02*accel_angle这个0.98和0.02就是权重根据陀螺仪零漂和加速度计噪声来调。Pixhawk用的是EKF2更复杂但效果更好。这里有个坑如果加速度计校准不准或者机架振动太大导致加速度计读数波动融合出来的角度就会抖PID再努力也稳不住。我遇到过一架飞机悬停时横滚角一直在±3度波动查了半天发现是飞控减震板太软电机振动传到了IMU上。换了硬一点的减震胶之后角度曲线立刻平滑了。3.2 角度环与角速度环的参数作用角度环的P决定飞机回到目标角度的力度。P太小飞机打杆后回中慢像开船P太大回中时会在目标角度附近来回振荡。角度环一般不用I因为角度误差的积分会导致飞机在水平方向上缓慢漂移。D也用得少因为角度环的输入已经经过滤波再微分噪声会放大。角速度环是核心。P决定对角速度偏差的响应强度I消除稳态误差D抑制振荡。以横滚角速度环为例假设目标角速度是0悬停陀螺仪测得当前角速度是10度/秒。P0.5时输出修正量是5P1.0时输出是10。P越大修正越猛但太大会引起高频振荡。I的作用是消除“持续偏差”。比如飞机因为电池偏置导致一直有轻微右滚趋势角速度环的P只能减小这个趋势不能完全消除。加上I之后误差累积到一定程度输出会慢慢增大直到趋势被抵消。D的作用是“预判”。当角速度快速变化时D项会产生反向修正防止过冲。但D对噪声极其敏感陀螺仪的微小抖动经过微分会被放大。所以D项一般要加低通滤波截止频率在50Hz到100Hz。3.3 电机混控PID输出怎么变成电机转速PID算出来的修正量是力矩需要分配到四个电机上。以X型四旋翼为例横滚修正左边两个电机加右边两个电机减俯仰修正前面两个电机加后面两个电机减偏航修正对角电机加另一对角减混控矩阵大概是motor1 throttle roll pitch - yaw motor2 throttle - roll pitch yaw motor3 throttle - roll - pitch - yaw motor4 throttle roll - pitch yaw这里有个关键点混控之后要限幅。如果PID输出太大某个电机算出来超过最大油门或低于最小油门就会导致姿态控制失效。所以代码里要做归一化处理保证四个电机都在有效范围内同时尽量保持总推力不变。我踩过的坑有一次调大P之后飞机在急打杆时一个电机饱和飞机瞬间失去平衡。后来在混控里加了优先级——姿态修正优先于油门当电机饱和时自动降低总油门保证姿态可控。3.4 积分限幅与抗饱和积分项是双刃剑。它能消除稳态误差但也会“ windup”——当误差长时间存在时积分项会累积到很大即使误差反向输出仍然很大导致超调。飞控里必须做积分限幅。比如角速度环的积分项限制在±0.3范围内超过就不再累加。另外当电机饱和时积分项应该停止累加甚至反向清零这就是抗饱和。Pixhawk的做法是当输出达到限幅值时积分项不再增加并且根据饱和程度回退一部分积分。这个逻辑在AC_AttitudeControl::rate_controller里可以找到。3.5 滤波让D项能用前面说了D对噪声敏感。实际飞控里陀螺仪原始数据有高频噪声直接微分会让电机发出高频啸叫甚至烧电调。所以D项前面要加低通e滤波。最简单的一阶低通d_filtered d_filtered alpha*(d_raw - d_filtered)alpha根据截止频率和采样周期算alpha dt / (RC dt)RC 1/(2pifc)fc是截止频率。我一般把D项滤波截止频率设在80Hz左右。太低会让D响应变慢太高噪声滤不干净。这个值要根据机架和桨叶的振动特性来调大桨低转速可以设低一点小桨高转速设高一点。4. 完整实操流程从零写一个姿态PID控制器4.1 准备工作硬件与工具清单要复现这套流程你需要一块带IMU的飞控板Pixhawk、F4/F7飞控都行一个能看日志的地面站QGroundControl或Mission Planner一台能编译飞控固件的电脑一架装好的无人机桨叶先拆掉用电机测试模式调参软件方面如果你用PX4或ArduPilot可以直接改参数。如果想自己写代码推荐用STM32FreeRTOS或者用ArduinoMPU6050做小规模验证。4.2 代码框架姿态控制任务下面是一个简化的姿态控制任务伪代码基于增量式PIDvoid attitude_control_task(void) { float dt 0.0025f; // 400Hz float gyro[3], accel[3]; float angle[3], target_angle[3]; float rate_error[3], rate_output[3]; // 增量式PID状态 static float last_rate_error[3] {0}; static float last_last_rate_error[3] {0}; while (1) { // 读取IMU imu_read(gyro, accel); // 姿态解算 attitude_estimate(gyro, accel, angle, dt); // 获取遥控器目标角度 rc_get_target_angle(target_angle); for (int i 0; i 3; i) { // 外环角度PID - 目标角速度 float angle_error target_angle[i] - angle[i]; float target_rate angle_pid[i].kp * angle_error; // 内环角速度PID - 电机修正量 rate_error[i] target_rate - gyro[i]; // 增量式PID float delta rate_pid[i].kp * (rate_error[i] - last_rate_error[i]) rate_pid[i].ki * rate_error[i] * dt rate_pid[i].kd * (rate_error[i] - 2*last_rate_error[i] last_last_rate_error[i]) / dt; rate_output[i] delta; // 限幅 rate_output[i] constrain(rate_output[i], -MAX_OUTPUT, MAX_OUTPUT); // 更新历史误差 last_last_rate_error[i] last_rate_error[i]; last_rate_error[i] rate_error[i]; } // 混控 motor_mix(rate_output, throttle); // 等待下一个周期 vTaskDelayUntil(last_wake, dt * 1000); } }这段代码里外环只用了P内环用了完整的PID。实际调试时先把内环调好再调外环。4.3 参数整定从默认值到能飞调参的顺序是先调角速度环P再调角速度环D然后调角速度环I最后调角度环P。第一步角速度环P把I和D设为零P从0.5开始。用手拿着飞机快速转动横滚方向感受电机是否在对抗你的转动。P太小电机反应弱P太大电机会剧烈抖动。找到那个“电机有力但不过冲”的值一般在0.8到1.5之间。第二步角速度环D加上D从0.01开始。D的作用是抑制振荡。如果你快速转动后松手飞机角度会来回摆几下才停说明D不够。如果电机发出高频啸叫说明D太大或滤波不够。我一般调到快速转动后只回摆一次就停。第三步角速度环II从0.01开始慢慢加。I的作用是消除缓慢漂移。如果你把飞机放在桌上电机慢慢加速试图纠正一个不存在的偏差说明I太大。合适的I应该让飞机在受到持续扰动时能慢慢回正但不会自己“跑偏”。第四步角度环P角度环P决定打杆后回中的力度。从2.0开始太小回中慢太大回中时振荡。一般调到打杆到极限松手后飞机能在0.5秒内回到水平且不振荡。4.4 试飞验证悬停与扰动测试参数调好后装上桨叶在开阔场地试飞。先悬停看飞机是否稳定。然后用手轻推一下机臂看飞机能否快速回正。再切定高模式看高度是否稳定。如果悬停时飞机有低频晃动说明角度环P太大或角速度环P太小。如果飞机有高频抖动说明角速度环P太大或D滤波不够。如果飞机缓慢漂移说明角速度环I不够或加速度计校准不准。我一般会飞完一块电池后看日志重点看陀螺仪曲线和电机输出曲线。如果电机输出在悬停时一直在±50以内波动说明参数比较健康。如果波动超过±200说明参数太激进。5. 常见问题与排查技巧实录5.1 飞机一解锁就翻这是最吓人的问题。原因通常是电机转向或桨叶装反飞控方向装反混控矩阵符号错误角速度环P太大排查方法拆掉桨叶解锁后用手转动飞机看电机转速变化是否符合预期。如果横滚时左边电机加速、右边减速说明方向对。如果反了改混控符号。5.2 悬停时高频抖动电机发出“滋滋”声飞机像得了帕金森。原因角速度环P太大D项滤波截止频率太高机架振动太大IMU减震不够桨叶不平衡排查方法先降低角速度环P如果抖动消失说明是P的问题。如果还在抖把D滤波截止频率降到50Hz。如果还抖检查桨叶平衡和IMU减震。5.3 打杆后回中慢飞机打杆后松手要好几秒才回到水平。原因角度环P太小角速度环I太小遥控器回中信号有延迟排查方法先加大角度环P如果回中变快但开始振荡说明P到了临界值。然后加角速度环I让飞机在受到持续扰动时能慢慢回正。5.4 定高模式上下窜动这是高度环PID的问题。高度环的输入是气压计或超声波测距输出是油门修正。如果P太大飞机会在目标高度上下振荡如果I太大飞机会缓慢漂移。排查方法先调高度环P让飞机能快速响应高度变化但不振荡。然后调I消除稳态误差。D一般不用因为气压计噪声大。5.5 参数速查表问题现象可能原因调整方向高频抖动角速度环P太大降低P检查D滤波低频晃动角度环P太大降低角度环P回中慢角度环P太小增大角度环P缓慢漂移角速度环I太小增大I检查加速度计校准电机啸叫D太大或滤波不够降低D降低滤波截止频率一解锁就翻电机转向/混控错误检查转向和混控矩阵定高振荡高度环P太大降低高度环P5.6 独家避坑技巧第一调参时一定要拆桨。我见过有人不拆桨调参飞机突然满油门桨叶直接把桌子削了一块。第二每次只调一个参数。同时调P和D你根本不知道是哪个起了作用。第三记录每次调参后的日志。我习惯在日志文件名里写上参数值比如“roll_p1.2_d0.05.bin”这样回头对比很方便。第四不要迷信自动调参。自动调参能给你一个不错的起点但最终还是要手动微调。因为自动调参不知道你的飞行风格——你是想拍视频要稳还是想穿越要灵敏。第五电池电压下降会影响PID效果。电压低时电机响应变慢同样的P值可能就不够了。所以调参时最好用满电电池并且飞完一块电池后检查参数是否还合适。6. 进阶话题从能飞到飞得好6.1 前馈控制让响应更快PID是反馈控制它只能在误差出现之后才修正。前馈控制是在误差出现之前就给出修正量。比如遥控器打杆时直接把打杆量的一部分加到电机输出上这样飞机响应更快PID只需要修正剩余误差。Pixhawk里有个参数叫“前馈增益”一般设在0.1到0.3之间。我试过把前馈加到0.2打杆响应明显变快而且PID的P可以适当降低减少振荡风险。6.2 自适应PID让参数随环境变化固定PID参数在电池电压变化、载重变化、风速变化时效果会打折扣。自适应PID可以根据飞行状态实时调整参数。比如根据电机输出饱和程度调整I的限幅根据角速度误差大小调整P。开源飞控里ArduPilot有“学习型PID”会在飞行中自动微调参数。但自适应算法复杂调不好反而更不稳定。我建议先把固定PID调好再考虑自适应。6.3 振动分析与滤波优化振动是PID的大敌。如果机架振动频率和PID的响应频率接近就会共振。分析振动的方法是看陀螺仪的FFT频谱。如果某个频率的幅值特别高说明机架在那个频率有共振。解决方法调整桨叶平衡、更换减震胶、在代码里加陷波滤波器。陷波滤波器可以针对特定频率衰减不影响其他频率。Pixhawk支持设置陷波滤波器中心频率和带宽。6.4 日志分析用数据说话调参不能靠感觉要看日志。我一般看三个曲线目标角度、实际角度、电机输出。如果实际角度总是滞后于目标角度说明P不够或前馈不够。如果实际角度在目标角度附近振荡说明P太大或D不够。如果电机输出一直在高频波动说明D滤波不够或振动太大。把日志导出成CSV用Python画图分析比在地面站里看更清楚。我写过一个脚本自动计算超调量和调节时间这样调参就有量化指标了。7. 我个人的调参体会调了这么多年飞控我最大的体会是PID参数没有“最优”只有“适合”。同一套参数在无风室内飞很稳到了室外有风环境可能就不够。载重不同、桨叶不同、电池不同参数都要微调。所以与其追求一套万能参数不如学会快速调参的方法。我现在的习惯是新飞机首飞前先用默认参数在自稳模式下低空悬停确认基本稳定。然后飞一个起落看日志根据曲线微调。一般两三个起落就能调到比较满意的状态。另外不要忽视机械部分。电机座松动、机臂裂纹、桨叶变形这些都会让PID失效。我遇到过一架飞机调了半天参数都不对最后发现是一个电机座螺丝松了导致那个电机有虚位。拧紧之后原来的参数直接就能飞。最后分享一个小技巧如果你不确定P该调大还是调小先往大调直到出现振荡然后往回退一半。这样比从小往大调更快找到临界点。D也是类似先加大到电机啸叫然后退到啸叫消失。I比较敏感建议从小往大慢慢加不要超过0.1。飞控PID这东西理论看再多不如实际调一次。找个安全的场地拆掉桨叶先练手把每个参数的作用摸清楚再装上桨叶试飞。炸几次机不可怕可怕的是炸了不知道为什么炸。只要每次炸机都能从日志里找到原因你的调参水平就会快速提升。