Reading MPU9250 sensors with Arduino

  • avatar

MPU-9250 is one of the most advanced combined accelerometer, gyroscope and compass small size sensors currently available. It replaces the popular MPU-9150 lowering the power consumption, improving gyro noise and compass full scale range performance. It has many advanced features, including low pass filtering, motion detection and even a programmable specialized processor.

MPU9250 sensors

Internally it includes the MPU-6500, which contains a 3-axis gyroscope plus a 3-axis accelerometer, and the AK8963, the market leading 3-axis digital compass. The MPU-9250 uses 16-bit analog-to-digital converters (ADCs) for digitizing all 9 axes.

Gyroscope

A gyroscope is a device used for measuring or maintaining orientation and angular velocity. Measured in degrees (or radian) per second, angular velocity is the change in the rotational angle of the object per unit of time.

Depending on the direction there are three types of angular rate measurements:

  • Yaw: the horizontal rotation on a flat surface when seen the object from above.

  • Pitch: vertical rotation as seen the object from front.

  • Roll: horizontal rotation when seen the object from front.

Acceletometer

Accelerometer sensors are integrated circuits (ICs) that measure acceleration, which is the change in speed per unit time. Measuring acceleration makes it possible to obtain information such as object inclination and vibration.

Commonly, g is used as a unit for acceleration, relative to standard gravity (1g = 9.80665m/s2).

Magnetometer

Magnetometer provides information about the magnetic field detected by the device sensor, and in theory, can expose location of a user. The magnetometer sensor measures the magnetic field for all three physical axes (x, y, z) in μT (micro Tesla).

The Absolute Orientation Sensor is one of the common use-cases of a magnetometer and represents a stationary orientation (fixed to the magnetic field vector and gravity vector) to the Earth plane.

Components

arduino-nano

1x Arduino Nano (or another Arduino module)

$3.08

Buy now

mini-breadboard

1x Mini Breadboard

$1.10 $1.07

Buy now

mpu9250

1x MPU9250

$3.82 $3.67

Buy now

dupont

Dupont wires

$1.53 $1.47

Buy now

github

I2C library

Download here

Wiring schema

MPU9250 module has 10 pins but for basic usage we will only need 4.

PIN

Description

VCC

Power supply pin

GND

Ground pin

SCL/SCLK

I2C Serial Clock/SPI Serial Clock pin

SDA/SDI

I2C Serial Data/SPI Serial Data pin

EDA

I2C Serial Data input for external sensors connection pin

ECL

I2C Master Serial Clock for external sensors connection pin

AD0/SDO

I2C Address/Serial data out pin

INT

Interrupt pin

NCS

Chip selection pin

FSYNC

Frame Synchronization input pin

As mentioned, for basic usage connect the power supply pins and SDA, SCL pins according to the connection diagram shown below:

arduino_mpu9250.png

Interpreting data

We have the official MPU9250 datasheet and register map available in our official repository. It describes the function and contents of each register within the MPU-9250, including the magnetometer. We recommend you to read Decimal, binary and hex representations post to easily identify a register and understand the meaning of the content inside it.

mpu9250_register_map.pngThe first two columns of the register map represent the address in HEX and decimal formats followed by the register name. Some of the registers are read-only (marked with R) and others allow us to write (marked with R/W). The content of the register is represented using 8-bits. In various cases, register's value may represent more than one thing, in other words, every bit or group of bits may have a different meaning, e.g., GYRO_CONFIG (register 27).

The MPU-9250 has 16-bits precision for each of the sensors. That means that two 8-bits registers are used to represent the output. We will read 8-bits data separately from each register and then concatenate them to form 16-bits.

Install Arduino library for I2C

We will use I2C protocol to interact with registers and read/write data. The I2C library provides a very simple interface for that purpose and can be reused in other projects that use I2C protocol. It can be downloaded from our official repository.

To import a library, open the Arduino IDE, go to Sketch > Include Library > Add .ZIP Library and select the library file downloaded from our GitHub repository.

arduino_import_library.png

Then you can simply use include statement:

#include "I2C.h"

It will include the library with predefined functions to interact with registers.

Arduino code

We've defined a separate struct for each raw sensor data: gyroscope_raw, accelerometer_raw, magnetometer_raw and temperature_raw. Every raw struct has a data normalizer function based on the current configuration. Human readable normalized values are stored in another struct called normalized.

Make sure to follow the previous step and import I2C library in order to use it with the include statement:

#include "Wire.h"
#include "I2C.h"

#define MPU9250_IMU_ADDRESS 0x68
#define MPU9250_MAG_ADDRESS 0x0C

#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18

#define ACC_FULL_SCALE_2G 0x00
#define ACC_FULL_SCALE_4G 0x08
#define ACC_FULL_SCALE_8G 0x10
#define ACC_FULL_SCALE_16G 0x18

#define TEMPERATURE_OFFSET 21 // As defined in documentation

#define INTERVAL_MS_PRINT 1000

#define G 9.80665

struct gyroscope_raw {
int16_t x, y, z;
} gyroscope;

struct accelerometer_raw {
int16_t x, y, z;
} accelerometer;

struct magnetometer_raw {
int16_t x, y, z;

struct {
int8_t x, y, z;
} adjustment;
} magnetometer;

struct temperature_raw {
int16_t value;
} temperature;

struct {
struct {
float x, y, z;
} accelerometer, gyroscope, magnetometer;

float temperature;
} normalized;

unsigned long lastPrintMillis = 0;

void setup()
{
Wire.begin();
Serial.begin(115200);

I2CwriteByte(MPU9250_IMU_ADDRESS, 27, GYRO_FULL_SCALE_1000_DPS); // Configure gyroscope range
I2CwriteByte(MPU9250_IMU_ADDRESS, 28, ACC_FULL_SCALE_2G); // Configure accelerometer range

I2CwriteByte(MPU9250_IMU_ADDRESS, 55, 0x02); // Set by pass mode for the magnetometers
I2CwriteByte(MPU9250_IMU_ADDRESS, 56, 0x01); // Enable interrupt pin for raw data

setMagnetometerAdjustmentValues();

//Start magnetometer
I2CwriteByte(MPU9250_MAG_ADDRESS, 0x0A, 0x12); // Request continuous magnetometer measurements in 16 bits (mode 1)
}

void loop()
{
unsigned long currentMillis = millis();

if (isImuReady()) {
readRawImu();

normalize(gyroscope);
normalize(accelerometer);
normalize(temperature);
}

if (isMagnetometerReady()) {
readRawMagnetometer();

normalize(magnetometer);
}

if (currentMillis - lastPrintMillis > INTERVAL_MS_PRINT) {
Serial.print("TEMP:\\t");
Serial.print(normalized.temperature, 2);
Serial.print("\\xC2\\xB0"); //Print degree symbol
Serial.print("C");
Serial.println();

Serial.print("GYR (");
Serial.print("\\xC2\\xB0"); //Print degree symbol
Serial.print("/s):\\t");
Serial.print(normalized.gyroscope.x, 3);
Serial.print("\\t\\t");
Serial.print(normalized.gyroscope.y, 3);
Serial.print("\\t\\t");
Serial.print(normalized.gyroscope.z, 3);
Serial.println();

Serial.print("ACC (m/s^2):\\t");
Serial.print(normalized.accelerometer.x, 3);
Serial.print("\\t\\t");
Serial.print(normalized.accelerometer.y, 3);
Serial.print("\\t\\t");
Serial.print(normalized.accelerometer.z, 3);
Serial.println();

Serial.print("MAG (");
Serial.print("\\xce\\xbc"); //Print micro symbol
Serial.print("T):\\t");
Serial.print(normalized.magnetometer.x, 3);
Serial.print("\\t\\t");
Serial.print(normalized.magnetometer.y, 3);
Serial.print("\\t\\t");
Serial.print(normalized.magnetometer.z, 3);
Serial.println();

Serial.println();

lastPrintMillis = currentMillis;
}
}

Note: the snippet is part of Arduino project located in our GitHub repository with the code separated in different logical files.

Testing

The serial monitor will print last available sensors data every INTERVAL_MS_PRINT milliseconds (in the example above, once per second) and it should be similar to:

mpu9250_testing_output.png

Usually the orientation is drawn on the physical module so you can easily detect X, Y and Z axes.

Credits

Official GitHub: https://github.com/hibit-dev/mpu9250

 Join Our Monthly Newsletter

Get the latest news and popular articles to your inbox every month

We never send SPAM nor unsolicited emails

2 Comments

avatar

Sergiu Reply

if i run the code above i get the same values repeating over and over, any ideea why my sensor doesnt get other readings?

avatar

Reply

To troubleshoot the issue, ensure that the wiring is correctly connected and consider replacing the cables. If the issue persists, it is possible that the module is defective or broken. Try using a different module to determine if the issue is resolved.

Leave a Reply

Your email address will not be published.

Replying to the message: View original

Hey visitor! Unlock access to featured articles, remove ads and much more - it's free.