Wii-Nunchuck Controlled Servo Motors

My previous project explored the accelerometer and gyroscope sensors in an MPU-6050 IMU chip, and showed how the data from both sensors could be combined for greater overall accuracy. While the project was interesting, the programming and data processing was too far above my kids’ heads for me to share with them.

I wanted to do a similar but simpler project that my kids would find interesting. It turns out that the Wii Nunchuck controller contains an accelerometer and the Wii Motion Plus controller contains a gyroscope sensor, both of which communicate over the I2C bus. I thought that it would be a fun, kid-friendly project to hack these controllers to manipulate some object in the real world. Fortunately, others have had this idea before me, and there are some well-documented projects online.

We decided to use a Wii controller to control a couple of servo motors. The components we used for this project were:

a WiiChuck Adapter – this allows easy communication between a Wii controller and an Arduino

Arduino Uno microcontroller and USB A-B cable for programming

Two small servo motors (small enough to be powered by the output of an Arduino Uno)

Breadboard and jumper cables

A Wii Nunchuck controller

Roll, pitch and yaw angles. An accelerometer can’t provide yaw data since the Z-axis is parallel to the force of gravity.

The first step was to obtain the data from the Wii controller. I’d initially wanted to use the Wii Motion Plus (WMP) controller and its gyroscope sensor, since a gyroscope sensor yields information about three rotational axes. Gyroscope sensor data, however, are prone to significant drift, which makes it difficult to consistently control a servo’s rotation angle over any significant time period.

So that left the Wii Nunchuck controller as the best option. The Wii Nunchuck contains a three-axis accelerometer from which we can compute rotation about two coordinate axes (pitch and roll, but not yaw). Accelerometers are prone to high-frequency noise from external forces and acceleration, but time averaging the data can help to eliminate some of the noise.

To get the accelerometer data, we hooked up the WiiChuck Adapter to the Nunchuck following the instructions here. It couldn’t be much easier. One end of the WiiChuck adapter fits nicely into the Nunchuck connector, and once you solder in four header pins to the WiiChuck, they plug directly into pins A2 through A5 on the Arduino Uno.

Simple setup to test the WiiChuck class.

The next step was to see what kind of data we were getting from the accelerometer in the Wii Nunchuck. The Arduino has a ready-made library for interfacing with a Wii Chuck adapter here: http://playground.arduino.cc/Main/WiiChuckClass. I installed the library and downloaded the sample program provided.

The WiiChuck class takes care of computing the pitch and roll data. The sample program below came directly from the Arduino.cc WiiChuckClass example and runs easily with the setup shown at right, with the Arduino Uno connected to a computer via the USB port.

The next step was then to add the servo motors to the setup and write a program to coordinate their movements with the Wii Nunchuck readings. The default Arduino IDE comes with a “Servo” class to make controlling servos easy. We got a breadboard and two servo motors. Each servo has three pins for power, ground, and control. We hooked up one servo control input to each of Arduino pins 10 (roll axis) and 11(pitch axis) since Arduino pins 9, 10 and 11 can provide the Pulse Width Modulation necessary to control servo rotation. A battery box with 4 AA batteries provided power. We adapted the sample code to control the servos. Note that the roll data runs from -90 to 90 degrees and the pitch data runs from 0 to 180 degrees while servo rotation angles are generally specified between 0 and 180 degrees. The code we used is below:

The program worked well, though I found that the servos showed a lot of jitter. The “pitch” servo was much more prone to the jitter than the “roll” servo. The code shows a few of steps we took to try to smooth the data out. We averaged the data over 5 readings before writing to the servos (averaging for longer smooths the data more but increases time lag in the servo response). We also rounded to the nearest 5 degrees and only wrote to the servos if the angle changed. In the end, none of these algorithms fully eliminated the servo jitter. I assume that it is partially due to my inability to produce smooth enough rotation about only a single axis when I move the Wii Nunchuck, partially due to noise in the accelerometer readings and partially a function of the servos. Still, even with the jitter, it is easy to see the correspondence between the motion of the Nunchuck and the servo motors in the video below:

One last thing. The coding for this project was pretty easy because we were able to use the “WiiChuck” and “Servo” classes from the Arduino libraries. If you would like a more in-depth understanding of exactly what is happening when we read the Wii Nunchuck data and when we tell a servo to move to a certain angular position, I strongly recommend reading the tutorial by Tod E. Kurt at: http://todbot.com/blog/2007/11/24/bionic-arduino-class-notes-3-4/. Click the “bionic_arduino_class_4.pdf” link for a more in-depth explanation and well commented sample code.

Hi, I’m trying to make a version of this using only one “roll” servo – I’m having the same problem as written above, where ” ‘chuck’ does not name a type” – I have successfully installed the Wiichuck.h library, so is the problem with the WiiChuck chuck = WiiChuck(); definition? The errors only occur when chuck. is written.

Are you sure your WiiChuck library files are installed in the correct location? Usually they go in a folder called ‘libraries’ inside the default folder for your Arduino sketches (as shown in http://arduino.cc/en/Guide/Libraries) It does sound like the compiler is not finding the source code for the “WiiChuck” class.

I downloaded the library from this link https://github.com/coopermaa/Wiichuck and it’s in the correct location, I am able to import it to the sketch. I basically skipped ahead to the last code written here. The error I’m getting is that chuck is not declared. Apologies, I’m very new to this! Do I need to install a different library? If so, does the code in the WiiChuckClass link above come as a zip file somewhere?

Hello Rachel,
take the following code and put it into the WiiChuck folder in the libaries folder.
Rename all the other WiiChuck.h to old or similar.
Greetings From Denmark Gregor

//-WiiChuck.h
/*
* Nunchuck — Use a Wii Nunchuck
* Tim Hirzel http://www.growdown.com
*
notes on Wii Nunchuck Behavior.
This library provides an improved derivation of rotation angles from the nunchuck accelerometer data.
The biggest different over existing libraries (that I know of ) is the full 360 degrees of Roll data
from teh combination of the x and z axis accelerometer data using the math library atan2.

It is accurate with 360 degrees of roll (rotation around axis coming out of the c button, the front of the wii),
and about 180 degrees of pitch (rotation about the axis coming out of the side of the wii). (read more below)

In terms of mapping the wii position to angles, its important to note that while the Nunchuck
sense Pitch, and Roll, it does not sense Yaw, or the compass direction. This creates an important
disparity where the nunchuck only works within one hemisphere. At a result, when the pitch values are
less than about 10, and greater than about 170, the Roll data gets very unstable. essentially, the roll
data flips over 180 degrees very quickly. To understand this property better, rotate the wii around the
axis of the joystick. You see the sensor data stays constant (with noise). Because of this, it cant know
the difference between arriving upside via 180 degree Roll, or 180 degree pitch. It just assumes its always
180 roll.

Hello,
I try to make a simpel gyro camera based on Your code.
My programming level is beginner.
So I like to ask how to run the servo revers of the nunchuck roll axis, like if nunchuck says 180 degrees the servo goes to 0 degrees.
Else the code works super. I tried to adapt it to a use on a attiny85 without succes, lack of my programming skills.
With greetings from Denmark
Gregor

Is it possible to control the servos with the stick on the nunchuck, so that when I push the stick to the left or right, one servo is controlled and when I push it up or down, the other servo is controlled? and if yes, how do I do it? Thanks in advance for the help! (Also this is my first project with coding something so I’m a beginner at this)