Sunday, September 27, 2009

XBee woes..

As I mentioned in my last post, I also procured a couple of XBee's and the XBee shield. I don't exactly know what the big idea with that shield is, as it really is a pain. In three ways:
  1. The CTS pin is hardwired to the reset-pin of the Arduino. You'd think that would be prominently displayed, but it isn't.
  2. It uses the same Serial as the USB. I have the Mega, so it might have more serials than the other Arduino's, I havent checked. (That would be the only reason I can see for doing this)
  3. It only connects a few of the pins.

Before I go on, I think I should explain my setup here, as it may to be crystal clear from the text alone..


  1. Arduino + XBee Shield + XBee (EndPoint), connected to COM4
  2. XBee Explorer + XBee (Coordinator), connected to COM5
  3. (Note to self: use bigger fonts)

So. Annoyance #1, the CTS-pin. That one threw me for a loop for a few hours. I have the XBee EndDevice on the Arduino (XBee ZB EndDevice, firmware 2x64). The Xbee ZB Coordinator is connected to my laptop, on the XBee Explorer. I uploaded the example sketch from Arduino "PhysicalPixel", which simply turns the LED on pin 13 off and on with the reception of a H or L on the serial-port.

With the default AT-firmware, I can now open the com-port where the XBee Coordinator is, set the DH/DL registers to the address of my EndDevice, and send H's and L's, observing the miracle that is a wirelessly transmittet blinking LED. Big Whoop.

This was, in itself, quite the little victory for me. Only, when the LED was on, I would ofcourse sit back and marvel at this little light (harbouring thoughts which included the words "evil" and "genious"). Only to observe that it turns itself off! For no reason what so ever! The code is so simple that it can not be a bug. So what is going on??

This is when Annoyance #2 hit me. Since the XBee and the USB FTDI shares the same serial-port, you must choose which one wins. This is done with a couple of jumpers, but it means that you can't simply add a few lines of code to the arduino to make it phone home with what is going on. Which makes it annoying to debug..

The "cure", so to speak, is exceedingly simple, at least on the Arduino Mega. Pull off the jumpers, connect the middle pin on each of the two jumpers to pin 18 and 19 on the arduino. It will then use Serial1 (as denoted in the Arduino GUI), instead of Serial, which allows you to fill your code up with "Serial.write("Hello");", and understand what is going on. (I simply use two instances X-CTU, on each of COM4 and COM5.)

(Note that in the picture I've left the jumpers connected to one pin, so I don't loose them. The blue socket is connected to the middle of the three pins, although it doesn't look that way in the photo..)

Very helpful, that.

Anyway, turns out the solution for Annoyance #1, Mysteriously Resetting Arduino is also extremely simple. When using X-CTU to configure your EndDevice, simply set IOD7=0 (or use ATD7=0, same thing). The XBee will no longer reset your Arduino simply because it wants to sleep.

Now, Annoyance #3. This one really occured to me while playing with this. Finally solving the two previous issues, I made a small program to let me connect to the EndDevice XBee on the Arduino through the USB-port. Very simple, read a byte from Serial, send it to XBee on Serial1. This way I could verify that the Arduino got the transmissions from the XBee Coordinator (by watching the Magic LED), and I could also enter command mode on the XBee EndDevice without pulling it off the XBee Shield.

This in itself was easy enough, but I noticed that the Xbee EndDevice, when sleeping, would not wake up from data on the serial-line (i.e. from the AVR). I don't know why. When I first sent something on the wireless side, it would wake up. As long as its awake, "talking" to it through the Arduino works just fine, but it will eventually go to sleep.

So. Another small "adustment" to the Xbee shield. First of all, I enabled Sleep Mode 5 (ATSM5) on the EndDevice. This sleepmode allows the microcontroller to wake the Xbee through pulling pin 9 (SleepRQ) on the XBee low. Fancy. Only, Pin 9 isn't connected anywhere on the Arduino! Annoying. Also, the XBee is 3.3v, while the Arduino Mega is 5v.

I "solved" this by soldering a 1.4Kohm resistor between pin 9 on the Xbee-socket and Pin 7 on the Arduino. Now, when I send anything on Serial (i.e. USB connected to my laptop), it pulls pin 7 (connected to pin 9 on XBee), low. This causes the XBee to wake up, and it is under my command. World domination must start somewhere, and I now consider myself well on the way.

A picture for the curious:



In case you're wondering why I chose a 1.4Kohm resistor, here's why:

  • The Arduino is 5v, the XBee is 3.3v
  • The XBee can sink maximum 4mA
  • The Internet told me 5V through 1.4Kohm equals 3.57mA. So won't fry the XBee.

So, in conclusion.. I now have a setup which allows me to

  1. Send random crap from my laptop, through the XBee Coordinator in COM4, to the Arduino.
  2. The Xbee EndDevice does not randomly reset my Arduino
  3. The Arduino can phone home over COM5 to my laptop.
  4. The Arduino can set a LED, in order to let me know it receives the stuff I send to it wirelessly (and because you have to have a LED)
  5. I can send AT-commands to the XBee EndDevice through the Arduino on COM5.
  6. The Arduino will wake the XBee up, so that it will Obey My Command.

Here's my Sketch:

/*

Hardware-mods:
- Pin 9 on XBee connected through 1.4Kohm resistor to pin 7 on Arduino (Any pin, allows arduino to control sleeping on XBee)
- XBee RX connected to pin 19 (RX1) on Arduino (Allows Arduino to phone home on USB-serial, for easy debugging)
- XBee TX connected to pin 18 (TX1) on Arduino (Ditto)

XBee config-changes (from default):
SM=5 (If not using the Sleep_RQ pin, set SM=0, and use Router firmware)
D7=0 (CTS on XBee is hardwired to reset pin of Arduino. When XBee sleeps, Arduino resets.)

My setup
Coordinator connected to COM5 on USB XBee Explorer
Arduino connected through USB to COM4, XBee EndDevice on XBee Shield.

Why?
To play with the EndDevice XBee and try to work out what's going on! Send H or L through the XBee connected
to the XBee Explorer (i. e. Coordinator) and watch the LED change, as if by magic! Send AT-commands through
the COM-port connected to the Arduino to see what the EndDevice is playing at, reconfigure parameters etc.
*/

const int ledPin = 13; // the pin that the LED is attached to
const int sleepPin = 7; // Connected to SleepRQ on the XBee, SM=5

int incomingByte; // a variable to read incoming serial data into

int graceperiod = 5000; // Milliseconds to wait before allowing XBee to sleep, to make sure no more data incoming on USB serial
unsigned long timeout = 0;
boolean sleeping = true;

void setup() {
// initialize USB serial communication:
Serial.begin(9600);

// Initialize XBee comms
Serial1.begin(9600);

// Say hello.
Serial.write("Hello.");

// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);

// Pin7 now connected to Sleep_RQ
pinMode(sleepPin, OUTPUT);

// Xbee sleep
digitalWrite(sleepPin, HIGH);
}

void loop() {

// see if there's incoming serial data from XBee:
while (Serial1.available() > 0) {

// read the oldest byte in the serial buffer:
incomingByte = Serial1.read();

// Echo back to USB
Serial.write(incomingByte);

// if it's a capital H or h, turn on the LED:
if ((incomingByte == 'H') (incomingByte == 'h')) {
digitalWrite(ledPin, HIGH);
}

// if it's an L or l, turn off the LED:
if ((incomingByte == 'L') (incomingByte == 'l')) {
digitalWrite(ledPin, LOW);
}
}

// Data from USB is echoed to XBEee
while(Serial.available() > 0){

// If sleeping, set sleepPin high and wait for XBee to wake up
if(sleeping == true){
digitalWrite(sleepPin,LOW);
sleeping = false;
delay(500); // Pick a number..
}

// A character was received, renew timeout
timeout = millis() + graceperiod;

// Send data to XBee
Serial1.write(Serial.read());
}

// Put XBee back to sleep, after graceperiod (to make sure no more keypresses are incoming)
if((sleeping == false) && (millis() >= timeout)){
digitalWrite(sleepPin, HIGH);
sleeping = true;
}
}

No comments:

Post a Comment