PID 控制器设计指南 第 1 部分

比例积分微分(PID)控制器以及比例(P)、比例积分(PI)和比例微分(PD)等较简单的控制系统已伴随我们很长时间。比例控制可追溯至18世纪詹姆斯·瓦特为蒸汽机设计的机械飞球调速器。这种基础机械自动化系统与最新的微控制器或可编程逻辑控制器(PLC)解决方案具有共同特性——所有实现方案都会监测受控设备或流程(自动化控制文献中称为"被控对象")的输出并作出响应。这是一个抑制性负反馈过程。若反馈丢失,被控对象将满负荷运行,存在灾难性故障风险。

PID 控制器简介

我们将探讨如图1所示的伺服电机PID应用。该机构基于PORTENTA Pro C33微控制器和PORTENTA扩展板构建。系统还包含Pololu #4754直流电机和Seeed MDD3A电机控制器。这套组合为研究P、PI、PD及PID控制器提供了绝佳测试平台。这是一个响应迅速且输出可被人观察的系统。在系统开发和调试过程中,我们可以听到、看到并感受到电机的响应。

1 :基于伺服电机的PID控制器测试平台,包含Arduino C33、PORTENTA扩展板、Seeed MDD3A电机驱动器和Pololu 4754有刷直流电机。

视频 1 :运行中的伺服电机完成完整旋转后返回起始位置。

技术提示 :PID是统称术语。简单比例控制、比例微分(PD)或比例积分(PI)等较简单的控制器通常被归类为PID控制器的子类。通过将相关增益值设为零来禁用未使用功能,可轻松将PID控制器转换为P、PI或PD控制器。例如,将D增益设为零即可将PID控制器转换为PI控制器。

作者撰写本文的动机

约20年前,我曾在《Nuts & Volts》杂志发表过三篇关于PID的文章。回首看来,我认为那是不错的尝试。但此后,我有机会将PID应用于许多不同场景,包括一些不太明显的应用。更重要的是,我曾指导过许多成功的学生项目。这是个艰难的学习过程,因为它融合了来自多门课程的理念。完成控制理论课程并学习PID及相关数学密集型控制器是一回事。将这些想法实现到一个响应式的现实系统,尤其是带有微控制器所有约束和复杂性的嵌入式系统中,是一种截然不同的体验。

本简报作为控制系统与微控制器主题融合的起点。它偏向于让系统简单运作的实用层面。一旦系统开始运行,并通过经验性调整PID增益和时序参数积累了一些经验,你就可以回头探索数学原理。最终成品如视频1所示。此处伺服电机完成单圈旋转后返回初始位置。

本文 PID 目标

自P、PI、PD和PID控制器最初问世以来,已有数千本相关书籍和文章问世。很可能你已经读过其中一些文章,现在正寻求实现项目并提升其稳定性的实用建议。本工程简报不再重复陈旧的理论内容,而是聚焦PID控制器的实际应用。为方便起见,我们基于您对Arduino微控制器的基础知识,简要探讨FreeRTOS以协助将PID集成到大型生态系统中。

本文具体目标如下:

  • 提供偏向教育导向的PID代码框架。例如,将各个PID增益元素以百分比形式探讨。
  • 提供可观察各PID分量贡献的实时界面。
  • 对各PID分量贡献设置限制。例如,这能让D分量在通常被P分量掩盖时仍可被观察到。
  • 基于Arduino教育基础,再将应用扩展至运行在先进硬件上的实时操作系统。
  • 展示采用现代高性能微控制器(如主打以太网和蓝牙功能的Arduino PORTENTA C33)的原型设计技术。
  • 利用多任务FreeRTOS的灵活性

总之,我们避开已有详尽记载的PID理论,专注于通过交互式经验调谐实现稳健系统。该技术将助您透彻理解PID,从而设计、调试并排查控制系统问题。

请注意DigiKey技术论坛已发布多篇先决文章。请务必查阅这些文章,它们构成本简报至关重要的基础。从现在起,我们假定您已熟悉以下主题:

运动与控制

Arduino PORTENTA Pro

技术提示 :PID控制器可设计为具有高程序效率,适合在8位微控制器上运行。例如,该程序可优化为使用快速整数运算而非浮点计算。本文介绍的PID未作优化尝试,因其完全采用浮点数运算。这种偏向教育的实现方式通过采用带浮点运算单元(FPU)的强大现代32位微控制器得到缓解。

PID 控制器有何用途?

比例积分微分(PID)控制器是广泛使用的过程控制算法。术语"过程"描述为在某个稳定设定点长期或连续运行而设计的系统。常见例子包括调节水压、保持恒温或维持机器恒定转速。

PID概念延伸至专用硬件模块,这些模块可以是模拟或数字形式。也可指运行在微控制器或可编程逻辑控制器(PLC)上的代码。本文将重点探讨PID的软件实现及配套微控制器架构。如有需求,我们后续可研究工业级PID硬件模块或PLC软件实现方案。

PID 控制器有哪些输入输出?

如图2所示,PID控制器具有两个输入和一个输出。输入包括被控对象当前位置(反馈)与目标位置(设定点)的模拟量。输出用于控制被控对象,最小化反馈信号与设定点信号的差值。理想情况下被控对象将精确跟随设定点。现实中这并非易事,尤其当物理对象具有动能和势能时。

经典 PID 算法如何运作?

PID控制器是可通过模拟电路或数字方法实现的数学模型。顾名思义,核心算法由三种数学运算组合而成:

  • 比例项——根据被控对象测量值与设定点偏差进行控制。误差越大,校正控制动作越强。从时间维度看,比例项作用于当前时刻。

  • 积分项——基于误差时间积分的控制动作。微小误差随时间累积会导致大幅控制动作。从时间维度看,积分项作用于历史信息,因为我们累积了所有过往误差。某种程度上,积分项类似低通滤波器,对噪声相对不敏感。

  • 微分项——基于变化速率的控制动作,反映被控对象输出的变化快慢。微分项作用与比例积分项相反。被控对象快速变化时,系统会产生大幅控制动作以减速。从时间维度看,微分项作用于未来——快速变化的系统即将越过目标值。某种程度上,微分项类似高通滤波器,对噪声和时序抖动极为敏感。

经典PID算法如图2所示。注意P、I、D各项均基于误差计算。其中误差为设定值与对象反馈值之差。P、I、D各项的强度由对应系数kP、kI、kD决定。最终将P、I、D各项组合生成对象驱动信号。

2 :传统(学术型)PID控制器框图。P、I、D各项基于误差信号(设定值与反馈值之差)。

核心PID运算可用这段C代码片段描述。为清晰起见,省略了变量声明及存取方法。可见该代码直接对应图2框图。

技术提示 :如图2时钟所示,采样PID控制系统存在隐含的时间要素。下文所示PID更新方法必须定期调用。例如电机控制系统可能需要每10毫秒更新一次。时间间隔波动会表现为噪声,降低PID控制器的微分性能。

float PIDController::update(float feedback) {  // Must be called at regular time intervals
    error = setpoint - feedback;
    P = error * kP;                            // now
    I += error * kI;                           // backwards looking accumulation of all previous errors
    D = (error - last_error) * kD;             // forward looking based on current trend (slow down a fast moving system)
    last_error = error;
    PID_output = P + I + D;
   return PID_output;
}

学生读者或可通过时域方程和离散时间方程识别PID。传统PID方程如下(不作解释):

u(t) = K_p \cdot e(t) + K_i \cdot \int_{0}^{t} e(\tau) \, d\tau + K_d \cdot \frac{d}{dt} e(t)

u[k] = K_p \cdot e[k] + K_i \cdot \sum_{i=0}^{k} e[i] \cdot \Delta t + K_d \cdot \frac{e[k] - e[k-1]}{\Delta t}

我们刚刚探讨了描述传统PID控制器的多种方式。尽管这些描述都真实有效,但对于实际应用中遇到的非线性系统响应和噪声问题,其作用有限。例如,在理想系统中,关联装置可能响应无界的PID指令提供无限功率。实际上,诸如脉宽调制(PWM)驱动的电机控制器等设备受限于物理饱和极限——一旦PWM达到100%,系统就无法再增加功率。噪声是所有反馈测量系统中不可避免的属性,包括本文所介绍的增量编码器。PID更新时间的变化也会引入噪声。

如何改进传统 PID 控制器以提升实际响应?

一个响应迅速的实际PID控制器包含防止积分和微分项相关问题的代码或电路。如图3所示,这包括防止积分饱和的机制、可预测的限制器、直接从反馈获取的微分输入,以及微分输入的低通滤波器。

在继续讨论之前,请注意每个限制器模块被设置为+/-100。因此,我们可以用百分比来讨论P、I和D项的贡献。例如,我们的伺服电机驱动装置可以100%顺时针或逆时针运转。如果发出大幅移动指令,如顺时针方向10圈,P分量将立即饱和并驱动装置100%顺时针运转。

3 :实用的改进PID控制器包含针对P、I和D分量的饱和限制模块。包含锁定机制以防止积分饱和。D项还配有低通滤波器(LPF),其输入直接来自反馈以防止微分冲击。

什么是积分饱和?

积分饱和是一种不良状态,积分项会累积至较大值。举例来说,假设伺服电机设定点改变,指令顺时针移动10圈。这样的运动需要几秒钟完成。若不干预,积分项会持续累积(积累大误差),可能增长到远超100%的驱动量。这将导致系统不稳定,在达到最终值前长期振荡——甚至可能无法稳定。

积分器后的饱和模块会将最大值限制在100%。这有所帮助,但超调和振荡仍存在。锁定模块在系统因P项饱和时阻止累积过程,从而起到作用。换句话说,I分量被冻结,直到电机接近指令设定点。组合作用显著减少了超调量,从而缩短了稳定时间。

什么是微分冲击?

微分冲击是指当PD或PID控制器的设定值改变时产生的不良微分作用。回顾图2可见微分项基于误差,而图3显示其与反馈信号本身相关联。在第一种基于误差的情况下,设定值的大幅变化会导致D项贡献量剧烈变化(冲击)。改进后的反馈方案使微分贡献完全由被控对象决定,对设定值变化无冲击响应。

图3还为微分项加入了低通滤波器(LPF)。这是个简单的滑动平均滤波器,用于消除噪声。包括测量过程中的噪声,以及采样过程引起的抖动噪声。配置该滤波器是调谐过程的一部分,需选择参与平均计算的样本数量。

响应式 PID 控制器代码

改进版PID的代码如本清单所示。注意饱和模块通过fLimit()函数实现。这将P、I、D各项的贡献限制在±100范围内。积分锁定是基于P项的初步检查。若P项饱和,则积分项保持当前值。微分项由反馈信号驱动,并采用包含DSamplesAveraged的滑动平均滤波器。

float PIDController::update(float feedback) {
  error = setpoint - feedback;
  lastSetpoint = setpoint;

  P = error * kP;
  P = fLimit(P, -100.0, 100.0);

  if(fabs(P) != 100) {
      I += error * kI;
  } else {
     ;                        // Hold on I if the P term is saturated.
  }
  I = fLimit(I, -100, 100);

  float runAvgFeedback = runningAverage(feedback, DSamplesAveraged);
  D = ( runAvgFeedback - last_feedback) * kD;
  D = fLimit(D, -100, 100);
  last_feedback = runAvgFeedback;

  PID_output = P + I - D;
  PID_output = fLimit(PID_output, -100, 100);

  return PID_output;

}

最后的思考

本系列后续文章将深入探讨改进版PID代码及配套微控制器结构。我们还将回溯并补充控制系统相关的必要术语。这将有助于更好地理解稳定性。

请在下方留下您的评论和建议。虽无法保证,但我会尝试在后续文章中解答各位的问题。

请点击此链接获取相关Arduino教育内容