středa 28. ledna 2015

PID regulátor

PID regulátor


Co je PID regulátor si můžete přečíst např. na Wikipedii. Pokud i po přečtení nebudete tušit, co PID je, zkusím napsat příklad trochu více lidsky:

P znamená proporcionální, I integrální a D derivační. Regulátor znamená, že něco reguluje, nejčastěji teplotu.
Takže stručně, jasně a zjednodušeně, jde o to, že máme například podlahové topení v domě a chceme PID regulátorem regulovat teplotu podlahy. PID proto, že nabízí nejlepší možnost regulování oproti P, PD nebo PI regulátorům.
Vždy potřebujeme spočítat chybu, resp. chyby. A nejlépe je, když je počítáme ve všech složkách (P, D a I).


P


P značí rozdíl mezi vstupní hodnotou a nastavenou požadovanou hodnotou

Pe = setpoint - input
Pout = Kp * E Kp je vlastně velikost chyby Kp = E


kde Pe - proporcionální chyba, setpoint - nastavená požadovaná hodnota, input - vstupní hodnota, Pout - velikost chyby, Kp - zesílení chyby, E - aktuální chyba

I


I značí integrál, neboli plochu pod křivkou. Je to vlastně chyba s časem. 

Ie = (ΣE + E) * t
Iout = Ki * ΣE Ki je vlastně plocha pod křivkou Ki = E * t



kde Ie - integrační chyba, ΣE je součet (suma) chyb předchozích, E - aktuální chyba, t - čas, Iout - velikost integrační chyby, Ki - zesílení integrační chyby

D


D značí derivaci, což je sklon křivky neboli změna chyby
De = (E - Elast) / t = (In - Inlast) / t
Dout = Kd * De Kd je vlastně sklon křivky Kd = E / t

kde De - derivační chyba, E - aktuální chyba, Elast - poslední známá chyba, t - čas, In - vstupní hodnota, Inlast - poslední známá vstupní hodnota, Dout - velikost derivační chyby, Kd - zesílení derivační chyby


Celkovou chybu spočítáme jako sumaci všech chyb:

OUT = Pout + Iout + Dout



Příklad 1 pro Walduino: (chybu určíme například 0.5)

// setup

t = 1000 ;                             // čas nastavíme na sekunduKp = 0.5;                              
Ki =  0.5 * t;                
Kd = 0.5 / t;                


// loop                                // smyčka vykonávající regulaci

nyni = millis(); // funkce millis vrací hodnotu v ms od spuštění programuzmena = (nyni – posledni);
if (zmena >= time change)
{   error = Setpoint – Input;                                      // výpočet E, neboli chyby
   errorsum = errorsum + error;   Derror = (Input – lastinput);
   Pout = Kp * error;                                              // jednotlivé chyby
   Iout = Ki * errorsum ;   Dout = Kd * Derror ;
   Output = Pout + Iout + Dout ;                                   // výsledná chyba
}
posledni = nyni;



Příklad 2 pro Walduino: (Trimr 200k (1GND, 2-A0, 3-PWM3), C 680uF (1-GND, 2-R), R 100R (1-C, 2-PWM3))


float Kp = .5 , Ki = .5, Kd = .5 ; // PID gain values
float Pout , Iout , Dout , OutputP, OutputI, OutputD, Output; // PID final ouput variables
float now , lasttime = 0 , timechange; // important time
float Input , lastinput , Setpoint = 127.0; // input-based variables
float error , errorsum = 0, Derror; // output of the PID components
int settime = 1000; // this = 1 second, so Ki and Kd do not need modification
void setup () {
  Serial.begin(9600); // serial setup for verification
  pinMode(3, OUTPUT);
} // end void setup (){
void loop () {
  now = millis() ; // get current milliseconds
  timechange = (now - lasttime); // calculate difference
  if (timechange >= settime) { // run PID when the time is at the set time
    Input = (analogRead(0) / 4.0); // read Input and normalize to output range
    error = Setpoint - Input; // calculate error
    errorsum = errorsum + error; // add curent error to running total of error
    Derror = (Input - lastinput); // calculate slope of the input
    Pout = Kp * error; // calculate PID gains
    Iout = Ki * errorsum ;
    Dout = Kd * Derror ;
    if (Iout > 255) // check for integral windup and correct
      Iout = 255;
    if (Iout < 0)
      Iout = 0;
    OutputP = Pout;
    OutputI = Iout;
    OutputD = Dout;
    Output = Pout + Iout + Dout ; // prep the output variable
    //Output = Pout; // prep the output variable
    if (Output > 255) // sanity check of the output, keeping it within the
      Output = 255; // available output range
    if (Output < 0)
      Output = 0;

    if (OutputP > 255) // sanity check of the output, keeping it within the
      OutputP = 255; // available output range
    if (OutputP < 0)
      OutputP = 0;

    if (OutputI > 255) // sanity check of the output, keeping it within the
      OutputI = 255; // available output range
    if (OutputI < 0)
      OutputI = 0;

    if (OutputD > 255) // sanity check of the output, keeping it within the
      OutputD = 255; // available output range
    if (OutputD < 0)
      OutputD = 0;

    lastinput = Input; // save the input and time for the next loop
    lasttime = now;
    analogWrite (3, Output); // write the output to PWM pin 3


    Serial.print ("Setpoint=");
    if (Setpoint < 100) Serial.print ("0");
    Serial.print (Setpoint); // print some information to the serial monitor
    Serial.print (" : ");
    Serial.print ("Input=");
    if (Input < 10) Serial.print ("0");
    if (Input < 100) Serial.print ("0");
    Serial.print (Input);
    Serial.print (" : ");
    Serial.print ("Output=");
    if (Output < 10) Serial.print ("0");
    if (Output < 100) Serial.print ("0");
    Serial.print (Output);
    Serial.print (" : ");
    Serial.print ("OutputP=");
    if (OutputP < 10) Serial.print ("0");
    if (OutputP < 100) Serial.print ("0");
    Serial.print (OutputP);
    Serial.print (" : ");
    Serial.print ("OutputI=");
    if (OutputI < 10) Serial.print ("0");
    if (OutputI < 100) Serial.print ("0");
    Serial.print (OutputI);
    Serial.print (" : ");
    Serial.print ("OutputD=");
    if (OutputD < 10) Serial.print ("0");
    if (OutputD < 100) Serial.print ("0");
    Serial.println (OutputD);

  } // end if (timechange >= settime)
} // end void loop ()

Popisovat program patrně nemá význam vzhledem k množství komentářů, které jsou v programu. Výsledkem je regulace PID regulátorem dle zadaného Setpointu a Vstupní veličiny.

Příklad 3 pro Walduino (využívá knihovnu PID_v1 a byl převzat z Arduino.cc)

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

#include <PID_v1.h>

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

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

void setup()
{
  Serial.begin(9600); // serial setup for verification
  //initialize the variables we're linked to
  Input = analogRead(0);

  Setpoint = 100;

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

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

  Serial.print ("Input=");
       if (Input < 10) Serial.print ("0");
     if (Input < 100) Serial.print ("0");  
  Serial.print (Input);
  Serial.print (" : ");
  
  myPID.Compute();
  analogWrite(3,Output);
  
  Serial.print ("Output=");
       if (Output < 10) Serial.print ("0");
     if (Output < 100) Serial.print ("0");  
  Serial.print (Output);
  Serial.println (" : ");
  delay(100);
  
}

Program funguje stejně jako výše popsaný.

Žádné komentáře:

Okomentovat