This example shows how to use the i2c and i2c_stream_read programs with an extension board for the Khepera III robot. The extension board used here is the odor sensor board developed by DISAL. With its tree VOC sensors, this board allows to measure the concentration of alcohol (or other substances) in the air. The sensors are internally sampled at several kHz, and the board integrates (averages) them over a certain period to provide a few samples per second to the outside world.
The interface to the outside world is an I2C bus, connected to the main CPU on the Khepera III robot. Over this I2C bus, the board can be configured and samples can be read in two different modes:
In snapshot mode, the board returns the last acquired value for each sensor.
In streaming mode, the board sends each sample exactly once. I.e., once streaming is started, the board buffers the samples in its internal memory. This buffer has to be read (and emptied) continuously in order to avoid buffer overruns.In this example, we will configure the integration interval and read the samples both in snapshot and streaming mode. This is all done manually with the general-purpose i2c and i2c_stream_read programs. Of course, if one needs to do this more frequently, it is advisable to write a separate program for these tasks.
== Setup ==
Boot a Khepera III robot (equipped with an odor sensor board) and make sure it is connected to your computer. In the remainder of this chapter, we assume that your robot is connected via USB.
Copy the I2C programs onto the robot
You are now ready to work with the odor board.
== Configuring the integration interval ==
The odor board is a register based device with I2C address 0x50. The integration interval is stored in an 8-bit register at address 0x90.
First, let us read this register by issuing the following command:
The output may look a bit cryptic at first glance, but it is actually very simple to read. The above message simply says that 2 messages have been transmitted on the I2C bus. The first message was a write message with a single byte (0x90), and the second message was a read message with a single byte (0x0a). This last byte is obviously the content of the register, and translates to 10 in decimal notation.
Hence, our current integration interval is 10. Note that the odor board actually uses a power-of-two scale for this interval, i.e. setting the interval to 9 would produce twice as many samples per second.
10 is quite slow, though - let's set the interval to 8, which is 4 times faster. To write that register, we simply transmit this new value after the register number:
Operation confirmed! One message was sent, containing two bytes (0x90, 0x08). Just to make sure that the new value has been accepted and stored in the register, let us read the register again:
Everything looks all right.
=== Reading the last value (snapshot mode) ===
The odor board stores the last acquired sample in register 0x92 (read-only). A sample actually consists of one value for each sensor, plus a timestamp derived from the internal oscillator on the odor board. All values are 16-bit and therefore require 2 bytes, totaling to a register size of 8 bytes.
To read this register, we will issue the following command:
The received message is to be interpreted as follows:
- Sensor 1:
- Sensor 2:
- Sensor 3:
- Timestamp: 0x6b 0x0d -> 107 + 13 * 256 = 3435
This snapshot mode mode is very handy if one only needs to request a sample every now and then, e.g. to take a decision whether or not the odor concentration has exceeded a certain threshold or not. However, if you want to plot the evolution of the odor concentration, you may want to query the board all the time for new values. If you do that too often, you may obtain the same sample several times. This is an effect that can be easily demonstrated with:
which does the same as above, but 100 times in a row. The output may look like this:
In this example, every sample has been transmitted about N (TODO) times, but this will depend upon the load of the CPU and the I2C bus.
=== Reading a stream of samples (streaming mode) ===
To get a consistent picture of the evolution of the odor concentration, it is advisable to "stream" the samples in a way that each sample is transmitted exactly once.
The odor board indeed provides a VOC streaming register (0x93). Reading this register with the i2c program is a bit painful, though, because streaming requires several (different) messages to be sent.
Fortunately, there is this other program - i2c_stream_read - which does all that automatically. This program takes as arguments the I2C device address (0x50), the streaming register (0x93) and the block length (8):
and will return something like this:
Each line corresponds to an 8-byte data block that has been transmitted. The first byte of the block is a status byte indicating the number of samples remaining in the buffer (including the currently transmitted sample) and is printed in the second column (all 1's here). The 7 data bytes - printed in hex notation - make up the last column.
The odor sensor values are coded in the last 6 data bytes of each block. E.g., in the block we got the following values:
- Sensor 1:
- Sensor 2:
- Sensor 3:
== Plotting odor samples ==
To plot the evolution of the odor concentration, we just need to convert the output of the i2c_stream_read program into something that Matlab can read, and plot it there afterwards.
First, let us launch the program from a computer and redirect the output into a file:
Once you feel you've collected enough samples, press Ctrl-C to stop the program.
Use parse_stream.pl to convert the samples into a text file with tab-separated values, i.e.
Finally, launch Matlab and type
This Matlab script (m-file) will load the matlab_odor_stream file and plot the three curves.