Füttern Sie Ihren Mindstorms-Robot per Bluetooth mit Programmen und schicken Sie ihn auf Ballsuche durchs Labyrinth.
Linux-Anwender haben es oft schwer, wenn sie Hardware kaufen, für die es nur Windows-Treiber gibt. Dieses Problem betrifft teilweise auch den Mindstorms-Roboter von Lego: Mangels grafischem Tool müssen Linux-Benutzer hier auf die Kommandozeile ausweichen und Ihre Programme per NXT-Manager auf den Lego-Roboter hochladen.
NXT-Manager
Mit dem NXT-Manager verwalten Sie von einem Linux-Client aus die Dateien des NXT-Roboters. Der Vorteil des NXT-Managers gegenüber bereits bestehenden Linux-Lösungen besteht darin, dass er die Programmdaten per Bluetooth an den Lego-Roboter überträgt. Bisherige Open-Source-Projekte benutzten dazu den USB-Port. Das hat den großen Nachteil, dass man den NXT immer wieder mit dem PC verbinden muss, auch wenn man nur kleine Änderungen an der Software vollziehen will.
Als Ausweg aus diesem Problem entstand das unter der GPL stehende Programm NXT-Manager, welches die Dateien per Bluetooth verwaltet. Beim NXT-Manager handelt es sich um ein Konsolenprogramm ohne grafische Oberfläche. Es ist komplett in Perl programmiert, da es für Perl eine extra für den NXT entwickelte Library (LEGO::NXT) gibt.
Um die Entwickler von Software für den NXT zu unterstützen, hat Lego einige Dokumentation in From von Developer-Kits auf der Mindstorms-Webseite [1] zur Verfügung gestellt. Unter anderem findet man dort ein Bluetooth-Developer-Kit, das zahlreiche Informationen zum verwendeten Protokoll bietet.
Verbindungsaufnahme
Den NXT-Manager, der selbst keine Installation benötigt, finden Sie auf der Heft-CD oder auf der Entwicklerseite [2]. Die Redaktion testete ihn unter Ubuntu 7.04 und Open Suse 10.2, er sollte aber auf jeder Linux-Distribution mit aktuellen Bluetooth-Paketen funktionieren.
Der NXT-Manager benötigt die Perl-Bibliothek Net::Bluetooth. Am einfachsten installieren Sie diese mit cpan:
$ cpan Net::Bluetooth
Einige Distributionen bringen auch fertige Pakete mit. Auf Systemen, die auf Debian basieren, benötigen Sie zur Installation des Net::Bluetooth-Moduls zusätzlich das Paket libbluetooth2-dev.
Nun legen Sie in Ihrem Home-Verzeichnis den Ordner NXT an und packen den NXT-Manager dort aus. Der Name des Hauptverzeichnisses ist im Programm fest eingestellt, Sie können also keinen beliebigen Verzeichnisnamen nutzen. Um den NXT-Manager trotzdem von einem beliebigen Verzeichnis aus zu starten, legen Sie einen symbolischen Link auf das Perl-Programm an:
$ sudo ln -s ~/NXT/nxtmanager/nxtmanager /usr/bin/nxtmanager
Beim Starten des NXT-Manager übergeben Sie als Option die MAC-Adresse des Mindstorms-Roboters. Die ermitteln sie beispielsweise über den Befehl hcitool:
$ hcitool scan Scanning … 00:16:53:03:A1:3C NXT
Um die Adresse nicht bei jedem Start von Hand eintippen zu müssen, tragen Sie sie am besten in die Datei ~.nxtmanager/address ein. Alternativ bleibt der Aufruf nxtmanager 00:16:53:03:A1:3C.
Beim ersten Start des NXT-Managers müssen Sie den Roboter mit Ihrem Bluetooth-Dongle koppeln (“Pairing”). Unter KDE startet dazu automatisch die Passwort-Eingabe des KDE-Bluetooth-Frameworks. Alternativ führen beim ersten Start des NXT in einer weiteren Konsolensitzung den Befehl sudo passkey_agent --default /usr/bin/bluez-pin aus. In beiden Fällen müssen Sie nun zuerst auf dem NXT den Pin 1234 bestätigen und den gleichen anschließend auf dem PC eingeben. Danach sind der NXT und der Computer gekoppelt und können miteinander kommunizieren.
Erstkontakt
Der NXT-Manager bietet ihnen quasi eine Shell zum Lego-Roboter (Abbildung 1). Der Befehl ls listet alle Programmdateien des NXT auf. Um sämtliche Dateien (inklusive Systemdateien) angezeigt zu bekommen, geben Sie ls -a ein.

info-Befehl können Sie ignorieren.” width=”300″ height=”245″ />
Abbildung 1: Der NXT-Manager in Aktion. Die Fehlermeldung beiminfo-Befehl können Sie ignorieren. Mit dem Befehl setname Name ändern Sie den Devicename des NXT. Über info erhalten Sie allgemeine Informationen, wie die Firmware-Version und den Batteriestand. Die drei Fehlermeldungen beim Info-Aufruf können Sie ignorieren: Der Autor hofft, diese in naher Zukunft zu eliminieren.
Um eine Datei auf dem NXT zu löschen, rufen Sie rm Datei auf. Dabei müssen Sie stets die Dateiendung mit angeben, beispielsweise rm muster.rxe. Achten Sie darauf, nicht versehentlich Systemdateien zu löschen.
Das Kommando u Datei lädt Dateien auf den NXT hoch. Gibt es die Datei schon auf dem NXT, fragt der NXT-Manager nach, ob Sie diese überschreiben möchten. Der Befehl quit beendet den NXT-Manager.
Softwareentwicklung
Möchten Sie selbst Software für den NXT erstellen, besorgen Sie sich zuerst einmal den aktuellen Compiler nbc von der Entwicklerseite [4] und machen sich dann mit der Programmiersprache NXC vertraut (siehe Kasten “Die Sprache NXC”).
Den Compiler extrahieren Sie in ein beliebiges Verzeichnis (zum Beispiel ~/NXT/nbc). Um das Tool von jedem Ordner aus aufrufen zu können, empfiehlt es sich, mit sudo ln -s ~/NXT/nbc/nbc /usr/bin/nbc eine symbolische Verknüpfung nach /usr/bin zu erstellen.
Für Ihr erstes Programm benötigen Sie nur einen Texteditor. Achten Sie darauf, die Programmdatei mit der Endung .nxc abzuspeichern. Um das erstellte Programm zu kompilieren, geben Sie im Verzeichnis der Programmdatei folgenden Befehl ein:
$ nbc -T=NXT -O=File.rxe File.nxc
Für File setzen Sie den gewünschten Dateinamen ein. Das fertige Binary heißt dann File.rxe. Sie übertragen es nach dem Kompilieren mit dem NXT-Manager auf den Lego-Roboter.
Die Sprache NXC
Zur Steuerung der Mindstorms-Roboter kommt unter Linux die C-ähnliche Programmiersprache NXC zum Einsatz. Die Abkürzung steht für Not eXactly C. In NXC geschriebene Programme arbeiten mit der Standard-Firmware des Lego-Roboters zusammen, ein Update ist nicht nötig.
Im Unterschied zu dem für Windows erhältlichen NXT-G braucht man bei dieser Programmiersprache kein grafisches Werkzeug, sondern arbeitet in einem Texteditor. Das hat den Vorteil, dass man die Software auf jedem Betriebssystem erstellen kann. Das Verhältnis von NXT-G zu NXC entspricht also ungefähr dem von Visual Basic zu Basic.
Wie die meisten alternativen Programmiersprachen für den NXT befindet sich auch NXC noch im Entwicklungsstadium. Es kommen immer wieder neue Funktionen dazu, die enthaltenen arbeiten aber sehr stabil und genügen für die meisten Einsatzzwecke.
Linienverfolger
Einem Roboter beizubringen, einer schwarzen Linie zu folgen, ist eine einfache Aufgabe mit gutem Lerneffekt. Es bietet sich deshalb als Einstieg in die Programmierung von Robotern abb.
Der Roboter fährt, solange er sich auf der Linie befindet, geradeaus. Sobald er die Linie verlässt, versucht er, sie wieder zu finden. Da er nicht wissen kann, nach welcher Seite er die schwarze Linie verlassen hat, muss er in beide Richtungen suchen. Am leichtesten findet er die Linie wieder, indem er abwechselnd in die verschiedenen Richtungen dreht und dabei den maximalen Drehwinkel immer mehr zu erhöht. Dies tut der Roboter so lange, bis er die schwarze Linie wieder gefunden hat. Findet er die Linie, fährt er erneut geradeaus, bis er die Linie wieder verlässt. Die Umsetzung dieses Verfahrens in ein NXC-Programm finden Sie in Listing 1.
Der Start der Software ruft den main-Task auf (Zeile 14). Die while-Schleife ab Zeile 18 sorgt dafür, dass dieser laufend wiederholt wird. Vor dieser Endlosschleife müssen noch drei Befehle im Programm enthalten sein, die nur einmal ausgeführt werden sollen: Man muss den Lichtsensor starten, den Startwert für die maximale Drehzahl setzen und den Startwert der Variable state setzen, auf die der Artikel unten noch genauer eingeht.
Alle anderen Befehle soll der Roboter endlos wiederholen. Als erstes liest das Programm zwei Sensoren aus (Zeile 19 und 20) und speichert die Werte in den Variablen light und rot_c, die das Programm in Zeile 8 definiert hat.
Der Roboter kann sich in drei verschiedenen Zuständen befinden (DRIVE, TURN_LEFT, TURN_RIGHT). Deshalb ist es sinnvoll, die Software statusbasierend aufzubauen: In einem Zustand soll der Roboter einfach nur geradeaus fahren und in den anderen zwei Zuständen soll er sich entweder nach links oder nach rechts drehen. Dazu dient der switch-Aufruf, der je nach dem Wert der Variable state andere Befehle ausführt. Verschiedene Konstanten für die einzelnen Zustände halten den Quelltext übersichtlicher. Diese Konstanten – jede mit einem eindeutigen Wert – finden sich im Definitionskopf ganz am Anfang des Programms.
Startet das Programm zum ersten Mal, so befindet sich der Roboter im Status DRIVE (Zeile 17). Zuerst gilt es – für den Fall, dass der Robot gerade die Linie wieder gefunden hat – den maximalen Drehwert zurückzusetzen. Der Befehl in Zeile 24 lässt den Roboter mit der in der Konstante GESCHW definierten Geschwindigkeit geradeaus fahren. Die if-Abfrage in Zeile 32 überprüft, ob der Lichtsensor einen Helligkeitswert über dem in LIGHT definierten Grenzwert gemessen hat. Ist das der Fall, befindet sich der Roboter nicht mehr auf der Linie – und wechselt durch das Ändern der Variable state den Status zu TURN_LEFT.
Nun dreht sich der Roboter nach links. Mit den ersten zwei Befehlen dieses Zustandes, dreht der Roboter den linken Motor rückwärts und den rechten Motor vorwärts – so wendet er ähnlich wie ein Kettenfahrzeug auf der Stelle nach links. Liegt anschließend der Helligkeitswert wieder unter den Grenzwert, dann hat der Roboter die Linie erneut gefunden. Er wechselt zurück in den Status DRIVE und setzt den Rotationssensor zurück, damit er im DRIVE-Status mit beiden Motoren synchron geradeaus fahren kann. Liegt der Helligkeitswert dagegen nicht unter dem Grenzwert, erfolgt eine weitere Abfrage, ob der Rotationssensor den maximalen Drehwert überschritten hat. Ist das der Fall, so erhöht sich der in turn gespeicherte Drehwert. Anschließend wechselt der Status zu TURN_RIGHT und der Rotationssensor wird zurück gesetzt, damit es bei der Drehwertkontrolle in die andere Richtung keine Probleme gibt (Zeilen 38 und 39).
Im Status TURN_RIGHT verhält sich der Roboter sinngemäß gleich wie bei TURN_LEFT – mit der Ausnahme, dass er sich nach rechts dreht,.
#define DRIVE 0
#define TURN_RIGHT 1
#define TURN_LEFT 2
#define GESCHW 30
#define LIGHT 40
#define TURN 10
int state, light, rot_c, turn;
sub dreherweiterung() {
turn = turn+2*TURN;
}
task main() {
SetSensorLight(IN_1);
turn = TURN;
state = DRIVE;
while(true) {
light = Sensor(IN_1);
rot_c = MotorRotationCount(OUT_C);
switch(state) {
case DRIVE:
turn = TURN;
OnFwdReg(OUT_BC, GESCHW, 1);
if(light > LIGHT) {
state = TURN_LEFT;
}
break;
case TURN_LEFT:
OnFwd(OUT_B,GESCHW);
OnRev(OUT_C,GESCHW);
if(light < LIGHT) {
state = DRIVE;
ResetRotationCount(OUT_BC);
}
else if(rot_c <= -turn) {
dreherweiterung();
state = TURN_RIGHT;
ResetRotationCount(OUT_BC);
}
break;
case TURN_RIGHT:
OnFwd(OUT_C,GESCHW);
OnRev(OUT_B,GESCHW);
if(light < LIGHT) {
state = DRIVE;
ResetRotationCount(OUT_BC);
}
else if(rot_c >= turn) {
dreherweiterung();
state = TURN_LEFT;
ResetRotationCount(OUT_BC);
}
break;
}
}
}
Noch mehr
Die geschilderte Aufgabe lässt sich beliebig erweitern – etwa durch ein Szenario, bei dem der Roboter zunächst ebenfalls der schwarzen Line folgen, dann aber ein Labyrinth durchqueren und einen Ball einsammeln muss (Abbildung 2).
Der Roboter besitzt einen Lichtsensor zum Messen des Helligkeitswerts des Bodens, einen Ultraschallsensor, um die Entfernung zu Objekten messen zu können, sowie einen Geräuschsensor, der Laute wahrnimmt. Außerdem verfügt der Roboter über drei Motoren. Zwei davon benutzt er wie bei dem Linienverfolger für die Fortbewegung, der dritte kommt für den Greifmechanismus zum Einsatz.
Der Roboter verfolgt zuerst die schwarze Linie – dieser Abschnitt funktioniert wie schon beschrieben. Sobald der Roboter ein Objekt in der Nahe wahrnimmt (Abbildung 3), weiß er, dass er sich in einem Labyrinth befindet. Dieses durchfährt er dann, indem er sich zuerst nach rechts dreht und dabei misst, ob in näherer Entfernung eine Wand vor ihm befindet. Ist das nicht der Fall ist, dreht er sich noch ein bisschen weiter (weil sich der Ultraschallsensor in der Mitte befindet) und fährt dann los.

Abbildung 3: Der Roboter kommt am Anfang des Labyrinths an und erkennt die Wand, die sich vor ihm befindet.
Anderenfalls dreht er bis zu einem Winkel von 90 Grad. Hat er dann immer noch keinen Weg gefunden, dreht er in die andere Richtung. Nimmt der Lichtsensor eine schwarze Linie wahr und der Ultraschallsensor signalisiert, dass es sich um diejenige handelt, die zum Ball führt, dreht sich der Roboter in deren Richtung und verfolgt die Linie, bis er sich in der Nähe des Balls befindet. Nun fährt er zum Ball und greift diesen. Anschließend dreht er sich in die andere Richtung und verfolgt die Linie bis zur grünen Fläche, ohne sich von der Abzweigung (Abbildung 4) irritieren zu lassen. Ist der Roboter dort angekommen, stoppt der Anwender ihn durch ein Klatschen.
Den kompletten, kommentierten Quelltext für das zweite Szenario finden Sie auf der Heft-CD. Dort sind alle im Quelltext verwendeten Befehle beschrieben. Außerdem befindet sich auf der CD ein Video des Roboters beim Absolvieren der Aufgabe. Weitere Informationen zur Programmierung mit NXC finden Sie auf der Homepage des Autors [5].
[1] Developer Kits: http://mindstorms.lego.com/overview/NXTreme.aspx
[2] NXT-Manager Entwicklerseite: http://lukas.internet-freaks.net/nxtmanager.php
[3] LEGO::NXT: http://nxt.ivorycity.com
[4] NXC: http://bricxcc.sourceforge.net/nbc
[5] Tutorial: http://lukas.internet-freaks.net/nxt.php
[6] IT-Seminar Lörrach: http://it-seminar-loerrach.de
[] Lukas Probst ist 17 Jahre alt und studiert am Hans-Thoma-Gymnasium in Lörrach. Seine ersten Erfahrungen mit der Programmierung von Robotern sammelte er am IT-Seminar-Lörrach.







