The NXT supports two kinds of sensor interfaces.
1. “Dumb” analog sensors provides a voltage level that the NXT converts to a digital value. For example, the NXT sound and the NXT light sensors. There is only a single value associated with an analog sensor.
2. “Smart” digital sensors that communicate with the NXT via the industry standard I2C protocol. The sensor can have multiple values – for example, a three-axis gyroscope has three different sensor values. The NXT Ultrasonic sensor uses the I2C protocol. The sensors are call “smart” because they typically contained an embedded microcontroller (CPU) chip.
This document describes how to write device drivers for the I2C sensors.
I2C is a multi-byte master-slave messaging protocol. The NXT is always the master and the sensor is the slave. The master device always initiates the messaging. It sends two types of messages.
Sensor Type |
Description |
Ultrasonic |
Measures the distance to an
object by bouncing an ultrasonic pulse off the object and measuring the
elapsed time for the echo to be received. Basic mode returns the closest object
found. An expanded mode returns the distance to up to five objects. |
Gyroscope |
Typically contains one to
three axis of measurement for a small gyroscope. Each axis may have one or
two bytes of precision. |
Accelerometer |
Typically contains one to
three axis of measurement for a small accelerometer. Each axis may have one
or two bytes of precision. |
Gyroscope + Accelerometer |
Combined gyroscope and
accelerometer. |
Motor Multiplexer |
Provides control for additional
motors. Typically four motors are supported. |
RCX IR Communication |
Provides interface to an
infrared communications link. Used to talk to the RCX and selected other LEGO
IR devices. |
Video Camera |
Provides access to smart
video camera sensors. This is a smart camera where, rather than returning a
video image, it returns the location in the camera image of a shape or color.
I2C messages are sent to the camera to tell it the shape to look for. |
Hitechnic (www.hitechnic.com) and Mindsensors (www.mindsensors.com) are two suppliers of 3rd party sensors for the NXT.
I2C is a multi-byte master-slave messaging protocol. The NXT is always the master and the sensor is the slave. The master device always initiates the messaging. It sends two types of messages.
· A “write” message is used to send one or more bytes of data to the sensor.
· A “read” message is used to read one or more bytes from the sensor.
Both message types begin with a header consisting of the sensor address and a “register index” within the sensor. For most NXT devices, the register address is 2. The register index is the internal location (address) within the sensor that you want to read/write.
Each slave I2C device is assigned an address because the I2C protocol supports multiple slaves connected to a single master. This architecture is possible with some 3rd party NXT devices but is beyond the scope of this document.
The NXT I2C implementation operates at 9600 bits / second. Or about one byte of data transferred per millisecond. Read messages are N + 3 bytes in length where ‘N’ is the number of bytes to read and ‘3’ is two bytes of protocol overhead. Write messages are N + 2 bytes in length. To read the data from a 3-axis accelerometer takes 9 bytes – 3 bytes of overhead and two bytes of data for each axis. The time to perform I2C I/O can become significant!
Fortunately, ROBOTC has a “fast” transmission mode which operates about five times faster than the 9600 baud found in the standard NXT-G firmware. At the time of writing, all 3rd party sensors have been found compatible with this faster mode and its use is strongly encouraged. Only the LEGO developed Ultrasonic sensor needs to operate at the slower 9600 baud. Third party sensors generally contain a microcontroller that has integrated hardware support for I2C whereas the Ultrasonic sensor uses a firmware implementation for the I2C protocol.
NOTE: the I2C standard specifies that I2C device should support clock rates up to 400 KHz. This is a little faster than the clock used for NXT I2C sensors!
ROBOTC provides several built-in functions for easily sending read or write messages to an I2C sensor.
Function |
Description |
sendI2CMsg(nPort,
sendMsg, nReplySize); |
Send an I2C message on the
specified sensor port. |
nI2CBytesReady[] |
This array contains the
number of bytes available from a I2C read on the specified sensor port. |
readI2CReply(nPort,
replyBytes, nBytesToRead); |
Retrieve the reply bytes
from an I2C message. |
nI2CStatus[] |
Currents status of the
selected sensor I2C link. |
nI2CRetries |
This variable allows changing
the number of message retries. The default action tries to
send every I2C message three times before giving up and reporting an error.
Unfortunately, this many retries can easily mask any faults that can exist. |
SensorType[] |
This array is used to
configure a sensor for I2C operation. It also indicates whether ‘standard’ or
‘fast’ transmission should be used with this sensor. |
There are several well-commented sample programs in the ROBOTC distribution that illustrate the use of these functions.
The simplest approach to implementing a “device driver” for an I2C sensor is to use “inline” code that reads the value of the sensor whenever you want to retrieve the current value. Generally you call a function to perform the I2C read. The function needs to do the following steps:
1. Wait for any previous I2C sensor activity to complete. I2C messages must be performed one at a time!
2. Initiate an I2C message to read the sensor value.
3. Wait for the I2C read to complete.
4. Extract the sensor value from the reply received from the sensor.
Several of the NXT programming environments – NXT-G, NXC – use this method for handling the Ultrasonic sensor. A significant drawback of this method is that it takes about four milliseconds to read the current sensor value; this is time when you program execution is suspended waiting on the I2C transaction. This can be a “long” time for a real time system!
An alternative approach is to continuously read the sensor value as a background activity. When your program wants the value of the sensor it simply uses the value that was last read. This preferred implementation is discussed later in this document.
The above four step description presented a simplified version of the activities that needed to be performed. The additional complexity that needs to be dealt with includes:
1. The application should initialize the SensorType to an I2C type.
2. There may be some one-time initialization messages that need to be sent to the sensor. For the Ultrasonic sensor this includes:
· Reset the sensor.
· Configure the measurement scale to be ‘cm’ or ‘inch’.
3. Some devices require a setup delay while they perform initialization. You should not send new messages to the device during this time
4. Recover from error conditions from the I2C messaging to the sensor. The cable may not be connected or the sensor may use an external power source that is not available.
5. Some sensors require a “guard” time between I2C transactions. The sensor may give inaccurate results if values are polled too fast. On the Ultrasonic sensor, 25 milliseconds should elapse between read requests.
6. Some sensors only update their results on a periodic basis. For example, a GPS sensor may update values only once per second. It doesn’t make sense to poll the sensor on a faster basis than its update rate!
ROBOTC has a very powerful utility for testing digital sensors on the NXT. Digital sensors are those that support the industry standard I2C protocol for communications between the NXT and the sensor. The utility allows you to easily test an I2C sensor on the NXT. A screen shot of the utility is shown below.