PID 控制器设计:从原理到实现
系列:电机控制系列 - 第 9 篇 目标平台:STM32F407ZGT6 阅读时间:30 分钟
前言
PID 是电机控制的灵魂:
- 电流环 PID → 控制电流
- 速度环 PID → 控制转速
- 位置环 PID → 控制位置
本篇目标:
- ✅ 理解 PID 原理
- ✅ 掌握参数整定方法
- ✅ 实现抗积分饱和
一、PID 控制器原理
1.1 连续 PID
┌─────────────────────────────┐
│ │
│ u(t) = Kp·e(t) + Ki·∫e(t)dt + Kd·de(t)/dt
│ └──┬──┘ └───┬───┘ └───┬───┘
│ P I D
│
e(t) ────┴──────────────────────────────────────> u(t)
误差 输出三项作用:
| 项 | 公式 | 作用 | 特点 |
|---|---|---|---|
| P | Kp·e(t) | 快速响应 | 比例调节 |
| I | Ki·∫e(t)dt | 消除稳态误差 | 积分累积 |
| D | Kd·de(t)/dt | 抑制超调 | 微分预测 |
1.2 离散 PID
位置式 PID:
u(k) = Kp·e(k) + Ki·Σe(k)·Ts + Kd·(e(k)-e(k-1))/Ts增量式 PID(推荐):
Δu(k) = u(k) - u(k-1)
= Kp·(e(k)-e(k-1)) + Ki·e(k)·Ts + Kd·(e(k)-2e(k-1)+e(k-2))/Ts优点:
- ✅ 计算量小
- ✅ 无冲击切换
- ✅ 适合增量式编码器
二、PID 代码实现
2.1 基础 PID 结构体
/**
* @brief PID 控制器
*/
typedef struct {
float Kp; // 比例增益
float Ki; // 积分增益
float Kd; // 微分增益
float integral; // 积分累积
float prev_error; // 上次误差
float prev_prev_error; // 上上次误差
float integral_limit; // 积分限幅
float output_limit; // 输出限幅
float Ts; // 采样周期(s)
} PID_t;2.2 位置式 PID
/**
* @brief 位置式 PID 计算
*/
float PID_Position(PID_t *pid, float error) {
// P 项
float p_term = pid->Kp * error;
// I 项
pid->integral += error * pid->Ts;
// 积分限幅(抗饱和)
if (pid->integral > pid->integral_limit) {
pid->integral = pid->integral_limit;
} else if (pid->integral < -pid->integral_limit) {
pid->integral = -pid->integral_limit;
}
float i_term = pid->Ki * pid->integral;
// D 项
float d_term = pid->Kd * (error - pid->prev_error) / pid->Ts;
// 更新历史
pid->prev_error = error;
// 输出
float output = p_term + i_term + d_term;
// 输出限幅
if (output > pid->output_limit) {
output = pid->output_limit;
} else if (output < -pid->output_limit) {
output = -pid->output_limit;
}
return output;
}2.3 增量式 PID
/**
* @brief 增量式 PID 计算
*/
float PID_Increment(PID_t *pid, float error) {
// 计算增量
float delta_u = pid->Kp * (error - pid->prev_error) +
pid->Ki * error * pid->Ts +
pid->Kd * (error - 2.0f * pid->prev_error + pid->prev_prev_error) / pid->Ts;
// 更新历史
pid->prev_prev_error = pid->prev_error;
pid->prev_error = error;
// 累积输出
static float output = 0;
output += delta_u;
// 输出限幅
if (output > pid->output_limit) {
output = pid->output_limit;
} else if (output < -pid->output_limit) {
output = -pid->output_limit;
}
return output;
}三、抗积分饱和
3.1 积分饱和问题
现象:
误差持续存在 → 积分累积过大 → 输出饱和 → 响应变慢例子:
- 电机堵转 → 误差持续 → 积分很大
- 堵转解除 → 积分仍很大 → 电机飞车
3.2 抗饱和方法
方法 1:积分限幅(已实现)
// 积分累积不超过 ±integral_limit
if (pid->integral > pid->integral_limit) {
pid->integral = pid->integral_limit;
}方法 2:条件积分
/**
* @brief 条件积分(误差小时才积分)
*/
void PID_Conditional_Integral(PID_t *pid, float error) {
// 误差在 ±epsilon 内才积分
float epsilon = 1.0f;
if (fabsf(error) < epsilon) {
pid->integral += error * pid->Ts;
}
}方法 3:积分分离
/**
* @brief 积分分离(启动时禁用积分)
*/
void PID_Integral_Separation(PID_t *pid, float error, float threshold) {
// 误差大于阈值时,清零积分
if (fabsf(error) > threshold) {
pid->integral = 0;
} else {
pid->integral += error * pid->Ts;
}
}方法 4:抗饱和反馈
/**
* @brief 抗饱和反馈
*/
float PID_Anti_Windup(PID_t *pid, float error, float output) {
// 计算饱和误差
float saturation_error = output - pid->output_limit;
// 反馈到积分
float K_anti = 0.5f; // 抗饱和增益
pid->integral -= K_anti * saturation_error * pid->Ts;
return output;
}四、PID 参数整定
4.1 试凑法
步骤:
1. Ki = 0, Kd = 0,逐步增大 Kp
→ 直到系统开始震荡
2. 减小 Kp 到震荡消失
→ Kp_final = 0.6 × Kp_osc
3. 增大 Ki
→ 消除稳态误差
4. 增大 Kd(可选)
→ 减小超调4.2 临界比例度法
步骤:
1. Ki = 0, Kd = 0
2. 增大 Kp 直到系统临界震荡
3. 记录:
- Kp_crit:临界 Kp
- T_crit:震荡周期
4. 计算参数:
Kp = 0.6 × Kp_crit
Ki = Kp / (0.5 × T_crit)
Kd = Kp × 0.125 × T_crit4.3 继电反馈法
/**
* @brief 继电反馈整定
*/
void PID_Relay_Tuning(void) {
// 施加继电控制
float h = 1.0f; // 继电幅值
while (1) {
float error = ref - feedback;
if (error > 0) {
output = h;
} else {
output = -h;
}
// 测量震荡周期 T_crit
// ...
// 计算 PID 参数
float Kp = 0.6f * Kp_crit;
float Ki = Kp / (0.5f * T_crit);
float Kd = Kp * 0.125f * T_crit;
}
}五、电机 PID 应用
5.1 电流环 PID
// 电流环(快速,kHz 级)
PID_t pid_id = {
.Kp = 2.0f,
.Ki = 200.0f, // 大 Ki,快速消除误差
.Kd = 0.0f,
.Ts = 0.00005f, // 20kHz → 50us
.integral_limit = 50.0f,
.output_limit = 24.0f // 母线电压
};
PID_t pid_iq = {
.Kp = 2.0f,
.Ki = 200.0f,
.Kd = 0.0f,
.Ts = 0.00005f,
.integral_limit = 50.0f,
.output_limit = 24.0f
};5.2 速度环 PID
// 速度环(中等,100Hz 级)
PID_t pid_speed = {
.Kp = 0.5f,
.Ki = 10.0f,
.Kd = 0.01f, // 小 Kd,抑制超调
.Ts = 0.01f, // 100Hz → 10ms
.integral_limit = 10.0f,
.output_limit = 10.0f // 最大电流
};5.3 位置环 PID
// 位置环(慢速,10Hz 级)
PID_t pid_position = {
.Kp = 10.0f,
.Ki = 1.0f,
.Kd = 0.1f,
.Ts = 0.1f, // 10Hz → 100ms
.integral_limit = 5.0f,
.output_limit = 100.0f // 最大速度
};六、总结
PID 核心要点:
- P:快速响应
- I:消除稳态误差
- D:抑制超调
- 抗积分饱和很重要!
下一篇:FOC 控制框架