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
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.
kannst den MOSFET ja auch direkt als Heizelement einsetzen, ist dem Wesen nach ja ein steuerbarer Widerstand. Dirk
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.
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.
Ich würde für eine relativ langsame Regelung wie eine Temperaturregelung auch einen PI-Regler bevorzugen, der D-Anteil ist überflüssig.
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.
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
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
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
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?
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
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
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.
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.
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
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
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!
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
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
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
Ok, nun war das Nachvollziehen möglich...ist ja eigentlich einfach ;-) Danke nochmals. Thomas
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
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.
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"?
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 ;-)