Forum: Mikrocontroller und Digitale Elektronik PI-Drehzahlregler bürstenbehafteter Gleichstrommotor


von Steff G. (steff_123)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich bin momentan dran einen PI-Regler für meinen bürstenbehafteten 
Gleichstrommotor : Drive System DSMP523 ( inkl. Encoder-Scheibe) zu 
implementieren.

Dazu habe ich ein Mega2560-Board und programmiere dieses in C.

Da mein Board via USB mit Matlab kommuniziert lasse ich mir hier die 
Drehzahlen ausgeben.

Zur Überprüfung, ob ich die Flanken der Encoderscheibe richtig einlese, 
habe ich den Motor einfach angesteurt und mir die Drehzahl ausgeben 
lassen - hat soweit gut funktioniert -> Interrupts vom Drehgeber sollten 
richtig empfangen werden.

Ich will meinen Motor auf 10 U/min regeln, jedoch macht meine Regelung 
nicht was sie soll -> siehe Anhang Foto.

Mein Code der Regelung sieht wie folgt aus:
1
...
2
// Reglerparameter
3
  float e = 0;
4
  float esum = 0;
5
  float K_p = 10.0 , K_i = 0;
6
  float u = 0;
7
8
for (int i=0;i<Anzahl;i++)
9
    {
10
      RESET_T4();
11
      RESET_T5();
12
      
13
      esum = 0;
14
    
15
      while (counter4_OVERFLOW < Zeit[i])    // Zeitdauer Zeit[i] des i-ten Prüfzykluses
16
      {
17
        
18
        if(counter5_OVERFLOW == 5) // alle 100ms
19
        {
20
          float y = ((counter_IMPULSE/5.0)/(counter5_OVERFLOW*20.0))* 60000.0;  // Regelgroesse y - Motordrehzahl berechnen
21
            
22
            // Drehzahldaten per serieller Schnittstelle versenden
23
            if(y==0)                  
24
            {  uart_puts("N\n");
25
              uart_puts("0\n");
26
            }
27
            else
28
            {
29
              uart_puts("N\n");
30
              uart_puts( dtostrf( y, 10, 3, s ) );
31
              uart_puts("\n");
32
            }
33
          
34
          e = n_soll[i] - y;              // Regelabweichung e
35
          esum = esum + e;
36
          
37
          u = K_p*e + K_i*0.1*esum;    // Stellgroesse u
38
          
39
          if (u>254.0) {u = 254.0;}          // Stellgroessenbegrenzung um wind-up Effekt zu vermeiden
40
          if (u<0.0) {u = 0.0;}
41
          
42
          counter5_OVERFLOW = 0;            // Zuruecksetzen des counters
43
          counter_IMPULSE = 0;            // Zuruecksetzen des Impulszaehlers
44
        }
45
        OCR1AL = (int)u;                // Berechnete Stellgroesse wird auf Ausgang gelegt
46
      }
47
      
48
      uart_puts("xxx");                  // Befehl um die aktuelle Messreihe abzuschliessen
49
      uart_puts("\n");
50
    }
51
    
52
    uart_puts("End");                    // Befehl um die Kommunikation mit Matlab abzubrechen
53
    uart_puts("\n");
54
    
55
    // Abbremsen des Motors bis zum Stillstand
56
    for (int i=(int)u;i==0;i--)
57
    {
58
      OCR1AL--;
59
      _delay_ms(10);
60
    }
61
    
62
    OCR1AL = 0;
63
64
...

Ich hoffe von euch kann mir jemand helfen, aber ich finde meinen Fehler 
einfach nicht.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Steff G. schrieb:
> // Drehzahldaten per serieller Schnittstelle versenden
>             if(y==0)
>             {  uart_puts("N\n");
>               uart_puts("0\n");
>             }
>             else
>             {
>               uart_puts("N\n");
>               uart_puts( dtostrf( y, 10, 3, s ) );
>               uart_puts("\n");
>             }

Das ist gar keine gute Idee. Wenn du alle 100ms erstmal die Bibel über 
seriell rausschiebst, wie soll dann die Regelung noch greifen?
Wirf das mal aus dem getimeden Code raus und packs irgendwo in die 
Hauptschleife. Ein Regler möchte regelmässig aufgerufen werden, sonst 
wird er nicht stabil. Dann machst du am besten P und I von aussen 
änderbar und schaust, was bei verschiedenen Werten passiert.
Application Note AVR221 beschreibt übrigens einen PID Regler für die 
Megas und Tinys, denn solltest du dir evtl. mal anschauen.
Noch eines: Es ist evtl. gar nicht nötig, die echte Drehzahl des Motors 
jedesmal wieder zu berechnen, sondern die Zeit zwischen zwei Encoder 
Events zu messen.

: Bearbeitet durch User
von Steff G. (steff_123)


Lesenswert?

Die Zeichenkette werde via der Bibliothek von Peter-Fleury versendet.
Dass läuft ja dann sowieso im "Hintergrund" per Ring-Puffer usw. ab 
oder?

Auch wenn ich das versenden der Zeichenkette auskommentiere läuft mein 
Gleichstrommotor ganz und gar nicht passend.

Matthias S. schrieb:
>Application Note AVR221 beschreibt übrigens einen PID Regler für die
>Megas und Tinys, denn solltest du dir evtl. mal anschauen.

Ich schau mir die Bibliothek mal an, aber grundsätzlich wollte ich den 
PI-Regler selbst implementieren.
Dürfte ja eig. kein großes Hexenwerk sein oder?

Kann in meinem Code evtl. jemand einen Fehler finden?

Der Regler befindet sich aktuell in der Hauptschleife - sollte ich den 
denn wo anders hinpacken?

: Bearbeitet durch User
von Bastian W. (jackfrost)


Lesenswert?

Mit Ki=0 ist der I-Anteil unwirksam. Wie viele Impulse sind eine 
Umdrehung ?


Gruß JackFrost

von Der Andere (Gast)


Lesenswert?

Steff G. schrieb:
> Der Regler befindet sich aktuell in der Hauptschleife - sollte ich den
> denn wo anders hinpacken?

Ein digitaler Regler braucht vor allem eins:
Ein konstantes delta-T (= Abtastrate).
Also sollte der Regler immer von einem Timer abgeleitet werden.
Ob das direkt in einem Timerinterrupt geschieht oder ob man in der 
Hauptschleife schaut ob eine bestimmte Delta Zeit vergangen ist seit 
Beginn des letzten Aufrufs hängt vom Rest des Programms und dem Wert der 
Abtastrate ab.
Den Regleralgorithmus einfach in der Hauptschleife aufzurufen ist ein 
Garant dass es nicht funktioniert.

von Steff G. (steff_123)


Lesenswert?

Bastian Werner schrieb:
> Mit Ki=0 ist der I-Anteil unwirksam.

Ich wollte erst mal nur mit dem P-Anteil ungefähr an den Sollwert kommen 
und dann mit dem I-Anteil die stationäre Genauigkeit abbilden.


Bastian Werner schrieb:
> Wie viele Impulse sind eine Umdrehung ?

5 Impulse entsprechen einer Umdrehung.
Im Motor ist ein Getriebe eingebaut mit einer Untersetzung von 150.
Folglich müsste sich der Motor bei einer vorgegebenen 
Getriebeabtriebsdrehzahl von 10 mit 1500 U/min drehen.

von Steff G. (steff_123)


Lesenswert?

Der Andere schrieb:

> Den Regleralgorithmus einfach in der Hauptschleife aufzurufen ist ein
> Garant dass es nicht funktioniert.

Der Regler wird doch in der Hauptschleife alle 100ms aufgerufen, somit 
habe ich ja mein konstantes delta-T hergestellt oder sehe ich das 
falsch?
1
if(counter5_OVERFLOW == 5) // alle 100ms
2
  ...

von Sumo (Gast)


Lesenswert?

Steff G. schrieb:
> Der Regler wird doch in der Hauptschleife alle 100ms aufgerufen,

Nur musst du dir mal überlegen, dass der Motor mit 1500rpm laufen soll 
und jede Umdrehung bringt 5 Impulse. Also hast du 7500 Impulse/min. Das 
sind 125 Impulse/s und du willst mit 10 Regelvorgängen/s (100ms) regeln?
Ergo: Deine Wiederholrate für den Regler ist VIEL zu langsam...

von Bastian W. (jackfrost)


Lesenswert?

Steff G. schrieb:
> Bastian Werner schrieb:
>> Mit Ki=0 ist der I-Anteil unwirksam.
>
> Ich wollte erst mal nur mit dem P-Anteil ungefähr an den Sollwert kommen
> und dann mit dem I-Anteil die stationäre Genauigkeit abbilden.
>
>
> Bastian Werner schrieb:
>> Wie viele Impulse sind eine Umdrehung ?
>
> 5 Impulse entsprechen einer Umdrehung.
> Im Motor ist ein Getriebe eingebaut mit einer Untersetzung von 150.
> Folglich müsste sich der Motor bei einer vorgegebenen
> Getriebeabtriebsdrehzahl von 10 mit 1500 U/min drehen.


Misst du an der Motorwelle oder am Getriebe ?

Wie lange braucht deine Berechnung in der 100 ms Schleife ?

Wenn er nur mit P so schwingt ist das P schon zu groß.

Schreib das Programm so das die Werte von außen ändern kannst. Dann 
kannst du besser Werte finden.

Gruß JackFrost

von Ralf B. (Firma: Scorptech) (mad_scorp)


Lesenswert?

Steff G. schrieb:
> 5 Impulse entsprechen einer Umdrehung.
> Im Motor ist ein Getriebe eingebaut mit einer Untersetzung von 150.
> Folglich müsste sich der Motor bei einer vorgegebenen
> Getriebeabtriebsdrehzahl von 10 mit 1500 U/min drehen.

Heisst das du kriegst 50 Impulse oder 7500? Entschuldige die Frage, aber 
ich habe den Aufbau noch nicht ganz verstanden.

Falls es 7500 sind (5 Imp * 1500) dann hast du 125 Imp/s und dann sind 
deine 100ms Abtastzeit schon recht knapp gewählt, meiner Meinung nach.

Digitale Regler sind tricky. Die meisten Bastler implementieren das 
quasi-kontinuierlich dh. mit Abtastraten >> Regelzeit.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Steff G. schrieb:
> aber grundsätzlich wollte ich den
> PI-Regler selbst implementieren.

Die UART Lib benutzt du doch auch schon. Da schadet es sicher nicht, 
sich mal den PID Regler von Atmel anzuschauen.
Im FU benutze ich den auch und schubse in per Timer Interrupt alle 200 
PWM Durchläufe an:
https://www.mikrocontroller.net/articles/3-Phasen_Frequenzumrichter_mit_AVR

Kannst ja mal reinschauen. Klare Skalierung der Eingangswerte schadet 
übrigens nicht. Im Idealfall sind Soll und Ist in der gleichen 
Grössenordnung, dann ist auch der Regler nicht überfordert.

: Bearbeitet durch User
von Steff G. (steff_123)


Lesenswert?

Bastian Werner schrieb:
> Misst du an der Motorwelle oder am Getriebe ?

Ich messe an der Motorwelle.

> Wie lange braucht deine Berechnung in der 100 ms Schleife ?

Habe den Prüfaufbau leider gerade nicht parat - versuche es morgen 
gleich nochmal.
Da brauche ich die time.h Bibliothek um das umzusetzen denke ich...

Ralf B. schrieb:
> Heisst das du kriegst 50 Impulse oder 7500?

7500 der Encoder sitzt auf der Motorwelle.

Ich versuche morgen gleich nochmal am P-Regler zu drehen, ob sich da was 
tut, aber grundsätzlich sollte das C-Programm passen?

Falls ich überhaupt nicht voran komme schau ich mir mal den fertigen 
PID-Regler von Atmel an.

von Ralf B. (Firma: Scorptech) (mad_scorp)


Lesenswert?

Steff G. schrieb:
> Ralf B. schrieb:
>> Heisst das du kriegst 50 Impulse oder 7500?
>
> 7500 der Encoder sitzt auf der Motorwelle.

Dh. du tastest 10 mal pro Sekunde ab und hast 125 Impulse pro Sekunde. 
Ich bin mir nicht sicher, ob du nicht schneller abtasten müsstest.

von Michael M. (michael89)


Lesenswert?

Hi, hier ist mal ein PID-Regler in eine Funktion geschrieben.. kann 
leider nicht sehen wo der Fehler bei dir liegt, aber evtl kannst du 
damit was anfangen.


float PIDRegler(float Drezahl1,float Drehzahl2)    // PID-Regler
{
  // Diese Werte müssen gespeichert werden
static float En=0.0,en1=0.0,en2=0.0;
static float Yn=0.0,yn1=0.0;
static int Yna;

  // Empfindlichkeit des PID-Reglers
float Tn = 1.0;
float Tv = 1.0;
float Kp = 1.0;

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

  // Zeitkostante

float delta_t=0.1;    // Zykluszeit bei der die Funktion aufgerufen wird 
[s]
float delta_y;

En = Drezahl1 - Drezahl2;  // "Regelgröße" Drezahl2 wird an Drezhal1
                           // angeglichen
// 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 Zyklisch aufgerufen werden.

MfG
M.V

: Bearbeitet durch User
von Steff G. (steff_123)


Lesenswert?

Vielen Dank für eure Antworten.

Ich hoffe ich hab mein Problem soweit eingrenzen können.

Die Zeile :
1
float y = ((counter_IMPULSE/5.0)/(counter5_OVERFLOW*20.0))* 60000.0;  // Regelgroesse y - Motordrehzahl berechnen
ist das Problem, da mir dieser bei einer Abtastrate von 20 ms nur zu 
bestimmten Motordrehzahlen eine Flanke liefert und ich hier nach Flanken 
die Regelgroesse berechne.

Jetzt versuche ich die Zeit zwischen zwei Interrupts zu messen und somit 
die aktuelle Drehzahl zu berechnen.
Melde mich dann

Darüber hinaus hätte ich grundsätzlich noch eine Frage:

Grundsätzlich wollte ich die Drehzahlen eig. kontinuierlich an den PC 
schicken.
Wo würdet ihr diesen Befehl denn dann einbauen, wenn nicht direkt in die 
Regelschleife?

Oder die auftretenden in ein char Array schreiben und zum Schluss erst 
die kompletten Drehzahlen als Paket versenden?
Es muss nämlich berücksichtigt werden, dass auch noch Drehmomentdaten 
via der seriellen Schnittstelle versendet werden sollen (ca. alle 100 
ms).

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.