mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Digitaler PID Regler frage zur Formel


Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hej

Hätte mal eine Verständnis Frage zur PID Regler.

Hier gibt es eine sehr gute erklärung was regelungstechnik angeht.

http://rn-wissen.de/wiki/index.php/Regelungstechnik

Wenn man runter scrolt kommt man irgend wann zum Digital PID Regler.
Ich habe auch soweit alles verstanden bis auf eine Sache.

Da steht Ta ist die Abtastzeit. Ich bin mir nicht ganz sicher woher ich 
den wert für Ta bekomme.

Ich bin gerade dabei einen DC Bürstenmotor mit Encoder anzusteuern.
Möchte das ganze anhant von PID Regler und PWM machen.

Als Controler kommt ein Atmega328P mit 16MHz zum einsatz der mit Atmel 
Studio in C programmiert wird. Die PWM geht auf eine H Brücke L293. 
Links rechtslauf ist erwünscht. Denke werde erstmal mit drehzahlregelung 
starten. Nächstes ziel ist die positionierung.

Würde mich auf Tipps sehr freuen.


LG

: Bearbeitet durch User
Autor: aSma>> (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Servus,
ein digitaler Regler basiert immer auf eine feste äquidistante 
Abtastzeit.
Dafür eignet sich wunderbar ein Interrupt mit 1khz Frequenz.

Autor: Tasker (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
>Dafür eignet sich wunderbar ein Interrupt mit 1khz Frequenz
Besser als Interrupt:
Zieh Dir ne 1ms Task im Hauptprogramm auf.

Autor: Alexander (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Tasker,
Tasker schrieb:
> Besser als Interrupt:
> Zieh Dir ne 1ms Task im Hauptprogramm auf.

Ich kenne/lese bisher auch nur die Methode über den Interrupt. Da uC 
eher ein Nebenbereich für mich sind, bin ich mir nicht sicher, was genau 
du mit Task meinst.

Magst du das bitte ein wenig näher ausführen?

Vielen Dank.

Cheers,
Alexander

Autor: Volle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
eine Zeitscheibe

der vernünftigen Gegenentwurf zum schwachsinnigen delay

z.B erstellt man ein 1ms Task eine 10ms Task  und einen 100ms Task
die immer entsprechend aufgerufen werden un sich alle aus dem selben 1ms 
Takt ableiten.

Temperaturregler funktionen mit Erfassung packt man dann in das 100ms 
Raster
Schalteranfragen in das 10ms Raster
und extrem Zeitkritische Sachen in das 1ms

Der Softwareteil der sich darum kümmert wer jetzt dran kommt nennt man 
Scheduler
und mit allem was man sonst noch dazugehört Betriebssystem.


Das geht auch schon mit weniges kByte Code.

Autor: aSma>> (Gast)
Datum:

Bewertung
-1 lesenswert
nicht lesenswert
Alexander schrieb:
> Magst du das bitte ein wenig näher ausführen?

Der meint wohl bestimmt den µC als Statemachine.
(https://www.mikrocontroller.net/articles/Statemachine)

Kann man auch machen, wenn µC nichts anders zu tun hat. Dafür erstellst 
du einen Interrupt mit 1khz Frequenz. Ungefähr so:

#define PID_UPDATE_TIME  10
uint8_t pid_motor = 0;

void ISR(){  //1ms
static uint32_t cnt_ms=0;
cnt_ms++;

  if (!(pid_motor%PID_UPDATE_TIME))
  motor = 1;
  if(!lcd....
}

int main{
   while(1){

   if(pid_motor)
   pid_motor=0;
   //PID Regelung
   }
   if(lcd)
   lcd=0
...
return 0;
}

Man muss hier aber ein paar Dinge beachten:
-Überlauf cnt_ms nach 50 Tagen, besser ist es als uint64_t zu 
deklarieren
-alle Task dürfen nicht zu lang ausgeführt sein
wie hier z.B. wenn der lcd task 20ms braucht, dann wird es mit 1ms 
motor_pid nicht klappen, dann wäre der Interrupt doch besser.

Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo  jungs,

super danke schonmal für die Antworten.
Wenn ich es richtig verstanden habe ist die abtastzeit die Zeit in der 
eine Regelabweichung stattfindet korrekt?
Das Heißt wenn eine Störgröße mein System stört das eine Regelabweichung 
entsteht, fägt die Abtastzeit an zu zählen? (I Regler e*Ta).


Z.B.


wenn ich folgenden Code verwende:

als PseudoCode betrachten:

int PID()
{

   e = w - x;          //Vergleich
   if (e <> 0)         // Wenn die e kleiner oder auh größer als 0
   {
      Ta++;
      delay_m(1);
   }
   else
   {
      Ta = 1;          // Damit keine Division durch 0 entsteht.
   }

   esum = esum + e;    //Integration I-Anteil

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


Bitte den code nicht auf Syntax prüfen ist nur damit ich es auch richtig 
verstehe. Und bitte nicht wegem delay festnageln.

Ich würde oben erst e berechnen, dann gucken ob e größer oder kleiner 0. 
Wenn ja Ta++ ansonsten Ta=1.


Hoffe bin in etwa auf ded richtigen Weg.


LG

: Bearbeitet durch User
Autor: Huh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nee, du mußt die Werte jede ms erfassen und jede ms die Reglergleichung 
aufrufen. Das heisst, im Takt von 1ms wird immer die Veränderung zur 
vorherigen ms berechnet, daraus der Ausgabewert bestimmt und der an das 
Stellglied ausgegeben.

Autor: Joe G. (feinmechaniker) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Digit-22 N. schrieb:
> Da steht Ta ist die Abtastzeit. Ich bin mir nicht ganz sicher woher ich
> den wert für Ta bekomme.

Das wurde schon hier im Forum behandelt.
Beitrag "Abtastzeit bei PID Regler"

Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hhhm versthe ich das richtig? Die Abtastzeit ist im Grunde t=1/f, wobei 
f=anzahl der PID Algurithmus Aufrufe ist?.

Z.B. wenn ich 100 mal in der sekunde meine PID Funktion aufrufe, ist 
mein Ta = 1/100Hz. Somit ist Ta = 0,01s -> 10ms. Ist das korrekt?

Dann ist ja Ta in diesem Fall ein fetser Wert korrekt?



LG

: Bearbeitet durch User
Autor: Sebastian S. (amateur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei üblichen µC gibst DU die Abtastzeit vor!

Das kann durch das Abfragen eines Timers (interne Uhr) erfolgen oder 
durch eine vom Timer ausgelösten Unterbrechung.

Die Zeit hängt von Deinem Problem ab - und nicht zu vergessen - der 
benötigten Rechenzeit.
Es ist völlig sinnlos eine Temperatur oder eine schwere Masse im 
Mikrosekundenbereich abzutasten.

Hast Du es aber "Eilig", so solltest Du nicht vergessen, dass die oft 
verwendete Fließkommaarithmetik relativ Zeitintensiv ist, so keine 
Fließkommarecheneinheit eingebaut ist.
Auch kann das Bloße einbinden der Fließkommaarithmetikbibliotheken 
Deinen Flash leicht zum Überlaufen bringen.

Mit Ganzzahlarithmetik kann man über den einen oder anderen Stolperstein 
hinwegkommen.

Autor: Bernd K. (prof7bit)
Datum:

Bewertung
-3 lesenswert
nicht lesenswert
Volle schrieb:
> Der Softwareteil der sich darum kümmert wer jetzt dran kommt nennt man
> Scheduler
> und mit allem was man sonst noch dazugehört Betriebssystem.

Warum tust Du so als wäre es eine Selbstverständlichkeit daß jeder für 
jeden Kleinkram gleich ein komplettes OS und einen Controller der 4 
Nummern teurer ist als nötig mit einplant? Mach mal nen 
Realitätsabgleich.

Autor: Sebastian S. (amateur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Multitaskingbetriebssystem fällt für mich in die Kategorie: Kanonen 
und Spatzen.

Da ein Multitaskingsystem immer noch langsamer ist, als ein System ohne, 
hält sich der Nutzen in überschaubaren Grenzen. Es gibt natürlich auch 
hier Ausnahmen.

Ist man sich unsicher, ob man konstante Zeiten einhalten kann, so macht 
man einfach: So schnell es geht, also z.B. bei jedem 
Hauptschleifendurchlauf.

Kann es hier zu einer unkalkulierbaren Periode kommen, so muss man sich 
nur die Zeit der letzten Berechnung merken (Takt – Tvor) und dann mit 
einer, minimal, variablen Zykluszeit arbeiten.

Es wird immer wieder vergessen, dass eine konstante Zykluszeit sinnvoll 
und bequem ist, aber nicht notwendig!

: Bearbeitet durch User
Autor: Md M. (Firma: Potilatormanufaktur) (mdma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Digit-22 N. schrieb:
> hhhm versthe ich das richtig? Die Abtastzeit ist im Grunde t=1/f, wobei
> f=anzahl der PID Algurithmus Aufrufe ist?.
>
> Z.B. wenn ich 100 mal in der sekunde meine PID Funktion aufrufe, ist
> mein Ta = 1/100Hz. Somit ist Ta = 0,01s -> 10ms. Ist das korrekt?
>
> Dann ist ja Ta in diesem Fall ein fetser Wert korrekt?

Ja, so ist es. Ta ist sogar immer ein fester Wert, wenn du nicht grade 
deine loop-Frequenz änderst.

Es haben bis dahin in der Tat irgendwie alle an deiner Frage und deinem 
Verständnisproblem vorbei geantwortet.

: Bearbeitet durch User
Autor: Volle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernd K. schrieb:
> Warum tust Du so als wäre es eine Selbstverständlichkeit daß jeder für
> jeden Kleinkram gleich ein komplettes OS und einen Controller der 4
> Nummern teurer ist als nötig mit einplant? Mach mal nen
> Realitätsabgleich.

solltest du mal machen

Ein funktionierendes Multitasking  Echtzeit OS benötigt wirklich nicht 
viel Code.

Mein erstes habe ich vor 23 Jahren als Teil meiner Diplomarbeit 
geschrieben
hat so 20% der ganzen Arbeit ausbemacht und lief auf einem MC56156 
Signalprozessor.

Seither sind noch ein paar Implementierungen dazugekommen
Andere kommerzielle habe ich recht tief untersucht.

Es muss nicht 100% POSIX kompatibel sein um ein gutes Betriebssystem zu 
sein.

Autor: Volle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sebastian S. schrieb:
> Ist man sich unsicher, ob man konstante Zeiten einhalten kann, so macht
> man einfach: So schnell es geht, also z.B. bei jedem
> Hauptschleifendurchlauf

eine "Lösung" die nur durch Zufall funktionieren kann
irgendwann knallt und man ist dann bei 0 Steht.


Echtzeit ist nicht möglichst schnell
sondern so schnell wie notwendig.


Ein OID Regler mit variablem dt ist eine Herausforderung was Auslegung 
und Stabilität angeht.

Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo mdma,

Ja irgendwie schon. Aber habs ja jetzt kappiert. :-).

Ich hab das ganze gestern abend getestet. Funkionirt ganz gut soweit.
Hab nen kleinen getriebe dc motor mit einem 360 poti als feedback 
angesteuert.
Ein zweiter poti gibt den soll positionswert vor...

Jetzt kommt der nächste schritt. Dc motor mit encoder regeln. Der 
encoder hat AB und einen nulldurchgang Z. 500 pulse/u...


Mal schauen ob es klappt.
Lg

Autor: Sven L. (svenl)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vergiss bitte nicht, dass Du in Deinen PID-Regler ggf. noch weitere 
Funktionen hinzufügen musst, wie das Begrenzen des I-Terms 
(Anti-Windup/-Winddown) oder ein Totbereich (Deadband), in welchem die 
Steuergröße Null wird...

In der Praxis fehlen diese Funktionalitäten oft, was ein unharmonisches 
Regelverhalten, trotz korrekt dimensionierter Terme, zur Folge hat.

Viele Grüße!

Sven

Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Jungs,

hier sind die ersten Versuche.
Das einlesen des Encoders funktioniert sehr gut.
Aber irgendwie scheint der Bereich in der While Schleife nicht so 
optimal zu sein. Der motor fährt nicht auf den Sollwert sonder dreht 
sich vibriert und macht was er will. Irgendwie scheint es an den PWMs zu 
liegen. Am oszi sieht man die PWMs nur zappeln.

Im Grunde schaue ich ob y < 0 ist und schalte dem entsprechen den 
ausgang, also zb. OCR1A läuft hoch und OCR0A runter.
Und das gleich für y > 0 nur umgekehrt.

#define F_CPU 16000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

int count = 0;
int state = 0;



int main(void)
{
  // Definition Eingänge für Encoder
  //----------------------------------------------------------------------------------------------
  PORTD |= (1<<PD2) | (0<<PD1);        // Encoder Eingänge. PD2 = A, PD1 = B.
  DDRD &= ~(1 << DDD2);            // Clear the PD2 pin PD2 (PCINT0 pin) is now an input
  PORTD |= (1 << PORTD2);            // turn On the Pull-up  PD2 is now an input with pull-up enabled
  //----------------------------------------------------------------------------------------------
  
  // Definition externer Interupt Eingang
  //----------------------------------------------------------------------------------------------
  EICRA |= (1 << ISC00);            // set INT0 to trigger on ANY logic change
  EIMSK |= (1 << INT0);            // Turns on INT0
  //----------------------------------------------------------------------------------------------
  
  // Definition Ausgänge zur Steuerung der H-Brücke
  //----------------------------------------------------------------------------------------------
  //DDRB = (1<<PB0) | (1<<PB1);          // Motorausgänge zweipunktregelung ohne PWM
  DDRB |= _BV(PB1);                // Ausgang PWM
  DDRD |= _BV(PD6);                // Ausgang PWM
  
  TCCR1A |= _BV(COM1A1) | _BV(WGM10);        // PWM PB1 OCR1A 
  TCCR1B |= _BV(CS10) | _BV(WGM12);
  
  TCCR0A |= _BV(COM0A1) | _BV(WGM00) | _BV(WGM01);// PWM PD6 OCR0A 
  TCCR0B |= _BV(CS00);
  
  //----------------------------------------------------------------------------------------------
  
  //----------------------------------------------------------------------------------------------
  sei();                    // turn on interrupts
  //----------------------------------------------------------------------------------------------
  
  // Definition PID Regler Variablen
  //----------------------------------------------------------------------------------------------
  float e = 0;                // Regelabweichung
  float w = 4000;                // Sollwert-Position/Geschwindigkeit
  float x = 0;                // Regelgröße aktueller Encoderwert
  float y = 0;                // Stellgröße
  float esum = 0;                // Summer aller Regelabweichungen
  float ealt = 0;                // Letzte Regelabweichung
  
  float Kp = 1;                // Propotionalbeiwert
  float Ki = 1;                // Integralbeiwert
  float Kd = 1;                // Differenzialbeiwert
  float Ta = 0.01;              // Abtastzeit
  //----------------------------------------------------------------------------------------------
  

  while(1)
  {
    x = count;
    e = w - x;
    esum = esum + e;
    
    y = Kp*e + Ki*Ta*esum + Kd/Ta * (e - ealt);
    ealt = e;  
    
    
    
    if (y < 0)
    {
      OCR1A = y * (-1);  
      OCR0A = 0;
      //OCR1A =0;  
      //PORTD &= ~(1<<PD6);  //LOW
      //PORTB |= 1<<PB1;  //HIGH
      //PORTB &= ~(1<<PB1); //LOW
    }
    if (y > 0)
    //_delay_ms(1);
    {
      
      OCR0A = y;
      OCR1A = 0;
      //PORTB &= ~(1<<PB1); //LOW
      //PORTD |= 1<<PD6;    //HIGH
      //PORTD &= ~(1<<PD6);  //LOW
    }
    _delay_ms(1);
  }
}



ISR (INT0_vect)
{
  
  if ( !(PIND & (1<<PIND2)) and !(PIND & (1<<PIND1) ))
  {
    count++;
  }
  if ( PIND & (1<<PIND2) and PIND & (1<<PIND1) )
  {
    count++;
  }
  
  if ( PIND & (1<<PIND2) and !(PIND & (1<<PIND1) ))
  {
    count--;
  }
  if ( !(PIND & (1<<PIND2)) and PIND & (1<<PIND1) )
  {
    count--;
  }
}


Die parametrierung Kp Ki Kd und Ta sind erstmal nur testweise also bitte 
nicht deswegen festnageln. Im ersten Schritt möchte ich nur einen 
Sollwert Position vor geben und diesen soll der Motor erreichen und 
halten. Pro Umdrehung habe ich 500 Steigende und 500 Fallende Falnke 
worauf mein Interupt reagiert. Somit 1000 Pulse/U.


Vielleicht entdeckt ja jemand den Fehler oder hat einen viel besseren 
Ansatz.

: Bearbeitet durch User
Autor: Walter L. (charly2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Digit-22 N.
ich gehe davon aus, dass Du mit dem Motor positionieren möchtest.
Die Vorgehensweise ist folgende:
1. Den Strom durch den Motor mit eine PI-Regler regeln.
2. Die Drehzahl mit einem PI-Regler regeln.
3. Die Position mit einem P-Regler regeln.

Die ist eine vermaschte Regelung, wobei die Stromregelung die schnellste 
ist (ca. 100uSek), Drehzahlregelung ca. 1 mSek, Positionierung ca. 5 
mSek Abtastzeit.

Nur mit einem PID-Regler habe ich es nie probiert. Industriell werden 
Motoren nach dem oben beschrieben Verfahren Positioniert.
VG Walter

Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo walter.
Danke für den tipp. Die kaskadierte regelung ist natürlich in planung. 
Steht jedoch als letzten Schritt auf der liste. Für die strom regelung 
würde ich dann kleine stromsensoren einstzen...

Aber erstmal die Kinderkrankheiten ausmerzen. Daher zuerst der PID 
Regler. So lerne ich das ganze am besten...


LG

Autor: aSma>> (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Servus,
nehme einen PID-T1 Regler! Der D-Anteil wird sonst schwingen.

Es gibt Faustregeln wie man T1 in Abhängigkeit von KD einstellt 
(Aström).

Man kann schon eine Positionierung mit einen PID-T1 hinkriegen, dann 
braucht man aber schon den Anti-Windup Ansatz nach Aström.

mfg

Autor: Digit-22 N. (digit-22)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok danke für den Tipp.

Kannst du mir auch etwas zum Code sagen?
Bin etwas am verzweifeln und finde einfach das Problem nicht.

Könnte es sein das mein externer Interut und die PWM Erzeugung sich 
nicht vertragen?


LG
Digit-22

Autor: aSma>> (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Digit-22 N. schrieb:
> Kannst du mir auch etwas zum Code sagen?
> Bin etwas am verzweifeln und finde einfach das Problem nicht.

> float y = 0;                // Stellgröße

Benennt man üblichweise mit "u".
Später wäre viellt eine fix-point Arichmetik sinnvoller beim 328P. Ich 
weiß ja nicht welche Ambitionen angepeilt sind.

> float Ta = 0.01;              // Abtastzeit

stimmt nicht mit
>_delay_ms(1);
überein!

Vorausgesetzt die PWM für die Motoransteuerung fkt. (Datenblätter werde 
ich jetzt nicht lesen für dich) ist dieser Regler einfach Murks.

> x = count;
>     e = w - x;
>     esum = esum + e;
>
>     y = Kp*e + Ki*Ta*esum + Kd/Ta * (e - ealt);
>     ealt = e;

Hier fehlt die Saturation:
y=Kp*e... gleich zu anfang macht es: y=1*1000;

Hier musst du die Einheiten umrechnen. Ich vermute mal, dass du mit 12V 
arbeitest.

if(y<=-12)
  y=-12;
if(y>=12
  y=12;

Hier musst du jetzt weiterhin umrechnen: z.B. 12V entspricht 1024 pwm...

Ohne richtige Systemanalyse kriegst du auch keinen guten Regler hin! Das 
ist wie die berühmte Nagel im Heuhaufen. Den Heuhaufen abbrennen kann 
man hier auch nicht.

Du könntest einen Eingangsprung auf den Regler geben und diesen mal in 
Excel ploten lassen. Wie das aussehen los, kannst du mal googeln.

Ich rate dir aber dazu meinen vorgeschlagenen Regler zu nehmen:
u=k1* uk_1+ k2* uk_2 + k3* e+ k4* ek_1+ k5* ek_2;
uk_2=uk_1;
uk_1=u;
ek_2=ek_1;
ek_1=e;

Die Kontanten Ki gleich am Anfang ausrechnen.

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.