The Sparkfun Blocks
I’ve started experimenting with the SparkFun blocks for Intel Edison. To use them, you’re going to need a Base Block or a Console Block. If you’re deciding which one to get let me save you the trouble…buy the Base Block. While the console block will allow you to connect to other blocks and tether to your Edison, it won’t let you access Edison as a mass storage device, upload Arduino sketches, or connect other peripheral USB devices (webcams, usb headsets, etc.). For $4 more the base block is definitely worth it.
For this experiment I’ll be hooking up the 9dof block to the console block and reading the values from it. A quick image of the 9dof block is shown below.
You might notice that the 9dof block page contains no libraries and very little hardware information. In a nutshell, the 9dof block contains the LSM9DS0 sensor from STMicroelectronics. The datasheet can be found here. The sensor has a combined 6-axis accelerometer and magnetometer and a separate 3-axis gyroscope. The 6-axis accel/mag also has an integrated temperature sensor. The LSM9DS0 is the same sensor that resides on many 9-axis IMU arduino breakouts, including the ones from Adafruit and Sparkfun.
These breakouts have associated Arduino libraries and there are a few other C/C++ github repositories that people have developed, mostly for flight controllers. I’ve listed a couple that will work below…some require more work than others to run them on Edison. The ones listed as Arduino require you to load the library into Intel’s Arduino IDE and run it from there:
- Adafruit Library for Arduino
- Sparkfun Library for Arduino
- Library for Interfacing with Teensy
- A C library written for Intel Edison
- An expansive C library for 9-axis IMU sensors on different platforms [Note: also has python bindings]
Setup and Configuration
I didn’t find any stand-alone python libraries for the 9dof block and, to be honest, I just like figuring things out on my own. So, I started investigating writing my own library for python.
The next few paragraphs describe a bit of setup in order to get my library to work. If you’re looking for an easier solve, download my entire repo from github and run the shell script for these installs with
root@edison:~# sh ./dependencies.sh
That’ll take care of everything in one shot, so long as you’re on a recent build and connected to the internet. For the detailed manual instructions, read on.
I’m going to connect to the 9dof block using the I2C interface on Edison. Writing these connections is cumbersome, so we’re going to use Intel’s mraa library and python bindings to handle the connection and protocol for us. If you don’t have Intel’s mraa library installed yet, install it with
root@edison:~# echo "src mraa-upm http://iotdk.intel.com/repos/1.1/intelgalactic" > /etc/opkg/mraa-upm.conf root@edison:~# opkg update root@edison:~# opkg install libmraa0
Obviously, make sure you’re connected to the internet.
We’re going to be shifting and recombining bytes read from our sensor into signed integers. Python doesn’t like signed integers, it defaults to unsigned. While you could write a function to handle all this shifting with the base python modules, easier is to exploit Numerical Python (numpy), which has many more types implicit to it, including signed integers. So, let’s first install numpy using Alex T’s amazing repo. If you don’t already have it, you can add the repo to your opkg package manager:
root@edison:~# echo "src/gz all http://repo.opkg.net/edison/repo/all src/gz edison http://repo.opkg.net/edison/repo/edison src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32" >> /etc/opkg/base-feeds.conf root@edison:~# opkg update
Then installing numpy is as simple as:
root@edison:~# opkg install python-numpy
Connecting to 9DOF Block using the Python Shell
After install, open up your python prompt:
root@edison:~# python Python 2.7.3 (default, Dec 9 2014, 18:06:54) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>>
First thing is to import the mraa library and connect to our device over I2C
>>> import mraa as m >>> x = m.I2c(1)
The accel/mag (XM) and gyro (G) are separate, so let’s define the byte addresses of each sensor now
>>> G = 0x6B # gyro >>> XM = 0x1D # accel/mag/thermometer
To check for the connection to XM and G, check the register 0x0F. You should receive the XM response 0xD4 = 212L and the G response 0x49 = 73L if you’re hooked up and talking properly:
>>> WHO_AM_I = 0x0F >>> x.address(XM) >>> x.readReg(WHO_AM_I) 73L >>> x.address(G) >>> x.readReg(WHO_AM_I) 212L
Great. So we’re all connected and everything is working well. Now we need to configure the settings for our accel, mag, and gyro. To enable the accelerometer at 100 Hz continuously on all three axes write the bytes 0x67 and 0xF0 to the registers 0x20 and 0x24 respectively. Be sure to first set the I2C address to the accel/mag sensor.
>>> x.address(XM) >>> x.writeReg(0x20, 0x67) >>> x.address(XM) >>> x.writeReg(0x24, 0xF0)
We use the same idea to enable the mag and gyro to log continuously:
>>> # Enable the mag continuous >>> x.address(XM) >>> x.writeReg(0x26, 0x00) >>> # Enable the gyro continuous >>> x.address(G) >>> x.writeReg(0x20, 0x0F)
If you’re interested, we can also configure the temperature sensor to log at the same rate as the mag
>>> x.address(XM) >>> tempReg = x.readReg(0x24) >>> x.address(0x1d) >>> x.writeReg(0x24, tempReg | (1<<7))
For a full list of the configuration setting and registers, have a look at the product datasheet.
The default range for the accelerometer is +/- 2Gs, for the mag is +/- 2 Gauss, and for the Gyro is +/- 245 degrees per second. An example of how to set the accelerometer to 2Gs is given below. To set a different range, simply replace the line “Arange = ” with the corresponding range provided up top in the comments.
# Range the accel # 2G: Arange = (0b000 << 3) # 4G: Arange = (0b001 << 3) # 6G: Arange = (0b010 << 3) # 8G: Arange = (0b011 << 3) # 16G: Arange = (0b100 << 3) Arange = (0b000 << 3) # 2 Gs x.address(XM) accelReg = x.readReg(0x21) accelReg |= Arange x.address(XM) x.writeReg(0x21, accelReg)
Similar code for the mag and gyro, with comments listing other possible ranges:
# Range the Mag # 2GAUSS: Mrange = (0b00 << 5), // +/- 2 gauss # 4GAUSS: Mrange = (0b01 << 5), // +/- 4 gauss # 8GAUSS: Mrange = (0b10 << 5), // +/- 8 gauss # 12GAUSS: Mrange = (0b11 << 5) // +/- 12 gauss Mrange = (0b00 << 5) # 2 Gauss x.address(XM) magReg = x.readReg(0x25) magReg &= ~(0b01100000) magReg |= Mrange x.address(XM) x.writeReg(0x25, magReg) # Range the gyro # 245DPS: Grange = (0b00 << 4), // +/- 245 degrees per second rotation # 500DPS: Grange = (0b01 << 4), // +/- 500 degrees per second rotation # 2000DPS: Grange = (0b10 << 4) // +/- 2000 degrees per second rotation Grange = (0b00 << 4) x.address(G) gyroReg = x.readReg(0x23) gyroReg &= ~(0b00110000) gyroReg |= Grange; x.address(G) x.writeReg(0x23, gyroReg)
Finally, we’re on to reading the data from our sensors!
Data from the accel, mag, and gyro comes in as 6-bytes apiece: the first 2 of each are the x-axis data, the next 2 are the y-axis data, and the last 2 are the z-axis data. To grab the 6-bytes for any one sensor, set the address and then read 6-bytes from the corresponding register. For the accel, this looks like
x.address(XM) data = x.readBytesReg(0x80 | 0x28, 6)
Then we need to take the 2-byte pairs, bit shift the high-byte by 8 and combine it with the low byte.
x = np.int16(data | (data << 8)) y = np.int16(data | (data << 8)) z = np.int16(data | (data << 8))
And finally, we need to calibrate the data to actual units. The calibration for the accelerometer at 2Gs is 2 / 32768.0 – the positive range divided by the maximum positive 2-byte signed integer units. If you were using the 8G range, you’d use a calibration factor of 2 / 32768.0. Basically, it’s always a trade-off between range and precision: higher range gives lower precision and vice versa.
Alright! That’s it for this lesson on SparkFun’s 9dof block. Of course, it’s not super fun to code hardware by reading and writing registers by hand, so I’ve created a library and posted it on github that does all this stuff for you. An example script and instructions for use are also given in the repo. Happy hacking!