suche fertiger PID-regler

Gast
Das wird dir höchstwahrscheinlich nicht viel bringen, kommt darauf an 
was für Eingangs- und Ausgangssignale du hast. PWM? Analog? Wieviel bit? 
AD/DA-Wandler per I²c, SPI, Parallel?

Mit der Berechnung der Stellgröße könnte ich aushelfen, den Rest musst 
du schon selbstanpassen.

In diesem Fall mit Resourcen 'geaast' (double-Variablen), Abtastung alle 
20ms
1
double PID_Berechnung (double x, double w)
2
{
3
e = w - x;  // Regelabweichung ermitteln
4
y = yalt + (Kp*e) + (I*ealt) + (D*ealt2);  // Reglergleichung
5
if (y > 1023)    // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
6
 {
7
  y = 1023;
8
 }
9
if (y < 1)
10
 {
11
  y = 0;
12
 }
13
ealt2 = ealt;    // Regelabweichungs-Historie zuweisen
14
ealt = e;
15
yalt = y;    // Stellgrößen-Historie zuweisen
16
  
17
return y;    // Stellgröße zurückgeben
18
}
e => Regelabweichung
w => Sollwert
x => Istwert
y => Stellgröße
Kp => Proportionalverstärkung
I => Integralverstärkung
D => Differentialverstärkung

Der Schnipsel ist für die Ausgabe über 10-bit-PWM geschrieben und 
funktioniert prima.
Wo ist denn beim D-Anteil die Differenz?

Es sollte m.E. heissen
ealt2 = e - ealt;    // Differenz der Regelabweichungen


Sonst wird der D-Anteil ja nicht 0 bei konstantem e.


EDIT

Und beim Integral ist ja eine Aufsummierung der delta e notwendig.
Gast
ealt und ealt2 werden mit den jeweiligen Differential- und 
Integralverstärkungen multipliziert, das Ganze bezieht sich jeweils nur 
auf die letzten zwei Messwerte.
Der D-Anteil ist auch niemals 0, nur wenn die Regelabweichung über 
längere Zeit genau null ist.
Gast
D*ealt2 wird niemals null, nur wenn der Sollwert null ist. Wie soll denn 
ein Motor/Lüfter/Pumpe o.Ä. laufen, wenn keine Ansteuerung erfolgt? Eine 
gewisse Stellgröße braucht jedes Stellglied, um einen Sollwert zu 
halten.

Die Stellgröße y setzt sich ja aus den drei Anteilen zusammen.
Danke für den Quellenhinweis, nur tauchen die dort genannten 
Rechenschritte

esum = esum + e
y = Kp * e + Ki  Ta  esum + Kd * (e – ealt)/Ta
ealt = e

nur bruchstückhaft und verstümmelt in dem Programm im ersten Post auf.

EDIT
Ich meinte natürlich im ersten Antwortpost.
Gast
Ich denke, wenn man das Thema PID Regler nicht gerafft hat, sollte man's 
eh seinlassen. Und wenn man's gerafft hat, sind die paar Zeilen in ein 
paar Minuten geschrieben.
Gast
Und ich denke, dass jeder einen PID-Regler einsetzen kann, ganz gleich 
ob er ihn verstanden hat oder nicht. Ist wie beim Autofahren, das kann 
auch jeder...
Gast
@ Starter:
Ich habe mir elaubt, den Code vom obigen Antwortposting anzupassen:
1
double PID_Berechnung (double x, double w)
2
{
3
e = w - x;         // aktuelle Regelabweichung bestimmen
4
esum = esum + e;   // Summe der Regelabweichung aktualisieren
5
y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
6
ealt = e;          // Regelabweichung für nächste Abtastung merken
7
if (y > 1023)      // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
8
  {
9
    y = 1023;
10
  }
11
if (y < 1)
12
  {
13
    y = 0;
14
  }
15
return y;          // Stellgröße zurückgeben
16
}
mit
Ta = 0.02 (20ms)
Kp = 18
I  = 16
D  = 0.05

regelt mein Lüfter sauber, schnell und ruhig, ohne großes Zappeln der 
Stellgröße.
Ich bitte um Korrektur, falls ich auf die Schnelle was vergessen habe!
Gast
Für die Regelung einer Lüfterdrehzahl kann man auf den D-Anteil locker 
verzichten, das brauchts nur bei dynamischen Vorgängen wie Positions- 
oder Lageregelung mit Motoren.
Gast
@ JÜrgen G.:
Stimmt schon mit den doubles. Habe ich von oben übernommen, da es nicht 
auf die Rechenleistung ankommt (16MHz, mega32) kann ich die schon 
nehmen. Bei int muss man die Überläufe abfangen (vermeiden), da kommt 
dann auch noch Rechenleistung dazu.
Was meinst du mit Anti-Windup-Maßnahme? Kannst du das Beispiel damit 
ausstatten?

@ Dieter Werner:
Haste Recht. Ich habe grade einen Lüfter mit Reflexkoppler da gehabt, 
darum habe ich den benutzt. Den D-Anteil kann man problemlos weglassen.
(Firma: 4CKnowLedge) Persönliche Seite
Anti Windup meint eigentlich nur den I-Anteil "einfrieren" wenn er über 
die Aussteuerungsgrenzen des Reglers kommt.

Ich hab mir die Website durchgelesen -> kommt auf AWR hin!


Das Problem ohne AWR: Der I-Anteil integriert immer weiter auf, auch 
wenn der Regler auf Anschlag steht, bis das der Datentyp erschöpft ist. 
Wenn jetzt allerdings eine Änderung im System ist, muss der ganze 
I-Anteil wieder runter gerackert werden, bis das er überhaupt mal zu 
Aussteuerungsgrenze kommt und dann erst für den Ausgang wirksam zu 
sinken beginnt...

http://virtual.cvut.cz/dynlabmodules/ihtml/dynlabmodules/syscontrol/img1963.gif

kleine Demonstration was ohne WindUp-Maßnahme sein kann.



Bei dem obigen Source wurde zwar der gesamte Ausgang begrenzt allerdings 
der I-Anteil nicht "vereist" ^^
Gast
1
double PID_Berechnung (double x, double w)
2
{
3
e = w - x;         // aktuelle Regelabweichung bestimmen
4
esum = esum + e;   // Summe der Regelabweichung aktualisieren
5
y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
6
ealt = e;          // Regelabweichung für nächste Abtastung merken
7
if (y > 1023)      // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
8
  {
9
    y = 1023;
10
    Itemp = I;         // I merken
11
    I = 0;             // nicht weiter integrieren
12
    return y;          // Stellgröße zurückgeben
13
}
14
  }
15
else
16
  {
17
    I = Itemp;
18
  }
19
if (y < 1)
20
  {
21
    y = 0;
22
    Itemp = I;         // I merken
23
    I = 0;             // nicht weiter integrieren
24
    return y;          // Stellgröße zurückgeben
25
}
26
  }
27
else
28
  {
29
    I = Itemp;
30
  }
31
return y;          // Stellgröße zurückgeben
32
}
Itemp muss zu Anfang natürlich mit dem Wert von I initialisiert werden.
Sollte das Problem beheben, oder?
Gast
Upps.. so natürlich nicht!
1
double PID_Berechnung (double x, double w)
2
{
3
e = w - x;         // aktuelle Regelabweichung bestimmen
4
esum = esum + e;   // Summe der Regelabweichung aktualisieren
5
y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
6
ealt = e;          // Regelabweichung für nächste Abtastung merken
7
if (y > 1023)      // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
8
  {
9
    y = 1023;
10
    I = 0;             // nicht weiter integrieren
11
    return y;          // Stellgröße zurückgeben
12
}
13
  }
14
else
15
  {
16
    I = Itemp;
17
  }
18
if (y < 1)
19
  {
20
    y = 0;
21
    I = 0;             // nicht weiter integrieren
22
    return y;          // Stellgröße zurückgeben
23
}
24
  }
25
else
26
  {
27
    I = Itemp;
28
  }
29
return y;          // Stellgröße zurückgeben
30
}
So wir deher 'n Schuh draus. ;)
(Firma: 4CKnowLedge) Persönliche Seite
Meine Meinung wär ja sowieso die einzelnen Elemente einzeln zu errechnen 
und dann zu addieren! So kann man sich die Einzelnen Begrenzungen besser 
ansehen & Maßnahmen setzen!



Ich such ma Quellcode... Vllt liegt irgendwo einer rum...


EDIT:

http://www.mstarlabs.com/apeng/techniques/pidsoftw.html

Hier ist der Algo in eine Klasse gepackt... ein wenig umschreiben und 
dann geht...
Gast
Ok, ich habe hier die Aufintegration der Regelabweichung bei 
übersteuerten Stellglied eingefroren. Fonktioniert auch soweit ...
1
double PID_Berechnung (double x, double w)
2
{    
3
e = w - x;                  // aktuelle Regelabweichung bestimmen
4
if ((y <= 1023)&&(y >= 0))
5
  {
6
    esum = esum + e;        // Summe der Regelabweichung aktualisieren  
7
  }
8
y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
9
ealt = e;                   // Regelabweichung für nächste Abtastung merken
10
if (y > 1023)               // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
11
  {
12
    y = 1023;
13
  }
14
    if (y < 1)
15
  {
16
    y = 0;
17
  }
18
return y;
19
}
Die einzelnen Anteile getrennt zu berechnen ist sicher die bessere 
Lösung.
Gast
So jetzt mal ein positives Ergebnis:
1
double PID_Berechnung (double x, double w)
2
{    
3
e = w - x;                  // aktuelle Regelabweichung bestimmen
4
if ((y < 1023)&&(y > 0))
5
  {
6
    esum = esum + e;        // Summe der Regelabweichung aktualisieren  
7
  }
8
y = (Kp*e)+(I*Ta*esum)+(D*((e-ealt))/Ta);  // Reglergleichung
9
ealt = e;                   // Regelabweichung für nächste Abtastung merken
10
if (y > 1023)               // Stellgröße auf 0..1023 begrenzen (10 bit PWM)
11
  {
12
    y = 1023;
13
  }
14
    if (y < 1)
15
  {
16
    y = 0;
17
  }
18
return y;
19
}
Hab's getestet, funktioniert prima! :)
(Firma: 4CKnowLedge) Persönliche Seite
1
unsigned int PID_Berechnung (double x, double w)
2
{
3
    
4
e = w - x;                  // aktuelle Regelabweichung bestimmen
5

6
if ((integ <= 1023)&&(integ >= 0))
7
  {
8
    esum+=e;        // Summe der Regelabweichung aktualisieren  
9
  }
10

11
prop = (Kp*e);   // Proportional Faktor
12
integ = (I*Ta*esum); // Integraler Anteil
13
diff = (D*((e-ealt))/Ta);   // Differenzieller Anteil
14
ealt = e;                   // Regelabweichung für nächste Abtastung merken
15
y = prop + integ + diff;    // Ausgangsstellgröße
16

17
if (y > 1023)               // Stellgröße auf 0..1023 begrenzen(10 bitPWM)
18
  {
19
    y = 1023;
20
  }
21
    if (y < 1)
22
  {
23
    y = 0;
24
  }
25
return y;              // unsigned int weil y nur zwischen 0 und 1023
26
}


So falls Fehler drinne sind melden ^^

Habs nur ein wenig leichter gemacht... In Bezug auf Aufteilung... Vllt 
optimier ich den Code auch noch ein wenig...

EDIT:
@THM: Wenn du wie e Begrenzung durch y machst, kann der I-Anteil nicht 
wirken, während der D-Anteil voll aufdreht... Deswegen NUR das integral 
begrenzen ^^
Gast
Ich habe bei übersteuertem Stellglied nur esum eingefroren. Dadurch kann 
nicht mehr integriert werden. Die anderen Parameter bleiben davon 
unberührt.
Ich hab's auf meiner Hardware laufen, der Unterschied zu vorher ist 
Welten besser! :)
(Firma: 4CKnowLedge) Persönliche Seite
THM wrote:

> Ich hab's auf meiner Hardware laufen, der Unterschied zu vorher ist
> Welten besser! :)


Immer gern xP

WENN REGELEN dann RICHTIG ^_^


So aber nun zur Optimierung... Die Datentypen gefallen mir nicht 
wirklich... Ich hab doch nur einen 10bit AD-Wandler also zurück zu 
signed INT (16bit)
Gast
>Die Datentypen gefallen mir nicht
Jo, mir auch nicht! ;) Das kommt als nächstes.

Zur Visualisierung mal den Unterschied des Regelverhaltens.
In diesem Bild OHNE anti-Windup.

Grün => Stellgröße
Rot => Sollwert (70 Hz)
Weiß => Istwert

Der Lüfter gibt eine Frequenz von 0 bis max 140 Hz zurück
Angehängte Dateien:
Gast
Achso, zur Erklärung:
Ich ahbe den Lüfter für ca. 2s angehalten und wieder losgelassen. Im 
Bild mit anti-Windup sieht man, dass der 1. Überschwinger deutlich 
kleiner ist. Ohne Anti-Windup wird er umso größer, je länger ich den 
Lüfter anhalte.
(Firma: 4CKnowLedge) Persönliche Seite
1
// W, X, Y in INT  - Eingänge mit Vorzeichen
2
// interne Variablen sollten dennoch in double gehalten werden (Gleitkommadarstellung)
3

4
unsigned int PID_Berechnung (signed int x, signed int w)
5
{
6
    
7
e = w - x;                  // aktuelle Regelabweichung bestimmen
8

9
if ((integ <= 1023)&&(integ >= 0))
10
  {
11
    esum+=e;        // Summe der Regelabweichung aktualisieren  
12
  }
13

14
prop = (Kp*e);   // Proportional Faktor
15
integ = (I*Ta*esum); // Integraler Anteil
16
diff = (D*((e-ealt))/Ta);   // Differenzieller Anteil
17
ealt = e;                   // Regelabweichung für nächste Abtastung merken
18
(unsigned int) y = prop + integ + diff;    // Ausgangsstellgröße
19

20
if (y > 1023)               // Stellgröße auf 0..1023 begrenzen(10 bitPWM)
21
  {
22
    y = 1023;
23
  }
24
    if (y < 1)
25
  {
26
    y = 0;
27
  }
28
return y;              // unsigned int weil y nur zwischen 0 und 1023
29
}
Gast
Sieht doch schon besser aus ;)
nur glaube ich dass
1
if ((integ <= 1023)&&(integ >= 0))
nicht funtioniert, da sonst die nachfolgende Begrenzung der Stellgöße 
diese Bedingung immer erfüllt.
Besser wäre
1
if ((integ < 1023)&&(integ > 0))
oder hast du's schon ausprobiert?
Gast
> (unsigned int) y = prop + integ + diff;    // Ausgangsstellgröße

Sorry, müsste das nicht

y = (unsigned int)(prop + integ + diff);

heissen ?

Ich lerne gerne dazu....

Gruß Sven
(Firma: 4CKnowLedge) Persönliche Seite
Sven wrote:
>> (unsigned int) y = prop + integ + diff;    // Ausgangsstellgröße
>
> Sorry, müsste das nicht
>
> y = (unsigned int)(prop + integ + diff);
>
> heissen ?
>
> Ich lerne gerne dazu....
>
> Gruß Sven


sorry... stimmt... wollen ja ANSI C proggen... geht nur in C++ !!!


@THM: Das stimmt schon so... Ich muss ja das ganze "Spektrum" vom 
I-Anteil ausnützen können... und ich fange mit 0 an -> also integ<=0


Ich probiere nicht aus, weil ich keinen µC grad bei der Hand hab -> muss 
ja so auch gehn ^^
Gast
>Ich probiere nicht aus, weil ich keinen µC grad bei der Hand hab
Aber ich! :)

Mit größer-gleich geht's nicht. Mit größer schon.

Das Problem ist, wie erkenne ich ob der Ausgang übersteuert ist (z.B. 
1028) oder ob er bei genau 1023 ist. Das geht nur, wenn ich ein Bit 
abziehe. Darum der 'größer', bzw. 'kleiner'-Verleich anstatt >=, bzw <=.
Gast
>Wie iniitierst du denn das ganze?
Kp = 18;
I = 12;
D = 0;
w = 50;
Den ganzen Rest mit 0.

Also esum ist ja das Element, das integriert wird. Wenn ich dieses 
einfriere, also den Wert bei überschreiten der Übersteuergrenze (0 und 
1023) halte (nicht 0 setzen!), dann bleibt esum außerhalb der 
Übersteuergrenzen auf einem konstanten Wert und der Regler 'fängt' sich 
bei Rückkehr in den Regelbereich an dem Punkt wieder, an dem das 
Stellglied übersteuert wurde. Von dort arbeitet er wieder korrekt.
Wenn du integ auf 0 setzt fängt das ganze furchtbar an zu schwingen, 
sobald einmal die Übersteuergrenze überschritten war.
(Firma: 4CKnowLedge) Persönliche Seite
Naja, D-Anteil kann das wahre Wunder bringen... Allerdings auch sehr 
gefährlich werden ^^

1
// W, X, Y in INT  - Eingänge mit Vorzeichen
2
// interne Variablen sollten dennoch in double gehalten werden (Gleitkommadarstellung)
3

4
unsigned int PID_Berechnung (signed int x, signed int w)
5
{
6
    
7
e = w - x;                  // aktuelle Regelabweichung bestimmen
8

9
if ((integ < 1023)&&(integ > 0))
10
  {
11
    esum+=e;        // Summe der Regelabweichung aktualisieren  
12
  }
13

14
prop = (Kp*e);   // Proportional Faktor
15
integ = (I*Ta*esum); // Integraler Anteil
16
diff = (D*((e-ealt))/Ta);   // Differenzieller Anteil
17
ealt = e;                   // Regelabweichung für nächste Abtastung merken
18
y = (unsigned int)(prop + integ + diff);    // Ausgangsstellgröße - casten auf unsigned int
19

20
if (y > 1023)               // Stellgröße auf 0..1023 begrenzen(10 bitPWM)
21
  {
22
    y = 1023;
23
  }
24
    if (y < 1)
25
  {
26
    y = 0;
27
  }
28
return y;              // unsigned int weil y nur zwischen 0 und 1023
29
}

So jetzt mal der fertige Regler... THM - bitte noch mal drübersehn... 
und dann ab in die Codesammlung ^^

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 19 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.