手把手教你看懂并理解Arduino PID控制库——初始化

引子

本文将分析《手把手教你看懂并理解Arduino PID控制库》中:初始化的问题

问题定义

先看问题的图示:

上一节,讨论的是PID控制由开转关的过程中存在的问题,那么紧接着上一节,如果在关闭后,突然再次开启,那么会产生什么问题呢?直观来看,对于被控量会出现图中,绿色线的一个bump,这个bump是由于由关转开的一瞬间,输出突然放大,那么对于灵敏度高的系统,则会出现,滞后大的系统可能不会如此明显,但不管怎么说,为了杜绝一切不利因素,我们都应该想办法消除这个bump。由于这个bump的根因是由于输出的突变而造成的,所以需要想办法控制这个输出的突变。

解决方案

想一想,所有此类问题都是发生在时间轴上的,那么PID控制中时间轴会影响的项只有积分项和微分项(可以想象,比例向为Kp * (设定值 - 被控量),这是一个连续量,不存在突变的可能(除非是采样时间特别长,在改变输出前,被控量飞上天了),所以只需要从这两项上想办法,控制住这两项的突变,即可控制住输出的突变。首先问题发生在PID关闭转开启的过程中,由于PID开启关闭控制的函数是SetMode,所以在此函数中,增加一个initial函数用于控制积分项和微分项即可。具体做法是:

1、更新微分项上一次采样值为PID开启一瞬间的采样值,这样可以保持微分项维持在上一次开启结束的状态不变。

2、将积分项设置为当前的输出,为什么要这么做呢?积分项由于PID关闭长时间维持关闭前的状态,一旦开启,如果不改变积分项,输出会瞬间被拉回到上一次开启结束的状态,突变就这样产生了

代码

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double ITerm, lastInput;
double kp, ki, kd;
int SampleTime = 1000; //1 sec
double outMin, outMax;
bool inAuto = false;
 
#define MANUAL 0
#define AUTOMATIC 1
 
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 Kp, double Ki, double Kd)
{
  double SampleTimeInSec = ((double)SampleTime)/1000;
   kp = Kp;
   ki = Ki * SampleTimeInSec;
   kd = Kd / SampleTimeInSec;
}
 
void SetSampleTime(int NewSampleTime)
{
   if (NewSampleTime > 0)
   {
      double ratio  = (double)NewSampleTime
                      / (double)SampleTime;
      ki *= ratio;
      kd /= ratio;
      SampleTime = (unsigned long)NewSampleTime;
   }
}
 
void SetOutputLimits(double Min, double 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;
}

结论

图片说明一切。。。。。

NOTE:如有不足之处请告知。^.^

下一章将介绍如果在系统运行过程中,控制方向对系统的影响

NEXT

PS:转载请注明出处:欧阳天华

猜你喜欢

转载自my.oschina.net/u/3162997/blog/827570