Navigation

    Navigation

      12b) Wireless Wii Nunchuck Arduino interface for twin-wheeler

      PLAN A: Use a wired conventional NIntendo Wii Nunchuck
      The first plan was to get this to work with a "hacked" wired Nunchuck, once this was done the plan was to go up to a wireless 'chuck.
      Code modified from that developed by others using the Arduino microcontroller to "hack" the data coming out of a Wii Nunchuck and use the Arduino output pins to send control information to my main microcontroller. The Nunchuck is low cost, fits the hand perfectly, has a 3 axis accelerometer and a proper proportional 2 axis joystick on top. In addition it has 2 buttons I can use as the motor "kill" switch if they are released. The Arduino is also very low cost. I now have it working (see base of this page) - I can steer board by just tipping handcontroller left or right, or I can use the thumb joystick on the top..

      YouTube Video

      YouTube Video

       
       
       
      There are some other websites referenced below where you can find more info on wiring in the Nunchuck (4 wires).
      The idea is that I will use the joystick forward/back control to fine-tune the skateboard balance point. If you press the lower button on front of the Nunchuck, you steer by using the left/right joystick movement.
      If you press the upper button (or both together) then you can still trim balance point via the joystick but the steering is now done by tilting the whole nunchuck to the right or the left - i.e. you use the x-axis accelerometer to steer with.
      If you fail to press any of the front 2 buttons, it assumes you have fallen off and a logic signal goes low to "tell" the main controller to cut the power to the motor etc.
       
      You can get the idea from the 2 vids I have put on YouTube, where I am just dimming and brightening PWM'ed LEDs on the outputs to show you the general idea.
       
      The Arduino programming environment is a simplified form of "C" and is designed as a low cost and easier way for people to get their projects up and running very quickly. The boards are open-source and come with a serial port, the capacity to assign additional pins as "software" serial outputs and inputs. They are programmed directly via a USB cable from the PC.
      If I had started the skateboard project again now, I would probably have used Arduino - cheaper and easier. There are loads of add-on accessories such as Bluetooth, wireless data transfer, GPS units, even a complete model aircraft "autopilot" system if you want to build yourself a UAV.
      The code below was for the WIRED Nunchuck, not the wireless version which was much more of a headache to get working.
       
       
       

      // Arduino based interface between a Wii Nunchuck and a Segway style self balancing electric vehicle.

      // In my case this is a twin wheeled electric skateboard. Outputs from Arduino go to the main microcontroller which is controlling

      // and balancing the board.

      // Uses Duemilanove ATMega328  Arduino 17 with wired Wii Nunchuck.

       

      // 5V output on Arduino to Nunchuck (works better than using 3.3V line)

      // GND

      // SDA to analog pin 4

      // SCK to analog pin 5

      // the middle upper and middle lower contacts of nunchuck plug are not used

       

      //Derived from code developed by Chad Phillips, see:  http://windmeadow.com/node/42

      //   For info on wiring up the chuck to the Arduino, download Bionic Arduino Class 4 from TodBot blog:

      //   http://todbot.com/blog/2007/11/24/bionic-arduino-class-notes-3-4/

       

      // To avoid hacking off plug you can buy a nunchuck extender cable (plug one end socket the other) and

      // cut that in half to get the socket on a cable, with free wires on the other end to attach to Arduino

       

      // Some non-nintendo Nunchucks have shorter cables by the way than the real thing.

       

      // Outputs for skateboard: Digital Pin 9 outputs 5V to balance controller board when buttons(s) pressed.

      //                         if neither button pressed, Pin 9 goes to 0V to "tell" main board to cut the motors

       

      //                         Smoothed PWM output on pin 10 gives 2.5V most of time. Climbs to +5V or drops to 0V when joystick

      //                         moved forwards or backwards. Main microcontroller accesses this and uses it to control the "Trim" function

      //                         which can be used to fine-tune balance point of the board

      //                         Smoothed PWM output on pin 11 gives 2.5V most of time. If z button pressed, then joystick left/right will make it

      //                         go down to 0V or up to 5V. Main micro takes this and uses it as signal to control steering of twin wheeled board.

      //                         If z and c buttons pressed (or just c button alone) then this Pin 11 output becomes controlled by L/R TILT of the

      //                         nunchuck (via embedded accelerometer) and the L/R joystick component is disabled.

       

       

       

       

       

       

      #include <Wire.h>

      #include <string.h>

       

      #undef int

      #include <stdio.h>

       

      uint8_t outbuf[6];                   // array to store arduino output

      int cnt = 0;

      int ledPin = 13;

      int i; //declare i as an integer

      int j; //declare j as an integer

       

      #define LEDx 11   //pin 11 varies according to x accel  pin10 is a pwm

      #define LEDy 10   //defines pin 10 as varying according to y accel pin 9 is a pwm

      #define ledc 8   //defines pin 8 as output for c button

      #define ledz 9   //defines pin 9 as output for z button

       

       

      void

      setup ()

      {

        //Serial.begin (19200);

        //Serial.print ("Finished setup\n");

        pinMode(LEDx, OUTPUT); //tell arduino it is an output

        pinMode(LEDy, OUTPUT); //tell arduino it is an output

        pinMode(ledc, OUTPUT); //tell arduino it is an output

        pinMode(ledz, OUTPUT); //tell arduino it is an output

       

        Wire.begin ();                       // join i2c bus with address 0x52

        nunchuck_init (); // send the initilization handshake

      }

       

      void

      nunchuck_init ()

      {

        Wire.beginTransmission (0x52);          // transmit to device 0x52

        Wire.send (0x40);                 // sends memory address

        Wire.send (0x00);                 // sends sent a zero. 

        Wire.endTransmission ();     // stop transmitting

      }

       

      void

      send_zero ()

      {

        Wire.beginTransmission (0x52);          // transmit to device 0x52

        Wire.send (0x00);                 // sends one byte

        Wire.endTransmission ();     // stop transmitting

      }

       

      void

      loop ()

      {

        Wire.requestFrom (0x52, 6);                // request data from nunchuck

        while (Wire.available ())

          {

            outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());   // receive byte as an integer

            digitalWrite (ledPin, HIGH);             // sets the LED on

            cnt++;

          }

       

        // If we recieved the 6 bytes, then go print them

        if (cnt >= 5)

          {

            print ();

          }

       

        cnt = 0;

        send_zero (); // send the request for next bytes

        delay (100);

      }

       

      // Print the input data we have recieved

      // accel data is 10 bits long

      // so we read 8 bits, then we have to add

      // on the last 2 bits.  That is why I

      // multiply them by 2 * 2

      void

      print ()

      {

        int joy_x_axis = outbuf[0];

        int joy_y_axis = outbuf[1];

        int accel_x_axis = outbuf[2] * 2 * 2;

        int accel_y_axis = outbuf[3] * 2 * 2;

        int accel_z_axis = outbuf[4] * 2 * 2;

       

        int z_button = 0;

        int c_button = 0;

       

       // byte outbuf[5] contains bits for z and c buttons

       // it also contains the least significant bits for the accelerometer data

       // so we have to check each bit of byte outbuf[5]

        if ((outbuf[5] >> 0) & 1)

          {

            z_button = 1;

          }

        if ((outbuf[5] >> 1) & 1)

          {

            c_button = 1;

          }

       

        if ((outbuf[5] >> 2) & 1)

          {

            accel_x_axis += 2;

          }

        if ((outbuf[5] >> 3) & 1)

          {

            accel_x_axis += 1;

          }

       

        if ((outbuf[5] >> 4) & 1)

          {

            accel_y_axis += 2;

          }

        if ((outbuf[5] >> 5) & 1)

          {

            accel_y_axis += 1;

          }

       

        if ((outbuf[5] >> 6) & 1)

          {

            accel_z_axis += 2;

          }

        if ((outbuf[5] >> 7) & 1)

          {

            accel_z_axis += 1;

          }

       

        /*

        Serial.print (joy_x_axis, DEC); //values seen: 37left 134mid  234right

        Serial.print ("\t");

       

        Serial.print (joy_y_axis, DEC); //values seen: 218forward  124mid  23back

        Serial.print ("\t");

       

        Serial.print (accel_x_axis, DEC); //values: 312left  512mid  745right

        Serial.print ("\t");

       

        Serial.print (accel_y_axis, DEC); //values: forward754  mid576   back361

        Serial.print ("\t");

       

        Serial.print (accel_z_axis, DEC);  // values: hovers around 530 - 743

        Serial.print ("\t");

       

        Serial.print (z_button, DEC); //NB: 0 when pressed 1 when not

        Serial.print ("\t");

       

        Serial.print (c_button, DEC); //NB: 0 when pressed 1 when not

        Serial.print ("\t");

       

        Serial.print ("\r\n");

        */

       

       

       

      j = joy_y_axis;

      analogWrite(LEDy, j);  //sets LED on pin 10 used to control the Trim function brightness according to forward/back of joystick

       

       

       

       

      if (z_button < 1 && c_button == 1) {  //if pressing z button only, steer on left/right joystick

                        digitalWrite (ledz, HIGH);    // sets the LED high on pin 9

                        i = joy_x_axis - 6; //mid point is 134 this corrects it to 128

                        analogWrite(LEDx, i);  //sets LED on pin 11 steering PWM brightness

                                        }

                                       

      if (z_button < 1 && c_button < 1) {  //if pressing both buttons, steer using accelerometer

                        digitalWrite (ledz, HIGH);    // sets the LED high motor kill switch control on pin 9

                        i= (int) (accel_x_axis - 512) / 2 + 128;   //convert from range 312 to 512mid to 745 to a 0-255 scale

                        if (i>255) i=255;

                        if (i<0) i=0;

                        analogWrite(LEDx, i);  //sets LED on pin 10 brightness

                                        }

       

       

                                          

      if (z_button == 1 && c_button < 1) {  //if c button only pressed then steer on accelerometer

                        digitalWrite (ledz, HIGH);    // sets the LED high on pin 9

                        i= (int) (accel_x_axis - 512) / 2 + 128;   //convert from range 312 to 512mid to 745 to a 0-255 scale

                        if (i>255) i=255;

                        if (i<0) i=0;

                        analogWrite(LEDx, i);  //sets LED on pin 11 steering brightness

                                          }

                         

      if (z_button == 1 && c_button == 1) {   //if no button pressed then dead ahead and control signal to AVR off i.e. stop motor

                        digitalWrite (ledz, LOW);     // sets the LED low on pin 9

                        analogWrite(LEDx, 128);  //sets LED on pin 11 steering half PWM i.e. dead ahead if skateboard 

                        analogWrite(LEDy, 128);  //sets LED on pin 10 half PWM i.e. mid point for the trim function if skateboard            

                                           }

               

      }

       

      // Encode data to format that most wiimote drivers except

      // only needed if you use one of the regular wiimote drivers

      char

      nunchuk_decode_byte (char x)

      {

        x = (x ^ 0x17) + 0x17;

        return x;

      }

       
      PLAN B: Once that was done, try to use a wireles Nunchuck to do the same job
      The Arduino code to read a wireless Nunchuck is different to that used for the wired Nunchuck.
       

      The code "hack" for this was proving very tricky to make work. It is different to the one used for the "wired" Nunchuck.
       
      OK managed to get this to work after much conversation on the Arduino forum November 09. For the wireless nunchuck code have a look at this forum page:
       
      Take note of the comments about external pull-up resistors.
       
      You can turn it by just tilting your hand left or right.
       
      I have 2 different makes of wireless controllers, BlazePro and a newer rechargeable type with no name. Both of them work OK with this code
      (Nintendo don't make a wireless one, these are all made in China, several types available).
       
       
       
       
      Photo of the Arduino board which just spends its time reading the wireless Nunchuck and then sending control info to the main balance/steering microcontroller.
       
       
      Also check out this link to someone who has usd an Arduin to read the 3 axis gyroscoe found within the Wii Motion Plus adapter.
      This is a cheap way of getting a 3 axis gyro into an Arduino project.    Click Here
       
       
       
       
       
      Comments