Reading MPU9250 sensors with Arduino
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
1x Arduino Nano (or another Arduino module) $3.18 | |
1x Mini Breadboard $1.17 | |
1x MPU9250 $1.74 | |
Dupont wires $1.61 | |
I2C library |
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:
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.
The 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.
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:
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
2 Comments
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?
HiBit 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.