形象解释PID算法

形象解释PID算法+PID算法源代码

小明接到这样一个任务:

有一个水缸点漏水(而且漏水的速度还不一定固定不变),要求水面高度维持在某个位置,一旦发现水面高度低于要求位置,就要往水缸里加水。

小明接到任务后就一直守在水缸旁边,时间长就觉得无聊,就跑到房里看小说了,每30分钟来检查一次水面高度。水漏得太快,
每次小明来检查时,水都快漏完了,离要求的高度相差很远,小明改为每3分钟来检查一次,结果每次来水都没怎么漏,不需要加水,来得太频繁做的是无用功。
几次试验后,确定每10分钟来检查一次。这个检查时间就称为采样周期。

开始小明用瓢加水,水龙头离水缸有十几米的距离,经常要跑好几趟才加够水,于是小明又改为用桶加,一加就是一桶,跑的次数少了,加水的速度也快了,
但好几次将缸给加溢出了,不小心弄湿了几次鞋,小明又动脑筋,我不用瓢也不用桶,老子用盆,几次下来,
发现刚刚好,不用跑太多次,也不会让水溢出。这个加水工具的大小就称为比例系数。

小明又发现水虽然不会加过量溢出了,有时会高过要求位置比较多,还是有打湿鞋的危险。他又想了个办法,在水缸上装一个漏斗,
每次加水不直接倒进水缸,而是倒进漏斗让它慢慢加。这样溢出的问题解决了,但加水的速度又慢了,有时还赶不上漏水的速度。
于是他试着变换不同大小口径的漏斗来控制加水的速度,最后终于找到了满意的漏斗。漏斗的时间就称为积分时间 。

小明终于喘了一口,但任务的要求突然严了,水位控制的及时性要求大大提高,一旦水位过低,必须立即将水加到要求位置,而且不能高出太多,否则不给工钱。
小明又为难了!于是他又开努脑筋,终于让它想到一个办法,常放一盆备用水在旁边,一发现水位低了,不经过漏斗就是一盆水下去,这样及时性是保证了,但水位有时会高多了。
他又在要求水面位置上面一点将水凿一孔,再接一根管子到下面的备用桶里这样多出的水会从上面的孔里漏出来。这个水漏出的快慢就称为微分时间。

拿一个水池水位来说,我们 可以制定一个规则,
把水位分为超高、高、较高、中、较低、低、超低几个区段;
再把水位波动的趋势分为甚快、快、较快、慢、停几个区段,并区分趋势的正负;
把输出分为超大幅 度、大幅度、较大幅度、微小几个区段。

当水位处于中值、趋势处于停顿的时候,不调节;
当水位处于中值、趋势缓慢变化的时候,也可以暂不调节;
当水位处于较高、趋势缓慢变化 的时候,输出一个微小调节两就够了;
当水位处于中值、趋势较快变化的时候,输出进行叫 大幅度调节……。

如上所述,我们需要制定一个控制规则表,然后制定参数判断水位区段的界值、波动趋 势的界值、输出幅度的界值。

PID算法的解释-转自老外的博客

博客地址:
http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

源文件下载地址:
http://www.arduino.cc/playground/Code/PIDLibrary

DOWNLOAD

PID Library

PID Front-End using Processing.org

  • Latest version: v0.3

Older Versions can be viewed / downloaded here

THE BASICS

What Is PID?

From Wikipedia: "A PID controller calculates an ‘error‘ value as the difference between a measured [Input] and a desired setpoint. The controller attempts to minimize the error by adjusting [an Output]."

So, you tell the PID what to measure (the "Input",) Where you want that measurement to be (the "Setpoint",) and the variable to adjust that can make that happen (the "Output".) The PID then adjusts the output trying to make the input equal the setpoint.

For reference, in a car, the Input, Setpoint, and Output would be the speed, desired speed, and gas pedal angle respectively.

Tuning Parameters

The black magic of PID comes in when we talk about HOW it adjusts the Output to drive the Input towards Setpoint. There are 3 Tuning Parameters (or "Tunings"): Kp, Ki & Kd. Adjusting these values will change the way the output is adjusted. Fast? Slow? God-awful? All of these can be achieved depending on the values of Kp, Ki, and Kd.

So what are the "right" tuning values to use? There isn‘t one right answer. The values that work for one application may not work for another, just as the driving style that works for a truck may not work for a race car. With each new application you will need to try Several Tuning values until you find a set that gives you what you want.

Note: there is also now a PID Autotune Library that can help you determine tuning parameters.

Should I Use PID?

PID is a pretty impressive control algorithm, but it‘s not magic. You should at least be able to answer "yes" to these questions:

  • Is it worth the extra work? If you‘re using a more basic system and it‘s working for you, there‘s no real reason to use PID.
  • Is your system repeatable? The PID needs some semblance of repeatability. When the output is changed from A to B, at least roughly the same thing should happen every time. (think of a car where you step on the gas and sometimes you speed up and sometimes you slow down. not repeatable, not a place where you could use PID)

(This list will probably grow as I think of more criteria. These are the big ones though)

A Note About Relays

Even though a PID controller is designed to work with an analog output, it is possible to connect to a discrete output such as a relay. Be sure to look at the RelayOutput example below.

Questions?

Try the newly created Google group.

The Library

Using The PID Library has two benefits in my mind

  1. There are many ways to write the PID algorithm. A lot of time was spent making the algorithm in this library as solid as any found in industry. If you want to read more about this, check out this detailed explanation.
  2. When using the library all the PID code is self-contained. This makes your code easier to understand. It also lets you do more complex stuff, like say having 8 PIDs in the same program.

Functions

PID()

Compute()

SetMode()

SetOutputLimits()

SetTunings()

SetSampleTime()

SetControllerDirection()

Display Functions

Examples

Basic

RelayOutput

AdaptiveTunings

***************************************************************
* Arduino PID Library - Version 1.1.1
* by Brett Beauregard <[email protected]> brettbeauregard.com
*
* This Library is licensed under a GPLv3 License
***************************************************************

- For an ultra-detailed explanation of why the code is the way it is, please visit:
http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/

- For function documentation see: http://playground.arduino.cc/Code/PIDLibrary

#ifndef PID_v1_h
#define PID_v1_h
#define LIBRARY_VERSION    1.1.1

class PID
{

  public:

  //Constants used in some of the functions below
  #define AUTOMATIC    1
  #define MANUAL    0
  #define DIRECT  0
  #define REVERSE  1

  //commonly used functions **************************************************************************
    PID(double*, double*, double*,        // * constructor.  links the PID to the Input, Output, and
        double, double, double, int);     //   Setpoint.  Initial tuning parameters are also set here

    void SetMode(int Mode);               // * sets PID to either Manual (0) or Auto (non-0)

    bool Compute();                       // * performs the PID calculation.  it should be
                                          //   called every time loop() cycles. ON/OFF and
                                          //   calculation frequency can be set using SetMode
                                          //   SetSampleTime respectively

    void SetOutputLimits(double, double); //clamps the output to a specific range. 0-255 by default, but
                                          //it‘s likely the user will want to change this depending on
                                          //the application

  //available but not commonly used functions ********************************************************
    void SetTunings(double, double,       // * While most users will set the tunings once in the
                    double);               //   constructor, this function gives the user the option
                                          //   of changing tunings during runtime for Adaptive control
    void SetControllerDirection(int);      // * Sets the Direction, or "Action" of the controller. DIRECT
                                          //   means the output will increase when error is positive. REVERSE
                                          //   means the opposite.  it‘s very unlikely that this will be needed
                                          //   once it is set in the constructor.
    void SetSampleTime(int);              // * sets the frequency, in Milliseconds, with which
                                          //   the PID calculation is performed.  default is 100

  //Display functions ****************************************************************
    double GetKp();                          // These functions query the pid for interal values.
    double GetKi();                          //  they were created mainly for the pid front-end,
    double GetKd();                          // where it‘s important to know what is actually
    int GetMode();                          //  inside the PID.
    int GetDirection();                      //

  private:
    void Initialize();

    double dispKp;                // * we‘ll hold on to the tuning parameters in user-entered
    double dispKi;                //   format for display purposes
    double dispKd;                //

    double kp;                  // * (P)roportional Tuning Parameter
    double ki;                  // * (I)ntegral Tuning Parameter
    double kd;                  // * (D)erivative Tuning Parameter

    int controllerDirection;

    double *myInput;              // * Pointers to the Input, Output, and Setpoint variables
    double *myOutput;             //   This creates a hard link between the variables and the
    double *mySetpoint;           //   PID, freeing the user from having to constantly tell us
                                  //   what these values are.  with pointers we‘ll just know.

    unsigned long lastTime;
    double ITerm, lastInput;

    unsigned long SampleTime;
    double outMin, outMax;
    bool inAuto;
};
#endif
/**********************************************************************************************
 * Arduino PID Library - Version 1.1.1
 * by Brett Beauregard <[email protected]> brettbeauregard.com
 *
 * This Library is licensed under a GPLv3 License
 **********************************************************************************************/

#if ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#include <PID_v1.h>

/*Constructor (...)*********************************************************
 *    The parameters specified here are those for for which we can‘t set up
 *    reliable defaults, so we need to have the user set them.
 ***************************************************************************/
PID::PID(double* Input, double* Output, double* Setpoint,
        double Kp, double Ki, double Kd, int ControllerDirection)
{

    myOutput = Output;
    myInput = Input;
    mySetpoint = Setpoint;
    inAuto = false;

    PID::SetOutputLimits(0, 255);                //default output limit corresponds to
                                                //the arduino pwm limits

    SampleTime = 100;                            //default Controller Sample Time is 0.1 seconds

    PID::SetControllerDirection(ControllerDirection);
    PID::SetTunings(Kp, Ki, Kd);

    lastTime = millis()-SampleTime;
}

/* Compute() **********************************************************************
 *     This, as they say, is where the magic happens.  this function should be called
 *   every time "void loop()" executes.  the function will decide for itself whether a new
 *   pid Output needs to be computed.  returns true when the output is computed,
 *   false when nothing has been done.
 **********************************************************************************/
bool PID::Compute()
{
   if(!inAuto) return false;
   unsigned long now = millis();
   unsigned long timeChange = (now - lastTime);
   if(timeChange>=SampleTime)
   {
      /*Compute all the working error variables*/
      double input = *myInput;
      double error = *mySetpoint - input;
      ITerm+= (ki * error);
      if(ITerm > outMax) ITerm= outMax;
      else if(ITerm < outMin) ITerm= outMin;
      double dInput = (input - lastInput);

      /*Compute PID Output*/
      double output = kp * error + ITerm- kd * dInput;

      if(output > outMax) output = outMax;
      else if(output < outMin) output = outMin;
      *myOutput = output;

      /*Remember some variables for next time*/
      lastInput = input;
      lastTime = now;
      return true;
   }
   else return false;
}

/* SetTunings(...)*************************************************************
 * This function allows the controller‘s dynamic performance to be adjusted.
 * it‘s called automatically from the constructor, but tunings can also
 * be adjusted on the fly during normal operation
 ******************************************************************************/
void PID::SetTunings(double Kp, double Ki, double Kd)
{
   if (Kp<0 || Ki<0 || Kd<0) return;

   dispKp = Kp; dispKi = Ki; dispKd = Kd;

   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);
   }
}

/* SetSampleTime(...) *********************************************************
 * sets the period, in Milliseconds, at which the calculation is performed
 ******************************************************************************/
void PID::SetSampleTime(int NewSampleTime)
{
   if (NewSampleTime > 0)
   {
      double ratio  = (double)NewSampleTime
                      / (double)SampleTime;
      ki *= ratio;
      kd /= ratio;
      SampleTime = (unsigned long)NewSampleTime;
   }
}

/* SetOutputLimits(...)****************************************************
 *     This function will be used far more often than SetInputLimits.  while
 *  the input to the controller will generally be in the 0-1023 range (which is
 *  the default already,)  the output will be a little different.  maybe they‘ll
 *  be doing a time window and will need 0-8000 or something.  or maybe they‘ll
 *  want to clamp it from 0-125.  who knows.  at any rate, that can all be done
 *  here.
 **************************************************************************/
void PID::SetOutputLimits(double Min, double Max)
{
   if(Min >= Max) return;
   outMin = Min;
   outMax = Max;

   if(inAuto)
   {
       if(*myOutput > outMax) *myOutput = outMax;
       else if(*myOutput < outMin) *myOutput = outMin;

       if(ITerm > outMax) ITerm= outMax;
       else if(ITerm < outMin) ITerm= outMin;
   }
}

/* SetMode(...)****************************************************************
 * Allows the controller Mode to be set to manual (0) or Automatic (non-zero)
 * when the transition from manual to auto occurs, the controller is
 * automatically initialized
 ******************************************************************************/
void PID::SetMode(int Mode)
{
    bool newAuto = (Mode == AUTOMATIC);
    if(newAuto == !inAuto)
    {  /*we just went from manual to auto*/
        PID::Initialize();
    }
    inAuto = newAuto;
}

/* Initialize()****************************************************************
 *    does all the things that need to happen to ensure a bumpless transfer
 *  from manual to automatic mode.
 ******************************************************************************/
void PID::Initialize()
{
   ITerm = *myOutput;
   lastInput = *myInput;
   if(ITerm > outMax) ITerm = outMax;
   else if(ITerm < outMin) ITerm = outMin;
}

/* SetControllerDirection(...)*************************************************
 * The PID will either be connected to a DIRECT acting process (+Output leads
 * to +Input) or a REVERSE acting process(+Output leads to -Input.)  we need to
 * know which one, because otherwise we may increase the output when we should
 * be decreasing.  This is called from the constructor.
 ******************************************************************************/
void PID::SetControllerDirection(int Direction)
{
   if(inAuto && Direction !=controllerDirection)
   {
      kp = (0 - kp);
      ki = (0 - ki);
      kd = (0 - kd);
   }
   controllerDirection = Direction;
}

/* Status Funcions*************************************************************
 * Just because you set the Kp=-1 doesn‘t mean it actually happened.  these
 * functions query the internal state of the PID.  they‘re here for display
 * purposes.  this are the functions the PID Front-end uses for example
 ******************************************************************************/
double PID::GetKp(){ return  dispKp; }
double PID::GetKi(){ return  dispKi;}
double PID::GetKd(){ return  dispKd;}
int PID::GetMode(){ return  inAuto ? AUTOMATIC : MANUAL;}
int PID::GetDirection(){ return controllerDirection;}

Example

/********************************************************
 * PID Basic Example
 * Reading analog input 0 to control analog PWM output 3
 ********************************************************/

#include <PID_v1.h>

#define PIN_INPUT 0
#define PIN_OUTPUT 3

//Define Variables we‘ll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup()
{
  //initialize the variables we‘re linked to
  Input = analogRead(PIN_INPUT);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(PIN_INPUT);
  myPID.Compute();
  analogWrite(PIN_OUTPUT, Output);
}
/********************************************************
 * PID Adaptive Tuning Example
 * One of the benefits of the PID library is that you can
 * change the tuning parameters at any time.  this can be
 * helpful if we want the controller to be agressive at some
 * times, and conservative at others.   in the example below
 * we set the controller to use Conservative Tuning Parameters
 * when we‘re near setpoint and more agressive Tuning
 * Parameters when we‘re farther away.
 ********************************************************/

#include <PID_v1.h>

#define PIN_INPUT 0
#define PIN_OUTPUT 3

//Define Variables we‘ll be connecting to
double Setpoint, Input, Output;

//Define the aggressive and conservative Tuning Parameters
double aggKp=4, aggKi=0.2, aggKd=1;
double consKp=1, consKi=0.05, consKd=0.25;

//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT);

void setup()
{
  //initialize the variables we‘re linked to
  Input = analogRead(PIN_INPUT);
  Setpoint = 100;

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(PIN_INPUT);

  double gap = abs(Setpoint-Input); //distance away from setpoint
  if (gap < 10)
  {  //we‘re close to setpoint, use conservative tuning parameters
    myPID.SetTunings(consKp, consKi, consKd);
  }
  else
  {
     //we‘re far from setpoint, use aggressive tuning parameters
     myPID.SetTunings(aggKp, aggKi, aggKd);
  }

  myPID.Compute();
  analogWrite(PIN_OUTPUT, Output);
}
/********************************************************
 * PID RelayOutput Example
 * Same as basic example, except that this time, the output
 * is going to a digital pin which (we presume) is controlling
 * a relay.  the pid is designed to Output an analog value,
 * but the relay can only be On/Off.
 *
 *   to connect them together we use "time proportioning
 * control"  it‘s essentially a really slow version of PWM.
 * first we decide on a window size (5000mS say.) we then
 * set the pid to adjust its output between 0 and that window
 * size.  lastly, we add some logic that translates the PID
 * output into "Relay On Time" with the remainder of the
 * window being "Relay Off Time"
 ********************************************************/

#include <PID_v1.h>

#define PIN_INPUT 0
#define RELAY_PIN 6

//Define Variables we‘ll be connecting to
double Setpoint, Input, Output;

//Specify the links and initial tuning parameters
double Kp=2, Ki=5, Kd=1;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

void setup()
{
  windowStartTime = millis();

  //initialize the variables we‘re linked to
  Setpoint = 100;

  //tell the PID to range between 0 and the full window size
  myPID.SetOutputLimits(0, WindowSize);

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
}

void loop()
{
  Input = analogRead(PIN_INPUT);
  myPID.Compute();

  /************************************************
   * turn the output pin on/off based on pid output
   ************************************************/
  if (millis() - windowStartTime > WindowSize)
  { //time to shift the Relay Window
    windowStartTime += WindowSize;
  }
  if (Output < millis() - windowStartTime) digitalWrite(RELAY_PIN, HIGH);
  else digitalWrite(RELAY_PIN, LOW);

}
时间: 2024-10-13 17:56:53

形象解释PID算法的相关文章

PID算法的含义及其应用,PID基础,适合不懂PID算法的人来看!

                    先插句广告,本人QQ522414928,不熟悉PID算法的可以一起交流学习,随时在线 在正式进入正文前,补充一下本人学习PID算法的背景,先自我介绍一下:本人一名大三电子专业的学生,什么学校你就别管了,学校一般,普通的二本院校.到现在可以说我已经研究了快两年的PID,这期间做过帆板角度控制系统,做过平衡车,做过倒立摆,做过板球控制系统,做过openmv小球追踪系统,还做过四旋翼等--,可以说现在已经很熟悉PID算法,包括单级的PID算法和多级的PID算法.

PID算法(C语言)

/************ PID算法(C语言) ************/ #include <stdio.h> #include<math.h> struct _pid { int pv; /*integer that contains the process value*/ int sp; /*integer that contains the set point*/ float integral; float pgain; float igain; float dgain;

PID 算法理解

PID 算法 使用环境:受到外界的影响不能按照理想状态发展.如小车的速度不稳定的调节,尽快达到目标速度. 条件:闭环系统->有反馈 要求:快准狠 分类:位置式.增量式 增量式 输入:前次速度.前前次速度.前前前次速度 输出:pwm的增加值或减少值 位置式 输入: 输出: 公式 或 Kp 比例放大系数     Ti  积分时间    Td 微分时间 Kp比例放大系数  Ki 积分系数  Kd 微分系数

小车PID算法跑直线

#include<stm32f10x.h> #include"sys.h" extern unsigned char Rec_Dat_U1; extern unsigned char Rec_String_U1[200]; extern int conut_flag_1; #define in_1(x)    x?GPIO_ResetBits(GPIOC , GPIO_Pin_0): GPIO_SetBits(GPIOC , GPIO_Pin_0) #define in_2

模糊PID控温算法的具体实现(一):参数自整定模糊PID算法概念

上个学期已经基本上实现了PID的温控算法,为了撰写小论文,这个学期最先要做的事情就是实现模糊PID的温控算法. 模糊控制系统的构成与与常规的反馈控制系统的主要区别在于控制器主要是由模糊化,模糊推理机和精确化三个功能模块和知识库(包括数据库和规则库)构成的.具体实现过程如下所示: (1)预处理: 输入数据往往是通过测量设备测量得到的一个具体数据,预处理就是在它们进入控制器前对这些数据进行分类,或性质程度的定义.预处理过程也是量化过程,它是在离散空间中把输入数据划分为若干个数字级别.例如,假设一个反

mwc飞控PID算法解析

0.说明 基于mwc2.3的pid算法解析,2.3中增加了一种新的pid算法,在此分别解析. P:比例 I:积分 D:微分 1.老版PID代码 代码大概在MultiWii.cpp的1350行上下. 1 if ( f.HORIZON_MODE ) prop = min(max(abs(rcCommand[PITCH]),abs(rcCommand[ROLL])),512); 2 3 // PITCH & ROLL 4 for(axis = 0; axis < 2; axis++) { 5 rc

线性控制原理——PID算法应用

使用控制系统(PID)控制被控对象 PID控制的三要素:控制器,被控对象,反馈器.控制器就是一个数学模型,就PID来说,等同于PID算法.是对反馈量的一个处理与输出.通俗的说就是对于每个被控的量,我的输出量通过什么函数式算出,或者说,我如何描述我的输出量.现在我给定一个描述性的传递函数.从数学角度来看:它的自变量是反馈值,当这个函数的对应关系确定了之后,输出量就是个定值了.我的希望是:这个描述函数是一个透明的空箱--它既能反映系统外部特性,又可以看到其内部结构. 就拿比赛来说:假设我现在要构建这

【sky第二期--PID算法】--【智能车论坛】

[sky第二期--PID算法] 想学PID的可以来[智能车论坛]这里有我发布的资料http://bbs.tekbots.eefocus.com/forum.php?mod=viewthread&tid=213301&fromuid=108990 欢迎交流

PID算法实现及参数整定图解(附代码)

一. PID含义 PID是英文单词比例(Proportion),积分(Integral),微分(Differential coefficient)的缩写.PID调节实际上是由比例.积分.微分三种调节方式组成,它们各自的作用如下: 比例调节作用:是按比例反应系统的偏差,系统一旦出现了偏差,比例调节立即产生调节作用用以减少偏差.比例作用大,可以加快调节,减少误差,但是过大的比例,使系统的稳定性下降,甚至造成系统的不稳定. 积分调节作用:是使系统消除稳态误差,提高无差度.因为有误差,积分调节就进行,直