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


von Digit-22 N. (digit-22)


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
von aSma>> (Gast)


Lesenswert?

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

von Tasker (Gast)


Lesenswert?

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

von Alexander (Gast)


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

von Volle (Gast)


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.

von aSma>> (Gast)


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:

1
#define PID_UPDATE_TIME  10
2
uint8_t pid_motor = 0;
3
4
void ISR(){  //1ms
5
static uint32_t cnt_ms=0;
6
cnt_ms++;
7
8
  if (!(pid_motor%PID_UPDATE_TIME))
9
  motor = 1;
10
  if(!lcd....
11
}
12
13
int main{
14
   while(1){
15
16
   if(pid_motor)
17
   pid_motor=0;
18
   //PID Regelung
19
   }
20
   if(lcd)
21
   lcd=0
22
...
23
return 0;
24
}

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.

von Digit-22 N. (digit-22)


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
von Huh (Gast)


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.

von Joe G. (feinmechaniker) Benutzerseite


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"

von Digit-22 N. (digit-22)


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
von Sebastian S. (amateur)


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.

von Bernd K. (prof7bit)


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.

von Sebastian S. (amateur)


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
von Md M. (Firma: Potilatormanufaktur) (mdma)


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
von Volle (Gast)


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.

von Volle (Gast)


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.

von Digit-22 N. (digit-22)


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

von Sven L. (svenl)


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

von Digit-22 N. (digit-22)


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.
1
#define F_CPU 16000000UL
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
int count = 0;
8
int state = 0;
9
10
11
12
int main(void)
13
{
14
  // Definition Eingänge für Encoder
15
  //----------------------------------------------------------------------------------------------
16
  PORTD |= (1<<PD2) | (0<<PD1);        // Encoder Eingänge. PD2 = A, PD1 = B.
17
  DDRD &= ~(1 << DDD2);            // Clear the PD2 pin PD2 (PCINT0 pin) is now an input
18
  PORTD |= (1 << PORTD2);            // turn On the Pull-up  PD2 is now an input with pull-up enabled
19
  //----------------------------------------------------------------------------------------------
20
  
21
  // Definition externer Interupt Eingang
22
  //----------------------------------------------------------------------------------------------
23
  EICRA |= (1 << ISC00);            // set INT0 to trigger on ANY logic change
24
  EIMSK |= (1 << INT0);            // Turns on INT0
25
  //----------------------------------------------------------------------------------------------
26
  
27
  // Definition Ausgänge zur Steuerung der H-Brücke
28
  //----------------------------------------------------------------------------------------------
29
  //DDRB = (1<<PB0) | (1<<PB1);          // Motorausgänge zweipunktregelung ohne PWM
30
  DDRB |= _BV(PB1);                // Ausgang PWM
31
  DDRD |= _BV(PD6);                // Ausgang PWM
32
  
33
  TCCR1A |= _BV(COM1A1) | _BV(WGM10);        // PWM PB1 OCR1A 
34
  TCCR1B |= _BV(CS10) | _BV(WGM12);
35
  
36
  TCCR0A |= _BV(COM0A1) | _BV(WGM00) | _BV(WGM01);// PWM PD6 OCR0A 
37
  TCCR0B |= _BV(CS00);
38
  
39
  //----------------------------------------------------------------------------------------------
40
  
41
  //----------------------------------------------------------------------------------------------
42
  sei();                    // turn on interrupts
43
  //----------------------------------------------------------------------------------------------
44
  
45
  // Definition PID Regler Variablen
46
  //----------------------------------------------------------------------------------------------
47
  float e = 0;                // Regelabweichung
48
  float w = 4000;                // Sollwert-Position/Geschwindigkeit
49
  float x = 0;                // Regelgröße aktueller Encoderwert
50
  float y = 0;                // Stellgröße
51
  float esum = 0;                // Summer aller Regelabweichungen
52
  float ealt = 0;                // Letzte Regelabweichung
53
  
54
  float Kp = 1;                // Propotionalbeiwert
55
  float Ki = 1;                // Integralbeiwert
56
  float Kd = 1;                // Differenzialbeiwert
57
  float Ta = 0.01;              // Abtastzeit
58
  //----------------------------------------------------------------------------------------------
59
  
60
61
  while(1)
62
  {
63
    x = count;
64
    e = w - x;
65
    esum = esum + e;
66
    
67
    y = Kp*e + Ki*Ta*esum + Kd/Ta * (e - ealt);
68
    ealt = e;  
69
    
70
    
71
    
72
    if (y < 0)
73
    {
74
      OCR1A = y * (-1);  
75
      OCR0A = 0;
76
      //OCR1A =0;  
77
      //PORTD &= ~(1<<PD6);  //LOW
78
      //PORTB |= 1<<PB1;  //HIGH
79
      //PORTB &= ~(1<<PB1); //LOW
80
    }
81
    if (y > 0)
82
    //_delay_ms(1);
83
    {
84
      
85
      OCR0A = y;
86
      OCR1A = 0;
87
      //PORTB &= ~(1<<PB1); //LOW
88
      //PORTD |= 1<<PD6;    //HIGH
89
      //PORTD &= ~(1<<PD6);  //LOW
90
    }
91
    _delay_ms(1);
92
  }
93
}
94
95
96
97
ISR (INT0_vect)
98
{
99
  
100
  if ( !(PIND & (1<<PIND2)) and !(PIND & (1<<PIND1) ))
101
  {
102
    count++;
103
  }
104
  if ( PIND & (1<<PIND2) and PIND & (1<<PIND1) )
105
  {
106
    count++;
107
  }
108
  
109
  if ( PIND & (1<<PIND2) and !(PIND & (1<<PIND1) ))
110
  {
111
    count--;
112
  }
113
  if ( !(PIND & (1<<PIND2)) and PIND & (1<<PIND1) )
114
  {
115
    count--;
116
  }
117
}

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
von Walter L. (Gast)


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

von Digit-22 N. (digit-22)


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

von aSma>> (Gast)


Angehängte Dateien:

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

von Digit-22 N. (digit-22)


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

von aSma>> (Gast)


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:
1
u=k1* uk_1+ k2* uk_2 + k3* e+ k4* ek_1+ k5* ek_2;
2
uk_2=uk_1;
3
uk_1=u;
4
ek_2=ek_1;
5
ek_1=e;

Die Kontanten Ki gleich am Anfang ausrechnen.

von Ferdinand (Gast)


Lesenswert?

Hier auch ein code zum Periodischen Ausführen von Funktionen

int Zeitstempel;

//-------- TIMING FUNCTION ------------//
bool tick(unsigned long ms, unsigned long *ptstamp)
{
  unsigned long tAct = millis();
  if(tAct >= *ptstamp + ms) // Zeit fürs Warten
  {
   *ptstamp = tAct; // Zeitpunkt letzter Durchlauf speichern
   return 1;
  }
  else
  {
   return 0;
  }
}

// in der loop:

if(tick(1000, &Zeitstempel))
{
  // wird alle 10 Sekunden ausgeführt
}

von Ferdinand (Gast)


Lesenswert?

es müsste heißen:

bool tick(unsigned long ms, unsigned long *Zeitstempel)
...
  if(tAct >= *Zeitstempel + ms) // Zeit fürs Warten


Und ich habe eine Frage:
Wofür ist eigentlich die Stromregelung, wie es die Industrie macht 
(siehe oben) zuständig?

Hat jemand ein Codebeispiel für den Anti-Windup? meine bisherigen 
Versuche waren nur ungenügend :-).

von Md M. (Firma: Potilatormanufaktur) (mdma)


Lesenswert?

Ferdinand schrieb:
> es müsste heißen:
>
> bool tick(unsigned long ms, unsigned long *Zeitstempel)
> ...
>   if(tAct >= *Zeitstempel + ms) // Zeit fürs Warten

Warum?

von Wächter (Gast)


Lesenswert?

Und das nach 3 Jahren!

von Md M. (Firma: Potilatormanufaktur) (mdma)


Lesenswert?

Wächter schrieb:
> Und das nach 3 Jahren!

Wär/ist doch in Ordnung, solange man inhaltlich was beiträgt.

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.