改进初学者的PID-正反作用

匿名 (未验证) 提交于 2019-12-03 00:06:01

最近看到了Brett Beauregard发表的有关PID的系列文章,感觉对于理解PID算法很有帮助,于是将系列文章翻译过来!在自我提高的过程中,也希望对同道中人有所帮助。作者Brett Beauregard的原文网址:http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-direction/

 

1、问题所在

将PID连接过程分为两组:直接作用和反向作用。到目前为止,我所展示的所有例子都是直接行动。也就是说,输出的增加会导致输入的增加。对于反向作用过程,情况正好相反。例如,在冰箱中,冷却水的增加会导致温度下降。要使初学者 PID 使用反向过程,kp、ki 和 kp 的符号都必须为负数。

这本身不是问题,但用户必须选择正确的符号,并确保所有参数都具有相同的符号。

2、解决方案

为了让这个过程简单一点,我要求 kp、ki 和 kp 都是大于等于0的。如果用户连接到反向进程,则使用SetControllerDirection函数指定反向进程。这可以确保所有参数都具有相同的符号,并使事情操作起来更直观。

3、代码

/*working variables*/ unsigned long lastTime; double InputOutputSetpoint; double ITermlastInput; double kpkikd; int SampleTime = 1000;  //1 sec double outMinoutMax; bool inAuto = false;  #define MANUAL 0 #define AUTOMATIC 1  #define DIRECT 0 #define REVERSE 1 int controllerDirection = DIRECT;  void Compute() {    if(!inAuto) return;    unsigned long now = millis();    int timeChange = (now - lastTime);    if(timeChange>=SampleTime)    {       /*Compute all the working error variables*/       double error = Setpoint - Input;       ITerm+= (ki * error);       if(ITerm > outMax) ITerm= outMax;       else if(ITerm < outMin) ITerm= outMin;       double dInput = (Input - lastInput);        /*Compute PID Output*/       Output = kp * error + ITerm- kd * dInput;       if(Output > outMax) Output = outMax;       else if(Output < outMin) Output = outMin;        /*Remember some variables for next time*/       lastInput = Input;       lastTime = now;    } }  void SetTunings(double Kpdouble Kidouble Kd) {    if (Kp<0 || Ki<0|| Kd<0) return;     double SampleTimeInSec = ((double)SampleTime)/1000;    kp = Kp;    ki = Ki * SampleTimeInSec;    kd = Kd / SampleTimeInSec;     if(controllerDirection ==REVERSE)    {       kp = (0 - kp);       ki = (0 - ki);       kd = (0 - kd);    } }  void SetSampleTime(int NewSampleTime) {    if (NewSampleTime > 0)    {       double ratio  = (double)NewSampleTime/(double)SampleTime;       ki *= ratio;       kd /= ratio;       SampleTime = (unsigned long)NewSampleTime;    } }  void SetOutputLimits(double Mindouble Max) {    if(Min > Max) return;    outMin = Min;    outMax = Max;     if(Output > outMax) Output = outMax;    else if(Output < outMin) Output = outMin;     if(ITerm > outMax) ITerm= outMax;    else if(ITerm < outMin) ITerm= outMin; }  void SetMode(int Mode) {     bool newAuto = (Mode == AUTOMATIC);     if(newAuto == !inAuto)     {  /*we just went from manual to auto*/         Initialize();     }     inAuto = newAuto; }  void Initialize() {    lastInput = Input;    ITerm = Output;    if(ITerm > outMax) ITerm= outMax;    else if(ITerm < outMin) ITerm= outMin; }  void SetControllerDirection(int Direction) {    controllerDirection = Direction; }

4PID 完成

差不多结束了。我们已经把“初学者的PID”变成了我目前知道的最健壮的控制器。对于那些正在寻找PID库的详细解释的读者,我希望您得到了您想要的。对于那些正在编写自己的PID的人,我希望您能够收集到一些想法,这些想法可以为您节省一些时间。

最后说明两点:

  1. 如果这个系列中的东西看起来不对,请告诉我。我可能错过了什么,或者可能只需要在我的解释中更清楚。无论哪种方式,我都想知道。
  2. 这只是一个基本的PID。为了简单起见,我有意省略了许多其他问题。在我的脑海中:前馈,重置平铺,整数数学,不同的PID形式,使用速度而不是位置。如果有兴趣让我探讨这些话题,请让我知道。

欢迎关注:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!