Mahlzeit, ich versuche mich gerade daran, vorerst einmal nur die Geschwindigkeit eines Druckerschlittens (Spender: Epson Stylus) halbwegs unter Kontrolle zu bringen. Vorab einmal zum System an sich, wie es hier auf dem Schreibtisch steht: Mechanik: Wie gesagt, es handelt sich um einen Druckerschlitten aus einem Epson Stylus. Was ich übrig gelassen habe, ist die Führung aus Metall, den Schlitten aus Plastik, den DC-Motor als Antrieb mit Zahnriemen und den Gray-Code Plastikstreifen mit entsprechendem Sensor. Achja, das Teil steht hochkant, die Bewegungsrichtungen sind also hoch und runter. Elektronik: Besagter Motor wird von einem halben LM298 und 12 V angetrieben. Über zwei Pins lässt sich die Drehrichtung des Motors bestimmen und über den Enable Pin per PWM die Geschwindigkeit. Als Controller kommt ist ein AtMega328P vorhanden. Den Gray-Code lese ich über zwei Pins am Controller mittels PinChange-Interrupts und dem Code aus dem Artikel über Drehgeber aus. Den Artikel über Regler von RN-Wissen habe ich mir auch schon zu Gemüte geführt, aber ein paar Sachen kann ich noch nicht ganz nachvollziehen: Eingang/Ausgang eines Reglers: Die Abweichung von Soll zu Ist, bzw. dessen Ableitung und Integral gehen in den Regler rein. Soweit so gut, ich will die Geschwindigkeit regeln, also kommt die Differenz der Positionen zum Zeitpunkt t und t-1 rein. Als Ausgang habe ich dann eine 8 bit PWM, bzw. durch Richtungsänderung eine "9-bit signed PWM", zur Verfügung. Aber wie bekomme ich diese beiden unterschiedlichen "Formate" unter einen Hut? Die PWM geht von -255 .. 255, die Geschwindigkeit von ~ -23 d/ms bis 15 d/ms. Sollte ich versuchen das auf %-te gleich zu setzen, oder ist das dem Regler mit den richtigen Einstellungen sogar egal? Ein weiteres Problem ist, dass der Schlitten sich unterhalb eines PWM-Wertes von 190 gar nicht mehr bewegt, also habe ich im Ausgabebereich sogar noch sowas wie einen "blinden Fleck", in dem gar nichts passiert. Ki/Kp/Kd eines Reglers: Ja, ich habe gelesen, dass man hier ordentlich spielen kann, bestenfalls erstmal Ki und Kd auf 0 setzen und dann mit Kp loslegen. Aber wie sind denn die ganz grob ungefähren Bereiche, in denen man sich hier bewegt? Kd = 1,00 - 1,99, oder 0 - 200 oder, oder, oder? Ich will mich halt nicht in Nachkommaschritten an etwas herantasten, dass erst ab 100 oder so irgendwas macht. Ich hoffe ich konnte meine Unklarheiten halbswegs greifbar formulieren... Achja, damit das System von dem ich hier rede nicht ein vollkommen unklares verbal beschriebenes Gebilde bleibt, anbei noch ein paar Diagramme, wie es sich denn so bei konstanter PWM verhält. 200d in der Legende steht dann für PWM: 200, Richtung down 220u entsprechend für PWM 220, nach oben fahrend, usw. Zu den Einheiten: das "d" in "d/10ms" steht einfach für "dots" aus dem Encoder. Die gesamte Strecke ist ~9000 von diesen "dots" lang. Beste Grüße Niels
Ich wuerd den blinden Fleck wegmachen. Also zu einem Stellwert von +1 oder mehr wird 190 addiert, bei einem Stellwert von -1 oder tiefer wird 190 subtrahiert. Bei mir laufen die Regelungen ueblicherweise mit Longint Zahlen. Am Schluss wird fuer das Stellglied dann runterskaliert. zB auf 0-255. So kann man alle Rechnungen mit Ganzzahlen durchfuehren.
Niels J. schrieb: > Ki/Kp/Kd eines Reglers: > Ja, ich habe gelesen, dass man hier ordentlich spielen kann, bestenfalls > erstmal Ki und Kd auf 0 setzen und dann mit Kp loslegen. Aber wie sind > denn die ganz grob ungefähren Bereiche, in denen man sich hier bewegt? Kann man nicht sagen. > nicht in Nachkommaschritten an etwas herantasten, dass erst ab 100 oder > so irgendwas macht. NIemand hindert dich, da ordentliche Schritte zu machen. Probierst du 0.1 und nichts tut sich, dann probierst du eben 0.2 Tut sich dann immer noch nichts, dann probierst du 100. Jetzt kann es sein, dass dein Schlitten einen ordentlichen Satz macht, dann probierst du eben mal 50. Oder es tut sich nichts, dann probierst du 200. Erst mal musst du eine unegfähre Vorstellung davon kriegen, in welchem Zahlenbereich dein Reglerwert zirka liegen wird. Klar kann man das auch ausrechnen, insbesondere wenn man die Fehlerwerte kennt, denn mehr als Vollgas kann auch dein Regler nicht geben und daraus kann man zurückrechnen, welcher Kp Wert bei bekanntem Fehlerwert zu Vollgas führt. Aber meistens muss man nicht päpstlicher als der Papst sein. Es ist ja nicht so, dass bei dir dann der Kernreaktor durchgeht, wenn dein Reglerwert vollkommen daneben liegt. SIehs mal so: Als du das erste mal selber Auto gefahren bist, hattest du auch keine Ahnung, wie stark du aufs Gaspedal treten musst. War das ein Problem? Nicht wirklich: in ein paar Sekunden hattest du das raus, wieviel es ungefähr sein muss. Ruckelt es eben beim ersten mal ein wenig, aber nach dem 10ten mal anfahren hattest du den Dreh raus. Eine Hand am Schalter der Stromversorgung hat noch nie geschadet.
Da ich so vom TE unbeantwortete Threads selbst nicht ab kann, hier einmal meine Résumes: Oder D. schrieb: > Ich wuerd den blinden Fleck wegmachen. Also zu einem Stellwert von +1 > oder mehr wird 190 addiert, bei einem Stellwert von -1 oder tiefer wird > 190 subtrahiert. Danke für den Rat, werde ich wahrscheinlich auch noch machen, wenn ich die "Nullwerte" genauer ermittelt habe. Bis dahin tut's auch ein kleiner I Anteil, dauert dann ungefähr 10 ms länger, bis sich was bewegt. Karl H. schrieb: > SIehs mal so: Als du das erste mal selber Auto gefahren bist, hattest du > auch keine Ahnung, wie stark du aufs Gaspedal treten musst. War das ein > Problem? Nicht wirklich: in ein paar Sekunden hattest du das raus, > wieviel es ungefähr sein muss. Ruckelt es eben beim ersten mal ein > wenig, aber nach dem 10ten mal anfahren hattest du den Dreh raus. Danke für das anschauliche Sinnbild :D Nachdem ich mich dann mal dran gemacht habe, noch mehr Variablen meines Programms von außen veränderlich zu machen, und ich mir noch ein kleines Hilfstool zum Einstellen geschrieben hatte, bekam ich doch tatsächlich schnell ein Gefühl für das Gaspedal ;) Anbei noch ein Screenshot des Hilfstools mit grafischer Darstellung des Geschwindigkeits- und Reglerausgangsverlaufs. Beste Grüße Niels
Niels J. schrieb: > ich versuche mich gerade daran, vorerst einmal nur die Geschwindigkeit > eines Druckerschlittens (Spender: Epson Stylus) halbwegs unter Kontrolle > zu bringen. [...] Dazu wäre als erstes zu überprüfen, ob deine Lösung für die Eingangsgröße auch bei maximaler Verfahrgeschwindigkeit noch zuverlässig zählt (was ich ernsthaft bezweifeln würde). Weil: wenn aus der Istwert-Gewinnung schon nur Mist rauskommt, kannst du an den Reglerkoeffizienten rumspielen, bis du in der Kiste liegst, da wird niemals ein vernünftiges Ergebnis bei rauskommen können...
c-hater schrieb: > Dazu wäre als erstes zu überprüfen, ob deine Lösung für die > Eingangsgröße auch bei maximaler Verfahrgeschwindigkeit noch zuverlässig > zählt (was ich ernsthaft bezweifeln würde). Ich wüsste jetzt nicht, warum das anzuzweifeln wäre. Die Strecke ist 9000 "Ticks" lang und die maximale Geschwindigkeit ungefähr 30 Ticks/ms. Somit wird das Pin Change Interrupt mit maximal 33 kHz aufgerufen, ich denke mal, dabei langweilt sich der Controller noch mehr als genug. Auch sonst konnte ich bei "so schnell mit der Hand verfahren wie möglich" noch keinen Drift feststellen. Beste Grüße Niels
Niels J. schrieb: > ich denke mal, dabei langweilt sich der Controller noch mehr als genug. Da würde ich mal ganz kritisch im Auge behalten, wieviel Zeit er noch außerhalb der ISR "frei" hat - nur so zur Vorsicht, bevor es komische Effekte gibt. Ich weiß ja nicht, wieviel Rechnerei du ihm sonst noch so aufgetragen hast.
Niels J. schrieb: > Ich wüsste jetzt nicht, warum das anzuzweifeln wäre. Die Strecke ist > 9000 "Ticks" lang und die maximale Geschwindigkeit ungefähr 30 Ticks/ms. > Somit wird das Pin Change Interrupt mit maximal 33 kHz aufgerufen Hmm. 33kHz ISR-Frequenz ist schon nicht unbedingt wenig, Es hängt aber natürlich auch vom verfügbaren Systemtakt ab, was genau damit tatsächlich möglich ist. Ich kann in deinen bisherigen Äußerungen nur leider keinerlei Angaben dazu finden. Habe ich aber möglicherweise auch im dritten Anlauf einfach bloß überlesen... Und während du das rauskramst: bitte auch gleich noch den Code der entsprechenden ISR hinzufügen. Auch der glänzt im Thread bisher nur durch eins: vollständige Absenz.
Immer mit der Ruhe zu so später Stunde ;) Meine eigentliche Frage wurde inzwischen ja schon längst geklärt. Damit, dass meine mir selbst auferlegte Aufgabenstellung noch solche Tücken aufweisen könnte, habe ich nicht gerechnet. Den Code reiche ich trotzfen erst morgen nach, dafür ist es mir jetzt zu spät. Bis dahin noch einen entspannten Samstag Abend
Hallo Niels, Deine Beschreibungen über den Druckerschlitten, der sich auf und ab bewegt, haben mich neugierig gemacht. Magst Du verraten, wie das Projekt am Ende aussehen soll?
Sodele.. c-hater schrieb: > Hmm. 33kHz ISR-Frequenz ist schon nicht unbedingt wenig, Es hängt aber > natürlich auch vom verfügbaren Systemtakt ab, was genau damit > tatsächlich möglich ist. > > Ich kann in deinen bisherigen Äußerungen nur leider keinerlei Angaben > dazu finden. Habe ich aber möglicherweise auch im dritten Anlauf einfach > bloß überlesen... Ich kann dich beruhigen, der Code war tatsächlich noch nicht zu finden ;) Die Funktion wird jedesmal aufgerufen, wenn sich an den Pins des Encoder Ausgangs was ändert. Ich hatte mich bei meiner Geschwindigkeitsangabe allerdings noch geirrt, die beträgt maximal ~15 Ticks/ms daraus resultiert also eine Frequenz von ungefähr 16.7 kHz
1 | //Encode the Gray Code to an absolute Position
|
2 | void encode_gray(void) |
3 | {
|
4 | int8_t new, diff; |
5 | |
6 | new = 0; |
7 | if( PHASE_A ) |
8 | new = 3; |
9 | if( PHASE_B ) |
10 | new ^= 1; // convert gray to binary |
11 | diff = last - new; // difference last - new |
12 | if( diff & 1 ){ // bit 0 = value (1) |
13 | last = new; // store new as next last |
14 | position_current += (diff & 2) - 1; // bit 1 = direction (+/-) |
15 | }
|
16 | }
|
In der Main Schleife wird dann "nur" noch einmal pro ms der PID Algorithmus ausgeführt:
1 | if(pid_tick) |
2 | {
|
3 | pid_tick = 0; |
4 | w = speed; |
5 | x = position_current - position_old; |
6 | position_old = position_current; |
7 | esum += e; |
8 | e = w - x; |
9 | y = Kp * e + Ki * Ta * esum + Kd * (e-ealt)/Ta; |
10 | ealt = e; |
11 | if (y>255) |
12 | y = 255; |
13 | if (y<-255) |
14 | y = -255; |
15 | uart_putc(x>>8); |
16 | uart_putc(x); |
17 | uart_putc(y>>8); |
18 | uart_putc(y); |
19 | setSpeed(y); |
20 | }
|
Der ATMega328P läuft aktuell mit 11.0592 MHz, ich muss mal noch nach meinen anderen Quarzen suchen, das war halt gerade auf dem STK500. Anbei ist noch die gesamte main.c. Die ist allerdings noch sehr spärlich kommentiert, etliche Variablen lassen sich sicher noch optimieren etc. Hauptsächlich ist er darauf ausgelegt erstmal zu funktionieren, was er auch tut (Zumindest unterliege ich bisher noch diesem Glauben) Conny P. schrieb: > Hallo Niels, > Deine Beschreibungen über den Druckerschlitten, der sich auf und ab > bewegt, haben mich neugierig gemacht. Magst Du verraten, wie das Projekt > am Ende aussehen soll? Wenn ich mich mal wirklich soweit zusammenreiße, das bis zum Ende durch zu ziehen, soll es ein Kossel 3D Drucker werden. Mehr dazu hier: http://reprap.org/wiki/Kossel Aber anstatt der Schrittmotoren und den teuren Führungen halt mit "2D Drucker Innereien". 3 * 2D macht dann 3D ;) So, soviel erstmal dazu, ich widme mich dann mal wieder dem unsonnigen Sonntag Niels
Niels J. schrieb: > Die Funktion wird jedesmal aufgerufen, wenn sich an den Pins des Encoder > Ausgangs was ändert.
1 | //Encode the Gray Code to an absolute Position
|
2 | void encode_gray(void) |
3 | {
|
4 | int8_t new, diff; |
5 | |
6 | new = 0; |
7 | if( PHASE_A ) |
8 | new = 3; |
9 | if( PHASE_B ) |
10 | new ^= 1; // convert gray to binary |
11 | diff = last - new; // difference last - new |
12 | if( diff & 1 ){ // bit 0 = value (1) |
13 | last = new; // store new as next last |
14 | position_current += (diff & 2) - 1; // bit 1 = direction (+/-) |
15 | }
|
16 | }
|
17 | |
18 | ISR(PCINT1_vect) |
19 | {
|
20 | encode_gray(); |
21 | }
|
Das sieht schonmal garnicht gut aus. Es würde mich nicht wundern, wenn die Laufzeit des erzeugten Codes über 100 Takte ist. Du hast wirklich alles unternommen, um dem Compiler eine wenigstens auch nur halbwegs effiziente Umsetzung nicht zu ermöglichen. Wie wär's mal mit einem "inline"? Bei 33kHz ISR-Frequenz bräuchtest du also ca. 3MHz Takt, um auch nur die Positionserfassung zu machen. Und da dürfte dann nix anderes stören. Tut es aber, denn es gibt ja noch die genauso bescheuert gestrickte zweite ISR... Das zusammen könnte sogar bei 11MHz schon eng werden. Hoffentlich bist du wenigstens sicher, daß das Teil wirklich mit den angegeben 11Mhz läuft. Fuses?
c-hater schrieb: > Das sieht schonmal garnicht gut aus. Es würde mich nicht wundern, wenn > die Laufzeit des erzeugten Codes über 100 Takte ist. Du hast wirklich > alles unternommen, um dem Compiler eine wenigstens auch nur halbwegs > effiziente Umsetzung nicht zu ermöglichen. Wie wär's mal mit einem > "inline"? > > Bei 33kHz ISR-Frequenz bräuchtest du also ca. 3MHz Takt, um auch nur die > Positionserfassung zu machen. Und da dürfte dann nix anderes stören. Tut > es aber, denn es gibt ja noch die genauso bescheuert gestrickte zweite > ISR... Charmant.. wenn gleich auch absolut richtig. Deine Vermutung mit den 100 Takten hat mich dann doch mal etwas stutzig gemacht, also mal in die main.lss geguckt und siehe da: In der ISR Routine werden erstmal ALLE Register zwischengespeichert. Also die main.c editiert und neu kompiliert. Jetzt fallen acht mal push und acht mal pull weg, alleine das spart ja schon mal 32 Takte. Danke dafür :) Da die andere Funktion, die ich in der Timer ISR aufgerufen habe, inwzwischen ja auch nur noch eine Zeile lang war habe ich den Code direkt in die ISR verfrachtet, da sollte jetzt auch wesentlich weniger unnötiger Overhead produziert werden. Hast du sonst noch andere derartig grobe Patzer gefunden, oder ist's soweit erstmal erträglich? Beste Grüße Niels PS.: Bei den ~11 MHz bin ich mir sicher, anfänglich hatte ich noch eine LED im Sekundentakt am blinken, einfach als sichtbares Lebenszeichen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.