Die Wii Remote besitzt zur Positionserkennung eine Infrarotkamera. Dazu gibt es die Wii-Sensorleiste die 2 Infrarot-Leuchtdioden an den Enden besitzt. Diese Sensorleiste muss unter oder über dem Bildschirm platziert werden. Die Kamera in der Wii Remote kann dadurch ihre Position relativ zur Sensorleiste feststellen und sie kann zum Zielen auf dem Bildschirm verwendet werden.
Die Kamera in der Wii Remote besitzt bereits eine eingebaute Elektronik, die bis zu 4 Infrarot-Punkte erkennen kann und deren Position über eine I2C-Schnittstelle ausgibt. Diese Kamera kann aus der Wii Remote ausgebaut werden und einzeln betrieben.
Die Funktion wurde vor einiger Zeit in Zusammenhang mit Mikrocontrollern oder einem Arduino-Board beschrieben:
http://letsmakerobots.com/node/7752
http://translate.google.com/translate?hl=en&sl=ja&tl=en&u=http%3A%2F%2Fwww.kako.com%2Fneta%2F2008-009%2F2008-009.html
http://procrastineering.blogspot.de/2008/09/working-with-pixart-camera-directly.html
Genauso gut kann die Kamera aber auch mit einem Raspberry Pi verwendet werden.
Beschaltung des Sensors
Dazu muss der Sensor aus einer Wii Remote ausgebaut werden. Glücklicherweise arbeitet die Kamera genau wie der Raspberry Pi mit 3,3 V, dadurch passen dann auch die Pegel für die I2C-Schnittstelle. Zusätzlich braucht die Kamera noch einen externen Takt mit 25 MHz. Dies kann einfach mit einem Quarzoszillator mit 3,3 V Betriebsspannung erzeugt werden.
Initialisierung und Ansteuerung
Der Sensor hat die Adresse 58h. Bevor der Sensor Daten liefert muss er initialisiert werden. Dies geschieht mit einer Reihe von Byte writes über den I2C-Bus. Nach der Initialisierung muss etwa 50 – 100 ms gewartet werden, bevor der Sensor Daten liefern kann. Danach muss ein Block Read an der Adresse 36h durchgeführt werden. Dies geschieht mit dem Befehl i2c_smbus_read_i2c_block_data. Die zurückgelieferten Daten enthalten die Positionen von bis zu 4 IR-Quellen. Die x- und y-Koordinaten sind in jeweils 3 Bytes kodiert. Wenn kein IR-Punkt erkannt wurde, sind alle 3 Bytes FFh. Ansonsten müssen die Koordinaten folgendermaßen umgerechnet werden:
x=((buf[2]&0x30)<<4)+buf[0];
y=((buf[2]&0xc0)<<2)+buf[1];
Das komplette Programm
Das komplette Programm schaut dann so aus:
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <unistd.h>
int calculate_coordinates(char *buf, int *x, int *y) { if(buf[0]==0xff&&buf[1]==0xff&&buf[2]==0xff) return -1; // no valid data *x=((buf[2]&0x30)<<4)+buf[0]; *y=((buf[2]&0xc0)<<2)+buf[1]; return 1; }
int main(void) { int file; int x=0,y=0,ret=0; char data[16]; int i=0;
printf("Nintendo Wii infrared sensor\n"); if((file=open("/dev/i2c-1",O_RDWR))<0) // open i2c-bus { perror("cannot open i2c-1"); exit(1); } if(ioctl(file, I2C_SLAVE, 0x58)<0) // open slave, address = 0x58 { perror("cannot open slave address"); exit(1); } i2c_smbus_write_byte_data(file,0x30,0x01); // initialize sensor i2c_smbus_write_byte_data(file,0x30,0x08); i2c_smbus_write_byte_data(file,0x06,0x90); i2c_smbus_write_byte_data(file,0x08,0xc0); i2c_smbus_write_byte_data(file,0x1a,0x40); i2c_smbus_write_byte_data(file,0x33,0x33);
usleep(50000); // wait until sensor is ready
ret=i2c_smbus_read_i2c_block_data(file, 0x36,16,(__u8*)&data); // read 16 byte data block printf("%i bytes read\n",ret); for(i=0;i<16;i++) printf("Byte %02i: 0x%02x\n", i,data[i]); // show data
if(calculate_coordinates(&(data[1]),&x,&y)>0) printf("coordinates point 1: x=%i,y=%i\n",x,y); else printf("no point 1\n"); if(calculate_coordinates(&(data[4]),&x,&y)>0) printf("coordinates point 2: x=%i,y=%i\n",x,y); else printf("no point 2\n"); if(calculate_coordinates(&(data[7]),&x,&y)>0) printf("coordinates point 3: x=%i,y=%i\n",x,y); else printf("no point 3\n"); if(calculate_coordinates(&(data[10]),&x,&y)>0) printf("coordinates point 4: x=%i,y=%i\n",x,y); else printf("no point 4\n");
close(file);
return 0; }
Kommentare
Kommentarfunktion für diesen Artikel geschlossen.