Asuro + Arduino + Wii Nunchuk = Ferngesteuerter Roboter

Im Rahmen meines Studiums der angewandten Informatik im Maschinenbau, haben wir an der FH Gelsenkirchen des öfteren mit dem kleinen Forschungsroboter Asuro der Firma Arexx gearbeitet.

Zugegebenermaßen ist der Asuro nicht mehr der aktuellste Robotorbausatz, aber um in die Welt der Robotik einzusteigen und sich am Löten zu versuchen ist der kleine immer noch sehr gut geeignet.

Auch ist der Einstiegspreis von 50-60€ je nach Anbieter angemessen.

Ein Projekt welches ich mithilfe des Asuro während meines Studiums umgesetzt habe war die drahtlose Steuerung über einen Nunchuck Controller der Nintendo Wii. Um dies umzusetzen galt es ersteinmal eine Bestandsaufnahme durchzuführen um zu sehen welche Möglichkeiten uns zur Verfügung stehen und somit den gewünschten Funktionsumfang zu bestimmen.

Den Funktionsumfang zu definieren war relativ einfach, der Asuro sollte über den analogen Joystick des Wii Nunchuck gesteuert werden und bei Druck auf die beiden Nunchuck Buttons aktionen wie eine 180° bzw. 360° Drehung ausführen.

Da wir nun wissen was wir wollen schauen wir nun wie wir dies erreichen können, fangen wir beim Asuro an:

Der Asuro bietet nur eine drahtlose Schnittstelle zur Aussenwelt, seinen IR- Empfänger bzw. IR- Diode. Diese Bauteile werden auch genutzt um die Firmware auf den Mikrocontroller des Asuro zu flashen. Infrarot ist zwar nicht die beste drahtlose Schnittstelle für unsere Aufgabe, aber man nimmt was man kriegen kann.

Schauen wir uns den Wii Nunchuck an. Eigentlich ein sehr nettes Teil was Nintendo dort verkauft. Ein analoger Joystick, zwei Bottons und innenliegend noch ein paar Beschleunigungssensoren. Blöd ist nur der proprietäre Anschluss bedeutet das man entweder den Stecker abschneiden muss, oder sich mit einem Adapter wie dem WiiChuck behilft. Ist diese Hardwarebarriere erst einmal überwunden so gibt der WiiChuck seine daten problemlos per I2C aus.

So nun haben wir einen Roboter der nur per Infrarot und einen Wii Nunchuck der nur per I2C Kommunizieren kann. Passt noch nicht so ganz zusammen und hier kommst der Arduino Uno ins Spiel. Ich muss sagen ich bin von der Arduino Plattform begeistert weil sie es sehr einfach macht solche Projekte umzusetzen. Das Arduino Board wird uns als Vermittler dienen indem es die Daten des Wii Nunchuck entgegen nimmt und diese per Infrarot an den Asuro weiter sendet. Dazu muss an das Arduino nur noch eine IR- Diode mit passendem Vorwiderstand angeschlossen werden.

Jetzt müssen wir nur noch klären wie wir die Steuerbefehle an den Asuro schicken wollen. Wir haben hier prinzipiell zwei möglichkeiten, wir können zwischen dem Asuro und dem Arduino eine serielle Verbindung via Infrarot aufbauen und die Steuerbefehle z.B. als Ascii zeichen versenden und auswerten oder wir benutzen das RC5 Protokoll welches auch bei Infrarot Fernbedienungen zum einsatz kommt. Im vorliegenden Fall habe ich mich für RC5 entschieden, ich muss allerdings auch zugeben auf die Lösung mit der seriellen Schnittstelle bin ich erst später gekommen 😉

So nun benötigt man noch ein bisschen Software welche auf den beiden Mikrocontrollern laufen soll. der Arduino nimmt also die Daten vom Wii Nunchuck entgegen, interpretiert Sie und sendet die Steuerbefehle an den Asuro, dieser reagiert auf diese. Da der Asuro per RC5 gesteuert wird kann man Ihn auch mit einer passend eingestellten Universalfernbedienung steuern.

Zum Glück gibt es hier einige Libraries (sowohl für den Asuro also auch für den Arduino) die uns das Leben einwenig einfacher machen:

Für den Asuro:

AsuroLib-v280rc1 Diese enthält eine passende Library zur Decodierung von RC5 Signalen

Für den Arduino:

ArduinoNunchuck von Gabriel Bianconi Diese ermöglicht uns das initialisieren und auslesen des Wii Nunchuck

IRemote Library von Ken Shirriff Mit dieser erzeugen wir die passenden Steuerbefehle

Die Projektseiten zeigen wie die Hardware miteinander verbunden werden muss.

Nun können wir unsere Software schreiben. Der Sourcecode sollte so dokumentiert sein das er keiner großen Erklärung bedarf:

Sourcecode für den Asuro:

/*******************************************************************************
*
* Beschreibung: Asuro von IR- Fernbedienung (RC5) bzw. Wii-Nunchuk gesteuert
* Author: Björn Sengotta
* Verwendet zusätzliche Libraries von http://sourceforge.net/projects/asuro/
*
*****************************************************************************/
#include "asuro.h"
//Library zur dekodierung von RC5 Fernbedienungscodes
#include "rc5.h"
#include

//Zuweisung von Fernbedienungscodes zu besser verständlichen Begriffen
#define VOR         0x1002
#define RUECK       0x1008
#define STOP        0x1005
#define RECHTS      0x1006
#define LRECHTS     0x1003
#define LRECHTSRW   0x1009
#define LINKS       0x1004
#define LLINKS      0x1001
#define LLINKSRW    0x1007
#define ONEEIGHTY   0x103F
#define THREESIXTY  0x1026

//Lässt den Asuro geradeaus fahren, Motorgeschwindigkeiten manuell ermittelt
void geradeaus()
{
BackLED(ON,ON);
MotorDir(FWD,FWD);
MotorSpeed(150,160);
}

//Stoppt den Asuro
void anhalten()
{
BackLED(OFF,OFF);
MotorSpeed (0,0);
}

//Lässt den Asuro rückwärts fahren, Motorgeschwindigkeiten manuell ermittelt
void rueckwaerts()
{
BackLED(ON,ON);
MotorDir(RWD,RWD);
MotorSpeed(150,160);
}

//Asuro dreht sich auf der Stelle nach rechts
void vollrechts()
{
BackLED(OFF,ON);
MotorDir(FWD,FWD);
MotorSpeed(150,0);
}

//Asuro dreht sich auf der Stelle nach links
void volllinks()
{
BackLED(ON,OFF);
MotorDir(FWD,FWD);
MotorSpeed(0,160);
}

//Asuro fährt eine Rechtskurve
void leichtrechts()
{
BackLED(OFF,ON);
MotorDir(FWD,FWD);
MotorSpeed(150,120);
}

//Asuro fährt eine Linkskurve
void leichtlinks()
{
BackLED(ON,OFF);
MotorDir(FWD,FWD);
MotorSpeed(130,160);
}

//Asuro fährt Rückwärts eine Rechtskurve
void leichtrechtsrw()
{
BackLED(OFF,ON);
MotorDir(RWD,RWD);
MotorSpeed(150,120);
}

//Asuro fährt Rückwärts eine Linkskurve
void leichtlinksrw()
{
BackLED(ON,OFF);
MotorDir(RWD,RWD);
MotorSpeed(130,160);
}

//Asuro macht eine 180° Drehung
void halbedrehung()
{
int i=0;

BackLED(OFF,ON);
MotorDir(FWD,RWD);
MotorSpeed(150,160);

for (i=0; i<90;i++)
{
Sleep(255);
}

MotorSpeed(0,0);
}

//Asuro macht eine 360° Drehung
void volledrehung()
{
int i=0;

BackLED(OFF,ON);
MotorDir(FWD,RWD);
MotorSpeed(150,160);

for (i=0; i<180;i++)
{
Sleep(255);
}

MotorSpeed(0,0);
}

//Main Methode
int main(void)
{
//variablen für die IR Kommandos
static unsigned int ircmd;
static unsigned int oldircmd;

//Erstzuweisung des Kommandos "Stop"
ircmd = 1005;
oldircmd = 1005;

//Initialisierungsmethoden für den Normalbetrieb und für die RC5 Klasse
Init();
InitRC5();

//Serielle Ausgabe
SerPrint("Asuro Ferngesteuert\r\n");

while(1)
{        //Zuweisung des letzten IR Kommandos auf die Variable oldircmd
oldircmd =ircmd;

//Lesen des IR Kommandos von der Fernbedienung und Verarbeitung mit der RC5_Mask
ircmd = ReadRC5();
ircmd &= RC5_MASK;

/*Wenn das alte und das neue IR Kommando verschieden sind springt das
Programm in die Switchanweisung und führt die zum IR Kommando passende Funktion aus*/
if (ircmd!=oldircmd)
switch(ircmd)
{
case VOR:
geradeaus();
break;
case STOP:
anhalten();
break;
case RUECK:
rueckwaerts();
break;
case RECHTS:
vollrechts();
break;
case LINKS:
volllinks();
break;
case LRECHTS:
leichtrechts();
break;
case LLINKS:
leichtlinks();
break;
case LRECHTSRW:
leichtrechtsrw();
break;
case LLINKSRW:
leichtlinksrw();
break;
case ONEEIGHTY:
halbedrehung();
break;
case THREESIXTY:
volledrehung();
break;
}
//Sind ircmd und oldircmd identisch führt der Asuro die vorhergehende Aktion weiter aus
else
;

}
return(0);
}

Und hier für den Arduino:

/*
* Beschreibung: Wii Nunchuck Fernsteuerung für den Asuro
* Author: Björn Sengotta
* Verwendet zusätzliche Libraries:
* ArduinoNunchuk (zum Auslesen des Nunchuk via I2C) https://github.com/GabrielBianconi/ArduinoNunchuk
* IRemote (zum Senden der RC5 IR Codes) http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
*/

#include
//Libraries zum auslesen des Nunchuck und zum Senden der RC5 Codes einbinden
#include
#include

//Baudrate für die serielle Verbindung setzen
#define BAUDRATE 19200

//Nunchuk Objekt anlegen
ArduinoNunchuk nunchuk = ArduinoNunchuk();
//Variablen für die Nullpunkt Koordinaten des Nunchuk Joysticks anlegen
int analogXzero;
int analogYzero;
//Variable für den RC5 Code anlegen
unsigned long code;

//IRemote initialiseren
IRsend irsend;

//Setup Routine
void setup()
{
//Serielle Verbindung aufbauen
Serial.begin(BAUDRATE);
//Nunchuck initialisieren
nunchuk.init();
/*Das erste mal die Werte des Nunchuks einlesen und als Nullreferenz verwenden
*da es sich nur um ganzzahlige Integerwerte handelt und diese auch sehr stabil
*sind ist eine mittlung der Werte (z.B. durch eine for- Schleife) nicht notwendig
*/
nunchuk.update();
//Werte der Nullstellen den Variablen zuweisen
analogXzero = nunchuk.analogX;
analogYzero = nunchuk.analogY;
}

// Haiptprogramm
void loop()
{
//Frische Werte vom Nunchuck holen
nunchuk.update();

//Werte für X- Achse und Y-Achse des Joysticks auslesen und mit den Nullpunkten
//verrechnen, auf diese Weise bekommen wir ungefähr Werte zwischen -127 und +127
int xValue = (nunchuk.analogX-analogXzero);
int yValue = (nunchuk.analogY-analogYzero);

//Prüfen ob einer der Knöpfe am Nunchuk gedrückt wurde
if (nunchuk.cButton == 1 || nunchuk.zButton == 1)
{
//Wenn Knopf C am Nunchuck gedrückt wurde wird das RC5 Signal für eine 180° Drehung an den Asuro gesendet
//und ein Text auf der seriellen Konsole ausgegeben
if (nunchuk.cButton == 1)
{
code = 0x83F;
sendCommand(code);
Serial.print("180° \n");
}
//Wenn Knopf Z am Nunchuck gedrückt wurde wird das RC5 Signal für eine 360° Drehung an den Asuro gesendet
//und ein Text auf der seriellen Konsole ausgegeben
else if (nunchuk.zButton == 1)
{
code = 0x826;
sendCommand(code);
Serial.print("360° \n");
}
}
else
{
//Testen ob sich der Joystick auf der X-Achse nahe des Mittelpunktes befindet
if (xValue > -49 && xValue < 49)
{
//Testen ob sich der Joystick auf der Y-Achse nahe des Mittelpunktes befindet, ist dies der Fall wird das "Stop"
//Kommando gesendet
if (yValue > -49 && yValue < 49)
{
code = 0x805;
sendCommand(code);
Serial.print("STOP \n");
}
//Testen ob sich der Joystick auf der Y-Achse im positiven Bereich (vom Körper weg) über dem Schwellenwert von 50
//liegt, ist dies der Fall wird das Kommando zum Vorwärtsfahren gesendet
else if (yValue > 50)
{
code = 0x802;
sendCommand(code);
Serial.print("VOR \n");
}
//Testen ob sich der Joystick auf der Y-Achse im negativen Bereich (zum Körper hin) unter dem Schwellenwert von -50
//liegt, ist dies der Fall wird das Kommando zum Rückwärtsfahren gesendet
else if (yValue < -50)
{
code = 0x808;
sendCommand(code);
Serial.print("ZURUECK \n");
}
}
//Testen ob sich der Joystick auf der X-Achse im negativen Bereich unter dem Schwellenwert von -50 befindet,
//dies bedeutet das der Joystick einen Ausschlag nach Links hat
else if (xValue < -50)
{
//Testen ob sich der Joystick auf der Y-Achse zwischen den Schwellenwerten von -49 und +49 bewegt,
//ist dies der Fall befindet sich der Joystick in einer Mittelstellung und das Kommando "LINKS" wird gesendet
if (yValue > -49 && yValue < 49)
{
code = 0x804;
sendCommand(code);
Serial.print("LINKS \n");
}
//Testen ob sich der Joystick auf der Y-Achse zwischen über dem Schwellenwert von 50 bewegt,
//ist dies der Fall befindet sich der Joystick links oben und das Kommando "LINKS OBEN" wird gesendet
else if (yValue > 50)
{
code = 0x801;
sendCommand(code);
Serial.print("LINKS OBEN\n");
}
//Testen ob sich der Joystick auf der Y-Achse zwischen unter dem Schwellenwert von -50 bewegt,
//ist dies der Fall befindet sich der Joystick links unten und das Kommando "LINKS UNTEN" wird gesendet
else if (yValue < -50)
{
code = 0x807;
sendCommand(code);
Serial.print("LINKS UNTEN\n");
}

}
//Testen ob sich der Joystick auf der X-Achse im positiven Bereich über dem Schwellenwert von 50 befindet,
//dies bedeutet das der Joystick einen Ausschlag nach Rechts hat
else if (xValue > 50)
{
//Testen ob sich der Joystick auf der Y-Achse zwischen den Schwellenwerten von -49 und +49 bewegt,
//ist dies der Fall befindet sich der Joystick in einer Mittelstellung und das Kommando "RECHTS" wird gesendet
if (yValue > -49 && yValue < 49)
{
code = 0x806;
sendCommand(code);
Serial.print("RECHTS \n");
}
//Testen ob sich der Joystick auf der Y-Achse zwischen über dem Schwellenwert von 50 bewegt,
//ist dies der Fall befindet sich der Joystick rechts oben und das Kommando "RECHTS OBEN" wird gesendet
else if (yValue > 50)
{
code = 0x803;
sendCommand(code);
Serial.print("RECHTS OBEN\n");
}
//Testen ob sich der Joystick auf der Y-Achse zwischen unter dem Schwellenwert von -50 bewegt,
//ist dies der Fall befindet sich der Joystick rechts unten und das Kommando "RECHTS UNTEN" wird gesendet
else if (yValue < -50)
{
code = 0x809;
sendCommand(code);
Serial.print("RECHTS UNTEN\n");
}

}
//Falls alle Bedingungen nicht zutreffen (z.B. Nunchuck nicht angeschlossen) wird der Fehler auf der seriellen
//seriellen Konsole ausgegeben
else
{
Serial.print("Failure \n");
}
}
//Ausgabe der Nunchuk Werte zum debuggen
Serial.print((nunchuk.analogX-analogXzero), DEC);
Serial.print(' ');
Serial.print((nunchuk.analogY-analogYzero), DEC);
Serial.print(' ');
Serial.print(nunchuk.zButton, DEC);
Serial.print(' ');
Serial.println(nunchuk.cButton, DEC);
}

//Funktion zum senden des RC5 Kommandos via IRemote Library, bekommt als Argument den RC5 Code mitgeteilt
void sendCommand(unsigned long code)
{
//Der RC5 Standard sieht vor, das das Kommando 3 mal gesendet werden muss
for (int i = 0; i < 3; i++) {
irsend.sendRC5(code, 12);
//Delay von 40ms vor dem erneuten senden des Kommandos
delay(40);
}
}

Damit sollte der Asuro sich nun per Wii Nunchuck steuern lassen. Ein Problem ist natürlich die Reichweite der IR- Verbindung, diese ist nicht wirklich groß und hängt auch sehr stark von der Ausrichtung der IR Diode und des Empfängers ab.

Viel Spass beim nachmachen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.