一、什么是 PID

在过程控制中,PID 控制器,一直是应用最为广泛的一种自动控制器。PID 控制也一直是众多控制方法中应用最为普遍的控制算法。它不依赖复杂的数学模型,仅仅通过三个参数 (比例、积分和微分) 即可调节出效果较好控制效果。

更具象和通俗一点,对于 PID 来说,我们配置的比例、积分和微分是常量。而我们需要给 PID 控制器输入目标值和实际测量值,这样 PID 控制器就可以输出控制值。之后再采集实际测量值反复循环这个过程。

比如:你开车时,眼睛看路(传感器的捕捉的当前值),大脑对比车道(目标值),手调方向盘(PID计算控制量)。

如果车偏左了,PID会让你往右打方向盘,直到车回到车道中央。

二、位置式 PID

2.2 P 比例

比例项的物理意义是将当前的误差值乘一个系数

如果仅使用比例控制,那么我们的 PID 公式是这样的:

  •  = 比例系数
  •  = 目标值和当前的值的差,也就是误差值

2.2.1 比例环仿真

在 PID Controller Simulator 平台可以仿真 PID 参数

当我们调节参数为 P = 3、I = 0、D = 0

可见实际值并不能贴合到目标值上,而且产生了一个静态误差。

虚线:目标值;粉线:实际值;绿线:PID 调节输出值

当我们调节参数为 P = 5、I = 0、D = 0

可见目标值又开始震荡了,所以只调整比例不能实现我们的控制。

虚线:目标值;粉线:实际值;绿线:PID 调节输出值

2.3 I 积分

积分项的物理意义是将一段时间内的误差累加起来

如果仅使用积分控制,那么我们的 PID 公式是这样的:

  •  = 积分系数
  •  = 累加某一时间段的所有误差

2.3.1 积分环仿真

当我们调节参数为 P = 3、I = 0.03、D = 0

可见在一段时间后系统趋近于贴合目标值,但是还是有一定的震荡

虚线:目标值;粉线:实际值;绿线:PID 调节输出值

2.4 D 微分

微分项的物理意义是计算误差的微分。

如果仅使用微分控制,那么我们的 PID 公式是这样的:

  •  = 微分系数
  •  = 误差变化率

2.4.1 微分环仿真

当我们调节参数为 P = 2.5、I = 0.02、D = 12

震荡的稳态误差也消失了,此时系统比较符合我们的要求

虚线:目标值;粉线:实际值;绿线:PID 调节输出值

2.5 完整的 PID 公式

简单的将、积分和微分相加即构成完整的 PID 公式:

2.5 离散化

离散化(Discretization)是指将连续时间系统​(如模拟信号、微分方程)转换为离散时间系统​(如数字信号、差分方程)的过程。

对于计算机和微控制器 (MCU) 来说,因为只能处理离散时间的数据(即按固定时间间隔采样),并不能完整的处理连续时间系统,无法直接计算积分或微分。因此必须将连续的PID控制算法转换为离散形式。

2.6 离散化的 PID 公式

比例项不变,同时将积分项转化为累加形式并且乘时间 T,微分也简单的变成了本次误差减去上次误差除时间 T。通过离散化处理,这样计算机和 MCU 就可以计算 PID 了。

2.6 离散化公式的代码形式

下面代码中的 error、error_sum 和 derivative,分别对应离散形式的比例项,积分项和微分项。

因为我们简单的看作每次采样和计算时间间隔都是相当的,也就 T 恒等于 1。所以在 C 语言代码中直接省略 T 这个变量。

// 简易位置式PID计算(使用static变量保存状态)
float PID_Calculate(float target, float actual, float Kp, float Ki, float Kd)
{
    static float error_sum = 0;  // 积分项(自动保持)
    static float last_error = 0; // 上次误差(自动保持)

    float error = target - actual;
    error_sum += error;                    // 累积误差(积分项)
    float derivative = error - last_error; // 误差变化率(微分项)

    // PID输出 = 比例 + 积分 + 微分
    float output = Kp * error + Ki * error_sum + Kd * derivative;

    last_error = error; // 保存本次误差供下次使用
    return output;
}

三、增量式 PID

增量 PID,就是每次的比例、积分和微分求和后并不是直接输出的结果,而是上次的增量。

增量式其中的积分只累加三次,不会造成积分饱和的过冲,这样也会让响应快一些。

控制框图如下:

3.1 增量式 PID 推导

这是我们的离散 PID 公式:

那么上一次输出的 PID 应该是这样的,所有 K 减 1 即可:

此时,我们把

减去

其结果应该是本次位置式 PID 输出值减去上次位置式 PID 输出的值,换句话说,也就是本次的控制量的增量(Δu),即 ​​“这一步要比上一步多调整多少”​。

结果如下:

  •  = 本次的控制量的增量

最终输出只需要:

两者相加即可,也就是上次输出的值和本次的增量相加

3.2 增量式 PID 代码

如果没看懂公式的推导,结合代码阅读即可:

/**
 * @brief 增量式PID控制器
 * @param setpoint  目标设定值(如目标温度、速度等)
 * @param actual    当前实际测量值(来自传感器)
 * @param Kp        比例系数(决定对当前误差的反应强度)
 * @param Ki        积分系数(需已乘以采样周期T,用于消除稳态误差)
 * @param Kd        微分系数(需已除以采样周期T,用于抑制振荡)
 * @return          计算得到的控制量输出(如PWM占空比、电机电压等)
 */
float Incremental_PID(float setpoint, float actual, float Kp, float Ki, float Kd) 
{
    // 静态变量声明(保持函数调用间的历史数据)
    static float e_prev = 0;      // 保存上一次的误差值 e(k-1)
    static float e_prev2 = 0;     // 保存上上次的误差值 e(k-2)
    static float u_prev = 0;      // 保存上一次的控制量输出 u(k-1)

    // 计算当前误差 = 目标值 - 实际值
    float e = setpoint - actual;

    // 计算控制增量 Δu(k):
    // 比例项:Kp*[e(k)-e(k-1)] —— 响应误差变化量
    // 积分项:Ki*e(k)          —— 消除当前误差(注意Ki已含采样周期T)
    // 微分项:Kd*[e(k)-2e(k-1)+e(k-2)] —— 抑制误差波动(二阶差分)
    float delta_u = Kp * (e - e_prev)    // 比例项计算
                  + Ki * e               // 积分项计算
                  + Kd * (e - 2 * e_prev + e_prev2); // 微分项计算

    // 计算当前控制量 = 上一次控制量 + 本次增量
    float u = u_prev + delta_u;

    // 更新历史数据(为下一次计算做准备):
    e_prev2 = e_prev;   // 将e(k-1)存入e(k-2)(下次变为e(k-2))
    e_prev = e;         // 将当前误差e(k)存入e(k-1)
    u_prev = u;         // 保存当前控制量供下次使用

    // 返回当前计算的控制量
    return u;
}

四、PI 和 PD 控制

4.1 稳态误差下的两个概念

稳态误差(Steady-state Error)​是自动控制系统在进入稳定状态后,期望输出与实际输出之间的固定偏差。它是衡量系统控制精度的重要指标,反映了系统长期运行时的准确性。

4.1.1 静态误差

静态误差是动态误差函数在  时的极限值。并不是实际误差函数的一部分。也就是说,当时间趋近于无穷后,实际值和目标值仍有一个固定的偏差。

比如:你希望水池内水的高度是10cm,于是你对水龙头进行了控制(把水龙头阀门打开到一定程度),经过足够长的时间,水池内的水高度不不变了,到达了9cm,于是你控制的静态就是1cm。

在 PID 控制中,I 积分项主要用于消除掉这个静态误差。

4.1.2 动态误差

动态误差是一个关于时间的函数,记录了水池内水的高度和目标高度之间的差值(误差)随时间的变化。

4.2 PD 控制器

PD控制就是比例 + 微分控制,在系统稳定后能快速预测未来的变化并做出响应。

特点是快速性和稳定性。微分相当于一个阻力,能有效抑制系统本身产生的震荡。缺点是有静差和放大噪声,当偏差很小时 P 和 D 基本不起作用所以会有静差。噪声与系统自身调节产生的震荡是不同的,噪声一般是高频的干扰。噪声会在输出端影响系统然后反馈到输入端,由于微分控制是有一个系数的,当系数乘上噪声后,可以想象到噪声是被放大了。噪声的放大效果取决于微分系数,如果系统的微分系数很大那就要注意噪声的干扰了。

平衡小车的直立控制就需要用到 PD 控制。当角度接近机械零度时,P控制器就不工作了,控制器认为完成了任务,然而控制器忽略了一种对下一个时刻的预测,即角度在机械零度时电机还存在角速度,简单来说就是小车还有惯性。这时候就需要加入 D 控制器,预测下一时刻的偏差。

对于平衡小车,倒立摆来说,静差对于直立的影响其实并不大,也没有必要一直让平衡车保持机械中值(平衡车,倒立摆在位置不动的情况下也会自身轻微摆动保持平衡)。所以不是很依赖于积分项。视情况会使用 PD 来控制。

4.3 PI 控制器

以伺服为例,PID 的 D 分量作为微分,可以加快动态响应,就类似开车的时候提前预判马上到人行道了,提前踩刹车,防止冲到人行道上,就和抑制过冲类似。

但是在实际的离散控制系统,微分很容易放大噪声,更加建议加前馈,而不是加微分,前馈也可以加快动态响应,但是不会对噪声进行放大。伺服中,位置环,电流环,速度环都可以加前馈。在变频空调常用的单转子压缩机的抑制振荡中,也是通过给速度环加前馈的方式解决。

五、前馈控制

5.1 前馈控制简谈

通过比例 (P)、积分 (I)、微分 (D) 三个环节对系统误差进行反馈调节,适用于消除稳态误差和抑制扰动,但存在响应滞后的问题。同时在之前分析到,微分项在一些情况还会引发震荡,所以 PI + 控制能够解决我们大部分的问题。

所谓前馈控制,就是如下图所示,仅根据目标值输出一个前馈值,与 PI 相加得出输出值。也就是前馈环节根据参考信号或可测扰动(如进料流量、送风量等)生成补偿量,与 PI 输出的校正量叠加,形成总控制量。 

前馈控制快速抵消主要扰动的影响,而 PI 处理剩余误差和未建模动态,两者结合可同时提升响应速度和稳态精度。

5.2 前馈控制代码解析

在这里只举例较为简单的目标微分前馈控制。

前馈补偿的核心思想是通过预测系统输入 (目标值) 的变化趋势,提前生成控制量以抵消潜在的动态误差。微分项(Δtarget = target - last_target)反映了目标值的瞬时变化率,类似于微分控制的“超前校正”特性。这种设计能够快速响应设定值的突变,减少系统因惯性导致的跟踪滞后。

核心代码如下:

// 前馈计算:补偿目标值的变化量(Δtarget = target - last_target)
float feedforward = Kff * (target - last_target);

全部代码如下:

/**
 * @brief 带前馈补偿的位置式PID控制器
 * @param target    目标设定值(如目标位置、温度)
 * @param actual    当前实际测量值
 * @param Kp        比例系数
 * @param Ki        积分系数
 * @param Kff       前馈增益(根据系统模型或实验调整)
 * @return          控制量输出(如PWM占空比、电机电压)
 */
float Feedforward_PID(float target, float actual, float Kp, float Ki, float Kff)
{
    // 静态变量声明(保存历史状态)
    static float error_sum = 0;   // 积分项累积
    static float last_error = 0;  // 上一次误差
    static float last_target = 0; // 上一次目标值(用于前馈计算)

    // 计算当前误差
    float error = target - actual;

    // PID计算
    error_sum += error; // 积分项累积
    float pid_output = Kp * error + Ki * error_sum;

    // 前馈计算:补偿目标值的变化量(Δtarget = target - last_target)
    float feedforward = Kff * (target - last_target);

    // 总控制量 = PID输出 + 前馈补偿
    float output = pid_output + feedforward;

    // 更新历史数据
    last_error = error;
    last_target = target;

    return output;
}

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐