第2章:PID控制基础
各位同学,今天我们来聊聊PID控制的基础。说实话,我刚入行那会儿,觉得PID就是个黑盒子——给个目标值,它就帮你调好了。但真正做飞控调参时才发现,不懂原理,你连参数怎么调都不知道。
这一章,我们就把PID的底裤扒开看看。
2.1 开环与闭环控制
先搞清楚一个基本概念:开环和闭环。
开环控制,说白了就是「只管发指令,不管结果」。比如你给电机一个PWM值,它就转那么快。至于实际转速是不是你想要的?不知道,也不管。
我做过一个开环的无人机——嗯,就是那种飞起来就回不来的。你推油门,它上升;但你不知道它到底升了多少。风一吹,它就飘走了。这就是开环的典型问题:没有反馈。
闭环控制就不一样了。它会不断问自己:「我现在在哪?我要去哪?差多少?」然后根据这个差值去调整。
你想想看,飞控里最核心的就是这个闭环。传感器告诉你当前姿态,目标姿态是水平的,差值就是误差。控制器根据误差去调整电机转速。
核心区别:
- 开环:输入 → 输出(无反馈)
- 闭环:输入 → 比较误差 → 控制器 → 输出 → 反馈
我在项目中遇到过最典型的例子:用开环控制舵机角度,结果负载一变,角度就偏了。换成闭环后,不管负载怎么变,舵机都能准确到位。
2.2 P(比例)的作用与效果
比例控制,就是「误差越大,调整越猛」。
公式很简单:输出 = Kp × 误差
举个例子。你的四轴无人机要水平悬停,但当前向右倾斜了10度。比例控制器就会说:「好,我加大左边电机的转速,减小右边电机的转速,力度跟10度成正比。」
Kp越大,调整越猛。但问题来了——调太猛会怎样?
注意:Kp过大,系统会震荡。就像你开车,看到偏离车道了,猛打方向盘——结果打过了,又猛打回来——最后在路上画龙。
我刚开始调飞控时,Kp设得很大,结果无人机在地上疯狂抖动,像得了帕金森。嗯,这就是比例过大的典型表现。
比例控制还有个问题:稳态误差。什么意思?就是系统稳定后,跟目标值之间总差那么一点点。比如你要飞到10米高度,结果它停在9.8米就不动了。
为什么会这样?因为当误差很小时,比例输出也很小,小到不足以克服重力或摩擦力。这时候就需要I了。
2.3 I(积分)的作用与效果
积分控制,就是「把过去的误差累积起来,再算账」。
公式:输出 = Ki × ∫误差 dt
说白了,积分就是记仇。你一直有0.2米的误差,积分项就会越来越大,直到输出足够大,把误差消除掉。
我做过一个定高悬停的项目,只用P控制,高度总是差那么几厘米。加上I之后,几秒钟内误差就归零了。效果立竿见影。
个人经验:积分项不要加太大。我曾经在四轴上把Ki设得过高,结果无人机像坐过山车一样上下震荡。积分饱和是个很头疼的问题——误差累积太大,恢复需要很长时间。
积分的作用总结一下:
- 消除稳态误差
- 对抗持续的外力(比如风、重力)
- 但容易引起超调和震荡
你想想看,积分项就像个「慢性子」——它不着急,但一直在积累。等它反应过来,可能已经过头了。
2.4 D(微分)的作用与效果
微分控制,就是「预测未来,提前刹车」。
公式:输出 = Kd × d(误差)/dt
微分看的是误差的变化率。如果误差正在快速增大,微分就会输出一个很大的反向力,阻止它继续增大。如果误差正在减小,微分就会「踩刹车」,防止超调。
我调试过一架固定翼无人机,只用PI控制时,每次转向都会超调,然后来回摆动。加上D之后,飞机就像老司机——提前减速,稳稳地停在目标角度上。
微分的作用:
- 抑制震荡
- 提高系统稳定性
- 加快响应速度(其实是提前反应)
但微分有个大坑:对噪声极其敏感。传感器数据稍微抖一下,微分项就会剧烈变化。我遇到过最头疼的问题——IMU数据有高频噪声,微分项输出比比例项还大,整个系统都在乱跳。
避坑指南:使用微分前,一定要对传感器数据做低通滤波。我曾经因为没滤波,微分项直接把电机烧了——嗯,那是个惨痛的教训。
2.5 三个参数的关系
P、I、D三个参数,就像三个性格不同的人一起干活:
| 参数 | 性格 | 优点 | 缺点 |
|---|---|---|---|
| P | 急性子 | 反应快,立即响应 | 有稳态误差,容易震荡 |
| I | 记仇型 | 消除稳态误差 | 容易超调,积分饱和 |
| D | 预言家 | 抑制震荡,提前刹车 | 对噪声敏感 |
调参的顺序,我个人习惯是:先调P,让系统基本能工作;再加D,抑制震荡;最后加I,消除稳态误差。
当然,这只是个通用流程。实际项目中,我经常需要反复调整。比如有一次调四轴,P和D都调好了,一加I就震荡。最后发现是积分限幅没设好——嗯,细节决定成败。
2.6 代码实现示例
最后,给一个最简单的PID实现。这是我在STM32上用的基础版本:
typedef struct {
float Kp, Ki, Kd;
float integral;
float prev_error;
float limit; // 输出限幅
} PID_Controller;
float PID_Update(PID_Controller *pid, float target, float current) {
float error = target - current;
// 比例项
float p_out = pid->Kp * error;
// 积分项
pid->integral += error;
float i_out = pid->Ki * pid->integral;
// 微分项
float d_out = pid->Kd * (error - pid->prev_error);
pid->prev_error = error;
// 总输出
float output = p_out + i_out + d_out;
// 输出限幅
if (output > pid->limit) output = pid->limit;
if (output < -pid->limit) output = -pid->limit;
return output;
}
这段代码看起来简单,但实际用起来要注意几点:
- 积分项要加限幅,防止积分饱和
- 微分项最好加一阶低通滤波
- 输出限幅一定要做,不然电机可能烧掉
好了,这一章就到这里。PID的基础概念搞清楚了,下一章我们开始讲具体的调参方法——到时候我会分享一些实战中的「玄学」技巧。
记住:理论是基础,实践出真知。光看书不调参,永远学不会PID。
课后练习:用上面的代码,在仿真环境里调一个温度控制系统的PID参数。先只用P,看看稳态误差有多大;再加I,看能不能消除;最后加D,看能不能减少超调。
公众号:蓝海资料掘金营,微信deep3321