PID-Regler-Implementierung

Gast #5674334
Lesenswert?

Hi,

ich möchte auf einem Mikrocontroller einen PID-Regler implementieren: 
abhängig von einem analogen Eingangswert (0..1023) soll ein 
Digitalausgang an- oder ausgeschaltet werden.

Der Hardwareteil ist kein Problem, ich würde jetzt nur eine fertige 
PID-Implementierung suchen, bei der man entsprechende Parameter 
dynamisch übergeben kann (um das Rad nicht noch mal komplett neu 
erfinden zu müssen).

Deswegen meine Frage: kennt jemand eine passend Implementierung in C?

Danke!
Gast #5674384
Lesenswert?

An sich ist das eine ganze einfache Gleichung, die man in C oder den 
meisten höheren Programmiersprachen nahezu wortwörtlich hinschreiben 
kann.

Der folgende Halbsatz: "... bei der man entsprechende Parameter
dynamisch übergeben kann (um das Rad nicht noch mal komplett neu
erfinden zu müssen)."
deutet an, dass für Dich dennoch ein Problem zu bestehen scheint.

Der einzige Anhaltspunkt scheint mir das Wort "dynamisch" zu sein. Kann 
es sein, dass Du auch die Reglerparameter programmatisch bestimmen 
willst?

Vielleicht schreibst Du mal ausführlicher, worum es Dir geht.
Gast #5674393
Lesenswert?

Stokmarknes schrieb:
(um das Rad nicht noch mal komplett neu
> erfinden zu müssen).

Nenn das Kind doch beim Namen: Weil du dich nicht mit programmieren oder 
der Mathematik dahinter beschäftigen willst.
Das sollte wie oben beschrieben kein Problem sein, denn das gibts 
bestimmt schon tausend mal im Netz

Stokmarknes schrieb:
> bei der man entsprechende Parameter
> dynamisch übergeben kann

Was meinst du damit. Es sollte ja kein Problem sein, daß die Konstanten 
als 8 oder 16 Bit Werte in einer Speicherzelle stehen.
Willst du sie jetzt im Programm verändern können und neu flashen oder 
sollen sie während des Programmablaufs geändert werden?
Und wenn, dann wie? Mit Potis? Mit einer RS232 Terminalanbindung? ...

Und hier wirds schwieriger mit einem fertigen Programm
Gast #5674433
Lesenswert?

Theor schrieb:
> Der einzige Anhaltspunkt scheint mir das Wort "dynamisch" zu sein. Kann
> es sein, dass Du auch die Reglerparameter programmatisch bestimmen
> willst?

Genau das, es geht um eine generische Implementierung, bei der der 
Anwender die (PID-)Parameter entsprechend seiner Umgebung selber 
verändern kann.
Gast #5674440
Lesenswert?

Stokmarknes schrieb:
> Theor schrieb:
>> Der einzige Anhaltspunkt scheint mir das Wort "dynamisch" zu sein. Kann
>> es sein, dass Du auch die Reglerparameter programmatisch bestimmen
>> willst?
>
> Genau das, es geht um eine generische Implementierung, bei der der
> Anwender die (PID-)Parameter entsprechend seiner Umgebung selber
> verändern kann.

Das sind nach meinem Verständnis zwei verschiedene Vorgänge.
Einmal ist der Anwender der Akteur, im anderen Fall das Programm.

1. Der Anwender verändert die Parameter.
Das würde an meiner Grundaussage nichts ändern. Die PID-Gleichung ist 
einfach hin zu schreiben. Hinzufügen ist nur eine Eingabemöglichkeit.
Das ist sehr einfach und völlig unproblematisch - was das Programm 
betrifft.

2. Das Programm ermittelt (bestimmt) die Parameter.
Das ist schon wesentlich komplizierter.
#5674591
Lesenswert?

Christopher J. schrieb:
> Für letzteres
> gibt es viele Möglichkeiten, da musst du schon eher sagen wo es hingehen
> soll. Drehencoder mit Display, UART-Terminal, rein analoge Drehpoties...

Jemand, der mit der Materie erst anfängt, weiß zunächst noch gar nicht,
womit er(sie) anfangen soll und fragt deshalb hier im Forum, was für 
einen Anfänger am einfachsten umzusetzen ist. (Stichwort: Fahrrad neu 
erfinden)
Gast #5675943
Lesenswert?

Meine Fresse, seitenweise großkotzige Selbstdarstellung aber nicht eine 
einzige Antwort dabei, die irgendwie weiter helfen würde. Was habt ihr 
alle für ein Problem mit eurem Ego? Seid und dürft ihr im realen Leben 
sonst nix? Könnt ihr euch nicht lieber einen SUV kaufen statt hier 
rumzuprollen?

An den Thread-Opener: schau dir mal 
https://homepages.uni-regensburg.de/~erc24492/PID-Regler/AVR221/IAR/doxygen/pid_8c.html 
an, ich habe zwar keine Idee, was die Reset-Funktion machen soll, aber 
das dürfte das sein, was du suchst.
(Firma: matzetronics) #5675952
Lesenswert?

Zorg3000 schrieb:
> aber nicht eine
> einzige Antwort dabei, die irgendwie weiter helfen würde.

Doch, natürlich sind da brauchbare Antworten bei. Hier ist z.B. eine:

M. K. schrieb:
> AVR221 von Atmel. Sehr empfehlenswert ;)
Man sollte vllt. noch erwähnen, das damit eine Application Note von 
Atmel/Microchip und eine Impementation in C gemeint ist.

Und noch eine:
Bastler schrieb:
> Schon mal bei Arduino nachgeschaut?
>
> https://playground.arduino.cc/Code/PIDLibrary

Du Spassvogel verlinkst ja selber auf die AVR221:

Zorg3000 schrieb:
> An den Thread-Opener: schau dir mal
> 
https://homepages.uni-regensburg.de/~erc24492/PID-Regler/AVR221/IAR/doxygen/pid_8c.html


Zorg3000 schrieb:
> ich habe zwar keine Idee, was die Reset-Funktion machen soll

Es ist sinnvoll, nach einer Änderung von P,I oder D den Regler 
zurückzusetzen. Schadet auch nicht bei der Initialisierung.
Einfach mal AVR221 lesen.
Gast #5676492
Lesenswert?

Hallo,

hab den Rest der Beiträge nicht gelesen, aber hab mir mal die Formeln 
aus Wikipedia besorgt und nach programmiert ggf hilft es dir ja.

float PIDRegler(float T1,float T2)    // PID-Regler
{
  // Empfindlichkeit des PID-Reglers

float Tn = 1.0;      // dient zur Einstellung des PID Reglers
float Tv = 1.0;      // dient zur Einstellung des PID Reglers
float Kp = 1.0;      // dient zur Einstellung des PID Reglers

  // Variablen für P,I,D
float P,I,D;

  // Zeitkostente
float delta_t=0.5;


En = T1 - T2;       // T1 = Temperatur_1 = Sollwert hier
                    // T2 = Temperatur_2 = Istwert
                    // En = Regelabweichung

// Berechnugn P I D
P = En - en1;
D = (delta_t / Tn) * En;
I = Tv * (En - 2 * en1 + en2);

// Berechnung neuer Stellgröße
delta_y = Kp * ( P + D + I);
Yn = yn1 + delta_y;

// Speichert alte Werte
en2 = en1;
en1 = En;
yn1 = Yn;

// Begrenzt Yn auf 100
if (Yn > 100.0) Yn=99.99;
if (Yn <   0.0) Yn=  0.0;


return Yn;          // Gibt Stellgröße zurück und springt ins 
Hautprogramm zurück
}

DIE FUNKTION MUSS ALLE 0.5 SEKUNDEN AUFGERUFEN WERDEN DAS ES 
FUNKTIONIERT.

falls du dich nicht so auskennst. TV, TN , KP kann man nachgoogln .. zu 
not auch der Funktion übergeben.

Hoffe konnte dir helfen.

Gruß
Gast #5676550
Lesenswert?

P.s

Bei meinem alten Programm sind en1,en2, etc als Globale Varirablen 
deklaiert. Endweder machst du das auch oder deklaierst die in der 
Funktion mit -> static da die Werte beim wiederaufruf vorhanden sein 
müssen.

static float en1,en2,etc.;

oder vorm Hauptprogramm

float en1,en2,etc.;

Gruß
#5676615
Lesenswert?

Michael V. schrieb:
> aber hab mir mal die Formeln aus Wikipedia besorgt und nach programmiert
> ggf hilft es dir ja.

Wobei erwähnt werden sollte, dass das lediglich für einfache/träge 
Strecken erfolgreich ist, auf diese gezeigte Weise von analog auf 
digital umzusteigen.

Wenn phasenreserve und Dynamik kritisch sind, wird meist Tustin 
Transformation (bilinear Transformation) verwendet.

Gruß,
#5676652
Lesenswert?

Al3ko -. schrieb:
> Wobei erwähnt werden sollte, dass das lediglich für einfache/träge
> Strecken erfolgreich ist, auf diese gezeigte Weise von analog auf
> digital umzusteigen.
>
> Wenn phasenreserve und Dynamik kritisch sind, wird meist Tustin
> Transformation (bilinear Transformation) verwendet.

Gute Ergänzung :)

Stokmarknes schrieb:

> abhängig von einem analogen Eingangswert (0..1023) soll ein
> Digitalausgang an- oder ausgeschaltet werden.

Würde da nicht ein Zweipunkt-Regler ausreichen ?

Gruß
#5676697
Lesenswert?

> aber long int haben doch keine Kommastellen ?

Was willst du denn mit Kommastellen ?

Nehmen wir einen Temperaturregler :

ADC : -32768 .. 32767 , entsprechend zB -30..400 Grad, wie auch immer
linearisiert : mit 20 Schritt pro Grad.

Solltemp = 2452, entsprechend (irgendwas), in der ADC skala
Isttemp = 1127

Fehler = 1325

Proportional gain= 150 -> P Anteil = 198750

Integral gain = 10
Integrator = Integrator + 10* Fehler
sei der Integrator bei 2134436 -> I Anteil = 2134436

Ausgang Regler = P Anteil  + I Anteil = 2333186

Das Stellglied, dh die Heizung ist PWM mit 0-4095 (12bit)

Wir bilden den Reglerausgang auf das Stellglied ab, mit
2^24 = 16777216 -> 2^12 = 4096
als div 4096, heisst als shift rechts 12.

Ausgang Regler (2333186) -> Stellglied = 569

Fertig. Du benoetigst keine Kommastellen.
(Firma: matzetronics) #5676719
Lesenswert?

Michael V. schrieb:
> Klar so gehts auch, aber benutzt man die Umgewandelten Temperaturen (z.B
> 23.10°C) und nicht den ADC-Wert... halt nicht.

Falls man für den Benutzer da was anzeigen muss, kann man immer noch 
eine Rechenroutine für eine Benutzerschnittsstelle zu machen, die dann 
die gewohnte Temperatur errechnet.
Aber intern reicht es, ganzzahlig zu arbeiten, auch weil der PID Regler 
ja am besten eine gleichmässige Durchlaufzeit haben sollte. Wie o.a. 
enthält AVR221 auch schöne Grafiken und ist nicht nur für AVR Anwender 
nützlich. Bei mir läuft dieser PID Regler auch auf XMega und STM32.

Michael V. schrieb:
> Würde da nicht ein Zweipunkt-Regler ausreichen ?

Sollte man als erstes mal checken.
#5677436
Lesenswert?

Zitronen F. schrieb:
> Vergiss float. Longint ist besser geeignet und schneller zu rechnen.

Nö, float ist schneller, da es nur 24Bit berechnen muß.

Zitronen F. schrieb:
> Denn Float hat 5-6 signifikante Stellen, waehrend longint 9 signifikante
> Stellen hat.

Von den 9 Stellen bleibt aber kaum was übrig, wenn die Koeffizienten 
sehr klein werden. Float rechnet dagegen über einen großen Bereich 
genau.
Ich hab deshalb den Ärger mit Ganzzahlen hinter mir gelassen.
(Firma: fritzler-avr.de) #5677447
Lesenswert?

Peter D. schrieb:
> Zitronen F. schrieb:
>> Vergiss float. Longint ist besser geeignet und schneller zu rechnen.
>
> Nö, float ist schneller, da es nur 24Bit berechnen muß.

Ähhhm, NÖ!
Bevor ein float berechnet werden kann muss es ersteinmal ausgepackt und 
normalisiert werden.
Guck dir im objdump mal ein float MUL und ein 32Bit int MUL an.
Da staunste Bauklötze bei den Berechnungen.
Statt longint und Konsorten sollten stdint.h genutzt werden, also 
uint32_t.

Da hat der 8Bit Prozessor (z.B. nen AVR) die 32Bit mul/div/add/sub schon 
alle durch bevor der float überhaupt erstmal ausgepackt wurde.

Ein 32Bit Prozessor hat den 32Bit Wert noch schneller durch.
Float wird erst schnell mit einer FPU.
Gast #5678257
Lesenswert?

Danke für die brauchbaren Hinweise. Was mir noch unklar ist: im Beispiel 
oben gibt es diese Werte hier:

Michael V. schrieb:
> float Tn = 1.0;      // dient zur Einstellung des PID Reglers
> float Tv = 1.0;      // dient zur Einstellung des PID Reglers
> float Kp = 1.0;      // dient zur Einstellung des PID Reglers

und in pid.c einen SCALING_FACTOR. Die scheinen die 
Reaktionsgeschwindigkeit des Reglers zu beeinflussen. Ich hätte das aber 
jetzt so verstanden, dass man das eigentlich mit den PID-Werten macht - 
wieso gibt es die noch mal zusätzlich?
#5678839
Lesenswert?

Die AVR221 ist ein PID der mit Integer Werten arbeitet. Du müsstest also 
die entsprechenden Werte für TN, TV und KP als Integer Werte umrechnen 
(im einfachsten Fall einfach die Nachkommastellen abschneiden).

Der Scaling Factor ist dazu zu, die Genauigkeit zu erhöhen. Dazu ein 
Beispiel:

Du hast KP ermittelt und festgestellt dass z.B. 1.25 ein guter KP-Wert 
wäre. Der PID aus der AVR221 rechnet/arbeitet aber nur mit Interger 
Werten. Willst du also die Nachkommastellen mit benutzen im PID dann 
musst du das Komma um mindestens zwei Stellen nach rechts schieben, also 
mindestens mit 100 multiplizieren.
Genau das macht der Scaling Factor in der AVR221. Man rechnet dann in 
der PID-Routine/Funktion mit den um den Scaling Factor multiplizierten 
Werten und dividiert den Rückgabewert später wieder durch den Scaling 
Factor.

In der AVR221 wurde nur nicht 100 als Scaling Factor gewählt sondern 
128. 128 ist eine Zweierpotenz, jeder C-Compiler sollte das heute 
erkennen und so wird aus einer Multiplikation/Division eine 
Shift-Operation die erheblich schneller ausgeführt werden kann als eine 
Multiplikation/Division.

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