When the Nintendo Wii was released in 2006, there was a lot of talk about their new weird control system. In place of a typical control pad, players would use a one-handed “remote” with infrared sensors and accelerometers in place of a joystick. For those games that required additional controls, players would use an accessory controller in their off-hand.

This ‘accessory’ controller is the Nunchuk. A strange, bean-shaped attachment with a joystick, two buttons, and a three-axis accelerometer. Although the Nunchuk had a lukewarm response when it was first released, it’s the perfect controller for makers who want to add some fine control to their projects.

Although I’m writing this post with Arduino in mind, most of this information also applies to using a Nunchuk with something like a Raspberry Pi or an ARM-based board.

Let’s get started!

Getting Connected

While the Wii remote itself is wireless, the Nunchuk was designed to plug into an accessory port at the bottom of the remote. This is actually better for my purposes, because it means that I can connect the hardware directly to a microcontroller.

To connect to the Nunchuk I purchased a “Nunchuky” breakout board from Adafruit for a cool $3. The Nunchuk’s extension connector snaps right into the board, which exposes the power and data lines so I can connect it to a breadboard. I could have also cut the connectors off and used the bare wires, but there’s something to be said for keeping the controller intact.

From the Nunchuk’s 6-pin connector, these breakout boards expose 4 pins:

  • Gnd: Ground.
  • 3.3V: VCC, can also be +5V.
  • Data: SDA, serial data.
  • Clk: SCL, serial clock line.

Of the remaining two pins, one is not-populated on the connector and one is a power return used for controller detection. Unfortunately the breakout doesn’t expose this return pin, so I’ll have to live without another glowy indicator LED.

Inter-Integrated Wii

As it turns out, the communication protocol used by the Nunchuk is none-other than standard I2C! The data and clock lines from the Nunchuk can be hooked directly to the hardware protocol pins on the microcontroller.

For an Arduino Uno and other 328P-based boards, the connection pins for SDA and SCL are A4 and A5, respectively. For the Arduino Leonardo and other 32U4-based boards, you use pins 2 and 3 for data and clock.

Voltage Levels

According to information I can find online, the Wii remote outputs 3.3V from its extension connector at the bottom of the controller. This is the expected voltage level for the Nunchuk.

This presents a problem for using something like an Arduino Pro Micro, which has no onboard regulator and operates directly from the PC’s +5V via USB. Nevertheless, some information online seems to indicate that the Nunchuk works fine when powered with +5V. So I did what any maker would do with a $5 part and gave it a shot.

It works, but it doesn’t work perfectly. The Nunchuk will respond to commands and outputs data to the board when powered from +5V, which for the most part appears accurate. The only problem occurs when the joystick is maxed out on both the X and Y axis (NE corner). In this position, both axes report ‘center’ values over the bus (127) rather than maxed values (255). I verified this with a logic analyzer to make sure it wasn’t a software fault with my library.

These problems went away when using a +3.3V supply with a 5V -> 3.3V logic level converter. This may or may not be a problem with a ‘genuine’ Nunchuk. YMMV.

As with any electrical component, using a higher voltage level than expected – if it works at all – will usually lower the lifespan of the part. If your Nunchuk does work perfectly with +5V power, beware that it might fail prematurely.

Nunchuk Data

With the Nunchuk connected to the Arduino it’s time to start reading data from the controller!

Thankfully in the last 11 years a lot of smart people have messed around with these Wii extension controllers, so there is plenty of information online about how they work. After fighting with most of the existing libraries out there, I decided to create my own called NintendoExtensionCtrl, which works with the Nunchuk and a few other controllers. You can download it from GitHub or by using the libraries manager in the Arduino IDE.

Initialization

Before it will send any data, the Nunchuk needs to be initialized. The library makes this easy with a connect method, but let’s look at what’s going on under the hood.

The library joins the hardware I2C bus as a master and then writes two bytes to the Nunchuk: ‘0x55’ to register 0xF0, and ‘0x00’ to register 0xFB. According to information I found online, the Nunchuk normally encrypts its output using an XOR transformation. By initializing the device with these two commands, the Nunchuk operates in an “unencrypted communication mode”. This means the data it sends in response to a polling request is plainly formatted and easily parsed.

The connect method for the library also has a function to identify what type of controller was connected, as the Wii remote’s port also supports things like the Wii classic controller and musical controllers for things like Guitar Hero.

Lastly, the method polls the controller for its control data (update()) so the user can start using it right away.

Polling Updates

Because the Nunchuk works over the two-wire I2C bus, updates need to be polled from the device.

To poll for an update, the Arduino first sends ‘0x00’ to the Nunchuk to set the register pointer at the start of the data block. It then requests 6 bytes of data from the Nunchuk. These 6 bytes contain all of the information from the Nunchuk’s controls.

Data Formatting

The data from the Nunchuk comes packaged in a specific way to save bandwidth on the bus. This allows Nintendo to squeeze a little more range out of the accelerometer while keeping the max polling rate the same.

Table from WiiBrew.org

The first two bytes are the joystick X and Y values, respectively. The next three bytes are the most significant bits for the accelerometer values (XYZ). The last byte contains the two least significant bits for all three accelerometer values, as well as single bits for the on/off states of both buttons. These button values are inverted, so a ‘0’ means the button is pressed (don’t worry, this is flipped by the ‘get’ function).

The bit-depth for the controls are as follows:

  • Joystick XY: 8 bit / 0 – 255
  • Accelerometer XYZ:  10 bit / 0 – 1023
  • Buttons C/Z: 1 bit / 0 – 1

In the library, each control is parsed by it ‘get’ method as they are called. This keeps the overhead low for controls that aren’t needed by the user.

Retrieving Data

Using the NintendoExtensionCtrl library, getting data from the Nunchuk is a piece of cake:

Calling updatewill update the microcontroller’s buffer with the latest values from the Nunchuk. Calling each data function will return the transformed version of that respective value, either as an unsigned integer (joystick, accelerometer) or as a boolean (buttons).

Using Multiple Nunchuks

This is all fine-and-dandy for using a single controller, but what if you want to use two or more Nunchuks?

This is possible, but unfortunately it isn’t quite as easy. The system was designed to only use one device per Wii remote, so they aren’t built with scalability in mind. The limitation here is the I2C address.

The I2C bus used by the Nunchuk (and other extension controllers) is addressable. This means that it’s possible to have dozens of devices all communicating on the same bus using just two wires. To talk to a specific device the controller makes a request to that address. This is the problem, as all Wii extension controllers have the same address – 0x52. If you put two controllers on the same bus, they will both try to respond at the same time and you’ll have a conflict.

The solution is to use two I2C buses. Or, if you only have one bus, to use an I2C multiplexer like the TCA9548A. Adafruit sells a nice breakout that works well. I’m currently using this multiplexer to have two Nunchuks work on an Arduino Pro Micro. It also conveniently acts as a level-converter!

Example Project: LED Controller

Now it’s time to put this knowledge to work and make something! My typical go-to is something with RGB LEDs because they are quick to set up, have a lot of parameters, and offer clear visual feedback. As the Nunchuk is a controller, why not set it up to control a few LEDs?

I’m going to set this up as follows:

  • Joystick X: Set number of LEDs (left to right)
  • Joystick Y: Set brightness
  • Accel XYZ: Set RGB values
  • C Button: Flicker on/off
  • Z Button: Turn on / off all

For my LEDs I’m going to use a small strip of WS2812B addressable LEDs, or what Adafruit calls “NeoPixels”. They’re inexpensive and easy to work with if you use a library like FastLED.

Setup

First a few housecleaning things. Import the NintendoExtensionCtrl and FastLED libraries, set a few global variables, and start both libraries in the setup function.

Once we get to the loop, the code clears the LED data and polls the controller for new information. Each control is then handled in-turn.

JoyX: Number of LEDs

The ‘X’ value of the joystick controls how many LEDs are on. The value is divided by a parameter so the max possible value is the maximum number of LEDs in the strip.

This value is stored in a global variable. It’s going to be used to set the loop length when the LED colors are set.

JoyY: Brightness

The ‘Y’ value of the joystick controls the brightness of the LEDs.

The brightness is scaled depending on the ‘min’ and ‘max’ brightness values, set at the top of the code. This is just a quality of life thing – the LEDs can get crazy bright. It also works using the joystick value directly.

Accel XYZ: Color Values

The accelerometer values for X, Y, and Z control the RGB color of the strip.

The accelerometer value is 10 bits (0 – 1023), so it’s divided by 4 to get an 8-bit value that fits in the array. The LEDs are assigned from the start of the strip through the number dictated by the ‘X’ joystick value stored earlier.

Z Button: Turn off

The large ‘Z’ button turns off the entire strip.

This just calls the ‘clear’ function from earlier if the button is pressed. Nice and easy.

Z Button: Flicker

The smaller ‘C’ button makes the strip flicker.

The function takes a millisecond input of the total blinking period and flips a boolean every half period. If that boolean is true, the function clears the LEDs.

Writing to the Strip

At the end of the loop, the program updates the brightness and writes the LED data to the strip.


And just like that, I have a working LED controller from a Wii Nunchuk!


Here’s the full sketch. Click below to expand the code.

Conclusion

These are really cool little controllers, and they’re surprisingly easy to interface with (library or not). I have a thousand different ideas for how to use these things, and I hope this inspires you to use a Nunchuk in your own project.

My first ‘proper’ project with these is going to be replacing the DDR dance pad for my Nerf McCree controller. Stay tuned!


2018/6/22: This post was originally written using Kevin Harrington’s fork of the WiiChuck library, version 0.0.23. That library no longer works as well as it used to, so I’ve rewritten this using my own extension controller library.

7 Comments

  1. Thanks much for this article. Just ordered a wireless Nunchuk from eBay to replace the IR remote on one of my remixed EEZYbot robot arms. IR is OK, but too directional, and Arduino Bluetooth cheap controllers not ideal for a 4 axis robot. Can’t wait to try this, thanks again !

    rich942
  2. I’m trying to hook a Nunchuck up with an Arduino Nano but I can’t get the two to connect for the life of me. I have all the hardware connected properly, but I can’t get any data to show up on the serial monitor. I’ve tried multiple different libraries, and I still can’t get it to work. For your Nunchuk_DebugPrint example, I cannot get anything to appear over the serial bus besides, “Nunchuk not detected!”. I’m not getting any errors when compiling/uploading either.

    I’m using a generic Nunchuck made by a company called PowerA. I’ve also tried using an original white one too, but didn’t get any further. Am I not doing something right?

    ryan3473
    1. If you’ve tried multiple libraries that all don’t work then my guess is that your hardware *isn’t* connected properly. 3.3V to power, SDA to pin A4, SCL to pin A5, GND to GND. If you’re not using a breakout board, double-check your wiring using a multimeter.

      Generic / knockoff devices can potentially be more troublesome. If you’re having issues, I would try getting the genuine device working before the generic.

      Dave
  3. Thanks for creating this library! I recently came across an old Guitar Hero controller and after looking at several Wii controller libraries yours seems like the easiest to use and most responsive.

    My plan was to combine this controller with the Mozzi wavetable synthesizer library but when I load the two libraries they conflict…it appears that Mozzi blocks the i2c bus to better free up the processor for audio. I found a reference to this issue on their forums and they’ve written a utility that allows for i2c to run in a non-blocking way and they suggest replacing the Wire functions in the controller code with their non-blocking version, so that’s what I’m trying to do. Unfortunately, I’m not very strong in C++ (or i2c for that matter) so I’m a bit in the weeds and could use some advice. As far as I can tell, I’ll need to sub out the Wire library references in the NXC_Comms.h with Mozzi’s twi_nonblocking equivalent functions. Do you think I’m on the right track?

    Here’s what I’ve been referencing…the Mozzi utility is twi_nonblock:

    https://github.com/sensorium/Mozzi

    and a forum reference to the same issue:

    https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/mozzi-users/0YMdH0y0I1Q/91VT8YRYBgAJ;context-place=msg/mozzi-users/Kcq8we8wAek/9V31EDHM3lQJ

    Any advice would be appreciated.

    ectokon
    1. Hey there!

      It definitely sounds like you’re on the right track, although you’ll have your work cut out for you.

      From what I remember I collected all of the I2C functionality into that ‘comms’ header, so you should only need to edit that file. If you’re not importing the I2C library (Wire) at all you’ll also have to edit the preprocessor define at the top to provide an alternate object ‘type’ for the rest of the library. A reference to the I2C object is used elsewhere, but almost exclusively to pass back to the ‘comms’ functions for multiple bus support. The only exception to that is the initial ‘begin’ call (see ExtensionController.cpp). You can ignore the object in the functions, but it’s going to be easier to provide a dummy than it is to rewrite the function arguments everywhere.

      There are three delays used in the I2C functions that you’ll also have to account for – two for the initial ‘connect’ function (total of 30 ms) and one 200 us delay in the data update. If the guitar is the only input to the synth you can probably leave the ‘connect’ function as-is, but you’ll likely have to write some non-blocking time check code for the update function to make sure the read is spaced out. If you try to read the data too soon after requesting it the data will be corrupt.

      The good news is that if the Mozzi I2C implementation matches the Wire library in layout and functionality you shouldn’t have to mess with any lower level I2C stuff. Just make sure you do your due diligence testing the robustness of the non-blocking controller communications before you try adding the synth stuff on top.

      I’ve never used Mozzi myself so I can’t help there, but it sounds like a fun project. I hope that helps – let me know how it goes!

      Dave

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.