PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmega168 Timer initialisieren und an/aus-schalten



erik_wolfram
02.01.2013, 15:57
Hallo!

Ich versuche einen optimalen Code für meinen Quadrupped mit 12 Modellbauservos zu schreiben und stehe vor vor folgendem Problem:

Hierfür möchte ich 2 Timer verwenden.
Ein Timer (Timer1 16-Bit) der alle 20 Sekunden auslöst und den 2. Timer (Timer0 8-Bit) aktiviert. Der 2. Timer arbeitet dann alle Servoimpulslängen ab und beendet sich danach bis er wieder vom 1. Timer aktiviert wird.

Das klappt eigentlich auch schon fast, aber beim "Anschalten" des 2. Timers löst dieser sofort aus anstatt der vorgegebenen Zeit zu warten.
Danach hält er sich an die Zeiten.
Also habe ich den Timer0 wie folgt aktiviert:



TCNT0 = 0; // um sicherzustellen, dass er von Null aufwärtszählt
OCR0A = 50;
TIMSK0 |= (1 << OCIE0A); // Timer0 aktivieren


Aber egal welchen Wert ich für OCR0A eingebe, er startet immer sofort...
Der andere Timer wartet artig seine 20 ms ab bevor er zum ersten mal auslöst.

Hier nochmal ein bisschen mehr Code zur Übersicht:


...

int main(void)
{

// Timer0 - 8-Bit
TCCR0A |= (1 << WGM01); // Clear Timer on compare
TCCR0B |= (1 << CS02); // Prescaler 256, Interrupt max Verzögerung 4,1 ms
//TIMSK0 |= (1 << OCIE0A); // Compare-mode aktivieren


// Timer1 - 16-Bit
// Servo Impuls-Zeit
TCCR1B |= (1 << WGM12) | (1 << CS12); // Prescaler 256, Clear Timer on compare
OCR1A = 1249; // Interrupt Verzögerung 20 ms
TIMSK1 |= (1 << OCIE1A); // Compare-mode aktivieren

sei(); // Interrupts global ein

....
}


...

ISR (TIMER0_COMPA_vect)
{
....
OCR0A = wartezeit[zaehler]; // Hier gibts die neue Wartezeit - diese wird auch eingehalten!
}


ISR (TIMER1_COMPA_vect)
{
...

TCNT0 = 0;
OCR0A = 50; // <-------------------------------------dieser Wert wird ignoriert
TIMSK0 |= (1 << OCIE0A); // Timer0 aktivieren
}


Zum beenden des Timer0 setze ich TIMSK0 = 0.


Vielleicht sieht hier jemand meinen Fehler? Ich wäre für jede Hilfe dankbar :)

Zur Herangehensweise:
Ich habe schon einen anderen Code zur Ansteuerung der 12 Servos verwendet, dieser ist aber sehr unsauber und die Servos bewegen sich nur sehr ungenau.
Deshalb möchte ich UNBEDINGT diese Methode zum laufen bekommen um auch die Pausenzeiten konstant zu halten.

Gruß Erik

markusj
02.01.2013, 16:14
Deine Problembeschreibung verwirrt mich etwas.

Aber: Timer schaltet man ab in dem man ihren Takt deaktiviert, nur den Interrupt stummzuschalten reicht nicht. Wenn du den Interrupt wieder zulässt, löst das vorher irgendwann Mal gesetzte Interrupt-Flag (im TIFR-Register) den Interrupt gleich aus.

mfG
Markus

erik_wolfram
02.01.2013, 16:29
Hallo,

Super! Danke für den Tip. Ich habe diese Möglichkeit nicht gesehen...
Wenn ich nun den Prescaler deaktiviere und wieder setzte funktiert alles so wie es soll!
Man lernt immer dazu - danke für die schnelle Hilfe!

Hier nochmal der Code für andere:


OCR0A = 50;
TCCR0B |= (1 << CS02);

..zum starten und


TCCR0B = 0;

...zum Beenden

TIMSK bleibt dabei die ganze Zeit gesetzt.

Gruß Erik

oberallgeier
02.01.2013, 17:11
... Timer schaltet man ab in dem man ihren Takt deaktiviert, nur den Interrupt stummzuschalten reicht nicht ...Hmmmm, reicht wirklich nicht? Ich habe eine ähnliche Routine auf einem mega328/20MHz laufen für zehn Servos auf Timer1. ISRCompA macht mir die 2 ms-Schritte, startet den zuständigen Portpin und lädt OCR1B und setzt OCIE1B. ISRCompA gibt bei zehn Durchläufen 20 ms. Die ISRCompB schaltet den Interrupt ab und löscht den zuständigen Portpin - und es läuft und läuft und ....


// ================================================== ============================ =
// === Nicht unterbrechbare ISR für TIMER1_COMPB_vect ====================== =
ISR (TIMER1_COMPB_vect) // VECTOR 19 S 65
{ //
TIMSK1 &= ~(1<<OCIE1B); // Tmr/Cntr1 CompB Match interrupt disabled
// - - - - - - - - - - - - - - -
if (Svpt == 1) PORTB &= ~(1<<1); //
if (Svpt == 2) PORTB &= ~(1<<2); //
if (Svpt == 3) PORTD &= ~(1<<3); //
if (Svpt == 4) PORTD &= ~(1<<4); //
if (Svpt == 5) PORTD &= ~(1<<5); //
if (Svpt == 6) PORTD &= ~(1<<6); //
if (Svpt == 7) PORTD &= ~(1<<7); //
if (Svpt == 8) PORTB &= ~(1<<0); //
if (Svpt == 9) PORTC &= ~(1<<0); //
if (Svpt == 10) PORTC &= ~(1<<1); //
// - - - - - - - - - - - - - - -
} //
// ================================================== ============================ =

Vorteile: genaue Periodenlänge und für den Puls habe ich - natürlich je nach Servo - reichlich Schritte. Aktuell kann ich OCR1B von 120 bis 780 fahren - dann gehts wirklich Anschlag bis Anschlag, rund 180°. Brauch ich aber nicht, für mich (neee, für die Servos) sind 300 Ticks für ziemlich genaue 90 Grad mehr als genug.

markusj
02.01.2013, 17:21
So wird beim Freischalten des Interrupts direkt erst Mal noch einer ausgelöst werden, außer du löschst das Flag im TIFR. Die Output-Compare-Unit setzt das Flag solange der Timer läuft, unabhängig von der Interruptfreigabe.

mfG
Markus

oberallgeier
02.01.2013, 17:38
... außer du löschst das Flag im TIFR ...Genau. Wollt ja nur andeuten, dass es doch geht (und wollte nicht irgendwie besserwisserisch sein). Irgendeinen Tod muss man - ähhhhh - irgend ein Bit muss man doch immer setzen oder löschen.

Der (für mich ziemlich markante) Nachteil beim Deaktivieren des Taktes ist natürlich, dass dann der andere Timer auch abgeschaltet wird - und von den datenblattbekannten zwei unabhängigen Output Compare Units ist nur noch eine funktionierende übrig geblieben. Wer natürlich für den Puls nen eigenen Timer spendiert, der kann den Takt deaktivieren. Ich komme ja mit einem einzigen Timer für die Servobedienung aus.

erik_wolfram
08.01.2013, 22:28
Hallo,

das eine Problem habe ich gelöst, da tut sich schon das nächste größere auf ... dieser Versuch die 12 Servos zu steuern hat sich als problematisch erwiesen. Zur Übersicht nochmal eine Zusammenfassung des Ablaufs:

Nach jeder erfolgreichen Servoansteuerung (also 20 ms) werden die neuen Positionen berechnet (Dauer ca 4 ms). Dann werden die Einschaltzeiten nach der Dauer sortiert, die Differenzen berechnet und in einem Array abgespeichert (1 ms).
Jetzt beginnt der Zyklus, der 20 ms Timer aktiviert alle Ausgänge für die Servos und den 2. Timer mit der kürztesten Servozeit. Wenn dann der 2. Timer auslöst wird der 1. Ausgang der Sortierreihenfolge auf Aus gesetzt und es wird die nächste Differenzwartezeit für diesen Timer gesetzt. Und der nächste Servo wird abgeschaltet ... usw usw...

Dummerweise benötigt der Vergleich im Timer 2, welcher Servo als nächstes ausgeschaltet werden muss, ganze 15 µs - also verzögert sich der 2. Timer jedesmal um diese Zeit. Bei 12 Servos macht das dann ca 180 µs. Bedenkt man jetzt die Impulszeit für die Servos von 1-2 ms so sind das minimal 9% Abweichung des Drehwinkels der letzten Servos.

Als Mikrocontroller verwende ich den genannten Atmega168 mit einem 16-Bit Timer und zwei 8-Bit Timern und einer Taktung von 16 MHz.

Nun suche ich nach einem alternativen Lösungsweg, wie ich es schaffen kann die Servos sauber (ohne Abweichung) anzusteuern und trotzdem nebenbei noch Berechnungen auszuführen. Ich möchte keine komplette Lösung, aber vielleicht hätte jemand einen Denkanstoß, wie ich das lösen könnte?
Ich weis, dass 3 Timer eigentlich zu wenig für diese Aufgabe ist, aber trotzdem würde ich es gerne schaffen, den Roboter endlich mal fertigzustellen!

Gruß Erik

oberallgeier
08.01.2013, 23:10
... Ich weis, dass 3 Timer eigentlich zu wenig für diese Aufgabe ist ...Kannst Du mir bitte erklären, wieso Du weißt, dass drei Timer für diese Aufgabe zu wenig sind ? ? ?

Schau Dir doch bitte da oben an, wie ich meine Lösung für 10 Servos gemacht habe. Auf einem (E I N E M) Timer, bei dem ich beide Output Compare Units von Timer1 benutze. Eine als Takt für den sequentiellen Servopuls und einen für die tatsächliche Pulslänge in dem gerade aktuellen Pulsabschnitt. Ausrüstung: mega328/20 MHz, clk/64 => 312 500 Hz, OCR1A = 6250 => alle 20 ms ein Interrupt. Das geht bei mir mit 10 mal OCR1A = 800. Ergibt 25,6 ms - hab ich schon erfolgreich getestet. Nutzbar sind bei mir Pulse - gesteuert durch OCR1B zwischen 780 und 120, dann gehts bis in die Anschläge. Die Pulse werden in der ISR der Output Compare Unit A gestartet. Für einen 90° Schwenk brauche ich bei meinen Servos und der genannten Controllereinstellung ziemlich genau ne OCR1B-Differenz von 300. Oberer OCR1B-Wert bei einem 90°-Schenk wären also 120+300, mindestens 420. WENN ich zwölf Servos bräuchte, dürfte ich also 1/12tel als Takt nehmen . Andersrum - der 90°-Schwenk würde nicht mal an die Grenze der Funktion meiner Servos gehen.

Viele Servos kommen ohne Störung mit mehr als 20 ms Periodenzeit aus, dies ist ein allgemein verbreitetes Statement. Nachteil: ich habe es eben NICHT an allen, sogar nur an gaaanz wenigen Servos getestet. Die eben genannte Controllereinstellung macht eine Periodendauer von satten 25 ms. Wie gesagt, bei mir läufts.


... Ich weis, dass 3 Timer eigentlich zu wenig für diese Aufgabe ist ...Ich meine eben, dass bei Deinen zwei Timern schon einer zuviel beschäftigt wird.

Nachträge: wenn Dir die 300 Ticks für 90° eine zu grobe Auflösung bieten, kannst Du auch bei 20 MHz mit clk/8 fahren - dann wird für OCR1A 50000 fällig - gibt auch 20 ms. Für OCR1B gäbs dann wieder das Zwölftel *ggg*, und diese Auflösung kann wohl kein handelsübliche Modellbauservo bieten.

Ach so, ich hoffe Dir ist klar, dass dies alles auch für den m168 gilt. Für andere Quarze musst Du eben selber rechnen.

erik_wolfram
09.01.2013, 08:25
JA, eine ähnliche Methode hatte ich schon verwendet, allerdings mit einem kleinen Fehler:
Ich habe die Servosteuerzeiten direkt aneinander gereiht um die komplette Ansteuerung aller 12 Servos kurz zu halten....

Wenn die 1. paar Servos größere Steuerzeiten hatten, hat sich der Impuls der letzten Servos umsoweiter verzögert - dadurch gabs dann eine unschöne Ansteuerung der Servos.

Ein großes Problem nebenbei ist, dass ich sehr billige Servos verwende, und erstmal testen woltle, ob ich den Roboter zum laufen bekomme eh ich da richtig Geld reinstecke! (die Servos laufen generell nicht ganz flüssig)

Ich werde mal deinen Weg probieren! Wenn ich die Servowinkel auf +-45° Beschränke (weil ich nicht mehr benötige) komme ich auf eine Periodenzeit von 21 Sekunden, im Schlimmsten Fall 24 Sekunden.
Generell werde ich das mit dem Versatz berücksichtigen und alles Servos im 1,75 / 2 ms Takt ansteuern anstatt sie aneinander zu reihen.

Mit den vielen Timern meinte ich, je mehr Timer man hat, desto mehr kann man den MC entlasten und die Servo-Ansteuerung in die "Hardware" verlagern. ....das hätte sicher auch seine Vorzüge.

Aber generell benötigen die Berechnungen für die aktuellen Beinpositionen 5 ms - das heißt pro 20-ms Periode habe ich noch 15 ms den Controller was anderes tun zu lassen (z.B. den Weg berechnen).
Später wird der MC sowieso ausgewechselt!

Danke für die Hilfe, ich werde berichten wenn es etwas neues gibt :)

Gruß Erik

oberallgeier
09.01.2013, 09:58
Hi Erik.

... ähnliche Methode ... verwendet ... Servosteuerzeiten ... aneinander gereiht ...Das Aneinanderreihen geht offensichtlich auch, obwohl da die Pausen zwischen den Pulsen z.T. ziemlich variieren. So stehts jedenfalls in vielen Beiträgen hier und in anderen Foren. Ich wollte bei meiner Lösung einfach, soweit es möglich ist, zweifelsfrei reproduzierbar genau sein, ob es nun nötig ist oder nicht.


... großes Problem nebenbei ist, dass ich sehr billige Servos verwende ...Gibts damit Probleme? (kopfschüttel) Ich verwende die Carson CM-1 (ganz offensichtlich dasselbe wie früher Conrads ES-2) - hatte ich für 395 als Auslaufmodell noch schnell gekauft. Ausserdem laufen noch zwei RS-2 mit - schauderhafte Langsamkeit und SEHR weicher P-Regler :-/. Die Carsons laufen bei mir prächtig. Bauteilunterschiede werden durch einen Offset in der "finalen" Ansteuerung ausgeblendet, siehe Code


// - - - - - - - - - - - - - - -
Svpt ++; // Pointer eins rauf für nächsten, aktuellen Servo
if ( (Svpt < 1) || (Svpt > Svmx)) Svpt = 1; // Definierten Wert eingrenzen
// - - - - - - - - - - - - - - -
// Für den aktuellen Servopointer liegt ein korrekter Wert vor
// Jetzt wird der aktuelle Srv_tm-Wert in zulässige Schranken eingegrenzt
// und vor dem Setzen geoffsettet.
if ( Srv_tm[Svpt] < SerMin [Svpt] ) Srv_tm[Svpt] = SerMin [Svpt];
if ( Srv_tm[Svpt] > SerMax [Svpt] ) Srv_tm[Svpt] = SerMax [Svpt];
// - - - - - - - - - - - - - - -
if (Svpt == 1) PORTB |= (1<<1); //
if (Svpt == 2) PORTB |= (1<<2); //
if (Svpt == 3) PORTD |= (1<<3); //
if (Svpt == 4) PORTD |= (1<<4); //
if (Svpt == 5) PORTD |= (1<<5); //
if (Svpt == 6) PORTD |= (1<<6); //
if (Svpt == 7) PORTD |= (1<<7); //
if (Svpt == 8) PORTB |= (1<<0); //
if (Svpt == 9) PORTC |= (1<<0); //
if (Svpt == 10) PORTC |= (1<<1); //
// - - - - - - - - - - - - - - -
// OCR1B = Srv_tm[Svpt]; // Rampe ist durch Stellwert Srv_tm definiert
OCR1B = Srv_tm[Svpt] + Seroff [Svpt]; // Stellwert evtl. korrigieren
TIFR1 |= (1<<OCF1B); // Klappt nur wenn dies gesetzt wird
TIMSK1 |= (1<<OCIE1B); // Tmr/Cntr1 CompB Match interrupt enabled
// - - - - - - - - - - - - - - -


... komme ich auf eine Periodenzeit von 21 Sekunden, im Schlimmsten Fall 24 Sekunden ...Ähhh - Schreibfehler, gelle! Das sind drei Zehnerpotenzen weniger - ist schon klar.


... Versatz berücksichtigen ... Servos im 1,75 / 2 ms Takt ... anstatt sie aneinander zu reihen ...Nochmal - ich bin nicht der Meinung, dass es notwendig ist diesen Versatz zu vermeiden, dazu kenne ich zu viele Aussagen, dass dies keine Rolle spielt. Aber bei mir klappts bestens, die Routine steht, was soll ich also ändern. Nebenbei bemerkt: von restlichen Timern ist nur mein traditioneller 50µs-heartbeat belegt. ABER - mit dem 16bitter kann ich eben so präzise unterteilte Signalpulse ausgeben, dass von daher kein Störungseinfluss zu erwarten ist.

Wenn Du den kompletten Code für die Timer brauchst, kriegste auch. Aber ohne Garantie ;-)



Nachbemerkung: ein paar ES-2er und die Carsons waren mir vor Jahren ziemlich schnell über den Jordan gegangen, deswegen hatte ich die gehackt (siehe mein Getriebemotorthread und meine autonomen Dosen) - seither laufen die STUN DEN LANG

erik_wolfram
09.01.2013, 21:49
Hallo,

kleine Rückmeldung!

Natürlich meine ich Millisekunden! :)

Code ist fertig geschrieben - das mit dem Timer funktioniert ja super so - und der Code ist jetzt winzig.
Es war mir leider vorher nicht bewusst wie man mit dem PWM-Timer CompA/CompB arbeiten kann...
Die Zeiten sind sehr präzise! (Könnte nicht besser sein)

Leider habe ich heuet nicht die Möglichkeit den Roboter mit dem Code zu "füttern" - das kommt dann morgen!

Für den 16-Bit Timer habe ich jetzt einen Bereich von 1 ms (15999) bis 2 ms (31999) für die Stellzeit der Servomotoren. (Das ist mehr als genug)
Ich hoffe nur, dass mir nie das Interrupt beim Schreiben der 16-Bit-Werte dazwischen funkt. Wie könnte man denn den Timer dafür pausieren?


Zum Servo: Ich verwende die billigen Mini-Servos Y-3009 von C*** - einer ist mir schon durchgebrannt :(
Schließe ich einen größeren (billigen) RS-2 an läuft dieser seidenweich!

Gruß Erik

oberallgeier
09.01.2013, 22:46
... Ich hoffe nur, dass mir nie das Interrupt beim Schreiben der 16-Bit-Werte dazwischen funkt ...Hoffe nicht, die Hoffnung stirbt doch immer - zwar zuletzt, aber doch. Lies lieber das Datenblatt für ATmega48A/PA/88A/PA/168A/PA/328/P, 8271E–AVR–07/2012, S 114, "16.3 Accessing 16-bit Registers". Am Besten vorm Schlafen gehen, dann schläfst Du ruhig(er). Ist sozusagen der "atomar"-Trick der Atmel-Leute.


... und der Code ist jetzt winzig ...Na ja, trotz meiner bescheidenen Cäh-Kenntnisse siehts manchmal ganz gut aus - und ich liebe es beautiful - ähhhh - small!

Na ja, der RS-2 fährt seidenweich - aber drück mal dagegen. Erst leichter, dann fester - zumindest meiner hat eine lausige Nachgiebigkeit - sieht nach ziemlich wenig Steifigkeit im Regler aus :( . Ja, den 3009 hab ich auch, aber noch nicht getestet, noch nie betrieben. Hoffentlich halten die bei mir ne Weile.

erik_wolfram
10.01.2013, 21:53
So war heute fleißig und habe den Code übertragen und angepasst.
Die 2. Servos fordern mein 15 V 3 A Schaltnetzteil ganzschön... aber es funktioniert - sehr schöne (im Verhältnis zu vorher) Ansteuerung der Servos!!!

Aber für heute reichts dann auch. Morgen werde ich die Servos noch kallibrieren so, dass kleine Offsets ausgeglichen werden...
Dann wird eine Laufbewegung geschrieben.

Danke für den Hinweis mit den 16-Bit Registern, ich habe unter dem Suchbegriff gleich das richtige gefunden - Hauptargument "cli()" mit anschließendem Widerherstellen des SRegisters.

Wenn der Roboter (hoffentlich) am Wochenende läuft werde ich weiter berichten.

oberallgeier
10.01.2013, 22:59
... Die 2. Servos fordern mein 15 V 3 A Schaltnetzteil ganzschön ...Servos des Typs *3009 benötigen ca. 150 bis 300 mA. Bei 12 Servos hast Du dann rund 200 mA zur Verfügung - und verheizt ca. 66 % der Energie ab Schaltznetzteil-Ausgang. Aber das ist Dir hoffentlich klar. Übrigens gibts alte Notebook-Netzteile die auch 15V machen und meist 5A. Nur mal so als Tipp.


... Hinweis mit den 16-Bit Registern ... Hauptargument "cli()" mit ...Hmmmm. Hast Du Dir Deine *.lls durchgelesen? Und das oben genannte Datenblatt - an der genau beschriebenen Stelle?


... Accessing the low byte triggers the 16-bit read or write operation ...Und der kluge Compiler schickt eben erst das highbyte los - siehe *.lls. Da kann das cli/sei-Pärchen doch entfallen!? Ok, ich drück mich manchmal zu lasch aus . . . .

Nachtrag:

Servos des Typs *3009 benötigen ca. 150 bis 300 mA ...Wenn man keine Ahnung hat - einfach mal Klappe halten. Die Stromaufnahme war von mir geraten. Eben habe ich nachgesehen - NEIN , im Datenblatt schreibt das wohl kein Hersteller und auch der gute Sven Brandt (klick mal) (http://www.digital-bahn.de/bau_servo/servo.htm) hatte mit diesem Typ keine Messung gemacht. Ich hatte ihn an ein simples Netzteil gehängt mit ner einstellbaren Strombegrenzung. Der Servo läuft bei Einstellung unter 700..800 mA bei 6V ruckartig . . . erst über 800 mA ist ein glatter Lauf mit meinem Selbstbau-Servotester möglich.

erik_wolfram
13.01.2013, 22:08
Rückmeldung:

Heute bin ich fertig geworden, er läuft! Zwar erstmal nur geradeaus, aber mit einem guten Tempo (20 mm/s).
Die Servos laufen auch unerwartet gut (nachdem mir beim frühzeitigen Testen schon einer durchgebrannt ist).
Aus diesem Grund gabs bis jetzt auch nur 5 V bei einem durchschnittlichen Strom von knapp 1 A für alle 12 Servos.

Der Code zum Ansteuern der Servos ist jetzt sehr übersichtlich, leider muss ich den restlichen Code noch "aufarbeiten" - das Vorzeichen-wirrwarr ist sehr unübersichtlich.

Der Aufbau ist, wie auf dem Foto zu sehen sehr provisorisch. Die Beine sowie der Rahmen sind aus Acrylglas CNC-gefräst. Eigentlich hatte ich eine eigene Steuerung/Platine geätzt - leider mit Layout-Fehler. Die Masse der Servos ging zu dicht am Microcontroller vorbei und hatt diesen bei größeren Strömen resetet. Deshalb habe ich mir provisorisch einen Adapter für die RNMini-Control gefräst. Dem entsprechend sieht die Verkabelung aus...
Leider habe ich keinen passenden Akku - darum hängt der Roboter am Kabel...

Ein kleines (unscharfes) Video gibt es auch:
http://www.youtube.com/watch?v=S9qdJQgtg4I&list=UUkGoX5iV3AlvtCqID8qQyZw&index=1

(Alte Handykamera - das Smartphone-Zeitalter hat mich noch nicht erreicht)

Gruß Erik

robin
14.01.2013, 11:31
Sieht doch gut aus.

Wie machst du das mit dem Bein anheben? Berücksichtigst du da den Schwerpunkt oder machst du das über die Geschwindigkeit des Beins?

erik_wolfram
14.01.2013, 19:42
Also der Schwerpunkt ist schon gut austarriert so dass er garnicht/kaum kippt.
Die Beine werden nacheinander im Uhrzeigersinn einzeln vorgesetzten während sich der Torso auf einer um 180° versetzten Kreisbahn bewegt um das Gewicht zu verlagern.
Das klappt weitestgehend ganz gut, aber leider ist damit nicht berücksichtigt, dass sich die Hinterbeine doch deutlich anders bewegen und der Schwerpunkt doch verlagert ist.

Aber um genaueres zu sagen muss ich jetzt erstmal die MC-Platine überarbeiten, dass der ganezt Kabelsalat verschwindet.

Und ein passender Akku wäre ganz schön .... mit Kabel ist "unschön" :D