After building my little autonomous wanderer robot, I saw this iPad-controlled blimp and went ahead and added iPad control to my robot too. I had a Python script on my iMac which took commands from the iPad over Wifi and relayed them to the Arduino using XBee. I demo'ed this at BitNorth 2010, but I'm not sure if the video is up yet. That said, the fact that all the commands were relayed through a 'base station' bothered me, and I saw a cheap wireless Wii Nunchuk which I immediately bought, thinking I could make it into a really ergonomic remote control for my little robot. I probably could have gotten a Wifi shield instead, but I was up for a different kind of challenge.
The Wii Nunchuck (wired or wireless) communicates using the I2C protocol, which the Arduino supports quite nicely. There exists a cheap little hardware Arduino/Nunchuck interface but I had no use for the little white casing around the receiver that's supposed to plug into the WiiMote so I cracked it open and interfaced the little circuit board inside directly to my Arduino. After a lot of experimentation and reading of forum posts and wikis, I found a magic incantation of bytes to send to my particular Nunchuck that would enable me to pull data from it reliably, and I packaged it up into a little object-oriented Nunchuck library here. While I was at it, I also packaged up my Pololu motor controller interface code. The robot code sketch itself is on GitHub as well.
So after all this hardware and software work, I have remote-controllable wanderer robot! In the video above you can see that it's capable of autonomous and controlled modes. I used the joystick to control motion, the C button to stop and the Z button to turn on autonomous mode. It's pretty convenient to have a remote for a bot like this, so I can bring it back if it wanders underneath the bed, or turn it around if it gets stuck in a corner or something.
For reference, and because I want to try out my syntax highlighter plugin, here is the initialization code that works for my 'Intec' wireless Wii Nunchuck (look in GitHub at how I handle retrying after failing initialization):
void WiiChuck::init()
{
Wire.beginTransmission(0x52);
Wire.send (0xF0);
Wire.send (0x55);
Wire.endTransmission();
delay(30);
Wire.beginTransmission (0x52);
Wire.send (0xFB);
Wire.send (0x00);
Wire.endTransmission();
delay(30);
Wire.beginTransmission(0x52);
Wire.send (0xFA);
Wire.endTransmission();
delay(30);
Wire.requestFrom(0x52, 6);
boolean allFF = true;
int bytesReceived = 0;
while(Wire.available())
{
byte c = Wire.receive();
bytesReceived++;
if(c != 0xFF) {
allFF = false;
}
}
if(bytesReceived == 0)
{
return;
}
delay(30);
if(allFF)
{
delay(1000);
}
else
{
Wire.beginTransmission(0x52);
Wire.send (0xF0);
Wire.send (0xAA);
Wire.endTransmission();
delay(30);
Wire.beginTransmission(0x52);
Wire.send (0x40);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.endTransmission();
delay(30);
Wire.beginTransmission(0x52);
Wire.send (0x46);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.endTransmission();
delay(30);
Wire.beginTransmission(0x52);
Wire.send (0x4C);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.send (0x00);
Wire.endTransmission();
delay(30);
inSync = true;
}
}
⁂