PID regulacija

PID regulacija

Regulacija je zaprtozančno vodenje procesa, ki na osnovi primerjave dejanske in želene regulirane veličine na proces vpliva tako, da je napaka čim manjša. Poznamo dva načina delovanja regulacij: sledilno in regulacijsko. Pri sledilnem mora regulacijski sistem zagotoviti, da regulirana veličina dobro sledi referenci, spremembi nastavitvene točke (npr. primerno odzivanje DC motorčka ob spremembah nastavitvene točke). Pri regulacijskem delovanju pa je pomembno predvsem to, da regulator učinkovito odpravlja motnje.

Slika 1: Potek referenčne U(t) in regulirane y(t) veličine pri sledilni regulaciji

Proporcionalno-integralno-diferencialna regulacija ali regulacija PID je najbolj razširjena metoda v procesni industriji. Regulacija je izvedena kot vsota proporcionalnega (P), integralnega (I) in diferencialnega (D) člena. Člen P je neposredno odvisen od trenutne velikosti napake, člen I je odvisen od integrala preteklih napak, člen D pa od hitrosti spreminjanja napake, s katerim lahko deloma predvidimo prihodnje delovanje sistema.

Slika 2: Blok shema regulacije PID

KP = proporcionalni prirastek

KI = integralni prirastek

KD = diferencialni prirastek

e(t) = napaka (error), ki predstavlja razliko med nastavitveno vrednostjo U(t) in vrednostjo procesa, y(t)

Spodnja enačba opisuje delovanje regulacije PID:

Regulator PID ima tri nastavljive parametre: ojačanje KP, integralno časovno konstanto TI in konstanto diferenciranja TD. Referenčno veličino predstavlja nastavitvena vrednost (Set point), to je vrednost, ki jo želimo v našem procesu.

Slika 3: Proporcionalno, integralno in diferencialno delovanje

Pri regulatorju PID delujejo vsi trije členi istočasno, zato je odziv regulacije na spremembo nastavitvene točke rezultanta vseh treh členov.

PID regulacija razsvetljave (svetilnosti LED diode)

Slika 4: Načrt priključitve elementov na Arduino Uno

Za regulacijo bomo uporabili Arduinovo PID krmilno knjižnico PID_v1.h. PID krmilnik kontinuirano izračunava vrednost napake kot razliko med želeno nastavljeno vrednostjo (Setpoint) in izmerjeno procesno vrednostjo (Input). PID krmilnik poskuša neprestano napake minimirati z uporabo kontrolnih spremenljivk Kp, Ki in Kd. Na osnovi želene vrednosti (Setpoint) krmili razsvetljavo LED diode tako, da je fotoupor vedno enako osvetljen. Če na primer v bližini vklopimo dodatno razsvetljavo, ki vpliva na osvetljenost fotoupora, se bo svetilnost LED diode ustrezno zmanjšala. LED dioda naj bo postavljena tik ob fotouporu, fotoupor naj bo prislonjen ob LED diodo (ne od spredaj).

Program:

/*

 * PID regilacija svetilnosti LED diode v odvisnosti od nastavitve Setpoint (Trimer potenciometer).

 * Avtor: Milan Ivič

 * Datum: marec 2016

 */

 #include <PID_v1.h>   //PID knjižnica.

 //Deklariranje spremenljivk:

 double Potenciometer = A0;         //Potenciometer za nastavitev Setpoint ja priključen na pin A0.

 double Setpoint, Input, Output;    //Spremenljivke za PID.

 

//PID parametri:

 double Kp=0.1, Ki=1.9, Kd=0.01;

 

 //Start PID:

 PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

 

 void setup()

 {

   Serial.begin(9600);     //Vključitev serijske komunikacije.  

    //Tukaj nastavljamo svetilnost LED diode.

    //Setpoint nastavljamo s potenciometrom (A0). Prestavimo v območje od 0 do 255.

   Setpoint = map(analogRead(A0), 0, 600, 0, 255);  

 

   myPID.SetMode(AUTOMATIC);       //Vklopimo PID regulacijo.  

   myPID.SetTunings(Kp, Ki, Kd);       //Nastavitve PID z našimi izbranimi parametri.

 

   TCCR2A = _BV(WGM21) | _BV(WGM20);    //Fast PWM. 

   TCCR2B = 0x01;                       //Preddelitev 1:1 => f = 62,5 kHz.

 }

 

 void loop()

 {

   //Setpoint nastavljamo s potenciometrom. Vhod A0 vsebuje 10 bitni AD pretvornik (0-1023).

   //Vrednost 600 je odvisna od svetlobe v prostoru. Območje od 0-600 prestavimo v območje 0-255.

   Setpoint = map(analogRead(A0), 0, 600, 0, 255);

 

   //Branje vrednosti na fotouporu. V območje 0-255 prestavimo zato, ker ima PWM na pinu 3 8-bitno vrednost.

   //PWM pin 3 pripada Timerju2 Arduino Uno.

   Input = map(analogRead(A2), 0, 600, 0, 255);

 

   //PID izračunavanje:

   myPID.Compute();

   //Izračunano vrednost PID funkcije zapišemo na pin 3:

   analogWrite(3,Output);

 

   Serial.print(Setpoint);   //Izpis na serijskem monitorju ali izris na grafu.

   Serial.print(" ");

   Serial.println(Input);    

 }

 

S potenciometrom, priključenim na analogni vhod A0, nastavljamo želeno osvetljitev (Setpoint), ki jo neprestano kontrolira fotoupor LDR. Napetost na fotouporu se spreminja v odvisnosti od svetlobe, saj je zaporedno z njim povezan upor vrednosti 3,3 kohm (napetostni delilnik).

Slika 5: Vezava fotoupora LDR

Izhod napetostega delilnika povežemo z analognim vhodom A2 razvojne plošče Arduino Uno. Ta, kot vsi analogni vhodi Arduino Uno, vsebuje 10-bitni analogno digitalni pretvornik (ločljivost od 0 do 1023).

Za obe stremenljivki, Setpoint in Input smo uporabili tip spremenljivke double. V spremenljivko tipa double lahko shranimo predznačno število z decimalno vejico, veliko 4 bajte (32-bitni register).

V glavni zanki void loop() neprestano beremo vrednost na analognem vhodu A0. To je želena vrednost (Setpoint), ki jo nastavljamo s potenciometrom. V odvisnosti od te vrednosti se bo neprestano spreminjal duty cicle PWM signala na pinu 3 razvojne plošče Arduino Uno s ciljem, da je svetilnost LED diode takšna, da ustreza naši želeni vrednosti. Če v bližini fotoupora LDR vklopimo dodatno razsvetljavo, to fotoupor takoj zazna, zato se mora ustrezno zmanjšati svetilnost LED diode, ki je neposredno zraven fotoupora. Spremembe PID regulacija neprestano izračunava (myPID.Compute();) in ustrezne vrednosti zapisuje na pin 3 Arduino Uno, kamor je priključena LED dioda. Pin 3 plošče Arduino Uno je PWM izhod časovnika Timer2, ki je 8 bitni (ločljivost 0-255). V programu smo spremenili frekvenco tega PWM signala na vrednost 62,5 kHz.

Arduino okolje 1.6.7 vsebuje dodatek, ki grafično prikazuje vrednosti izbranih spremenljivk (Serial Plotter). Najdemo ga v meniju Orodja. Vrednosti spremenljivk, ki jih v programu izpisujemo na serijski monitor, se v tem primeru izrisujejo na grafu. V našem programu želimo izpisovanje spremenljivke Setpoint in Input:

   Serial.print(Setpoint);   //Izpis na serijskem monitorju.

   Serial.print(" ");

   Serial.println(Input);

Če se odločimo za grafični prikaz, dobimo izris vrednosti teh dveh spremenljivk v odvisnosti od časa, kot prikazuje slika 6.

Slika 6: Grafični prikaz vrednosti spremenljivke Setpoint in spremenljivke Input (Serial Plotter)

PID regulacija skrbi, da je vrednost spremenljivke Input enaka vrednosti spremenljivke Setpoint. Če spremenimo želeno vrednost osvetlitve (Setpoint), PID regulacija poskrbi, da se ustrezno spremeni tudi odziv (Input), kot prikazuje slika 7.

Slika 7: Sprememba želene vrednosti (Setpoint) in odziv

PID regulacija temperature

PWM izhod PID regulacije

Slika 8: Povezava elementov in priključitev na pine razvojne plošče Arduino Uno

Neposredno poleg temperaturnega senzorja LM35 je nameščena žarnica, ki služi kot grelec. Uporabili smo avtomobilsko žarnico za osvetljevanje notranjosti avtomobila (12 V, 330 mA). Vezana je v kolektorskem krogu tranzistorja BC337 (Icmax = 800 mA). Tranzistor krmilimo s PWM izhodom timerja2 Arduino Uno, pin 3. Izhod analognega temperaturnega senzorja LM35 je povezan na analogni vhod A0. Drsnik potenciometra 4,7 kohm, s katerim nastavljamo želeno temperaturo (Setpoint) je povezan na analogni vhod A2.

Najprej bomo napisali program, ki bo s pomočjo PID regulacije kontinuirano vzdrževal želeno temperaturo. Dogajanje bomo spremljali z grafičnim orodjem Serial Plotter.

Duty cycle PWM signala na pinu 3 (PWM izhod Timer2) se bo neprestano spreminjal. PID regulacija bo namreč stremela k temu, da je odziv (Input) enak želeni vrednosti temperature (Setpoint). V odvisnosti od srednje vrednosti PWM signala bo žarnica (grelec) spreminjala svetilnost in s tem oddano temperaturo, ki jo preverja temperaturni senzor LM35.

Slika 9: PWM signal in duty cycle

 

Program:

/*

 * PID regilacija temperature v odvisnosti od nastavitvene, želene vrednosti => Setpoint.

 * Želeno vrednost temperature nastavljamo s trimer potenciometrom.

 * Avtor: Milan Ivič

 * Datum: marec 2016

 */

 #include <PID_v1.h>

 //Deklariranje spremenljivk in nastavitev PID parametrov:

 double Kp=1, Ki=51, Kd=0;

 double Setpoint, Input, Output;

 //Start PID:

 PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

 int Grelec = 3;    //Žarnico kot grelec preko tranzistorja BC337 priključimo na pin 3 (PWM izhod Timer2).

 void setup()

 {

   Serial.begin(9600);   //Serijska komunikacija.

 

   Input = map(analogRead(A0), 0, 1023, 255, 0);         //Nastavitev območja za branje na A0 (temp senzor LM35).

   Setpoint = map(analogRead(A2), 0, 1023, 255, 0);      //Setpoint nastavljamo s potenciometrom na pinu A2.

   myPID.SetOutputLimits(0, 255);                        //Nastavitev območja PWM signala na izhodu (pin 3).

 

   myPID.SetMode(AUTOMATIC);           //Vklopimo PID regulacijo.

   myPID.SetTunings(Kp, Ki, Kd);       //Nastavitve PID z našimi izbranimi parametri.

 }

 void loop()

 {

   //Setpoint nastavljamo s potenciometrom. Vhod A2 vsebuje 10 bitni AD pretvornik (0-1023).

   Setpoint = map(analogRead(A2), 0, 1023, 255, 0);      //Območje od 0-1023 prestavimo v območje 255-0.  

   Input = analogRead(A0);                               //Branje vrednosti na A0 (temperatura).   

   myPID.SetTunings(Kp, Ki, Kd);                         //Nastavitve PID z našimi izbranimi parametri.

   //PID izračunavanje:

   myPID.Compute();  

   analogWrite(3,Output);            //Izračunano vrednost PID funkcije zapišemo na pin 3:

   Serial.print(Setpoint);           //Izpis na serijskem monitorju ali izris na grafu.

   Serial.print(" ");

   Serial.println(Input);   

 }

PID regulacija temperature

Digitalni izhod PID regulacije

Včasih moramo neko napravo (grelec) priklopiti preko kontaktov releja. Releja ne moremo krmiliti s PWM signalom, ampak potrebujemo digitalni izhod, ki bo v določenih časovnih presledkih v stanju logične 1 oziroma v stanju logične 0. Kako dolgo bo v teh časovnih presledkih rele vklopljen je odvisno od razlike med nastavitveno vrednostjo (Setpoint) in odzivom.

Program:

/*

 * PID regilacija temperature v odvisnosti od nastavitvene, želene vrednosti => Setpoint.

 * Želeno vrednost temperature nastavljamo s trimer potenciometrom.

 * Digitalni izhod.

 * Avtor: Milan Ivič

 * Datum: marec 2016

 */

 #include <PID_v1.h>

 //Deklariranje spremenljivk in nastavitev PID parametrov:

 double Kp=1, Ki=40, Kd=0.5;

 double Setpoint, Input, Output;

 //Start PID:

 PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

 #define Grelec 2    //Žarnico kot grelec preko tranzistorja BC337 priključimo na pin 2, digitalni izod.

 int Presledek = 3000;          //3000 ms = 3 s. Ta čas lahko spremenimo (povečamo).

 unsigned long Start_Cas;

 void setup()

 {

   Serial.begin(9600);          //Serijska komunikacija.

   pinMode(2, OUTPUT);

   Start_Cas = millis();        //Spremenljivka Start_Cas se povečuje z vrednostjo ms od začetka izvajanja programa. 

   myPID.SetOutputLimits(0, Presledek);      //PID se naj izvaja v času med 0 in 3000 ms.

 

   myPID.SetMode(AUTOMATIC);                 //Vklopimo PID regulacijo.

   myPID.SetTunings(Kp, Ki, Kd);             //Nastavitve PID z našimi izbranimi parametri.

 }

 void loop()

 {

   //Setpoint nastavljamo s potenciometrom. Vhod A2 vsebuje 10 bitni AD pretvornik (0-1023).

   Setpoint = map(analogRead(A2), 0, 1023, 255, 0);          //Območje od 0-1023 prestavimo v območje 255-0.

   Input = analogRead(A0);                                   //Branje vrednosti na A0 (temperatura).

   myPID.Compute();  

  

   if(millis() - Start_Cas > Presledek)               //Ali je čas izvajanja programa v ms - 3000 ms večje od 3000 ms?

   {

     Start_Cas = Start_Cas + Presledek;               //Povečaj Start_Cas za 3000.

   }

 

   if(Output > millis() - Start_Cas)

   {

     digitalWrite(Grelec, HIGH);               //Vklopi grelec.

   }

   else

   {

     digitalWrite(Grelec, LOW);                //Izklopi grelec.

   }      

 

   Serial.print(Setpoint);                     //Izpis na serijskem monitorju oziroma grafu.

   Serial.print(" ");

   Serial.println(Input);  

 }

Funkcija millis() vrača število v ms od takrat naprej, ko se je začel izvajati program. Ko prekorači svojo vrednost (po cca. 50-tih dneh), začne zopet od 0.

PID regulacija temperature

PWM izhod PID regulacije za krmiljenje ventilatorja, ki vzdržuje želeno (Setpoint) temperaturo.

/*

 * PID regilacija temperature v odvisnosti od nastavitvene, želene vrednosti => Setpoint.

 * Želeno vrednost temperature nastavljamo s trimer potenciometrom.

 * Ventilator ohlajuje prostor za vzdrževanje želene temperature.

 * Avtor: Milan Ivič

 * Datum: marec 2016

 */

 #include <PID_v1.h>

 //Deklariranje spremenljivk in nastavitev PID parametrov:

 double Kp=1, Ki=50, Kd=0.1;

 double Setpoint, Input, Output;

 //Start PID:

 PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);

 int Ventilator = 3;    //Ventilator preko tranzistorja BC337 priključimo na pin 3 (PWM izhod Timer2).

   

 void setup()

 {

   Serial.begin(9600);   //Serijska komunikacija.

 

   Input = map(analogRead(A0), 0, 1023, 255, 0);         //Nastavitev območja za branje na A0 (temp senzor LM35).

   Setpoint = map(analogRead(A2), 0, 1023, 255, 0);      //Setpoint nastavljamo s potenciometrom na pinu A2.

   myPID.SetOutputLimits(0, 255);                        //Nastavitev območja PWM signala na izhodu (pin 3).

 

   myPID.SetMode(AUTOMATIC);           //Vklopimo PID regulacijo.

   myPID.SetTunings(Kp, Ki, Kd);       //Nastavitve PID z našimi izbranimi parametri.

   //Nastavitev Timerja2, Frekvenca PWM signala je 488 Hz (f = 16 MHz/(128*256) = 488 Hz):

   TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM21) | _BV(WGM20);        //Pina 3 in 11 sta PWM izhoda, Fast PWM.

   TCCR2B = _BV(CS20) | _BV(CS22);                                      //Preddelitev 1:128

 }

 void loop()

 {   

   //Setpoint nastavljamo s potenciometrom. Vhod A2 vsebuje 10 bitni AD pretvornik (0-1023).

   Setpoint = map(analogRead(A2), 0, 1023, 255, 0);      //Območje od 0-1023 prestavimo v območje 255-0.   

   Input = analogRead(A0);                                      //Branje vrednosti na A0 (temperatura).   

   myPID.SetTunings(Kp, Ki, Kd);                                //Nastavitve PID z našimi izbranimi parametri.

   //PID izračunavanje:

   myPID.Compute();  

   analogWrite(3,Output);            //Izračunano vrednost PID funkcije zapišemo na pin 3:

   Serial.print(Setpoint);           //Izpis na serijskem monitorju ali izris na grafu.

   Serial.print(" ");

   Serial.println(Input);    

 }