NXT-Tutorial
Einleitung
Was ist das hier?
Diese Seite ist ein Tutorial zum NXT, das sich mit der Programmierung von Software mit NXC unter Linux beschäftigt.
Was ist ein NXT?
Ein NXT ist die neuste Version der Lego Mindstorms Roboterreihe. Diese Roboter kann man selber zusammenbauen und anschließend nach den eigenen Wünschen programmieren. Standardmäßig liefert Lego eine grafische Oberfläche zum Erstellen der Programme. Diese ist einfach zu verstehen und ist daher von jedem ohne Probleme nutzbar. Diese Oberfläche wird hier jedoch nicht behandelt.
Beim Kauf enthalten ist der programmierbare Stein, 3 Motoren (mit eingebauten Drehsensoren), ein Lichtsensor (Helligkeit), ein Geräuschsensor, ein Tastsensor und ein Infratorsensor (Abstand). Außerdem enthalten sind alle nötigen Kabel, sowie viele Teile zum bauen der Roboter (Teile ähnlich wie Lego Technik).
Was ist NXC?
NXC ist eine weitere Möglichkeit die Roboter zu programmieren. NXC steht für "Not eXactly C". Es handelt sich um eine Programmiersprache die sich an C orientiert. NXC wird als Plain Text programmiert. Das bedeutet man sieht beim Programmieren erstmal nur Text. Dadurch erhält man mehr Möglichkeiten der Programmierung. NXC benötigt keine andere Firmware. NXC-Dateien kann man in jedem Editor erstellen. Anschließend werden sie dann kompiliert und auf den Roboter transferiert. Näheres dazu später.
Ist eine Programmierung unter Linux möglich?
Ja. Die grafische Oberfläche ist zwar nur unter Windows und OSX möglich, aber NXC kann durchaus auch unter Linux programmiert werden, das es mit jedem Editor funktioniert und es den Compiler auch für Linux gibt.
Voraussetzungen um NXC mit dieser Anleitung programmieren zu können
Um mit dieser Anleitung etwas anfangen zu können, müssen grundlegende Kenntnisse von Programmiersprachen gegeben sein. Ich werde keine Dinge wie Schleifen usw. erklären sondern nur beschreiben wie man die Sensoren, Motoren usw. anspricht.
Anleitung für Linux
Dieses Abschnitt des Tutorials wurde unter Ubuntu/Kubuntu getestet. (Achtung: Der letzte Test ist schon eine Weile her.)
Benötigte Programme
- NBC (Compiler bei dem NXC enthalten ist) (download)
- linxt (Programm zum Überspielen der Software auf den NXT per USB) (download)
- beliebiger Editor (Gedit, Kate, Nano, Bluefish, usw.)
Software erstellen
Die Software wird nun im gewählten Editor geschrieben. Es empfiehlt sich das Synthaxhighlighting von C zu benutzen, da NXC ja sehr ähnlich ist. Wenn man damit fertig ist speichert man die Datei einfach mit der Endung ".nxc".
Das Kompilieren
Zum Kompilieren benötigt man das Programm NBC. Dies lädt man auf der oben verlinkten Seite runter und extrahiert es in ein beliebiger Verzeichnis (z.B.: ~/NXT/nbc). Hat man das getan, empfiehlt es sich mit folgendem Befehl eine Verknüpfung zu erstellen um das Programm einfacher zu erreichen:
sudo ln -s ~/NXT/nbc/nbc /usr/bin/nbc
Nun lässt sich das Programm einfacher erreichen.
Zum Kompilieren benutzt man nun Folgenden Befehl:
nbc -T=NXT -O=file.rxe file.nxc
"file" ist dabei der Dateiname.
Wenn keine Fehlermeldung erscheint, wurde die Software für den NXT richtig programmiert und umgewandelt.
Transferireren per Bluetooth
Wenn man einen Bluetoothstick oder ähnliches hat, kann man mein selbstgeschreibenes Programm namens "NXT-Manager" verwenden um Dateien auf den NXT zu übertragen und noch einiges mehr zu tun. Hier findet ihr eine Anleitung und den Download.
Vorbereitung zum Transferieren per USB (nur einmal erforderlich)
Nun muss man die USB Schnittstelle für linxt verfügbar machen.
Zuerst installiert man die Pakete "libusb-dev" und "libusb-0.1-4" mit folgendem Befehl:
sudo apt-get install libusb-dev libusb-0.1-4
Wenn dies erfolgreich abgeschlossen, ist startet man cpan:
sudo cpan
Sollte man nun mit Fragen bombardiert werden, bestätigt man einfach immer mit Enter bis nur noch "cpan" dasteht und man etwas eingeben kann. Nun führt man die 2 folgenden Befehle aus:
install Inline
install Device::USB
Zum Transferieren der Programme auf den NXT benötigt man das Programm linxt. Dies lädt man auch runter und extrahiert es in ein beliebiges Verzeichnis (z.B.: ~/NXT/linxt). Nun empfiehlt sich es sich weiter eine Verknüpfung zu erstellen:
sudo ln -s ~NXT/linxt/linxt /usr/bin/linxt
Wenn man auch das erfolgreich absolviert hat, ist man zum Transferieren auf den NXT bereit.
Das Transferieren auf den NXT per USB
Jetzt kann man anfangen zu Transferieren. Dies geht mit folgendem Befehl:
sudo linxt -u file.rxe
Nun sind folgende Punkte zu Beachten:
- Der NXT muss an sein und eine USB Verbindung zum PC aufweisen.
- Man muss im Verzeichnis der Datei sein die man transferieren will.
- Es darf keine Software mit gleichem Namen vorhanden sein (vor Aktualisierung im NXT löschen)
Beachtet man diese Punkte sollte man keine Probleme haben.
Nun sollten die Programme auf dem NXT unter Software zu finden sein.
Anleitung für Windows
Benötigte Programme
Die Installation
Sind sowohl Bricxcc sowie die Windowsversion von NBC runter geladen, kann die Installation beginnen.
Zuerst muss man Bricxcc einfach ganz normal installieren.
Ist man damit fertig, muss man das NBC Paket in das Installationsverzeichnis, indem sich auch die Bricxcc.exe befindet, extrahieren.
Nun ist man auch schon fertig mit der Installation und kann zum Erstellen eines Programms Bricxcc starten.
Die Auswahl beim Start von Bricxcc
Beim Start von Bricxcc muss man einige Angaben machen. Man muss die Felder folgendermaßen ausfüllen:
- Port: usb
- BrickType: NXT
- Firmware: Standard
Software erstellen
Die Software erstellt man nun im Bricxcc und speichert sie anschließend als NXC File (*.nxc).
Das Kompilieren
Um die Software zu Kompilieren klickt man einfach auf die beiden Zahnräder in der Symbolleiste oder drückt F5.
Das Transferieren auf den NXT
Hierfür klickt man einfach auf das blaue Dreieck in der Symbolleiste oder drückt F6.
Programmieren des NXT mit NXC
Grundsätze
Ganz oben in jeder Datei musst erstmal die Definitions Datei der APIs eingebunden werden. Das geht mit folgendem Befehl:
#include "NXCDefs.h"
Wichtig: Ab der Version "NBC 1.0.1.b29 beta" muss/darf man diesen Include nicht mehr machen.
Jedes Programm durchläuft, wenn es zu nichts anderes aufgefordert wird, nur den Maintask. Dieser muss in jedem Programm enthalten sein und sieht wie folgt aus:
task main() {
// Hier müssen die Befehle rein
}
Außerdem ist es möglich Unteranwendungen zu erstellen, die mit einem kurzen Befehl ausgeführt werden können. Diese erstellt man folgendermaßen:
sub name() {
// Hier müssen die Befehle rein
}
Das "name" lässt sich dabei frei wählen. Diese Unteranwendung bindet man dann einfach mit
name();
in der Main oder einer weiteren Unteranwendung ein.
Um eine While-Schleife zu erstellen, die solange läuft bis man das Programm auf dem NXT beendet, kann man folgenden Befehl benutzen:
while(true) {
// Hier müssen die Befehle rein
}
Um neue Variablen des Typ int anzulegen benutzt man folgenden Befehl:
int name;
Diese Variable ist jetzt mit "name" abrufbar.
Arrays anzulegen gestaltet sich schon etwas komplizierter:
int name[] = {};
Nun muss man noch die Reihen und den Anfangswert erstellen:
ArrayInit(name, 0, 100); // Erstellt 100 Reihen mit dem Wert 0 für das Array name
Jetzt kann man das Array einfach wie eine Variable mit
name[x];
(x in diesem Fall 0 - 99) abrufen, wobei zu beachten ist, dass ein Array immer bei 0 anfängt zu zählen.
Ausgänge
- OUT_A
- OUT_B
- OUT_C
Die Ausgänge(OUT) werden mit A, B und C durchnummeriert. Diese Ausgänge werden nur für Motoren und deren integrierte Drehsensoren verwendet.
Die Ausgänge können auch miteinander kombiniert werden:
- OUT_AB
- OUT_BC
- OUT_AC
- OUT_ABC
Auf diese Art ist es möglich mehrere Motoren mit der selben Funktion in nur einem Befehl anzusprechen.
Eingänge
- IN_1
- IN_2
- IN_3
- IN_4
Die Eingänge(IN) werden mit 1, 2, 3, 4 durchnummeriert. Diese Eingänge werden für die Sensoren (Licht, Geräusch, Tast, Infrarot) verwendet.
Eine Kombination dieser Eingänge macht keinen Sinn und ist deshalb auch nicht möglich.
Die Motoren
Die Motoren des NXT kann man den Roboter vorwärts und rückwärts fahren lassen, sowie stehen bleiben oder drehen. Der NXT nimmt hierbei Geschwindigkeiten in Prozent (zwischen 0 und 100) an.
Um einfach vorwärts zu Fahren benutzt man folgende Funktionen:
OnFwd(OUT_A, 75); // Dreht Motor A mit 75
OnFwd(OUT_B, 50); // Dreht Motor B mit 50
OnFwd(OUT_BC, 100); // Dreht Motor B und Motor C mit 100
Das Rückwärtsfahren funktioniert fast genau so:
OnRev(OUT_C, 60); // Dreht Motor C mit 60 rückwärts
Um den Motor anzuhalten, benutzt man folgenden Befehl:
Off(OUT_ABC); // Schaltet die Motoren A, B und C aus
Um den Roboter drehen zu lassen muss man nur einen Motor rückwärts und den anderen vorwärts drehen lassen oder den einen langsamer als den anderen drehen lassen.
Um ein 100% gerades Fahren zu ermöglichen gibt es eine Funktion, die die Motoren beim Drehen aufeinander warten lässt: (hier muss man natürlich mindestens 2 Ausgänge angeben)
OnFwdReg(OUT_AB, 30, 1); // Lässt die Motoren A und B mit 30 synchron fahren
OnFwdReg(OUT_ABC, -50, 1); // Lässt die Motoren A, B und C mit 50 synchron rückwärts fahren
Außerdem kann man einen Motor um einen bestimmten Winkel drehen lassen:
RotateMotor(OUT_A, 30, 90); // Dreht Motor A mit 30 um 90°
Dies lässt sich auch auf 2 Motoren synchron anwenden:
RotateMotorEx(OUT_AB, 20, 360, 0, true, false); // Vorwärts mit 20 um 360°
RotateMotorEx(OUT_AB, -20, 360, 0, true, false); // Rückwärts mit -20 um 360°
RotateMotorEx(OUT_AB, 20, 360, 100, true, false); // Motor A rückwärts und B vorwärts
RotateMotorEx(OUT_AB, 20, 360, -100, true, false); // Motor A vorwärts und B rückwärts
Die Drehsensoren
Zuerst einmal ist es wichtig zu wissen, dass man die Drehsensoren nicht, wie beim alten RCX, zusätzlich einbauen muss, sondern dass sie in den Motor integriert sind.
Eine Umdrehung des Motors hat 360°. Um die Umdrehungen eines Motors auszulesen kann man folgenden Befehl verwenden:
Umdrehungen_a = MotorRotationCount(OUT_A); // liest die Umdrehungen vom Motor A aus
Die Variable Umdrehungen_a muss natürlich zuerst erstellt werden.
Außerdem ist darauf zu achten, dass der RotationCounter natürlich auch negative Werte haben kann, wenn der Motor zuvor rückwärts gedreht wurde.
Um die Werte des Umdrehungssensors zurück zu setzen, benutzt man folgenden Befehl:
ResetRoatationCount(OUT_A); // Motor A wird zurück gesetzt
Der Lichtsensor
Der Lichtsensor des NXT erkennt die Helligkeit des Untergrunds. Dadurch sind auch Farben erkennbar. Er misst die Helligkeit im Bereich von 0 bis 100.
Um den Lichtsensor verwenden zu können, muss man ihn erstmal als solchen erkennen:
SetSensorLight(IN_1); // Setzt IN_1 als Lichtsensor
Nun kann man die Werte des Sensors mit folgendem Befehl auslesen:
light = Sensor(IN_1); // liest den Helligkeitswert von IN_1 aus
Die Variable light ist vorher zu erstellen.
Der Soundsensor
Der Soundsensor ist dem Lichtsensor in der Handhabung sehr ähnlich. Auch er misst die Werte zwischen 0 und 100.
Der Soundsensor kann also nur hören, wie laut die Umgebung ist und keine Befehle in Form von Worten verstehen. Allerdings ist ein Erkennen von Klatschen oft hilfreich.
Um ihn als solchen zu definieren, benutzt man folgenden Befehl:
SetSensorSound(IN_4); // Setzt IN_4 als Soundsensor
Um die Werte des Sensors abzurufen,geht man folgendermaßen vor:
sound = Sensor(IN_4); // liest den Soundwert von IN_4 aus
Wie immer ist die Variable sound vorher zu erstellen.
Der Tastsensor
Der Tastsensor des NXT erkennt nur zwischen 2 Zuständen.
- 0 = nicht gedrückt
- 1 = gedrückt
Auch diesen Sensor muss man wieder zuerst als solchen erkennbar machen:
SetSensorTouch(IN_2); // Setzt IN_2 als Tastsensor
Zum Auslesen verwendet mann wieder folgenden Befehl:
tast = Sensor(IN_2); // liest den Wert des Sensors IN_2 aus
Die Variable tast ist natürlich wie immer zu erstellen.
Der Ultraschallsensor
Der Ultraschallsensor des NXT kann Abstände zu einem Gegenstand messen. Er misst diese in inch.
Bei der Benutzung sind folgende Dinge zu beachten:
- Manche Untergründe verfälschen die Werte (Beispiel: Teppich)
- Für sehr kleine Abstände (<10inch) ist er nicht gut geeinget.
- Auf größere Distanz werden kleinere Objekte nicht mehr erfasst (mitgelieferter Ball nur bis maximal 50cm).
Beachtet man diese Punkte kann man den Ultraschallsensor problemlos benutzen.
Um ihn als solchen zu erkennen benutzt man folgende Funktion:
SetSensorLowspeed(IN_3); // Setzt IN_3 als Ultraschallsensor
Der Befehl zum Auslesen sieht diesmal etwas anders aus:
ultra = SensorUS(IN_3); // liest den Wert des Ultraschallsensors in Port 3 aus.
Auch hier ist die Variable ultra vorher zu erstellen.
IR-Seeker
Mit Hilfe des IR-Seekers kann der NXT die Richtung wahrnehmen, aus der eine Infrarotlicht auf den Sensir trifft. Er kann dabei zwischen 9 Richtungen unterscheiden.
Dieser Sensor wird vor Allem für den RoboCup verwendet, bei dem mit einem Infrarotball Roboterfußball gespielt wird.
Um den Sensor benutzen zu können, muss er zunächst als Lowspeed-Sensor definiert werden:
SetSensorLowspeed(IN_4); // Setzt IN_4 als IR-Seeker
Mit folgender Funktion kann der aktuelle Wert abgerufen werden:
ir = SensorHTIRSeekerDir(IN_4); // liest den Wert des IR-Seekers in Port 4 aus.
Die Variable ir ist wieder vorher zu definieren.
Display
Der NXT hat ein schwarz-weißes Display mit der Auflösung 100*64. Dieses kann man vor allem sehr gut zum debuggen oder wenn man einfach mal eine Ausgabe sehen will verwenden.
Den Standort der Ausgaben gibt man mit x und y Koordinaten an (x von links, y von unten). Für die Y Koordinaten kann man auch folgendes benutzen LCD_LINE1, LCD_LINE2, ...
Außerdem gibt es immer die Option "true" oder "false". True bedeutet das immer die ganze Ausgabe gelöscht und wieder neu angelegt wird (erzeugt mitunter Flackern). False bedeutet das nur die geänderten Stellen verändert werden.
Die einfache Textausgabe funktioniert folgendermaßen:
TextOut(0,50,"Hallo"); // Gibt bei x=0 y=50 den Text Hallo aus
TextOut(20,LCD_LINE3,"Test"); // Gibt bei x=20 in der 3.Zeile von oben Test aus
Um eine vorher erstellte Variable oder den Rückgabewert einer Funktion auszugeben, benutzt man folgenden Befehl:
NumOut(0,50,a); // Gibt bei x=0 y=50 die Variable a aus
NumOut(20,LCD_LINE3,Sensor(IN_2)); // Gibt bei x=20 in der 3. Zeile den Sensorwert von IN_2 aus
Um Linien zu erstellen, die man zum Beispiel als Trennnlinien verwenden kann, geht man folgendermaßen vor:
LineOut(10, 100, 50); // Zeichnet eine Linie von x1=0 y1=10 zu x2=100 y2=50
Um einen Kreis zu zeichnen benutzt man folgenden Befehl:
CircleOut(20, LCD_LINE6, 15); // Zeichnet einen Kreis um x=20 in der 6.Zeile mit dem Radius 15
Bluetooth
Der NXT hat die Möglichkeit mit einem weiteren NXT per Bluetooth zu kommunizieren.
Wichtig: Vor dem Programmstart muss manuell über das NXT-Menü eine Verbindung aufgebaut werden, da NXC keine solche Funktion bereitstellt.
Der NXT der die Verbindung aufbaut, ist der sogennante Master. Er kann Verbindung mit bis zu 3 NXTs aufnehmen (Verbindung 1-3). Der NXT mit dem die Verbindung aufgenommen wurde, ist der sogenannte Slave. Er kann über die Verbindung 0 mit dem Master kommunizieren.
Um eine Nachricht abzurufen kann die folgende Funktion verwendet werden:
ReceiveRemoteString(0, true, BT_msg); // hohlt die Nachricht aus Mailbox 0 und speichert sie in "BT_msg"
Der Abrufvorgang funktioniert am Master und am Slave genau gleich.
Um mit dem Slave eine Nachricht an den Master (Verbindung 0) zu senden, kann folgende Funktion verwendet werden:
SendRemoteString(0, 0, "Hello World!"); // sendet die Nachricht "Hello World!" an den Master (Verbindung 0) an die Mailbox 0
Um mit dem Master eine Nachricht zu versenden, muss anstatt der Verbindung 0, die jeweilige Verbindung zum Slave angegeben werden:
SendRemoteString(1, 0, "Hello World!"); // sendet die Nachricht "Hello World!" an den Slave (Verbindung 1) an die Mailbox 0
Auf diese Art ist es möglich zwischen mehreren NXTs zu kommunizieren und so größere Projekte zu verwirklichen. Es sollte jedoch darauf geachtet werden, dass die Bluetoothkommunikation viel Strom verbraucht und die Batterien deshalb schneller entladen werden.
Projekte
Follow the Line (13. Januar 2007)
Das klassische Einstiegs-Projekt.
Der Roboter verfolgt durch Hilfe eines Lichtsensors, der die Helligkeit des Untergrunds misst, die schwarze Linie auf dem Testblatt, welches von Lego mitgeliefert wurde. Das geht natürlich auch auf anderen hellen Flächen mit einer schwarzen Linie. Der Roboter geht dabei folgendermaßen vor:
Solange er auf der schwarzen Linie ist, fährt er ganz normal synchron vorwärts. Sobald er die schwarze Linie verlässt, beginnt er sich in eine Richtung zu drehen. Wenn er nach einer bestimmten Zeit nichts findet, erhöht er den Drehwinkel und dreht und dreht in die andere Richtung. Dies wiederholt er bis er etwas gefunden hat (auf einer komplett weißen Fläche also bis die Batterien leer sind). Wenn er die schwarze Linie wieder gefunden hat merkt er sich in welcher Richtung er die Linie gefunden hat, da er für eine Kurve ja meistens mehr als einmal korrigieren muss. Nun beginnt alles wieder von vorne.
Find the Ball (25. Februar 2007)
Der Roboter findet Bälle im Umkreis von ca. 50cm, sammelt diese ein und erkennt ihre Farbe.
Zu Beginn des Programms muss man zunächst den roten und den blauen Ball unter den Lichtsensor legen und mit dem Tastsensor bestätigen, damit ihre Helligkeitswerte, welche sich je nach Lichtverhältnissen ändern, gespeichert werden. Anschließend beginnt man das eigentliche Programm indem man klatscht oder ein anderes lautes Geräusch erzeugt.
Nun beginnt sich der Roboter gegen den Uhrzeigersinn zu drehen. Dabei überprüft er immer ob er ein Objekt (den Ball) im Sichtfeld hat. Ist dies der Fall, beginnt der Roboter darauf zu zu fahren. Verliert er ihn wieder, beginnt er erneut sich zu drehen. Alle Schritte, egal ob gerade ausfährt oder sich dreht werden in einem Array gespeichert um später wieder zurück fahren zu können. Wenn er kurz vor dem Ball ist schließt er die Zange und prüft die Farbe des Balles.
Nun hat man 5 Sekunden Zeit um zu entscheiden, ob man den Ball will oder nicht. Durch ein Klatschen bestätigt man, dass man den Ball haben will. Will man ihn nicht öffnet er die Zange. Anschließend fährt der Roboter wieder zurück (durch Hilfe des Arrays). Um so glatter der Untergrund um so genauer trifft er den Ausgangspunkt (im Video ist der Untergrund nicht ideal).
Ist am Ausgangspunkt ein Ball vorhanden, wird das Programm beendet. Wenn nicht beginnt alles wieder von vorne, nur wird jetzt in die andere Richtung gedreht. Dies lässt sich beliebig oft wiederholen.
Artikel LinuxUser 09.2007
Link auf die Seite + beschreibung
RoboCup Junior 2008
Link auf die Seite + beschreibung
Abschluss
Danke
... an die Entwickler von NXC und linxt
Ohne diese 2 Programme wäre es für mich unmöglich den NXT per Plaintext zu programmieren. Deshalb vielen dank dann die Entwicklung dieser 2 Programme.
Hilfe
Sollte jemand von euch eine Frage zu dem Tutorial haben, kann er sich gerne per Email oder ICQ an mich wenden.
Links
Copyright
© by Lukas Probst
Das Erstellen dieses Tutorials hat einiges an Zeit gekostet. Wenn ihr Teile dieses Tutorials kopieren, veröffentlichen (oder ähnliches) wollt, fragt bitte vorher per Mail nach.






