Friday, January 27, 2012

Wireless Remote Sensing with Arduino and Zigbee

In "Remote Sensing with Arduino", part of my Amigo project, I described how to access light and temperature sensors on an Arduino board over Ethernet via a web server. In this article I'll describe how I've taken the same basic sensor platform and am now accessing it wirelessly via XBee radios.

Xbee is a family of tiny radios made by Digi International and based on Zigbee, the IEEE 802.15.4 standard for personal area networks (PAN) that are characterized by low power (one milliwatt), short ranges (about one hundred feet), and a pretty sophisticated network stack. Zigbee is capable of implementing a wireless mesh network, but the radios and firmware I am using in this application do something much simpler, so simple in fact that it requires no configuration and works right out of the box: a 9600 baud wireless serial connection.

I did this using a SparkFun Xbee Wireless Kit. The kit includes two XBee 2.4 gigaHertz series 1 radio modules, an XBee Arduino shield (some assembly required, so I had to break out the soldering iron to attach the Arduino headers), and an XBee Explorer. The Explorer is a tiny board with a socket for the radio module and an FTDI chip that performs the serial to USB conversions. The Explorer implements the PC/Mac end of the wireless serial connection. The Explorer requires the FTDI Virtual COM Port (VCP) drivers be installed on your PC or Mac. (I've written of my affection for FTDI and the quality of their products before, in "Deconstructing the AR.drone: Part 5".)

Below you can see the new setup. The breadboard at the top has exactly the same sensor setup as before. The Ethernet shield has been replaced on the Arduino board with the red XBee shield. The blue XBee radio module is plugged into a socket on the top of the shield. Jumper wires for power, ground, and the two sensors are plugged into the headers on top of the shield just as they were on the Ethernet shield. The Explorer is to the left with its own blue XBee radio module and a USB cable connecting it to my Mac. Note that there is no USB connection from the Arduino to my Mac; that's just a power cable from a wall wart powering the Arduino board. You could also power the Arduino side with something as simple as a nine volt transistor radio battery.

XBee Explorer and Arduino

Here's a side view where you can see the power cable coming into the Arduino, with the XBee shield plugged in on top of it similar to the Ethernet shield.

Arduino and XBee Shield

Here's a closeup of the XBee shield. Near the lower right on the shield you might be able to see a tiny silver surface-mounted slider switch, so small you need a something like a toothpick to throw it. The switch has two positions, labelled DLINE, in which you can load your Arduino board over its USB cable just as you normally would, and UART, in which the XBee hijacks the serial pins on the Atmel ATmega328 so that, for example, whatever your software displays over the microcontroller's serial port goes across the wireless XBee channel instead of the USB cable.

XBee Shield with XBee Module

And here's a closeup of the XBee Explorer. It is powered completely off the USB cable connected to my Mac. Although the XBee modules can be configured to do different things, right out of the box they implement a wireless serial connection and automatically pair with one another. Digi refers to this as transparent mode. Under the hood however, the radios are implementing a peer-to-peer network based on a Carrier Sense Multiple Access/Collision Avoidance (CSMA/CA) model.

XBee Explorer with XBee Module

So I loaded the FTDI drivers onto my Mac and restarted it. I plugged the USB cable from the XBee Explorer into my Mac and verified that a new serial device, /dev/tty.usbserial-A800f3aA, showed up. I hooked up the Arduino to its USB cable and downloaded my program over its own serial device, /dev/tty.usbmodem26431. I brought up the serial monitor tool in the Arduino IDE and verified that I was printing sensor values. I plugged in the power cable to the Arduino and removed the USB cable. I flipped the tiny switch on the XBee shield from DLINE to UART. I brought up the Arduino serial monitor tool again, this time using the Serial Port option in the IDE's Tools pull down menu to specify the new serial device from the XBee Explorer. And this is what I saw.

Screen Shot: XBee Wireless Serial Port

No, it is not 30.55°F in my office. Unfortunately I haven't replaced the temperature sensor I fried in "Another Victim of Electrostatic Discharge", so we'll ignore the actual temperature readings for now. But the Arduino is reliably reporting sensor readings wirelessly via its serial port once per second. Here's the complete program, which is mostly the same as before with all the Ethernet and Webduino stuff stripped out of it.

byte lightLevel = 0;
float temperatureCentigrade = 0;
float temperatureFahrenheit = 0;
unsigned long then = 0;

static const int lightAnalog = 4, lightDigital = A4;
static const int temperatureAnalog = 5, temperatureDigital = A5;

static const int oversample = 10;
static const float reference = 4.66; // Measured; nominally 5v, or 3.3v external.
static const boolean internal = true;

void sense(unsigned long now) {
int lightRaw = 0;
for (int ii = 0; ii < oversample; ++ii) {
lightRaw += analogRead(lightAnalog);
delay(1);
}
lightRaw /= oversample;
int temperatureRaw = 0;
for (int ii = 0; ii < oversample; ++ii) {
temperatureRaw += analogRead(temperatureAnalog);
delay(1);
}
temperatureRaw /= oversample;
float lightVolts = (lightRaw * reference) / 1023.0;
lightLevel = 100 - ((100UL * lightRaw) / 1023);
float temperatureVolts = (temperatureRaw * reference) / 1023.0;
temperatureCentigrade = (temperatureVolts - 0.5) * 100.0;
temperatureFahrenheit = (temperatureCentigrade * 1.8) + 32.0;
Serial.print(lightRaw);
Serial.print('=');
Serial.print(lightVolts);
Serial.print('v');
Serial.print('=');
Serial.print(lightLevel);
Serial.print('%');
Serial.print(' ');
Serial.print(temperatureRaw);
Serial.print('=');
Serial.print(temperatureVolts);
Serial.print('v');
Serial.print('=');
Serial.print(temperatureCentigrade);
Serial.print('C');
Serial.print('=');
Serial.print(temperatureFahrenheit);
Serial.println('F');
then = now;
}

void sense() {
sense(millis());
}

void setup() {
Serial.begin(9600);
pinMode(lightDigital, INPUT);
digitalWrite(lightDigital, LOW);
pinMode(temperatureDigital, INPUT);
digitalWrite(temperatureDigital, LOW);
if (!internal) {
analogReference(EXTERNAL);
delay(1);
}
sense();
}

void loop() {
unsigned long now = millis();
if ((now - then) > 1000) {
sense(now);
}
}


Some models of the Xbee radios do allow you to some configuration, in order to, for example, use them in other than transparent mode. Unfortunately, the tool to do this from Digi, X-CTU, is only available for Windows. But as James Sentman has pointed out, you can run X-CTU on the Mac, although to do so requires that you install MacPorts, a software package that makes it easier to port GNU-based open source applications to MacOS, and Wine, a software package that lets you run Windows applications on MacOS (and other OSes as well). Being a glutton for punishment, I of course did all of this, eventually running the X-CTU installer on the Mac under Wine, and then running X-CTU itself under Wine to talk to the XBee Explorer. (Update 2012-02-03: Wrong. I got X-CTU to run on the Mac but was mistaken thinking it was talking to the XBee. However, X-CTU on my Windows netbook talked to it just fine. More tinkering needed.) However, you don't need to do any of this to accomplish what I've described here.

I found some of these references handy (in no particular order):

"XBee Manual" from SparkFun;
"XBee Data Sheet" from SparkFun;
"Configuring XBees" from Indestructables;

But once again, you don't need any of these to actually get this wireless setup working. The hardest part was, for me, not being a hardware guy, soldering the headers onto the XBee shield, and even that worked the first time. I was, however, careful to wear an ESD strap while putting all of this together.

2 comments:

Chip Overclock said...

Thanks for passing along that link to the Arduino-specific quick reference guide to the Xbee-brand Zigbee radios. For sure I would have found that useful. Instead, I used the book Building Wireless Sensor Networks: with ZigBee, XBee, Arduino, and Processing by Robert Faludi, and an Xbee shield for Arduino from Boulder-based Sparkfun. I have used the Xbee S2 radio on Android by building in the appropriate USB-to-serial device driver into Android's Linux kernel, and using a Xbee Explorer board from Sparkfun. I talk about this in Arduino to Android on BeagleBoard via Zigbee.

Alain said...

What would be some good application of this remote sensor? Especially for temperature? Can the arduino and shield go to temperatures humans couldn't walk to with a thermometer?