An Encounter with XBee

It has always been on my list to try a project with some wireless communication. I now have a project in mind but there are a few things to sort out first. I have not worked with any wireless at the embedded hardware level. This is not inteded to be any instructional post but my usual style of describing how I have approached this topic, what I encountered and how I worked around any issues I discovered. Maybe this might be of some help to others like me, starting at zero.

Which Radio?

I thought this was not such a hard question. There might be other providers out there but I qickly decided on the XBee from Digi.com. The question got suddenly harder. The range of devices available was at best a little daunting to overwhelming. I had to make a decision as to what I wanted. The actual project I have in mind is no so well defined that I could really make a sensible choice. I therefore decided just to take a stab at it and see what I can learn. In the choice, it was clear that I did not want a Cellular solution or Wifi. So that narrowed the field down a bit. I was attracted to the development kits that provide up to three radios. Based in the research I did at the time, I decided on the Digi XBee 2SC Digimesh 2.4 Kit. Since then I have discovered even more variations on development kits. I feel that as I understand more about at at least one of these variants works, I will be in a better position to make a more informed choice next time.

Getting Started

The typical place to start with these is the Getting Started notes in the tutorial. I worked through those notes which use their Configuration and Test Utility software (XCTU) application to setup and configure the XBee radios. I was able to get messages happening from one device to the other and also use the third to help extend the range. A couple of things became apparent. You can use the device as a serial line to the remote device (Transparent mode) or send the data in packets (API Mode). The later provides more power in that it then becomes possible to interact with the GPIO that is provisioned on the radio modules. The other thing that became apparent was that to interact with the radio module, an AT command structure is used. I have not seen that since messing with Hayes Modems way back when. So at lest something was a little familiar.

In transparent mode, the destination address that messages are sent to are hard-coded into the configuration of the XBee radio module with the DH and DL parameters (Designation High and Destination Low addresses – which are in effect the MAC address for the destination device). In API mode, the address is a part of the frame to be sent. In the transparent mode, the devices are effectively hard-wired together.

The basic tutorial does not go beyond sending messages. I was also interested in what the hardware and on-board GPIO cold offer. It took me a little while to work out how to Interact with the GPIO on the Grove development board, that is supplied with the kit. The User Button and User LED are both on Digital IO pin 4 (D4). I was a little confused with this arrangement. But then I realised when we want something to blink, we take the input on one line and output it on the other. In this case, the input is on one radio device and the output is on the other. With this thinking, it does not matter that they are the same pin – as long as it is a different radio module.

The diagram below shows the Grove Development boards and the associated XBee radio devices. What was important was to ensure that for the source device, the D4 is set to Input and that IU and IC properties are set to enable the digital IO. On the destination device, the D4 needs to be set as a digital Output.

XBee_Button_TestSeeing this working is very encouraging and slowly the use of these devices is becoming clear.  I would be using the UART interface to send/receive messages from the radio device. This brings me to the first design question for my project: To use the built in GPIO of the radio device and communicate these with the AT commands? Or to hand-craft my own data frames to communicate between the nodes? This would effectively ignore the provided GPIO of the XBee modules.

Next Steps – Blinking Programatically

With the basic test of having the hardware of the Grove Board successfully interacting with the XBee such that the User Button on one device will illuminate the User LED of the other, the next logical step is to try this programatically.

What I was interested in here is not to use the User Button any more but to send a message from a program to the XBEE_A and have the LED illuminate on XBEE_B. In preparation and to understand how to achieve this, I thought it best to first try this through the XCTU. i.e. that is to send the individual messages from XBEE_A to XBEE_B to set the D4 to HIGH and LOW as needed. To help with this, I found this excellent resource to explain how to set this up with the XCTU. Creating frames this way gives the exact message required to be sent.

My language of choice for these experiments and eventually the project I have in mind is Python. I found a reference site for the Python API for XBee.  I was able to install this for python3 with no problems

pip3 install xbee

The provided samples did not work straight off. This has to do partly because I am using Python3 but mostly because my understanding of how to use this API is not at all strong.

Taking a step back, and taking the message from the XCTU and applying this directory to the serial port, I could at least prove that I can communicate with the XBee, even if it is not through a tailored API. The code below worked fine. Blinking the User LED 5 times.

import serial
import time

ser = serial.Serial('/dev/tty.usbserial-A5056Y8X', 9600)
print(ser.name)

for a in range(0, 5):
    print("Sending LOW")
    ser.write(b'\x7E\x00\x10\x17\x01\x00\x13\xA2\x00\x41\x62\x9B\xFB\xFF\xFE\x02\x44\x34\x04\x7E')
    time.sleep(1)
    print("Sending HIGH")
    ser.write(b'\x7E\x00\x10\x17\x01\x00\x13\xA2\x00\x41\x62\x9B\xFB\xFF\xFE\x02\x44\x34\x05\x7D')
    time.sleep(1)

ser.close()

I opened up the downloaded package for the XBee API for Python, and referred to the associated documentation. In the downloaded package, there are further examples. i.e. led_adc_example.py.  It is not clear to me why the examples use a two byte dest_address. My exposure to these devices so far, has an eight byte address. Further rummaging revealed there is a long_dest_address parameter that seems hopeful. I adapted the findings so far into the the script above to create the following with the same behaviour. Sending a message through XBEE_A is received by XBEE_B and the User LED will blink.

#! /usr/bin/python3

# Import and init an XBee device
from xbee import XBee, ZigBee
import serial
import time

ser = serial.Serial('/dev/tty.usbserial-A5056Y8X', 9600)
xbee = XBee(ser=ser, shorthand=True)

for a in range(0, 5):

 print("Sending LOW")
 xbee.remote_at(
 dest_addr_long=b'\x00\x13\xA2\x00\x41\x62\x9B\xFB',
 command=b'D4',
 parameter=b'\x04' )

 time.sleep(1)
 print("Sending HIGH")
 xbee.remote_at(
 dest_addr_long=b'\x00\x13\xA2\x00\x41\x62\x9B\xFB',
 command=b'D4',
 parameter=b'\x05')
 time.sleep(1)

ser.close()
print("End")

Beyond Blinky

It was not until being forced to look into the actual package code that other things fell into place. Namely with the definition of the XBee class itself (defined in ieee.py), the parameters to those APIs are defined. I also found in the package what I was looking for. There is DigiMesh class (defined in digimesh.py) that is not published to the web pages. This class allowed me to take the experimenting one step further and be able to send an arbitrary message to the XBEE_B module.

#! /usr/bin/python3

# Import and init an XBee device
from xbee import XBee, DigiMesh
import serial
import time

ser = serial.Serial('/dev/tty.usbserial-A5056Y8X', 9600)
xbee = DigiMesh(ser=ser)

print("Sending message")
xbee.tx(
 frame_id = b'\x01',
 dest_addr=b'\x00\x13\xA2\x00\x41\x62\x9B\xFB',
 data=b'Hello Mr. B. XBEE' )

# Wait for response
print("Waiting for response...")

response = xbee.wait_read_frame()
print ("Response={0}".format(str(response)))

ser.close()
print("End")
XBEE_B - Received Packet


 Receive Packet (API 1)

7E 00 1D 90 00 13 A2 00 41 62 9B CE FF FE C1 48 65 6C 6C 6F 20 4D 72 2E 20 42 2E 20 58 42 45 45 1B

Start delimiter: 7E
Length: 00 1D (29)
Frame type: 90 (Receive Packet)
64-bit source address: 00 13 A2 00 41 62 9B CE
16-bit source address: FF FE
Receive options: C1
RF data: 48 65 6C 6C 6F 20 4D 72 2E 20 42 2E 20 58 42 45 45
Checksum: 1B

Conclusion

I see out there many people have implemented these devices in their projects. Whether they have gone along the same path as myself, I will never know. Though the development kit has kept me occupied, the questions and issues were always able to be resolved. In essence, these radio devices will only respond to a message presented on the serial line. The APIs regardless of language are just helpers to get that message in the right format. So much of the time spent has been locating and finding out how to use the Python API. The most effective way to work with this API was to verify the class definitions at the source level – the real source of truth.

I look forward to continuing to experiment with these devices. This whole exercise has helped me get a little more confident in working with these devices.

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s