|For ROBOTC Bluetooth NXT functions, see: NXT Bluetooth Functions.
|For a complete setup guide on Bluetooth for the NXT, see: NXT Bluetooth Setup.
We are always impressed with what users are able to accomplish with ROBOTC. Our community continues to grow, and over time we find “power users” out there that not only understand the more difficult programming concepts, but are able to create tutorials to help many others perform certain tasks. Bluetooth is one of those harder behaviors to program. Luckily, Laurens over at Robot Square wrote up a nice tutorial on how to use Bluetooth communication with ROBOTC.
Take a look at Laurens‘s writeup over on robotsquare.com:
|Bluetooth (BT) is an industry standard short-distance (up to 10 meters) wireless communications protocol operating at 2.4 GHz. It can optionally use a higher power transmission to achieve distances up to 100 meters. The NXT utilizes the 10 meter option.
BT includes not only the low-level radio transmission (at 2.5 GHz) but also several higher layer message protocols (or profiles) designed for different applications. There are over 25 different BT profiles currently defined. Some of the more popular profiles include:
- The Serial Port Profile (SPP) is used to provide wireless emulation of a conventional RS-232 serial communications cable. This is the only protocol supported on the NXT.
- The Human Interface Device (HID) protocol is used for communication on wireless keyboards and mice. It is also used on some game controllers like the Nintendo Wii or SONY Playstation 3.
- The Headset Profile (HSP) is used to connect wireless headsets to devices like cellphones.
In order to connect two devices via BT, the devices must not only support BT but also support the type of profile that will be used for the connection. The NXT only supports the SPP so that it cannot, for example, directly connect to a Nintendo or Sony game controller.
The NXT has a very powerful communication capability between two NXTs using the wireless Bluetooth functionality built into every NXT. The Messaging functions described here provide an easy approach for using this communication. It limits the communication to messages containing three 16-bit parameters.
It is very easy to set up Bluetooth communications between two NXTs.
- Use the NXT’s on-brick user interface to make a connection between two NXTs.
- It is also possible to set up the connections within a user’s program but that is for advanced users.
- Use the sendMessage(nMessageID)and sendMessageWithParms(nMessageID, nParm1, nParm2) functions to send outgoing messages.
- Use the variables message and messageParms to retrieve the contents of a message. When you’ve finished processing a message, use the ClearMessage() function to “zero out” the message so that your program can process subsequent messages. The next time your program references the message variable, it will be for the next message that has arrived.
The ROBOTC BT messaging has been optimized for a single slave connection on the master. This allows for significantly less latency on the BT message link. Slaves can immediately transmit messages without having to wait for a polling request from the master. ROBOTC also allows for multiple slave support, but a description of this is beyond the scope of this tutorial. This optimization gives a performance improvement of three to 20 times over other architecture that support – at a significantly reduced performance level – multiple simultaneous slaves.
ROBOTC measured performance to send a BT message, receive it at far end, process it, generate a reply and receive it at original device is about 36 such transactions per second. Other implementations (e.g. NXT-G) typically support about 13 transactions per second.
ROBOTC allows full duplex operation over a single BT stream. Measured performance indicates that each end of the stream can autonomously send 250 messages per second. The half-duplex implementation is limited to 13.
Bluetooth Messaging is Incompatible with Debugging Over BT Link
NOTE: The ROBOTC IDE debugger can operate over either USB or Bluetooth connection to the NXT. When an application program uses the Bluetooth connection to send messages to another NXT then you cannot use the Bluetooth debugger connection. They are incompatible.
Differences Between NXT Messaging and the RCX Infrared Messaging
This functionality is similar to that found on the LEGO Mindstorms RCX with a few notable exceptions:
- The RCX uses an infrared communications link. The NXT uses a wireless Bluetooth link.
- The RCX used broadcast messages that could be received by any RCX. The NXT uses “directed” messages that go to a single NXT.
- Two RCXes sending messages simultaneously would corrupt both messages. The NXT’s Bluetooth allows simultaneous message transmission.
- There was no queuing of received messages on the RCX. When a new message arrives at the RCX it overwrites previously unhandled messages or it is discarded if the current message is not finished processing.
Sending Messages via Bluetooth
|Once you have two NXTs connected via BT, it is very easy to send messages between them. There are only three functions that are needed:
- cCmdMessageWriteToBluetooth writes a message.
- cCmdMessageGetSize get the size of the first message in a mailbox containing a queue of received messages.
- cCmdMessageRead removes the first message from a mailbox queue and copies it to a user buffer.
After calling each of the above functions you should check the returned value to determine the success/failure of the function.
Use the function cCmdMessageWriteToBluetooth(nQueueID, nXmitBuffer, nSizeOfMessage) to send a BT message to the far end NXT. Check the error code to make sure message was transmitted successfully. This sends the message (up to 58 bytes in length) in the variable nXmitBuffer to queue or mailbox number nQueueID on the far end NXT. nSizeOfMessage is the length of the message.
When messages are received over BT by a NXT they are automatically added to the end of one of the 10 message or mailbox queues. Use the function cCmdMessageGetSize(nQueueID) to determine whether any messages have been received. A positive return value indicates that a message was received and is the number of bytes in the message.
Use the function cCmdMessageRead(nQueueID, nRcvBuffer, nSizeOfMessage) to retrieve the first message from the specified mailbox and copy it to a user’s buffer at nRcvBuffer. Only the first nSizeOfMessage bytes of the message are copied. nQueueID is the mailbox number to obtain the message from.
The sample program "NXT BT Messaging No Error Checking.c" is a simple program to show how to use all three of the functions.
|There are two functions for easily sending messages. One sends a single 16-bit value and the other sends three 16-bit values. Either of the two NXTs can send messages at either time. It is the responsibility of the user program to not send messages too frequently as they may cause congestion on either the Bluetooth link or overflow of the NXT’s transmit and receive queues.
Sends a single 16-bit word message. nMessageID should range in value form -32767 to +32767. Message value 0 is invalid and should not be used. It is a special value to indicate "no message" received when using the message variable.
sendMessageWithParm(nMessageID, nParm1, nParm2)
This function is identical to the sendMessage function except that the message contains three 16-bit values. This is useful in easily sending separate items of information in a single message. Do not use a value of zero for nMessageID.
|The NXT firmware automatically receives messages and adds them to a queue of incoming messages. The application program takes the messages from this queue and processes them one at a time. The variables message and messageParm contain the contents of the current message being processed. The function ClearMessage discards the current message and sets up to process the next message.
This variable contains the 16-bit value of message received over the Bluetooth channel. It has a range of -32767 to 32767. A value of zero is special and indicates that there is “no message”. Whenever the value is zero and the message variable is accessed, the firmware will check to see if it has any received messages in its queue; if so, it will take the first message and transfer its contents to the message and messageParms variables. These two variables will continue to contain the message contents until the user’s program indicates it has finished processing the message by calling the ClearMessage() function.
Array containing optional message parameters (up to 3 16-bit words) for messages received over the RCX infrared channel. messageParm is the same as message. messageParm and messageParm are additional 16-bit values.
Boolean function that indicates whether a unprocessed message is available in the NXT's received message queue. This is useful when multiple messages have been queued and your program wants to skip to the last message received. Your program can simply read and discard messages as long as a message is available in the queue.
Clears the current message. The next time the message variable is accessed, the firmware will attempt to obtain the first message from the queue of messages received by the NXT.
Do not send messages faster than about one message per 30 milliseconds or it is possible for some messages to be lost.
Skipping Queued Messages
|A typical application might have one NXT send a message to the NXT on a periodic basis. For example, it might send a message containing the current values of sensors S1 and S2 every 100 milliseconds. Due to processing delays in the receiving NXT, several messages may have been queued and your program may want to rapidly skip to the last message received. The following are two code snippets that show how this might be accomplished.
|The code in the NXT sending the sensor values:
sendMessageWithParm(SensorValue[S1], SensorValue[S2], 0);
wait1Msec(100); // Don’t send messages too frequently.
|The code in the receiving NXT:
// Skip to the last message received
ClearMessage(); // We’re ready to process the next message
temp = message; // Obtain the next message
if (message == 0)
// No message is available to process
// A message is ready to be processed
remoteSensor1 = message; // the value of ‘S1’ from the remote NXT
remoteSensor2 = messageParm; /* the value of ‘S2’ from the remote NXT . . . */
/* user code to process the message. It may have many delays. */
Master vs Slave Device
|One end of a BT connection is the master device and the other end is the slave device. The master device generates the clocking signal used for the BT connection and the slave device derives its clock from the received radio signal. This results in the following restrictions:
- A device can be either a slave or a master, but not both.
- A single master can (optionally) make connections to multiple slaves.
- A slave can only connect to a single master. It cannot have connections to other masters as it would then need to support multiple clock sources!
- The BT protocol is asymmetric. At its lowest level, A master can transmit over radio at any time.
- A slave only transmits in response to a request from a master.
During the initial connection setup, the two devices negotiate the maximum bandwidth that they will use and how often they are listening for traffic. This allows the devices to use a low-power mode (i.e. the radios are only enabled part of the time) at the expense of lower bandwidth.
Bluecore Bluetooth Information
|BT implementation on the NXT uses a "Bluecore" chip from CSR. Bluecore is a self-contained implementation of BT that manages the BT hardware and protocols. It has a few limitations that are common to many other BT hardware implementations:
- The "search" function requires 100% of the BT resources. When a search is in progress no other BT activity can take place on the NXT.
- The module can be in either "command" or "data" mode. They are mutually exclusive states.
- In command mode, housekeeping functions related to the BT protocol are being performed -- this includes things like searching, pairing, making connections and disconnection.
- Data mode is used to transfer data between two devices over the BTX wireless link.
- Bluecore supports a single "master" device connecting to up to three 'slave' devices at one time. However, it can only communicate data with one device at a time; it could not simultaneously receive data from all three slaves!
On the radio side, Bluecore can have three connections (or "streams") to different slave devices. However, on the other side -- i.e. the connection from Bluecore to the NXT CPU, only a single connection is possible. It is this implementation that leads to the above restrictions. So, for example:
- If you wanted to add a second slave connection to a NXT, the Bluecore module would be switched into "command" mode. This would interrupt "data" traffic from the original connection. The appropriate commands would be performed to set up the connection and then Bluecore would be switched back to "data" mode.
- In data mode, Bluecore is only connection to one of the two streams/connections at a time. If data from the disconnected stream is received, it is discarded.
- Bluecore can be switched from "data mode on stream 1" to "data mode on stream 2". This is done by switching to "command" mode, sending the "switch stream" command and then switching back to "data" mode; this takes over 100 milliseconds.
NXT-G Bluetooth Messaging Compatibility
|The NXT-G firmware has built a message passing system on top of the NXT Bluecore implementation. It works as follows:
- Messages can contain up to 58 bytes of data. The restriction is that firmware has a fixed 64-byte format for message buffers and there are six bytes of overhead in the structure.
- Single master can connect to up to three slaves.
- Messages can be sent to one of ten queues. The queue number is one of the overhead bytes.
- When a message is sent from the master, it is put on a queue of outgoing BT messages.
- Messages are transmitted from the queue in a FIFO basis whenever the previous queue item is completed.
- The firmware looks at the stream ID -- ie. which of the three possible connections -- before transmitting a message.
- If the stream ID does not match the currently "active" stream, then the active stream is switched to this stream by the 100+ millisecond process described above.
- Slave devices cannot use the above process! The slave does not know whether it's stream is the master's "active" stream. The implementation for messaging from the slave is as follows:
- An outgoing message from the slave is always added to one of the ten outgoing message queues. One queue for each of the ten possible "mailboxes".
- The message sits in the outgoing queue until the slave receives a "poll for message from mailbox N" message from the master.
- In response to the "poll for message" the slave responds with either "the selected mailbox is empty" or it sends the first message found in the queue.
If there is only a single slave, then the above process does not incur the 100+ msec delays of switching 'active' streams on the master. It still incurs a delay while the slave waits for a polling request from the master.