volle Verzweiflung, wo liegt der Fehler :-(((((

Gast #880757
Lesenswert?

Hallo noch mal,
Leute Hilfe, ich programmier einen PI-Regler für einen GS-Motor.(mit 
Keil und XC167 von Infineon).
Die Reglerparameter habe ich theoretisch bestimmt, also müssten die 
passen.
Hier der Code:
1
#include "MAIN.H"
2
#include <REGLER.h>
3
#include <stdio.h>
4

5

6

7
//*************************************************************************************
8
//                    Defines
9
//*************************************************************************************
10
#define MAX 65535    // untere Grenze
11
#define MIN 65135    // obere Grenze
12

13

14
//*************************************************************************************
15
//                    Variablen
16
//*************************************************************************************
17

18
bit Begrenzung;              //Flag signalisiert, wenn Stellgröße in der Begrenzung ist
19
int Pulsbr = 400;
20
extern unsigned int Solldrehzahl; // Drehzahlvorgabe
21

22

23
//*************************************************************************************
24
//                    Prototypen
25
//*************************************************************************************
26

27
//unsigned long int Regeln (unsigned long int Istdrehzahl); // Funktion zum Aufrufen des Reglers
28

29

30
//*************************************************************************************
31
//                     Funktionen
32
//*************************************************************************************
33
extern int PI_Init(void)
34
{         
35
pi_r.Kp = 1;
36
//pi_r.Ki = 60;
37
pi_r.Ki = 12;
38
pi_r.Ta = 210;
39

40

41
Begrenzung = 0;
42
pi_r.I_Anteil = 0;
43
pi_r.Regelabweichung = 0;
44

45
return 0;
46
}
47
//*************************************************************************************
48

49
unsigned int Regeln (unsigned int Istdrehzahl)
50
{
51
//signed  int Stellwert_p = 0;       // Bereich zwischen -XXXXXX bis +XXXXXX
52
signed  int Stellwert = 0;
53

54
  pi_r.Istwert=Istdrehzahl;
55

56
  //printf("Istdrehzahl: %d",pi_r.Istwert);
57
  //printf("\n");
58

59
  pi_r.Sollwert=Solldrehzahl;  
60
  pi_r.Regelabweichung = pi_r.Sollwert-pi_r.Istwert;     // e=w-x
61

62
  
63
  printf("Regelabweichung: %d",pi_r.Regelabweichung);
64
  printf("\n");
65

66
   
67
//         Antiwindup     
68

69
  if (Begrenzung!=1)          // dann nicht im begrenzten Bereich
70
  {
71
    pi_r.I_Anteil = pi_r.I_Anteil + pi_r.Regelabweichung;          // esum=esum+e
72

73
  }  
74

75
  Stellwert = (pi_r.Kp*(pi_r.Regelabweichung))/16 + ((pi_r.Ki*pi_r.I_Anteil)*pi_r.Ta)/10000;  //Ta= 210ms, nicht durch 1000, weil  Ki=12/10
76
  
77
  printf("Stellwert: %d",Stellwert);
78
  printf("\n");
79

80

81
  if(Stellwert < 20)      // Begrenzung nach unten, also auf FE6F
82
  {
83
    Stellwert = 20;
84
    Begrenzung = 1;         // Rergler läuft in der Begrenzung
85
 
86
  } 
87

88
  else if(Stellwert > 400)    // Begrenzung nach oben, also auf FFFF
89
  {  
90
    Stellwert =400;
91
    Begrenzung = 1;            // Regler läuft in der Begrenzung
92
  }
93
  else 
94
  {
95
  Begrenzung = 0;
96
  }
97

98
  printf("Stellwert nach Begrenzung: %d",Stellwert);
99
  printf("\n");
100

101
pi_r.Stellwert = MIN + Stellwert;
102

103

104
printf("pi_r.Stellwert: %X",pi_r.Stellwert);
105
printf("\n");        
106
return pi_r.Stellwert;      // Übergabe Stellgröße
107
}

Der pi_r.Stellwert lad ich in ein Register, mit dem ich die Breite von 
PWM einstelle, so:
CC2_CC30 = Regeln (Drehzahl_mot);

Hab mir ein paar Werte ausgeben lassen. Die Datei hab ich angehängt.
Die Solldrehzahl beträgt 500U/min.
Mein Regler pendelt sich bei ca. 150 U/min ein und sense.....

Könnt ihr BITTE drüber schauen, ich find den Fehler nicht:-((((
Angehängte Dateien:
#880777
Lesenswert?

Dein Log mal etwas besser formatiert, sodass man auch die
zeitliche Entwicklung der Werte erkennen kann

Istdrehzahl   Abw    Stellwert Begr
   462         38       11      30    FE8D
   248        252       24      30    FE8D
   165        335       29      30    FE8D
   157        343       30      30    FE8D
   162        338      115     115    FEE2
   861       -361      -19      30    FE8D
   428         72        7      30    FE8D
   173        327       23      30    FE8D
   163        337       24      30    FE8D
   156        344       24      30    FE8D
   160        340       24      30    FE8D
   155        345       24      30    FE8D
   156        344       24      30    FE8D
   154        346       24      30    FE8D
   153        347       24      30    FE8D
   153        347       24      30    FE8D
   154        346       24      30    FE8D
   154        346       24      30    FE8D
   155        345       24      30    FE8D
   162        338       24      30    FE8D
   156        344       24      30    FE8D
   161        339       24      30    FE8D

(Du solltest wirklich dein Programm so modifizerien, dass es
diese Tabelle ganz von alleine erzeugt. Es ist nämlich
ziemlich fad, jedes mal diese Formatierung händisch zu machen)

Was auffällt. Deine Regelabweichung wird nicht kleiner. Das
ist für mich der Hinweis, dass dein I Anteil nicht stimmt.
Das könnte jetzt wiederrum von deiner seltsamen Anti-Windup
Begrenzung kommen oder aber Ki hat ganz einfach das falsche
Vorzeichen.

Anti Windup:
Beim Anti Windup begrenzt du die Summe auf einen bestimmten
Maximalen oder Minimalen Wert, damit die nicht unendlich hoch
wird. Das hat nichts mit dem Stellwert der hinten raus kommt
zu tun.

    pi_r.I_Anteil = pi_r.I_Anteil + pi_r.Regelabweichung;

   if( pi_r.I_Anteil > SomeMaximum )
     pi_r.I_Anteil = SomeMaximum;
   if( pi_r.I_Anteil < SomeMinimum )
     pi_r.I_Anteil = SomeMinimum;

Was noch auffällt.
Du hast hier

   248        252       24      30    FE8D
   165        335       29      30    FE8D
   157        343       30      30    FE8D
   162        338      115     115    FEE2
   861       -361      -19      30    FE8D

einen enormen Sprung. Sobald der Regler aus deiner 'Begrenzung'
raus kommt, fährt er die Stellgröße extrem in die Höhe. Wieder
ein Hinweis darauf, dass mit der Begrenzung was nicht stimmen
kann.
Gast #880795
Lesenswert?

@AC/DC:

hier ist das Debuggen nicht möglich, da das ganze ja ein physikalischer 
Prozess ist. Im Einzelschrittmodus hat man keinen zusammenhängenden 
Prozess mehr.
Ein Main hab ich schon geschrieben, ist hier nicht von Bedeutung, da da 
nur Sachen initialisiert werden etc.
#880813
Lesenswert?

Kartoffel wrote:
> @AC/DC:
>
> hier ist das Debuggen nicht möglich, da das ganze ja ein physikalischer
> Prozess ist. Im Einzelschrittmodus hat man keinen zusammenhängenden
> Prozess mehr.

Um so wichtiger, dass du Log Files hast, mit denen man auch etwas
anfangen kann.
Gast #880854
Lesenswert?

Nimm die neuberechnung für deinen I-Anteil aus der If bedingung raus.

Dann den I - Anteil begrenzen auf z.B. +- 10 oder +- 15

Dann den P- Anteil begrenzen  auf z.B. +- 15 oder +- 20

Dann summieren

Dann alles begrenzen auf 20 bis 400


Ich denke, dass bei deinem log die untere Begrenzung bei 30 lag. Wenn 
deine Stellgroße nun kleine als 30 ist (z.B. P =15, I= 5), wird dein I 
Anteil niemals größer. also reiner  p_ Regler mit offset, da I=konstant.
Gast #881454
Lesenswert?

@AC/DC:

>hier ist das Debuggen nicht möglich, da das ganze ja ein physikalischer
>Prozess ist. Im Einzelschrittmodus hat man keinen zusammenhängenden
>Prozess mehr.

Meine Frage nach der Sollwertangabe hast du leider nicht beantwortet.

Also nach einer Dokumentation über das Debuggen macht es keinen Sinn
wenn Echtzeit oder die Aktion/Reaktion der Hardware getestet werden 
soll.
(Ich vermute da du das mit physikalischer Prozess meinst)
Wenn du mit printf Werte ausgibst ist das für mich sehr wohl debuggbar.
Aber mach man es so wie du das für richtig hälst. Vielleicht bin ich mit
meinem Vorschlag ja auf dem Holzweg. Habs ja nur gut gemeint.
Gast #881571
Lesenswert?

@ gast und gast 99:

also normalerweise würde ich die untere Grenze der Stellgröße auf 0 
begrenzen. Das Problem dabei ist, dass bei Stellgröße=0 die 
Motordrehzahl auch = 0 U/min wird. Heißt: Motor dreht sich nicht.
Meine Drehzahlbestimmung erfolgt mittels Interrupt, der bei jedem pos. 
Impuls des Encoders ausgelöst wird. Das bedeutet, wenn sich der Motor 
nicht dreht, dann kann auch keine Drehzahlbestimmung mehr erfolgen und 
es kann nicht festgestellt werden, dass die aktuelle Motordrehzahl = 0 
ist. Es wird mit dann mit alten Werten geregelt und nicht mit den 
aktuellen.
Gast #881633
Lesenswert?

Du überprfts bei einer bestimmten anzahl von interrupten, wieviel zeit 
vergangen ist?

Überprüfe doch in regelmäßigen zeitabständen, die anzahl der interrupte 
und mache dann einen reset.

Wenn du in der unteren begrenzung bist, kann dein I anteil die bleibende 
regelabweichung nicht mehr ausregeln.

Was macht deine regelung denn bei einer sollgröße (z.B. 1500 U/min), bei 
der deine stellgröße nicht in der begrenzung arbeitet?
#881674
Lesenswert?

So ungefähr müsste das aussehen. Ob die +- 1000 bei der Begrenzung
der I-Anteils sinnvoll sind oder nicht, kann ich so nicht sagen.
Das muss man ausprobieren.
1
//*************************************************************************************
2

3
unsigned int Regeln (unsigned int Istdrehzahl)
4
{
5
  int Stellwert;
6

7
  pi_r.Istwert = Istdrehzahl;
8
  pi_r.Sollwert = Solldrehzahl;  
9
  pi_r.Regelabweichung = pi_r.Sollwert - pi_r.Istwert;
10

11
  pi_r.I_Anteil = pi_r.I_Anteil + pi_r.Regelabweichung;
12
  // I Anteil begrenzen, Anti Windup
13
  if( pi_r.I_Anteil > 1000 )
14
    pi_r.I_Anteil = 1000;
15
  else if( pi_r.I_Anteil < -1000 )
16
    pi_r.I_Anteil = -1000;
17

18
  Stellwert = (pi_r.Kp*(pi_r.Regelabweichung))/16 +
19
              ((pi_r.Ki*pi_r.I_Anteil)*pi_r.Ta)/10000;  //Ta= 210ms, nicht durch 1000, weil  Ki=12/10
20
  
21
  if( Stellwert < 20 )          // Begrenzung nach unten, also auf FE6F
22
    Stellwert = 20;
23

24
  else if( Stellwert > 400 )    // Begrenzung nach oben, also auf FFFF
25
    Stellwert = 400;
26

27
  pi_r.Stellwert = MIN + Stellwert;
28

29
  printf("%d\t%d\t%d\t%d\n", Istdrehzahl,
30
                             pi_r.Regelabweichung,
31
                             pi_r.I_Anteil,
32
                             Stellwert );
33

34
  return pi_r.Stellwert;      // Übergabe Stellgröße
35
}
Gast #881695
Lesenswert?

@ Karl heinz Buchegger:
hab ich doch schon lang getan, hab noch nicht gepostet gehabt, weil es 
noch nicht optimal läuft.
Den I_Anteil hab ich zufälligerweise auch auf +/-1000 begrenzt. Hab es 
aber auch mit anderen Werten ausprobiert, der Regler verhält sich bei 
verschiedenen Drehzahlen anders, heißt bei 500 u/min ist die Begrenzung 
von 1000 gut, bei 1000u/min eine andere....
#881700
Lesenswert?

Kartoffel wrote:
> verschiedenen Drehzahlen anders, heißt bei 500 u/min ist die Begrenzung
> von 1000 gut, bei 1000u/min eine andere....

Lass mich raten, du hast Schwingungen?
Ich würde mich auch an deiner Stelle nicht zusehr an die K-Parameter
klammern. Auch wenn du die theoretisch bestimmt hast (oder gerade
deswegen)
Gast #881701
Lesenswert?

@ Karl heinz Buchegger:
ja, der Motor bewegt sich total ruckartig und manchmal regelt er sich 
nicht auf die Solldrehzahl ein. Z.B. bei einer niedrigen Solldrehzahl 
von unter 300, schwingt er sich auf ne Drehzahl von ca. 70 ein.
Vielleicht sollte ich wirklich an dem Kp noch drehen.....??
Persönliche Seite #881741
Lesenswert?

Wegen dem Timer:

Du nimmst die kleine auftretenden Drehzal und bestimmst die Zeit die 
dann ein Interupt dauert.
Sagen wir mal auf niedrigster Drehzahl kommt alle 100ms ein Interupt.

Dann startest du einen Timer der bei etwa 150ms überlauft/einen Compare 
auslöst.

Im Interupt für die Drehzalmessung sezt du den Timer auf 0.

Timer interupt tritt nie auf --> Der Motor dreht
Timer interupt tritt auf --> Der Motor steht
Gast #881939
Lesenswert?

Ein Motor hat eine statische (konstant) und eine dynamische (in 
Abhängigkeit von der Drehzahl) Reibung. Beides muss man (zumindest) 
näherungsweise bestimmen und dann kompensieren.

Mit einfach an einem Parameter drehen wird es echt schwer. Gib doch 
einmal genauere daten zum Motor (Datenblatt?).
Gast #884142
Lesenswert?

sodala, jetzt hab ich ein bisschen was geändert, denn die 
Stellwertbegrenzung:
1
if(Stellwert <= 0)      // Begrenzung nach unten, also auf FE6F
2
  {
3
    Stellwert = 30;
4

5
  }
stimmt ja nicht. Das hab ich nur vorläufig so gemacht, weil bei 
Stellwert = 0(das wär die richtige Begrenzung), die Drehzahl auch auf 0 
gesetzt wird.

Die Drehzahlermittlung geschieht aber nur bei nem Interrupt durch pos. 
Impuls vom Encoder. Das würde heißen: es kann nicht festgestellt werden, 
dass die Drehzahl = 0 ist.
Jetzt hab ich es so geändert:
1
Drehzahl_mot =(unsigned int) (Drehz_sum/Durchlauf);
2
    if (Stellwert_alt == 0)
3
    {
4
      Drehzahl_mot = 0;
5
      Drehz_sum = 0;
6
      Durchlauf = 0;
7

8
    }

in Drehz_sum ist die Summe der Drehzahlen über eine Umdrehung (500 
Impulse).

Die Ausgabe der Werte, hab ich angehängt. Etwas haut da nicht hin....
Wieso zeigt er mir die pi_r. Stellwert so komisch an?

Ausgabe:
1
printf("%d\t%d\t%d\t%d\t%d\t\n",Istdrehzahl,
2
                                pi_r.Regelabweichung,
3
                                pi_r.I_Anteil,
4
                                Stellwert,
5
                  pi_r.Stellwert);
Angehängte Dateien:
Gast #884178
Lesenswert?

pi Struktur:
1
struct PI_Regler                   // Motorregler, realisiert als PI-Regler
2
{
3

4
unsigned int Sollwert;
5
unsigned int Istwert;
6
unsigned int Stellwert;     
7
signed int Regelabweichung;     // kann auch negativ werden  
8
signed long int I_Anteil;         // kann auch negativ werden 
9

10

11
int Kp;
12
int Ki;
13
int Ta;    // Abtastzeit = Zeit zw. 2 Drehzahlmessungen
14

15
}pi_r;
Gast #885140
Lesenswert?

Hab die Ausgabe jetzt berichtigt. Hab aus dem I-Anteil auch nen unsigned 
int gemacht.
Gestern ist mir noch ein Fehler aufgefallen und zwar: die Aufrufperiode 
des Reglers war größer als die Streckenzeitkonstante des Reglers (=Ta 
beim PT1=12,77ms).
Hab die Aufrufperiode jetzt auf ca. 1ms reduziert.
Außerdem wurde mir empfohlen, die Periode von PWM auch auf ca. 1ms 
einzustellen, ich hatte sie viel schneller eingestellt gehabt.
Weiß jemand warum?
Ich hab es schon gemacht, bin jetzt auch im hörbaren Bereich und es 
piepst schrecklich...
Gast #885371
Lesenswert?

sodala, die Abtastzeit beträgt jetzt 1,6ms.
Der Code sieht so aus:
1
//*************************************************************************************
2
//                     Funktionen
3
//*************************************************************************************
4
extern int PI_Init(void)
5
{         
6
pi_r.Kp = 1;
7
//pi_r.Ki = 12; // Ki = 1,2
8
pi_r.Ki = 10;
9
pi_r.Ta = 16;  // Ta ist 1,6 ms
10

11

12
Begrenzung = 0;
13
pi_r.I_Anteil = 0;
14
pi_r.Regelabweichung = 0;
15

16
return 0;
17
}
18
//*************************************************************************************
19

20
unsigned int Regeln (unsigned int Istdrehzahl)
21
{
22

23
signed int Stellwert = 0;
24

25
  pi_r.Istwert=Istdrehzahl;
26

27
  //printf("Istdrehzahl: %d",pi_r.Istwert);
28
  //printf("\n");
29

30
  pi_r.Sollwert=Solldrehzahl;  
31
  pi_r.Regelabweichung = pi_r.Sollwert-pi_r.Istwert;     // e=w-x
32

33
   
34
  //         Antiwindup     
35

36
    pi_r.I_Anteil = pi_r.I_Anteil + pi_r.Regelabweichung;          // esum=esum+e
37
    
38
    if( pi_r.I_Anteil > 100 )
39
       pi_r.I_Anteil = 100;
40
                
41
       if( pi_r.I_Anteil < -100 )
42
       pi_r.I_Anteil = -100;  
43

44

45
  Stellwert = (pi_r.Kp*(pi_r.Regelabweichung))/5 + ((pi_r.Ki*pi_r.I_Anteil)*pi_r.Ta)/10000;  //Ta= 210ms, nicht durch 1000, weil  Ki=12/10
46
  
47

48
  if(Stellwert <= 0)      // Begrenzung nach unten, also auf FE6F
49
  {
50
    Stellwert = 0;
51

52
  } 
53

54
   if(Stellwert > 400)    // Begrenzung nach oben, also auf FFFF
55
  {  
56
    Stellwert =400;
57
  }
58

59
Stellwert_alt = Stellwert;     
60
pi_r.Stellwert = MIN + Stellwert;
61

62
printf("%d\t%d\t%d\t%d\t%u\t\n",Istdrehzahl,
63
                                pi_r.Regelabweichung,
64
                                pi_r.I_Anteil,
65
                                Stellwert,
66
                  pi_r.Stellwert);    
67

68

69
  return pi_r.Stellwert;      // Übergabe Stellgröße
70
}

Hab die Werte, die ich beobachte angehängt. Irgendwie ist es jetzt so, 
dass dass egal wie ich mein Ki verändern tue,  sich nichts ändert. Ich 
hatte Ki zwischen 1 und 10000 und meine geregelte Istdrehzahl hat sich 
nicht geändert.
Angehängte Dateien:
#885525
Lesenswert?

Schau dir doch mal dein LOG File an.

Dein I-Anteil ist ständig in der Begrenzung von +100.
Wie soll denn da der Regler die Stellgröße noch erhöhen
können, wenn die Begrenzung das verhindert.


Was wird das eigentlich? Soll jetzt das Forum deinen Regler
per Ferndiagnose komplett debuggen? Ein bischen mehr
Eigeninitiative!
Gast #886318
Lesenswert?

@ Karl heinz Buchegger:
also an der Begrenzung des I-Anteils ist es nicht gelegen. Egal ob ich 
auf 100, 1000 oder 10000 begrenzt habe, hatte ich das gleiche Verhalten.

Habe das Problem jetzt orten können(aus Eigeninitiative :-)).
Wenn ich Ki=100 genommen habe und die Reglergleichung so:
1
Stellwert = ((pi_r.Kp*(pi_r.Regelabweichung))/5) + (((pi_r.Ki*pi_r.I_Anteil)*pi_r.Ta)/10000);

dann hat es nicht funktioniert und er hat nie auf den Sollwert geregelt. 
Wenn ich allerdings Ki=1 hatte und die 100 mit den 10000 verrechnet hab 
(mathematisch eigentlich das Gleiche).
Die Gleichung schaut so aus:
1
Stellwert = ((pi_r.Kp*(pi_r.Regelabweichung))/5) + (((pi_r.Ki*pi_r.I_Anteil)*pi_r.Ta)/100);

Dann hats funktioniert. Erklären hab ichs mir noch nicht können, bin 
eingentlich durch Ausprobieren drauf gekommen. Werd mir jetzt noch 
Gedanken machen, wieso es so funktioniert und anders nicht.
Ach ja, die /10000 kommen von der Abtastzeit von 1,6ms.
Die hatte ich am Anfang 0,2 s gewählt und die war eindeutig zu groß 
gewählt (auch Eigeninitiative!!!).

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