The Spideruino’s Controller
One of the hardest things for me to wrap my mind around in building the Spideruino was the way XBee worked. It was actually way too simple, and I wasted a long time trying all this complicated stuff to get it to send and receive data. I have put together a little post for anyone else trying to use the Joystick Shield with XBee.
When I first approached the problem of getting it to send commands to the robot, my gut reaction was to send a comma separated string representing the values from the controller. So I tried sending:
512,512,0,0,0,0,0
x,y,button1,button3,button3,button4,button5
This was super inconvenient, because I had the receiving xbee watching for the commas as they came into the buffer… Not nice stuff. I was missing one key thing – XBee radios send BYTES. While they can represent characters, I found it was easiest to think of them as neat little numbers. So instead of sending that first number as ‘512’ (which is actually sent as 3 bytes 5,1,2) I just mapped the joystick values to byte(-10) to byte(10) and sent that instead. Only 1 byte to get!
This was one big breakthrough. So all I had to do was send out 7 bytes, 1 per input, -10 to 10 for analog sticks and 0 or 1 for buttons.
But there was another problem. If I just had the thing spew out all those bytes in a loop, how would the robot know if the stuff it was getting was worth a damn? If I turn on the controller first, then the robot could get the 4th byte and think it was first, which would not work.
The solution is to have the two XBees in question sort of handshake first. In the Spideruino’s case, when it starts up, it just idles and sends out a byte until it gets a byte back from the controller. Once they perform this handshake, the controller sends out it’s 7 bytes. So the logic is like this
Robot requests joystick data – > Joystick sends out 7 bytes -> Rinse and repeat.
If the controller does not respond, the robot just does nothing. UNLESS it is already running autonomous mode, in which case, it goes about it’s business.
Here is the controller code – feel free to adapt it for your own RC goodness! I hope that someone else who is trying to use the Sparkfun Joystick Shield with XBee would find this to be helpful. I think that XBee is a pretty rad RC system 🙂
You can download the Arduino file here. The robot’s code is on there too.
/*
Simple XBee Joystick
By Agustin M. Sevilla
Parts list:
Arduino Uno
Sparkfun XBee Shield + Series 1 Xbee
Sparkfun Joystick Shield
Sends out all joystick data as a series of 7 bytes, 1 for each of the controllers inputs.
Used as controller for the Spideruino.
*/
const byte ROBOT_REQUEST = byte(255);
const byte PIN_ANALOG_X = 1;
const byte PIN_ANALOG_Y = 0;
const byte btn_d2 = 2;//Thumbstick button
const byte btn_d3 = 3;
const byte btn_d4 = 4;
const byte btn_d5 = 5;
const byte btn_d6 = 6;
void setup() {
Serial.begin(9600);
pinMode(btn_d2, INPUT);
digitalWrite(btn_d2, HIGH);
pinMode(btn_d3, INPUT);
digitalWrite(btn_d3, HIGH);
pinMode(btn_d4, INPUT);
digitalWrite(btn_d4, HIGH);
pinMode(btn_d5, INPUT);
digitalWrite(btn_d5, HIGH);
pinMode(btn_d6, INPUT);
digitalWrite(btn_d6, HIGH);
//Delay startup by a little
delay(1000);
}
void loop() {
//The Controller waits to receive a byte (ROBOT_REQUEST) from the Spiduino before sending the commands.
if (Serial.available() > 0) {
byte command = Serial.read(); //store data into byte command from serial
Serial.flush(); //Clear Any incoming serial data
if (command == ROBOT_REQUEST) { //The robot is requesting that data be sent. Return Joystick Values.
printToSerial(map(analogRead(PIN_ANALOG_X), 0, 1023, -10, 10));
printToSerial(map(analogRead(PIN_ANALOG_Y), 0, 1023, -10, 10));
printToSerial(interpretDigitalButton(btn_d2));//THUMBSTICK BUTTON
printToSerial(interpretDigitalButton(btn_d3));//"RIGHT" BUTTON
printToSerial(interpretDigitalButton(btn_d4));//"UP" BUTTON
printToSerial(interpretDigitalButton(btn_d5));//"DOWN" BUTTON
printToSerial(interpretDigitalButton(btn_d6));//"LEFT" BUTTON
delay(100);
}
}
}
/*
This function returns a char,
which can be passed via xbee as one byte.
Char is a signed byte: value be within -127 and 127
*/
void printToSerial (int val) {
char c = val;
Serial.print(c);
//Serial.print(separator);
}
/*
This function sends a byte as well, but it is "boolean"
0 for button not pushed and 1 when pushed.
*/
int interpretDigitalButton(byte pin) {
if (digitalRead(pin) == LOW) {
return 1;
} else {
return 0;
}
}
Comments