All posts by Per Magnusson

Interfacing to an XBee Module from Python

In a previous post, I described how to talk to an XBee ZigBee module from a FRDM development platform. In this post, I describe how to do it from Python on e.g. a Windows PC.

First, one obviously has to have a Python environment set up on the computer. I use Python 2.7 and the IPython interactive shell. I will not describe how to install that, but it should not be too hard to do using the instructions on the IPython website.

Then we need to install two modules to enable communication with the XBee. The first one is simply called xbee and can be found here. Download, unpack (using e.g. 7-zip), start a cmd window, cd to the folder with the downloaded files and install it by typing:

python setup.py install

The second is pyserial. Download it from here and install it in a similar manner as described above. This module mentions that it is intended for 32-bit windows, but it has worked fine for me on 64-bit Windows 7.

I use a SparkFun XBee Explorer USB board to interface to the XBee module. This provides an FTDI serial port for communication with the XBee. I soldered an LED with a series resistor between DIO1 and GND to provide easy verification that I was able to control the I/Os of the XBee. The XBee needs to be in API mode. If it is not, the XCTU program from Digi can be used to upload a proper firmware to the module.

Here is the program I wrote to test communication with the XBee:

#! /usr/bin/python

# Demo to talk to an XBee ZigBee device
# Per Magnusson, 2015-07-28
 
from xbee import ZigBee
import serial
import serial.tools.list_ports
import time
import sys

# Look for COM port that might have an XBee connected
portfound = False
ports = list(serial.tools.list_ports.comports())
for p in ports:
    # The SparkFun XBee Explorer USB board uses an FTDI chip as USB interface
    if "FTDIBUS" in p[2]:
        print "Found possible XBee on " + p[0]
        if not portfound:
            portfound = True
            portname = p[0]
            print "Using " + p[0] + " as XBee COM port."
        else:
            print "Ignoring this port, using the first one that was found."

if portfound:
    ser = serial.Serial(portname, 9600)
else:
    sys.exit("No serial port seems to have an XBee connected.")

# Flash the LED attached to DIO1 of the XBee
try:
    xbee = ZigBee(ser)
    print "XBee test"

    xbee.at(command='D1', parameter='\x05') # Pin 1 high
    resp = xbee.wait_read_frame()
    print resp

    time.sleep(1)
    xbee.at(command='D1', parameter='\x04') # Pin 1 low
    resp = xbee.wait_read_frame()
    print resp

    # Try another AT command
    xbee.at(command='ID')
    resp = xbee.wait_read_frame()
    print resp
    print "Done"
    ser.close()
except:
    print "Error!"
    ser.close()

raw_input("Press Enter to continue...")

The program has some bells and whistles. First it looks at all the serial ports it can find and selects the first one that could be the XBee (indicated by the text FTDIBUS in the description of the port). It then tries to set up a connection to the ZigBee and issues three local AT commands. The first turns the LED on (then it waits for 1 second), the second turns the LED off and then it issues the ATID command. The response from these commands are printed. At last the serial port is closed and the program waits for the user to press enter to exit the program.

The output may look like this:

In [3]: %run xbee_prog.py
Found possible XBee on COM3
Using COM3 as XBee COM port.
XBee test
{'status': '\x00', 'frame_id': '\x01', 'command': 'D1', 'id': 'at_response'}
{'status': '\x00', 'frame_id': '\x01', 'command': 'D1', 'id': 'at_response'}
{'status': '\x00', 'frame_id': '\x01', 'parameter': '\x00\x00\x00\x00\x00\x00\x0
0\x01', 'command': 'ID', 'id': 'at_response'}
Done
Press Enter to continue...

In [4]:

Stupid mistake

While writing this program I made a stupid mistake that prevented it from working. I happened to name the program xbee.py and this made the line

from xbee import ZigBee

import the program itself, instead of the installed module. The error message was: ImportError: cannot import name ZigBee. Renaming the program from xbee.py to xbee_prog.py solved this issue.

Now that I realize that Python imported the program itself instead of the module, it is obvious why it could not find ZigBee inside it, but it took a while before I figured that one out.

 

Solution to Very Slow Keyboard Response in IPython

I am starting to use Python (on Windows) and am running IPython as well as pylab and matplotlib. I had a problem though, keyboard input in IPython was very slow (maybe half a second delay for each character). This was extra noticeable when pasting e.g. a path. After some googling around, I found this discussion:

https://groups.google.com/a/continuum.io/forum/#!topic/anaconda/kvWVtW40aDI

There, they say that starting IPython using the following command could help:

ipython console --pylab

I adapted this to Windows by right-clicking the on the IPython icon in the start menu and added

console --pylab

to the string in the target field so that it reads:

C:\Anaconda\python.exe "C:\Anaconda\Scripts/ipython-script.py" console --pylab

When I now start IPython through this shortcut, the delay is almost completely gone! When I paste in a string, it might take a tenth of a second or so for 20 characters to be pasted, which is not really fast, but still well below the limit for being annoying and a vast improvement over the previous situation.

Interfacing an XBee Module to a FRDM Board

I am prototyping a wireless sensor node based on a (cheap) FRDM-KL25Z board from Freescale containing an ARM Cortex-M0+ processor and a (not quite as cheap) XBee ZigBee module from Digi. This blog post briefly describes the first steps of the prototyping, namely to get to the point where the XBee is connected to the FRDM board and they talk to each other.

I decided to use the mbed environment to develop the program and in order to do that, I had to change the FRDM board firmware according to these instructions.

For the initial tests, I wanted to write AT commands to the XBee from a terminal on the PC via the FRDM board. The XBee can run any of a number of different firmwares and in order for it to understand AT commands, one of the AT firmwares need to be loaded. This is done using the XCTU program from Digi while the module is connected to a PC serial port, e.g. through the SparkFun XBee Explorer USB board. Below is a screenshot from XCTU showing the major steps to program an AT firmware into the XBee module.

In XCTU, connect to the XBee radio, select it in the left pane, click the button circled in red, select the desired AT firmware (e.g. Router AT) and click update.
In XCTU, connect to the XBee radio, select it in the left pane, click the button circled in red, select the desired AT firmware (e.g. Router AT) and click Update.

The XBee module interface is a 3.3 V serial port running at 9600 baud, and the Cortex-M0+ processor also runs at 3.3 V, so this should match nicely. However, I have the XBee mounted on a Sparkfun XBee Explorer board, which translates the 3.3 V serial port to 5 V levels. The translation is done via pass transistors and pull-up resistors (see the schematic), so it might be OK to connect them directly to the FRDM board, but just to play extra nice with the FRDM board I decided to mod the XBee explorer so that the pull-ups go to the 3.3 V supply instead of the to 5 V supply as shown in the schematic excerpt and the photo below:

Schematic view of the modification of the XBee explorer board to get 3.3 V serial port levels.
Schematic view of the modification of the XBee explorer board to get 3.3 V serial port levels.
Modification for 3.3 V serial port levels. Cut the 5-V track to the pull-up resistors and solder in a wire to 3.3 V instead.
Modification for 3.3 V serial port levels. Cut the 5-V track to the pull-up resistors and solder a wire to 3.3 V instead.

One easy way of physically getting a confirmation of successful communication with the XBee (apart from serial port responses to the AT commands) is to connect an LED to one of the digital I/O-pins. Below is a photo of how I connected an LED to XBee I/O-pin 1.

An LED with a series resistor has been connected to I/O-pin 1 of the XBee.
An LED with a series resistor has been connected to I/O-pin 1 of the XBee.

Now we need to connect the XBee to the FRDM board. There are several pins that can be used as serial I/Os on FRDM-KL25Z and based on the schematics, I happened to select PTE0 (also known as D14 and J2 pin 18) for UART1_TX and PTE1 (also known as D15 and J2 pin 20) for UART1_RX. This pin pair can also used for I2C bus 1, but if I later need to use that bus, I can route it out on PTC10 and PTC11, or I can use different pins for the UART. This page has a picture that may serve as a guide for pin selection. GND and 5V to supply the XBee is available on pins 10 and 12 respectively in the connector J9.

If I had used the simpler breakout board instead of the one with a regulator and level translation, I would not have needed the level translation patch and I would have used the 3.3 V supply from the FRDM board instead of the 5 V supply.

I soldered sockets to the FRDM board connectors J2 and J9 and pin headers to small pieces of prototype board. In one of these I placed a header for the XBee breakout board and then I connected 5V, GND, RX and TX. The whole thing may not be particularly mechanically robust, but it serves its purpose, see photo below.

XBee module connected to a FRDM-KL25Z board.
XBee module connected to a FRDM-KL25Z board.

A program for the FRDM board is of course needed as well. I made it very simple; characters coming from the serial port from the PC are sent on to the XBee and vice versa. Also, characters from the PC are echoed back to the PC. I also flash the RGB LED based on what is happening as further feedback. Here is the code:

#include "mbed.h" 

Serial pc(USBTX, USBRX); 
Serial xbee(PTE0, PTE1); 
DigitalOut redled(LED1); 
DigitalOut greenled(LED2); 
DigitalOut blueled(LED3); 

int main() { 
    char bufchar; 
    
    blueled = 0; // Turn blue led on
    pc.printf("Type what you want to transmit to the XBee.\n\r"); 
    xbee.baud(9600);
    greenled = 1; // Turn green led off
    redled = 1; // Turn red led off
    blueled = 1; // Turn blue led off
    while (1) { 
        if (pc.readable()) { 
            greenled = 0;
            bufchar = pc.getc(); 
            xbee.putc(bufchar); 
            pc.putc(bufchar); // Local echo
            greenled = 1; 
        } 
        if (xbee.readable()) { 
            redled = 0;
            bufchar = xbee.getc(); 
            pc.putc(bufchar); 
            redled = 1;
        } 
    } 
}

To be able to talk to the FRDM board as a USB serial port, a Windows driver is needed. This can be found on the mbed site. As a serial terminal program, I decided to use Tera Term, which is free. I set it up for communication at 9600 bauds with the serial port number that Windows assigned to the FRDM board serial port.

To get into AT command mode in the XBee module, three plus signs (+) must be sent guarded by at least a 1 second pause before and after. The module returns to transparent mode 10 seconds after the last activity on the serial port, so an AT command have to be sent within this time. To test the LED I connected to the XBee module, I use the command ATD14 (set XBee IO pin 1 low) and ATD15 (set XBee IO pin 1 high). For some reason these commands do not take effect until the module reverts to transparent mode, and in order to not have to wait the 10 seconds for a timeout, I issue the ATCN command, which forces the module to immediately go to transparent mode so that the LED update happens. I am not sure it is meant to work this way.

Below is a screenshot of the terminal window showing the commands and the response from the system.

Serial terminal session turning XBee LED on I/O 1 off and then on.
Serial terminal session turning XBee LED on I/O 1 off and then on.

The OK texts come from the XBee module.

So far so good. For the sensor application, I will not use AT commands, but instead use the API mode, but this exercise served as a stepping stone that allowed verification of the connection between the processor board and the XBee module.