Arduino PID 控制教程
Arduino PID 控制教程
PID控制是工业自动化和机器人领域中一种非常重要的控制算法,广泛应用于各种需要精确控制的场景。本文将详细介绍PID控制的基本原理,并通过Arduino平台展示其具体实现方法,帮助读者掌握这一核心技术。
什么是PID?
如上所述,PID 是比例、积分和微分的缩写。这种控制器仅用于反馈系统。反馈系统是指将输出“反馈”到输入。例如,您可以有一个控制炉火的项目。下面是一个简单的例子:
您希望将炉内温度保持在某个设定点。炉内的温度传感器随时测定温度。在这种情况下,该传感器提供反馈,作为所需温度升高或降低的参考,温度传感器测量炉膛温度低于设定值将电子阀开大释放更多燃料从而提高炉膛温度,反之将电子阀关闭一部分,从而降低炉膛温度。
温度传感器反馈的值与温度设定点之间的差异就是误差。PID的功能就是消除这个误差。
比例控制
比例控制是指与误差成比例的调节。如果误差较小,阀门将释放少量燃料,以使设定点和反馈匹配。如果误差较大,阀门必须释放更多燃料。
积分控制
比例控制在校正过程中,不会正好消除所有的误差可能会多可能会少,从而每次校正后的误差会积累形成偏移。积分控制器可以消除这种偏移,并将累计的误差恢复为零。这种控制器会根据随时间累积的误差进行调整。如果没有积分控制,系统就无法处理误差趋势。
用我们之前的例子来说,当燃油阀在增加然后减少燃油输出时没有回到其原始位置时,可能存在偏移。积分控制器将检测到这种情况,并将燃油阀转到其原始位置。
导数控制
最后,微分控制处理误差的变化率。如果积分控制关注误差的历史,那么微分控制则预测误差。基本上,校正量将基于误差变化的速度。这种类型的控制器最适合处理比例和积分控制器都无法处理的动态误差。
例如炉膛内的温度在1秒内由120度上升到了130度和2秒内由120度上升到130度,误差发生速度就不同,微处理器需要及时处理这种情况。而比例和积分控制器将很难跟上误差发生的速度。微分控制器可以处理这种情况,因为它从一开始就一直在关注误差的变化率。
带有 PID 控制器的反馈系统:
这里的输入变量或设定点是r(t),输出变量是y(t),受控变量是u(t),误差是e(t)。继续使用我们的熔炉示例,r(t) 是期望温度,y(t) 是实际温度;e(t) 是期望温度和实际温度之间的差值;u(t) 是 P、I 和 D 控制器的校正值之和,这些校正值被馈送到设备,即燃料阀。
请注意,PID 控制器并非开箱即用。必须进行调整以确保达到所需性能。这可以通过仔细更改K 常数来实现,如上图所示。必须事先确定这些常数,并根据系统的实际响应进行更改,直到达到最佳值。
在代码中实现 PID
要在代码或arduino草图中实现 PID 控制器,必须知道五个参数:比例、积分和微分常数、输入值和设定点值。
PID 计算必须在循环函数内进行。函数的第一部分应该是确定经过的时间。在 Arduino 中,函数millis()返回自程序启动以来的时间(以毫秒为单位)。因此,经过的时间就是:
currentTime = millis();
elapsedTime = currentTime - previousTime;
接下来必须确定误差也就是设置值与输入值的差:
error = setPoint - input;
误差的积分是误差随时间的累积,使用Arduino 计算积分,我们只需执行以下操作:
cumError += error * elapsedTime;
误差的导数是误差的变化率也就是误差除以采样时间:
rateError = (error - lastError)/elapsedTime;
最后计算的输出为:
output = Kp * error + Ki * cumError + Kd * rateError;
这里,Kp、Ki、Kd是预先确定的常数。
最后,必须注意下一次迭代的变量:
lastError = error;//将误差存入上次误差变量中
previousTime = currentTime;
让我们尝试一个更具体的例子。想象一个车轮连接到一个马达上。我们希望车轮保持在所示的位置:
车轮上的旋转编码器以度为单位显示当前车轮位置的角度。在我们的目标车轮位置,角度为零。
我们想要的是,只要车轮偏离位置,电机就会转动。此外,电机是通过脉冲宽度调制来控制的。脉冲越宽,电机转动得越远。
接下来,让我们使用 Arduino 实现这个简单的控制系统。
PID 控制器 – Arduino 代码:
double kp = 2
double ki = 5
double kd = 1
unsigned long currentTime, previousTime;
double elapsedTime;
double error;
double lastError;
double input, output, setPoint;
double cumError, rateError;
void setup(){
setPoint = 0;
}
void loop(){
input = analogRead(A0);
output = computePID(input);
delay(100);
analogWrite(3, output); //control the motor based on PID value
}
double computePID(double inp){
currentTime = millis();
elapsedTime = (double)(currentTime - previousTime);
error = Setpoint - inp;
cumError += error * elapsedTime;
rateError = (error - lastError)/elapsedTime;
double out = kp*error + ki*cumError + kd*rateError; //PID output
lastError = error;
previousTime = currentTime;
return out;
}
在循环函数中,旋转编码器确定车轮的当前位置,其输出值成为computePID()函数的参数。此函数返回一个值,用于使用 PWM 控制电机。
PID Arduino 代码库
借助Brett Beauregard 的 PID 库,我们可以进一步简化在 Arduino 项目中使用 PID 的过程。该库仅要求您指定 kd、ki、kp 和设定值,就可以开始了!
这是库附带的PID_Basic.ino。
#include <PID_v1.h>
#define PIN_INPUT 0
#define PIN_OUTPUT 3
double Setpoint, Input, Output;
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void setup()
{
Input = analogRead(PIN_INPUT);
Setpoint = 100;
myPID.SetMode(AUTOMATIC);
}
void loop()
{
Input = analogRead(PIN_INPUT);
myPID.Compute();
analogWrite(PIN_OUTPUT, Output);
}