Arduino PID 控制教程
Arduino PID 控制教程
PID控制是工业自动化领域中一种非常重要的控制策略,广泛应用于各种需要精确控制的场景。本文将详细介绍PID控制的基本原理,并通过具体的Arduino代码示例,帮助读者掌握如何在实际项目中应用PID控制。
什么是PID?
PID是比例(Proportional)、积分(Integral)和微分(Derivative)的缩写。这种控制器仅用于反馈系统。反馈系统是指将输出“反馈”到输入。例如,您可以有一个控制炉火的项目。
比例控制
比例控制是指与误差成比例的调节。如果误差较小,阀门将释放少量燃料,以使设定点和反馈匹配。如果误差较大,阀门必须释放更多燃料。
积分控制
积分控制器可以消除这种偏移,并将累计的误差恢复为零。这种控制器会根据随时间累积的误差进行调整。如果没有积分控制,系统就无法处理误差趋势。
微分控制
微分控制处理误差的变化率。如果积分控制关注误差的历史,那么微分控制则预测误差。基本上,校正量将基于误差变化的速度。这种类型的控制器最适合处理比例和积分控制器都无法处理的动态误差。
带有 PID 控制器的反馈系统:
这里的输入变量或设定点是r(t),输出变量是y(t),受控变量是u(t),误差是e(t)。继续使用我们的熔炉示例,r(t) 是期望温度,y(t) 是实际温度;e(t) 是期望温度和实际温度之间的差值;u(t) 是 P、I 和 D 控制器的校正值之和,这些校正值被馈送到设备,即燃料阀。
在代码中实现 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);
}