05PID 控制

P/I/D、限幅和抗积分饱和

本模块主旨
P / I / D + 限幅 + 抗积分饱和 + 采样周期 —— 把这六件事拧成一个能上 STM32 ISR 的闭环。

学完应能回答

查看完整 Walkthrough(8 步 + 4 误区)

总览
PID 不是玄学旋钮,是带采样周期 / 限幅 / 抗饱和的一套工程闭环。会调一个就会调全部。

零基础速入

类比
PID 就像调淋浴水温:**P** 像直接拧——水太冷就猛拧热水(拧多大与冷热差成正比);**I** 是慢慢补——还差一点就持续多加一点直到水温就位;**D** 是预判——感觉水温正在快速变化时先反向收一下避免过头。这三项加在一起,让"输出"自动跟踪"目标值"。
核心概念
PID = 当前误差(P) + 历史累积(I) + 变化趋势(D)。电机控制 99% 的场景只用 PI(P+I),D 在位置环或抖动很大时才加。

为什么要学

第一手操作
右侧拖 Kp 从 2.2 慢慢推到 8,看响应曲线从光滑爬升变成超调振荡。再点"振荡预设"看极端情况,然后开"抗积分饱和"对比关闭时大超调的差异。

学习目标

核心概念

公式

离散位置式 PID
u[k] = Kp·e[k] + Ki·Ts·Σe + Kd·(e[k]−e[k−1])/Ts

Ts 是采样周期;输出 u 必须限幅,否则积分会越攒越大。

增量式 PID
Δu[k] = Kp·(e[k]−e[k−1]) + Ki·Ts·e[k] + Kd·(e[k]−2·e[k−1]+e[k−2])/Ts

每次只算"增量",无需保存积分;自带防积分饱和(误差为零时输出不变)。

抗积分饱和(Back-Calculation)
I[k+1] = I[k] + Ki·Ts·e[k] + Kt·(u_sat − u_unsat)

Kt 是回写增益,让积分按饱和差值反向调整。Kt = Ki/Kp 是经验起点。

工程意义

STM32 移植指南

常见误区

  • 积分没限幅 → 撞限幅后大超调甚至过流保护。
  • 电流环和速度环同频同样高带宽 → 互相打架振荡。
  • 改 Ts 后没重算 Ki/Kd → 行为完全变样。
  • 没区分位置式/增量式,混着写。

调试方法

建议实验

STM32 C 代码骨架

/* ============================================
 * pi.h — 带抗积分饱和的 PI 控制器(增量式 + Back-Calculation)
 * 适合电机电流环、速度环
 * ============================================ */

typedef struct {
    float kp;
    float ki;             // 真实增益,注意 Ts 已含在使用方式里
    float ts;             // 采样周期 (s)
    float integral;
    float out_min;
    float out_max;
    float kt;             // 抗饱和回写增益,建议 = ki / kp
} pi_t;

static inline void pi_init(pi_t *c, float kp, float ki, float ts,
                           float lim_min, float lim_max) {
    c->kp = kp;  c->ki = ki;  c->ts = ts;
    c->integral = 0.0f;
    c->out_min = lim_min;  c->out_max = lim_max;
    c->kt = (kp > 1e-6f) ? (ki / kp) : 0.0f;
}

/* 单步 PI(位置式 + 抗积分饱和回写) */
static inline float pi_step(pi_t *c, float ref, float meas) {
    float err = ref - meas;

    /* 1. 先算未饱和输出 */
    float u_unsat = c->kp * err + c->integral;

    /* 2. 限幅 */
    float u = u_unsat;
    if (u > c->out_max) u = c->out_max;
    else if (u < c->out_min) u = c->out_min;

    /* 3. 积分更新 + 抗饱和回写
     *    撞限时 (u_unsat - u) 反符号写回积分,让它退一点 */
    c->integral += c->ki * c->ts * err + c->kt * (u - u_unsat);

    return u;
}

void pi_reset(pi_t *c) { c->integral = 0.0f; }

/* === 整定建议 ===
 * 电流环:Kp = ω_bw × L,  Ki = ω_bw × R
 *   想要 1 kHz 带宽(ω_bw = 6283 rad/s)+ L = 1.2 mH + R = 0.55 Ω:
 *     Kp ≈ 7.5,  Ki ≈ 3450
 *   PWM = 16 kHz → Ts = 62.5 μs,实际整定先取 Kp = 1-2 安全起步
 * 速度环:内环带宽 / 5-10 倍,Kp 试 0.05-0.3,Ki 试 0.5-3
 */

下一步

随堂题

PID 的 I(积分)项主要解决什么问题?
  1. 加快响应
  2. 消除稳态误差 (正确)
  3. 抑制噪声
  4. 降低过流风险
提示:P 项只在有误差时输出;当误差小但非零,需要 I 慢慢累加把它推到位。这就是"消除稳态余差"。
关掉抗积分饱和、Ki 较大时给一个超出限幅的大目标值,撞限后会怎样?
  1. 没影响
  2. 正常
  3. 积分一直累加,限幅释放后产生大超调和长时间振荡 (正确)
  4. PWM 关断
提示:撞限期间积分仍在累加,攒了一大笔"虚假积分"。一旦目标改回正常,积分要花很长时间反方向消化,期间输出大超调。
电流环带宽 1 kHz、速度环带宽多少最合理?
  1. 同样 1 kHz
  2. 500 Hz
  3. 100-200 Hz (正确)
  4. 5 kHz
提示:外环带宽要远小于内环(5-10×),否则外环命令变化太快内环跟不上 → 互相打架振荡。
采样周期 Ts 从 1ms 改成 0.5ms(采样率翻倍),位置式 PID 的 Ki 该怎么调?
  1. 不变
  2. Ki 加倍
  3. Ki 减半 (正确)
  4. 改 Kp
提示:位置式 I 项 = Ki·Ts·Σe,Ts 减半要保持等效积分增益就要 Ki 加倍——但更可靠的做法是不动 Ki,改用增量式 PID。
D(微分)项在电机控制里通常不加,主要原因是?
  1. 硬件不支持
  2. 数学复杂
  3. 采样噪声经过 (e[k]-e[k-1])/Ts 微分会被放大,反而引入抖动 (正确)
  4. 没必要
提示:D 项放大高频噪声。位置环必要时加 D 也要先低通滤波。电流环和速度环用 PI 已足够。