Forum: Mikrocontroller und Digitale Elektronik suche fertiger PID-regler


von Tom (Gast)


Lesenswert?

suche ein fertiges pid.c file! kennt ihr etwas, das man irgendwo 
herunterladen kann?

von Starter (Gast)


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.

von Dieter W. (dds5)


Lesenswert?

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.

von Starter (Gast)


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.

von Dieter W. (dds5)


Lesenswert?

Dann erklär mir doch bitte einmal wie der Term (D*ealt2) zu Null werden 
soll, da ealt2 ja immer die zweitletzte Regelabweichng ist.

von Starter (Gast)


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.

von Starter (Gast)


Lesenswert?


von Dieter W. (dds5)


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.

von Joerg K. (sirfrancisdrake)


Lesenswert?

Also vor geraumer Zeit habe ich hier ein wenig dazu erklärt. Habe die 
Beiträge oben kurz überflogen. Ich glaube auch, dass der Quelltext oben 
nicht ganz richtig ist. Also hier ersteinmal für die Interessierten...

Beitrag "Re: PID- Regler"

von 2921 (Gast)


Lesenswert?

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.

von Thomas (Gast)


Lesenswert?

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

von THM (Gast)


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!

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Also wieso der Double Datentyp?

Braucht meiner Meinung nach einfach zu viel Rechenleistung!! Da ist man 
mit Int auch leicht bedient!


Ausserdem würde ich für den I-Anteil eine Anti-Windup Maßnahme setzen!

von Dieter Werner (Gast)


Lesenswert?

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.

von THM (Gast)


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.

von THM (Gast)


Lesenswert?

OK, hab selber mal gegoogelt. Wird wohl auf AWR (Anti-Windup-Reset) 
'rauslaufen. Werde mich mal dransetzen.
Hier noch ein recht übersichtlicher Link zum Thema:
http://www.energietechnik.fh-dortmund.de/personen/walter/walter/mikrocontroller_infos/Regler_und_Optimierung.htm

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


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" ^^

von Nixvielwissen (Gast)


Lesenswert?

Wie sollte man dann den Sourcecode ändern, um den I-Anteil einzufrieren?

von 2921 (Gast)


Lesenswert?

Na, sobald das Ausgangssignal, aka Stellgroesse, an das Limit kommt, 
wird nicht mehr weiter integriert.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Nixvielwissen wrote:
> Wie sollte man dann den Sourcecode ändern, um den I-Anteil einzufrieren?


Schon mal C programmiert?

von THM (Gast)


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?

von THM (Gast)


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. ;)

von THM (Gast)


Lesenswert?

OK, hab's getestet. So geht's nicht. Werde weitertesten.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


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

von THM (Gast)


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.

von THM (Gast)


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! :)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


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 ^^

von THM (Gast)


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! :)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

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)

von THM (Gast)


Angehängte Dateien:

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

von THM (Gast)


Angehängte Dateien:

Lesenswert?

Und hier MIT anti-Windup.

von THM (Gast)


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.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


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
}

von THM (Gast)


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?

von Sven (Gast)


Lesenswert?

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

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


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 ^^

von THM (Gast)


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 <=.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Wie iniitierst du denn das ganze?

integ muss 0 gesetzt werden sonst nimmt das einen bullsh** an...

Also es muss bei 0 genauso funktionieren deshalb ja integ<=0




Ja, also probiern hat seinen Wert ^^
Bin nich zuhause - also µC-los heul

von THM (Gast)


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.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Ok, d.h. wir belassen es bei den bisherigen Werten... Du hast ja nicht 
mal einen D-Anteil drinnen - hat das einen besonderen Grund?

von THM (Gast)


Lesenswert?

Jo, den D-Anteil brauche ich beim Lüfter nicht, das macht nur die 
Stellgröße 'hibbelig'.

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


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 ^^

von THM (Gast)


Lesenswert?

>und dann ab in die Codesammlung ^^

Da isser schon :-)

von JÜrgen G. (Firma: 4CKnowLedge) (psicom) Benutzerseite


Lesenswert?

Ok schon gesehen ^^

Von Thomas sind dort auch ein paar SEHR interessante Aspekte bezüglich 
Optimierung gekommen...


Vllt teilen wir das ganze in PID_init und in PID_cyclic od. so... Damit 
man sich dann wirklich keine Sorgen machen muss und sonst noch was "dazu 
pfuschen"...

von THM (Gast)


Lesenswert?

Gute Idee, lass' dich nicht aufhalten ! ;)

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
Noch kein Account? Hier anmelden.