zoukankan      html  css  js  c++  java
  • 改进初学者的PID-手自动切换

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

    1、问题所在

      有一个 PID 控制器虽然是很好的,但你并不是什么时候都需要它。

     

      假设在程序中的某个时刻,您希望将输出强制为某个值 (例如 0),您当然可以在调用例程中执行此操作:

    1 void loop()
    2 {
    3   Compute();
    4   Output=0;
    5 }

      这样,无论 PID 输出是什么,您只需覆盖其值。然而,这在实践中是一个可怕的想法。PID 会变得非常混乱:“我一直发送输出,但是什么都没有发生!到底发生了什么事? !我再发送一下。”因此,当您停止覆盖输出并切换回 PID 时,您可能会立即得到一个巨大的输出值改变。

    2、解决方案

      解决这个问题的办法是有办法关闭和打开 PID。这些状态的常用术语是 "手动" (我将手动调整输出值) 和 "自动" (PID 将自动调整输出)。让我们看看这是如何在代码中完成的。

    3、代码

     1 /*working variables*/
     2 unsigned long lastTime;
     3 double Input,Output,Setpoint;
     4 double ITerm,lastInput;
     5 double kp,ki,kd;
     6 int SampleTime = 1000; //1 sec
     7 double outMin,outMax;
     8 bool inAuto = false;
     9  
    10 #define MANUAL 0
    11 #define AUTOMATIC 1
    12  
    13 void Compute()
    14 {
    15    if(!inAuto) return;
    16    unsigned long now = millis();
    17    int timeChange = (now - lastTime);
    18    if(timeChange>=SampleTime)
    19    {
    20       /*Compute all the working error variables*/
    21       double error = Setpoint - Input;
    22       ITerm+= (ki * error);
    23       if(ITerm> outMax) ITerm= outMax;
    24       else if(ITerm< outMin) ITerm= outMin;
    25       double dInput = (Input - lastInput);
    26  
    27       /*Compute PID Output*/
    28       Output = kp * error + ITerm- kd * dInput;
    29       if(Output > outMax) Output = outMax;
    30       else if(Output < outMin) Output = outMin;
    31  
    32       /*Remember some variables for next time*/
    33       lastInput = Input;
    34       lastTime = now;
    35    }
    36 }
    37  
    38 void SetTunings(double Kp,double Ki,double Kd)
    39 {
    40   double SampleTimeInSec = ((double)SampleTime)/1000;
    41    kp = Kp;
    42    ki = Ki * SampleTimeInSec;
    43    kd = Kd / SampleTimeInSec;
    44 }
    45  
    46 void SetSampleTime(int NewSampleTime)
    47 {
    48    if (NewSampleTime > 0)
    49    {
    50       double ratio  = (double)NewSampleTime
    51                       / (double)SampleTime;
    52       ki *= ratio;
    53       kd /= ratio;
    54       SampleTime = (unsigned long)NewSampleTime;
    55    }
    56 }
    57  
    58 void SetOutputLimits(double Min,double Max)
    59 {
    60    if(Min > Max) return;
    61    outMin = Min;
    62    outMax = Max;
    63    
    64    if(Output > outMax) Output = outMax;
    65    else if(Output < outMin) Output = outMin;
    66  
    67    if(ITerm> outMax) ITerm= outMax;
    68    else if(ITerm< outMin) ITerm= outMin;
    69 }
    70  
    71 void SetMode(int Mode)
    72 {
    73   inAuto = (Mode == AUTOMATIC);
    74 }

      一个相当简单的解决方案。如果您不在自动模式下,请立即离开计算函数,而不调整 "输出" 或任何内部变量。

    4、最终结果

     

      的确,您可以通过不象例程那样调用计算来实现类似的效果,但此解决方案保持PID所包含的工作原理,这是我们所需要的。通过保持事物的内部过程,我们可以跟踪处于哪种模式中,更重要的是,当我们改变模式时,它让我们知道有哪些工作需要进行。这就引出了下一期.....。

    欢迎关注:

  • 相关阅读:
    buildroot编译文件系统,出现mount: you must be root. can't open /dev/console: Permission denied这种错误。
    Ubuntu 18.04实现实时显示网速
    git 第一次push 出现fatal: 无法读取远程仓库。
    Sql2012 AlwaysOn
    SCVMM 安装
    POJ 3537 Crosses and Crosses
    HDOJ 1524 A Chess Game
    HDOJ 1907 John
    HDOJ 1848 Fibonacci again and again
    HDOJ 1536 S-Nim
  • 原文地址:https://www.cnblogs.com/foxclever/p/11371375.html
Copyright © 2011-2022 走看看