Mein Raspberry Pi auf 2 Rädern
mit einer praktischen Kamera-Fernbedienung
Mein neustes Projekt ist fertig. Sonst baue ich Webseiten… Dieses Mal hatte ich Lust auf was Echtes! :-)
Also lasse ich meinen Raspberry Pi durch die Wohnung fahren… mit zwei Servomotoren, Rädern, kabellosem Strom und einer Handy-Kamera-Steuerung.
Was habe ich dafür gebraucht?
- 1x Raspberry Pi
- 2x Continuous Rotation Micro Servos
- 2x passende Räder
- 6x Jumper Kabel m/w — ich hab’ sie von meinem Vater. ;-)
- 1x USB Power Bank aus der Schublade — ich habe die hier.
- 1x schöne Box mit Deckel in genau der richtigen Größe — Danke an meine Frau. ;-)
- Bunte Aufkleber, um den Roboter in einem Kamerabild finden zu können
- 1x zermatschter Tischtennisball als 3. Standbein
- Deko, Scheren, Tesafilm, …
Wie funktioniert das?
Hier der Weg, den ich gegangen bin…
1. Servo-Motoren ansteuern.
Servomotoren haben 3 Eingänge: 5 Volt (rot), Erde (braun), Signal (gelb). Diese werden mit Jumper-Kabeln an die passenden GPIO-Pins des Raspberry Pi angeschlossen. Hier gibt’s die Pin-Belegung. 5V gibt es 2x oben rechts. Ground ein paar mal quer verteilt. Für die Signalpins habe ich GPIO 17 und GPIO 27 genommen. Die liegen direkt nebeneinander.
Das Signal wird über Pulsweitenmodulation (PWM) gesetzt. Das bedeutet: Das Signal wechselt schnell zwischen 0 und 1. Je nach Dauer (“Weite”) der 1 ergibt sich der Sollwert für die Geschwindigkeit.
- 1500 µs — Stillstand
- 1500 µs + 800 µs = 2300 µs — volle Kraft gegen den Uhrzeigersinn
- 1500 µs - 800 µs = 700 µs — volle Kraft im Uhrzeigersinn
Jetzt kann ich mich auf den Raspberry Pi verbinden und die Servomotoren per Kommandozeile ansteuern. Das Programm pigs ist ein knackiges Kommandozeilentool dafür (pigs man page).
- sudo pigpiod — zum Starten des Pi GPIO Dienstes.
- pigs m 17 w — um Pin 17 auf Write zu setzen
- pigs servo 17 2300 — volle Kraft voraus!
- pigs servo 17 700 — volle Kraft zurück!
- pigs servo 17 0 — Stopp!
- pigs m 17 w m 27 w servo 17 2300 servo 27 700 mils 1000 servo 17 0 servo 27 0 — für eine nützliche Sequenz: Erst die GPIO-Ports 17 und 27 auf Write setzen. Dann volle Kraft auf beide Motoren in entgegengesetzter Richtung. Dann 1000 Millisekunden beibehalten. Dann beide Motoren wieder stoppen.
2. Servomotoren über HTTP freigeben.
Als nächstes habe ich diese Kommandos über HTTP offen gelegt. Als Java Web-Entwickler ist das für mich ein Heimspiel.
Ich betreibe einen Tomcat 8 Java Web Server auf dem RasPi. Darin läuft ein Java Web-Archive (WAR). Ein HttpServlet verarbeitet HTTP-Aufrufe. Es nimmt als URL-Parameter Sollwerte entgegen und startet das pigs-Programm mittels ProcessBuilder.
Die zweite Version ist etwas schlauer und versteht Kommando-Reihen:
- left <-800 … 0 … 800> — zum Steuern des linken Motors
- right <-800 … 0 … 800> — zum Steuern des rechten Motors
- wait <Millisekunden> — zum Beibehalten
- stop — als Kurzform von left 0 right 0
- clear — zum Löschen bisheriger Kommandos
Ein Beispiel-Aufruf:
http://…/wheels?x=clear+left+800+right+800+wait+1000+stop
3. Einfache Fernbedienung bauen.
Die einfache Fernbedienung erlaubt dann per Klick auf die passende Stelle das linke und rechte Rad zu steuern. Damit kann ich den Pi schon mal durch die Gegend fahren… Yay!
4. Handy-Kamera abgreifen, bunte Markierungen erkennen, aus vier Punkten das Roboter-Koordinatensystem berechnen.
Ich möchte aber eine coolere Steuerung haben!
Die Steuerung soll auf dem Handy im Browser geöffnet werden. Sie zeigt dann das Handy-Video. Der Benutzer filmt den Roboter. Es werden signal-rote Aufkleber oben auf dem Roboter erkannt. So kann der Roboter im Handybild gefunden werden. Anhand der 4 großen Markierungen kann ich das perspektivisch verzerrte Roboter-Koordinatensystem ausrechnen. Wenn ich dann irgendwo hinklicke, weiß ich z.B: Das sind 210mm geradeaus und 32mm nach links.
Im Einzelnen läuft es auf diese Schritte hinaus:
- Über navigator.getUserMedia die Kamera anzapfen. Die Kamera in ein <video>-Tag leiten.
- Wiederholt Einzelbilder in ein <canvas> zeichnen und die Pixel abgreifen.
- Erkennen, ob die Pixel signal-rot sind… am besten über Ähnlichkeit im HSV-Farbraum, dann hängt es nicht so stark von Licht und Schatten ab.
- Per FloodFill zusammenhängende Inseln signal-roter Pixel finden, die eine Mindestgröße haben. Per Durchschnitt deren Mittelpunkte ermitteln.
- Die Inseln absteigend nach Größe sortieren.
- Die Markierungen sind so gestaltet, dass die größte Insel links-vorne ist. Dann können die vier größten Inseln so sortiert werden, dass sich ein Kreis im Uhrzeigersinn ergibt. Voilà! Links-vorne, rechts-vorne, rechts-hinten, links-hinten.
- Jetzt haben wir vier bekannte Punkte im Bild und wissen, wie ihre Koordinaten im Roboter-Koordinatensystem sein sollen. Mit diesem cleveren Ansatz kann ich dann ein lineares Gleichungssystem aufstellen und die zwei Matrizen ausrechnen, mit denen ich Bild-Koordinaten in Roboter-Koordinaten umrechnen kann und umgekehrt.
- Dann zeichne ich einen Rahmen um den Roboter als Zeichen, dass ich das Koordinatensystem richtig erkannt habe — siehe Bild oben.
- Wenn der Benutzer dann auf’s Bild klickt, weiß ich, wie viele Millimeter geradeaus/zurück und links/rechts ich ansteuern will…
- Das übergebe ich per HTTP an die Steuerung, die dann über pigs die Motoren ansteuert und der Roboter fährt dort hin.
5. Kommando: Drehen um 32°, 240mm geradeaus fahren.
Bleibt also, dass ich ein Kommando wie dieses ausführen können muss: 32° drehen, 240mm geradeaus fahren.
Geradeaus fahren ist leicht: Gleiche Geschwindigkeit auf beide Räder geben. Ich habe versucht, aus dem Datenblatt abzulesen, wie viele Umdrehungen ich bei so-und-so-viel Input zu erwarten habe. Aber letztendlich war das zu ungenau. Also habe ich den Pi aufgebockt und mich an die Millisekunden herangetastet, die ich für eine bzw. 10 Radumdrehungen brauche. Ich kenne den Radumfang. So kann ich leicht ausrechnen, wie lange ich für 240mm geradeaus fahren muss. Geradeaus: Check.
Drehen um den Mittelpunkt zwischen den Rädern geht so: Ein Rad geradeaus. Das andere Rad in gleicher Geschwindigkeit rückwärts. Eigentlich kann ich mit dem Radabstand und dem Radradius ausrechnen, wie lange gefahren werden muss, um eine bestimmte Drehung zu erreichen. Aber wegen der Reibung etc. war auch das zu ungenau. Also habe ich hierzu abgemessen, wie viel Zeit ich für eine 360°-Drehung brauche. Je nach Winkel drehe ich dann den entsprechenden Anteil dieser Zeit. Da sich die Reibung immer leicht anders verhält, schleichen sich dabei kleine Fehler ein, aber für meine Zwecke reicht es. Drehung: Check.
Voilà!
Und hier ist er nun, mein Raspberry Pi mit Kamera-Steuerung:
Es war ein schönes Projekt, meine Kenntnisse über autonome Differential Drive Roboter aus meinem Studium mal an meinem Raspberry Pi auszuprobieren. Das hat wirklich Spaß gemacht!
Die Servomotoren anzusteuern war einfacher als gedacht.
Weil der Raspberry Pi WLAN hat und ein Webserver darauf laufen kann, bin ich schnell wieder in heimischen Gefilden gewesen. Dank HTML5 Kamera / Video / Canvas kann man heutzutage prima Adhoc-Bilderkennung im Smartphone/Tablet-Browser anbieten.
Besonders viel Spaß hat vor allem das Stöbern im Adafruit Online-Shop und Lernbereich gemacht! Dort kannst du dich super inspirieren lassen für alle möglichen Hardware-Projekte. Das Paket wurde in nur drei Tagen von New York nach Nordrhein-Westfalen geliefert — abgefahren!
Mal sehen, was ich als Nächstes baue… :-)