Nachdem wir im vorherigen Artikel bereits unsere Idee zu „Anki OVERDRIVE goes IoT“ präsentiert haben, werden wir in diesem Teil der Reihe einen Blick auf die Technik hinter Anki Overdrive werfen, demonstrieren, wie die Fahrzeuge mit unserem SDK verwendet werden können und auf die Probleme, mit denen wir bei der Anbindung der Fahrzeuge konfrontiert waren, eingehen. Zudem wird zusammen mit diesem Beitrag unser Projekt auf GitHub veröffentlicht.

Die Anki-Fahrzeuge nutzen zur Kommunikation Bluetooth Low Energy (Bluetooth LE oder kurz: BLE) und fungieren als GATT-Server (Generic Attributes). Als solcher bieten sie eine Reihe von Services an, die wiederum diverse Characteristics enthalten. Diese Characteristics werden abonniert um Werte vom Gerät zu empfangen oder um Werte an dieses zu senden.
Die Kommunikation zwischen den Fahrzeugen und dem Host wird nicht verschlüsselt und lässt sich daher mit entsprechenden Sniffing-Tools mitschneiden und interpretieren.

Bei der Interpretation der Daten erweist sich das von Anki auf GitHub bereitgestellte SDK als nützlich, da es sehr detailliert – allerdings in C – die einzelnen Datenpakete gruppiert nach der Art der Kommunikation (Controller to Vehicle, Vehicle to Controller) definiert.
Da das offizielle SDK von Anki aufgrund seiner Umsetzung in C sehr gehalten und die Datenstrukturen nicht „komfortabel“ zu nutzen sind, haben wir uns für eine eigene Umsetzung in C++ entschieden. In C++ wurden uns, dank dem Qt-Framework, etliche Teile, wie der direkte Zugriff auf die BLE-Schnittstelle via BlueZ, erspart. Zudem konnten wir so sicherstellen, dass das Design eine Nutzung, wie sie für unseren IoT-Showcase notwendig war, ermöglicht. Zur erfolgreichen Realisierung des Projekts, war es unumgänglich, sich intensiv mit der Funktionsweise von Anki Overdrive zu beschäftigen und die Umsetzung eines eigenen SDKs zur Kommunikation war bei diesem Unterfangen definitiv hilfreich.

Bei der Verwendung von Bluetooth bzw. Bluetooth LE ist zu beachten, dass ein gewisser „Flow“ eingehalten werden muss:

  • Scannen verfügbarer Geräte
  • Aufbau der Verbindung
  • Suchen nach Services, die vom Gerät angeboten werden
  • Suchen nach Characteristics, die der Service enthält

Die Services und Characteristics werden durch UUIDs identifiziert. Da Anki-Fahrzeuge mehrere Services anbieten, ist es von Vorteil, dass die UUIDs, sowohl für den entsprechenden Service, als auch die Characteristics, im Anki SDK aufgelistet sind.

Die Abbildung dieses Prozesses in entsprechenden Klassen ermöglicht es uns, eine Verbindung zu allen vorhandenen Fahrzeugen aufzubauen, nach Services beziehungsweise Characteristics zu suchen und schließlich Datenpakete vom Fahrzeug zu empfangen oder Befehle an selbiges zu senden.
Im Sourcecode sieht dieses Vorgehen dann wie folgt aus:

QList<AnkiCar*> ankiCarList;
ankiCarList.append(new AnkiCar());
 
BluetoothController* bluetoothController = new BluetoothController(ankiCarList, this);
 
...

AnkiCar* ankiCar = ankiCarList->at(0);
ankiCar->setVelocity(300);
ankiCar->changeLane(68.0f); //Drive right
ankiCar->doUturn();
ankiCar->stop();

Eine besondere Hürde in der Entwicklung war es, die aktuelle Position des Fahrzeuges auf der Bahn zu erfassen. Die Fahrzeuge mit einer Kamera an der Unterseite für das menschliche Auge „unsichtbare“ Codes auf den Segmenten der Fahrbahn. Anhand dieser Daten können beispielsweise die ID (wobei es sich hierbei um keine eindeutige Identifikationsnummer handelt) der Segmente und die aktuelle Spur auf der sich das Fahrzeug bewegt bestimmt werden. Eine exakte Erfassung der Position auf dem Segment ist allerdings nur schwer möglich. Bei unseren Recherchen sind wir auf das Projekt TrageDIY auf GitHub gestoßen.
TrageDIY steht für Track Generator Do It Yourself und ermöglicht es, eigene mit für Anki-Fahrzeuge lesbaren Codes bedruckte Segmente herzustellen beziehungsweise eine eigene Strecke, basierend auf von den Fahrzeugen erfassten Daten, in entsprechende Codes umwandeln zu können.
TrageDIY kann zudem alle möglichen Positionen auf der Strecke errechnen und diese kartesischen Koordinaten zuweisen. Diese Daten werden als .csv-Datei gespeichert.
Unser Ansatz war es also, erst den Streckenscan von TradeDIY zu replizieren, um die Daten in das entsprechende Format zu bringen. Anschließend werden die aufbereiteten Daten von TrageDIY verarbeitet und in einer Map abgelegt. So kann jedem Position-Update eines Fahrzeugs anhand der Informationen, die in jedem Messpunkt kodiert sind, die aktuelle Position in kartesischen Koordinaten verarbeitet werden.

In diesem Video haben wir das fertige Ergebnis festgehalten, um den Funktionsumfang zu veranschaulichen.

Um unser Projekt mit anderen zu teilen, die an der Entwicklung mit Anki Overdrive interessiert sind – oder einfach nur eine Rennbahn mit ferngesteuerten Autos im Büro oder Wohnzimmer stehen haben möchten – haben wir unser SDK mitsamt einer Demo-Anwendung, die die Steuerung der Fahrzeuge ermöglicht, auf GitHub veröffentlicht.

In diesem Beitrag haben wir die Entstehung unseres SDKs mit ihren diversen Hürden veranschaulicht und konnten hoffentlich einen kleinen Einblick in die Funktionsweise von Anki Overdrive geben.