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
floate=0;
4
floatesum=0;
5
floatK_p=10.0,K_i=0;
6
floatu=0;
7
8
for(inti=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
floaty=((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(inti=(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.
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.
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?
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.
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.
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?
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...
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
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.
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.
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.
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.
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
Vielen Dank für eure Antworten.
Ich hoffe ich hab mein Problem soweit eingrenzen können.
Die Zeile :
1
floaty=((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).
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