Logo

PiBot-A

mobiler Roboter mit Raspberry Pi A+

PiBot-A - mobile robot with Raspberry Pi A+

PiBot-A – ein mobiler Roboter auf Basis des Raspberry Pi Model A+

Eigenschaften

PiBot-A ist ein kleiner, mobiler, sich autonom bewegender Roboter auf Basis des Einplatinencomputers Raspberry Pi, Model A+. Er fährt auf zwei axial angeordneten, separat angetriebenen Rädern und stützt sich dabei vorn und hinten auf jeweils einer Gleitkugel ab; aufgrund dieser Konstruktion ist er vorzugsweise auf glattem Untergrund unterwegs. An der Vorderseite verfügt er über eine Buchsenleiste, an die unterschiedliche Sensoren (zum Beispiel für die Hinderniserkennung oder Linienverfolgung) angeschlossen werden können.

PiBot-A mit Abstandssensoren für die Hinderniserkennung (Obstacle Avoidance)

PiBot-A als Linienfolger (Line Follower)

PiBot-A beim Auflösen eines Labyrinthes (Maze Solver)

Vergleich zum PiBot-B

Im Vergleich zum PiBot-B, der auf dem Raspberry Pi Model B basiert, war der Entwicklungsaufwand für die Roboter-Basis hier deutlich geringer (wenn man mal von den diversen Hürden absieht, die sich mir unerwartet in den Weg stellten – siehe Anmerkungen):

  • Das Model A+ verfügt über zwei Hardware-PWM-Ausgänge (Model B besitzt nur einen); der „PWM-Umschalter“ konnte daher entfallen.
  • Mit dem Pololu DRV8835 Dual Motor Driver Kit for Raspberry Pi B+ steht ein Modul (einschließlich Software) zur Verfügung, das direkt auf den GPIO-Konnektor des Raspberry Pi aufgesteckt werden kann und die H-Brücken-Steuerung für die Motoren anschlussfertig implementiert.

Wenn man auf den weiter unten beschriebenen besonders kompakten Aufbau und den damit verbundenen Aufwand verzichtet, sollte dieses Roboter-Projekt aufgrund seiner Einfachheit und Nachbausicherheit daher auch für Schulen gut geeignet sein. Aus diesem Grunde habe ich hier – im Gegensatz zum PiBot-B – die Software vollständig dokumentiert. Sie sollte nach Download und Installation auf Anhieb funktionieren.

Blockbild

schematic of Raspberry Pi robot

Blockbild

Herzstück des Roboters ist der Einplatinencomputer Raspberry Pi in der Variante „Model A+“. Die Ansteuerung der beiden Gleichstrommotoren mittels Pulsweitenmodulation (PWM) übernimmt das Pololu DRV8835 Dual Motor Driver Kit for Raspberry Pi B+ mit zwei integrierten H-Brücken, das auf den GPIO-Port des Raspberry Pi aufgesteckt wird und auch mit dem Model A+ tadellos funktioniert.

Die Stromversorgung erfolgt durch vier AAA-Akkus, die sowohl die Motoren speisen als auch mittels eines Step-Up/Step-Down-Spannungsreglers den Raspberry Pi über den GPIO-Pfostenstecker mit den benötigten 5 Volt Spannung versorgen. (Um den Akku während der Softwareentwicklung im nicht-mobilen Betrieb schonen zu können, kann der Spannungsregler an einer Steckverbindung abgetrennt und statt dessen ein Netzteil an der dafür vorgesehenen Micro-USB-Buchse angeschlossen werden.)

Mit einem an den GPIO-Konnektor angeschlossenen Taster (links) können der Roboter-Fahrbetrieb gestartet und gestoppt sowie ein Shutdown ausgelöst werden, auf den auch beim Raspberry Pi vor dem Ausschalten keinesfalls verzichtet werden darf. Die diversen Betriebszustände werden durch die auf dem Raspberry Pi vorhandene grüne Status-LED signalisiert.

An eine frontseitig zugängliche 8-Pin-Buchsenleiste sind 3,3 Volt, Masse sowie eine Handvoll GPIO-Pins herausgeführt; hier können bei Bedarf unterschiedliche Sensoren angeschlossen werden.

Die (beim Model A+ einzige) USB-Buchse wird für den Anschluss eines WLAN-Dongles genutzt. Über das WLAN können dann mit einer simplen Smartphone-Web-App dieselben Funktionen wie mit dem Taster ausgeführt werden (Start, Stop, Shutdown). Zwar ist dank des Tasters auch ein Betrieb ganz ohne diese Fernbedienung möglich, für die Wartung und Programmierung sollte aber ohnehin ein drahtloser SSH-Zugang existieren.

GPIO-Anschlüsse

Mit Ausnahme des WLAN-Adapters wird die gesamte Elektronik rund um den Raspberry Pi (Modul für die Motorsteuerung, Start/Stopp-Shutdown-Taster, Sensoren) an den GPIO-Konnektor angeschlossen. Die Modul-Platine belegt mechanisch die Pins 1 – 34, obwohl sie nur wenige davon tatsächlich nutzt. Für die zusätzlichen eigenen Anwendungen (Sensoren, Taster) habe ich daher für die sechs noch zugänglichen Pins am Ende des Konnektors eine passende Steckverbindung basteln und Kabel auf die Modul-Platine auflöten müssen.

Die Tabelle zeigt (sortiert nach den Pins am GPIO-Konnektor) die Belegung:

Pin GPIO Funktion
13,3 VSensoren: Versorgungsspannung (Buchsenleiste Pin 7)
25 VVersorgungsspannung des Raspberry Pi über das Modul
18GPIO 24Sensoren: I/O (Buchsenleiste Pin 3)
20GND Start/Stopp-Shutdown-Taster: Masse
22GPIO 25Start/Stopp-Shutdown-Taster: Eingang
29GPIO 5Modul Motorsteuerung: linker Motor, Drehrichtung
31GPIO 6Modul Motorsteuerung: rechter Motor, Drehrichtung
32GPIO 12Modul Motorsteuerung: linker Motor, PWM
33GPIO 13Modul Motorsteuerung: rechter Motor, PWM
35GPIO 19Sensoren: I/O (Buchsenleiste Pin 4)
37GPIO 26Sensoren: I/O (Buchsenleiste Pin 5)
38GPIO 20Sensoren: I/O (Buchsenleiste Pin 2)
39GNDSensoren: Masse
40GPIO 21Sensoren: I/O (Buchsenleiste Pin 1)

Belegung des GPIO-Konnektors

Start/Stopp-Shutdown-Taster

Der Taster für das Ein- und Ausschalten des Roboterbetriebs und für den Shutdown wird zwischen Masse und GPIO-Pin 25 angeschlossen. Der als Eingang(!) konfigurierte GPIO-Pin wird bei offenem Taster mit einem softwareseitig aktivierten Pull-Up-Widerstand auf High gezogen, bei gedrücktem Taster liefert er ein Low (siehe Software).

Sensoren

Für den Anschluss von Sensoren habe ich 3,3 Volt, Masse und fünf freie GPIO-Pins mit einer 8-poligen Buchsenleiste verdrahtet. Die Belegung ist wie folgt:

Sensoren-Buchsenleiste

Buchsenleiste an der Chassis-Front

Pin Funktion
1GPIO 21
2GPIO 20
3GPIO 24
4GPIO 19
5GPIO 26
6Masse
73,3 Volt
8Reserve (evtl. 5 Volt)

Belegung der Buchsenleiste


(Zu Pin 3 siehe Anmerkungen).

Roboter-Chassis

Acryl-Plättchen für das Roboter-Chassis

Acryl-Plättchen für das Roboter-Chassis

Da die neuen Modelle des Raspberry Pi (A+ und B+) vier Bohrungen in exakt rechteckiger Anordnung aufweisen, bot sich ein äußerst kompakter Aufbau in „Etagen“ mit dem Grundriss der Raspberry-Pi-Platine an. (Glücklicherweise passt sogar ein Batteriehalter für vier AAA-Akkus genau hinein.) Dazu habe ich mir bei Nordic Panel auf Grundlage nebenstehender Zeichnung drei passende Acryl-Plättchen mit Bohrungen und gerundeten Ecken anfertigen lassen. (Für das untere Plättchen wählte ich schwarzes, für die übrigen transparentes Material. Das ist nicht ganz billig, sieht aber sehr chic aus.) Um gängige Abstandsbolzen und Schrauben mit M3-Gewinden verwenden zu können, musste ich die Bohrungen in der Platine des Raspberry Pi auf 3,2 mm erweitern. (Dass dabei der Garantieanspruch erlischt, versteht sich von selbst; alternativ müsste man die übrigen Komponenten mit Gewinden M2,5 beschaffen.)

schematic of Raspberry Pi robot

Aufbau des Chassis (Seitenansicht)

Durch die Verwendung von Kunstoff-Bolzen und -Unterlegscheiben kommt die Platine des Raspberry Pi zwar nirgendwo mit Metall in Berührung, es ist zwischen den Bolzen und den benachbarten SMD-Bauteilen auf der Platine aber extrem eng, hier muss mit äußerster Vorsicht zu Werke gegangen werden.

Ich empfehle daher, beim Aufbau des Chassis folgendermaßen vorzugehen: Die Bolzen mit Innen- und Außengewinde werden mit dem Außengewinde von oben durch die Platine des Raspberry Pi gesteckt, so ausgerichtet, dass sie möglichst keinen Kontakt zu Bauteilen auf der Platine haben, und in dieser Position fixiert. Dann wird der Raspberry Pi umgedreht und auf die Bolzengewinde werden einige Kunststoff-Unterlegscheiben und die mittlere Acryl-Platte gesteckt. Anschließend werden die Bolzen mit Innen-Innen-Gewinde aufgeschraubt. Zuletzt werden die äußeren Acrylplatten mit je vier M3-Schrauben befestigt.

Zusammenbau

(1) Front

(2) von oben

(3) Heck

(4) rechte Seite

(5) von unten

(6) linke Seite

Fahrgestell

Da ich mich nicht traute, die kostbare schwarze Acryl-Bodenplatte zu durchbohren, habe ich die Motoren (mit den dazu gehörigen Haltern) und die Gleitkugeln mit doppelseitigem Klebeband angeklebt (siehe Bild 5). Die Lager der Gleitkugeln werden mit zwei Lagen selbstklebender Möbel-Filzgleiter auf den richtigen Abstand gebracht (siehe Bild 1 und Bild 3).

Verkabelung untere Etage

schematic of Raspberry Pi robot

Aufgeklappt nach dem Lösen der Schrauben am Boden

Den Ein/Aus-Schalter und den Start/Stopp-Shutdown-Taster habe ich auf ein Platinchen montiert, das ich an den Batteriehalter geklebt und mit dessen Anschlussfahnen verdrahtet habe (blau isoliert auf dem Bild oben sowie auf Bild 3 und Bild 6). Drei Litzen – verbunden mit Plus- und Minuspol der Akkus sowie dem GPIO-Anschluss des Tasters – führen von hier eine Etage höher (siehe Bild 3). Der Akku-Minuspol ist die gemeinsame Masse; der Masse-Anschluss des Tasters befindet sich daher auf der Platine. Den Batteriehalter habe ich (ebenfalls mit doppelseitigem Klebeband) auf die Oberseite der Bodenplatte geklebt (siehe Foto oben).

Verkabelung obere Etage

schematic of Raspberry Pi robot

Kabelanschlüsse am GPIO-Konnektor

Damit ich das Platinchen mit dem Spannungsregler für den nicht-mobilen Netzteilbetrieb abziehen kann, habe ich es mit einem Steckverbinder an das Pololu-Modul angeschlossen, ein daran befestigter Kunststoffstreifen (links im Bild) dient dabei als Griff. Um den Aufbau über dem Raspberry Pi möglichst flach zu halten, habe ich den Regler horizontal montiert; deshalb konnte ich die Stiftleisten-Paare für die Motoren und die Akkuspannung nur noch wie abgebildet anbringen. Insbesondere die Stecker für den linken Motor passten nur noch unter die Platine (Lötpunkte M2A und M2B, im Foto oben gelb umrandet).

Das hässliche Gebilde rechts neben dem Pololu-Modul ist mein Selbstbau-GPIO-Stecker; die orangefarbene Litze führt ihm von dem von der Pololu-Platine okkupierten Pin 1 des GPIO-Konnektors 3,3 V zu. Nach rechts führt von diesem Stecker ein Flachbandkabel unter der mittleren Acrylplatte hindurch nach vorn zu der Sensor-Buchsenleiste (siehe auch Foto weiter oben).

PiBot-A - mobile robot with Raspberry Pi PiBot-A - mobile robot with Raspberry Pi

Selbstbau-GPIO-Stecker und Flachkabel zu den Sensoren

Die grüne Litze verbindet Pin 22 (GPIO 25) mit dem Taster in der unteren Ebene. Die fertige Verkabelung der oberen Etage zeigt Bild 2.

(Zu Pin 3 des Sensor-Konnektors siehe Anmerkungen).

Software

Die Software besteht aus einer von Pololu zusammen mit dem Modul für die Motorsteuerung bereitgestellten Python-Bibliothek, sowie einer Handvoll selbst geschriebener Skripte (Bash, Python und PHP), die im Folgenden dokumentiert werden und als Tarball zum Download zur Verfügung stehen.

Software-Komponenten

Zusammenwirken der Software-Komponenten

Der Einfachheit halber habe ich die Teilfunktionen der Software auf kleinere Skripte aufgeteilt, die ich in der aus meiner Sicht für den jeweiligen Zweck geeigneten Sprache geschrieben habe.

robot.sh

robot.sh – zentrales Bash-Skript

Das Zentrum der Software bildet das Bash-Skript „robot.sh“, das – teils über andere Skripte – den Roboter startet und stoppt, die grüne Status-LED ansteuert und ggf. einen Shutdown fährt. Es wird wahlweise aufgerufen

  • vom Skript button.py, das (als Daemon) den Taster abfragt,
  • durch die Smartphone-Web-App mittels CGI, oder
  • aus der Kommandozeile (als root oder mittels sudo).

Der Roboter kann – je nachdem, welche Sensoren angeschlossenen wurden – in unterschiedlichen Modi betrieben werden, beispielsweise als Obstacle Avoider (Hindernissen ausweichen) oder Line Follower (einer Linie auf dem Boden folgen). Für jeden dieser Modi existiert ein Python-Skript, das die jeweils benötigte Funktionalität implementiert. Die Konfigurationsdatei robot.cfg enthält für jeden dieser Modi eine Zeile; bei dem gerade aktiven beginnt die Zeile mit einer "1", bei allen anderen mit "0":

0 oa obstacle avoider
1 lf line follower
0 ms maze solver
0 bv braitenberg vehicle
0 rc remote control

Konfigurationsdatei robot.cfg

Das Skript robot.sh entnimmt der Konfigurationsdatei den aktiven Modus und startet das passende Python-Skript. Im Beispiel oben ist der Modus „obstacle avoider“ mit dem Kürzel „oa“ aktiviert, es würde also das Python-Skript robot-oa.py ausgeführt werden.

Es ist darauf zu achten, dass die Konfigurationsdatei zu den angesteckten Sensoren passt, andernfalls kann es zu (im schlimmsten Fall verheerenden) Fehlfunktionen kommen. Die Einstellung des aktiven Modus kann mit dem Skript robot.sh erfolgen (siehe unten), künftig soll dies auch mit der Web-App möglich sein.

Da auf die GPIOs zugegriffen wird, muss robot.sh als root (oder via sudo) ausgeführt werden, was beim Start durch button.py oder die Web-App gegeben ist. Es existieren folgende Kommandozeilen-Optionen: Mit „start“ bzw. „stop“ wird der Roboter gestartet (robot-xy.py wird als Daemon ausgeführt) beziehungsweise gestoppt (der Prozess wird mit SIGTERM terminiert), mit „toggle“ wird – je nach Ausgangszustand – ein laufender Roboter gestoppt bzw. ein nicht laufender gestartet, und mit „shutdown“ wird der Raspberry Pi heruntergefahren. Wird das Kürzel eines der in der Konfigurationsdatei eingetragenen Modi übergeben, wird dieser Modus aktiviert (indem die Konfigurationsdatei editiert wird); ohne Argument werden bei laufendem Roboter-Prozess dessen PID (oder stattdessen ein "-") und der aktive Modus auf STDOUT ausgegeben:

$ sudo ./robot.sh lf
$ sudo ./robot.sh start
$ sudo ./robot.sh
2036 lf line follower

Motorsteuerung

Mit dem Pololu-Modul für die Ansteuerung der Motoren wird eine Python-Bibliothek mitgeliefert, welche die für die Motorsteuerung benötigten Funktionen implementiert; ein Beispiel-Skript demonstriert, wie einfach das geht. Beispielsweise können mit dem folgenden Funktionsaufruf der linke Motor angehalten und der rechte mit halber Kraft vorwärts angetrieben werden:

$ sudo python 2>&-
>>> from pololu_drv8835_rpi import motors, MAX_SPEED
>>> motors.setSpeeds(0, MAX_SPEED/2)

Und schon macht der Roboter eine Linksdrehung!

In den oben erwähnten Python-Skripten wird diese Bibliothek importiert, so dass diese Funktionen für die Motorsteuerung zur Verfügung stehen.

Web-App

Web-App auf iPhone 5

Web-App auf iPhone 5

Die Web-App wird durch das PHP-Skript robot.php implementiert.

In einem Formular werden die Buttons Start, Stop und Shutdown angezeigt. Wird einer dieser Buttons gedrückt, wird das Skript robot.sh ausgeführt und der Name (genau genommen der „value“) dieses Buttons als Argument übergeben. Das ist schon alles!

Mit ein wenig CSS (robot.css) und ein paar Optimierungen für die Anzeige auf dem Smartphone wird daraus eine recht ansehnliche Web-App. Ich zeige hier die Optimierungen für das iPhone 5 (mit den beiden meta-Tags „apple-mobile-web-app-*“) – für andere Smartphones sind andere Anpassungen erforderlich.

Die Web-App setzt natürlich einen installierten Webserver (ich habe mit lighttpd gute Erfahrungen gemacht) und eine WLAN-Anbindung voraus. Außerdem muss der Webserver-User (www-data) in /etc/sudoers für die Ausführung des Skriptes robot.sh mittels sudo autorisiert werden:

www-data ALL=NOPASSWD: /home/pi/robot/robot.sh

Hier ist das PHP-Skript:

Die Web-App ist ein simples PHP-Skript

Start/Stopp-Shutdown-Taster

Mit dem Taster wird der Roboter-Fahrbetrieb zunächst gestartet, danach kann er damit alternierend ein- und ausgeschaltet werden. Wird der Taster länger als 2 Sekunden gedrückt, wird ein Shutdown ausgelöst.

Der Taster ist mit Pin 22 des Pfostensteckers (GPIO 25) verbunden und schaltet diesen bei Betätigung auf Masse, während ein per Software aktivierbarer Pull-Up-Widerstand den Pin bei offenem Taster auf High-Pegel hält. Bei betätigtem Taster wird ein Interrupt ausgelöst und es erfolgt die Auswertung der Tastenfunktion. Das Python-Modul RPi.GPIO ist hierfür bestens geeignet, da es ab der Version 0.5.0a auch in der Lage ist, Interrupts zu verarbeiten.

button.py – Abfrage des Start/Stopp-Shutdown-Tasters

Das Python-Skript „button.py“ definiert zu Beginn der Hauptschleife zunächst GPIO 25 als Input und aktiviert den internen Pull-Up-Widerstand. Anschließend wird ein Wartezustand eingeleitet, der erst durch einen Interrupt wieder beendet wird. Ausgelöst wird dieser Interrupt durch eine fallende Flanke an GPIO 25 (erzeugt durch Drücken des Tasters). Anschließend wird das Tastenprellen durch eine 0,2 Sekunden lange Pause überbrückt und geprüft, ob der Tasters nach mehr als 2 Sekunden noch immer gedrückt ist. Ist dies der Fall, wird (über das Skript robot.sh) ein Shutdown ausgelöst. Andernfalls wird der Roboter gestartet oder gestoppt – je nach Ausgangszustand (dazu wird das Skript robot.sh mit dem Argument toggle aufgerufen). Dann wird der Interrupt zurückgesetzt (siehe Anmerkungen) und der GPIO-Pin reinitialisiert. Das Skript geht wieder in den Schlafzustand über und wartet auf den nächsten Interrupt.

Das Skript wird nach dem Booten in /etc/rc.local als Daemon in den Hintergrund gestartet:

/home/pi/robot/button.py <&- >/dev/null 2>&1 &

Ansteuerung der Status-LED

led0 – Ansteuerung der Status-LED

Die Steuerung der im Raspberry Pi bereits vorhandenen grünen Status-LED (die normalerweise beim Zugriff auf die SD-Karte flackert) erfolgt mit dem oben stehenden, als root auszuführenden Bash-Skript „led0“ über das virtuelle sysfs-Filesystem. Die LED wird im PiBot-A für die Anzeige folgender Betriebszustände genutzt:

LED-AnzeigeBedeutung
unregelmäßiges FlackernStandard-Verhalten beim Booten
1-Hertz-BlinkenKontakt zu WLAN-Router hergestellt
2-Hertz-BlinkenBetrieb als WLAN-Access-Point
an (alle 2 Sekunden kurz aus)Roboter „ein“
aus (alle 2 Sekunden kurz an)Roboter „aus“
10-Hertz-FlackernShutdown im Gange

Anzeige der Status-LED

Bezüglich der Kommandozeilen-Optionen siehe Usage-Meldung im Code.

Liste der Komponenten

Roboter-Basis

Komponente Produkt Hersteller Händler
Raspberry Pi Raspberry Pi Model A+ Raspberry Pi Watterott
Motorsteuerung DRV8835 for Raspberry Pi B+ Pololu Exp-Tech
5V-Spannungsregler Pololu S7V7F5 Pololu Exp-Tech
Ein-/Ausschalter Schiebeschalter 1 x Ein/Ein unbekannt Conrad
Start-/Stopp-Taster Drucktaster 24 V/DC 0.05 A T604 unbekannt Conrad
Roboter-Chassis Acryl-Platten Nordic Panel Nordic Panel
Abstandsbolzen 15 mm Gewinde M3 innen/innen Schäfer Conrad
Abstandsbolzen 15 mm Gewinde M3 innen/außen Schäfer Conrad
Batteriehalter Batteriehalter L für 4 Micro Wentronic Conrad
Motoren 100:1 Micro Metal Gearmotor Pololu Lipoly
Motorhalterung Micro Metal Gearmotor Bracket Pololu Exp-Tech
Räder Pololu Wheel 32x7mm Pololu Exp-Tech
Gleitkugeln Ball Caster with 1/2" Plastic Ball Pololu Exp-Tech
WLAN-Adapter Edimax EW-7811Un Edimax Amazon

Komponenten für die Roboter-Basis

Modus: Obstacle Avoider

Sensoren

Abnehmbarer Träger mit den Sensoren für die Hinderniserkennung

Als Sensoren für die Hinderniserkennung (Obstacle detection) verwende ich drei Infrarot-Distanzsensoren von Sharp, die Pololu auf kleinen Platinchen, fertig beschaltet mit einigen passiven Bauteilen, anbietet. Diese „Carrier“ haben drei Anschlüsse (Versorgungsspannung, Masse und Digitalausgang), über die sie direkt mit dem Sensor-Konnektor (3,3 Volt, Masse und GPIO-Input) des Roboters verbunden werden können. Ein kleiner Elko (Tantalperle, 33 µF) parallel zur Versorgungsspannung der Sensoren fängt von diesen erzeugte Spannungsspitzen ab.

Es gibt diese Sensoren in unterschiedlichen Varianten; ich verwende den Typ, der auf Hindernisse ab einem Abstand von 5 cm und darunter reagiert, für die beiden äußeren Sensoren, und den Typ ab 10 cm für den mittleren – das hat sich in meinen Experimenten bewährt (siehe Liste der Komponenten weiter unten). Die beiden äußeren Sensoren sind in einem Winkel von etwa 45° schräg nach vorn und außen gerichtet, der mittlere geradeaus nach vorn.

Um mit den unterschiedlichen Sensortypen experimentieren zu können, habe ich diese nicht fest verbaut, sondern mit 3-poligen Stiftleisten versehen. Als Träger für die Sensoren dient eine kleine Platine, die hinten die 8-polige Stiftleiste für den Sensor-Konnektor hat und am unteren Rand drei je 3-polige Buchsen für das Anstecken der Sensoren, die dann am oberen Rand des Trägers mit M2-Schräubchen fixiert werden. Der Träger stützt sich oben und unten jeweils mit einem angeklebten Kunststoffprofil am Roboter-Chassis ab – insgesamt ergibt sich so eine recht stabile Konstruktion. (Diese sah aber nach meiner dilettantischen Kleberei und Löterei so grauenhaft aus, dass ich den Murks mit Flüssigkunststoff kaschiert habe.)

Software

robot-oa.py – Skript für den Obstacle Avoider

Die Software ist – so wie ich sie hier veröffentliche – mehr als Proof of Concept zu verstehen; sie implementiert das Minimum der Funktionalität, die man meines Erachtens braucht, um Hindernisse erkennen und ihnen ausweichen zu können. Das Video oben entstand mit dieser Minimalversion, ich experimentiere derzeit mit aufwändigeren Varianten.

In der Hauptschleife, die 10 Mal pro Sekunde durchlaufen wird, werden zunächst die Sensoren abgefragt (diese liefern bei Hinderniserkennung ein Low). Anschließend wird die Reaktion auf diesen Input festgelegt:

  • Wenn beide äußeren Sensoren ein Signal liefern, dann befindet sich unmittelbar vor dem Roboter ein Hindernis. Er wird dann etwa 10 cm zurück fahren, eine kleine Linksdrehung ausführen und dann wieder vorwärts fahren.
  • Wenn der mittlere Sensor ein Hindernis erkennt (in etwa 10 cm Entfernung voraus), wird der Roboter eine Linkskurve ausführen und sich in der Regel dem Hindernis dabei mit der rechten Flanke weiter nähern.
  • Sobald einer der äußeren Sensoren ein seitliches Hindernis meldet, weicht der Roboter diesem mit einer Korrekturbewegung in die entgegengesetzte Richtung aus.
  • Wenn keiner der Sensoren anschlägt, fährt der Roboter geradeaus.

Mit dieser sehr einfachen Software kann der Roboter mit ein bisschen Glück minutenlang umherfahren, ohne irgendwo anzustoßen; er hat aber einen Linksdrall, und er wird immer mal wieder irgendwo hängen bleiben.

Komponenten

Komponente Produkt Hersteller Händler
Sensoren außen Digital Distance Sensor 5 cm Pololu Exp-Tech
Sensor Mitte Digital Distance Sensor 10 cm Pololu Exp-Tech

Sensoren für die Hinderniserkennung

Modus: Line Follower

Sensoren

Abnehmbarer Träger mit den Sensoren für die Linienverfolgung

Als Sensoren für die Linienverfolgung verwende ich das Dreifach-Array „QTR-3A Reflectance Sensor Array“ von Pololu. Ich habe es an einen Träger montiert, der auf die Sensor-Buchsenleiste an der Roboterfront aufgesteckt werden kann; die drei Infrarot-Reflex-Sensoren schweben dann im empfohlenen Abstand von etwa 3 mm über dem Boden. Damit die winzigen SMD-Bauteile nicht durch Bodenberührung Schaden nehmen können, habe ich in die Bohrlöcher der Platine kleine Plastikschräubchen eingeschraubt, deren Köpfe etwas weiter herausstehen als die Bauteile auf der Platine. Durch die nach unten gerichtete Steckverbindung kann die Sensorplatine in der Höhe exakt justiert werden.

Dass diese Sensoren einwandfrei funktionieren (und das tun sie), ist nicht ganz selbstverständlich, denn

  • sie haben Analog-Ausgänge, mit denen sie direkt auf die digitalen GPIO-Eingänge geschaltet sind (was wegen der Flankensteilheit des Analogsignals aber kein Problem ist),
  • sie werden mit nur 3,3 Volt Versorgungsspannung statt mit den empfohlenen 5 Volt betrieben, und
  • sie sind geometrisch für die in USA üblichen 19 mm Tapes optimiert (ich verwende das hier handelsübliche Isolierband von 15 mm Breite).

Linienkurs

Line follower course

Kurs für den Line Follower

Den Kurs für den Line Follower habe ich aus schwarzen PVC-Isolierband von 15 mm Breite auf weißen Bastelkarton geklebt. Dieser Kurs enthält einige Herausforderungen (siehe Bild), denen sich meine Software zu stellen hatte.

Software

robot-lf.py – Skript für den Line Follower

Das Python-Skript robot-lf.py implementiert die für die Bewältigung des oben abgebildeten Linienkurses benötigten Fahrmanöver, lediglich spitze Winkel (kleiner 90°) sind damit nicht zu befahren.

  • Zu Beginn kann der Roboter außerhalb der schwarzen Linie gestartet werden, er fährt dann solange geradeaus, bis er erstmals Linienberührung hat. Danach akzeptiert er einen Verlust des Kontaktes zur schwarzen Linie nur noch unter bestimmten Bedingungen (siehe unten).
  • Wenn er mit einem der äußeren Sensoren auf die Linie gerät, korrigiert er durch eine Kurvenfahrt in entgegengesetzter Richtung. Sollte er dabei aus der Kurve geraten, verringert er den Radius der korrigierenden Kurve so stark, dass das innere Rad rückwärts angetrieben wird. (Währenddessen geht der Kontakt zur schwarzen Linie natürlich kurzzeitig verloren.) Auf diese Weise können beliebig enge Kurven und Winkel von 90° sicher befahren werden.
  • Sollte außerhalb einer solchen Kurvenfahrt der Kontakt zur schwarzen Linie verloren gehen, wird dies für die Dauer einer halben Sekunde akzeptiert und in unveränderter Richtung weiter gefahren, so dass Lücken bis zu einer Länge von etwa 5 cm überbrückt werden können. (Auch die „Weichen“ funktionieren so.) Wird die Linie nicht spätestens nach einer halben Sekunde wiedergefunden, erfolgt ein Nothalt.
  • Wenn alle drei Sensoren länger als eine Zehntelsekunde „schwarz“ signalisieren, befindet sich der Roboter auf der schwarzen Scheibe, und er führt eine 180°-Drehung auf der Stelle aus.

Komponenten

Komponente Produkt Hersteller Händler
Linienverfolgung QTR-3A Reflectance Sensor Array Pololu Exp-Tech

Sensor für die Linienverfolgung

Modus: Maze Solver

Sensoren

Das Labyrinth für den Maze Solver habe ich – genauso wie den Kurs für den Linienfolger – mit schwarzen Linien auf weißem Grund realisiert, auch hier werden also Liniensensoren benötigt. Üblicherweise werden für solche Labyrinthe Arrays mit fünf oder mehr Sensoren eingesetzt; die mittleren zwei oder drei dienen dann (wie beim Linienfolger) dem Spurhalten auf der Linie, die zusätzlichen äußeren Sensoren können unabhängig davon sehr einfach erkennen, ob an einem Knoten des Labyrinthes nach links und/oder rechts eine Linie abgeht.

Ich hatte mir allerdings in den Kopf gesetzt, auch den Maze Solver mit den vom Linienfolger bereits vorhandenen drei Sensoren zu realisieren. Hierzu ist an jedem Knoten des Labyrinthes ein etwas aufwändigeres Manöver erforderlich:

Die drei Sensoren am Labyrinth-Knoten

Die Bewegung der drei Sensoren am Labyrinth-Knoten

  1. Der Roboter nähert sich (im Bild von unten) dem Knoten, der mittlere Sensor befindet sich über der Linie.
  2. Der rechte Sensor erfasst die nach rechts abgehende Linie, der Roboter glaubt jedoch, er sei zu weit nach links geraten, und korrigiert nach rechts.
  3. Als Resultat dieser Korrekturbewegung stehen nun alle drei Sensoren auf „schwarz“; der Roboter erkennt daran, dass er auf einem Knoten angekommen ist. Da er (als Folge der Rechts-Korrektur) rechts von der Mitte steht, bedeutet nun „schwarz“ unter dem rechten Sensor, dass hier eine Linie nach rechts abgehen muss.
  4. Er schwenkt nun nach links aus, um mit dem linken Sensor eine u. U. nach links abgehende Linie zu erkennen (im Beispiel ist hier keine).
  5. Er korrigiert seine Ausrichtung mit einer kleinen Rechtsdrehung und steht nun wieder annähernd parallel zur Linie.
  6. Der Roboter fährt ein Stück geradeaus nach vorn, bis der Knoten unter seiner Achse liegt; er steht nun mit seiner vertikalen Drehachse genau über dem Knoten. Hier erfasst er, ob es hinter dem Knoten eine weiterführende Linie gibt (das ist hier der Fall).

Aus den so gewonnenen Informationen kann der Roboter schließen, um welchen Typ es sich bei dem aktuellen Knoten handelt (im Beispiel: T-Abzweigung nach rechts), und die als Nächstes folgende Bewegung berechnen (geradeaus weiter oder 90°-Drehung nach links oder rechts zum Abzweigen). Die kurzen Schwenks an jedem Knoten kann man in den Videos gut erkennen.

Sackgassen (Dead Ends) werden dagegen unmittelbar erkannt (alle Sensoren „weiß“) und der Roboter kann sofort – als einzig mögliche Reaktion – eine 180°-Kehre einleiten.

Timing

Da der Roboter nicht über Sensoren (z. B. an den Rädern) verfügt, die die zurückgelegte Wegstrecke messen könnten, kann eine definierte Strecke nur dadurch gefahren werden, dass die Dauer dieser Fahrt festgelegt wird – und diese liegt im Hundertstel-Sekunden-Bereich. Das Timing ist hier (insbesondere bei den Schritten 2 – 4) ziemlich kritisch, denn es macht einen erheblichen Unterschied aus, ob der Roboter einige Hundertstel-Sekunden mit voll geladenen oder bereits halb entladenen Akkus fährt.

Ich habe daher eine Kalibrierung implementiert: Zu Beginn jeder Labyrinth-Fahrt führt der Roboter auf einem Stück gerader Strecke zwei entgegengesetzte 360°-Drehungen aus und misst und mittelt die dafür benötigte Zeit. Der so ermittelte Wert geht als Faktor in die Zeitparameter ein, die den Roboter das jeweils benötigte Stück Wegstrecke fahren lassen.

Maze Solver beim Auflösen des Labyrinthes, andere Ausgangs- und Zielpositionen

Regeln und Strategie

Im Labyrinth wird an beliebiger Stelle eine schwarze Scheibe platziert, diese stellt das Ziel dar. Dann wird der Roboter an beliebiger Stelle auf ein gerades Wegstück gestellt und gestartet. Er beginnt mit der oben erwähnten Kalibrierung und sucht dann nach der Linke-Hand-Regel das Ziel. (In einem „einfach zusammenhängenden“ Labyrinth – also einem ohne Schleifen – ist garantiert, dass das Ziel so gefunden wird.) An der schwarzen Scheibe angekommen berechnet er mit einem Verfahren, das der Methode Dead End Filling ähnlich ist, den kürzesten Weg zurück zum Ausgangspunkt und folgt diesem. Am Ausgangspunkt angekommen macht er als Zeichen der Freude über diesen Erfolg eine kurze Hin- und Herbewegung, die an ein Kopfnicken erinnern soll (siehe Videos).

Software

robot-ms.py – Skript für den Maze Solver

Das Python-Skript „robot-ms.py“ implementiert die oben angedeuteten Funktionen, es ist deutlich aufwändiger als die Skripte für Obstacle Avoider und Line Follower.

Anmerkungen

  • Die Akkus versorgen den Raspberry Pi einige Stunden lang mit Strom. Die Ausgangsspannung am 5-Volt-Spannungsregler bricht irgendwann zusammen, ein Shutdown ist dann nicht mehr möglich. Bei den neuen Raspberry-Pi-Modellen wird die rote LED von einem Schaltkreis für die Spannungsüberwachung angesteuert (siehe hier) und erlischt, wenn die Betriebsspannung einen Wert von etwa 4,65 Volt unterschreitet. Es kann also Sinn machen, die rote LED im Auge zu behalten.
  • Bei meinem mit Noobs v1.3.9 (Juli 2014) frisch installierten Raspberry Pi Model A+ (merkwürdigerweise nicht bei Model B+) zeigte die grüne Status-LED anfänglich nicht das erwartete Verhalten (Flackern beim SD-Card-Zugriff), sondern ging (und blieb) nach zweimaligem Blinken aus; auch ließ sie sich nicht über Sysfs oder RPI.GPIO ansteuern. Nach Update/Upgrade funktionierte sie dann wie gewohnt.
  • Mein auf einem Model B+ mit älterem Raspbian lauffähiges Python-Skript für einen Shutdown-Taster via Interrupt funktionierte erst, nachdem ich nach jedem Interrupt ein GPIO.cleanup() ausführe. Ich vermute, dass der Interrupt auf diese Weise zurückgesetzt werden muss.
  • Ich hatte ursprünglich GPIO 16 (GPIO-Header Pin 36) an Pin 3 meines Sensor-Konnektors gelegt, ohne ihn aber zuvor getestet zu haben. Erst danach stellte sich heraus, dass sich dieser Pin nicht als Input verwenden lässt. (Wie ich inzwischen glaube, wegen veralteter Firmware, in der GPIO 16 noch mit der grünen LED gekoppelt ist.) Inzwischen habe ich statt dessen GPIO 24 an den Sensor-Konnektor angeschlossen.

Download

  1. Lade diesen Tarball herunter (Version 2015-06-06).
  2. Entpacke den Tarball mit: tar xzf <Tarball>.
  3. Verfahre gemäß der im Tarball enthaltenen Datei README.txt.

© 2015 – Thomas Schochwww.retas.de

Valid HTML 4.01 Transitional