Go Down

Topic: Problem bei Temperaturregelung mit PID-Bibliothek (Read 7513 times) previous topic - next topic

Elektrometaller

Oct 26, 2016, 09:27 pm Last Edit: Oct 26, 2016, 09:33 pm by Elektrometaller
Hallo,

ich plane eine Temperaturregelung für einen Härteofen zu bauen. Aber die Regelung der Temperatur funktioniert noch nicht so, wie ich es gerne hätte. Vielleicht kann mir jemand weiterhelfen.

Ich verwende einen Arduino Micro als Herzstück. Die Ist-Temperatur des Ofens wird über ein Typ-K Thermoelement erfasst und das Signal mittels MAX31855 an den Arduino übertragen (Bibliothek von https://github.com/adafruit/Adafruit-MAX31855-library). Die PID-Regler Bibliothek (http://playground.arduino.cc/Code/PIDLibrary) habe ich ebenfalls eingebunden. (Code folgt später im Post). Nun soll die einprogrammierte Solltemperatur aperiodisch erreicht werden.

Zu Beginn habe ich die Sprungantwort meiner Strecke ermittelt (siehe Bild im Anhang). Ergebnis Pt-2-Strecke. Mittels Wendetangenten-Methode komme ich auf Folgende Werte für die Strecke:

Ks = 950°C / 230V = 4,13K/V
Tu = ca. 18s
Tg = ca. 1875s

Für eine Simulation mit Scilab und der integrierten Toolbox XCOS habe ich die Strecke durch Pt1-Tt approximiert.

Mathematisch:

G(s) = Ks * 1/(Tg*s +1) * e^(-s*Tu)

Ich habe nun schon mehrere Regelparameter nach unterschiedlichen Methoden ermittelt (Ziegler&Nichols , Chien&Hrones&Reswick , empirisch aus der Simulation) und getestet aber kein Ansatz hat bisher zur Realität gepasst. Ich vermute, dass der simulierte Regler nicht mit der PID-Regler-Bibliothek übereinstimmt aber da wäre ich über jede Hilfe froh.

Mein Reglermodell ist ebenfalls im Anhang

Hier noch der Code:

Code: [Select]
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_MAX31855.h"
#include <LiquidCrystal.h>

#include <PID_v1.h>

// Example creating a thermocouple instance with software SPI on any three
// digital IO pins.
#define MAXDO   14
#define MAXCS   6
#define MAXCLK  15

#define RELAY_PIN 13

// Initialize the Thermocouple
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

//******************************
// Regelparameter
//******************************
double Setpoint, Input, Output;

double Kp = 2;
double Ki = 0.0005;
double Kd = 0;

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

int WindowSize = 5000;
unsigned long windowStartTime;

void setup() {
  Serial.begin(9600);

  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);
 
  lcd.begin(16, 2);
 
  lcd.clear();
  lcd.print("MAX31855 test");
  // wait for MAX chip to stabilize
  delay(500);
 
  //turn the PID on
  myPID.SetMode(AUTOMATIC); 
}

void loop() {

  lcd.clear();
  lcd.setCursor(0, 0);

  //*********************************************
  // Ausgabe der Zeit[s] und der Temperatur[°C]
  // auf dem seriellen Monitor
  //*********************************************
  int zeit = (millis()/1000);
  Input = thermocouple.readCelsius();
  Serial.print(zeit);
  Serial.print(";");
  Serial.print(Input);
  Serial.println(";");
  //******************************************
 
  if (isnan(Input))
    {
      lcd.print("T/C Problem");
    }
  else
  {
    lcd.print("Ist: ");
    lcd.print(Input);
  }
   
  myPID.Compute();
  // Display ausgabe des Regler-Ausgangs
  lcd.setCursor(0, 1);
  lcd.print("Out: ");
  lcd.print(Output);
  lcd.print(" ms");
  /************************************************
   * 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, LOW);
  else digitalWrite(RELAY_PIN, HIGH);
  delay(1000);
}


Für den Regler wurde das Beispiel des Relais-Ausgangs herangezogen (hier ein SSR verwendet). Dabei habe ich die Logik am Ende des Codes im gegensatz zum Beispiel invertiert. Bei mir soll eine "1" am Ausgangspin das Relais und folglich den Ofen anschalten bei "0" aus.

Ich hoffe ich habe alles genau genug beschrieben. Falls Rückfragen entstehen beantworte ich diese gern.

Im Vorfeld schonmal vielen Dank und viele Grüße

Elektrometaller

fckw

Hallo,

was du benötigst ist ein sogenannter "Schrittregler", ich kenne obige PID Bibliothek leider nicht, aber ich denke mit deinem Beispiel für den "Relais-Ausgang" ist selbiger gemeint. Nach meiner Erfahrung in Regelungstechnik (diskret aufgebaute) lassen sich Regelparameter, egal nach welcher Methode, nie genau berechnen, höchstens sind sie für eine Annäherung zu gebrauchen. Das wichtigste ist ausprobieren und beobachten. Bastel dir eine Ausgabe (kurvendiagramm z.b) wo du einen Soll /Ist Vergleich hast und die Stellimpulse siehst, zur Laufzeit.
Bei so einer trägen Temperaturegelung wie du sie benötigst ist ein PI-Regler besser geignet auf einen D-Anteil würde ich komplett verzichten. Was macht den dein Regler, schwingt er?
Grüße

Elektrometaller

Danke für die schnelle Rückmeldung.

Wenn ich die Bibliothek richtig verstehe wird bei dem verwendeten Beispiel ein PID-Regelalgorithmus berechnet und der Ausgang dann in eine "langsame" PWM umgerechnet mit einer Periodendauer von 5 Sekunden.

Bei den Parametern nach Ziegler/Nichols bekomme bei einem Sollwert von 100°C als ersten Überschwinger 148°C. Danach fällt die Temperatur auf etwa 98°C ab und beginnt dann wieder zu heizen. Danach schwingt der Regler etwa zwischen 120°C und 98°C.

In der Simulation habe ich den D-Anteil auch schon zu 0 gesetzt.
Bei den Parametern die ich empirisch aus der Simulation ermittelt habe kommt der Regler nicht wirklich in die Gänge. Bleibt etwa bei 40°C hängen.

Ich hätte gerne ein System in der Simulation, dass sich genauso wie das reale System verhällt. Damit könnte ich dann die Parameter schnell simulieren und verändern. Das reale System ist für die Beobachtung und das Einstellen der Parameter zur Laufzeit deutlich zu träge.

fckw

auf deiner reale Regelstrecke wirken aber viele verschiedene "Störgrößen" wie willst du die alle simulieren oder kennen?
Was ich bei der Sache noch nicht ganz verstanden habe, wie du deinen Ofen betreibst? Also, kannst du den in der Leistung dynamisch anfahren (0-100%), oder nur Ein und Aus schalten? Das ist für die "Betriebsart" deines PID-Regelalgorithmus wesentlich.

Elektrometaller

Der Ofen geht nur an oder aus. Aber durch das träge System und diese Puls-Pause-Betriebsart sollte er ja gut Regelbar sein. Dadurch kann ich die Eingangsspannung von 230V im Prinzip auf jede Spannung einstellen

peter_de

Hallo

Weil du ein SSR als Stellglied einsetzt, hast du eigentlich ideale Voraussetzungen eine Schwingungspaketsteuerung zu nutzen.
Optimal wäre ein SSR mit Nulldurchgangsschalter.


Ich habe dein Programm dafür modifiziert.
Code: [Select]

#include <SPI.h>
#include <Wire.h>
#include "Adafruit_MAX31855.h"
#include <LiquidCrystal.h>

#include <PID_v1.h>

// Example creating a thermocouple instance with software SPI on any three
// digital IO pins.
#define MAXDO   14
#define MAXCS   6
#define MAXCLK  15

#define RELAY_PIN 13

// Initialize the Thermocouple
Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO);

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

//******************************
// Regelparameter
//******************************
double Setpoint, Input, Output;

double Kp = 2.0;
double Ki = 0.2;
double Kd = 0.0;

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

unsigned long WindowSize = 5000;

void setup() {
  Serial.begin(9600);

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

  lcd.begin(16, 2);

  lcd.clear();
  lcd.print("MAX31855 test");
  // wait for MAX chip to stabilize
  delay(500);

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

void loop() {

  if (millis() % 1000 == 0) {
    lcd.clear();
    lcd.setCursor(0, 0);

    //*********************************************
    // Ausgabe der Zeit[s] und der Temperatur[°C]
    // auf dem seriellen Monitor
    //*********************************************
    unsigned long zeit = (millis() / 1000);
    Input = thermocouple.readCelsius();
    Serial.print(zeit);
    Serial.print("; ");
    Serial.print(Input);
    Serial.print("; ");
    Serial.print(Output);
    Serial.println(" ms");
    //******************************************

    if (isnan(Input))
    {
      lcd.print("T/C Problem");
    }
    else
    {
      lcd.print("Ist: ");
      lcd.print(Input);
    }

    // Display ausgabe des Regler-Ausgangs
    lcd.setCursor(0, 1);
    lcd.print("Out: ");
    lcd.print(Output);
    lcd.print(" ms");
  }
  // Input = thermocouple.readCelsius();
  myPID.Compute();
  sps(Output);
}

/************************************************
 * turn the output pin on/off based on pid output
 ************************************************/
void sps(double hz)
{
  //https://de.wikipedia.org/wiki/Schwingungspaketsteuerung

  static unsigned long szl;
  static unsigned long szh;
  unsigned long lzl = WindowSize - hz;
  unsigned long lzh = hz;

  if (!digitalRead(RELAY_PIN) && millis() - szl >= lzl ) {
    szh = millis();
    digitalWrite(RELAY_PIN, HIGH);
  }
  if (digitalRead(RELAY_PIN) && millis() - szh >= lzh ) {
    szl = millis();
    digitalWrite(RELAY_PIN, LOW);
  }
}



Der Parameter "WindowSize" gibt die Gesamtdauer eines Schwingungspaketes in ms an.
Der "Output" des Reglers gibt an für welche Zeit in ms das SSR eingeschaltet ist.
Das ist dann Quasi eine PWM-Ausgabe für träge Wechselstromverbraucher wie es Heizungen nun mal sind.
Je nach Trägheit der Regelstrecke kannst du "WindowSize" größer oder kleiner machen um bessere Regelergebnisse zu erzielen.
"Ki" habe ich gefühlsmäßig mal mal etwas schneller gemacht, 0.0005 erschien mir etwas zu träge. Aber ich kenne halt die echte Regelstrecke nicht.

Die Anzeige erfolgt nach wie vor im Sekundentakt, die eigentliche Regelung läuft jetzt aber mit voller Loopgeschwindigkeit.

Nach Möglichkeit kannst du noch das einlesen des Istwertes
Code: [Select]

Input = thermocouple.readCelsius();
aus dem Sekundentakt heraus nehmen und in jeden Loopdurchlauf vor den Regler packen. (Ist im Programm eingebaut aber auskommentiert)


Mit den ganzen theoretischen Berechnungsmethoden (Ziegler&Nichols ect.) für die Reglerparameter konnte ich bisher aus meiner Erfahrung nur 50% Trefferquote erreichen. Theorie und Praxis ist halt meist nicht das Gleiche. Mit etwas Erfahrung hat man "Kp" und "Ki" relativ schnell im Griff. "Kd" kannst du auf 0.0 stehen lassen, es sei den es treten größere Sprünge (Störungen) beim Istwert auf die schnell ausgeregelt werden müssen.
Bei einem Härteofen könnte das öffnen der Tür oder beschicken mit neuem Material solche Störungen verursachen. Dann hängt es aber auch wieder davon ab wie viel thermische Energie im Ofen gespeichert ist im Verhältnis zu der thermischen Trägheit des Härtematerials.

Gruß Peter

Kaum macht man Etwas richtig, funktioniert es auch!

guntherb

Ich habe bei meinen Regler auch immer erst mit (diversen) theoretischen Methoden die Parameter ermittelt.  (mit Wendetangente die besten Ergebnisse erzielt).

Das reicht, für eine gute erste Einstellung.
Aber es muss trotzdem immer von Hand nachjustiert werden. Ich habe den PID-Regler aus dieser Bibliothek in zwei Anwendungen laufen: einen (Holzkohle-)Grillregler der auch sehr langsam ist, und einen Luftfeuchteregler, der ist noch viel langsamer (1 Woche zum einpendeln).

Ich binde zum Zwecke der Abstimmung immer noch die sd.h mit ein und logge alle relevanten Daten (soll, ist, error, p-term, i-therm, out etc) auf SD-Karte.
da kann man dann schön analysieren, und die Parameter nachstellen.
Grüße
Gunther

Elektrometaller

Hallo

vielen Dank schon mal für die Mühe die Ihr reingesteckt habt.

Von einer SP-Steuerung habe ich bisher noch nichts gehört; macht aber sinn. Das SSR hat leider keine Nulldurchgangserkennung (Ist schon etwas älter und ich hab auch nur noch die Nachfolgerdatenblätter gefunden).

Die Parameter die hier noch angegeben waren stammten aus meinem XCOS-Simulationsmodell. Dort hatte ich gute Ergebnisse damit erzielt...aber wie du schon richtig geschrieben hast passt die Theorie und die Praxis nicht immer zusammen. Ich bin auch auf die Störeinflüsse beim öffnen der Tür gespannt. Das habe ich bisher noch nicht berücksichtigt da ich erst das Führungsverhalten in den Griff bekommen wollte.

Die Parameter die ich aus der Wendetangentenmethode ermittelt habe ergaben wie bereits geschrieben einen großen Überschwinger und ein Schwingen in der Strecke.

Ich werden mir bei nächstmöglicher Gelegenheit den Code und die SPS mal genauer ansehen und nachvollziehen und auch auf meinem System ausprobieren. Komme aber vorraussichtlich erst nächste Woche dazu. Nochmals vielen Dank für die detailierte Beschreibung.


Eine Frage kam mir noch bei der if-Abfrage für die Anzeige auf:

Es könnte doch passieren, dass immer kurz bevor millis()%1000 == 00 abgefragt der Rest der Loop ausgeführt wird und so dieser Programmausschnitt niemals ausgeführt wird? Dann würde ja meine Anzeige nie aktualisiert oder?

Viele Grüße

Elektrometaller

peter_de

Hallo Elektrometaller,

die Modulogeschichte für den Sekundentakt ist tatsächlich etwas unglücklich gewählt.
Aber da gibt es genügend andere Möglichkeiten und das bekommst du hin.

Wichtig war mir nur dass
Code: [Select]
  myPID.Compute();
  sps(Output);
außerhalb der langsamen Anzeigeroutine läuft.


Mit einem SSR ohne Nulldurchgangserkennung wird wohl öfter nicht im Nulldurchgang eingeschaltet werden was evtl. zu Netzstörungen führen kann. Besser wäre ein SSR mit Nulldurchgangserkennung.
Bei "WindowSize" = 5000 wird maximal alle 5 Sekunden eingeschaltet. Es hängt von den Gerätschaften in der Umgebung ab ob sich da etwas gestört fühlt. (Lampenflackern z.B.)

Mit der ursprünglichen Relaisausgangs-Variante hättest du aber das gleiche Problem.


Welche el. Leistung hat der Ofen denn?

 
Gruß Peter
Kaum macht man Etwas richtig, funktioniert es auch!

Elektrometaller


peter_de

Der Ofen hat eine Leistung von ca. 1,5kW.
Das ist ja weniger als ein Bügeleisen und das hat auch keinen Nulldurchgangsschalter.
Kaum macht man Etwas richtig, funktioniert es auch!

michael_x

Quote
ein Bügeleisen und das hat auch keinen Nulldurchgangsschalter
Auch kein SSR und keinen PID Regler

Elektrometaller

Guten Abend,

ich habe nun den Code von peter_de ausprobiert und habe die Werte (Zeit, Ist-Temperatur und Reglerausgangsgröße) aufgezeichnet (siehe Bild im Anhang). Sollwert war 100°C. Die Reglerparameter so gewählt, wie vorgeschlagen: Kp = 2; Ki = 0.2; kd = 0.

Mich wundert, dass die Stellgröße zu Beginn so klein ist, sich dann steigert und dann wieder abfällt.
Ich hätte einen sofortigen Sprung in Richtung Reglermaximum erwartet, welches mit Näherung der Temperatur gegen den Sollwert langsam abnimmt.

Ich musste leider aus Zeitmangel den Versuch abbrechen weshalb ich nicht sagen kann, wo sich der Regler eingependelt hätte. Aber ein Überschwinger von mehr als 100°C über dem Sollwert ist für meine Zwecke auch nicht tolerierbar. Jemand noch eine Idee, wie ggf. die Parameter zu ändern sind oder ich den Regler und die Strecke simulieren kann?

Viele Grüße

Elektrometaller

peter_de

Guten Abend,
Kp = 2 hatte ich unverändert aus deinem Eingangspost übernommen und angenommen dass das ein Wert aus Erfahrungen mit deine Regelstrecke ist.

So wie die Kurve jetzt aussieht ist Kp viel zu groß.
Da musst du dich rantasten. Ich würde mal einen Versuch mit Kp = 0.4; und Ki = 0.2; (unverändert) machen.
Die Schwingungspaketsteuerung scheint aber zu laufen?

Temperaturregelungen sind halt meist sehr träge und man muss deshalb viel Zeit in die Optimierung stecken.

Gruß Peter
Kaum macht man Etwas richtig, funktioniert es auch!

Elektrometaller

Kp = 2 hatte ich empirisch mit der Reglersimulation in XCOS ermittelt. Hatte dort damit sehr gute Ergebnisse, die aber in der Praxis absolut nicht gepasst haben.

Ich werd morgen mal einen neuen Versuch starten und berichten. Ich denke aber, dass ich mit dem angepassten Kp besser hinkomme. Vielen Dank nochmals.

Go Up