05PID 控制
P/I/D、限幅和抗积分饱和
本模块主旨
P / I / D + 限幅 + 抗积分饱和 + 采样周期 —— 把这六件事拧成一个能上 STM32 ISR 的闭环。学完应能回答
- 能用一句话说清 P / I / D 各自解决什么(响应速度 / 稳态误差 / 变化率抑制)
- 能识别 4 类典型病症:响应慢、超调、稳态误差、积分饱和大超调
- 理解输出限幅 + 抗积分饱和必须成对出现,并能写出 Back-Calc 的 C 代码(Kt = Ki/Kp)
- 知道 Ts 是 PID 参数的"刻度尺"——改 PWM 频率必须重算 Ki/Kd 或换增量式
- 能说出"内环带宽 ≥ 外环带宽 × 5~10"和实测如何整定(先内后外、Ziegler-Nichols 临界)
- 会用 ARM CMSIS-DSP arm_pid_f32 / STM32 CORDIC 加速 ISR 内 PID 计算
总览
PID 不是玄学旋钮,是带采样周期 / 限幅 / 抗饱和的一套工程闭环。会调一个就会调全部。零基础速入
类比
PID 就像调淋浴水温:**P** 像直接拧——水太冷就猛拧热水(拧多大与冷热差成正比);**I** 是慢慢补——还差一点就持续多加一点直到水温就位;**D** 是预判——感觉水温正在快速变化时先反向收一下避免过头。这三项加在一起,让"输出"自动跟踪"目标值"。核心概念
PID = 当前误差(P) + 历史累积(I) + 变化趋势(D)。电机控制 99% 的场景只用 PI(P+I),D 在位置环或抖动很大时才加。为什么要学
- 电流环、速度环、位置环全是 PID/PI——会调一个就会调全套。
- Kp 太低响应慢,太高振荡过流;Ki 不够稳态有余差,太大积分饱和大超调。
- "采样周期改变后必须重算 Ki/Kd"是无数初学者翻车的坑——PID 参数和 Ts 是绑定的。
第一手操作
右侧拖 Kp 从 2.2 慢慢推到 8,看响应曲线从光滑爬升变成超调振荡。再点"振荡预设"看极端情况,然后开"抗积分饱和"对比关闭时大超调的差异。学习目标
- 理解 P、I、D 三项的物理作用
- 区分电流环 PI、速度环 PI、位置环 PID 各自的角色
- 识别超调 / 稳态误差 / 振荡 / 积分饱和四类典型病症
核心概念
- P 像弹簧,误差越大推得越猛;I 像记账本,长期误差被慢慢补掉;D 像阻尼器,抑制变化太快。
- 电机控制中电流环用 PI(带宽 1-5 kHz),速度环用 PI(带宽 50-500 Hz),位置环常用 PID 或前馈。
- 抗积分饱和:输出撞限幅时停止/减小积分累加,避免释放限幅后大超调。
公式
离散位置式 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 是经验起点。
工程意义
- 参数过小响应慢,参数过大振荡甚至过流。抗积分饱和必须开。
- 内环带宽 ≥ 外环带宽 × 5~10,否则外环追内环会振荡。
- 采样周期 Ts 是 PID 参数的"刻度尺"——Ts 减半,要么 Ki/2 + Kd×2 重算,要么改用增量式更稳。
STM32 移植指南
- PID 状态结构体含 integral / last_error / out_min / out_max / Kt。
- 电流环固定在 PWM 中断(16-20kHz),速度环以 1-5kHz 分频执行。
- 所有浮点 PID 函数加 static inline,编译器展开到中断后无函数调用开销。
常见误区
- 积分没限幅 → 撞限幅后大超调甚至过流保护。
- 电流环和速度环同频同样高带宽 → 互相打架振荡。
- 改 Ts 后没重算 Ki/Kd → 行为完全变样。
- 没区分位置式/增量式,混着写。
调试方法
- 整定顺序:先电流环(看 Iq 阶跃响应),再速度环(看转速阶跃),最后位置环。
- 只调 P 找到刚开始振荡的 Kp_critical,取 0.4-0.6 倍作为工作点。
- 加 I 直到稳态误差 < 1%,再观察是否有积分振荡。
- D 通常先设 0;位置环抖动严重时再加,且要带低通避免噪声放大。
建议实验
- 加载"慢响应"预设 → 看上升时间长。
- 加载"振荡"预设 → 看明显超调和持续振荡。
- 关掉"抗积分饱和"+ 设 Ki 较大 + 大目标值 → 看撞限释放后的"积分饱和大超调"。
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
*/下一步
- 把 PI 放进 FOC 电流环,观察 Id/Iq 跟踪与限幅互动。
随堂题
PID 的 I(积分)项主要解决什么问题?
- 加快响应
- 消除稳态误差 (正确)
- 抑制噪声
- 降低过流风险
提示:P 项只在有误差时输出;当误差小但非零,需要 I 慢慢累加把它推到位。这就是"消除稳态余差"。
关掉抗积分饱和、Ki 较大时给一个超出限幅的大目标值,撞限后会怎样?
- 没影响
- 正常
- 积分一直累加,限幅释放后产生大超调和长时间振荡 (正确)
- PWM 关断
提示:撞限期间积分仍在累加,攒了一大笔"虚假积分"。一旦目标改回正常,积分要花很长时间反方向消化,期间输出大超调。
电流环带宽 1 kHz、速度环带宽多少最合理?
- 同样 1 kHz
- 500 Hz
- 100-200 Hz (正确)
- 5 kHz
提示:外环带宽要远小于内环(5-10×),否则外环命令变化太快内环跟不上 → 互相打架振荡。
采样周期 Ts 从 1ms 改成 0.5ms(采样率翻倍),位置式 PID 的 Ki 该怎么调?
- 不变
- Ki 加倍
- Ki 减半 (正确)
- 改 Kp
提示:位置式 I 项 = Ki·Ts·Σe,Ts 减半要保持等效积分增益就要 Ki 加倍——但更可靠的做法是不动 Ki,改用增量式 PID。
D(微分)项在电机控制里通常不加,主要原因是?
- 硬件不支持
- 数学复杂
- 采样噪声经过 (e[k]-e[k-1])/Ts 微分会被放大,反而引入抖动 (正确)
- 没必要
提示:D 项放大高频噪声。位置环必要时加 D 也要先低通滤波。电流环和速度环用 PI 已足够。