PID控制器基础和教程:Arduino中的PID实现
对于从事工业控制的人来说,比例、积分、微分(PID)理论可能是一个熟悉的概念。对大多数人来说,这个术语完全陌生,但您可能比想象中更熟悉它。当您在汽车中踩油门踏板时,您不仅考虑距离理想速度有多远——这是PID的比例部分——还考虑到您的车辆如何加速以及诸如坡道之类的条件。
对于从事工业控制的人来说,比例、积分、微分(PID)理论可能是一个熟悉的概念。对大多数人来说,这个术语完全陌生,但您可能比想象中更熟悉它。当您在汽车中踩油门踏板时,您不仅考虑距离理想速度有多远——这是PID的比例部分——还考虑到您的车辆如何加速以及诸如坡道之类的条件。
这些更为微妙的效果是I和D项在数学上考虑的。在这个示例中,它们会防止汽车的速度在上限和下限之间波动,并且我们可以将同样的概念应用于各种控制情况。虽然基于上限的控制可以大致到达目标区域,但您的系统会趋向于表现得有些不稳定。
PID方程
我们可以通过以下方程式用数学表达PID控制。P、I和D由这里相加的三个项表示。Kp、Ki和Kd是调整系统对每个因素反应的常数:
我们还可以分别将 Ki 和 Kd 替换为 1/Ti 和 Td。这种变化使方程与其物理意义有更好的关系,并使单位正确地转化为一个无单位的数值:
我们还可以变换方程以提取Kp值,并将其应用于整个方程,这就是标准形式。此形式的一个优点是可以一次调整整个方程的整体Kp常数:
所有这些看起来可能有点吓人,甚至对于一个拥有工程学位的人来说也是如此。好消息是,你不必翻出你的动态系统的建模与分析教科书来理解这里的内容。而且,尽管了解微积分从来不会有坏处,但你甚至不必能做微积分。
分解第一个方程式,我们在方程左侧得到 u(t)——无单位的控制器输出——通过在等号右侧加入三个数学元素:P、I 和 D。每个元素前面都有一个常数 K 值(Kp、Ki 和 Kd),这表示每个元素作为u(t)形成时的权重,或特定时间的控制输出。我们可以单独调整每个 K 值以提高系统性能,我们将在下面进一步解释:
比例(P—Kp)
这个方程式中的第一个也是最重要的项是 e(t)。因此,它之前的 Kp 值通常大于方程式中的其他 K 值。在这里,e(t) 只是某个时间点的即时误差——受控设备的实际值减去期望值。将这个结果乘以 Kp ,即可得出其对整体控制器输出的贡献。
积分(I—KI)
这个方程式中的第二项与时间相关的综合误差有关。它是设备所经历的所有误差的总和:
每次控制器计算 u(t) 时,它都会将瞬时误差加到一个累积总和中。
然后这个数值乘以 Ki 并加入到 u(t) 中。
考虑一种情况,一种力将电机固定在原位,并阻止其在正常条件下返回设定点。随着其超出规格的时间越来越长,I 项将继续增加,最终克服这种力或达到电机能力的极限。
微分(D—Kd)
这个方程中的第三项与误差变化的速度有关:
理论上,如果你在这个方程中只有一个 D 项,并且你的过程持续保持错误的值,这项将保持为零,并不会对正确的输出做出贡献。另一方面,如果另外两个项之一试图让设备的输出过快地恢复到位,微分可以帮助缓解这一效果。
虽然基于微积分的这个概念表达可能很有用,但PID控制的现实情况要比最初看起来的神奇简单得多。从实际角度来看,我们只使用加法、减法和乘法来计算输出,考虑到误差以及读数之间的时间。事实上,我们使用气动系统来实现早期形式的PID控制,通过机械手段输入每个“项”。
- 控制器读取瞬时误差。
- 从中减去之前的瞬时读数。
- 将所得值乘以 Kd 来计算其对 u(t) 的贡献。
Arduino PID控制器教程
在许多情况下,将一个专用的 PID 控制器直接接入你的系统是比较方便的,但你也可以使用 Arduino 或类似的开发板自行实现。你甚至可以编写你自己的 PID 算法。在代码中,可以按照如下方式表示各个项:
- P:instanteneousError = setpoint – input;
- I:cumulativeError += error * elapsedTime;
- D:rateOfError = (error – errorLastCalculation) / elapsedTime
要获得所需的输出,将每一项分别乘以对应的 K 值,然后将它们相加即可。另一方面,如果你不想重复造轮子,可以直接使用Brett Beuregard 的 PID 库。这个库会帮你处理底层细节,让你可以专注于根据需要调节 P、I 和 D 的常数值。
为了展示PID理论的实际应用,我从工具箱中拿出了一个Arduino Nano Every,以及:
- 电机驱动板
- 红外传感器
- 从Hubsan H107C无人机拆下的电机
值得注意的代码片段包括使用中断例程注册每个脉冲,因为阻塞设备旋转,并使用 millis() 计算脉冲之间的时间。我在代码的第一部分中,在函数外设置了 PID,如下:
PID myPID (&difference, &driverOut, &setPoint,Kp,Ki,Kd, DIRECT)
Kp、Ki 和 Kd在代码中的这行之前定义,&difference 控制 &driverOut,其中 &setPoint 由串行监视器修改。我们可以操作这个数学运算,将时间差转换为 RPM,但因为这个特定的驱动器在输入被拉低时启动,PID 设置以 DIRECT 输出的形式工作。随着模拟输出升高(电机关闭),脉冲之间的延迟也会增加。
PID例程的早期版本。注意CH1读取输入脉冲,而CH2则通过PID例程计算输出—低脉冲是电机的输入。
这个简单的PID控制器示例是由手头的部件驱动的(包括新的Arduino Nano Every)和一个我稍微熟悉的电机。但我能够展示如何在各种情况下应用PID控制,即使没有所有的事实。不论是电机控制、烤箱的温度控制,还是平衡机器人,只需一点点PID设置和调试,就能给你无限的实验选择。
文章标签