Feb 6, 2010

Programming the Wiimote in Ubuntu

This post has been a long time in coming, but I finally got up off my ass and decided to figure out how to code using a Wiimote in Ubuntu.

First, you need a Wiimote (obviously). Note that you don't actually need a Wii to do this, you can just head on down to Future Shop or whatever and grab a Wiimote. It should still work.
Second you need a Bluetooth adapter. I've got a RocketFish micro-dongle thing which works just fine, I'll leave it to you to find something for your machine.
Third, I'm going to assume you have Bluetooth working on your computer, otherwise there isn't much hope for you since the Wiimote is a Bluetooth device.

Let's start by grabbing the required libraries. In Ubuntu you can go:
sudo apt-get install lswm libcwiid1-dev libbluetooth-dev wmgui
To test to see if your adapter can detect the Wiimote, just run this command and press the 1 and 2 buttons:
lswm
If it displays a bunch of hex characters, then your Wiimote has been detected and you're set to go. If it doesn't display it right away and the LEDs are still flashing on the Wiimote, run it again since lswm doesn't wait very long and you might have missed it.

You can also test it out using wmgui, which basically shows you all the various sensors the Wiimote has in it. This includes the buttons, accelerometer and IR sensor. It's pretty easy to get it going, the only issue comes when you want to start using the IR. Since Wii sensor bar is actually just a bunch of infrared LEDs, you just need an IR light source. Unfortunately since the Wii bar doesn't plug into my computer (it has some weird plug that connects to the Wii), I went with something simpler - a candle. If you actually start programming using the IR it'd probably work better if you used two candles so that you can detect the orientation of the Wiimote, but it still works fine with one.

Now let's get to some code! I'll be using C with gcc. There's a Python version of this library but I haven't tested it and don't know how it works.
First, we include the needed libraries:
#include <bluetooth/bluetooth.h>
#include <cwiid.h>
We then set up the various structs we need to interact with the Wiimote:
bdaddr_t bdaddr = *BDADDR_ANY;
cwiid_wiimote_t * wiimote = NULL;
We obviously need a cwiid_wiimote_t struct in order to call functions on it, we also need the bdaddr_t struct to give us the Bluetooth code for the Wiimote (remember those hex digits that lswm printed out?).

Next we set up the Wiimote. Normally you would wrap these up in if statements for error checking, but I'm going to leave those out for clarity:
/* Connect to the Wiimote - the CWIID_FLAG_MESG_IFC
means that we want to use a callback method for
interacting with the device */
wiimote = cwiid_open(&bdaddr, CWIID_FLAG_MESG_IFC);

/* Now we register a callback. I'll define this later. */
cwiid_set_mesg_callback(wiimote, &wii_callback);

/* Set the reporting mode. This says which messages we want
to receive in our callback. Let's only get buttons for now. */
cwiid_set_rpt_mode(wiimote, CWIID_RPT_BTN);
Then we define our callback function. I'll just make it so that when you press B the program will quit:

void wii_callback(cwiid_wiimote_t * wiimote, /* The Wiimote struct */
int msg_count, /* The number of messages received */
union cwiid_mesg msgs[], /* The messages themselves */
struct timespec * timestamp /* The timestamp of the callback */){
int i;
for (i = 0; i < msg_count; i++){
if (msgs[i].type == CWIID_MESG_BTN){
if (msgs[i].btn_mesg.buttons & CWIID_BTN_B){
printf("B button pushed!\n");

/* Close the connection to the Wiimote and quit */
cwiid_close(wiimote);
exit(0);
}
}
}
}
The way the callback works is that it sends you an array of messages that happened. The message is a union of different types of messages, determined by the type field. For the button message, it includes an integer that for each bit it says whether or not each button is pushed. There are many other types of events, you can check it all out by browsing the cwiid source code (in Ubuntu it installs to /usr/include/cwiid.h) and by looking at the cwiid docs. Have fun playing with the Wiimote!

If you want to enable other functions, you just use a binary OR for the reporting mode:
/* Enable the buttons, accelerometer, and nunchuk */
cwiid_set_rpt_mode(wiimote, CWIID_RPT_BTN | CWIID_RPT_ACC | CWIID_RPT_NUNCHUK);

No comments: