mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Immer noch Fragen zu PI-Regler


Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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???

Autor: sechsminuszwei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, moeglichweise muss  mal zwischendurch skalieren. Das ist ganz 
normal.

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
also auf wieviel Bit wird sie begrenzt? Welche meiner Überlegungen ist 
denn richtig?

Autor: sechsminuszwei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was ich noch nicht ganz verstehe: wieso auf 128*400??????

Autor: sechs ueber drei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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 ?

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
if(pi_r.Stellwert<65135)  // Begrenzung nach unten, also auf FE60
{pi_r.Stellwert = 65135;} 

if(pi_r.Stellwert>65535)  // Begrenzung nach oben, also auf FFFF
{pi_r.Stellwert =65535;}


Oder hab ich da nen Denkfehler??

Autor: sechs ueber drei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das kann man so machen. Ja.

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist pi_r.Stellwert denn implementiert? Wenn das ein unsigned int 
ist, geht die Abfrage (Begrenzung nach oben) in die Hose.

MW

Autor: sechs ueber drei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dh den Regelbereich von irgendwas kleiner 65k (400*128) erniedrigt man 
auf 400 und addiert diese zu 0xFE60 fuer das Stellglied.

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stellwert ist ein unsigned long int. Wieso geht die Abfrage denn in die 
Hose??

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
<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?

Autor: Michael Wilhelm (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei unsigned long ist alles in Ordnung. Habe ich nur zur Sicherheit 
geschrieben wg. unsigned int.

MW

Autor: sechs ueber drei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Worauf bezieht sich diese Aussage? Was sie an mich gerichtet?

Nee. War n'Furz in den Wind.

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also meine Regler-Funktion schaut jetzt so aus:
unsigned long int Regeln (unsigned long int Istdrehzahl)
{

pi_r.Istwert=Istdrehzahl;
pi_r.Regelabweichung = pi_r.Sollwert-pi_r.Istwert;             // e=w-x
pi_r.I_Anteil = pi_r.I_Anteil+pi_r.Regelabweichung;            // esum=esum+e


//         Reglergleichung  mit Antiwindup

if (Begrenzung==1)
{
pi_r.Stellwert = Kp*pi_r.Regelabweichung;  // ohne Integralanteil
}
else
{
pi_r.Stellwert = Kp*pi_r.Regelabweichung + (Ki*pi_r.I_Anteil)/100;  //y=....
}


//       Begrenzung des Stellenwertes auf die maximale Größe

if(pi_r.Stellwert<65135)    // Begrenzung nach unten, also auf FE60
{
  pi_r.Stellwert = 65135;
  Begrenzung = 1;       // Rergler läuft in der Begrenzung
 
} 

if(pi_r.Stellwert>65535)    // Begrenzung nach oben, also auf FFFF
{
  pi_r.Stellwert =65535;
  Begrenzung = 1;        // Regler läuft in der Begrenzung
}



  
  return pi_r.Stellwert;                    // Übergabe Stellgröße
}


wär nett, wenn ihr noch mal drüber schauen könntet.

Autor: sechs ueber drei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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
}

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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!!

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.
if (!Begrenzung)
    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.

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ mechatroniker : ok, und was macht das Ding dann, wenn ich mich in der 
Begrenzung befinde? Wie errechnet sich dann der I-Anteil??

Autor: sechs ueber drei (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: JÜrgen Grieshofer (Firma: 4CKnowLedge) (psicom) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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....

Autor: der mechatroniker (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ok, und was macht das Ding dann, wenn ich mich in der
> Begrenzung befinde? Wie errechnet sich dann der I-Anteil??

Der bleibt gleich!

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sodala, ich hab ein paar Änderungen vorgenommen und poste den Code jetzt 
noch mal, das mit dem Windup ist auch berücksichtigt.
//*************************************************************************************
//                    Variablen
//*************************************************************************************

//double Ta=0.01
//unsigned long int Stellwert_old = 0;
bit Begrenzung;




//*************************************************************************************
//                    Prototypen
//*************************************************************************************
unsigned long int Regeln (unsigned long int Istdrehzahl); // Funktion zum Aufrufen des Reglers
void PI_Init(void); // Reglerinitialisierung



//*************************************************************************************
//                     Funktionen
//*************************************************************************************
void PI_Init(void)
{         
pi_r.Kp = 18;
pi_r.Ki = 60;
Begrenzung=0;
pi_r.I_Anteil=0;
pi_r.Regelabweichung = 0;

}



unsigned long int Regeln (unsigned long int Istdrehzahl)
{
  pi_r.Istwert=Istdrehzahl;  
  pi_r.Regelabweichung = pi_r.Sollwert-pi_r.Istwert;             // e=w-x

  //         Antiwindup

  if (Begrenzung!=1)
  {
    pi_r.I_Anteil = pi_r.I_Anteil+pi_r.Regelabweichung;            // esum=esum+e

  }

  pi_r.Stellwert = pi_r.Kp*pi_r.Regelabweichung + (pi_r.Ki*pi_r.I_Anteil)/100;  //y=....

  //       Begrenzung des Stellenwertes auf die maximale Größe

  if(pi_r.Stellwert<65135)    // Begrenzung nach unten, also auf FE60
  {
    pi_r.Stellwert = 65135;
    Begrenzung = 1;       // Rergler läuft in der Begrenzung
 
  } 

  else if(pi_r.Stellwert>65535)    // Begrenzung nach oben, also auf FFFF
  {  
    pi_r.Stellwert =65535;
    Begrenzung = 1;           // Regler läuft in der Begrenzung
  }

  else
  {
    Begrenzung =0;
  }

  return pi_r.Stellwert;                    // Übergabe Stellgröße
}

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...:-(

Autor: Kartoffel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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?????

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.