Hallo Leute, also ich habe schon vor paar Tagen ein paar Fragen zum Thema PI-Regler in C programmieren gehabt, siehe: [[Beitrag "PI-Regler für GS-Motor"]] Einiges ist mir noch überhaupt nicht klar. Ich möchte einen Gleichstrommotor regeln. Angetrieben wird dieser Motor mit PWM, ich hab es so realisiert, dass ich einen Timer mitlaufen lasse mit Reloadregister= FCE0. Bei bestimmten Ereignissen hab ich dann nen Signalwechsel an den Pins, die dann zum Motortreiben führen. Also am Anfang sag ich: P6 = 0, P7 = 1; wenn der Timerwert mit einem Registerwert CC30 übereinstimmt (compare mode), dann P6=1, P7 =0; wenn der Timer abgelaufen ist, dann wieder P6 =0, P7 =1 usw. Das heißt mein Signal hat eine Periode von FFFF-FCE0 und die Breite der pos. Periode ist Wert von CC30-FCE0. Wenn die Breite des pos. Impulses = Breite des neg. Impulses (FFFF-FCE0)/2 = 400dez , dann dreht sich der Motor nicht, denn der Effektivwert der Spannung = 0V. (falls das einer kritisch hinterfragen mag, das ist wirklich so, ich hab es schon ausprobiert). Mit der Stellgröße des Reglers möchte ich Einfluß auf PWM nehmen, d.h. die Breite des pos. Impulses beeinflussen und zwar nur des pos. Imp. weil mein Motor sich nur in eine Richtung drehen muss. Eingentlich müsste ich die Stellgröße auf 2^16 begrenzen, weil sich sich ja aus der Differenz zweier Registerinhalte berechnet, allerdings und jetzt kommt endlich die Frage: meine Stellgröße bewegt sich nur im Bereich zw. 400dez und 800dez, denn sonst würd sich der Motor ja in andere Richtung drehen. Also müsste ich die doch nur auf 1024 begrenzen, oder???? Später verwende ich sie in einer unsigned long int variable, also vielleicht doch auf 2^16 begrenzen???
Ja, moeglichweise muss mal zwischendurch skalieren. Das ist ganz normal.
also auf wieviel Bit wird sie begrenzt? Welche meiner Überlegungen ist denn richtig?
Alle. Die Rechnung hat einen Raum von 2^16, genannt Integer. Macht Sinn. Das Stellglied ist schon bei 400+400 am Anschlag. Du willst nur positiv aussteuern. Dann ist der Steuerbereich noch 400. Dann wuerde ich den Rechenbereich auch auf 128 * 400 begrenzen. Man bildet den 2^16er Raum auf 400 ab und zaehlt noch 400 dazu. Nein ? If (Rechnung > 128*400) then Rechnung:=128*400; Stellglied:= 400+ Rechnung div 128; Das div 128 ist dasselbe wie Rechtsschieben 7
Wir erniedrigen den Wertebereich von kleiner 65535 auf 400, am Guenstigsten ist mit 128 dividieren. Eine Division mit 128 ist sieben Stellen nach rechts schieben. Damit wir nicht zuviel bekommen bBegrenzen wir zuerst auf 128*400. Alles was groesser ist wird auf 128*400 gesetzt. Nach der Division erhalten wir somit als maximum 400. Nein ?
Also 400dez ist ja (FFFF-FCE0)/2. Bei FCE0 fängt mein Timer an zu zählen. Wenn der WErt des Timers den im CC1_C30 entspricht, gibt es nen Interrupt und nen Flankenwechsel. Ich hab mir überlegt die Pulsbreite des PWM-Singales mit HIlfe von CC1_C30 zu steuern. Das heißt der Wert in diesem Register wird in Abhängigkeit der Stellgröße gesetzt. So wie ich es verstanden hab, ist die Stellgröße die Pulsbreite. Der Wert des CC1_c30 darf sich nur im Bereich zwischen FE6F und FFFF bewegen. Die Differenz beträgt dann genau 400dez. Also hab ich die Stellgröße so begrenzt: // Begrenzung des Stellenwertes auf die maximale Größe
1 | if(pi_r.Stellwert<65135) // Begrenzung nach unten, also auf FE60 |
2 | {pi_r.Stellwert = 65135;} |
3 | |
4 | if(pi_r.Stellwert>65535) // Begrenzung nach oben, also auf FFFF |
5 | {pi_r.Stellwert =65535;} |
Oder hab ich da nen Denkfehler??
Wie ist pi_r.Stellwert denn implementiert? Wenn das ein unsigned int ist, geht die Abfrage (Begrenzung nach oben) in die Hose. MW
Dh den Regelbereich von irgendwas kleiner 65k (400*128) erniedrigt man auf 400 und addiert diese zu 0xFE60 fuer das Stellglied.
Stellwert ist ein unsigned long int. Wieso geht die Abfrage denn in die Hose??
<Dh den Regelbereich von irgendwas kleiner 65k (400*128) erniedrigt man auf 400 und addiert diese zu 0xFE60 fuer das Stellglied.> Worauf bezieht sich diese Aussage? Was sie an mich gerichtet?
Bei unsigned long ist alles in Ordnung. Habe ich nur zur Sicherheit geschrieben wg. unsigned int. MW
>Worauf bezieht sich diese Aussage? Was sie an mich gerichtet?
Nee. War n'Furz in den Wind.
Also meine Regler-Funktion schaut jetzt so aus:
1 | unsigned long int Regeln (unsigned long int Istdrehzahl) |
2 | {
|
3 | |
4 | pi_r.Istwert=Istdrehzahl; |
5 | pi_r.Regelabweichung = pi_r.Sollwert-pi_r.Istwert; // e=w-x |
6 | pi_r.I_Anteil = pi_r.I_Anteil+pi_r.Regelabweichung; // esum=esum+e |
7 | |
8 | |
9 | // Reglergleichung mit Antiwindup
|
10 | |
11 | if (Begrenzung==1) |
12 | {
|
13 | pi_r.Stellwert = Kp*pi_r.Regelabweichung; // ohne Integralanteil |
14 | }
|
15 | else
|
16 | {
|
17 | pi_r.Stellwert = Kp*pi_r.Regelabweichung + (Ki*pi_r.I_Anteil)/100; //y=.... |
18 | }
|
19 | |
20 | |
21 | // Begrenzung des Stellenwertes auf die maximale Größe
|
22 | |
23 | if(pi_r.Stellwert<65135) // Begrenzung nach unten, also auf FE60 |
24 | {
|
25 | pi_r.Stellwert = 65135; |
26 | Begrenzung = 1; // Rergler läuft in der Begrenzung |
27 | |
28 | }
|
29 | |
30 | if(pi_r.Stellwert>65535) // Begrenzung nach oben, also auf FFFF |
31 | {
|
32 | pi_r.Stellwert =65535; |
33 | Begrenzung = 1; // Regler läuft in der Begrenzung |
34 | }
|
35 | |
36 | |
37 | |
38 | |
39 | return pi_r.Stellwert; // Übergabe Stellgröße |
40 | }
|
wär nett, wenn ihr noch mal drüber schauen könntet.
Einige Unguenstigkeiten. -Die Begrenzung wird nie aufgehoben. -die div 100 ist nicht gut, mach 128. Nee das wird nichts. Bei welchem Fehler beginnt sich die Stellgroesse zu bewegen ? Mach : pi_r.Stellwert= 0xFE60 + Kp*pi_r.Regelabweichung; .. Begrenzung =0; if(pi_r.Stellwert<0xFE60) // Begrenzung nach unten, also auf FE60 { pi_r.Stellwert = 0xFE60; Begrenzung = 1; // Rergler läuft in der Begrenzung } if(pi_r.Stellwert>0xFFFF) // Begrenzung nach oben, also auf FFFF { pi_r.Stellwert =0xFFFF; Begrenzung = 1; // Regler läuft in der Begrenzung }
also die Begrenzung hab ich aufgehoben, da hattest du völlig Recht. Die Division durch 100 hat eigenlich andere Bewandnis und zwar ist das meine Ta von 0.01. Ich dividiere duch 100, weil ich beim Multiplizieren der int mit Zahlen < 0 schlechte Karten hab. <Mach : pi_r.Stellwert= 0xFE60 + Kp*pi_r.Regelabweichung; ..> Wo kommt deiner Meinung nach dieser Therm hin? Und wieso soll ich nach unten bis FE60 begrenzen? Ich meine, es ist bis FE6F!!
Dein Antiwindup ist Mist. Man läßt den Integralanteil nicht schlagartig komplett weg, wenn man in der Begrenzung ist (woraufhin dann keine Begrenzung mehr da ist, also wieder rein, wieder raus, wieder rein...), sondern begrenzt ihn.
1 | if (!Begrenzung) |
2 | pi_r.I_Anteil = pi_r.I_Anteil+pi_r.Regelabweichung; // esum=esum+e |
Die andere if-Abfrage und die Formel ohne I-Anteil muß raus.
@ mechatroniker : ok, und was macht das Ding dann, wenn ich mich in der Begrenzung befinde? Wie errechnet sich dann der I-Anteil??
Meine Punkte. -Kostanten so schreiben wie sie sind. HexKonstanten in Hex. -Die Regel Berechnung und das Stellglied trennen. Lieber der Uebersichtlichkeit halber nochmals eine zusaetzliche Zeile. In dem Falle die Regelung zwischen 0 und irgendwas rechnen, dann auf Herunterskalieren auf die 0 bis 400 und dann zum Wert FE6F hinzuzaehlen. Ich denke dieser Wert ist sowieso dynamisch, dh Temperatur- und allenfalls Betriebsdspannungsabhaengig.
Kartoffel wrote: > ok, und was macht das Ding dann, wenn ich mich in der > Begrenzung befinde? Wie errechnet sich dann der I-Anteil?? bin zwar kein mechatroniker aber hab trotzdem einen PID Regler gecoded... Also, wenn du in der Begrenzung bist tut der gar nichts mehr (der I Anteil). Allerdings könnte ich dir ein wenig support geben wenn du meinen Code aus der Codesammlung verwenden würdest... ^^ lg
@ JÜrgen G. und alle anderen: Also laut deiner Aussage stimmt ja dann die Aussage des "mechatronikers" nicht und mann kann den I-Anteil in der Begrenzung schon weg lassen oder? Wenn nicht, also dann weiß ich überhaupt nicht, wie ich den Windup verhindern kann....
> ok, und was macht das Ding dann, wenn ich mich in der > Begrenzung befinde? Wie errechnet sich dann der I-Anteil?? Der bleibt gleich!
sodala, ich hab ein paar Änderungen vorgenommen und poste den Code jetzt noch mal, das mit dem Windup ist auch berücksichtigt.
1 | //*************************************************************************************
|
2 | // Variablen
|
3 | //*************************************************************************************
|
4 | |
5 | //double Ta=0.01
|
6 | //unsigned long int Stellwert_old = 0;
|
7 | bit Begrenzung; |
8 | |
9 | |
10 | |
11 | |
12 | //*************************************************************************************
|
13 | // Prototypen
|
14 | //*************************************************************************************
|
15 | unsigned long int Regeln (unsigned long int Istdrehzahl); // Funktion zum Aufrufen des Reglers |
16 | void PI_Init(void); // Reglerinitialisierung |
17 | |
18 | |
19 | |
20 | //*************************************************************************************
|
21 | // Funktionen
|
22 | //*************************************************************************************
|
23 | void PI_Init(void) |
24 | {
|
25 | pi_r.Kp = 18; |
26 | pi_r.Ki = 60; |
27 | Begrenzung=0; |
28 | pi_r.I_Anteil=0; |
29 | pi_r.Regelabweichung = 0; |
30 | |
31 | }
|
32 | |
33 | |
34 | |
35 | unsigned long int Regeln (unsigned long int Istdrehzahl) |
36 | {
|
37 | pi_r.Istwert=Istdrehzahl; |
38 | pi_r.Regelabweichung = pi_r.Sollwert-pi_r.Istwert; // e=w-x |
39 | |
40 | // Antiwindup
|
41 | |
42 | if (Begrenzung!=1) |
43 | {
|
44 | pi_r.I_Anteil = pi_r.I_Anteil+pi_r.Regelabweichung; // esum=esum+e |
45 | |
46 | }
|
47 | |
48 | pi_r.Stellwert = pi_r.Kp*pi_r.Regelabweichung + (pi_r.Ki*pi_r.I_Anteil)/100; //y=.... |
49 | |
50 | // Begrenzung des Stellenwertes auf die maximale Größe
|
51 | |
52 | if(pi_r.Stellwert<65135) // Begrenzung nach unten, also auf FE60 |
53 | {
|
54 | pi_r.Stellwert = 65135; |
55 | Begrenzung = 1; // Rergler läuft in der Begrenzung |
56 | |
57 | }
|
58 | |
59 | else if(pi_r.Stellwert>65535) // Begrenzung nach oben, also auf FFFF |
60 | {
|
61 | pi_r.Stellwert =65535; |
62 | Begrenzung = 1; // Regler läuft in der Begrenzung |
63 | }
|
64 | |
65 | else
|
66 | {
|
67 | Begrenzung =0; |
68 | }
|
69 | |
70 | return pi_r.Stellwert; // Übergabe Stellgröße |
71 | }
|
Ich meine, jetzt passt es einigermaßen...das mit dem Skallieren kommt no. Allerdings hab ich jetzt ne Warnung beim Aufrufen der Fkt. PI_Init. Ich ruf sie in main vor der Endlosschleife auf. Hab es auch schon probiert, die Fkt. als extern zu deklarieren, dat geht au net...:-(
Weiter im Text. Ach übrigens, das mit der Fkt. PI_Init hab ich behoben. Also : Der Stellwert. Was sagt er mir denn genau bei einem PWM-Singal. Zur Erinnerung: ich bewege mich in einem Bereich zwischen 400 und 800 (Pulsbreite). Bei 400 steht der Motor, bei 800 dreht er voll auf. Also ich berechne mich meiner Reglergleichung den Stellwert. Also ich hab da noch Probleme zu verstehen was der genau darstellt. Ist das eine Zahl im Bereich zwischen 400 und 800? Die Pulsbreite steuer ich ja mit einem Register. Muss dann der neu errechnete Reglerstellwert in dieses Register reingeschrieben werden?????
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.