This will get used for a small boat project (not the big boat project I work on; something to help with testing things for it). Out in the street this is testing pretty good so I have high hopes. The boat will also have a GPS and return to near the launch area to get the signal back if it goes too far. Anyway, I know this walkthrough is little redundant as others have done similar ones, but I think this is about as simple as you can do it.
Transmitter costs about $4 and the receiver about $5 at SFE. These are 2400 baud, but you often find 4800 baud for a little more and/or ones that use 315MHz. The only difference is you would need to change the baud rate setting on both sides for a 4800.
I am using a Fio to transmit and a Pro Mini to receive. The Fio and Pro Mini each cost about $19.
A little Arduino programming tip is hidden in there also - note that I use elapsed time by calling millis() instead of doing a delay. The reason for that is I can add more processing into the loop and it won't affect the timing as long as I don't overload the processor. You can have lots of things firing at all sorts of different intervals somewhat independent of each other.
The NewSoftserial tx or rx Pin goes to the radio's data pin (just about any available digital pin will work), then power (VCC on the receiver, something between 5v and 12v on transmitter - more power = more range - I used 7.2v), GND and an antenna (scrap of wire about 7") complete it. If you do this on a mega with an available serial port, just replace RemoteTx with a reference to the Serial to use. Note that if you use NewSoftSerial and the Servo library, you may need to use Servo2 (search on Arduino boards to find out about that).
In the software, I send the letter U continuously when I have nothing else to send. It has a nice bit pattern that keeps things in sync. A few time a second I send a value,alternating between X, Y and B (buttons). I encode the number with some shifting and adding to keep it in the ascii range and make it easy to test for validity.
The packets of meaningful info are 3 bytes long. This is not a magic number but if you use long packets the error rate will rise and effective range will fall pretty quickly. If you don't feed it lots of nice clean transitions (the U character) regularly it tends to get lost after a few bytes. If you need to power off between infrequent transmissions to save power, be sure to let it spew some Us for a second or two before you send packets.
There are two projects with 2 files (tabs) each.
#include <NewSoftSerial.h>
NewSoftSerial RemoteTx(2,3);
#include "nunchuck_funcs.h"
int loop_cnt=0;
byte accx,accy,zbut,cbut;
int ledPin = 13;
void setup()
{
Serial.begin(19200);
RemoteTx.begin(2400);
nunchuck_setpowerpins();
nunchuck_init(); // send the initilization handshake
Serial.println("WiiChuckTx");
}
int iNxtTx = 0; // 0 = X, 1 = Y, 2 = B
unsigned long lastPosTx = 0;
void loop()
{
if( (millis() - lastPosTx) > 100)
{
nunchuck_get_data();
accx = nunchuck_accelx(); // ranges from approx 70 - 182
accy = nunchuck_accely(); // ranges from approx 65 - 173
zbut = nunchuck_zbutton();
cbut = nunchuck_cbutton();
byte iVal;
byte iCode;
switch( iNxtTx)
{
case 0:
iVal = nunchuck_joyx();
iCode = 'X';
break;
case 1:
iVal = nunchuck_joyy();
iCode = 'Y';
break;
case 2:
iVal = (nunchuck_zbutton() << 4) + nunchuck_cbutton();
iCode = 'B';
break;
}
RemoteTx.print(iCode, BYTE);
RemoteTx.print((iVal & 0xf) + 'a', BYTE);
RemoteTx.print((iVal >> 4) + 'a', BYTE);
iNxtTx++;
if(iNxtTx > 2)
iNxtTx = 0;
lastPosTx = millis();
}
else
{
RemoteTx.print('U', BYTE);
}
}
-----there is a second tab named nunchunk_funcs.h
/*
* Nunchuck functions -- Talk to a Wii Nunchuck
*
* This library is from the Bionic Arduino course :
* http://todbot.com/blog/bionicarduino/
*
* 2007 Tod E. Kurt, http://todbot.com/blog/
*
* The Wii Nunchuck reading code originally from Windmeadow Labs
* http://www.windmeadow.com/node/42
*/
#include <WProgram.h>
static uint8_t nunchuck_buf[6]; // array to store nunchuck data,
// Uses port C (analog in) pins as power & ground for Nunchuck
static void nunchuck_setpowerpins()
{
#define pwrpin PORTC3
#define gndpin PORTC2
DDRC |= _BV(pwrpin) | _BV(gndpin);
PORTC &=~ _BV(gndpin);
PORTC |= _BV(pwrpin);
delay(100); // wait for things to stabilize
}
uint8_t ctrlr_type[6];
// initialize the I2C system, join the I2C bus,
// and tell the nunchuck we're talking to it
static void nunchuck_init()
{
byte cnt;
Wire.begin();
// init controller
delay(1);
Wire.beginTransmission(0x52); // device address
Wire.send(0xF0); // 1st initialisation register
Wire.send(0x55); // 1st initialisation value
Wire.endTransmission();
delay(1);
Wire.beginTransmission(0x52);
Wire.send(0xFB); // 2nd initialisation register
Wire.send(0x00); // 2nd initialisation value
Wire.endTransmission();
delay(1);
// read the extension type from the register block
Wire.beginTransmission(0x52);
Wire.send(0xFA); // extension type register
Wire.endTransmission();
Wire.beginTransmission(0x52);
Wire.requestFrom(0x52, 6); // request data from controller
for (cnt = 0; cnt < 6; cnt++) {
if (Wire.available()) {
ctrlr_type[cnt] = Wire.receive(); // Should be 0x0000 A420 0101 for Classic Controller, 0x0000 A420 0000 for nunchuck
}
}
Wire.endTransmission();
delay(1);
// send the crypto key (zeros), in 3 blocks of 6, 6 & 4.
Wire.beginTransmission(0x52);
Wire.send(0xF0); // crypto key command register
Wire.send(0xAA); // sends crypto enable notice
Wire.endTransmission();
delay(1);
Wire.beginTransmission(0x52);
Wire.send(0x40); // crypto key data address
for (cnt = 0; cnt < 6; cnt++) {
Wire.send(0x00); // sends 1st key block (zeros)
}
Wire.endTransmission();
Wire.beginTransmission(0x52);
Wire.send(0x40); // sends memory address
for (cnt = 6; cnt < 12; cnt++) {
Wire.send(0x00); // sends 2nd key block (zeros)
}
Wire.endTransmission();
Wire.beginTransmission(0x52);
Wire.send(0x40); // sends memory address
for (cnt = 12; cnt < 16; cnt++) {
Wire.send(0x00); // sends 3rd key block (zeros)
}
Wire.endTransmission();
delay(1);
// end device init
}
// Send a request for data to the nunchuck
// was "send_zero()"
static void nunchuck_send_request()
{
Wire.beginTransmission(0x52);// transmit to device 0x52
Wire.send(0x00);// sends one byte
Wire.endTransmission();// stop transmitting
}
// Encode data to format that most wiimote drivers except
// only needed if you use one of the regular wiimote drivers
static char nunchuk_decode_byte (char x)
{
x = (x ^ 0x17) + 0x17;
return x;
}
// Receive data back from the nunchuck,
// returns 1 on successful read. returns 0 on failure
static int nunchuck_get_data()
{
int cnt=0;
Wire.requestFrom (0x52, 6);// request data from nunchuck
while (Wire.available ()) {
// receive byte as an integer
nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());
cnt++;
}
nunchuck_send_request(); // send request for next data payload
// If we recieved the 6 bytes, then go print them
if (cnt >= 5) {
return 1; // success
}
return 0; //failure
}
// Print the input data we have recieved
// accel data is 10 bits long
// so we read 8 bits, then we have to add
// on the last 2 bits. That is why I
// multiply them by 2 * 2
static void nunchuck_print_data()
{
static int i=0;
int joy_x_axis = nunchuck_buf[0];
int joy_y_axis = nunchuck_buf[1];
int accel_x_axis = nunchuck_buf[2]; // * 2 * 2;
int accel_y_axis = nunchuck_buf[3]; // * 2 * 2;
int accel_z_axis = nunchuck_buf[4]; // * 2 * 2;
int z_button = 0;
int c_button = 0;
// byte nunchuck_buf[5] contains bits for z and c buttons
// it also contains the least significant bits for the accelerometer data
// so we have to check each bit of byte outbuf[5]
if ((nunchuck_buf[5] >> 0) & 1)
z_button = 1;
if ((nunchuck_buf[5] >> 1) & 1)
c_button = 1;
if ((nunchuck_buf[5] >> 2) & 1)
accel_x_axis += 2;
if ((nunchuck_buf[5] >> 3) & 1)
accel_x_axis += 1;
if ((nunchuck_buf[5] >> 4) & 1)
accel_y_axis += 2;
if ((nunchuck_buf[5] >> 5) & 1)
accel_y_axis += 1;
if ((nunchuck_buf[5] >> 6) & 1)
accel_z_axis += 2;
if ((nunchuck_buf[5] >> 7) & 1)
accel_z_axis += 1;
Serial.print(i,DEC);
Serial.print("\t");
Serial.print("joy:");
Serial.print(joy_x_axis,DEC);
Serial.print(",");
Serial.print(joy_y_axis, DEC);
Serial.print(" \t");
Serial.print("acc:");
Serial.print(accel_x_axis, DEC);
Serial.print(",");
Serial.print(accel_y_axis, DEC);
Serial.print(",");
Serial.print(accel_z_axis, DEC);
Serial.print("\t");
Serial.print("but:");
Serial.print(z_button, DEC);
Serial.print(",");
Serial.print(c_button, DEC);
Serial.print("\r\n"); // newline
i++;
}
// returns zbutton state: 1=pressed, 0=notpressed
static int nunchuck_zbutton()
{
return ((nunchuck_buf[5] >> 0) & 1) ? 0 : 1; // voodoo
}
// returns zbutton state: 1=pressed, 0=notpressed
static int nunchuck_cbutton()
{
return ((nunchuck_buf[5] >> 1) & 1) ? 0 : 1; // voodoo
}
// returns value of x-axis joystick
static int nunchuck_joyx()
{
return nunchuck_buf[0];
}
// returns value of y-axis joystick
static int nunchuck_joyy()
{
return nunchuck_buf[1];
}
// returns value of x-axis accelerometer
static int nunchuck_accelx()
{
return nunchuck_buf[2]; // FIXME: this leaves out 2-bits of the data
}
// returns value of y-axis accelerometer
static int nunchuck_accely()
{
return nunchuck_buf[3]; // FIXME: this leaves out 2-bits of the data
}
// returns value of z-axis accelerometer
static int nunchuck_accelz()
{
return nunchuck_buf[4]; // FIXME: this leaves out 2-bits of the data
}
All it does right now is print the received values to the serial port, but I think/hope you could figure out what to do with them from there.
That's it.
It is a real working example about to placed into service.