|
BigScreens / XBee
A great way for us to be able to combine ITP's physical computing talents with "Big Screens" is via the XBee radio. What is ZigBee"ZigBee is the name of a specification for a suite of high level communication protocols using small, low-power digital radios based on the IEEE 802.15.4 standard for wireless personal area networks (WPANs). ZigBee is targeted at RF applications that require a low data rate, long battery life, and secure networking." Useful Links:
What do you need to get started?
A Basic (No Microcontroller) ExampleXBee radios can read digital and analog data (and broadcast that data) without the use of a microcontroller. You can have up to seven channels of analog input and nine channels of digital I/O. Read Rob Faludi's post on how to set-up your XBee for digital and analog data. Our class example will assume the following:
Here are the settings for the output XBee radio (attached to the photocell). You can configure the XBee using a USB dongle and sending commands via ZTerm. +++ --> Enter into Command mode ATID3333 --> PAN ID (using Rob Faludi's ID for now, we will use 9990 eventually, or use your own) ATMY0 --> my address 1 ATDL1 --> destination address 1 (broadcast to Xbee below) ATD02 --> input 0 in analog mode ATIR64 --> sample rate 100 milliseconds (hex 64) ATIT1 --> transmitting just 1 sample! ATWR --> write settings to firmware And the input XBee radio connected to our computer. +++ --> Enter into Command mode ATID3333 --> PAN ID (using Rob Faludi's ID for now, we will use 9990 eventually, or use your own) ATMY1 --> my address 1 ATDL0 --> destination address 0 (we don't have a destination for now) ATDH0 --> destination address 0 Because the input Xbee is connected to the computer, we do not have to write the above settings to the firmware. Instead, we can take care of this using the Processing serial library and resetting the Xbee (ATRE) each time, i.e.
port.write("+++");
delay(1100); // Default guard time for XBee
port.write("ATRE,ID3333,MY1,DH0,DL0,CN\r\n"); // Setup XBee
Assuming your Xbees are configured correctly, bytes will start arriving via the Serial port in Processing. The full protocol is described in detail in the Xbee manual. In our example, the bytes will come in as follows: 0x7e --> Start Byte (this is hexademical) Length MSB --> High Byte for length of packet Length LSB --> Low Byte for length of packet API_ID --> Identifies what kind of packet this is Address MSB --> High Byte for address of source (this is useful if we have readings from multiple sources!) Address LSB --> Low Byte for address of source RSSI --> Received Signal Strength Indicator Options --> Some stuff that is not important totalSamples --> This is just going to be 1 for us, but could be more later!! Channel MSB --> Which channels are in use Channel LSB --> Which channels are in use Data MSB --> The data itself (will be multiple times if multiple sensors) Data LSB --> The data itself (will be multiple times if multiple sensors) Checksum --> Used to confirm that all the data was read correctly Assuming you have a Processing Serial object, you can read all the bytes in the above order and parse them. For example, this is how you might start:
while (port.available() < 1) {
; // do nothing while we wait for the buffer to fill
}
// Ok there is at least one byte available
if (port.available() >= 1) {
// Read that byte
int inByte = port.read();
// It is the start byte?
if (inByte == 0x7E) {
while (port.available() < 2) {
; // do nothing while we wait for the buffer to fill
}
// Two more bytes are available
if (port.available() >= 2) {
int lengthMSB = port.read(); // high byte for length of packet
int lengthLSB = port.read(); // low byte for length of packet
// Look, this is how you can put low and high byte together!!!
int length = (lengthLSB + (lengthMSB << 8));
A bit more parsing and eventually you'd get to the sensor data you want! Fortunately for us, Rob Faludi has created an example that does most of this work and I've adapted it into a simpler Processing library for use in Eclipse. So you don't have to do the above, unless you are doing something highly specialized. Using the XBeeReader libraryThe full example is on the CVS, under: /home/dts204/bigscreens/examples PROJECT: XBee The class that does the work for you is called XBeeReader.java. In order to make an XBeeReader object, you need to pass in a reference to the current PApplet (this) as well as a Serial object (It's your job to create the Serial object with the right port, etc.) You must then call the function start(), which will begin the processing of reading the Xbee data.
Serial port;
XBeeReader xbee;
public void setup() {
size(200, 200);
// Print a list in case COM1 doesn't work out
// println("Available serial ports:");
println(Serial.list());
port = new Serial(this, Serial.list()[0], 9600);
xbee = new XBeeReader(this,port);
xbee.start();
}
XBee data will arrive in an xBeeEvent() function, just like serialEvent():
public void xBeeEvent(XBeeReader xbee) {
int data = xbee.getXBeeReading();
//println(data);
}
The example is only set up to send back a single integer. If you want to read from multiple analog and digital inputs, you'll need to refer to the manual and change the getData() function inside XBeeReader.java. Serial in EclipseFor serial to work in Eclipse, copy over the entire library folder from Processing. You will then need to add the following jars to your build path:
Then right-click on RXTXComm.jar, select "Properties", "Native Library" and pick the folder in your project where the native files (JNILIB for mac, DLL for PC) are stored. Using XBee data with MPEFor a multi-screen application, you'll want to make sure that a single client creates and initializes the XBee object.
if (ID == 0) {
println(Serial.list());
port = new Serial(this, Serial.list()[0], 9600);
xbee = new XBeeReader(this,port);
xbee.start();
}
As soon as you read the data from the XBee, you'll want to turn right around and broadcast it out to all clients.
public void xBeeEvent(XBeeReader xbee) {
int data = xbee.getXBeeReading();
client.broadcast("" + data);
}
Remember, do not use the value directly or you risk going out of sync!!! Then, you can receive and use the data in frameEvent():
public void frameEvent(Client c){
if (c.messageAvailable()) {
String[] msg = c.getDataMessage();
x = Integer.parseInt(msg[0]);
}
redraw();
}
See mpe/XBeeMPE.java in the XBee project on the CVS for an implementation of the above. |