LEGO BOULES

Anfängerpraktikum im Sommersemester 2017

Projekt

Dies ist die Projektwebsite zum Anfängerpraktikum Lego Boules vom Team A im Sommersemester 2017 an der Universität Heidelberg.

Team

Tom und Jonas

Wir sind Tom (Angewandte Informatik) und Jonas (Mathematik) und studieren seit 4 Semestern im Bachelor 100%.

Unser Robotikpratikum wurde von Monika Harant betreut und von Katja Mombaur supervised.

Aufgabenstellung

Zu Beginn des Praktikums haben wir uns die folgende Aufgabe definiert:

Unser Ziel ist es, einen Roboter aus Lego zu bauen und programmieren. Dieser soll am Ende des Praktikums in der Lage sein, eine Metallkugel über eine vorgegebene Distanz über eine Schaumstofffläche rollen zu lassen. Insbesondere liegt der Fokus dabei auf der Genauigkeit.

Der Roboter soll also eine vereinfachte Form des Spieles Boules simulieren können. Dazu gab es am Ende des Projektes einen Wettbewerb mit dem anderen Lego Boules Team.

Meilensteine

Ebenfalls zu Beginn des Projektes haben wir uns Meilensteine definiert, welche einen Leitfaden bei der Umsetzung des Praktikums bildeten:

  1. Bibliothek einarbeiten und ausprobieren 30. Juni 2017
  2. Physikalisches Modell entwickeln 14. Juli 2017
  3. Hardware planen & bauen 05. August 2017
  4. erster Prototyp 26. August 2017
  5. Messen, Lernen, Bauen 18. September 2017
  6. Dokumentation und Präsentation 23. September 2017

Unseren ersten Meilenstein konnten wir schnell abschließen. Wir haben lange gebraucht, um den Brick mit dem Laptop zu verbinden, aber dann lies sich, dank Pythons einfacher Syntax, schnell damit arbeiten. Wir haben anschließend ein kleines Hello World-Programm geschrieben. Zu diesem Zeitpunkt haben wir uns auch dazu entschieden, git als Versionskontrollprogramm zu benutzen.

Die restlichen Meilensteine konnten wir dann relativ gut erreichen. Dies lag auch an intensiven Arbeitsphasen vor den Meilensteinterminen.

Hardware

Wie der Name des Praktikums schon verrät, besteht unser Roboter hauptsächlich aus Legosteinen. Diese sind auf der einen Seite besonders gut geeignet, weil sie einfach kombinierbar sind und problemlos wiederverwendet werden können. Jedoch hat Lego auch Nachteile, wie zum Beispiel:

  • fest vorgegebene Kombinierbarkeit, dadurch dass Steine nicht beliebig aufeinander passen und die Form unveränderlich ist
  • Instabilität, weil die Steine nur gesteckt und nicht sehr belastbar sind
  • Begrenzte Anzahl an bestimmten Bausteinen

Als Kugel wurden ca. 90 Gramm schwere und 2,8 cm breite Metallkugelen verwendet. Das Spielfeld bildete eine Schaumstoffmatte, welche ein paar Zentimeter dick war. Im Verlaufe des Praktikums sind zu unseren Materialien noch Pappe, Holz und Heißkleber hinzugekommen.

Physikalisches Modell

Unsere erste Idee war, eine Rampe mit verstellbarem Winkel zu bauen, von der wir die Kugel runterrollen lassen. Dabei sollte ein glatter Übergang von der Rampe zum Schaumstoff gegeben sein, sodass die Kugel beim Aufkommen nicht umherspringt. Konzeptuell sollte es so aussehen:

modell

Bevor wir angefangen haben, diese Idee in einen ersten Prototypen umzusetzen, wollten wir uns erst einmal mit den Grundlagen der Physik beschäftigen und analysieren, wie sich denn die Kugel auf einer Rampe verhalten würde. Hier haben wir versucht, das Modell zu vereinfachen, indem die Rampe komplett gerade ist. Es zeigte sich jedoch später, dass diese Verienfachung starke Auswirkungen auf die tatsächliche Weite der Kugel hat.

modell

Die Idee war relativ intuitiv und simpel: Je nachdem wie man den Winkel \( \alpha \) der Rampe zum Boden einstellt, verändert sich die Startposition der Kugel und somit die Höhe \( h \) bei fester Strecke \( s \). Dann lässt sich eine Funktion herleiten, welche für eine gegebene Distanz \( z \) den entsprechenden Winkel \( \alpha \) liefert. So kamen wir auf folgende Formel \[ z = \frac{5}{7}s \cdot \frac{\sin \alpha - c_s \cdot \cos \alpha}{c_z} , \] wobei \(c_s \) und \(c_z\) noch zu bestimmende Reibungskoeffizienten sind. Diese hat leider den Nachteil, dass sie schwer nach \( \alpha \) umstellbar ist. Womit wir unseren zweiten Meilenstein beendet haben, mit einem wenig hilfreichen Ergebnis.

Leider hat sich herausgestellt, dass dieses theoretische Modell in der Praxis nicht wirklich geeignet war, um Weiten für gegebenes \( \alpha \) vorherzusagen. Deshalb haben wir uns in der Zukunft dazu entschieden, eine empirisch begründete Funktion zu benutzen.

Rampe

Grundlegende Hardware

Zunächst haben wir versucht, eine Metallschiene als Rampe zu verwenden, jedoch gestaltete sich die Montage auf den Legosteinen als kompliziert. Deshalb haben wir die Rampe kurzerhand komplett aus Lego gebaut. Dies klappt relativ gut, da die Kugel auf den Kanten der Unterseiten entlang rollen kann. Einzig beim Übergang von einem zum nächsten Legostein gibt es leichte Unebenheiten, die sich aber nicht auf die Kugelbewegung auswirken.

Um die Rampe nun zu neigen, haben wir sie an einem Punkt unten auf einer Lego Platte befestigt, sodass sie sich um diesem Punkt drehen konnte. Hinten war die Rampe mit einer Stütze mit einem Motor auf dem Boden verbunden. Dadurch, dass der Motor sich vor- oder zurückbewegt hat, änderte sich der Winkel der Rampe.

Prototyp

Erste händische Versuche haben ergeben, dass die Kugel nur eine sehr geringe Reichweite hat. Außerdem lagen minimale und maximale Distanz sehr nah beieinander, wie man im obigen Bild sieht. Jedoch stellten wir fest, dass die Reichweite gar nicht so sehr von der Höhe, sondern von der Startposition auf der Rampe abhängt, was uns auf die Idee für die finale Version brachte. Insgesamt wirkten auch die Ergebnisse dieses Meilensteins "Hardware planen & bauen" eher enttäuschend. Deshalb sind wir dazu übergegangen, andere Ansätze auszuprobieren.

Andere Ansätze

Im nächsten Meilenstein "erster Protyp" haben wir kleine Prototypen erstellt und getestet, welche im folgenden jedoch zur besseren Erkennbarkeit nur schematisch dargestellt sind.

  • Ansätze

    Ansatz 1

    Idee: Die sechs Reifen werden von Motoren über Zahnräder gedreht, so gedreht, dass in der Mitte eine „Saugbewegung“ nach vorne entsteht. Die Kugel liegt dort drin und wird somit nach vorne katapultiert.

    Probleme: Zum einen ist die Kugel viel zu glatt, als dass es genügend Reibung geben könnte, um die Kugel zu bewegen. Zum anderen ist die Kugel für die entsprechenden Lego-Reifen zu klein gewesen, sodass sie in dem Loch zwischen vier Reifen hängen geblieben ist. Vermutlich wären die Motoren auch nicht schnell und kräftig genug, um die Kugel auf Geschwindigkeit zu bringen, wobei man dies durch geeignete Übersetzung vielleicht lösen könnte.

  • Ansätze

    Ansatz 2

    Idee: Um die notwendige Beschleunigung für die Kugel zu erhalten, wird in diesem Ansatz die Kugel sehr weit von Motorrotationsachse entfernt positioniert. Wenn sich der Motor nun etwas dreht, legt die Kugel eine große Strecke zurück. Sie muss nur noch zum richtigen Zeitpunkt aus der Halterung geschupst werden.

    Probleme: Das Gewicht der Kugel ist viel zu hoch, als dass ein solch langer Arm die Kugel und noch einen weiteren Motor aus Auslöser tragen könnte. Dafür müsste man mit einem Gegengewicht arbeiten, was die Geschwindigkeit wieder bremst. Außerdem vermuten wir, dass die Wurfdistanz nicht sehr hoch ist.

  • Ansätze

    Ansatz 3

    Idee: Die Rotationsenergie eines Motors wird in eine Längsbewegung umgewandelt, welche wiederum in elastische Energie umgewandelt wird, indem eine Platte mit einem Gummiband nach hinten gezogen wird. Beim Loslassen der Platte wird die Kugel angestoßen und nach vorne katapultiert. Je nachdem wie stark die Bänder gespannt werden desto weiter fliegt die Kugel.

    Probleme: Das Gewicht der Kugel ist sehr hoch und somit wären sehr viele Bänder nötig. Und auch dann würde man mit einer Impulsübertragung vermutlich nicht sehr weit gekommen.

  • Ansätze

    Ansatz 4

    Idee: Die Kugel wird zwischen zwei Reifen eingespannt, welche über Achsen an rotierenden Motoren befestigt sind. Somit wird die Kugel auf Geschwindigkeit gebracht. Zu einem geeigneten Zeitpunkt wird die Kugel dann losgelassen aus der Klemme und rollt nach vorne wegen der Haftreibung

    Probleme: Zum einen sind die Motoren sind nicht schnell genug, wobei dies durch Übersetzung lösbar wäre. Zum anderen ist die Kugel zu glatt und hat somit keine Haftung auf dem Untergrund und bewegt sich nicht vorwärts, sondern dreht durch.

Finale Version

Lift

Lift

Aus den geschilderten Problemen, haben wir uns dazu entschieden, noch einmal den Rampen-Ansatz auf Realisierbarkeit zu überprüfen.

Die erste Veränderung im Vergleich zu dem früheren Prototyp war die Fixierung der Rampe, d.h. der Winkel zwischen Rampe und Boden war fest. Stattdessen wollten wir nun die Startposition der Kugel auf der Rampe verschieben und dadurch verschiedene Weiten erzielen. Dadurch wurde die Gesamtkonstruktion sehr viel stabiler.

Trigger

Trigger

Dafür haben wir einen Käfig gebaut, der auf der Rampe beweglich ist. Diesen haben wir mit einer Kette an einem Zahnrad befestigt, durch Drehen dieses Zahnrades wurde dann der Käfig hoch- bzw runterbewegt. Um das Zahnrad automatisch zu bewegen, haben wir einen Motor angebracht, den Lift.

Der Käfig hat einen kleinen Freiraum, in dem die Kugel untergebracht wird. Dieser Käfig hat vorne ein Tor, dieses Tor kann durch einen weiteren Motor, den Trigger, geöffnet und geschlossen werden.

Durch den abrupten Übergang von der Rampe zu der Matte gab es einige Probleme. Einerseits wurde die Weite stark eingeschränkt, da die Kugel viel umhergesprungen ist; andererseits war die Weite aus dem selben Grund auch wenig konsistent.

Diesem Problem konnten wir dadurch entgegen wirken, dass wir einen Übergang aus Pappe mit Heiskleber an der Rampe befestigt haben. Dies führte dazu, dass wir sehr viel konsistenere und längere Weiten erzielen konnten. Durch diese Modifikation, wurde dann der Rampen-Ansatz gerettet und wir konnten die restliche Zeit dieses Meilenstein dafür verwenden die Rampe in einen wirklichen Roboter zu verwandeln.

Software

Damit unser Roboter sich auch tatsächlich bewegt, fehlt nun noch unsere Software. Da diese auf dem Brick mit ev3dev laufen soll, hatten wir die Auswahl zwischen verschiedenen Programmiersprachen. Wir haben uns für Python entschieden, da es gut dokumentiert war und Entwicklung in Python leicht ist.

Insgesamt besteht unsere Software aus zwei Programmen:

  1. Die Controller Klasse aus controller.py stellt das Grundgerüst unserer Software und wird automatisch beim Ausführen von controller.py instanziert und aufgerufen. Dafür besitzt der Controller eine Interaction Instanz, um der Userin Text anzuzeigen und um Eingaben zu bitten. Diese Eingabe wird dann mithilfe von model_dicts.py dazu benutzt, um die Kugel entsprechend weit zu rollen.
  2. In make_model_dicts.py wird model_dicts.py automatisch erstellt, um gegebene Weiten umzurechnen.

Controller

Für das Rollen einer Kugel wird zuerst die Weite abgefragt. Diese wird dann umgerechnet zu Umdrehungen des Lift-Motors. Der Lift bewegt sich so viele Grad. Anschließend wird der Trigger geöffnet und die Kugel somit losgelassen. Dann wird der Trigger geschlossen und der Lift begibt sich in die Ausgangsposition zurück. Abschließend wird die Userin gefragt, ob sie noch einmal spielen möchte.

Interaction

Wir haben uns gedacht, dass nicht jeder immer ihren Laptop zum Boules spielen dabei hat, deshalb ist es praktisch, den Roboter über den Brick bedienen zu können. Dafür haben wir eine Interaction-Klasse geschrieben.

Diese verfügt über drei Methoden:

  1. print: Gibt alle angebene Parameter als einzelne Zeilen so groß wie möglich auf dem Bildschirm aus.
  2. get_number: Lässt die Nutzerin eine Zahl zwischen start und end eingeben. Indem eine neue Klasse angelegt wird, die als Zustand die aktuell angegebene Zahl anzeigt und Methoden bereitstellt, um auf Tastendrücke zu reagieren. Dabei wird immer die aktuelle Stelle (die entsprechende Ziffer ist schwarz unterlegt) inkrementiert bzw. dekrementiert.
  3. get_bool: zeigt eine Zeile an, gefolgt von "ja" oder "nein" und lässt die Nutzerin dazwischen entscheiden.

ModelMaker

Da der Lift-Motor sich nur über Gradzahlen ansteuern lässt, mussten wir einen Weg finden diese in eine geschätze Entfernung umzurechnen.

Dafür haben wir zuerst 20 Datenpunkte gleichmäßig zwischen minimaler und maximaler Position gemessen (Schritt 1, siehe Messreihen). Da wir an diesen Punkten relativ sicher sind, wie weit die Kugel rollt, haben wir uns dafür entschieden Spline-Interpolation zu benutzen, um Schätzungen für die restliche Position des Triggers zu generieren (Schritt 3 (im Vergleich zu anderen Schritt 2)). Somit haben wir also eine Funktion, die für eine gegebene Höhe eine ungefähre Weite schätzt (Schritt 4). Diese müssen wir also noch invertieren. Dies geschieht indem wir die Funktion an 190 Punkten auswerten (Schritt 5) und dann für jeden Centimer die Höhe heraussuchen mit dem kleinsten Abstand zu dieser Weite (Schritt 6 und 7). So erhalten wir eine Funktion die eine gegebene Weite in eine Höhe umrechnet (Schritt 8).

Diese Funktion speichern wir in einem Dictionary und dieses Dictionary wird in der model_dicts.py Datei gespeichert

Quellcode

Der vollständige Quellcode befindet sich auf Github. Hier die wichtigsten 4 Dateien:

Fazit

Messreihen

In dem Meilenstein "Messen, Lernen, Bauen" haben wir uns dann viel damit beschäftigt, wie weit die Kugel bei verschiedenen Startpositionen rollt. Dafür haben wir mit unserem fertigen Roboter an verschiedenen Tagen häufig gemessen. Dabei haben sich Daten ergeben, die klare Unterschiede an verschiedenen Tagen zeigen. Die Unterschiede sind vermutlich auf die unten gelisteten Probleme zurükzuführen.

Fehlermessungen

Vorgegeben Spline Polynom
linear kubisch linear kubisch
41013.750
750-1.5-4-0.5
79-0.5-0.25-5.5-0.5
8211-50
84000-0.5
104-4-4-4.5-4
107-1.5-2-2.5-1.5
108-2-1.5-1.53.5
112-3-321
126010.53.5

Für unsere Datenpunkte hatten wir verschiedene Möglichkeiten, eine Funktion zu fitten, welche zu einer Höhe eine Weite berechnet. Dafür haben wir uns Spline-Interpolation und Polynom-Approximation angeschaut. Diese konnten dann einfach mit dem ModelMaker in verschiedene Modelle überführt werden, mit denen eine Höhe vorhergesagt wird, mithilfe derer man auf eine gegebene Weite kommen soll.

Wir wollen nun folgende Funktions-Typen vergleichen:

  1. Lineare Splines
  2. Kubische Splines
  3. Lineares Polynom
  4. Kubisches Polynom

Dafür sieht man in der nebenstehenden Tabelle verschiedene, zufällige Zielweiten und daneben den Abstand zur tatsächlich gerollten Weite mit der vorgeschlagenen Höhe, des jeweils vorgegebenen Modells.

Wir sind insgesamt mit den Ergebnissen zufrieden. Alle Modelle hatten relativ kleine Abweichungen für die getesteten Werte. Wobei allerdings die Splines klar besser sind als die Polynome. Zwischen linearen und kubischen Splines ist der Unterschied sehr gering. Da kubische Splines als Modellierungsfunktionen natürlicher sind, haben wir uns für die kubischen Splines entschieden. Allerdings ist das Laden der anderen Modelle mittels Komandozeilenargumenten problemlos möglich.

Probleme & Lösungen

Im Laufe des Praktikums sind wir auf verschiedene Probleme gestoßen.

  • Das wohl größte Problem war, dass der Übergang zwischen Schaumstoffmatte und Rampe zu unglatt war. Sobald die Kugel von der Rampe auf die Schaumstoffmatte kam, ist sie erst einmal tief versunken und dann unregelmäßig umhergesprungen, wobei viel Energie nicht in die Reichweite umgesetzt wurde. Damit konnten wir nicht präzise Boules spielen.

    Unsere Lösung für dieses Problem war eine Pappe, die wir mit Heißkleber unten an der Rampe befestigt haben. Da die Pappe sich im Gegensatz zu den Legosteinen biegen lässt, nimmt sie eine ziemlich optimale Form an, sodass der Übergang einigermaßen glatt ist. Um die Auswirkungen der Pappe zu sehen, haben wir ein vorher-nachher Vergleich gemacht:

    Jedoch ließ sich das "Springen" nicht ganz vermeiden. Das liegt daran, dass der Übergang von der Legorampe zur Pappe nicht ganz optimal ist. Wir haben zwar versucht, die Pappe so einzukerben und mit Holz zu beschweren, sodass die Kugel möglichst ideal auf die Pappe kommt, aber das scheint immer noch nicht perfekt zu sein.

    Das sieht man auch an den Werten der Messreihen. Wir vermuten, dass die Abweichungen mit der sich verändernden Pappe zusammenhängen. Denn je häufiger die Kugel auf die Pappe kommt, desto mehr verformt sich diese. Solch kleine Änderungen scheinen sich messbar auf die Distanz auszuwirken. Eine Lösungsidee hierfür wäre ein unverformbares, aber trotzdem vom Übergang her glattes Bauteil, welches man vielleicht mit einem 3D Drucker erstellen könnte.

  • Ein seltenes Problem war das zu frühe Auslösen des Triggers, wenn der Käfig beim hochziehen nach hinten gekippt ist. Die Kugel ist also schon die Rampe heruntergerollt, noch bevor der Lift den Käfig bis auf die gewünschte Position gezogen hat. Um dies zu verhindern, haben wir die Zuggeschwindigkeit vom Lift gesenkt, damit die Bewegung nicht so ruckartig ist und der Käfig nicht nach hinten kippt. Außerdem haben wir Gegengewichte an den Käfig befestigt, die ihn auf der Rampe behalten sollen, jedoch gleichzeitig noch beim Öffnen des Tores ein Losrollen ermöglichen sollen. Als letztes haben wir zwei kleine Legostäbe an den Käfig angebaut, die verhindern, dass sich der Käfig zu weit nach hinten neigen kann.
  • Wegend den Übergängen der Legosteine der Rampe blieb der Trigger-Käfig manchmal beim Herablassen an den Kanten hängen. Dies haben wir verhindert, indem wir die Geschwindigkeit gesteigert haben, sodass der Käfig einfach über die Unebenheiten schneller rüberfährt.
  • Ebenfalls problematisch war, dass der Lift den Trigger weiter herunter ließ als es hochgezogen wurde. Somit musste man jedes Mal den Lift neu kalibrieren. Unsere Vermutung war, dass dies mit dem Gewicht der Kugel zusammenhängt, welches beim Herunterlassen nicht mehr vorhanden ist. Außerdem war erkennbar, dass der Fehler einigermaßen proportional zur Distanz war. Deshalb haben wir softwareseitig einen prozentualen Offset eingebaut, der dieses Problem für ausreichend große Winkel behoben hat und für kleine Winkel den Fehler minimiert hat.
  • Beim Brick hatten wir das Problem, dass ein Button-Druck zweimal registriert wurde, bei zu schneller Abfrage, wenn wir zuerst einen bool abgefragt haben und direkt danach ein int. Nach langer Recherche, woran das liegen könnte, haben wir einfach ein sleep eingebaut, was den Fehler behoben hat.

Ausblick

  • Wie in den Problemen angesprochen, wäre es möglich, einen festeren Übergang zwischen Rampe und Schaumstoffmatte zu bauen, beispielsweise mit einem 3D-Drucker.
  • Da der Offset für das Herunterlassen des Liftes immer noch nicht perfekt für kleine Winkel ist, wäre eine gute Verbesserung, dort einen Winkelmesser anzubringen und mit diesem für genaues Zurücksetzen zu sorgen.
  • Es wäre interessant, zu vergleichen, wie sich unterschiedliche Rampenformen auf die Weite der Kugel und die Genauigkeit auswirken. Da andere Rampenformen beispielsweise die Kugel besser beschleunigen können.
  • Bei einem echten Boules spielt, steht man noch ein bisschen weiter weg von der Rampe als der Roboter zurzeit rollen kann. Deshalb wäre eine Verlängerung der Rampe, ein einfaches Unterfangen mit dem diesen Roboter fast praxistauglich machen kann.
  • Außerdem hat man in einem echten Boules-Spiel mehrere Kugeln, unser Roboter kann aber nur eine gleichzeitig aufnehmen. Ein schönes Projekt wäre es, unten ein Kugellager anzubauen, dass automatisch nach einem Schuss, den jetzigen Roboter nachlädt.
  • Für ein richtiges Spiel, ist es nötig, den Winkel in dem man Kugeln schießt anzupassen, um fremde Kugeln wegzustoßen. Dafür könnte man unter den Roboter Räder bauen, die ihn drehen. Zusätzlich wäre es schön, wenn sich der Roboter entlang der Startlinie von selbst bewegen könnte.
  • Zurzeit muss dem Roboter per Hand eingegeben werden, wie weit die Kugel gerollt werden soll, es wäre schön einen Sensor einbauen, mit dem der Roboter den Abstand zum Schweinchen selbst bestimmt und die Kugeln automatisch rollt.
  • Wenn der Roboter schon automatisch schießt, ist es auch sinnvoll eine Künstliche Intelligenz zu schreiben, die immer strategisch sinnvoll ihre Kugeln platziert.
  • Ein weiteres Problem, was bereits oben angesprochen wurde, ist das die Messungen sich an einzelnen Tagen stark unterschieden haben. Um ein bisschen mehr Licht auf dieses Problem zu werfen, wäre es sinnvoll mehr zu messen, um unterschiedliche Einflussfaktoren, wie die genaue Position des Roboters, welche Seite der Schaumstoffmatte gerade oben liegt und wie eben der Boden ist, zu untersuchen.

Inbetriebnahme

Zur Inbetriebnahme müssen folgende Dinge gemacht werden

Indikator

  1. Der Roboter muss an der gewünschten Position aufgestellt werden
  2. Der Käfig muss ganz unten auf die Rampe gestellt werden
  3. Die Kette des Käfigs muss im Lift eingespannt werden
  4. Der Indikator sollte auf der gleichen Position stehen wie auf dem Bild rechts zu sehen ist.
  5. Den Brick anmachen
  6. Auf dem Brick boules.sh starten (ein ausführbares Shell-Skript, dass python3 controller.py enthält). Alternativ zum Laden verschiedener Modelle sind folgende Aufrufe möglich:
    • Lineare Spline:python3 controller.py spline_lin
    • Kubischer Spline:python3 controller.py spline_cubic
    • Lineares Polynom (Ausgleichsgerade):python3 controller.py pol_lin
    • Kubisches Polynompython3 controller.py pol_cubic
  7. Kugel einlegen
  8. Weite in cm eingeben
  9. Mit Enter bestätigen
  10. Falls nochmal, Bestätigen und zurück zu Schritt 7

Jonas Müller und Tom Rix © 2017