Skocz do zawartości

Regulacja temperatury PID


Matiautomati

Pomocna odpowiedź

Witam,

proszę o pomoc. Posiadam małą makietę układu regulacji temperatury.

Chciałbym opracować układ regulacji temperatury powietrza zbudowany z grzałki (od małej suszarki 230V), silniczka MT78 ze śmigiełkiem i termistora NTC 110 5 kOhm 5% jako czujnika temperatury. Temperatura w zadanym punkcji będzie podlegała regulacji poprzez zmianę prędkości obrotowej wentylatora.

Chciałbym aby kod poniżej utrzymywał zadaną wartość. Korzystałem głównie ze strony https://playground.arduino.cc/Code/PIDLibrary. Mój układ po osiągnięciu wartości ok. 40 (odczytanej z kreślarki)przestaje ogrzewać, wartość spada do ok. 55 a potem znów ogrzewa i tak w kółko. Czy można zrobić tak aby temperatura na termistorze nie rosła do takiej wartości tylko trzymała się bliżej zadanej wartości? Proszę o pomoc. Nie wiem za bardzo jak to zrobić.

Dołączam schemat. Nie mogę znaleźć przekaźnika, którego używam więc zostawiłem tam trzy przewody (od pinu 12 jako sygnał sterujący, zasilanie i uziemienie). Do przekaźnika dołączona grzałka, również niewidoczna na schemacie ale w rzeczywistości znajdująca się między silniczkiem a termistorem. Przy termistorze znajduje się rezystor 10K.

Załóżmy, że chciałbym aby utrzymywał temperaturę 40 st. C. Przy termistorze znajduje się rezystor 10k. Do pinu 12 mam podłączony przekaźnik z grzałką, do 7 podłączony silniczek z wiatraczkiem. Natomiast pin 6 PWM służy do regulacji prędkości obrotów silniczka.

#include <PID_v1.h>
#define Relay 12
#define Krec 7
#define PWM 6


////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, 2, 5, 1, DIRECT);

int WindowSize = 5000;
unsigned long windowStartTime;

void setup() {
 Serial.begin(9600); 
 pinMode(Relay, OUTPUT);
 pinMode(Krec, OUTPUT);
 digitalWrite(Krec, HIGH);
 pinMode(8, OUTPUT);
 digitalWrite(8, LOW);



 windowStartTime = millis();

 //initialize the variables we're linked to

 Input = analogRead(0);
 Setpoint = 120;

 //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() {
 float resistance;

 Input = analogRead(0);
 Serial.println(analogRead(0));
 delay(200);
 resistance = map(analogRead(0), 0, 1023, 0, 100);


 double gap = abs(Setpoint - resistance); // 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 aggresive tuning parameters
   myPID.SetTunings(aggKp, aggKi, aggKd);
 }

 unsigned long now = millis();
 if (now - windowStartTime > WindowSize)
 { // time to shift the Relay Window
   windowStartTime += WindowSize;
 }
if (Output > now - windowStartTime) 
 {
   digitalWrite(Relay, HIGH); 
   }
else { 
   digitalWrite(Relay, LOW); }


 myPID.Compute();
 analogWrite(PWM, Output);


 }

Link do komentarza
Share on other sites

Nie bardzo rozumiem jaka jest tutaj rola wentylatora. Dodatkowy element wykonawczy?

Zakładając, że masz tylko grzałkę, element ogrzewany i sensor temperatury + sterowanie ON/OFF elementem wykonawczym, to oscylacje w układzie regulacji możesz zmniejszyć poprzez zmniejszenie szerokości pętli histerezy. Ale w takim układzie wtedy w ogóle nie ma PID, przydałby się tutaj jakiś schemat układu regulacji, bo domyślanie się z kodu nie jest zbyt fajne.

Link do komentarza
Share on other sites

Ale w takim układzie wtedy w ogóle nie ma PID, przydałby się tutaj jakiś schemat układu regulacji, bo domyślanie się z kodu nie jest zbyt fajne.

Szczególnie ważne jest abyś narysował jak jest podłączony termistor do pinu analogowego (przetwornik AC) Arduino.

Ten fragment kodu mi się nie zgadza:

Input = analogRead(0);
Setpoint = 120;

//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() {
float resistance;

Input = analogRead(0);
Serial.println(analogRead(0));
delay(200);
resistance = map(analogRead(0), 0, 1023, 0, 100);

Rozumiem, że wartosć Setpoint = 120;

to wartośc zadana dla regulatora PID (rezystancja termistora, która ma być stabilizowana ).

Czy znasz charkterystykę tego termistora (może być mocno nieliniowa). Jakiej temperaturze odpowiada ta wartość?

2) W instrukcji map:

resistance = map(analogRead(0), 0, 1023, 0, 100);

mapujesz wartość rezystancji (pełny zakres przetwornika Analogowo-Cyfrowego) na przedział od 0..100

A potem masz kod (obliczenie błędu):

double gap = abs(Setpoint - resistance); // 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 aggresive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
} 

W takim przypadku gap jest zawsze większe od 10 (120 - 100 = 20) i PID będzie używał "agresywnych parametrów" (double aggKp = 4, aggKi = 0.2, aggKd = 1; ) co może powodować takie efekty jak opisujesz. Nie wolisz ustawić dla poszczególnych członów PID stałych parametrów?

Podaję jako przykład mój kod z uzyciem tej samej biblioteki PID dla Arduino. Ten kod działa dobrze (stabilizuje prędkość obrotową małego silnika DC z enkoderami do pomiaru prędkości obrotowej) - wartośc zadana: Setpoint to wartość prędkości obrotowej do utrzymania:

#include <PID_v1.h>
const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
const byte encoder0pinB = 3;//B pin -> the digital pin 3
int E_left =6; //The enabling of L298PDC motor driver board connection to the digital interface port 5
int M_left =5; //The enabling of L298PDC motor driver board connection to the digital interface port 4
byte encoder0PinALast;
double duration,abs_duration;//the number of the pulses
boolean Direction;//the rotation direction 
boolean result;

double val_output;//Power supplied to the motor PWM value.
double Setpoint;
double Kp=0.8, Ki=7, Kd=0.038;  
PID myPID(&abs_duration, &val_output, &Setpoint, Kp, Ki, Kd, DIRECT); 

void setup()
{  
 Serial.begin(9600);//Initialize the serial port
  pinMode(M_left, OUTPUT);   //L298P Control port settings DC motor driver board for the output mode
  pinMode(E_left, OUTPUT); 
  Setpoint =80;  //Set the output value of the PID
  myPID.SetMode(AUTOMATIC);//PID is set to automatic mode
  myPID.SetSampleTime(100);//Set PID sampling frequency is 100ms
 EncoderInit();//Initialize the module
}

void loop()
{   
     advance();//Motor Forward
     abs_duration=abs(duration);
     result=myPID.Compute();//PID conversion is complete and returns 1
     if(result)
     {
       Serial.print("Pluse: ");
       Serial.println(duration); 
       //Serial.println(val_output); 
       duration = 0; //Count clear, wait for the next count
     }


}

void EncoderInit()
{
 Direction = true;//default -> Forward  
 pinMode(encoder0pinB,INPUT);  
 attachInterrupt(0, wheelSpeed, CHANGE);
}

void wheelSpeed()
{
 int Lstate = digitalRead(encoder0pinA);
 if((encoder0PinALast == LOW) && Lstate==HIGH)
 {
   int val = digitalRead(encoder0pinB);
   if(val == LOW && Direction)
   {
     Direction = false; //Reverse
   }
   else if(val == HIGH && !Direction)
   {
     Direction = true;  //Forward
   }
 }
 encoder0PinALast = Lstate;

 if(!Direction)  duration++;
 else  duration--;

}
void advance()//Motor Forward
{
    digitalWrite(M_left,HIGH);
    analogWrite(E_left,val_output);
}
void back()//Motor reverse
{
    digitalWrite(M_left,LOW);
    analogWrite(E_left,val_output);
}

void Stop()//Motor stops
{
    digitalWrite(E_left, LOW); 
}

Jak widzisz są tu ustawione stałe parametry dla 3 członów PID (Proporcjonalny: wzmocnienie sygnału błędu. Całkowy: wolne zmiany, Różniczkowy: stabilizacja gwałtownych zmian):

double Setpoint;
double Kp=0.8, Ki=7, Kd=0.038;  
PID myPID(&abs_duration, &val_output, &Setpoint, Kp, Ki, Kd, DIRECT); 

Poza tym w setup'ie jest ustawiny czas 'sampling time' dla regulatora, a to ważny parametr:

void setup()
{  
 Serial.begin(9600);//Initialize the serial port
  pinMode(M_left, OUTPUT);   //L298P Control port settings DC motor driver board for the output mode
  pinMode(E_left, OUTPUT); 
  Setpoint =80;  //Set the output value of the PID
  myPID.SetMode(AUTOMATIC);//PID is set to automatic mode
  myPID.SetSampleTime(100);//Set PID sampling frequency is 100ms
 EncoderInit();//Initialize the module
}

Po drugie co masz podłączone do pinu PWM? Bo przekaźnik z nim nie zadziała - nie rozumiem dlaczego sterujesz Relay (dwu-stanowo) a masz jeszcze na pin PWM wystawiony sygnał o zmiennym wypełnieniu też sterowany z PID?

A podaj wartość temperatury jak ma być stabilizowana (i odpowiadającą jej wartość rezystancji termistora)

2) Podaj wykres zależności rezystancji twojego termistora od temperatury (nota katalogowa producenta)

3) Narysuj schemat całego układu (szczególnie układ podłączony do pinu analogowego z Arduino do pomiaru rezystancji termistora).

A jeszcze jedno - rozumiem, że silniczek z wentylatorem ma chłodzić układ, czy jest włączony do układu regulacji. Jeśli będziesz chciał sterować grzałką za pomocą PWM to przekaźnik nie wystarczy - musisz mieć jakiś mostek MOSFET (lub układ z tyrystoroami).

Pozdrawiam

[ Dodano: 29-12-2017, 14:25 ]

Witam,

Dołączam schemat podłączenia termistora

Obrazek

A reszta układu i charakterystyka twojego termistora (podaj chociaż typ termistora)?

A podłączenie układów wykonawczych? Rezystor 10 K (rysunek jest mały i słabo widać kolory)?

Jeszcze jedno z kodu domyślam się, że:

#define Relay 12
#define Krec 7
#define PWM 6

Ze do pinu 12(Relay) masz podłączony przekaźnik z grzałką, do 7 (krec) pewno planowałeś podłąctyć silniczek z wiatraczkiem (nieużyty w programie). Pinu 6 (PWM) używasz w programie, ale nie wiem co masz tam podłączone?

jeśli ten rezystor połączony szeregowo z termistorem to 10K to maksymalna wartość napięcia na termistorze to 1,(6)V (dla rezystancji termistora = 5K). Dla rezystancji np. 1K to 0,945) V a dla 120 omów to około: 0,0593V. Pełen zakres przetwornika to napięcie 0-5V a wartość wskazań 0-1023 czyli w twoim układzie pomiarowym przetwornik może pokazać największą wartość około 341.

Link do komentarza
Share on other sites

Nie bardzo rozumiem jaka jest tutaj rola wentylatora. Dodatkowy element wykonawczy?

Silniczek dmucha powietrzem na grzałkę, które dalej leci w kierunku termistora.

Umieściłem schemat układu regulacji wykonany w programie Fritzing. Przepraszam, że tego od razu nie zrobiłem... 🙁

[ Dodano: 30-12-2017, 08:57 ]

Nie wolisz ustawić dla poszczególnych członów PID stałych parametrów?

Powiem szczerze nigdy wcześniej nie tworzyłem regulatora PID. Na stronie oficjalnej Arduino https://playground.arduino.cc/Code/PIDLibraryAdaptiveTuningsExample sugerują ustawianie parametrów "łagodnych" oraz "agresywnych", dlatego tak zrobiłem.

Po drugie co masz podłączone do pinu PWM? Bo przekaźnik z nim nie zadziała - nie rozumiem dlaczego sterujesz Relay (dwu-stanowo) a masz jeszcze na pin PWM wystawiony sygnał o zmiennym wypełnieniu też sterowany z PID?

Z pinu 6 PWM idzie przewód na wejście do mostka H odpowiedzialnego za sterowanie prędkością obrotów silniczka. Przepraszam, że wcześniej nie dodałem schematu układu regulacji. Teraz wszystko powinno być jaśniejsze.

Ja za bardzo nie rozumiem do czego jest funkcja WindowSize, windowStartTime. Nigdy wcześniej nie miałem z tym styczności. Muszę się poradzić doświadczonych 🙂

A jeszcze jedno - rozumiem, że silniczek z wentylatorem ma chłodzić układ, czy jest włączony do układu regulacji. Jeśli będziesz chciał sterować grzałką za pomocą PWM to przekaźnik nie wystarczy - musisz mieć jakiś mostek MOSFET (lub układ z tyrystoroami).

Silniczek ze śmigiełkiem oraz grzałką mają ogrzewać termistor. Jak najbardziej elementy te są włączone do układu regulacji. Grzałką nie chcę sterować za pomocą PWM.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Nie bardzo rozumiem jaka jest tutaj rola wentylatora. Dodatkowy element wykonawczy?

Silniczek dmucha powietrzem na grzałkę, które dalej leci w kierunku termistora.

Umieściłem schemat układu regulacji wykonany w programie Fritzing. Przepraszam, że tego od razu nie zrobiłem... 🙁

[ Dodano: 30-12-2017, 08:57 ]

Nie wolisz ustawić dla poszczególnych członów PID stałych parametrów?

Powiem szczerze nigdy wcześniej nie tworzyłem regulatora PID. Na stronie oficjalnej Arduino https://playground.arduino.cc/Code/PIDLibraryAdaptiveTuningsExample sugerują ustawianie parametrów "łagodnych" oraz "agresywnych", dlatego tak zrobiłem.

Po drugie co masz podłączone do pinu PWM? Bo przekaźnik z nim nie zadziała - nie rozumiem dlaczego sterujesz Relay (dwu-stanowo) a masz jeszcze na pin PWM wystawiony sygnał o zmiennym wypełnieniu też sterowany z PID?

Z pinu 6 PWM idzie przewód na wejście do mostka H odpowiedzialnego za sterowanie prędkością obrotów silniczka. Przepraszam, że wcześniej nie dodałem schematu układu regulacji. Teraz wszystko powinno być jaśniejsze.

Ja za bardzo nie rozumiem do czego jest funkcja WindowSize, windowStartTime. Nigdy wcześniej nie miałem z tym styczności. Muszę się poradzić doświadczonych 🙂

A jeszcze jedno - rozumiem, że silniczek z wentylatorem ma chłodzić układ, czy jest włączony do układu regulacji. Jeśli będziesz chciał sterować grzałką za pomocą PWM to przekaźnik nie wystarczy - musisz mieć jakiś mostek MOSFET (lub układ z tyrystoroami).

Silniczek ze śmigiełkiem oraz grzałką mają ogrzewać termistor. Jak najbardziej elementy te są włączone do układu regulacji. Grzałką nie chcę sterować za pomocą PWM.

Teraz całość układu jest jaśniejsza:

Najopierw przeprowadziłbym nastepujący test: zmieniłbym instrukcję w programie:

resistance = map(analogRead(0), 0, 1023, 0, 100);

na

resistance = map(analogRead(0), 0, 342, 0, 130);

a dla parametrów agresywnych zmieniłbym parametry:

double aggKp = 4, aggKi = 0.2, aggKd = 1; na

double aggKp = 3, aggKi = 0.2, aggKd = 0.3

Teraz rezystancja termistora (twój sygnał błędu będzie w prawidłowym zakresie). 3-ci parametr (człon różniczkowy) odpowiada za odpowiedź regulator na szybkie zmiany. Za duża wartość tego parametru może skutkować tym ,że wartość kontrolowana będzie za bardzo skakała (z dużą amplitudą wokół wartości zadanej). Ogólnie dobranie tych trzech parametrów do konkretnego układu regulacji jest bardzo ważna (robimy to metodą prób i błędów - no chyba ,że chcesz wyprowadzić równania różniczkowe układu i je rozwiązywać).

Instrukcja:

int WindowSize = 5000;

definiuje Ci "okno czasowe" o długości 5000 ms (czyli 5 sekund), które jest przesuwane po osi czasu. Wydaje mi się, że instrukcja: myPID.Compute(); powinna być przesunięta w inne miejsce. Czyli kod po zmianach powinien wyglądać tak:

#include <PID_v1.h>
#define Relay 12
#define Krec 7
#define PWM 6


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

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

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

int WindowSize = 5000;
unsigned long windowStartTime;

void setup() {
Serial.begin(9600);
pinMode(Relay, OUTPUT);
pinMode(Krec, OUTPUT);
digitalWrite(Krec, HIGH);
pinMode(8, OUTPUT);
digitalWrite(8, LOW);

windowStartTime = millis();

//initialize the variables we're linked to

Input = analogRead(0);
Setpoint = 120;

//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() {
float resistance;

Input = analogRead(0);
Serial.println(analogRead(0));
delay(200);
resistance = map(analogRead(0), 0, 342, 0, 130);

double gap = abs(Setpoint - resistance); // 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 aggresive tuning parameters
myPID.SetTunings(aggKp, aggKi, aggKd);
}

myPID.Compute();
unsigned long now = millis();
if (now - windowStartTime > WindowSize)
{ // time to shift the Relay Window
windowStartTime += WindowSize;
}
if (Output > now - windowStartTime)
{
digitalWrite(Relay, HIGH);
}
else {
digitalWrite(Relay, LOW); }

analogWrite(PWM, Output);

}

Zrób te zmiany i napisz jak to wpłynęło na pracę układu. Takiego sposobu użycia PID (z oknem czasowym nigdy nie używałem). Mógłbyś podać link do kodu, któy był punktem wyjścia do twojego?

Pozdrawiam

[ Dodano: 30-12-2017, 16:27 ]

Cześć,

znalazłem oryginalny kod przykłd użycia PID z którego skorzystałeś - tutaj link:

https://playground.arduino.cc/Code/PIDLibraryRelayOutputExample

A tutaj ten kod:

/********************************************************
  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"  Tt'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 RelayPin 6

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

int WindowSize = 5000;
unsigned long windowStartTime;
void setup()
{
 pinMode(RelayPin, OUTPUT);

 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(0);
 myPID.Compute();

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

Widzę, że obsługę wiatraczka dodałeś sam (PWM). Aby nie było wpływu za dużo parametrów naraz proponuję aby wiatraczek kręcił się na razie ze stałą prędkością.

Czyli, żeby twój kod całości wyglądał następująco:


   #include <PID_v1.h>
   #define Relay 12
   #define Krec 7
   #define PWM 6


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

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

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

   int WindowSize = 5000;
   unsigned long windowStartTime;

   void setup() {
   Serial.begin(9600);
   pinMode(Relay, OUTPUT);
   pinMode(Krec, OUTPUT);
   digitalWrite(Krec, HIGH);
   pinMode(8, OUTPUT);
   digitalWrite(8, LOW);

   analogWrite(PWM, 240);//Wiatraczek dmucha ze stala predkoscia

   windowStartTime = millis();

   //initialize the variables we're linked to

   Input = analogRead(0);
   Setpoint = 120;

   //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() {
   float resistance;

   Input = analogRead(0);
   Serial.println(analogRead(0));
   delay(200);
   resistance = map(analogRead(0), 0, 342, 0, 130);

   double gap = abs(Setpoint - resistance); // 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 aggresive tuning parameters
   myPID.SetTunings(aggKp, aggKi, aggKd);
   }

   myPID.Compute();
   unsigned long now = millis();
   if (now - windowStartTime > WindowSize)
   { // time to shift the Relay Window
   windowStartTime += WindowSize;
   }
   if (Output > now - windowStartTime)
   {
   digitalWrite(Relay, HIGH);
   }
   else {
   digitalWrite(Relay, LOW); }

   }

Daj znać jak działa zmieniony program, sam bardzo jestem ciekaw rezultatu 😉

Pozdrawiam

Link do komentarza
Share on other sites

Widzę, że obsługę wiatraczka dodałeś sam (PWM). Aby nie było wpływu za dużo parametrów naraz proponuję aby wiatraczek kręcił się na razie ze stałą prędkością.

Witam,

zrobiłem tak jak chciałeś. Ustawiłem stałą prędkość na pinie 6 PWM.

#include <PID_v1.h>
#define Relay 12
#define Krec 7
#define PWM 6


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

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

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

int WindowSize = 5000;
unsigned long windowStartTime;

void setup() {
 Serial.begin(9600); 
 pinMode(Relay, OUTPUT);
 pinMode(Krec, OUTPUT);
 digitalWrite(Krec, HIGH);
 pinMode(8, OUTPUT);
 digitalWrite(8, LOW);

 analogWrite(PWM, 240); // stala predkosc wiatraczka



 windowStartTime = millis();

 //initialize the variables we're linked to

 Input = analogRead(0);
 Setpoint = 120;

 //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() {
 float resistance;

 Input = analogRead(0);
 Serial.println(analogRead(0));
 delay(200);
 resistance = map(analogRead(0), 0, 342, 0, 130);


 double gap = abs(Setpoint - resistance); // 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 aggresive tuning parameters
   myPID.SetTunings(aggKp, aggKi, aggKd);
 }

 myPID.Compute();
 unsigned long now = millis();
 if (now - windowStartTime > WindowSize)
 { // time to shift the Relay Window
   windowStartTime += WindowSize;
 }
if (Output > now - windowStartTime) 
 {
   digitalWrite(Relay, HIGH); 
   }
else { 
   digitalWrite(Relay, LOW); }


// analogWrite(PWM, Output);

// if (Setpoint == 80) {
//   digitalWrite(Relay, LOW);
// }
// else {
 //  digitalWrite(Relay, HIGH);
 }

Wrzuciłem przebieg z Kreślarki

Nie jestem w stanie wrzucić całego przebiegu, więc wrzuciłem początek oraz koniec przebiegu. Zauważyłem, że praca przekaźnika ulegała zmianie, mianowicie wraz z dłuższą pracą układu wydłużał się czas załączenia przekaźnika a skracał czas jego wyłączenia, w wyniku czego przez cały czas rosła temperatura na termistorze. Przy końcu przebiegu przekaźnik "nie miał czasu na odpoczynek", gdy się wyłączał natychmiast się załączał do momentu aż przekaźnik był załączony cały czas. Dziwne ...

Zmieniłem Windowsize na 3000 zostawiając PWM na 240, sprawdzałem również na kreślarce przebieg przy setpoint = 80 oraz 180. Przebiegi są krótkie, ponieważ tutaj interesował mnie spadek wartości. Wyszło mi tak:

dla Setpoint = 80,

dla Setpoint = 180,

Zauważyłem, że w przypadku np. Setpoint =50, 80 lub 180, termistor osiągnię ostatecznie tą samą temperaturę (oczywiście w przypadku niższych będzie to przebiegać wolniej), a to chyba nie oto chodzi.

Kiedy ustawię PWM pinu 6 jak wcześniej, przekaźnik zachowuje się tak jak wcześniej wspomniałem.

Pozdrawiam

Link do komentarza
Share on other sites

Może stała czasowa układu jest dłuższa niż ustawione 5 s. Zmień rozmiar okna na 15 s:

int WindowSize = 15000;

a parametry PID na:

//Define the aggressive and conservative Tuning Parameters

double aggKp = 7, aggKi = 1.2, aggKd = 2;

double consKp = 3, consKi = 0.4, consKd = 0.65;

Resztę programu zostawiając bez zmian (ta wersja ze stałym PWM na wiatraczek). Ustawienie parametrów PID to kluczowa sprawa dla każdego układu regulacji i nie jest to proste. Niestety nie orientuję się ile w przybliżeniu może wynosić stała czasowa takiego układu z grzałką (dla silników elektrycznych DC są to czasy kilkudziesięciu milisekund), ale tu może to być dużo więcej.

Daj znać, czy to coś zmienia?

Pozdrawiam

Link do komentarza
Share on other sites

Może stała czasowa układu jest dłuższa niż ustawione 5 s. Zmień rozmiar okna na 15 s:

int WindowSize = 15000;

a parametry PID na:

//Define the aggressive and conservative Tuning Parameters

double aggKp = 7, aggKi = 1.2, aggKd = 2;

double consKp = 3, consKi = 0.4, consKd = 0.65;

Resztę programu zostawiając bez zmian (ta wersja ze stałym PWM na wiatraczek). Ustawienie parametrów PID to kluczowa sprawa dla każdego układu regulacji i nie jest to proste. Niestety nie orientuję się ile w przybliżeniu może wynosić stała czasowa takiego układu z grzałką (dla silników elektrycznych DC są to czasy kilkudziesięciu milisekund), ale tu może to być dużo więcej.

Daj znać, czy to coś zmienia?

Pozdrawiam

Witam,

zrobiłem jak poleciłeś

#include <PID_v1.h>
#define Relay 12
#define Krec 7
#define PWM 6


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

//Define the aggressive and conservative Tuning Parameters
double aggKp = 7, aggKi = 1.2, aggKd = 2;
double consKp = 3, consKi = 0.4, consKd = 0.65;

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

int WindowSize = 15000;
unsigned long windowStartTime;

void setup() {
 Serial.begin(9600); 
 pinMode(Relay, OUTPUT);
 pinMode(Krec, OUTPUT);
 digitalWrite(Krec, HIGH);
 pinMode(8, OUTPUT);
 digitalWrite(8, LOW);

 analogWrite(PWM, 240); // stala predkosc wiatraczka



 windowStartTime = millis();

 //initialize the variables we're linked to

 Input = analogRead(0);
 Setpoint = 180;

 //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() {
 float resistance;

 Input = analogRead(0);
 Serial.println(analogRead(0));
 delay(200);
 resistance = map(analogRead(0), 0, 342, 0, 130);


 double gap = abs(Setpoint - resistance); // 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 aggresive tuning parameters
   myPID.SetTunings(aggKp, aggKi, aggKd);
 }

 myPID.Compute();
 unsigned long now = millis();
 if (now - windowStartTime > WindowSize)
 { // time to shift the Relay Window
   windowStartTime += WindowSize;
 }
if (Output > now - windowStartTime) 
 {
   digitalWrite(Relay, HIGH); 
   }
else { 
   digitalWrite(Relay, LOW); }


// analogWrite(PWM, Output);

// if (Setpoint == 80) {
//   digitalWrite(Relay, LOW);
// }
// else {
 //  digitalWrite(Relay, HIGH);
 }

Przy Setpoint = 140 lub 180 ostatecznietermistor osiągał tą samą wartość.

Setpoint = 140

Setpoint = 180

Na początku przebiegu wykres ma taką postać

Link do komentarza
Share on other sites

Patrząc na ostatni wrzucony przebieg:

czy w ogóle element wykonawczy jest w stanie doprowadzić do takiego nagrzania termistora, żeby wielkość regulowana (jak rozumiem parametr 'resistance') osiągnął wartość 140?

W pierwszych dwóch 'okresach' zmian widać, że zmiany wielkości regulowanej zaczynają maleć (przebieg się wypłaszcza), więc możliwe, że wartości zadanej w ogóle nie będzie w stanie układ osiągnąć, nawet przy stale włączonej grzałce.

Proponuję zarejestrować odpowiedź skokową obiektu i zobaczyć jak sprawa wygląda.

Link do komentarza
Share on other sites

Patrząc na ostatni wrzucony przebieg:

czy w ogóle element wykonawczy jest w stanie doprowadzić do takiego nagrzania termistora, żeby wielkość regulowana (jak rozumiem parametr 'resistance') osiągnął wartość 140?

W pierwszych dwóch 'okresach' zmian widać, że zmiany wielkości regulowanej zaczynają maleć (przebieg się wypłaszcza), więc możliwe, że wartości zadanej w ogóle nie będzie w stanie układ osiągnąć, nawet przy stale włączonej grzałce.

Proponuję zarejestrować odpowiedź skokową obiektu i zobaczyć jak sprawa wygląda.

Cześć,

wydaje mi się ,że to może być słuszna diagnoza. Chciałem, by kolega sprawdził program z większym oknem czasowym, ale ostatnie wyniki wskazują, że twoja ocena jest mocno prawdopodobna. Dobrze by jeszcze było sprawdzić np oscyloskopem (lub chociażby miernikiem) jak wygląda przebieg napięcia na termistorze podczas pracy układu (no i sprawdzić jak wyglądają zmiany jego rezystancji w funkcji temperatury - strona producenta).

Pozdrawiam

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.