Problem gelöst: Optimierungen der Fahranweisungen

Heute hatten wir wieder die Gelegenheit, den Roboter am großen Übungsparcours der Schule zu testen. Nachdem wir einige Fehler aus der Erkennung der Sackgassen beseitigt haben und diese nun auch perfekt funktioniert, haben wir uns wie geplant wieder mal den Fahranweisungen zugewandt und nach sorgfältiger Analyse des Verhalten des Roboters (Was macht der Roboter falsch? Warum macht der Roboter das falsch? Was könnte besser funktionieren? Wie kann man das Problem beheben?) endlich die Lösung zu einem elementaren Problem gefunden, das wir so ähnlich auch schon letztes Jahr hatten und was uns große Probleme bereitet hat: Wie man in dem letzten Video sehen kann, fährt der Roboter öfters mal frontal gegen die Wände. Das liegt daran: Intern fragen wir nicht ab, ob ein Sensor eine Wand sieht, sondern wir fragen in der Karte ab, ob sich vor dem Roboter eine Wand befindet, da eine Wand eine Fusion der Sensordaten ist (eine Wand wird nur eingezeichnet, wenn mehrere Sensoren mit unterschiedlichen Prioritäten die Wand erkennen) und diese Information somit zuverlässiger als der Wert eines einzelnen Sensors ist. Dazu gibt es für jeden Sensor einen Schwellwert. Gleichzeitig gibt es unserer Fahranweisung für die Geradeausfahrt einer Fliese eine normale Schwellwertabfrage für einen Sensor, die verhindern soll, dass der Roboter gegen eine Wand fährt. Wenn der Schwellwert in der Fahrfunktion nun höher definiert ist, als in der Kartenzeichnung, wird der Roboter die Fahrfunktion abbrechen, wenn er eine Wand sieht, aber noch keine Wand an der Stelle eingezeichnet haben. Er denkt sich also, dass er noch eine Fliese geradeaus fahren kann. Die Fahrfunktion bricht aber nicht sofort ab, sondern bedingt durch eine Statemachine und dem Scheduler erst nach ca. 100ms. Zusammen mit der Geschwindigkeitsregelung und der Trägheit des Roboters fährt der Roboter also erst noch ca. 200ms geradeaus, bevor er erneut abbricht und nun auch der Schwellwert aus der Kartenzeichnung für eine Wand zutrifft und diese somit eingezeichnet wird.
Wir haben die Statemachine in der Fahranweisung nun verbessert, sodass sofort abgebrochen wird, ohne erst etwas zu fahren, obwohl sich eine Wand vor dem Roboter befindet. Außerdem haben wir die Schwellwerte in der Karte geändert, sodass definitiv auch eine Wand eingezeichnet wird, wenn die Fahranweisung eine Wand erkennt und abbricht. Hört sich komplizierter an, als es. Es ist eigentlich eine total simple Änderung bzw. Anpassung, wir haben nur sehr lange gebraucht, bis wir auf diese Idee gekommen sind. Die ganze Sache wurde erschwert durch einen defekten Entfernungssensor, der nur noch in einem Bereich von 3 – 10cm anstatt 3 – 30cm Werte lieferte. Nun fährt der Roboter aber nahezu perfekt.
Als nächstes werden wir uns nun um die Rampe und den Algorithmus zum Ändern der Position kümmern. Wahrscheinlich haben wir dann vor dem Wettbewerb auch noch mehr als genug Zeit, um eine zuverlässige Erkennung von Hindernissen einzubauen.

Langsam aber sicher…

… geht es voran! Wir haben nun eine sinnvolle Auswertung der Zeilenkamera entwickelt und können damit sehr zuverlässig frühzeitig, d.h. noch während der Roboter vor der Fliese steht und entscheidet, ob er jetzt in die Richtung fährt oder nicht, schwarze Fliesen erkennen und in die Karte einzeichnen.
Der Roboter sortiert dazu erst alle Helligkeitswerte des Untergrundes nach Größe. Dann nimmt er den sechstkleinsten Wert und entscheidet per Schwellwert, ob nun eine schwarze Fliese in Blickrichtung der Kamera liegt oder nicht. Durch die Sortierung ist es egal, wie weit oder nah der Roboter vor der schwarzen Fliese steht. Da die Kamera u.U. sogar über die schwarze Fliese hinausblicken kann und dann die letzten Pixel wieder weißen Untergrund sehen, wird eine Falscherkennung so vermieden, da diese weißen Pixel zum Schluss nach vorne geschoben werden. Wenn es einige Störungen in einigen Pixeln, vielleicht drei oder vier insgesamt, gibt, die also einen extrem kleinen Wert liefern, wird auch nicht sofort eine Sackgasse erkannt. Im Wesentlichen müssen also eine bestimmte Anzahl an Pixeln unter einem Schwellwert liegen, bis die Sackgasse erkannt wird.

Der Algorithmus zum Setzen des Roboters an eine neue Position nach einem Eingriff ist auch so gut wie fertig, darauf werden wir uns aber erstmal nicht konzentrieren, da er wahrscheinlich nicht zur Anwendung kommen wird.

Bei den Fahranweisungen sieht es leider nicht so ganz wie erhofft aus. Insgesamt fährt der Roboter nicht immer exakt 30cm. Besonders, nachdem er sich auf der Stelle gedreht hat, steht er manchmal nicht mehr 100%ig an der selben Stelle. Wir werden das als nächstes intensiv beobachten und dann wahrscheinlich an den entsprechenden Stellen automatische Korrekturen (auch zur Seite) einbauen. Dazu dann aber mehr.

Insgesamt sieht es aber gar nicht so schlecht aus und wir liegen gut im Zeitplan. Wir versuchen, in den Winterferien möglichst viel an den Fahranweisungen zu verbessern, sodass der Roboter nach den Winterferien (also Anfang der nächsten Jahres) extrem zuverlässig durch den Parcours fahren kann, ohne irgendwo hängen zu bleiben.

Zeilenkamera: Fortschritte

Nachdem wir nun mit unserem Navigationsalgorithmus und der Kartenerstellung mit dem neuen Roboter erhebliche Fortschritte erzielen konnten, haben wir uns noch einmal die Zeilenkamera vorgenommen.

Zuletzt hatten wir massive Timingprobleme, die uns letztendlich auch dazu veranlasst haben, einen Scheduler zu verwenden. Nach dem zweiten Programmieranlauf funktioniert die Kamera nun optimal. Im Wesentlichen gibt es nun den Task für die Kamera, in dem in einer Statemachine die Kamera initialisiert wird und das Bild belichtet wird. Wenn die Belichtungszeit, die am Ende jeder Aufnahme mithilfe eines Referenzpixels, der immer auf ein weißes Stück Papier gerichtet ist, ermittelt wurde, abgelaufen ist, wird eine Variable auf einen bestimmten Wert gesetzt. In dem Timer Interrupt, der unabhängig vom Scheduler und wesentlich schneller (mit 8kHz) aufgerufen wird, in dem die Anlogeingänge ausgelesen und aus 5 Messungen eines Analogeingangs der Median gebildet wird, wird kontrolliert, ob die Variable gesetzt wurde. Wenn sie gesetzt wurde, wird nun zum Analog Eingang geschaltet, an dem die Kamera angeschlossen ist und so lange die Werte gemessen, bis die Kamera einmal ausgelesen wurde (nach jedem gemessenen Wert wird eine Funktion aufgerufen, in der der Kamera mitgeteilt wird, dass der aktuelle Pixel ausgelesen wurde und somit zum nächsten Pixel geschaltet werden kann). Wir lesen nur jeden vierten Pixel der Kamera aus, da wir die volle Auflösung von 128 Pixeln nicht benötigen. Das Auslesen der Analogwerte dauert insgesamt
(1/8000)  *5           *(128/4)                        = 20ms
Freq.       Median   Auflösung der Kamera
Plus im schlimmsten Fall einer Belichtungszeit von 100ms = 120ms. Die Auswertung der Analogeingänge liegt dann immer noch im Rahmen, da die Sharp IR Entfernungssensoren ihren Ausgang sowieso nur alle 39ms aktualisieren.
Normalerweise liegt die Belichtungszeit um 60ms. Wenn es zu dunkel wird, wird immer noch automatisch die LED dazu geschaltet.

Als nächstes werden wir das Ergebnis der Kamera auswerten, weiterverarbeiten, das Ergebnis in unsere Kartenerstellung mit einbeziehen und die Kamera intensiv testen, sodass wir hoffentlich danach eine präzise Sackgassenfrüherkennung haben.

Wahrscheinlich werden wir allerdings direkt unter den Roboter einen zusätzlichen Sensor bauen, der die Sackgassen 100%ig zuverlässig erkennt, dann allerdings erst, wenn der Roboter in die Sackgasse gefahren ist, was insofern problematisch ist, dass die Sackgassenmarkierung beweglich ist, der Roboter sie also unter Umständen beim Befahren verschiebt und sich somit selbst den Weg zubaut. Aber so weit wird es wahrscheinlich nie kommen. 😉

Fortschritte: Bugs beseitigt

Leider haben wir in letzter Zeit recht wenig Zeit für den Roboter gehabt, da Schulprüfungen anstanden, aber langsam lockert sich die Situation und wir können uns wieder mehr dem Roboter zuwenden. 😉

Wir haben nun einige Bugs (darunter einen schwerwiegenden, der dafür sorgte, dass der Roboter u.U. endlos lange zwischen zwei Fliesen hin- und herfährt und einen, der für „Geisterwände“ gesorgt hat, also Wände an einigen Stellen in die Karte eingezeichnet, die nicht existierten; beide Fehler wurden verursacht durch die dynamische Kartenanpassung an das Labyrinth) behoben und etwas an den Fahrfunktionen gefeilt. Zum Einen kann der Roboter nun auch kurze Strecken direkt seitwärts fahren, das ist wichtig, wenn der Roboter doch mal aus der Spur kommen sollte und mit einer Seite an einer Wand hängen bleibt. Bis jetzt ist er dann mit einer Seite etwas rückwärts gefahren, was uns aber ja leider bei den deutschen Meisterschaften die Qualifikation gekostet hat – nun fährt er erst links zurück, rechts zurück, links vor, rechts vor, was eine leichte Bewegung nach links bzw. rechts ermöglicht, je nach Reihenfolge. Zum Anderen haben wir herausgefunden, dass die Geradeausfahrt immer noch ein paar Probleme macht, was aber eventuell mit den Entfernungssensoren zusammenhängt. Wir werden nun versuchen, die Encoderauswertung und die Geschwindigkeitsregelung zu optimieren, sodass es (hoffentlich) möglich wird, ausschließlich über die Encoder der Motoren, also quasi Strecke messen, zu fahren. Das ist wesentlich einfacher und auch etwas zuverlässiger als die Entfernungssensoren (die ausschließlich analog arbeiten und kein 100%ig sauberes Signal ausgeben).
Außerdem startet der Roboter die Navigation und Kartenerstellung nun nach 8s neu, nachdem der Roboter am Ziel angekommen ist (angenommen, der Roboter verfährt sich doch einmal und kommt aus dem Konzept: Der Roboter könnte „denken“, er sei mit dem Labyrinth fertig (da die Markierungen des Navigationsalgorithmus nicht mehr passen) und wartet nun an einer Fliese (soll er ja, das wäre eigentlich die Startfliese), er rettet sich dann selbst, indem er die Kartenerstellung neu startet. Dann können trotzdem immer noch alle Opfer gefunden werden, lediglich den Startbonus würden wir nicht bekommen.

Weiter haben wir uns erste Algorithmen überlegt und erste notwendige Teile dafür implementiert, zum Einen die vollautomatische Rampenerkennung (zuvor über Karte) und zum Anderen die Positionswahl des Roboters nach einem möglichen Lack of Progress per Backtracking des gefahrenen Pfades zum Löschen der bis zu dem neuen Einsetzpunkt gemachten Markierungen. Mehr dazu aber, wenn der Algorithmus weiterentwickelt ist und auch eine Chance hat, gut zu funktionieren (sieht aber gut aus).

Insgesamt sind wir sehr mit dem aktuellen Stand des Roboters zufrieden. Die Kartenerstellung selbst passt jetzt an die neuen Regeln und ist im Prinzip wettbewerbsfähig, damit könnten wir also jetzt schon am Wettbewerb teilnehmen. Lediglich die Fahrfunktionen müssen wie gesagt optimiert werden, das sollte aber kein allzu großes Problem sein.