- Calibration functions
- Common data collection functions
- Communication lag
- Configuration functions
- Credits
- Description
- Example list
- Fifo data collection
- Fifo setup
- Gimbal lock
- I2c object declaration
- Installation
- Instructions
- Interfacing mpu9250 with esp32 using arduino ide
- Mpu9250
- Mpu9250fifo class
- Real-time data collection
- Sensor orientation
- Spi object declaratioon
- Wake on motion setup
- Wiring and pullups
Calibration functions
(optional) int calibrateGyro()
The gyro bias is automatically estimated during the begin() function and removed from sensor measurements. This function will re-estimate the gyro bias and remove the new bias from future sensor measurements.
status = IMU.calibrateGyro();
(optional) float getGyroBiasX_rads()
This function returns the current gyro bias in the X direction in units of rad/s.
(optional) float getGyroBiasY_rads()
This function returns the current gyro bias in the Y direction in units of rad/s.
(optional) float getGyroBiasZ_rads()
This function returns the current gyro bias in the Z direction in units of rad/s.
(optional) void setGyroBiasX_rads(float bias)
This function sets the gyro bias being used in the X direction to the input value in units of rad/s.
(optional) void setGyroBiasY_rads(float bias)
This function sets the gyro bias being used in the Y direction to the input value in units of rad/s.
(optional) void setGyroBiasZ_rads(float bias)
This function sets the gyro bias being used in the Z direction to the input value in units of rad/s.
(optional) int calibrateAccel()
This function will estimate the bias and scale factor needed to calibrate the accelerometers. This function works one axis at a time and needs to be run for all 6 sensor orientations. After it has collected enough sensor data, it will estimate the bias and scale factor for all three accelerometer channels and apply these corrections to the measured data.
Accelerometer calibration only needs to be performed once on the IMU, the get and set functions detailed below can be used to retrieve the estimated bias and scale factors and use them during future power cycles or operations with the IMU. This function returns a positive value on success and a negative value on failure.
status = IMU.calibrateAccel();
(optional) float getAccelBiasX_mss()
This function returns the current accelerometer bias in the X direction in units of m/s/s.
(optional) float getAccelScaleFactorX()
This function returns the current accelerometer scale factor in the X direction.
(optional) float getAccelBiasY_mss()
This function returns the current accelerometer bias in the Y direction in units of m/s/s.
(optional) float getAccelScaleFactorY()
This function returns the current accelerometer scale factor in the Y direction.
(optional) float getAccelBiasZ_mss()
This function returns the current accelerometer bias in the Z direction in units of m/s/s.
(optional) float getAccelScaleFactorZ()
This function returns the current accelerometer scale factor in the Z direction.
(optional) void setAccelCalX(float bias,float scaleFactor)
This function sets the accelerometer bias (m/s/s) and scale factor being used in the X direction to the input values.
(optional) void setAccelCalY(float bias,float scaleFactor)
This function sets the accelerometer bias (m/s/s) and scale factor being used in the Y direction to the input values.
(optional) void setAccelCalZ(float bias,float scaleFactor)
This function sets the accelerometer bias (m/s/s) and scale factor being used in the Z direction to the input values.
(optional) int calibrateMag()
This function will estimate the bias and scale factor needed to calibrate the magnetometers. This function works on all the sensor axes at once, you should continuously and slowly move the sensor in a figure 8 while the function is running.
After it has collected enough sensor data, it will estimate the bias and scale factor for all three magnetometer channels and apply these corrections to the measured data. Magnetometer calibration only needs to be performed once on the IMU, unless the eletrical or magnetic environment changes.
The get and set functions detailed below can be used to retrieve the estimated bias and scale factors and use them during future power cycles or operations with the IMU. This function returns a positive value on success and a negative value on failure.
status = IMU.calibrateMag();
(optional) float getMagBiasX_uT()
This function returns the current magnetometer bias in the X direction in units of uT.
(optional) float getMagScaleFactorX()
This function returns the current magnetometer scale factor in the X direction.
(optional) float getMagBiasY_uT()
This function returns the current magnetometer bias in the Y direction in units of uT.
(optional) float getMagScaleFactorY()
This function returns the current magnetometer scale factor in the Y direction.
(optional) float getMagBiasZ_uT()
This function returns the current magnetometer bias in the Z direction in units of uT.
(optional) float getMagScaleFactorZ()
This function returns the current magnetometer scale factor in the Z direction.
(optional) void setMagCalX(float bias,float scaleFactor)
This function sets the magnetometer bias (uT) and scale factor being used in the X direction to the input values.
(optional) void setMagCalY(float bias,float scaleFactor)
This function sets the magnetometer bias (uT) and scale factor being used in the Y direction to the input values.
(optional) void setMagCalZ(float bias,float scaleFactor)
This function sets the magnetometer bias (uT) and scale factor being used in the Z direction to the input values.
Common data collection functions
The functions below are used to collect data from the MPU-9250 sensor. Data is returned scaled to engineering units and transformed to a common axis system.
Communication lag
Communication is sometimes frozen from a few hundred milliseconds up to several seconds. This is probably due to WiFi performance. I checked with another WiFi router and the results were much better, but not perfect. When tested in soft AP mode it worked flawlessly with my Android phone, but not with my Mac.
I also performed a test where JSON data is sent via the serial port to a Python script that transmits it via WebSocket to the web page (the Python script and web page ran on the same computer). In this setup the communication does not freeze anymore, but the serial communication has a longer response time, i.e. the movements are reflected on the screen with a small delay that is noticeable.
Configuration functions
(optional) int setAccelRange(AccelRange range)
This function sets the accelerometer full scale range to the given value. By default, if this function is not called, a full scale range of /- 16 g will be used. The enumerated accelerometer full scale ranges are:
Accelerometer Name | Accelerometer Full Scale Range |
---|---|
ACCEL_RANGE_2G | /- 2 (g) |
ACCEL_RANGE_4G | /- 4 (g) |
ACCEL_RANGE_8G | /- 8 (g) |
ACCEL_RANGE_16G | /- 16 (g) |
This function returns a positive value on success and a negative value on failure. Please see the Advanced_I2C example. The following is an example of selecting an accelerometer full scale range of /- 8g.
status = IMU.setAccelRange(MPU9250::ACCEL_RANGE_8G);
(optional) int setGyroRange(GyroRange range)
This function sets the gyroscope full scale range to the given value. By default, if this function is not called, a full scale range of /- 2000 deg/s will be used. The enumerated gyroscope full scale ranges are:
Gyroscope Name | Gyroscope Full Scale Range |
---|---|
GYRO_RANGE_250DPS | /- 250 (deg/s) |
GYRO_RANGE_500DPS | /- 500 (deg/s) |
GYRO_RANGE_1000DPS | /- 1000 (deg/s) |
GYRO_RANGE_2000DPS | /- 2000 (deg/s) |
This function returns a positive value on success and a negative value on failure. Please see the Advanced_I2C example. The following is an example of selecting an gyroscope full scale range of /- 250 deg/s.
status = IMU.setGyroRange(MPU9250::GYRO_RANGE_250DPS);
(optional) int setDlpfBandwidth(DlpfBandwidth bandwidth)
This is an optional function to set the programmable Digital Low Pass Filter (DLPF) bandwidth. By default, if this function is not called, a DLPF bandwidth of 184 Hz is used. The following DLPF bandwidths are supported:
Bandwidth Name | DLPF Bandwidth | Gyroscope Delay | Accelerometer Delay | Temperature Bandwidth | Temperature Delay |
---|---|---|---|---|---|
DLPF_BANDWIDTH_184HZ | 184 Hz | 2.9 ms | 5.8 ms | 188 Hz | 1.9 ms |
DLPF_BANDWIDTH_92HZ | 92 Hz | 3.9 ms | 7.8 ms | 98 Hz | 2.8 ms |
DLPF_BANDWIDTH_41HZ | 41 Hz | 5.9 ms | 11.8 ms | 42 Hz | 4.8 ms |
DLPF_BANDWIDTH_20HZ | 20 Hz | 9.9 ms | 19.8 ms | 20 Hz | 8.3 ms |
DLPF_BANDWIDTH_10HZ | 10 Hz | 17.85 ms | 35.7 ms | 10 Hz | 13.4 ms |
DLPF_BANDWIDTH_5HZ | 5 Hz | 33.48 ms | 66.96 ms | 5 Hz | 18.6 ms |
This function returns a positive value on success and a negative value on failure. Please see the Advanced_I2C example. The following is an example of selecting a DLPF bandwidth of 20 Hz.
status = IMU.setDlpfBandwidth(MPU9250::DLPF_BANDWIDTH_20HZ);
(optional) int setSrd(uint8_t srd)
This is an optional function to set the data output rate. The data output rate is set by a sample rate divider, uint8_t SRD. The data output rate is then given by:
Data Output Rate = 1000 / (1 SRD)
By default, if this function is not called, an SRD of 0 is used resulting in a data output rate of 1000 Hz. This allows the data output rate for the gyroscopes, accelerometers, and temperature sensor to be set between 3.9 Hz and 1000 Hz. Note that data should be read at or above the selected rate.
In order to prevent aliasing, the data should be sampled at twice the frequency of the DLPF bandwidth or higher. For example, this means for a DLPF bandwidth set to 41 Hz, the data output rate and data collection should be at frequencies of 82 Hz or higher.
The magnetometer is fixed to an output rate of:
- 100 Hz for frequencies of 100 Hz or above (SRD less than or equal to 9)
- 8 Hz for frequencies below 100 Hz (SRD greater than 9)
When the data is read above the selected output rate, the read data will be stagnant. For example, when the output rate is selected to 1000 Hz, the magnetometer data will be the same for 10 sequential frames.
This function returns a positive value on success and a negative value on failure. Please see the Advanced_I2C example. The following is an example of selecting an SRD of 9, resulting in a data output rate of 100 Hz.
(optional) int enableDataReadyInterrupt()
An interrupt is tied to the data output rate. The MPU-9250 INT pin will issue a 50us pulse when data is ready. This is extremely useful for using interrupts to clock data collection that should occur at a regular interval.
Please see the Interrupt_SPI example. This function enables this interrupt, which will occur at a frequency given by the SRD. This function returns a positive value on success and a negative value on failure. The following is an example of enabling the data ready interrupt.
status = IMU.enableDataReadyInterrupt();
(optional) int disableDataReadyInterrupt()
This function disables the data ready interrupt, described above. This function returns a positive value on success and a negative value on failure. The following is an example of disabling the data ready interrupt.
status = IMU.disableDataReadyInterrupt();
Credits
The three.js stuff comes from this project:
Description
The InvenSense MPU-9250 is a System in Package (SiP) that combines two chips: the MPU-6500 three-axis gyroscope and three-axis accelerometer; and the AK8963 three-axis magnetometer. The MPU-9250 supports I2C, up to 400 kHz, and SPI communication, up to 1 MHz for register setup and 20 MHz for data reading. The following selectable full scale sensor ranges are available:
Gyroscope Full Scale Range | Accelerometer Full Scale Range | Magnetometer Full Scale Range |
---|---|---|
/- 250 (deg/s) | /- 2 (g) | /- 4800 (uT) |
/- 500 (deg/s) | /- 4 (g) | |
/- 1000 (deg/s) | /- 8 (g) | |
/- 2000 (deg/s) | /- 16 (g) |
The MPU-9250 samples the gyroscopes, accelerometers, and magnetometers with 16 bit analog to digital converters. It also features programmable digital filters, a precision clock, an embedded temperature sensor, programmable interrupts (including wake on motion), and a 512 byte FIFO buffer.
Example list
- Basic_I2C: demonstrates declaring an MPU9250 object, initializing the sensor, and collecting data. I2C is used to communicate with the MPU-9250 sensor.
- Basic_SPI: demonstrates declaring an MPU9250 object, initializing the sensor, and collecting data. SPI is used to communicate with the MPU-9250 sensor.
- Advanced_I2C: demonstrates a more advanced setup. In this case, the accelerometer and gyroscope full scale ranges, DLPF, and SRD are set to non-default values. I2C is used to communicate with the MPU-9250 sensor.
- Interrupt_SPI: demonstrates having the MPU-9250 sensor create an interrupt pulse when data is ready, which is used to drive data collection at the specified rate. SPI is used to communicate with the MPU-9250 sensor.
- WOM_I2C: demonstrates setting up and using the wake on motion interrupt. I2C is used to communicate with the MPU-9250 sensor.
- FIFO_SPI: demonstrates setting up and using the FIFO buffer. SPI is used to communicate with the MPU-9250 sensor.
Fifo data collection
int readFifo() reads the FIFO buffer from the MPU-9250, parses it and stores the data in buffers on the microcontroller. It should be called every time you would like to retrieve data from the FIFO buffer. This function returns a positive value on success and a negative value on failure.
void getFifoAccelX_mss(size_t size,float data) gets the accelerometer value from the data buffer in the X direction and returns it in units of m/s/s. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoAccelY_mss(size_t size,float data) gets the accelerometer value from the data buffer in the Y direction and returns it in units of m/s/s. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoAccelZ_mss(size_t size,float data) gets the accelerometer value from the data buffer in the Z direction and returns it in units of m/s/s. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoGyroX_rads(size_t size,float data) gets the gyroscope value from the data buffer in the X direction and returns it in units of rad/s. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoGyroY_rads(size_t size,float data) gets the gyroscope value from the data buffer in the Y direction and returns it in units of rad/s. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoGyroZ_rads(size_t size,float data) gets the gyroscope value from the data buffer in the Z direction and returns it in units of rad/s. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoMagX_uT(size_t size,float data) gets the magnetometer value from the data buffer in the X direction and returns it in units of uT. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoMagY_uT(size_t size,float data) gets the magnetometer value from the data buffer in the Y direction and returns it in units of uT. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoMagZ_uT(size_t size,float data) gets the magnetometer value from the data buffer in the Z direction and returns it in units of uT. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
void getFifoTemperature_C(size_t size,float data) gets the die temperature value from the data buffer and returns it in units of C. The data is returned as an array along with the number of elements within that array. Ensure that the buffer you are transfering to has enough capacity to store the data.
Fifo setup
(optional) int enableFifo(bool accel,bool gyro,bool mag,bool temp)
This function configures and enables the MPU-9250 FIFO buffer. This 512 byte buffer samples data at the data output rate set by the SRD and enables the microcontroller to bulk read the data, reducing microcontroller workload for certain applications.
It is configured with a set of boolean values describing which data to buffer in the FIFO: accelerometer, gyroscope, magnetometer, or temperature. The accelerometer and gyroscope data each take 6 bytes of space per sample while the magnetometer takes 7 bytes of space and the temperature 2 bytes.
It’s important to select only the data sources desired to ensure that the FIFO does not overrun between reading it. For example, enabling all of the data sources would take 21 bytes per sample allowing the FIFO to hold only 24 samples before overflowing.
If only the accelerometer data is needed, this increases to 85 samples before overflowing. This function returns a positive value on success and a negative value on failure. Please see the FIFO_SPI example. The following is an example of enabling the FIFO to buffer accelerometer and gyroscope data.
Gimbal lock
The calculation of Euler angles has a Gimbal Lock problem. If you want to see it:
I2c object declaration
MPU9250FIFO(TwoWire &bus,uint8_t address)
An MPU9250FIFO object should be declared, specifying the I2C bus and MPU-9250 I2C address. The MPU-9250 I2C address will be 0x68 if the AD0 pin is grounded or 0x69 if the AD0 pin is pulled high.
Installation
Simply clone or download this library into your Arduino/libraries folder.
Instructions
- Make sure you have the latest PlatformIO revision (PlatformIO Core 4.0 at this time):
Connect the MPU9250 to the I²C port of the ESP32. Note that this step is not necessary for the M5Stack because it includes an MPU9250.
Create manually a file called
src/WifiSettings.h
with the following content:
Update the file
platformio.ini
. For most of the ESP32 models, the variabledefault_envs
must be set toesp32doit-devkit-v1
. If you have a M5Stack, you can set it tom5stack-core-esp32
. In case of a problem, you will need to add your own board model.Upload the web files on the ESP32 with the following command:
platformio run --target uploadfs
Upload the code to the ESP32 with PlatformIO.
Check the IP addresses in the serial output. You may need to reboot your ESP to see them. If you have a M5Stack, they will be displayed on the screen.
- Use
STATION IP address
to connect to your ESP32 via your WiFi router. - Use
SOFT-AP IP address
to connect your computer directly to your ESP32.
- Use
Navigate to the IP address of the ESP32 in your web browser. You should see the pages below.
Interfacing mpu9250 with esp32 using arduino ide
Following is my code, I am trying to read accelerometer readings. In the below code I am trying to read the z-axis reading of the accelerator. The output expected is around 1 but the output I get is either 0 or 2. Is it i2c or my logic is wrong.
I tried to find a solution but I couldn’t find anything relevant. Also, I am avoiding to use a library because I want to learn how the operation actually happens.
I am using ESP32 on Arduino IDE and IMU is MPU9250.
#include <Wire.h>
#define MPU9250 0x68
#define PWR_MGMT_1 0x6B
#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define ACCEL_CONFIG 0x1C
#define ACCEL_XOUT_H 0x3B
#define ACCEL_YOUT_H 0X3D
#define ACCEL_ZOUT_H 0X3F
#ifdef _ESP32_HAL_I2C_H_
#define SDA_PIN 21
#define SCL_PIN 22
#endif
uint8_t size = 1;
uint16_t final_val;
float fin;
uint8_t i2cRead(uint8_t Address, uint8_t Register) {
uint8_t var;
Wire.beginTransmission(Address);
Wire.write(Register);
uint8_t result = Wire.endTransmission();
if (result != 0) {
return result;
}
Wire.requestFrom(Address, size);
while(Wire.available()){
var = Wire.read();
}
return var;
}
void i2cWriteByte(uint8_t Address, uint8_t Register, uint8_t Data) {
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}
void MPU_Start()
{
i2cWriteByte(MPU9250, SMPLRT_DIV, 0x00);
delay(10);
i2cWriteByte(MPU9250, PWR_MGMT_1, 0x00);
delay(10);
i2cWriteByte(MPU9250, PWR_MGMT_1, 0x01);
delay(10);
i2cWriteByte(MPU9250, CONFIG, 0x00);
delay(10);
i2cWriteByte(MPU9250, ACCEL_CONFIG, 0x00); //2g
delay(10);
}
void MPU_convert()
{
//read_raw_data(ACCEL_XOUT_H);
//read_raw_data(ACCEL_YOUT_H);
read_raw_data(ACCEL_ZOUT_H);
}
void read_raw_data(uint8_t reg)
{
uint8_t high, low;
high = i2cRead(MPU9250, reg);
low = i2cRead(MPU9250, reg 1);
final_val = ((high << 8) | low);
fin = (final_val/32768)*2;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
while(!Serial);
#ifdef _ESP32_HAL_I2C_H_
Wire.begin(SDA_PIN, SCL_PIN);
#endif
MPU_Start();
}
void loop() {
// put your main code here, to run repeatedly:
MPU_convert();
Serial.println(fin);
}
Mpu9250
Arduino library for communicating with the MPU-9250 and MPU-9255 nine-axis Inertial Measurement Units (IMU).
Mpu9250fifo class
The MPU9250FIFO derived class extends the functionality provided by the MPU9250 base class by providing support for setting up and reading the MPU-9250 FIFO buffer. All of the functions described above, as part of the MPU9250 class are also available to the MPU9250FIFO class.
Real-time data collection
int readSensor() reads the sensor and stores the newest data in a buffer, it should be called every time you would like to retrieve data from the sensor. This function returns a positive value on success and a negative value on failure.
float getAccelX_mss() gets the accelerometer value from the data buffer in the X direction and returns it in units of m/s/s.
float getAccelY_mss() gets the accelerometer value from the data buffer in the Y direction and returns it in units of m/s/s.
float getAccelZ_mss() gets the accelerometer value from the data buffer in the Z direction and returns it in units of m/s/s.
float getGyroX_rads() gets the gyroscope value from the data buffer in the X direction and returns it in units of rad/s.
float getGyroY_rads() gets the gyroscope value from the data buffer in the Y direction and returns it in units of rad/s.
float getGyroZ_rads() gets the gyroscope value from the data buffer in the Z direction and returns it in units of rad/s.
float getMagX_uT() gets the magnetometer value from the data buffer in the X direction and returns it in units of uT.
float getMagY_uT() gets the magnetometer value from the data buffer in the Y direction and returns it in units of uT.
float getMagZ_uT() gets the magnetometer value from the data buffer in the Z direction and returns it in units of uT.
float getTemperature_C() gets the die temperature value from the data buffer and returns it in units of C.
Sensor orientation
This library transforms all data to a common axis system before it is returned. This axis system is shown below. It is a right handed coordinate system with the z-axis positive down, common in aircraft dynamics.
Caution! This axis system is shown relative to the MPU-9250 sensor. The sensor may be rotated relative to the breakout board.
Spi object declaratioon
MPU9250FIFO(SPIClass &bus,uint8_t csPin)
An MPU9250FIFO object should be declared, specifying the SPI bus and chip select pin used. Multiple MPU-9250 or other SPI objects could be used on the same SPI bus, each with their own chip select pin.
Wake on motion setup
(optional) int enableWakeOnMotion(float womThresh_mg,LpAccelOdr odr)
This function enables the MPU-9250 wake on motion interrupt functionality. It places the MPU-9250 into a low power state, with the MPU-9250 waking up at an interval determined by the Low Power Accelerometer Output Data Rate.
LpAccelOdr Name | Output Data Rate |
---|---|
LP_ACCEL_ODR_0_24HZ | 0.24 Hz |
LP_ACCEL_ODR_0_49HZ | 0.49 Hz |
LP_ACCEL_ODR_0_98HZ | 0.98 Hz |
LP_ACCEL_ODR_1_95HZ | 1.95 Hz |
LP_ACCEL_ODR_3_91HZ | 3.91 Hz |
LP_ACCEL_ODR_7_81HZ | 7.81 Hz |
LP_ACCEL_ODR_15_63HZ | 15.63 Hz |
LP_ACCEL_ODR_31_25HZ | 31.25 Hz |
LP_ACCEL_ODR_62_50HZ | 62.50 Hz |
LP_ACCEL_ODR_125HZ | 125 Hz |
LP_ACCEL_ODR_250HZ | 250 Hz |
LP_ACCEL_ODR_500HZ | 500 Hz |
The motion threshold is given as a float value between 0 and 1020 mg mapped, which is internally mapped to a single byte, 0-255 value. This function returns a positive value on success and a negative value on failure. Please see the WOM_I2C example. The following is an example of enabling the wake on motion with a 400 mg threshold and a ODR of 31.25 Hz.
Wiring and pullups
Please refer to the MPU-9250 datasheet and your microcontroller’s pinout diagram. This library was developed using the Embedded Masters breakout board v1.1 for the MPU-9250. The data sheet for this breakout board is located here. This library should work well for other breakout boards or embedded sensors, please refer to your vendor’s pinout diagram.