suche fertiger PID-regler

Gast #690106
Lesenswert?

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.
Gast #690134
Lesenswert?

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 #690147
Lesenswert?

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.
#690158
Lesenswert?

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 #690639
Lesenswert?

@ 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 #691149
Lesenswert?

@ 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 #691225
Lesenswert?

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 #691568
Lesenswert?

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 #691576
Lesenswert?

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 #691601
Lesenswert?

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 #691614
Lesenswert?

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 #691623
Lesenswert?

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 #691629
Lesenswert?

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 #691640
Lesenswert?

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! :)
Gast #691647
Lesenswert?

>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 #691649
Lesenswert?

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 #691661
Lesenswert?

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 #691687
Lesenswert?

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?
(Firma: 4CKnowLedge) Persönliche Seite #691710
Lesenswert?

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 #691718
Lesenswert?

>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 #691895
Lesenswert?

>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 #692115
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren