We used the Wiimote’s IR tracking capability and Bluetooth to wirelessly control a robotic crane arm. The Wiimote is a powerful gadget and we wanted to build a new hack with it. Our crane is composed of three servo motors, one of which is connected to a gripper. The servos are controlled by PWM signals sent by the Mega32 MCU, and these signals are generated from parsing the received IR data from a serial connection with a Macbook wirelessly connected through Bluetooth to the Wiimote.
II. High level design
After watching some of Johnny Chung Lee’s videos on Wiimote hacks(http://www.cs.cmu.edu/~johnny/projects/wii/), especially the infrared tracking video, we were inspired to create our own Wiimote application. Our first idea was to track points using two Wiimotes in 3-d, but the difficulty of getting just one Wiimote to work scratched that idea. We decided to use the remote to track infrared points and use this data to control a crane composed of three servos with a gripper.
There wasn’t any extremely challenging math involved in our project. We needed to understand how the Wii’s IR camera worked and also needed to be good at PWM signals for the servo motors. We also needed some basic circuit design skills for building the LED array. The explanations for these concepts come up in the later sections of this report.
We needed to generate three PWM signals to control the three servo motors. Only two timers on the Mega32 have PWM capabilities (Timer0/Timer2), so we had to manually generate a PWM signal, which sacrificed some accuracy on our timing. Fortunately the servo doesn’t have to be in a precise position for the crane to work, it only has to be roughly controllable.
Relation to Standards and Intellectual Property
Our project uses the Bluetooth wireless protocol, which is a built-in feature of the Macbook as well as the Wiimote. The Wiimote was designed by Nintendo, though I haven’t found a patent for the Wiimote itself. We do not intend to commercialize our design so this should not be an issue.
III. Program/hardware design
Timers and PWM
We use three timers to set up the PWM signals used in this project. For timer0 and timer2 we run them on full PWM mode with the prescalar set so they run at clk/1024 = 15.625 KHz. Since they are 8-bit timers they overflow with a period of roughly 16ms. We use this period as one PWM cycle and set OCR0 (or OCR2) to vary the width of the pulse. Timer 1 is set to clear on match mode running at 5KHz. In the timer1 compare match interrupt we set up a custom PWM signal to control the gripper servo. The hardest part of setting up the PWM signals was configuring the servos to be in the correct position and varying the pulses to the right degree to move the servo arm where we wanted it.
Parsing/Porting Wiimote Data
The Wiimote has two types of sensors: accelerometers and an infrared camera. With these two devices, the players communicate with the main console via Bluetooth. In our project we use the infrared camera and its ability to track an infrared source’s x-y coordinates within the Wiimote’s plane of view. A Wiimote view is 41° in x direction and 31° in y direction.
Communicating between the Wiimote and the MCU is established through the USB serial RS232 input using the serial UART receive/transmit feature on the Mega32. Here we only use the receive portion on the microcontroller to receive the Wiimote’s IR data from a MacBook. We use the MacBook to port the Wiimote’s IR data since MacBook has Bluetooth functionality built in, and by downloading a Wiimote driver on the MacBook (open source driver DarwiinRemote), we extract the IR data from the Wiimote and send it through the USB-to-serial connection
Within the DarwiinRemote application, the package includes a WiiRemote.framework, which is the binary for the WiiRemote library on the Macintosh. After downloading the application and the WiiRemoteFramework library source code from Source forge, with the XCode IDE we are able to locate where IR data and button status data are in the source code, open a serial port by calling the open serial port C code acquired from the Apple Developer website, and write data to the USB to serial connection located on the dev port of the MacBook hardware. Within the DarwiinRemote application, the x-coordinate IR data ranges from 0 to 1023 and y-coordinate IR data ranges from 0 to 767. If the WiiRemote sees no IR source, then the x and y IR data values are both 1023. These values are important for servo calibration control. The serial port code serialPort.c includes various functions, but the main functions we used were serialPort (int x, int y), OpenSerial (bsdPath) (internally called by serialPort), and InitializeModem (int x, int y, int pressed). When opening a serial port, the user can specify if the port is open for transmit or receive, blocking or nonblocking, and set for the existence of a control terminal. Here we set up the port as write only (since we are only sending data to MCU), nonblocking, and no controlling terminal. The serial port C code lets the user set the baud rate, data packet size, number of parity bits, and number of stop bits. We configure this to our regular hyper terminal settings at 9600 baud, 8 data bits, no parity bits, 1 stop bit, and no flow control.
For porting the x, y, and button data to the serial port, we first convert the x and y data from integer to string using sprintf and store them in buffers. For the A button, there is a defined array called buttonState, along with a define macro WiiRemoteAButton, where WiiRemoteAButton acts as a index into the buttonState array and will be set to predefined macro value YES if button is pressed. We define a local variable integer pressed to be set high whenever buttonState[WiiRemoteAButton] equals to YES within the WiiRemoteFramework source code. We then write this value to a string buffer and send the button data along with the x and y IR data every time we communicate with the serial port. Finally to terminate every set of data sent, we send a carriage return (“\r”) to the serial port so the MCU will know when a set of data completes transmission.
On the MCU side, we initialize the serial UART RX/TX capability in the initialize() function by setting UBRRL and UCSRB to the appropriate baud rate and enable serial USB receive. On the hardware side, we have to connect jumper RX/TX to pin D.0 and pin D.1 to enable receive. The receive interrupt will then be triggered after every incoming string character. The UDR_RXC interrupt will be called, and within the interrupt we place the data in its respective buffer array (x, y, or button data).
Using the IR data
An extremely challenging part of our project was figuring out how to translate the XY coordinates from the Wiimote to pulse widths for the servo motors. For the x-coordinates we set up a system where every 50 pixel range of points corresponded to one pulse width and we limited the motion of the servo to a change of one “pulse width” or one value of OCR0 per call of the compare_x function. For the y-coordinates we segmented the points into three positions, one for upwards movement, one to stay stationary, and one for downwards movement. The gripper servo has a specific sequence of pulses that is triggered each time the A button on the Wiimote is pressed. The gripper pulses slowly open and then close the gripper.
We built the custom Mega32 board exactly as described on the ECE 476 website (http://www.nbb.cornell.edu/neurobio/land/PROJECTS/Protoboard476/index.html).
The hardware used for this project wasn’t extremely complicated, but required several parts that have to work together. To provide infrared light that the Wiimote could track we built several IR led arrays. In the appendix there is a schematic for an LED array. The array has a 12V source connected in series with a 75 Ohm resistor and 8 LEDs. Each LED is rated for a forward voltage drop of 1.2V so 8 LEDs is a total drop of 9.6V. With a 12V source there should be a 2.4V drop over the 75 Ohm resistor, drawing 32mA of current. The LEDs are rated for 20mA with a maximum of 50mA so this array configuration should be fine.
Since we were using noisy motors we had to make sure the ground paths for the MCU and servo were not shared. Similar to Lab 3 we used 4N35 optoisolators to separate the two sides of the circuit. On the MCU side of the circuit we have a 330 Ohm resistor connected to the diode on the 4N35. On the motor side the base of the transistor is connected to ground through a 1MOhm resistor, the emitter is connected to the control line of the servo as well as to ground through a 10KOhm resistor. The collector is connected to 5V Vcc (separate from MCU).
To build the crane we mounted the arm servo to a piece of wood for a base and nailed a another piece of wood to the horn of the servo for the rotating arm. At the end of the arm is the continuous rotation servo that raises and lowers the gripper. We tied the gripper hardware to the horn of this servo with some string. The gripper as well as the gripper control servo hangs from the bottom of the string.
Servo PWM control
A servo motor is controlled by a pulse-width modulated signal (PWM) that tells its arm which position to be in. Generating these signals is fairly straightforward using the timers on the Mega32, though we had to ensure all three of our PWM signals were accurately timed. Below is a basic diagram of a PWM signal. There is a shorter pulse of voltage Vcc at the start of the pulse while the total pulse has a period of 20ms (though this has some tolerance). For two of our servos we used a 16 ms pulse, for the other we used a 20ms pulse. The difference was only due to the timers we used to set up the pulses.
Price per unit
|6 inch solder board||2.50||1||2.50|
|Small solder board||1.00||4||4|
|Custom PC Board||5.00||1||5.00|
|2 pin flat jumper cables||1.00||3||3.00|
|Standard Servo (R276-S03N)||10.90||2||21.80|
|LED – LTE-4208||0.18||32||5.76|
|Wood + Wood glue||2.00||1||2.00|
Total = $70.56
For more detail: Wiimote Crane Using Atmega32