9DoF Razor IMU M0 Hookup Guide

Pages
Contributors: jimblom
Favorited Favorite 7

Using the MPU-9250 DMP Arduino Library

Here are some quick tips to help you get started writing your own firmware for the 9DoF Razor IMU M0 using the SparkFun MPU-9250 DMP Arduino Library.

Set Up

As with any library, to call it into your sketch you'll need to include it at the top. You'll also need to create an object of type MPU9250_DMP -- we'll make one called imu, which will be used throughout the sketch.

language:c
#include <SparkFunMPU9250-DMP.h> // Include SparkFun MPU-9250-DMP library
//#include <Wire.h> // Depending on your Arduino version, you may need to include Wire.h

MPU9250_DMP imu; // Create an instance of the MPU9250_DMP class

Then, in the setup function initialize the MPU-9250 by calling imu.begin(). You can check the return value of this function to ensure that the IMU is correctly connected and was successfully initialized.

language:c
if (imu.begin() != INV_SUCCESS)
{
    while (1)
    {
        // Failed to initialize MPU-9250, loop forever
    }
}

Note that imu.begin() – all of the error-returning functions in this library, in fact – returns a 0 on success. Check for them to return INV_SUCCESS for a more verbose error check.

Configuring the MPU-9250

Once you've initialized the MPU-9250, you can configure it to your hearts desire. You can use setSensors to enable/disable specific sensors in the IMU. Disabling the gyroscope and magnetometer, for example, can save loads of power consumption.

language:c
// Use setSensors to turn on or off MPU-9250 sensors.
// Any of the following defines can be combined:
// INV_XYZ_GYRO, INV_XYZ_ACCEL, INV_XYZ_COMPASS,
// INV_X_GYRO, INV_Y_GYRO, or INV_Z_GYRO
imu.setSensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS); // Enable all sensors

You can also set the full-scale range of both the accelerometer and gyroscope using the setAccelFSR and setGyroFSR functions. (The magnetometer only has one possible full-scale range -- ±4912 µT.)

language:c
// Use setGyroFSR() and setAccelFSR() to configure the
// gyroscope and accelerometer full scale ranges.
// Gyro options are +/- 250, 500, 1000, or 2000 dps
imu.setGyroFSR(2000); // Set gyro to 2000 dps
// Accel options are +/- 2, 4, 8, or 16 g
imu.setAccelFSR(2); // Set accel to +/-2g

The gyroscope can be set to ranges of ±250, 500, 1000, or 2000 degrees per second (dps), and the accelerometer supports ranges of ±2, 4, 8, or 16 g.

Finally, you can configure the digital low pass filter (DLPF) and sample rate of the sensors:

language:c
// setLPF() can be used to set the digital low-pass filter
// of the accelerometer and gyroscope.
// Can be any of the following: 188, 98, 42, 20, 10, 5
// (values are in Hz).
imu.setLPF(5); // Set LPF corner frequency to 5Hz

// The sample rate of the accel/gyro can be set using
// setSampleRate. Acceptable values range from 4Hz to 1kHz
imu.setSampleRate(10); // Set sample rate to 10Hz

// Likewise, the compass (magnetometer) sample rate can be
// set using the setCompassSampleRate() function.
// This value can range between: 1-100Hz
imu.setCompassSampleRate(10); // Set mag rate to 10Hz

The sample rate of the accelerometer and gyroscope can reach 1kHz, while the maximum sample rate of the magnetometer is 100Hz. The corner frequency of the low-pass filter -- which operates on the accelerometer and gyroscope only -- can be set to 5, 10, 20, 42, 98, or 188Hz.

Reading from the MPU-9250

Once your IMU is configured to fit your needs, reading from the sensor is as simple as calling imu.update() and checking the ax, ay, az, ax, ay, az, ax, ay, and mz class variables (e.g. imu.ax, imu.gy, imu.mz, etc).

language:c
// Call update() to update the imu objects sensor data. You can specify 
// which sensors to update by OR'ing UPDATE_ACCEL, UPDATE_GYRO, 
// UPDATE_COMPASS, and/or UPDATE_TEMPERATURE.
// (The update function defaults to accel, gyro, compass, so you don't 
// have to specify these values.)
imu.update(UPDATE_ACCEL | UPDATE_GYRO | UPDATE_COMPASS);

The variables can be converted from raw, signed 16-bit values to their sensor's respective units by passing them to the calcGyro, calcAccel, and calcMag functions:

language:c
float accelX = imu.calcAccel(imu.ax); // accelX is x-axis acceleration in g's
float accelY = imu.calcAccel(imu.ay); // accelY is y-axis acceleration in g's
float accelZ = imu.calcAccel(imu.az); // accelZ is z-axis acceleration in g's

float gyroX = imu.calcGyro(imu.gx); // gyroX is x-axis rotation in dps
float gyroY = imu.calcGyro(imu.gy); // gyroY is y-axis rotation in dps
float gyroZ = imu.calcGyro(imu.gz); // gyroZ is z-axis rotation in dps

float magX = imu.calcMag(imu.mx); // magX is x-axis magnetic field in uT
float magY = imu.calcMag(imu.my); // magY is y-axis magnetic field in uT
float magZ = imu.calcMag(imu.mz); // magZ is z-axis magnetic field in uT

Using the Interrupt or Data-Ready

Instead of constantly polling the update function, you can use the MPU-9250's interrupt output to tell you when new data is ready. First, in the setup area, you should call enableInterrupt. (Don't forget to set your Arduino's interrupt pin as an input as well!)

language:c
#define INTERRUPT_PIN 4 // MPU-9250 INT pin tied to D4
...
void setup()
{
    pinMode(INTERRUPT_PIN, INPUT_PULLUP); // Set interrupt as an input w/ pull-up resistor
    ...
    // Use enableInterrupt() to configure the MPU-9250's 
    // interrupt output as a "data ready" indicator.
    imu.enableInterrupt();

    // The interrupt level can either be active-high or low. Configure as active-low.
    // Options are INT_ACTIVE_LOW or INT_ACTIVE_HIGH
    imu.setIntLevel(INT_ACTIVE_LOW);

    // The interrupt can be set to latch until data is read, or as a 50us pulse.
    // Options are INT_LATCHED or INT_50US_PULSE
    imu.setIntLatched(INT_LATCHED);
}

You can set the interrupt's active level to high or low, and set it to latch until the sensor is read or to send a 50µs pulse.

Once configured, simply read the status of your Arduino's interrupt pin. If it's active, you'll know to update the IMU's sensors.

language:c
if ( digitalRead(INTERRUPT_PIN) == LOW ) // If MPU-9250 interrupt fires (active-low)
{
    imu.update() // Update all sensor's
    // ... do stuff with imu.ax, imu.ay, etc.
}

Alternatively -- if you don't want to use the interrupt pin -- you can check the return value of dataReady, to check if new data is available. This function returns a boolean -- true if new data is ready.

language:c
if ( imu.dataReady() ) // If new IMU data is available
{
    imu.update(); // Update all sensor's
    ...
}

Using the Digital Motion Processor

The MPU-9250's digital motion processor (DMP) allows you to offload tasks like quaternion calculation, step-counting, and orientation-determining off to the IMU.

Configuring the Digital Motion Processor (DMP)

To use any of those functions, you first need to initialize the DMP by calling the dmpBegin function. This should be called after imu.begin().

dmpBegin's first parameter specifies which features of the DMP you want to enable. It can be an OR'd combination of any of the following:

  • DMP_FEATURE_PEDOMETER -- Pedometer counts steps and the amount of time those steps were taken in.
  • DMP_FEATURE_TAP -- Single and/or double-tap detection in any of the three planes.
  • DMP_FEATURE_ANDROID_ORIENT -- Detects portrait, landscape, reverse portrait, and reverse landscape orientations.
  • DMP_FEATURE_6X_LP_QUAT -- 6-axis (accelerometer and gyroscope) quaternion calculation.
  • DMP_FEATURE_LP_QUAT -- Low-power (accelerometer only) quaternion calculation.
  • DMP_FEATURE_GYRO_CAL -- Gyroscope calibration. After 8 seconds of no motion, the gyroscope axes are re-calibrated to 0.
  • DMP_FEATURE_SEND_RAW_ACCEL -- Sends raw accelerometer data to the DMP's FIFO buffer.
  • DMP_FEATURE_SEND_RAW_GYRO -- Sends raw gyroscope data to the DMP's FIFO buffer.
  • DMP_FEATURE_SEND_CAL_GYRO -- Sends calibrated gyroscope data to the DMP's FIFO buffer.

Note that the pair of quaternion-calculating features are mutually exclusive -- only use one of those features at a time. The same goes for the calibrated and raw gyroscope data gathering features.

A second, optional parameter for dmpBegin is the update rate, which can be anywhere between 4 and 200 Hz. Here's a quick example, demonstrating how to initialize the DMP to stream accelerometer, calibrated gyroscope, and quaternion data:

language:c
void setup
{
    imu.begin(); // Initialize the MPU-9250.

    // Initialize the digital motion processor
    imu.dmpBegin(DMP_FEATURE_SEND_RAW_ACCEL | // Send accelerometer data
                 DMP_FEATURE_GYRO_CAL       | // Calibrate the gyro data
                 DMP_FEATURE_SEND_CAL_GYRO  | // Send calibrated gyro data
                 DMP_FEATURE_6X_LP_QUAT     , // Calculate quat's with accel/gyro
                 10);                         // Set update rate to 10Hz.
}

Reading from the DMP

The DMP streams its data to the MPU-9250's 512-byte first-in, first-out (FIFO) buffer, so to get data from the DMP, the FIFO must be updated. You can use the fifoAvailable function, to check how full the FIFO is. Then call dmpUpdateFifo to read from the top of the FIFO.

language:c
if ( imu.fifoAvailable() > 0 ) / Check for new data in the FIFO
{
    // Use dmpUpdateFifo to update the ax, gx, qx, etc. values
    if ( imu.dmpUpdateFifo() == INV_SUCCESS )
    {
        // The following variables will have data from the top of the FIFO:
        // imu.ax, imu.ay, imu.az, -- Accelerometer
        // imu.gx, imu.gy, imu.gz -- calibrated gyroscope
        // and imu.qw, imu.qx, imu.qy, and imu.qz -- quaternions
    }
}

Serial Output Through Hardware UART Pins

The default test code does not output serial data automatically to the hardware Tx and Rx pins. It currently outputs to the SerialUSB port (i.e. the Arduino Serial Monitor). To adjust for the Hardware Serial UART pins, adjust the config.h file on line 25 to print to the Serial1 port (i.e. pin 0 for Rx and pin 1 for Tx):

language:c
#define LOG_PORT SERIAL_PORT_USBVIRTUAL

to

language:c
#define LOG_PORT SERIAL_PORT_HARDWARE

Additionally, the default firmware is currently waiting for a "$" under our QC test procedures so you would need to comment out line 131 in the _9DoF_Razor_M0_Firmware.ino by changing:

language:c
Serial1.begin(9600);

to

language:c
//Serial1.begin(9600);

Additionally, you need to comment out line 163 in the _9DoF_Razor_M0_Firmware.ino. We recommend commenting out this section of code by adding a //'s where it says:

language:c
if ( Serial1.available() )
{
if ( Serial1.read() == '$' ) production_testing();
}

After commenting out the lines, it should look like like the following:

language:c
//if ( Serial1.available() )
//{
//  if ( Serial1.read() == '$' ) production_testing();
//}

Be sure to change the baud rate when you initialize the serial port to match the receiving serial device. The default is 115200 baud. By changing a few lines and printing the string to one of the hardware UARTs, the other serial UART that is connected can read the serial data. At a minimum, make sure to connect GND-GND, Tx-RX, and Rx-Tx. This is assuming that you are connecting the 9DoF Razor to a 3.3V device. If the other serial device can be powered at 3.3V, you can connect it to the 9DoF Razor's 3.3V pin.

If you have not used a serial UART before, try looking at this tutorial for more information about serial communication and UARTs.

Check Out the Examples!

The MPU-9250 DMP library includes a handful of examples, which demonstrate everything from getting raw sensor data from the IMU to using the digital motion processor to track steps or orientation. Check out those examples under the File > Examples > SparkFun MPU-9250 DMP Arduino Library menu as you continue working with the library.