3. PID控制基础:比例、积分、微分的作用、PID参数对系统的影响、数字PID实现

聊到FOC速度环,绕不开的就是PID。说实话,我见过不少新手一上来就调参数,调得满头大汗,结果电机要么抖得像筛子,要么转都转不起来。其实,搞懂PID这三个字母到底在干什么,比盲目调参重要得多。

这一节,咱们就把PID掰开揉碎了讲。我会结合我在电机驱动项目里踩过的坑,帮你把基础打牢。

3.1 比例控制:最直接的“硬拉”

比例控制,说白了就是“看偏差,给力气”。

你设定目标转速是1000 RPM,现在实际转速是800 RPM。偏差是200 RPM。比例控制器就会把这个偏差乘以一个系数Kp,然后输出一个控制量去拉转速。

公式很简单:

u(t) = Kp * e(t)

其中e(t)就是当前偏差。

Kp大了会怎样?

反应快,但容易过头。我在一个无刷电机项目里,Kp设得太大,电机一启动就“嗡”的一声冲过目标,然后来回震荡,像极了秋千停不下来。这就是典型的超调和震荡。

Kp小了会怎样?

反应慢,而且永远追不上目标。你想想看,偏差越小,输出的力就越小。到最后,偏差小到一定程度,输出的力刚好只够克服摩擦力,电机就停在那里,离目标转速差那么一点点。这就是稳态误差。

核心结论:比例控制能快速响应,但单靠它,系统会有稳态误差,而且容易震荡。

3.2 积分控制:专治“差一口气”

刚才说的稳态误差,怎么消除?积分控制就是干这个的。

积分项会把过去所有的偏差累加起来。只要还有偏差,积分项就会一直增长,输出的控制力就会越来越大,直到把最后那点偏差给“磨掉”。

公式:

u(t) = Ki * ∫e(t) dt

Ki的作用:

Ki越大,积分作用越强,消除稳态误差越快。但Ki太大,积分项会“冲过头”,导致系统震荡,甚至出现“积分饱和”。

避坑指南:我曾经在一个大惯量负载的项目里,Ki设得偏大。电机启动时,积分项疯狂累加,等转速到达目标时,积分项已经积累了一大堆“能量”,导致转速直接冲过目标一大截,然后来回震荡了好几次才稳定下来。这就是积分饱和的典型表现。

解决办法:加积分限幅,或者用抗积分饱和算法。这个后面会细讲。

3.3 微分控制:提前“踩刹车”

比例和积分都是“事后”调节,微分则是“事前”预测。

微分项看的是偏差的变化率。如果偏差正在快速减小(转速正在快速接近目标),微分项就会输出一个反向的力,提前“踩刹车”,防止超调。

公式:

u(t) = Kd * de(t)/dt

Kd的作用:

Kd能抑制震荡,提高系统的稳定性。但Kd对噪声非常敏感。你想想看,如果速度反馈信号里有一点毛刺,微分项就会把它放大,导致控制量剧烈抖动。

我的经验:在FOC速度环里,我一般很少用微分项,或者只用很小的Kd。因为电流采样和速度计算本身就有噪声,微分项容易引入高频抖动。如果非要用,一定要先对速度信号做低通滤波。

3.4 PID参数对系统的影响

为了让你看得更清楚,我整理了一个表格。这是我在项目里反复验证过的经验总结。

参数 增大后的效果 减小后的效果 常见问题
Kp 响应变快,超调增大,稳态误差减小 响应变慢,稳态误差增大 Kp过大导致震荡
Ki 消除稳态误差更快,但容易超调 消除稳态误差变慢 Ki过大导致积分饱和
Kd 抑制超调,提高稳定性 系统容易震荡 Kd过大引入噪声

3.5 数字PID的实现

在实际的MCU里,我们用的是离散化的数字PID。说白了,就是把连续的积分和微分,变成累加和差分。

位置式PID:

直接计算当前时刻的控制量。公式如下:

u(k) = Kp * e(k) + Ki * ∑e(i) * T + Kd * (e(k) - e(k-1)) / T

其中T是采样周期。这个公式直接、好理解,但积分项需要一直累加,容易积分饱和。

增量式PID:

计算的是控制量的增量,而不是绝对值。公式如下:

Δu(k) = Kp * (e(k) - e(k-1)) + Ki * e(k) * T + Kd * (e(k) - 2*e(k-1) + e(k-2)) / T

这个公式的好处是:输出的是增量,不会出现积分饱和。而且就算MCU死机重启,控制量也不会突变。我在实际项目中,90%的情况都用增量式PID。

代码示例(增量式PID,C语言):

typedef struct {
    float Kp;
    float Ki;
    float Kd;
    float T;          // 采样周期
    float error_prev; // e(k-1)
    float error_pprev;// e(k-2)
    float output;     // 当前输出
} PID_IncTypeDef;

float PID_Inc_Calc(PID_IncTypeDef *pid, float target, float actual) {
    float error = target - actual;
    float delta_u;

    delta_u = pid->Kp * (error - pid->error_prev)
            + pid->Ki * error * pid->T
            + pid->Kd * (error - 2*pid->error_prev + pid->error_pprev) / pid->T;

    pid->output += delta_u;
    pid->error_pprev = pid->error_prev;
    pid->error_prev = error;

    return pid->output;
}

注意:实际使用时,一定要对输出做限幅。不然积分项或者微分项一抽风,输出值能飞到天上去,电机直接就炸了。

3.6 本章知识体系图

下面这张图,是我用SVG画的。它把PID的核心逻辑、参数影响、以及数字实现的关键点都串起来了。你可以把它当作一个速查地图。

PID控制基础 · 知识体系图 PID控制器 比例 (P) u = Kp * e(t) 快速响应,有稳态误差 积分 (I) u = Ki * ∫e(t) dt 消除稳态误差,易饱和 微分 (D) u = Kd * de/dt 抑制超调,怕噪声 参数影响速查 Kp↑ → 响应快、超调大 | Ki↑ → 消除误差快、易饱和 | Kd↑ → 更稳定、怕噪声 数字PID实现 位置式:直接算绝对值 增量式:算增量,防饱和 (推荐:增量式 + 输出限幅) 常见避坑指南 积分饱和 → 加限幅 微分噪声 → 先滤波 输出飞车 → 限幅+抗饱和 核心:P是主力,I是补刀,D是刹车。调参先调P,再调I,最后微调D。

嗯,这一节的内容就到这里。PID看起来简单,但真正用好,需要你在项目里反复体会。别急,后面我们会结合FOC速度环,一步步把参数调明白。


专注资料整理