Wii motion plus and Arduino


The Wii Motion Plus and a Solarbotics adapter for easy connection

As you might know from one of my previous posts, I’ve burned (I only now start to have an idea of a possible cause…) part of my Razor 9DOF IMU board. I can still use the accelerometer and magnetometer on it, BUT the gyroscopes (though I’m sure they are both fine) can’t be accessed simply because they are not on the I2C buss and it’s impossible for me to solder wires onto them…

So I’ve decided to explore the idea of using the Wii motion plus gyroscopes instead, especially that there are several people out there that have quadcopters flying with them !  (combined or not with nunchuck accelerometers…)

Ordered a WMP 3 days ago on the internet, but it’s Saturday and it still hasn’t arrived, so went to the local games shop, and bought a sencond hand one for just 10£ ! (cheaper, easier and more environmentally frendly than the new one from the Internet…)

Here it is, connected to the Arduino through a very handy adapter… this is only temporary to test that everything works ok:

WMP connected to an Arduino

And now let the hacking commence !

The Wii Motion Plus taken apart

Hardware Connection

Basicaly same as for the Nunchuck

| 1 2 3 |
|       |
| 6 5 4 |
|_-----_|

1 – green – data
2 – nothing
3 – red – 3.3+v
4 – yellow – clock
5 – nothing
6 – white – ground

WMP taken apart and desoldered, with the I2C wires indicated (Likly wrong, don't correspond to other posts on the Internet)

WMP with new wires in place (these indications are SURELY CORRECT !)

I’m running this directly at the 5V from the Arduino, which is not perfect, but I tried to use sparkfun’s logic level converter and for some reason it didn’t work (even though it works with the Razor IMU, so it’s not a problem with the converter).

Software

#include <Wire.h>

// 7bit addressing
#define GYROS_ADDR_INIT 0x53  //WM+ starts out deactivated at address 0x53
#define GYROS_ADDR 0x52   // Wii Motion Plus
#define DATA_SIZE 6

byte buff[DATA_SIZE]; //six data bytes
int gyroX0, gyroY0, gyroZ0; //calibration zeroes

void setup_I2Csensors(){
   Wire.begin(); // join as master

   initGyros();
   calibrateGyrosZeroes();
}

void initGyros(){
Wire.beginTransmission(GYROS_ADDR_INIT); //WM+ starts out deactivated at address 0x53
Wire.send(0xfe); //send 0x04 to address 0xFE to activate WM+
   Wire.send(0x04);
   Wire.endTransmission(); //WM+ jumps to address 0x52 and is now active
   delay(10);
}

void readGyros(){
    gyrosSendZero(); //send zero before each request (same as nunchuck)
    Wire.beginTransmission(GYROS_ADDR);
    Wire.requestFrom(GYROS_ADDR, DATA_SIZE); //request the six bytes from the WM+
    if(Wire.available() == DATA_SIZE) {
        for (int i=0; i<DATA_SIZE; i++) buff[i] = Wire.receive();

        //see http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Plus
        //for info on what each byte represents
        _gyroZ = ((buff[3] >> 2) << 8) + buff[0] - gyroZ0;
        _gyroX = ((buff[4] >> 2) << 8) + buff[1] - gyroX0;
        _gyroY = ((buff[5] >> 2) << 8) + buff[2] - gyroY0;
    }else{
        Serial.println("ERR_readGyros");
    }
    Wire.endTransmission();
}

void calibrateGyrosZeroes(){
    long tempX=0, tempY=0, tempZ=0;
    gyroX0 = 0; gyroY0 = 0; gyroZ0 = 0;
    for (int i=0; i<10; i++){
        readGyros();

        tempZ += _gyroZ;
        tempX += _gyroX;
        tempY += _gyroY;
    }

    // average 10 readings
    gyroZ0 = tempZ / 10;
    gyroX0 = tempX / 10;
    gyroY0 = tempY / 10;
}

void gyrosSendZero(){
   Wire.beginTransmission(GYROS_ADDR);//now at address 0x52
   Wire.send(0x00); //send zero to signal we want info
   Wire.endTransmission();
}

Conclusion

It all  worked nice and smoothly after some frustration with the logic level converter.

I was able to connect both the WMP and the Razor IMU on the I2C bus, and read data from both the accelerometer and the gyros…

And THEN, I nicely and firmly glued the 2 boards together, using standard 2 components epoxy… and that broke the WMP board, now it’s impossible to read the gyros… luckily the accelerometer on the Razor board still works though…

So I’m not really sure, but this could also explain why the Razor IMU board broke in the first place : the Atmega on it abruptly stopped working ! Even though it was several hours after I used epoxy on it..

Anyhow, it’s quite frustrating and I’ve decided never ever to use epoxy on circuit boards again and next thing today will be to buy some electronics grade silicone glue (like RTV162) !!!

24 Jan 2011 Update

It turns out the WMP board still works OK, my quest for optimisation made me remove its initialisation from the code.

Actually the WMP start at address 0x53 and you have to send it a specific code to a specific address to make it start and listen at address 0x52 !

And, as long as you don’t disconnect the board it will still work, hence my erroneous conclusion that the initialisation was useless.

I’ve just put back that code and it works flawlessly…

9 Responses to Wii motion plus and Arduino

  1. Pingback: Wii Motion plus Gyros on RaspberryPi | Robotics / Electronics / Physical Computing

  2. jm says:

    Hello, thanks for posting this code.
    I’m currently having trouble making it works though. I’ve added the following lines :
    int _gyroX, _gyroY, _gyroZ ;

    void setup(){
    setup_I2Csensors();
    Serial.begin(115200);
    Serial.println(“WM+ tester”);
    delay(1000);
    }

    void loop(){
    readGyros();
    Serial.print(“X:”);//see diagram on randomhacksofboredom.blogspot.com
    Serial.print(_gyroX); //for info on which axis is which
    Serial.print(” Y:”);
    Serial.print(_gyroY);
    Serial.print(” Z:”);
    Serial.println(_gyroZ);
    delay(100);
    }

    The sketch does compile but the result is an endless stream of “ERR_readGyros X:0 Y:0 Z:0”. So I think the problem hides in void readGyros but I can’t see it.

    Thank you very much !

    • trandi says:

      Hi,

      I’m glad you found my post useful.
      Regarding your problem, it seems like it fails on the line “Wire.available() == DATA_SIZE”, hence the “ERR_readGyros” message.
      This can be anything, from bad wiring or a defective unit.
      The code actually never checks the connection with the gyros before that point, so that might explain why you don’t see the error earlier, when initialising or calibrating the gyros.

      dan

    • jm says:

      When I add Serial.println(Wire.available()), it systematically gives me 0 ; I think the arduino doesn’t get anything from the wm+, but since the connections seems correct to me and a current is actually going, I don’t see where the problem comes from…

  3. mar99 says:

    I tried to use the code you posted, but for some reason, it dosen’t compile. any suggestions???

    • trandi says:

      First of all, when asking this kind of questions, you should ALWAYS send the exact error message and output !

      In this case, the code I posted is just the file with the “utility” functions. You’ll need to add a “setup()” and “loop()” methods that will call “setup_I2Csensors()” and “readGyros()” respectively, and then retrieve the data in “_gyroX”, Y and Z, which also should be defined as int in the main part of the code.

      Hope this helps,
      Dan

  4. Pingback: Android IOIO Wii Motion Plus – Gyroscopes | PDA8

  5. Pingback: Android IOIO Wii Motion Plus – Gyroscopes « Robotics / Electronics / Physical Computing

  6. Pingback: Quadcopter – home made « Robotics / Electronics / Physical Computing

Leave a comment