Skip to main content

XBee ZNet 2.5 Wireless Accelerometer

I managed to put together a wireless accelerometer the other night using my two new XBees, an Arduino XBee shield, an XBee Explorer USB, an ADXL330, and some Python. I struggled a bit with some of it, so here's what I learned:

First, a parts list.
I'm not sure exactly what the specs are on the XBee that comes with the Arduino shield. But, it is definitely a series 2.5.

The first thing to do is to configure and upgrade the firmware on your XBees. To do that, you'll need X-CTU (for the firmware upgrade at least, but it's also nice for configuration) which, unfortunately, is only available for Windows. But, it works fine from VMware. First up, the XBee we'll hook up to the computer to read incoming data from the accelerometer:
  • Plug one of the XBees into the Explorer (it's also possible to do this from the Arduino shield by shifting the two XBee/USB jumpers to USB and removing the MCU) and plug it into your USB port.
  • Crank up X-CTU, select the appropriate USB communications port (com port), click "Modem Configuration" and then "Read." This will determine what XBee is connected and what firmware is on the device.
  • Select "Always update firmware."
  • Click "Download new versions..."
  • Select the latest version of ZNet 2.5 Router/End Device API. The API version is necessary in order to read the incoming data on the computer. Only API firmware will write incoming sensor data to the device's UART so it can be read over USB/serial.
  • Click "Write." You may get an error after the writing is complete. That's normal. It's because you've changed the way the XBee communicates over it's UART. Go back to the "PC Settings" tab, select "Enable API" and then click "Read" on the "Modem Configuration" tab again.
  • Under "Networking," change NI (Node Identifer) to something like "ARDUINO". I named mine Arduino because I used the Arduino and XBee shield to provide a USB connection to the computer.
  • Click "Write" and hook it up to your computer. This is the XBee that your accelerometer will be sending data to. We'll hack up some Python to read that data later.
Next up is the XBee we'll hook to the accelerometer:
  • Follow the same steps as before until you reach the firmware selection.
  • Select the latest version of ZNet 2.5 Router/End Device AT.
  • Under "Networking," change NI (Node Identifer) to something like "ACCELEROMETER".
  • Under "I/O Settings," change D0-D2 to 2-ADC. These pins will be used to read from the accelerometer.
  • Again under "I/O Settings," change IR (sample rate) to 1F4 (hex for 500 milliseconds).
  • Click "Write."
  • Go to the "Termainal" tab. To enter command mode on the XBee, send it "+++" (do not press enter). It will respond with "OK". Next type "ATDNARDUINO" (or whatever you called your other XBee). That will set the destination node to your other XBee. It should respond with "OK". Next, send it "ATWR". That will write the settings to memory so that they aren't lost when the XBee is powered off.
  • Finally, hook up your XBee and ADXL330. You can power both with 3.3V (3V works too). Unfortunately, the XBee 2.5 series ADCs only accept voltages in the range of 0-1.2V. To get better results, you'll need to add voltage dividers on the X, Y, and Z axes. I don't have those in the schematic. If you use 3V, it works well enough to detect motion. For finer mesurements, you'll need the dividers.

Now, you should be able to test that everything is working. Connect to the Arduino XBee with the X-CTU terminal. Assuming your accelerometer XBee is powered on, you should see lots of data flying by. The data is transmitted in API packets over the XBee's UART, to the FTDI chip, to your computer's USB-serial device. The API packet specification is in the XBee 2.5 manual. Here's some Python that does part of the decoding.
import xbee
Just kidding. Although there is a XBee Python library, it doesn't currently support series 2.5 modules.
import serial  # pySerial
import struct
import sys


tty = sys.argv[1]

s = serial.Serial(tty, 9600)
movement = None
while True:
if == chr(0x7e): # Packet start indicator.
length, api_id = struct.unpack('>Hc',
if api_id == chr(0x92): # IO packet type.
# Lots of bytes we don't care about followed by 3 shorts.
z, y, x = struct.unpack('>xxxxxxxxxxxxxxxHHH', - 1))
print z, y, x
if (movement is not None and
abs(z + y + x - movement) > THRESHOLD):
print 'You moved!'
movement = z + y + x
If you read the spec for API packets, you'll notice I'm glossing over a lot of details. The analog IO bytes are always at the end of the packet. Since we enabled only 3 ADCs, we can just grab the last three shorts.

Finally, here is a picture of my breadboarded version (with voltage dividers) of this. It works great. I'm currently working on a PCB so that the whole thing is compact enough to be wearable.

Some further notes:
  • The chip antenna versions are pretty directional. There's a lot of interference in my apartment (a long story for another post) and I don't get very good range. I plan to buy some more 60mW XBee Pros with wire antennas in the future. I'd recommend getting the high power ones unless you're really concerned about battery life. I wish I had.
  • Digi's tech support is really pretty great. I had some trouble flashing one of my XBee's and they got in contact with me on the same business day.
  • Unfortunately, the XBee only has 4 ADCs. If it had one more, you could add a pitch and roll gyro to the mix without an additional MCU. Oh, well.
  • The XBee pin spacing doesn't match standard breadboards. But, the XBee Explorer USB doubles as an XBee breakout board for breadboard designs (as seen in the photo above) if you solder on some additional headers.

Popular posts from this blog

Email Injection

Not so long ago, I ran a wiki called SecurePHP. On that wiki, there was one particular article about email injection that received a lot of attention. Naturally, with all the attention came lots of spam. As a result, I disabled editing of the wiki and content stagnated. Still, the email injection article remained popular. About a year later, the server that hosted SecurePHP died and I never had a chance to hook it all back up. I saved the article though and I'm reposting it now. It may be a bit old (I've been away from PHP for a long time), and I didn't write all of it, so feel free to leave comments about needed updates and corrections. Though this article focuses on PHP, it provides a lot of general information regarding email injection attacks. The PHP mail() Function There are a lot of ways to send anonymous emails, some use it to mass mail, some use it to spoof identity, and some (a few) use it to send email anonymously. Usually a web mailform using the mail() funct
Read more

Bot Commander r1 Released

I just published Bot Commander , the code for my Lego NXT rover . There's a lot left to be done, but release early and often, right? Currently it provides a UI for controlling the direction and speed of all three motor ports on the NXT brick. You can link motors together to adjust their speed in unison. In addition, you can enable "Tilt Control" for a steering-wheel-type experience. To use tilt control: Hook up motor A and B to be the left and right wheels of your vehicle. Hold the phone sideways (i.e. landscape). Tilt the phone forward and backward to drive forward and backward. Turn the phone right and left (like a steering wheel) to steer right and left. As you tilt the phone, you'll see the UI update the slider controls for the speed of motors A and B. I plan to expand the UI to provide a lot more than just motor control. Before that, though, I'll push a JAR to make it easy to integrate control of Lego NXT robots into your own Android project. The code
Read more

Android Recipes and Snippets

I've put together a small collection of Android recipes. For each of these recipes, this is an instance of Context (more specifically, Activity or Service ) unless otherwise noted. Enjoy :) Intents One of the coolest things about Android is Intents . The two most common uses of Intents are starting an Activity (open an email, contact, etc.) and starting an Activity for a result (scan a barcode, take a picture to attach to an email, etc.). Intents are specified primarily using action strings and URIs. Here are some things you can do with the android.intent.action.VIEW action and startActivity() . Intent intent = new Intent(Intent.ACTION_VIEW); // Choose a value for uri from the following. // Search Google Maps: geo:0,0?q=query // Show contacts: content://contacts/people // Show a URL: intent.setData(Uri.parse(uri)); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); Other useful action/URI pairs include: Intent.ACTION_DIAL , tel://867530
Read more