Hallo Ihr, ich steh mal wieder auf dem Schlauch. Versuche gerade einen PI-Regler zu programmieren. Prinzipiell tuts auch. Ich bekomme nur meine Regelabweichung nicht weg. Wenn ich den I-Regler alleine betreibe, dann bleibt auch eine Differenz übrig. Das ganze Regelt die Drehzahl eines Motors. Der Code sieht folgendermaßen aus. Vielleicht hab ich ja einen Dennkfehler drin: global: s32 y_I=0; #define NMAX 3500 #define Kp 0 #define Ki 6 //schwingt bei 7 (besteht eigentlich aus TA*Ki TA ist 1ms) w ist der Sollwert 0-100% x ist der Istwert 0- 30.000 (U/min) im Moment nur bis 4000 U/min u32 closed_loop_control(u32 w, u32 x) { s32 y; //neue Stellgröße s32 e; //Regelabweichung s32 y_P; //Stellgröße des P Anteils //w in Drehzahl umrechnen w = w * NMAX / 100; //Sollwert e = (s32) w - (s32) x; //Drehzahldifferenz zwischen Soll und Ist y_P = Kp * e; //Proportionalwert y_I = Ki * (y_I + e); //alter I-Wert + aktuelle Regelabweichung y_I /= 10; //Ki <1 y = y_P + y_I; /* Rückrechnung auf % */ y = y * 100 / NMAX; if (y > 100) { y = 100; } if (y < 1) { y = 0; } return((u32)y); } Grüße, Michael
Etwas viel leere Rechnung im Code. Indem man die tatsaechliche Drehzahl aussen laesst, und mit dem Messwert rechnet, kann man die Skaliererei ( NMAX/100 ) weglassen. usw. Ich wuerd den code aml im simulator laufenlassen.
Hi ich weiss zwar nicht, ob es das Problem löst aber:
1 | y_I = Ki * (y_I + e); //alter I-Wert + aktuelle Regelabweichung |
ist nicht ganz korrekt. Du solltest eher eine statische Variable errorsum haben:
1 | static s32 errorsum; |
2 | errorsum += e; |
3 | if(errorsum > MAX_ERROR) errorsum = MAX_ERROR; |
4 | if(errorsum < MIN_ERROR) errorsum = MIN_ERROR; |
5 | |
6 | y_I = Ki * errorsum; |
7 | ..
|
Damit wird nur der Fehler mit Ki multipliziert. In deinem Code steckt das ki in y_I drin und wird dann nochmal mit ki multipliziert. Hab jetzt nicht genau auf die signed/unsigned Variablen in deinem Code geachtet, aber das ist auch öfters ein Fehler. Gruß
oder so:
1 | y_I += Ki * e; //alter I-Wert + aktuelle Regelabweichung |
1 | > y_I = Ki * (y_I + e); //alter I-Wert + aktuelle Regelabweichung |
>ist nicht ganz korrekt.
Würde ich so auch nicht machen, ist aber trotzdem (fast) korrekt.
Im alten Wert y_I ist ja die Summe aller vorheriger e's enthalten.
Allerdings darf man nicht alles erneut mit Ki multiplizieren:
1 | y_I = y_I + Ki*e; |
Ich würde mal debuggen, ob die Stellgröße überhaupt mal den Maximalwert erreicht, bzw. ob dieser Maximalwert y = 100 überhaupt in der Lage ist, den Motor auf Solldrehzahl zu bringen!
>Würde ich so auch nicht machen, ist aber trotzdem (fast) korrekt. >Im alten Wert y_I ist ja die Summe aller vorheriger e's enthalten. Naja, das Problem bei der ersten Lösung ist, dass im y_I die Summe aller e's multipliziert mit ki drin ist und dann noch mal multipliziert wird. >Allerdings darf man nicht alles erneut mit Ki multiplizieren: >y_I = y_I + Ki*e; Ja so stimmts.
Suuuper!!! So klappts: y_I = y_I + (Ki * e); //Ki<1 Tausend Dank!! (Der ursprüngliche Code war übrigends aus der Atmel Appnote 194/172...) Viele Grüße, Michael :)
Gibt auch noch eine Appnote AVR221 für einen PID Regler falls du dich noch andersweitig umsehen willst. Greetz Molch
Für Drehzahl ist meist ein PI-Regler besser als PID, bei großem Regelbereich evtl. die Solldrehzahl in die Regelfaktoren einrechnen. Für die Grundlagen recht gut: http://www.roboternetz.de/wissen/index.php/Regelungstechnik gruß hans
Danke für die Tipps. PID geht inzwischen auch. Wie aus dem Lehrbuch, Überschwinger, Regelabweichung, langsam... nun alles eine Frage der richtigen Parameter. Solldrehzahlabhängige Regelfaktoren hatte ich vor. Ohne das wirds nicht ordentlich gehen. Merci!
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.