LegDuinoWay

Hallöle.
Da es mit meinem Schiff gut vorangeht, und ich ab und zu gerne was anderes mache hab ich mich vor ner Weile auch mal hingesetzt und nen "Segway" aus nem Mega, einem MPU 6050 und nem Motorshield sowie einer Handvoll Legoteilen zumsammengetüdelt.
Nachdem der nun ne Weile mehr oder weniger unbeachtet hier herum stand (das Schiff war wichtiger) hab ich mich mal wieder rangesetzt und: es funktioniert.
Dank Volvodani, der im anderen Lego-Arduino-Segway-Thread so schön die Grundlagen erklärt hat.
Kricht er nen Karma für-wenn ich ihn mal sehe. Versprochen. :slight_smile:
Genauso mag ich das: ist toll, wenn andere hier helfen, aber ich möchte selber lernen, wies geht und nicht fertige Codes bekommen, die ich nachher nicht wirklich verstehe.
Nach hm, insgesamt vielleicht zwei Stunden Code tippen (ernsthaft, nen bisschen dran herumgespielt hab ich da schon länger) balanciert das Ding schon so, dass man "balancieren" dazu sagen kann.
Hab leider nix zum filmen-was das Handy "Videos" nennt ist grauslig, werd mir wohl doch mal ne neue Kamera zulegen müssen.

Darum gehts auch nicht- im Prinzip macht er seine Sache recht ordentlich, aber: er haut ab.
Früher oder später geht er stiften, und das-logisch- immer in die Richtung, die ein bisschen schwerer ist.
Ganz normal bei der Vorgehensweise, da man dem Regler ja nen absoluten Sollwert füttert: "Bleib senkrecht".
Meiner Meinung nach kanns so nicht optimal klappen, dann kullert das Ding nämlich, auch wenn es mechanisch ausbalanciert ist, schon bei Rückenwind davon...
Weit weg also von Praxistauglichkeit, oder?
Das muss doch ein ordentlicher XYZway besser können?
Die ich bisher so im Net gesehen habe, zumindest in Spielzeuggrösse können es wohl nahezu durchweg eben nicht.
Beim Bemannten stellt sich das Problem weniger da man den, wenn man ihn besteigt, automatisch ausbalanciert- man regelt ja mit.

Prinzipiell ist es so, dass der Kalman-Filter auf der entsprechenden Achse nen korrekten Winkel ausspuckt: steh der Sensor senkrecht, also 180 Grad. Und genau die versucht nun die Regelung auf Teufel-komm-raus irgendwie zu halten. Legt man nen Streichholz auf die eine Seite, klappt das nur noch, wenn ununterbrochen geregelt wird- und schon haut der Bursche ab.
Mir ist klar, dass man das über eine -dann-fahr-andersrum-Regelung auffangen kan, aber wärs nicht sinnvoller, wenn die Regelung so abläuft, dass diese 180 Grad dynamisch angepasst werden?

Im Grunde muss es dem Ding Wurst sein, in welchem Winkel er steht, solange er immer brav die Räder unter den Schwerpunkt wuchtet.
Hat jemand eine Idee, wie man das bewerkstelligen könnte?

Rabenauge:
Hat jemand eine Idee, wie man das bewerkstelligen könnte?

Vom Prinzip her darfst Du nicht nur auf den Balancewinkel regeln. Denn das Teil kann in Balance sein und stillstehen oder es kann in Balance sein und dabei fahren. Balance ist Balance und es macht für die Balanceregelung keinen Unterschied, ob es fährt oder nicht. Daher ist es reiner Zufall, wie die Balance erreicht wird, ob fahrend oder im Stillstand.

Prinzipiell benötigst Du einen Sensor, der die gefahrene Wegstrecke mißt und damit sowohl Strecke als auch Geschwindigkeit feststellen kann.

Die Regelfunktion darf dann eben nicht nur sagen "(Vertikalwinkel-180°==0)", sondern die Regelungsfunktion muss regeln auf:

"(Vertikalwinkel-180°==0) && (Entfernung vom Startpunkt ==0) && (aktuelle Geschwindigkeit==0)

Also Du darfst nicht nur eindimensional nur auf den Balancewinkel regeln, sondern die Regelung muß viel komplexer sein und auch die Entfernung von dem Punkt berücksichtigen, an dem sich das Gefährt befinden soll und die Geschwindigkeit, mit der es sich bewegen soll (im Stillstand also Nullgeschwindigkeit).

Hi,
hast du es mal versucht mit verschiednen PID Parameter gemacht. also wenn die Abwichung z.B. 3° ist einen größeren P bzw D Anteil zu nehmen damit der unterwagen "schneller" fährt als der schwerpunkt. Dann müsste er ja mit dem Nullpunkt herum tanzen da er dann wieder in den moderaten bereich kommt müsste er sich doch einfangen.
Gruß
DerDani

Am einfachsten 5 Poti ran (I-Anteil kann beleiben aber P,D jeweils einen moderaten und aggressiven Teil)

Der Rest ist Regler optimieren. Was immer wieder ein großes Problem bei dem "Spielzeug"-Motoren ist das die Getriebe nicht spielfrei sind bzw. du einen recht großen Totbreich im untern PWM-Bereich bei der anteuerung der Motoren.

Hm...schwerer Tobak.

@Jurs: der 6050 kann doch auch Beschleunigungen messen. Mein Gedankengang bisher ist der, dass man die Beschleunigung mit in die Regelung einspeist und somit die 180° (bzw. 0° für den Regler) dynamisch anpasen kann.
Wenn also eine ungewollte Beschleunigung über eine bestimmte Zeit anhält, kann man ja von ausgehen, dass das Gerät nicht im Gleichgewicht ist-also müssen die 0° angepasst werden.

@Dani: nein, hab ich noch nicht (das hattest du im anderen Thread auch schon geschrieben, war mir aber entfallen)- das werd ich gleich mal ausprobieren.

Was die "Spielzeugantriebe" angeht: stimmt, wirkliche Präzision gibts da nicht, zumal ich anders als "er" im anderen Thread (weiss grad den Namen nicht, sorry) die Räder nicht direkt auf den Motoren habe-ich hab noch mal ne Untersetzung drin, die natürlich auch Spiel aufweist (die RCX-Motoren an sich sind ziemlich präzise), und ich bin erstaunt, wir gut die Regelung trotzdem greift.
Wenn das Teil nun nicht absolut ruhig stehen will, kann ich damit leben- mein Ziel ist ein grösseres und da kommen auch andere Antriebe rein.
Aber um das Prinzip in den Griff zu bekommen, finde ich den LegDuinoWay recht praktisch.

Oook- es geht voran.
Der Tipp mit den dynamischen Regelparametern war gut- ich glaube, so wird es was.

Allerdings: wenn ich die PID-Regler richtig verstehe, dann ist es sinnvoller, bei grösseren Abweichungen von der Wunsch-Lage den I-Anteil zu verkleinern oder?
Momentan arbeite ich ohne I (und ohne D)..

Mit einem reinen P-Regler kommt man nicht weit, da keine Stellgröße mehr gebildet wird wenn die Regeldifferenz 0 ist. Der I-Regler behebt dies. Der D-Anteil ist dazu da die ganze Sache zu beschleunigen. z.B. bei langsamen Regelstrecken oder um den langsamen I-Anteil etwas auszugleichen. Kd ist dabei im Vergleich zu Kp und Ki recht klein. Ein PI-Regler tut es manchmal auch schon.

Vereinfacht gesagt...

Das mit dem unterschiedlichen I-Anteil kannst du auch machen. Ohne wird es schwierig. Ich habe nur die erfahrung gemacht das es keinen großen Unterschied macht auch die I-Zeit zu ändern da du ja sowieso "große" Regelabweichungen bei den aggressiven Werten hast. Aber einfach mal ausprobiern.
Bei so einem Instabilen System braucht man schon einen PID um es ordentlich zu balancieren. Irgendwann wenn du ihn zu sehr aus dem Gleichgewicht bringst schaffst du das dann nicht mehr auszuregeln wenn der Schwerpunkt zu sehr um die Achse gekippt ist.
Gruß
Der Dani

Genau da liegt der Hase im Pfeffer.
Wenn ichs richtig kapiert habe soll man zuerst den P-Anteil so lange hochschrauben, bis das Ganze anfängt, sich aufzuschwingen- der XYZ-Way also pendelt.

Ohne I-Anteil komme ich dort aber gar nicht erst hin, die Regler spucken dann, selbst bei 5 Grad Abweichung, eine lausige 10 aus.
Spätestens da aber müsste Vollgas gegeben werden, aber selbst mit P-Werten über 100 passiert eben das nicht.
Bin ich wirklich so beschränkt? Überall lese ich: ists nicht aggressiv genug-rauf mit P.

Bis gestern habe ich da getrickst und einfach den Wert, den der Regler ausspuckt, mit 10 multipliziert, um überhaupt in Bereiche zu kommen, in denen die Motoren irgendwas bewirken, aber das kann doch nicht die Lösung sein?

Änderungen an den Regler-Limits bringens auch nicht, wenn ich den Wertebereich von -120 bis 120 einstelle, dann ist das Ding genauso lahmarschig wie bei -255, 255 , hört aber halt nur früher auf...

im Prinzip macht er seine Sache recht ordentlich, aber: er haut ab

Das ist jetzt nicht mehr so ?
Spuckt dir die überlagerte Regelung ( wie greift die ein ? ) dazwischen ?

Bis gestern habe ich da getrickst und einfach den Wert, den der Regler ausspuckt, mit 10 multipliziert, um überhaupt in Bereiche zu kommen, in denen die Motoren irgendwas bewirken, aber das kann doch nicht die Lösung sein?

Das kannst du natürlich auch gleich im Regler machen: den P mal 10 nehmen oder die Regelabweichung in anderem Wertebereich skalieren.
Ist der Reglerausgang gleich der PWM Wert für den Motor ( -255 .. +255 ) ?

Nein, er rannte nicht mehr davon- aber das liegt auch daran, dass ich ihn soweit umgebaut habe, dass er so halbwegs alleine die Waage hält nun.

Den P-Wert noch höher stellen bringt nix: im unteren Bereich (praktisch kann das Ding gar nicht mehr als 15 grad kippen, weil er dann aufsitzt) kommen trotzdem keine höheren Werte aus dem Regler.
Und das ist das Problem.
Im kleinen Bereich (sagen wir, ein, zwei Grad Abweichung) regelt er sehr sanft-das ist supi. Teilweise steht das Ding (mit kleiner "Uunterstützung" durchs USB-Kabel-leise summend auf dem Punkt.
Aber: wenn er dann kippt (bzw. ich ihn schubse) ist die Regelung so lahm, dass er sich nicht rechtzeitig fängt.

Der Regler muss praktisch im Bereich von -5° bis 5° alles geben, was da ist-und das macht er eben nicht.
Momentan lasse ich Kp dynamisch berechnen, ungefähr so:

Kp=10*(Sollwert-Istwert)-> natürlich werden die Vorzeichen in ner if-Schleife beachtet.
Und die 10 ist flexibel-mit dem selben Ergebnis kann ich da eine 2 oder 5 eintragen. Tut sich nix.

Die Reglerausgänge hatte ich von Anfang an auf -120,120 eingestellt, inzwischen auch mal auf 255 erhöht- das bringt auch nix: dann kommen zwar höhere Werte heraus, aber erst, wenn ich das Maschinchen um 60 Grad umkippe...
In dem Bereich, denn ich brauche (max 5 Grad in jede Richtung, alles andere packen die Motoren eh kaum noch) ändert sich da überhaupt nichts.

Habe mal die dynamische Anpassung von P wieder rausgeworfen, und schon sieht es besser aus (warum auch immer), aber inzwischen hab ich ein ganz neues Problem:

Y:175.61     Kp: 30.00  |   Links: +134.28    Rechts: +134.28
Y:175.72     Kp: 30.00  |   Links: +128.28    Rechts: +128.28
Y:175.78     Kp: 30.00  |   Links: +128.28    Rechts: +128.28
Y:175.74     Kp: 30.00  |   Links: +127.70    Rechts: +127.70
Y:175.82     Kp: 30.00  |   Links: +127.70    Rechts: +127.70
Y:176.94     Kp: 30.00  |   Links: +91.70    Rechts: +91.70
Y:177.96     Kp: 30.00  |   Links: +91.70    Rechts: +91.70
Y:179.58     Kp: 30.00  |   Links: +12.66    Rechts: +12.66
Y:181.69     Kp: 30.00  |   Links: +12.66    Rechts: +12.66
Y:184.09     Kp: 30.00  |   Links: 122.76    Rechts: 122.76
Y:185.84     Kp: 30.00  |   Links: +122.76    Rechts: +122.76
Y:186.21     Kp: 30.00  |   Links: 186.41    Rechts: 186.41
Y:185.19     Kp: 30.00  |   Links: +186.41    Rechts: +186.41
Y:183.33     Kp: 30.00  |   Links: 99.97    Rechts: 99.97

Y ist der -durch den Kalmanfilter ermittelte-Wert der MPU. 180 wäre senkrecht.
Ist Y kleiner als 180, passt es bestens.
Wird Y jedoch grösser als 180, bekomme ich abwechselnd ein positives und ein negatives Vorzeichen.

Das "Vorzeichen" brauche ich, da das Motorshield Drehrichtung UND Geschwindigkeit haben möchte, das erledige ich so:

ReglerR.Compute();                                    // Regelung berechnen
   if (speedR<0){                                                        // wenn Ergebnis negativ
    speedR=abs(speedR);                                        // speedR in Absolutwert wandeln
    richtungR=0;                                                         // Richtungsflag umdrehen, für rückwärts
    }
  else{
    richtungR=1;                                                          // Richtung vorwärts
  }

speedR ist das, was der PID ausspuckt...da er von -255 bis +255 ausgeben kann, muss das in "Vorzeichen" (für vorwärts oder rückwärts) und "Betrag" (halt die "Drehzahl" ) aufgeteilt werden.

Ich schätze, ich hab da irgendwo nen Fehler drin, finde ihn aber nicht....jemand eine Idee dazu?

Ich schätze, ich hab da irgendwo nen Fehler drin, finde ihn aber nicht....jemand eine Idee dazu?

Der Fehler ist wohl, speedR zu verändern, da ReglerR.Compute() damit vermutlich was macht.

float speed;
boolean richtung;
if (speedR<0){ 
 speed = - speedR;
 richtung = 0;
} else {
 speed = speedR;
 richtung = 1;
}

Ich sehe das so, dass du den kp Wert jetzt von 10 statt nach 2 oder 5 (bringt nix) nach 30 verändert hast ... :wink:

ReglerR.Compute macht nix anderes als die Regelung zu berechnen-laut anleitung soll man das jedes Mal tun, wenn man es braucht.
speedR ist die Ausgabe des Reglers, also das Ergebnis.

Da das auch negativ sein kann (der Regler kann ja von -255 bis +255 ausgeben), muss ichs erstens in ne positive Zahl umwandeln (das Motorshield möchte das halt so) und je nach Vorzeichen eben ein "Flag" setzen- vor-oder rückwärts.
Wie gesagt: in der einen Hälfte des Wertebereichs klappt das super- nur in der anderen eben nicht, da kommt abwechselnd vor-und rückwärts raus bei. :frowning:
Toll daran ist, dass ich diese Umwandlung von Anfang an so mache-und die bis vor drei Stunden wunderbar funktioniert hat.

Was Kp angeht (monentan nicht das Thema, aber dabei tauchte dann das Problem irgendwie auf): stimmt. Kp ist derzeit 30- und zwar fest.
Damit erreiche ich sinnvolle Wertebereiche. Auch das kapiere ich nicht, denn als ich das noch dynamisch berechnen lassen habe kam ich, trotz Werten von Kp>100 nie in so hohe Ausgabe-Bereiche, ausser ich hab das Ding mit Gewalt richtig weit gekippt.
So langsam vermute ich da irgendwo Timing-Probleme...aber erstmal mus diese Vorzeichen-Geschichte geklärt werden.

Nachtrag: du hattest recht: schuld war die Manipulation von speedR. Zwar unverständlich, da es ne reine Ausgabe ist, aber es ist so.
Hab das ganze nun aufgeteilt, speedR bleibt wie sie ist und die Manipulation wird in einer zweiten Variable gemacht-schon gehts wiede r(hatte ich bis heute nachmittag auch so, kam mir aber unnötig vor-wars dann also nicht)..

Spielen wir also weiter mit dem Regler rum..:slight_smile:

speedR ist die Ausgabe des Reglers, also das Ergebnis.

speedR ist eine globale Variable, und Regler brauchen was für ihren Zustand... war aber nur ein Verdacht ...

mit einer eigenen lokalen Variable (speed) bist du auf jeden Fall "rückwirkungsfrei".

Wie ich oben schon editiert hab (wahrscheinlich zur selben Zeit wie du schriebst) lagst du richtig mit deinem Verdacht.
Ich hab die Änderung inzwischen in ne andere Variable ausgelagert-und schon läufts wieder.

Inzwischen spiel ich wieder an den PID`s rum.
Leider sind wieder die Batterien müde, ich glaub, ich baue das Gerät auf NC-Packs um, die kann ich schneller laden, als die LEGO-Motörchen sie leerfressen können. Muss mir nur irgendwie nen Adapter von Tamiya-Stecker auf Arduino zusammentüdeln und die Hardware bisschen umbauen- mit den AA-Batterien bringt das nix.

Ja, hab dein edit nicht rechtzeitig gesehen...

Zwar unverständlich, da es ne reine Ausgabe ist

Regler arbeiten gerne in festen Zeitintervallen. Für P ist das zwar egal bis ungünstig, aber I und D Anteile lassen sich so leichter berechnen.
Ich tippe drauf, dass man Compute() zwar so häufig wie möglich aufrufen sollte, das aber beileibe nicht immer was macht, sonden evtl. den Ausgangswert unverändert lässt (egal wer ihn verstellt haben sollte).

Schau dir den sourcecode des Reglers an. Auch wenn du zu dem Schluss kommst, dass da Mist drin sein sollte, lernst du sicher was.
Ob du dann den Regler anpasst oder dein Programm, ist eine andere Frage, die du inzwischen schon beantwortet hast :wink:
Die einzige zuverlässige Doku ist der Sourcecode selbst

Da fehlt mir ein bisschen Verständnis.
Einerseits soll Compute() dann aufgerufen werden, wenn ich das Resultat auch brauche.
Andererseits kann man festlegen, wie oft die Regelung berechnet wird- dafür gibts SetSampleTime().

Ich ging eigentlich immer von aus, dass Programme linear ablaufen.
Im Hauptprogramm läuft das bei mir so:
-Sensorwert des MPU holen
-den durch den Kalman-Filter jagen,
-das Resultat (ist dann schick der Winkel der betreffenden Achse) an den Regler übergeben
-Regelung berechnen (Compute() )
-Ergebnis zu den Motoren schicken

Hm, hilft, das mal aufzuschreiben, seh ich gerade...das Ganze dürfte weniger als 80mS dauern, und bei SetSampleTime hab ich 80ms angegeben. Möglicherweise rechnet dann der PID z.T. noch mit "alten" Daten?

Versuch das alles man so schnell wie möglich zu machen.
du kannst den ablauf deines Programmes mal ausgeben lassen.

Am anfang der loop

usigned long startmicros=micros();

am Ende der loop (vor deiner Seriellen Ausgabe)

usigned long endmicros=micros();

und dann ganz am Ende also an aller letzten Stelle

serial.Println(endmicros-startmicros,DEC);

dann bekommst du eine Zykluszeit der loop ich denke müsste irgenwas zwischen 1000-2500µs liegen
Die Sampletime im default ist 100ms kannst ja mal mit kleineren Werten probieren. (Wobei je kleiner die Zeit die Ausgabewerte vom D und I kleiner Werden aber diese dann auch öfter berechenet werden.
Gruß
DerDani

Hm- Tacho einbauen ist eine gute Idee.
Da ich das Maschinchen sowieso grade von Grund auf neu aufbaue (war zu tüdelig, man konnts nur an bestimmten Stellen anfassen und das Batteriefach ist nicht das Wahre- jetzt kommt nen Rachingpack drauf), könnte ich sogar nen Display anbauen.
Würde wohl auch praktisch nix schaden-ich glaub, sowas balancier besser wenn der Schwerpunkt möglichst hoch liegt oder?

So sieht es Aufgrund der Massenträgheit ist das Systemstabieler je höher der Schwerpunkt über der Achse hängt.
Versuch es mal mit nem Besen balancieren Normale Grifflänge und dann mit nem Kinder-Spielzeugbesen der "große" mit dem Schwerpunkt weiter oben lässt sich besser "regeln".
Schau mal hier bei den Instructables da gibt es eine Schönes Beispiel