CarreraVision

Aus toolbox_interaktion
Wechseln zu: Navigation, Suche

Projektidee

Für die kompetitive Spielweise der Autorennbahn müssen immer genau zwei Personen vor Ort sein. Die Nutzung ohne einen Kontrahenten erweist sich als monoton und langweilig. An dieser Stelle kommt das System dieses Projektes zum Einsatz, welches einen fordernden Gegenspieler für die Anwendung mit nur einer Person darstellen soll. Dabei kommt Software und Hardware zum Einsatz, die den Streckverlauf dynamisch erkennen und das Tempo des Fahrzeuges immer optimal anpassen.

Umsetzung

Ein Embedded Microcontroller-System bietet sich für diese Aufgabe an, da es eine einfache Ansteuerung einer Kamera und der digitalen Ausgänge ermöglicht. Um die Fahrzeuge anzusteuern, muss eigene Hardware entwickelt und designt werden. Nach dem Aufbau der Strecke erkennt die Kamera anhand eindeutiger Merkmale den Streckenverlauf. Nach Start eines Rennens berechnet das System eine optimale Geschwindigkeit für die einzelnen Streckenteile. Ein Feedback bezüglich der Position des Fahrzeugs erhält die Software über das Kamerabild.

Dokumentation

Der vollständige Programmcode ist auf GitHub zu finden. Als Hardware wurde ein Raspberry Pi Ver. 3 mit einer Raspi-Kamera Ver. 2 verwendet wurden. Der Code wurde möglichst modular aufgebaut und lässt sich unter Windows und Linux kompilieren. Dies ist sehr wichtig, da das Entwickeln deutlich bequemer auf einem großen Computer (Windows) ist. Später wurde der Programmcode auf den Raspberry Pi für Linux kompiliert und dort abgespielt. Durch zuvor aufgenommene Bilder und Videos kann die Software auch auf Rechnern ohne Kamera ausgeführt werden, wodurch die Fehlersuche und -behebung deutlich erleichtert wird.

Streckenerkennung / Fahrzeugerkennung

Für die Strecken- und Fahrzeugerkennung wurde die freie grafische Bibliothek OpenCV 3.4 verwendet. Ziel war ein sicheres Erkennen der Strecke auch unter nicht optimalen Verhältnissen. Grundsätzlich darf man nicht von einer perfekten Belichtung ausgehen, dadurch können auch Reflexionen an glatten Flächen entstehen. Dabei kamen zwei grundsätzliche Möglichkeiten in Frage. Zum einen kann man die Autos automatisch oder manuell die Strecke abfahren lassen und verfolgt dabei die Position der Fahrzeuge auf der Strecke. Zum anderen kann man anfangs ein Bild von der Strecke machen und aus diesem die Streckenführung berechnen. Da dies nur ein mal erfolgt, kann der Algorithmus auch etwas länger brauchen (1-10 Sekunden). Dagegen muss die spätere Fahrzeugerkennung in Echtzeit ablaufen (min. 10fps pro Sekunde). Dies ist besonders herausfordernd, da der RaspberryPi nur begrenzte Rechenleistung besitzt.
Wir haben uns für die zweite Variante entschieden ein Bild aufzunehmen und daraus die Strecke zu berechnen. Dies ist zwar die komplexere Lösung, aber bei korrekter Implementierung auch die sauberere Lösung. Zudem wollen wir auf jegliche zusätzliche Marker wie QR-Codes oder farbliche Veränderungen der Fahrzeuge und Strecke verzichten. In Kombination mit der begrenzten Rechenleistung des Raspberry Pi's ergibt dies eine komplexe Aufgabenstellung.

Grundlegendes Vorgehen bei der Bilderverarbeitung

Bildaufnahme und Grundidee

Als Bildquelle wird für die Streckenerkennung die höchstmögliche Auflösung der RaspberryPi Kamera Ver. 2 verwendet (3280x2464 Pixel). Hierbei ist man zwar auf 15fps begrenzt, was aber dennoch eine ausreichende Wiederholrate darstellt.
Die Schienen besitzen drei eindeutigen Merkmale: Die rot-weißen Seitenmarkeierungen, die weiße Mittellinie und die zwei metallischen Schienen. Am sichersten kann man die rote Streckenbegrenzung erkennen. Deswegen wurde sich auf diese konzentriert. Nach dem sicheren Erkennen der Punkte wird nur anhand dieser Daten beide Streckenverläufe berechnet. Einzig zum erkennen einer Weiche wird nochmals auf die Bilddaten zurückgegriffen.

Dieses Ausgangsbild wird im folgenden in einzelnen Schritten ausgewertet

Binarisierung / Morphologische Operation

Die Streckenbegrenzung ist durch die roten Punkte sehr gut sichtbar. Für eine Farbdetektierung bietet sich der HSV-Farbbereich an (cv.cvtColor()). Anfangs wurde die einfach cv::inRange() Funktion verwendet um die Daten zu filtern. Unter guten Bedingungen hat dies auch ein sicheres Ergebnis ergeben. Aber es stellte sich heraus, dass bei einer ungleichmäßigen Belichtung es schnell zu Problemen kommt. Durch genauere Analyse konnten die Rangeparameter immer weiter optimiert werden, wodurch ein sehr gutes Ergebnis erreicht wurde.
Um fehlerhafte Pixel zu entfernen, die durch Bildrauschen entstehen, wird eine Opening-Funktion verwendet (cv::morphologyEx()).

Ideales Ergebnis nach der Vorverarbeitung

Punkte erkennen

Nun werden zusammenhängende Flächen aus dem Binärbild berechnet (cv::SimpleBlobDetector). Als Punkte werden die Schwerpunkte der Flächen verwendet. Es wird zudem die Flächengröße geprüft. Sind Flächen doppelt so groß wie normal wird der Punkt doppelt in die Liste aufgenommen. Dies ist nötig, damit auch Strecken erkannt werden, bei denen sich Schienenteile seitlich berühren.

Alle erkannten Punkte

Seitenlinen berechnen

Die Seitenlinienberechnung wird mehrmals durchgeführt. Jeder Durchlauf kann leicht unterschiedliche Ergebnisse ergeben, dies liegt daran, dass immer ein zufälliger Punkt als Startpunkt verwendet wird. Am Ende der Seitenlinienberechnung wird geprüft, ob die Seitenlinien einen sinnvollen Verlauf besitzen. Wenn nicht, wird ein neuer Versuch begonnen. Dies kann theoretisch beliebig oft wiederholt werden, in der Praxis wurde es auf fünf Durchläufe begrenzt. Als erstes werden Punkte gesucht, die in einer geraden Linie hintereinander liegen. Solange kein Knick in der Linie ist, dürfen Punkte dann auch etwas weiter auseinander liegen, um kleine Fehler auszugleichen. Zudem können so sehr gut Kreuzungen erkannt werden.

Alle Verbindungen die gerade sind

Danach werden die Kurven erkannt. Wie weit ein Punkt von dem letzten entfernt sein darf, hängt dabei von dem Knickwinkel der Linie ab. Auch die Einstufung welcher Punkt als nächstes am besten liegt, hängt von den Faktoren Abstand in Kombination zu Linien-Knick-Winkel ab. Wird ein Endpunkt einer Geraden gefangen, wird am anderen Ende der Geraden weiter gesucht.

Mit allen weiteren Verbindungen wie Kurven nach der Erkennen

Am Ende muss geprüft werden, welche der Linien für die Strecke relevant sind. Dies sind immer die zwei längsten Geraden, dessen Anfangs- und Endpunkt nicht zu weit auseinander liegen. Sind diese zwei Linien gefunden, muss noch bestimmt werden welche der Linien innen und welche außen liegt.

Relevante Teile des Bildes zwischen den zwei relevantesten Linien

Fahrspuren berechnen

Zur Fahrzeugerkennung werden die Fahrlinien der zwei Autos benötigt. Dafür wereden zunächst senkrechte Querlinien zwischen den zwei Außenlinien berechnet. Diese sind im folgenden Bild rot eigezeichnet.

Alle berechneten Querlinen senkrecht zu den Seitenlinien

Diese Querlinien kann man in einem festgelegten Verhältnis teilen, wodurch man die Positionen der beiden Spuren bekommt. Durch das richtige Aneinanderreihen dieser Positionen entstehen zwei getrennte Fahrspuren. Durch optische Auswertung des Schwarzwertes der Strecke kann zudem eine Kreuzung erkannt werden. Dies funktioniert, ist aber nicht sehr zuverlässig.

Spuren die durch die Aufteilung der Querlinien entstanden sind

Fahrzeugerkennung

Um eine höhere Framerate zu erreichen, wird die Fahrzeugerkennung auf einer 4-fach kleineren Auflösung durchgeführt. Diese beträgt 820x616 Pixel. Das Field of View (FOV) bleibt dadurch gleich. Alle Koordinaten müssen deswegen einfach nur durch vier geteilt werden. Um möglichst wenig Rechenleistung zu beanspruchen, werden dann auf den Fahrlinien in regelmäßigen Abständen Punkte errechnet (weiße Punkte). An jedem dieser Punkte werden neun Pixel ausgewertet und die Durchschnittsfarbe errechnet. Neun Pixel wurden verwendet, um Rauschen einfach zu unterdrücken, was bei einem Pixel problematisch werden kann. Anfangs wird von jedem Auswertepunkt der Grundfarbwert berechnet. Ein Auto wird dann erkannt, wenn der Farbwert an einem Auswertepunkt sich zu stark ändert. Ist ein Auswertepunkt nicht getriggert, wird der Grundfarbwert langsam nachgeführt, um kleine optische Veränderungen zu korrigieren. Dies soll helfen Schatten oder einen veränderten Lichteinfall zu kompensieren. Werden mehrere Auswertepunkte getriggert, wird versucht den sinnvollsten Punkt zu errechnen. Dabei wird sich auch daran orientiert, wo das Auto sich zuletzt befand. Deswegen kann ein anderer Spieler auch in die Strecke greifen wenn sich das Auto wo anders befindet.

Auswertepunkte in regelmäßigen Abstand auf den Fahrlinien

Analoge Fahrzeugansteuerung

Die analoge Ansteuerung der Carrera-Bahn übernimmt die Spannungsregelung der beiden Schienen und somit die Geschwindigkeitssteuerung der Autos. Hierfür wurde ein separates Modul entworfen, welches mit Bluetooth über das Serial-Port-Profil mit der Host-Einheit kommuniziert. Das analoge Modul besitzt hierbei kaum eigene Intelligenz, sondern interpretiert im Wesentlichen nur die Stellsignale der Host-Einheit und bildet diese auf eine Spannung ab. Die beiden Schienen der Carrera-Bahn können dabei separat angesprochen werden. Auch ist es möglich eine negative Spannung auf die Schienen zu geben, um den Rundkurs in beiden Richtungen abfahren zu können. In den Autos sind handelsübliche zweipolige Gleichspannungsmotoren verbaut, die für einen Betrieb bis ca. 20 V ausgelegt sind. Die Größe der angelegten Spannung bestimmt die Drehzahl des Motors und somit die Geschwindigkeit des Autos. Nähere Untersuchungen bzw. Recherchen zum Betriebsbereich der Motoren sind nicht durchgeführt worden, da die Spannungsspeisung über das originale Netzteil der Carrera-Bahn erfolgt.

Einbindung des Moduls

Bei der Entwicklung des analogen Moduls wurde großes Augenmerk auf die Abwärtskompatibilität der Carrera-Bahn gelegt. So sollen die Autos und Streckenteile - insbesondere das Start/Ziel-Streckenteil - der Carrera-Bahn unverändert bleiben, sodass die Carrera-Bahn im 'Handbetrieb' auch ohne das Modul noch wie gewohnt mit den originalen Controllern verwendet werden kann. Dadurch wird zudem erreicht, dass man mit nur einem Controller gegen die künstliche Intelligenz (KI) des programmierten Algorithmus spielen kann. Alternativ kann auch komplett auf den Einsatz der Controller verzichtet werden, wodurch beide Autos durch den Algorithmus gesteuert werden können.
Das analoge Modul verfügt über zwei Eingangskanäle, an welche die beiden Kanäle des originalen Carrera-Bahn Netzteils angeschlossen werden. Jeder Kanal versorgt sowohl im manuellen als auch im automatisierten Betrieb jeweils eine Schiene mit Spannung. Ausgangsseitig besitzt das Modul zwei Kanäle, an welche Stecker angebracht sind, die baugleich mit denen der manuellen Controller sind. Die Stecker werden in das Start/Ziel-Streckenteil der Carrera-Bahn eingesteckt. Für den automatisierten Betrieb wird das Modul somit zwischen Netzteil und Start/Ziel-Streckenteil geschaltet. In der folgenden Abbildung ist eine Übersicht der verschiedenen Betriebsarten und die Einbindung des analogen Moduls aufgezeigt.

Übersicht verschiedener Betriebsarten

Beim Anschließen der Netzteilstecker an das Modul ist bei beiden Kanälen auf die korrekte Polung zu achten, da das Modul sonst nicht funktionsfähig ist oder sogar zerstört werden könnte. Zwar sind laut Datenblatt der H-Brücken negative Spannungen zulässig und eine Diode vor dem Festspannungsregler schützt in der Theorie vor Schäden durch Verpolung, jedoch sind entsprechende Tests nicht durchgeführt worden.

Interner Hardwareaufbau

Der interne Aufbau des Moduls besteht im Wesentlichen aus einem Microcontroller-Board (ESP32, Espressif), welches standardmäßig über ein integriertes Bluetooth-Modul verfügt. Die Ansteuerung der Autos wird über zwei H-Brücken realisiert, welche mit Puls-Weiten-Modulation (PWM) vom Microcontroller angesprochen werden. Jeweils eine H-Brücke (L293, Texas Instruments) übernimmt die Steuerung einer Schiene bzw. Autos. Sowohl die Spannungsversorgung des Microcontrollers als auch die Speisung der H-Brücken geschieht über die beiden Kanäle des Carrera-Bahn Netzteil mit einer nominalen Ausgangsspannung von 14 V. Messungen haben ergeben, dass die tatsächliche maximale Ausgangsspannung im Betrieb abhängig von der aktuellen Belastung des jeweiligen Kanals zwischen 18 V und 20 V schwankt. Der erste Kanal speist einen Festspannungsregler (LM2676, Texas Instruments) und einen nachgeschalteten LDO-Regler (auf Microcontroller-Board verbaut), welche auf die nötige Betriebsspannung von 3,3 V des Mikrocontrollers herunter regeln. Außerdem versorgt der erste Kanal eine der beiden H-Brücken und somit eine der Schienen mit Spannung. Der zweite Kanal des Netzteils übernimmt die Versorgung der zweiten H-Brücke. Dieser Aufbau hat zur Folge, dass bei Verwendung von nur einem Kanal zwangsläufig der erste Kanal verwendet werden muss, da dieser die Betriebsspannung für den Mikrocontroller liefert. Zusätzlich wurden im analogen Modul zwei LEDs verbaut, welche signalisieren, ob das Mikro- controller-Board mit Spannung versorgt ist (Grüne LED leuchtet dauerhaft) und ob gerade ein Datenaustausch zwischen Host-Einheit und analogem Modul stattfindet (Orange LED blinkt).

Aufbau der Hardware

Firmware

Für die Entwicklung der Firmware wurde die Arduino Entwicklungsumgebung verwendet. Die Firmware liest in einer Endlosschleife die serielle Bluetooth-Schnittstelle aus, interpretiert die eingegangen Stellsignale und moduliert die PWM-Ausgänge der H-Brücken. Für die Übertragung der Stellsignale wurde ein einfaches Protokoll definiert, sodass die Firmware die Stellsignale eindeutig der jeweiligen Schiene zuzuordnen kann. Für jede Schiene ist ein vorzeichenbehaftetes Stellsignal zwischen -255 und 255 vorgesehen, welches die Spannung unter Berücksichtigung der Polung zwischen 0 V und der maximalen Ausgangsspannung moduliert. Die Syntax ist wie folgt definiert:\\

{SETVALUE1},{SETVALUE2}

Wie ersichtlich ist, werden die beiden Stellsignale SETVALUE1 und SETVALUE2 durch ein einfaches Komma getrennt. Die Verwendung von zusätzlichen Leerzeichen ist nicht vorgesehen. Welches Stellsignal letztendlich welche Schiene ansteuert, wird durch den Anschluss des analogen Moduls an die Carrera-Bahn festgelegt.
Ein Programmablaufplan der kompletten Firmware ist in folgender Abbildung dargestellt.

CarreraVisionFirmwareAblauf.png

Ergebnis

Die Software arbeitet für ein Studentenprojekt sehr zuverlässig. Zudem konnte man eine einfache GUI erstellen, welche eine schnelle Justage und Fehlerbehebung im Vorführbetrieb ermöglicht hat. Alle wichtigen Parameter (ca. 60 Stück) vom Code wurden in ein xml-File ausgelagert, wodurch man zwicshen verschiedenen Autos schnell wechseln kann. Auch kleine Fehler bei der Streckenerkennung können so durch ein Erfahrener Entwickler ohne neukompilierung der Software behoben werden.

Streckenerkennung

Die Streckenerkennung arbeitet sehr zuverlässig. In der folgenden Übersicht wurden verschiedene Probleme künstlich erzeugt, mit welchen die Software häufig zurechkommt.
Kurze Erklärung zu jeder Zeile:

  1. OK - Einfache Strecke, aber mit Reflektionen durch Lampen auf der Metallschiene
  2. OK - Strecke mit unterschiedlichen Kurven
  3. OK - Strecke mit unterschiedlichen Kurven
  4. OK - Verwendung von Weichen
  5. FAIL - Verwendung einer Brücke
  6. OK - zwei rote Seitenstreifen berühren sich
  7. OK - starke Beschädigung der roten Seitenmarkierung, sowie überflüssige Teile neben der Strecke
  8. OK - erstellen von Farbstichen, Unterbelichtungen und Überbelichtungen
  9. OK - Brücke und Kreuzungen
  10. FAIL - Komplexe Streckenführung mit Kreuzungen und Randpunktkontakt an zwei Stellen in Kurven
  11. OK - Brücke, sowie überflüssige Teile neben der Strecke
  12. OK - Sehr viele überflüssige Teile neben der Strecke
Ergebnis des Unit-Tests. Viele verschiedene Strecken werden sicher erkannt