📖 第 13 章:直流有刷电机三环控制实现(Triple-Loop Cascade Control)

⚙️ 正点原子《DMF407 电机控制专题教程》V1.0 · Chapter 13
🗨️ 本章金句:「位置环是司令,速度环是连长,电流环是士兵:外环指挥内环,一级压一级。」
这一章在干嘛? 把第 10~12 章的三个单环起来:位置环输出当速度环的给定,速度环输出当电流环的给定,电流环输出管占空比。这是工业运动控制的经典「串级结构」,也是直流有刷部分的毕业典礼。
13.1 三环(串级)控制原理13.2 三组参数与四个关键机制13.3 核心代码:三环串级一次算完13.4 下载验证

13.1 三环(串级)控制原理

三环 = 电流环 + 速度环 + 位置环的级联。外环不直接驱动电机,而是给内环「下指标」:

原书图 13.1.1
原书图 13.1.1:三环 PID 控制流程:位置环 → 速度环 → 电流环 → PWM
$$\theta_{目标} \xrightarrow{\ e_\theta\ } \mathrm{PID}_\theta \to \omega_{给定} \xrightarrow{\ e_\omega\ } \mathrm{PID}_\omega \to I_{给定} \xrightarrow{\ e_I\ } \mathrm{PID}_I \to u_{PWM}$$

为什么要把环串起来? 各环各司其职:电流环在内,响应最快,管「出多大力」;速度环居中,管「转多快」;位置环在外,管「停在哪」。外环的输出天然就是内环该有的样子,抗扰、限流、平稳定位一次搞定。

13.2 三组参数与四个关键机制

KPKIKD输出身份输出限幅积分限幅
位置环0.060.000.01目标速度±120±1000
速度环5.000.300.01目标电流≤100±200
电流环8.004.001.00占空比[0, 8200]±150

机制一:积分限幅——每环各有一个限幅值,防积分深度饱和:

void integral_limit(PID_TypeDef *PID, float max_limit, float min_limit)
{
    if (PID->SumError >= max_limit)       /* 超上限就钳住 */
        PID->SumError = max_limit;
    else if (PID->SumError <= min_limit)
        PID->SumError = min_limit;
}

机制二:闭环死区——位置偏差绝对值 ≤20 时,偏差清零、积分清空,电机不在目标点附近「打摆子」。机制三:方向处理——电流大小无方向,由速度环输出的符号决定转向:为正则 dcmotor_dir(0) 正转,为负则取反并 dcmotor_dir(1) 反转,保证电流环给到手的恒为正。

限幅经验: 只有电流环/速度环的系统,限幅要比累计偏差最大值稍大(否则出现静态误差);最外环是位置环的系统,限幅可以更小。每次改 PID 系数后,都要复查限幅范围。

13.3 核心代码:三环串级一次算完

/* TIM6 中断里(50ms 一次),三环依序计算 */
integral_limit(&g_location_pid, 1000, -1000);
integral_limit(&g_speed_pid, 200, -200);
integral_limit(&g_current_pid, 150, -150);
/* 死区:位置偏差 |e| ≤ 20 时清零偏差与积分 */
if ((g_location_pid.Error <= 20) && (g_location_pid.Error >= -20)) {
    g_location_pid.Error = 0;  g_location_pid.SumError = 0;
}

/* ① 位置环:输出 = 目标速度,限幅 ±120 */
g_motor_data.motor_pwm = increment_pid_ctrl(&g_location_pid,
                          g_motor_data.location);
if (g_motor_data.motor_pwm >= 120)       g_motor_data.motor_pwm = 120;
else if (g_motor_data.motor_pwm <= -120) g_motor_data.motor_pwm = -120;
g_speed_pid.SetPoint = g_motor_data.motor_pwm;      /* 外环输出给内环 */

/* ② 速度环:输出 = 目标电流;符号决定转向 */
g_motor_data.motor_pwm = increment_pid_ctrl(&g_speed_pid,
                          g_motor_data.speed);
if (g_motor_data.motor_pwm > 0) { dcmotor_dir(0); }          /* 正转 */
else { g_motor_data.motor_pwm = -g_motor_data.motor_pwm;     /* 取反 */
       dcmotor_dir(1); }                                     /* 反转 */
if (g_motor_data.motor_pwm >= 100) g_motor_data.motor_pwm = 100;
g_current_pid.SetPoint = g_motor_data.motor_pwm;    /* 目标电流恒为正 */

/* ③ 电流环:输出 = 占空比,单向限幅 */
g_motor_data.motor_pwm = increment_pid_ctrl(&g_current_pid,
                          g_motor_data.current);
if (g_motor_data.motor_pwm >= 8200)   g_motor_data.motor_pwm = 8200;
else if (g_motor_data.motor_pwm <= 0) g_motor_data.motor_pwm = 0;
dcmotor_speed(g_motor_data.motor_pwm);

13.4 下载验证

上位机同步三组 PID(TYPE_PID1/2/3 分别对应位置/速度/电流环),目标值只能设最外环 g_location_pid.SetPoint——多环系统里内环的目标是外环的输出,手动去改等于越级指挥。按键功能与位置环实验相同:KEY0 +一圈、KEY1 −一圈、KEY2 回原点。

原书图 13.4.1
原书图 13.4.1:三环 PID 控制波形:电机平稳地一格格到位,无明显抖动
调试技巧: 想确定各环的积分限幅值,可以先用串口打印各环的累计偏差看它最大能到多少(注意别干扰 PID 数据上传)。现象上,三环系统最直观的变化是:到位过程「一格一格」很稳重,死区让电机停在目标点附近纹丝不动。
🧠 小测验
1. 三环控制的信号流向是什么?
目标位置 → 位置环(最外环)输出作为速度环给定 → 速度环(次外环)输出作为电流环给定 → 电流环(内环)输出控制 PWM 占空比。外环的输出永远是内环的给定。
2. 三环的积分限幅各是多少?为什么速度环输出为负时要「取反 + 换向」?
位置环 ±1000、速度环 ±200、电流环 ±150。电流大小没有方向,转向由 dcmotor_dir() 单独控制;速度环输出为负说明要反转,取反后电流环给定才恒为正。
3. 闭环死区怎么设置、有什么用?
位置偏差在 −20~+20 之间时把偏差和积分清零。PID 不再响应微小偏差,电机就不会在目标位置附近来回抖动。
← 上一篇🏠 顶层目录下一篇 →