NXTBee Communication

Library in Java, RobotC

March 2012

 

Last updated 30 March, 2012


All content © 2008, 2009, 2010, 2011, 2012  Mark Crosbie  mark@mastincrosbie.com


LEGO® is a trademark of the LEGO Group of companies which does not sponsor, authorize or endorse this site. This site, its owner and contents are in no way affiliated with or endorsed by the LEGO Group. For more please read the LEGO Fair Play policy.


When I was developing the Lego Street View Car I realised that I needed a way to control the car more reliably than Bluetooth, and without relying on the existing of a wifi network. The NXTBee is the obvious choice. It uses the industry-standard XBee protocol giving high-speed serial transmission over a 300 ft range without any setup or the overhead of Bluetooth communication.


The NXTBee connects onto port 4 of the NXT and acts as a high-speed RS485 serial device. My plan was to stream live telemetry from the Street View Car to my laptop as a base-station. I also wanted to walk alongside the car controlling it using a handheld remote. Thankfully this is easy to achieve as multiple NXTBees form a “mesh” network that allows all devices to communicate with each other as long as they are in range.


However the NXTBee acts as a simple serial link, in other words it sends a stream of bytes from one point to another. On top of that basic serial link I needed to build a library that would allow me to send basic data types from the NXT to my laptop, between NXTs, and from my MacBook laptop to the NXT. I wanted the library to provide:


  1. Message oriented. There are many examples of how to pass data between remote systems. The simplest method is to pack data to send into a message as a sequence of bytes and send it to the receiver who then unpacks it back into the original values.

  2. Best-effort message delivery. Why best-effort and not guaranteed ? I didn’t want to go to the trouble of inventing a reliable message transport protocol (laziness)!

  3. Compact message size. The easiest approach to sending values is to encode them as strings and parse the string at the receiving end. But this is wasteful of space, and leads to very large messages. I wanted my library to use a more efficient representation of values.

  4. Error detection. I wanted to know if the messages were being corrupted in transit. The NXTBee is not 100% reliable (it’s just the nature of wireless communication) and occasionally will drop messages, or truncate messages. The library needed to detect if a message had been corrupted so it could discard it.

  5. Unicast and Broadcast Addressing. The XBee allows for each device to have an address assigned, but I decided to implement a very simple addressing scheme on top of the serial link in the NXTBee. I use a single byte address, with the value 0 reserved for “broadcast”. Each NXT chooses an address value for itself and then will only receive messages destined for that address. If a NXT sends a message to address 0 then all other NXTs (or laptops) will receive it. If a NXT listens on address 0 then it receives all messages sent by all other NXTs. Simple, but effective for my needs.

  6. Supports NXT data types. The library has to allow me to transmit the basic data types in RobotC on the NXT. These are byte, boolean (true/false), integer (2 bytes signed), long (4 bytes signed), ASCII string (up to 20 bytes in length) and byte array (arbitrary length).

  7. Packed data format. I knew that I would want to transmit multiple values for each message; for example I needed to transmit (latitude,longitude,heading) from the Street View Car. I wanted to minimise the number of messages transmitted to improve the reliability of the protocol, so packing multiple data values into a single message became a requirement. Of course, you need to know how to re-assemble the packed data values on the receiving end, so I devised a very simple packed data format for messages.

  8. Multi-platform. Obviously the library had to work on the NXT to allow NXT-to-NXT data transmission. But I also wanted it to work on my laptop. As I use a Mac, but many other people who would use this library have Windows PCs, I needed to create a platform-independent library. Java is the obvious choice, and the Processing framework makes this as simple as possible. However Java represents data types in a different format from RobotC on the NXT, so my library had to translate between these.


The library must deal with the fact that data types are sized differently depending on the underlying platform. For example, an integer on the NXT is 2 bytes in RobotC, but is stored in 4 bytes in Java on the laptop. I chose the names of the functions and methods in the library to refer to data types from the perspective of the NXT. Thus transmitInt sends a 2 byte integer (the RobotC data type on the NXT) which would be a short in Java (integers are 4 bytes long in Java).


On this page I’ll explain the basic concepts behind using the library on the NXT in RobotC and on your PC/Mac using Processing. I’ll also give some sample code for calling the functions.


Simple data format

The data format used by both the RobotC and Java Processing libraries is the same. A small header of 5 bytes is placed in front of the data you want to send. The header contains the following fields:





For example, sending a byte value 123 from address 5 to address 7 would be encoded as:


4 1 XX 7 5 123 where XX is the checksum value.


Packed data format

The packed data format retains the 5 byte header used by the simple data format, but adds a two byte packing header in front of each value so that the recipient knows how many bytes to extra and what type the value is. For example, sending a byte of value 123, an integer of value 5 and a string “abc” would be encoded in packed format as:


6 12 xx 7 5 4 1 123 2 2 0 5 0 3 a b c



RobotC library


The NXTBee communication library is used to transmit data types from a NXT to either another remote NXT, a group of NXTs or a PC/Mac. The library supports a basic addressing scheme that allows 254 devices to communicate one-to-one with each other, or to broadcast to all devices within range. Basic error detection is supported through a checksum to detect corrupt or truncated messages.


Message delivery is "best effort". Messages may not make it to their final destination, or may be corrupted en-route. There is no notification back to the sender that the message was lost in transit. This is equivalent to the UDP network protocol. It is up to the sender to build a communication protocol that detects lost messages and re-transmits when needed. Message re-transmission may be added at a future point.


Messages are a sequence of bytes. The sender and receiver do not need to worry about packing data into the byte format used for transmission, that is performed by the library functions. The data types supported for transmission from the NXT are:


  1. Byte - a single byte value from 0 to 255. The recipient may interpret the byte value as signed or unsigned.

  2. Integer - a two byte value signed from -32768 to 32767.

  3. Long - a four byte signed long value.

  4. Boolean - true and false are sent as the values 1 and 0.

  5. String - the RobotC string type can hold up to 20 characters in ASCII format.

  6. Bytes - an arbitrary number of bytes can be transmitted.


The library provides two types of sending functions: transmit a single data type in a message, or pack multiple data types in a message. I’ll explain each of these functions below.


Common functions


These functions are used to initialise the library on the NXT.

  1. SetupHighSpeedLink - Initialises the high-speed serial link on port 4 on the nxt. The NXTBee should be connected to port 4 only. By default the baud rate is set to 115200 baud in the HS_BYTE variable on line 43 of the file. Out of the box the NXTBee operates at 9600 baud. To change the baud rate the NXT talks to the NXTBee at change line 43.

  2. SetMyAddress - Sets the address for this NXT. The default address is 0 or BROADCAST. This means that the NXT will accept all messages received on the NXTBee. If you want to bind this NXT to a specific address from 1..255 then call setMyAddress().

  3. VERBOSE_DEBUG (line 25). If you undefine the VERBOSE_DEBUG macro then the library will run silently. Defining this macro will send debug output to the debug console in RobotC.


Sending simple values


This set of functions will send a data value from the NXT to the given destination address. They will send the value immediately (or whenever the NXTBee is ready) and will return the number of bytes sent. Remember; this is best-effort delivery, so there is no guarantee that the destination actually ever received the message you sent!


  1. TransmitInt - transmits a two byte signed integer value. Equivalent to a two byte signed short in Java.

  2. TransmitLong - transmits a four byte signed long value in RobotC. Equivalent to a 4 byte signed integer in Java.

  3. TransmitASCII - transmits an ASCII string value, without the trailing null character.

  4. TransmitBytes - transmits a byte array of any length up to 95 bytes.

  5. TransmitBool - transmits a RobotC boolean type using a single byte to represent true and false.

  6. TransmitByte - transmits a single signed byte value.


Remember: there is a 5 byte header added onto each of these messages, so if you have a lot of data to send then it is better to use the packed data format described below.


Sending Packed Values

This set of functions are used to pack multiple data types into a single message before sending. A packed message is more space efficient in that single radio transmission can send many data values. The maximum size of the message body is 95 bytes, thus you can pack up to 95 bytes of data into a message. In reality there is a two-byte overhead per packed data type. So sending two integers and a byte would give a total message size of: (2+2) + (2+2) + (2+1) = 11 bytes of packed data.


The packing functions are used as follows; first you initialise the packing by calling initialisePacking(). This will set up the message header and byte count ready to pack values into the transmitBuffer. Next, pack your values into the transmitBuffer by calling any one of the pack functions. Finally call the transmitPackedMessage() function to send the values to the recipients.


  1. InitialisePacking - initialises the packing by wiping out the contents of the transmitBuffer. Call this before packing any values into the buffer.

  2. PackInt - packs a signed 2 byte integer.

  3. PackLong - packs a signed 4 byte long.

  4. PackByte - packs a signed byte.

  5. PackString - packs an ASCII string, without the trailing null.

  6. PackBytes - packs a byte array of size up to 95 bytes

  7. TransmitPackedMessage - sends the packed message to the recipient.


WARNING: Don’t mix packed and simple data sending functions as this will mess things up. In other words, every initialisePacking call must only be followed by pack function calls or a transmitMessage call before you can send any simple data. If you are writing multi-threaded code be sure to put a mutex around the packing function block.


Receiving Data

The Receive function is called to receive data from the NXTBee and store it into the global receiveBuffer. Unfortunately this function is not thread-safe as it uses a number of global variables, so I recommend having a single thread responsible for receiving data, or poll this function in your main loop.


  1. Receive - if a message is waiting in the NXTBee it reads the message. If a valid message is found the Receive function checks the CRC8 checksum for corruption, and if the message is destined for this NXT. If the checksum does not match then ECKSUM is returned. If both these tests pass it stores the message in the global receiveBuffer, and returns the parameters from the message in the msgHdr struct shown below. The return value is the size of the message body, excluding the header bytes.

  2. GetValue - extracts a value from the receiveBuffer and returns it. Can extra a signed byte, integer or long value.

  3. GetBytes - extracts a byte array from the receiveBuffer and returns it.

  4. GetString - extracts an ASCII string from the receiveBuffer.


// message header data

typedef struct {

  ubyte msgType;

  ubyte byteCount;

  ubyte checksum;

  ubyte srcAddress;

  ubyte destAddress;

} msgHdr_t;


The message header structure gives you the metadata associated with the message:

  1. MsgType - this field indicates the type of the message: BYTE_TYPE for a byte, INT_TYPE for an integer, LONG_TYPE for a long, BOOL_TYPE for a boolean value, ASCII_STRING_TYPE for a text string, BYTE_STRING_TYPE for a byte array and PACKED_TYPE if this is a packed message storing multiple data values.

  2. ByteCount - the length of the message body, excluding the header.

  3. Checksum - the CRC8 checksum for the message assigned by the sender.

  4. SrcAddress - the address of the sender.

  5. DestAddress - the destination address for the message.


The Receiver.c example program below shows how to use the msgHdr and msgType fields to parse an arbitrary message and print out the values it contains.


Unpacking data values

Unpacking data values is very simple; if you receive a packed message then you call getMsgType iteratively to get the type of each packed value, extract that value using one of the unpack functions and repeat until getMsgType() returns −1. The unpacking functions are:


  1. GetMsgType- gets the type of the next packed value, or returns −1 if no more packed values are in the receiveBuffer

  2. UnpackValue - unpacks a byte, integer or long value from the packed buffer and returns it.

  3. UnpackString - unpack an ASCII string from the receiveBuffer.

  4. UnpackBytes - unpacks a byte array from the receiveBuffer.



Sample RobotC programs

Three sample programs are included below to illustrate how to use the RobotC functions:


NXTBeeComms.h: This is the main header file that encapsulates all of the functions provided. Be sure to change line 32 to set the baud rate for your NXTBee.


crc8.h: This file stores the CRC8 lookup table and associated function.


SendSimpleData.c: The SendSimpleData program will loop sending an integer, a long and a byte value to the BROADCAST address. Any NXTBee or XStick in range will receive these values.


SendPackedData.c: The sendPackedData program will loop sending a packed message with a byte value, an integer, a long, a 5 character string and a byte array. Data is sent to the BROADCAST address to all NXTBees or XSticks in range will receive the message.


Receiver.c: An example of how to write a receiver program. It polls the Receive function to get data and then parses the data based on the type of the message received. You would adopt this program to do something specific with the data, such as control the speed of a robot’s motors.


NXTBeeComms_RobotC.zip: A zip file containing all of the RobotC programs needed to experiment with the library. I included a number of other sample test programs in this ZIP file.


Java Class Documentation


NXTBeeComms class is used on the Java side to send and receive data to/from a NXT (or indeed another PC running Processing with an XStick!) It is written for the Processing environment, which is a Java-based graphical programming tool used by artists and developers alike to quickly display graphical information. The core NXTBeeComms class is independent of Processing, so can be easily ported into leJOS if required.


The NXTBeeComms class encapsulates the same methods that the RobotC code. It supports simple data transmission and sending data in packed format. It also supports the addressing and checksum computation as before.


The class expects to have an XStick or XBee attached to your PC/Mac. If there is no NXTBee or XStick is attached then the class constructor will fail when it tries to open the serial port in the constructor.


Constructor

  1. NXTBeeComms - the default constructor initialises the class variables and assumes that it is receiving messages from all senders.

  2. NXTBeeComms(myaddr) - initialises the class to only receive messages for the given address myaddr (range 1..255).


Methods

The Java methods parallel the RobotC functions as follows:

  1. TransmitByte - send a single signed byte

  2. TransmitInt - send a two byte Java short. This value translates to a RobotC integer.

  3. TransmitLong - send a four byte Java integer to the NXT. This value translates to a RobotC long value.

  4. TransmitString - send an ASCII string to the NXT.

  5. TransmitBytes - send a byte array to the NXT.


Sending packed data is as follows:

  1. ClearTransmitBuffer - clear the transmit buffer and prepare for packing values

  2. PackByte - pack a single signed byte.

  3. PackInt - pack a two byte Java short.

  4. PackLong - pack a four byte Java integer.

  5. PackString - pack an ASCII string.

  6. PackBytes - pack a byte array

  7. TransmitPackedData - send the packed data to the receiver.


Receiving data follows the same model as in RobotC. You can see sample receiver code below.


Example Processing Java Sketches


  1. Packer.pde - Processing sketch that uses the NXTBeeComms class to send packed data to a receiving NXT. To use this class open it in Processing and then run the Receiver program on a NXT.

  2. Reader.pde - Processing sketch for receiving data and printing it on the console output. Run the Sender RobotC program on your NXT to send data and see it printed on the console output.