Forum: Mikrocontroller und Digitale Elektronik PID Regler in C


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von flo (Gast)


Lesenswert?

Hallo,

versuch gerade eine Art Quarzofen zu bauen. Dabei möchte ich über ein 
Heizelement einen kleinen Alu-Block welcher eine Vertiefung für die 
Quarze hat aufheizen und dabei die Temperatur regeln.
Das Heizelement möchte ich gerne mit Hilfe eines Atmega8535 Ports (8 
bit) über eine D/A Wandler (R 2R) und einen MOSFET Regeln.
Die Temperatur bekomme ich von einem DS1620 (Auflösung von 0,5°C)und 
wandle sie in eine Floatzahl.
Jetzt mein Problem habe leider keine genaue Vorstellung wie ich den 
Regler in C implementieren soll und wie ich Kp, Ki, Ta und eventuell Kd 
einstellen soll.
Meine Stellgröße liegt im Bereich zwischen 0 (Heizung aus) und 255 
(Heizung voll angesteuert).
Als Ergebnis soll der eingeschwungene Regler die Heizung gerade so 
ansteuern, dass gerade die Energie wieder zugeführt wird, welche 
Verloren geht.
Vielleicht hat ja jemand eine Idee für die Implementierung.
Vielen Dank im Voraus
Gruß Flo

: Gesperrt durch Moderator
von M. M. (miszou)


Lesenswert?

Hi

Schau mal Atmel nach der application note "AVR221"

Gruß MISZOU

von Simi (Gast)


Lesenswert?

Salü!

Also erst mal... Warum ein D/A Wandler? Das begreife ich nicht ganz... 
Du willst doch wohl nicht den MOSFET mit einem Analogsignal ansteueren 
oder? Da nimmste ein PWM! Sonst kannst Du auswählen, wer heizen soll, 
das Heizelement oder der MOSFET! ;-)

Zur Implementierung in C: Naja, ein PID Regler ist eigentlich ziemlich 
straight-forward:

P-Regler: Nimm den Temperaturfehler, multipliziere ihn mit dem 
"P-Anteil" und gib das zum Ausgang.
I-Regler: Nimm den Temperaturfehler, integriere ihn über die Zeit (also 
aufsummieren), multipliziere das mit dem "I-Anteil" und gib das zum 
Ausgang.
D-Regler: Nimm den Temperaturfehler, differentiere ihn (also jeweils den 
Unterschied zweier aufeinanderfolgender Samples berechnen), 
multipliziere das mit dem "D-Anteil" und gib das zum Ausgang.

PID-Regler: Summiere die drei Ausgänge und dann WIRKLICH zum Ausgang. 
:-)

Einstellen der Werte am besten mit probieren. I würde ich eh gleich 
weglassen.

von Dirk (Gast)


Lesenswert?

kannst den MOSFET ja auch direkt als Heizelement einsetzen, ist dem 
Wesen nach ja ein steuerbarer Widerstand.

Dirk

von Dirk (Gast)


Lesenswert?

noch etwas,
Ich würde den D-Anteil weglassen und nicht den I-Anteil sonst bleibt dir 
immer eine bleibende Regelabweichung stehen. Temperaturregelung ist eh 
eine träge Angelegenheit da hilft dir der D-Anteil nur wenig.

von Andreas Thanheiser (Gast)


Lesenswert?

Regler digital realisieren, geht (so hab ich das mal gelernt) über die 
Z-Transformation. Man kriegt einen Ausdruck für s abhängig von z. Dann 
den Ausdruck für s in die Übertragungsfunktion (im Laplace-Bereich) des 
Reglers einsetzen. Nach z-Potenzen sortieren, Zurücktransformieren in 
den Zeitbereich gibt eine Differenzengleichung, mit welcher der neue 
Ausgabewert aus den zurückliegenden Abtastwerten berechnet werden kann. 
Schwierigster Teil an der Sache ist wohl eher die Zwischenspeicherung 
von Abtastwerten resourcensparend in nem Ringbuffer oder ähnlichem.

Für die Theorie über die z-Transformation empfiehlt es sich natürlich in 
einem Mathebuch nachzuschlagen. Die Umrechnung von Laplace in 
z-Transformierte ist bestimmt in den ein oder anderen 
Regelungstechnik-Büchern genauer beschrieben.

MOSFET als Heizelement ist glaub ich nicht so trivial, weil dadurch die 
Strecke nichtlinear wird. Heizelement über PWM angesteuert ist da schon 
besser.

von Sonic (Gast)


Lesenswert?

Ich würde für eine relativ langsame Regelung wie eine Temperaturregelung 
auch einen PI-Regler bevorzugen, der D-Anteil ist überflüssig.

von Dieter Werner (Gast)


Lesenswert?

Ein PI Regler ist da sicher ausreichend, da bei der kleinen Masse und 
thermisch eng gekoppelter Heizung von einer Regelstrecke erster Ordnung 
(fast ohne Verzugszeit) ausgegangen werden kann.

Außerdem kommt es ja nicht wie z.B. bei einer Motorregelung auf eine 
kurze Einschwingzeit des Systems an, man wartet halt ein paar Minuten 
länger bis Stabilität erreicht ist.

von flo (Gast)


Lesenswert?

Hallo,

Die Rangbedingungen würde ich jetzt gern beibehalten.

Mein Regler Vorschlag sieht jetzt so aus:

float Regler(float IstWert, float SollWert, float Kp, float Ki)
{
  float u_ges, u_p, u_i;
  static float Abweichung=0;

  Abweichung=SollWert-IstWert;

  u_p  = Kp*Abweichung;

  u_i += Ki*Abweichung;

        u_ges = u_p + u_i;

  if (u_ges > 255) u_ges = 255;
  else if (u_ges < 0) u_ges = 0;

  return u_ges;
}

Stimmt dieser Algorithmus, wahrscheinlich muss irgendwie auch noch die 
Abtastzeit rein.
Gruß Flo

von flo (Gast)


Lesenswert?

Hallo MISZOU,

leider komme ich nicht ganz dahinter wie genau die application note 
"AVR221"
funktionieren soll. Gibt es igendwie fertige Funktionen und Dateien wie 
InitPID()?

Gruß Flo

von Michael (Gast)


Lesenswert?

flo
ne dein algorithmus kann nicht stimmen... wo ist bei dir der unterschied 
zwischen dem P- und dem I- Anteil? der wird ja genau gleich berechnet...

Hier kurz und einfach erklärt, müsste für diese einfache anwendung 
reichen...
http://de.wikipedia.org/wiki/Regler#PID-Regler

von flo (Gast)


Lesenswert?

Hallo Michael,
der I-Anteil wird doch anders berechnet.
u_i += Ki*Abweichung; bedeutet ja eigentlich u_i = u_i + Ki*Abweichung,
aber dann sollte vielleicht u_i auch als static float deklariert werden, 
oder?

von Olaf (Gast)


Lesenswert?

Also wenn das ganze einen praktischen Nutzen haben soll so wuerde ich 
den Regler analog aufbauen. Einfach weil kleiner und eleganter.
Ausser natuerlich du machst das aus akademischen Interesse. Dann hast du 
natuerlich jetzt die Moeglichkeit viel zu lernen.

Dazu mal ein paar Tips.

1. Die Idee den Mosfet gleich als Heizelement zu verwenden bietet
   sich an. Zumal man den Quarz vermutlich gleich an die Rueckwand
   anloeten kann.

2. Achte darauf das die maximale Heizleistung deiner Schaltung nur
   etwas ueber dem liegt was du brauchst. Wenn du also deinen Quarz
   auf 60Grad regeln willst dann wuerde ich die Schaltung so auslegen
   das du im Gehaeuse(!) maximal 80Grad bei 100%ED erreichen kannst.
   Das macht deine Regelung einfacher!

3. Achte darauf deinen Temperaturfuehler moeglichst nahe am Heizelement
   zu plazieren. Wenn du die Regelung mal laufen hast kannst du ja
   mal ausprobieren was passiert wenn du den Fuehler weiter entfernst. 
:-)

4. Du musst deinen Quarzofen ja in ein Gehaeuse bauen um ihn gegen
   die Umgebung zu isolieren. Je besser die Isolierung ist um so
   weniger Energie brauchst du spaeter. Aber eine sehr gute
   Isolierung macht wiederum die Regelung komplizierter.

Olaf

von Olaf (Gast)


Lesenswert?

Ich will auch noch mal was zum I-Anteil sagen. .-)

Wenn man eine relativ langsame Strecke hat dann hat der I-Anteil zu 
begin, also nach dem einschalten viel Zeit zu wachsen. Bei einem 
analogen
Regler wird dies dadurch begrenzt das aus einem Operationsverstaerker
nunmal nicht mehr rauskommen kann als wie seine Versorgungsspannung.

Bei einem digitalen Regler jedoch haengt der maximal Wert von der 
Registerbreite ab. Man sollte daher dafuer sorgen das der Wert nicht 
ueber ueber alle Massen wachsen kann.
Es waeren aber auch noch andere Loesungsansaetze denkbar. ZumBeispiel
den I-Anteil erst zuschalten wenn die Regelabweichung schon keiner ist.

Olaf

von Simi (Gast)


Lesenswert?

Oder ein sog. "Anti-Windup". Also den I-Anteil einfach in der Grösse 
begrenzen.

Öh.... ich hab mich schon lange nicht mehr mit Reglern beschäftigt, aber 
so aus dem Bauch raus, würde ich den I-Anteil noch eher als den D-Anteil 
weglassen.

Denn der kleine Regelfehler, der am Schluss übrig bleibt, der... naja, 
ok, das muss man halt schauen, ob der ok ist.

Aber ein D-Anteil kann gerade bei einer Temperaturregelung sehr helfen, 
wenn grosse Störeinflüsse zu erwarten sind und die Strecke sehr träge 
ist. Denn er reagiert einfach früher. Ich musste mal einen 
Wasserkreislauf mit PID regeln. Und da konnte man wunderschön sehen, wie 
der D-Anteil arbeitete. Wasser ist noch zu heiss, aber weil viel Wärme 
abgeführt wird, fällt die Temp gewaltig. Ohne D-Anteil. Der Regler ist 
zufrieden, und erst wenn es schon zu kalt ist, wacht er mal auf und 
fängt an, das Heizelement zu heizen. Bis das dann schön warm war.... 
naja.... Und Vice Versa. Schwingen.

D-Anteil: Es ist noch zu heiss, aber dennoch fängt er an zu heizen. Und 
fängt die Flüssigkeit schön brav bei der Solltemperatur ab.

von Simi (Gast)


Lesenswert?

Ach ja, wegen dem Laplace, Z-Trafo etcet...

Ich will nicht arrogant tönen, ganz ehrlich nicht: Aber aufgrund der 
Fragestellung würde ich schon bei einem PID-Regler bleiben und einem 
empirischen Ansatz bleiben und mich nicht an Laplace, Z-Zeugs etc wagen. 
Das wird mathematisch ziemlich komplex und vor allem abstrakt. Beim PID 
kannst Du Dir alles sehr schön bildlich vorstellen und weisst, was Du 
tust.

von M. M. (miszou)


Lesenswert?

Hi

@flo, ich weiß jetzt nicht genau was du meinst. Hast du dir den Code 
angesehen? Direkt neben dem pdf Symbol ist ein CD Symbol dort findest du 
alle Funktionen.
http://www.atmel.com/dyn/resources/prod_documents/AVR221.zip

Gruß MISZOU

von tom (Gast)


Lesenswert?

Hi,

prinzipiell passt der Code oben scho. Ich persönlich würde folgende 
Dinge anders machen:

-Keine float, sondern normierte Ganzzahlen. (P-Anteil 2Byte, I-Anteil 
4Byte) -> is viel schneller

- wie Olaf schon erwähnt hat I-Anteil unbedingt begrenzen. Es kann 
passieren das sich der I-Anteil sehr stark auf- bzw. abbaut. Bei einem 
VZ-Änderung muß der I-Anteil erst seinen "Speicher" wieder auf- oder 
abbauen und das kann dauern. Also sinnvolle Grenze wählen.

- Mit dem D-Anteil wäre ich persönlich vorsichtig. War bei mir noch nie 
nötig.

- Ich würde mir Gedanken über einen Vorsteueranteil machen. Physikalisch 
kannst Du Dir das so vorstellen. Wenn deine Zieltemeratur erreicht ist, 
mußt Du (wie du oben auch schon gesagt hast) die Energie zuführen, die 
von deiner Streck abgegeben wird. Diese ist theoretisch immer Gleich. -> 
Vorsteueranteil der bei einer gewissen Temperatur immer sofort auf den 
Regelausgang wirkt.

-Auf Z-Ebene würde ich verzichten. Dazu ist das Problem zu trivial um 
nicht im realen Zeitbereich gelöst zu werden.

cu

von Sonic (Gast)


Angehängte Dateien:

Lesenswert?

Hi, habe mir auch mal Gedanken wegen PID-Reglern mit µC gemacht und bin 
aud das Buch 'Mikroprozessoren und Mikrorechner', ISBN 3-486-24431-0 
gestoßen.
Den Teil für den PID-Regler habe ich in ein pdf verfrachtet und mal 
gepostet. Vielleicht hilft's ja jemanden. So ganz einfach ist die Sache 
jedenfalls nicht, wenn man's ordentlich machen will!

von Christoph (Gast)


Lesenswert?

Hallo,
ich misch mal mit...
Also die Formel für den PID-Regler sieht wie folgt aus:

u(t) = Kp ( e(t) + 1/Tn * Integral(e(t) * dt) +Tv * e'(t) )

wobei u(t ) die Stellgröße, e(t) die Regeldifferenz, KR die 
Reglerverstärkung, TN die Nachstellzeit
und TV die Vorhaltzeit ist. (siehe 1 seite vom pdf über mir)

So, das wollen wir in einer zeitdiskreten Form haben. Da nen Rechner nur 
diskrete Werte rechnen kann...
Also wird aus:

Integral(e(t) * dt) => Summe(e(k) ) * delta t // Fläche unter einer 
Kurve
und e'(t) => (e(k) - e(k-1) ) / delta t       // Steilheit einer 
Kurve...

wenn man das in die ürsprüngliche Gleichung setzt und bisschen hin und 
her rechnet (die unendliche Summe z.B. muss man eleminieren) kommt man 
auf:

u(k) = u(k-1) * Kr ( ( (1+Tv)/delta t) * e(k) - (1- delta t /Tn + 
2*Tv/delta t) * e(k-1) + Tv/delta t *e(k-2)  )

Diese obige Formel haut man in eine Programmierzeile. Danach speichert 
man noch u(k-1), e(k-1), e(k-2) für die nächste Rechnung...

Achja:
Kr = Kp ; Tn = Kr/Ki ; Tv = Kd/Kr

Tn = -26 und Tv = 0.16 sind gute richtwerte...

Viel Spaß damit...wer nachlesen will kann sich das obige pdf durchlesen 
:)

Ciao
Christoph

von XC866 (Gast)


Lesenswert?

Hallo

Schau mal hier. Sehr guter Link

http://www.roboternetz.de/wissen/index.php/Regelungstechnik

von Thomas F. (thomas-hn) Benutzerseite


Lesenswert?

Zu den Formeln auf der Seite von Roboternetz, kann mir da jemand 
erklären wie man vom "Differenzengleichung für den zeitdiskreten 
PID-Regler" zum "PID Stellungs-Algorithmus" kommt???
Ich steh da grad auf dem Schlauch.

Danke,

Thomas

von Christoph (Gast)


Lesenswert?

Das Problem bei der Differenzengleichung für den zeitdiskreten 
PID-Regler ist ja die Summe. Man müsste also die Summe immer wieder neu 
berechnen bzw. wird auch mit der Zeit ziemlich groß. Um diese Problem zu 
umgehen macht man folgendes:

Man betrachtet die Gleichung für einen Zeitpunnkt früher, also y(k-1). 
Der D-Anteil wird also zu:
(e(k-1) - e(k-2))/Ta
Die Summe beim I-Anteil wird jetzt von i=0 bis k-1 gezählt.
Der P-Anteil wird einfach zu y(k-1)...

Nun kommt der Trick: Man subtrahiert diese Gleichung von der Gl. für 
y(k).
Also: y(k) - y(k-1)
Was passiert bei der Summe? Folgendes:
Die Summe bei y(k) sieht explizit so aus: e0 + e1+ e2 + ...+e(k)
Die Summe bei y(k-1) hat ein Glied weniger: e0 + e1+  ...+e(k-1)
subrahiert man beide bleibt von den zwei großen Summen nur noch das 
Glied e(k) übrig! Und ist damit für den Rechner geeignet...

Gruß
Christoph

von Thomas F. (thomas-hn) Benutzerseite


Lesenswert?

Ok, nun war das Nachvollziehen möglich...ist ja eigentlich einfach ;-)
Danke nochmals.

Thomas

von Ferdinand (Gast)


Lesenswert?

Hallo,

also ich habe das so gelöst:

//-------- Motor Regelung ------------ //
int MotorRegelung(int *MotorStellwert, int *mmpsDeltaSum, int mmpsSet, 
bool *dir, int *mmpsDeltaBefore, int mmpsAct)
{
  // um
  // mmps
  int mmpsDelta;
  // control
  float Kp = 0.08; // Proportional 0.3
  float Ki = 0.3; // Integral 1.4
  float Kd = 0.005; // Differenziel 0.015
  float Ta = 0.02;

   mmpsDelta = mmpsSet - mmpsAct;
  *mmpsDeltaSum += mmpsDelta;
  *MotorStellwert = (Kp * mmpsDelta) + (Ki  Ta  *mmpsDeltaSum) + (Kd * 
(mmpsDelta - *mmpsDeltaBefore) / Ta);
  *mmpsDeltaBefore = mmpsDelta;

  if(mmpsSet == 0 && abs(mmpsAct) < 3)  // alles auf null wenn Sollwert 
= 0
  {
    *MotorStellwert = 0;
  }

  if(*MotorStellwert >= 0) // Richtung umschalten, Vorzeichen muss 
außerhalb der Funktion gesetzt werden :-))
  {
    *dir = 0;
  }
  else
  {
    *dir = 1;
  }
  return ((mmpsAct));
}

Der Motor treibt ein Antriebsrad. Die Geschwindigkeit messe ich mit 
einem Encoder und durch Umrechnung mit dem Raddurchmesser. Das ganze 
dann natürlich nur alle Ta=0.2 Sekunden in der Void() Schleife aufrufen. 
Dann sollte auch die Geschwindigkeit des Vorschubs stimmen/richtig 
skaliert sein. Die Regelabweichung (mmpsDelta) und die Summe der 
Regelabweichung über Zeit (mmpsDeltaSum) muss für den jeweils nächsten 
Durchlauf außerhalb der Funktion gespeichert werden, daher die Pointer 
(*).
Viel Spaß :-)

Gruß
Ferdinand Rudolph

von Ferdinand (Gast)


Lesenswert?

Entschuldigt, es müsste heißen alle Ta=0.02 Sekunden ausführen!

von Ferdinand (Gast)


Lesenswert?

Am Ausgang steuer ich ein Motorboard an, dieses kann nichts mit 
negativen Motorstellwerten anfangen (die Funktion abs() verwenden) und 
hat dafür einen extra Digitaleingang (hier mit der Variablen "dir" 
angesteuert). Jetzt aber.

von MiWi (Gast)


Lesenswert?

Ferdinand schrieb:
> Am Ausgang steuer ich ein Motorboard an, dieses kann nichts mit
> negativen Motorstellwerten anfangen (die Funktion abs() verwenden) und
> hat dafür einen extra Digitaleingang (hier mit der Variablen "dir"
> angesteuert). Jetzt aber.

^NAch 12 Jahren gräbst Du diese Threadleiche aus? Gehts noch? 
Farbenblind und die rote Warnung nicht gesehen? Dringendes "ich kanns 
aber auch"?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ferdinand schrieb:
> also ich habe das so gelöst:
> ...
> Viel Spaß :-)

Da der ursprüngliche Beitrag geschlagene 11,5 Jahre her ist, hat der TO 
wohl seinen Spaß bereits gehabt ;-)

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.