MPU6050 Accelerometer and Gyroscope

About this post

The MPU6050, or more precisely the module based on it, is a 3-axis accelerometer and 3-axis gyroscope. In addition, the MPU6050 measures the temperature. A lot has already been written about this sensor, but maybe I can give you one or the other new aspect with this post, like the interrupt programming.

The post is structured as follows:

If you just want to get started quickly, you can go directly to the libraries.

Basics

The measuring principle of the MPU6050

In the context of accelerometers, you often come across the terms “3-axis”, “6-axis” or even “9-axis sensors”. Don’t worry, we are not leaving the three-dimensional world. Instead, one or more sensors, which are effective in three dimensions, are used in parallel. And in the case of the MPU6050, this is an accelerometer and a gyroscope. 9-axis sensors usually have an additional geomagnetic field sensor.

Gyroscopes

The classical gyroscope works like a toy whipping top. Everyone knows it from childhood and also its effect. The rotation stabilizes it (precession) and therefore the attempt to tilt its axis of rotation requires force. And exactly with this you can determine the inclination or angular acceleration of an object (e.g. an airplane or ship). Compared to the simple whipping tops, the gyroscope is mounted in a frame. An exemplary toy gyroscope:

A toy gyroscope
A toy gyroscope

In the MPU6050 there is of course no part which is spinning (and fortunately, you don’t have to move it manually ;-)). Such sensors are based on Micro-Electric-Mechanical Systems (MEMS). In the case of gyroscopes, these are moving parts that change their position within a fixed frame when accelerated. The distance change results in a change in capacity. In principle, this is how it looks:

The measuring principle of the MPU6050
The measuring principle of the MPU6050

An older technique is based on the piezo effect, so it uses pressure changes as the measuring principle.

Accelerometers

An accelerometer works according to the same principle. The difference is that the accelerometer detects acceleration in the x-, y-, and z-axis directions, while the gyroscope detects motion about the axes. When the module is in the idle state, the gyroscope returns zero for x, y and z. The acceleration sensor, on the other hand, detects the acceleration due to gravity even at rest (in the z-direction when the module is flat).

The modules have printed the position of the x- and y-axis. The z-axis is the perpendicular on the module.

MPU6050 Module
MPU6050 Module

Technical Data / Features

The most important technical data of the MPU6050 are:

  • Power supply (VDD/GND): the module has an LDO voltage converter (see also here), so can be supplied with 3.3 V as well as with 5 V. The bare IC should be supplied with 2,375 – 3.46 V.
  • Power consumption (module): approx. 5.1 mA, in sleep mode approx. 1.4 mA (own measurements). If you remove the LED, the consumption is reduced to 3.7 mA or 33 µA in sleep mode.
  • Accelerometer:16-bit resolution, measuring ranges +/- 2, 4, 8 or 16 g; with g = earth acceleration, not grams!
  • Gyroscope:16-bit resolution, measuring ranges: +/- 250, 500, 1000 or 2000°/s.
  • Communication (SDA/SCL): I2C, address 0x68 (AD0 = GND or unconnected) or 0x69 (AD0 = HIGH)
  • Interrupt function: “Data Ready”, “Free Fall”, acceleration limit;
  • Connection of additional sensors (XDA / XCL): I will not go into this

For more information, see the data sheet and the register map.

Control of the MPU6050 without library

The minimal sketch

If you can live with the defaults (+/-2 g, +/-250°/s), then you might get by with the following sketch (base: Arduino Playground). 

I’m not going to go through all the details of the sketch, just so much:

  • First the MPU6050 is awakened by the entry of a zero in the “Power Management 1” register.
  • The MPU6050 continuously produces results for acceleration, gyroscope and temperature.
  • Since the result registers are sequential, they can be read out conveniently in one go.
  • Only raw data is output (-32767 to + 32767).
#include "Wire.h" 

#define MPU6050_ADDR 0x68 // Alternatively set AD0 to HIGH  --> Address = 0x69

int16_t accX, accY, accZ, gyroX, gyroY, gyroZ, tRaw; // Raw register values (accelaration, gyroscope, temperature)
char result[7]; // temporary variable used in convert function

void setup() {
  Serial.begin(9600);
  Wire.begin();
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x6B); // PWR_MGMT_1 register
  Wire.write(0); // wake up!
  Wire.endTransmission(true);
}
void loop() {
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. 
                               // As a result, the connection is kept active.
  Wire.requestFrom(MPU6050_ADDR, 14, true); // request a total of 7*2=14 registers
  
  // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same int16_t variable
  accX = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
  accY = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
  accZ = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
  tRaw = Wire.read()<<8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
  gyroX = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
  gyroY = Wire.read()<<8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
  gyroZ = Wire.read()<<8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)
  
  Serial.print("AcX = "); Serial.print(toStr(accX));
  Serial.print(" | AcY = "); Serial.print(toStr(accY));
  Serial.print(" | AcZ = "); Serial.print(toStr(accZ));
  // from data sheet:
  Serial.print(" | tmp = "); Serial.print((tRaw + 12412.0) / 340.0);
  Serial.print(" | GyX = "); Serial.print(toStr(gyroX));
  Serial.print(" | GyY = "); Serial.print(toStr(gyroY));
  Serial.print(" | GyZ = "); Serial.print(toStr(gyroZ));
  Serial.println();
  
  delay(1000);
}

char* toStr(int16_t character) { // converts int16 to string and formatting
  sprintf(result, "%6d", character);
  return result;
}

 

Below you can see the output of the sketch on the serial monitor. Since the MPU6050 was placed flat in the x/y plane, all results except acceleration in the z-direction (acceleration due to gravity) should be zero. This is not the case, but the result is not bad in first approximation.

You can adjust the initial values by entering offset values in corresponding registers. Some libraries have implemented this option, others have not.

Output of the minimal sketch for the MPU6050
Output of the minimal sketch for the MPU6050

For completeness, I have shown the circuit here. We will need the LED and the line to the interrupt later. Pull-ups for the I2C lines (3.3 V) are integrated on the module.

Wiring the MPU6050 with the Arduino
Wiring the MPU6050 with the Arduino

The extended Minimalsketch

I then added a few extras to the Minimalsketch:

  • setAccRange() sets the measuring range for acceleration.
  • setGyrRange() sets the measuring range for the gyroscope.
  • MCP6050_wakeUp() awakens the MPU6050.
    • It needs some time to wake up, only after 30 ms I could determine meaningful gyroscope values.
  • MCP6050_sleep sends the MPU6050 to sleep.

Through intermittent sleep I could reduce the power consumption from 5.2 to 1.4 mA with the following sketch. If you then remove the LED, the consumption drops to less than 0.1 mA. 

If you want to understand the sketch in terms of register settings, take a look at the register map.

#include "Wire.h" 

#define MPU6050_ADDR              0x68 // Alternatively set AD0 to HIGH  --> Address = 0x69
#define MPU6050_GYRO_CONFIG       0x1B ///< Gyro specfic configuration register
#define MPU6050_ACCEL_CONFIG      0x1C
#define MPU6050_ACCEL_XOUT_H      0x3B
#define MPU6050_PWR_MGT_1         0x6B
#define MPU6050_SLEEP             0x06

typedef enum {
  MPU6050_ACC_RANGE_2G,  // +/- 2g (default)
  MPU6050_ACC_RANGE_4G,  // +/- 4g
  MPU6050_ACC_RANGE_8G,  // +/- 8g
  MPU6050_ACC_RANGE_16G // +/- 16g
} mpu6050_acc_range;

typedef enum {
  MPU6050_GYR_RANGE_250,  // +/- 250 deg/s (default)
  MPU6050_GYR_RANGE_500,  // +/- 500 deg/s
  MPU6050_GYR_RANGE_1000, // +/- 1000 deg/s
  MPU6050_GYR_RANGE_2000  // +/- 2000 deg/s
} mpu6050_gyr_range;

int16_t accX, accY, accZ, gyroX, gyroY, gyroZ, tRaw; // Raw register values (accelaration, gyroscope, temperature)
char result[7];

void setup() {
  Serial.begin(9600);
  Wire.begin();
  MPU6050_wakeUp();
  setAccRange(MPU6050_ACC_RANGE_16G);
  setGyrRange(MPU6050_GYR_RANGE_250);
}

void loop() {
  MPU6050_wakeUp();
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(MPU6050_ACCEL_XOUT_H); // starting with register ACCEL_XOUT_H
  Wire.endTransmission(false); // the parameter indicates that the Arduino will send a restart. 
                               // As a result, the connection is kept active.
  Wire.requestFrom(MPU6050_ADDR, 7*2, true); // request a total of 7*2=14 registers
  
  // "Wire.read()<<8 | Wire.read();" means two registers are read and stored in the same variable
  accX = Wire.read()<<8 | Wire.read(); // reading registers: 0x3B (ACCEL_XOUT_H) and 0x3C (ACCEL_XOUT_L)
  accY = Wire.read()<<8 | Wire.read(); // reading registers: 0x3D (ACCEL_YOUT_H) and 0x3E (ACCEL_YOUT_L)
  accZ = Wire.read()<<8 | Wire.read(); // reading registers: 0x3F (ACCEL_ZOUT_H) and 0x40 (ACCEL_ZOUT_L)
  tRaw = Wire.read()<<8 | Wire.read(); // reading registers: 0x41 (TEMP_OUT_H) and 0x42 (TEMP_OUT_L)
  gyroX = Wire.read()<<8 | Wire.read(); // reading registers: 0x43 (GYRO_XOUT_H) and 0x44 (GYRO_XOUT_L)
  gyroY = Wire.read()<<8 | Wire.read(); // reading registers: 0x45 (GYRO_YOUT_H) and 0x46 (GYRO_YOUT_L)
  gyroZ = Wire.read()<<8 | Wire.read(); // reading registers: 0x47 (GYRO_ZOUT_H) and 0x48 (GYRO_ZOUT_L)
  MPU6050_sleep();
  
  // print out data
  Serial.print("AcX = "); Serial.print(toStr(accX));
  Serial.print(" | AcY = "); Serial.print(toStr(accY));
  Serial.print(" | AcZ = "); Serial.print(toStr(accZ));
  // the following equation was taken from the documentation [MPU-6000/MPU-6050 Register Map and Description, p.30]
  Serial.print(" | tmp = "); Serial.print((tRaw + 12412.0) / 340.0);
  Serial.print(" | GyX = "); Serial.print(toStr(gyroX));
  Serial.print(" | GyY = "); Serial.print(toStr(gyroY));
  Serial.print(" | GyZ = "); Serial.print(toStr(gyroZ));
  Serial.println();
  
  delay(1000);
}

char* toStr(int16_t i) { // int16 to string plus output format
  sprintf(result, "%6d", i);
  return result;
}

void setAccRange(mpu6050_acc_range range){
  writeRegister(MPU6050_ACCEL_CONFIG, range<<3);
}

void setGyrRange(mpu6050_gyr_range range){
  writeRegister(MPU6050_GYRO_CONFIG, range<<3);
}

void MPU6050_wakeUp(){
  writeRegister(MPU6050_PWR_MGT_1, 0); 
  delay(30); // give him time to wake up, gyro needs quite a while to stabilize;
}

void MPU6050_sleep(){
  writeRegister(MPU6050_PWR_MGT_1, 1<<MPU6050_SLEEP); 
}

void writeRegister(uint16_t reg, byte value){
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(reg); 
  Wire.write(value); 
  Wire.endTransmission(true);
}

 

Since I have chosen the range +/- 16 g in the example, the measured values for the acceleration in z-direction decrease to one eighth:

Output of the extended minimal sketch
Output of the extended minimal sketch

I could have added more features, but at some point it gets confusing and then libraries are the better choice.

Conversion of raw data

For the conversion of the raw values to values in g, the following applies:

\text{g-value}\;[\text{g}]=\frac{\vert range \vert\cdot rawV\!alue}{32768}

The conversion of the gyroscope data into angular velocities is done according to the following formula (derived from the data sheet):

\omega\;[\text{°\!/s}] = \frac{\vert range \vert\ \cdot rawV\!alue}{131\cdot 250}

Interrupts

Perhaps the following very short video of the “Magic Push Button” will whet your appetite for the interrupt function, which by the way was not implemented in any library I looked at.

As you can see, a press on the button makes the LED glow – even though the button is not connected at all. The solution to the puzzle is that the vibration when the pushbutton is pressed is sufficient to trigger a correspondingly sensitive “wake on motion” interrupt. So, I could just as easily have knocked on the table. The Arduino sketch ensures that when the interrupt is registered, the LED lights up for one second.

You can also do other great things with this interrupt. For example, you can build a device that turns itself on when you pick it up. If it’s lying around, it should be sleeping. No problem, you only have to use the interrupt signal as a wake-up signal for the microcontroller. See also my article about Sleep Modes.

The problem with undocumented registers

The datasheet of the MPU6050 describes a procedure for setting up interrupts. The problem is that it doesn’t work. While searching the net, I came across this webpage that explains how to do it right. Both undocumented registers in the data sheet and undocumented bits of documented registers are used.

Interestingly, there are hardworking people who have done the documentation work for the registers in a reverse engineering process. The result, i.e. the complete register map, can be found here.

The Interrupt Sketch

I took the instructions and wrote the following sketch based on it. Some steps suggested in the manual are not necessary in my opinion. I inserted but commented them.

Explaining the sketch in detail would be beyond the scope. Just a few comments:

  • setInterrupt(x) activates the interrupt; x sets sensitivity to a value between 1 (4 mg = “4 milli-g”, not milligrams) and 255 (1024 mg)
    • at 255 you have to shake the MPU6050 vigorously to trigger the interrupt
  • if you want to set the interrupt pin active-low, then uncomment line 41
  • using the latch function you can set the interrupt pin to remain active until the next read. To do this, change line 41 to: writeRegister(MPU6050_INT_PIN_CFG, 1<<MPU6050_LATCH_INT_EN)
  • Combination of active-low and latch: writeRegister(MPU6050_INT_PIN_CFG, ((1<<MPU6050_ACTL) | (1<<MPU6050_LATCH_IN_EN))

Here’s the sketch:

#include "Wire.h" 

#define MPU6050_ADDR              0x68 // Alternatively set AD0 to HIGH  --> Address = 0x69
#define MPU6050_ACCEL_CONFIG      0x1C // Accelerometer Configuration Register
#define MPU6050_PWR_MGT_1         0x6B // Power Management 1 Register
#define MPU6050_INT_PIN_CFG       0x37 // Interrupt Pin / Bypass Enable Configuration Register
#define MPU6050_INT_ENABLE        0x38 // Interrupt Enable Register
#define MPU6050_LATCH_INT_EN      0x05 // Latch Enable Bit for Interrupt 
#define MPU6050_ACTL              0x07 // Active-Low Enable Bit
#define MPU6050_WOM_EN            0x06 // Wake on Motion Enable bit
#define MPU6050_WOM_THR           0x1F // Wake on Motion Threshold Register
#define MPU6050_MOT_DUR           0x20 // Motion Detection Duration Register
#define MPU6050_ACCEL_INTEL_CTRL  0x69 // Accelaration Interrupt Control Register
#define MPU6050_SIGNAL_PATH_RESET 0x68 // Signal Path Reset Register

byte interruptPin=2;
byte ledPin=10;
volatile bool accEvent = false;

void setup() {
  Wire.begin();
  writeRegister(MPU6050_PWR_MGT_1, 0);
  setInterrupt(1); // set Wake on Motion Interrupt / Sensitivity; 1(highest sensitivity) - 255
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT);
  attachInterrupt(digitalPinToInterrupt(interruptPin), motion, RISING);
}

void loop() {
   if(accEvent){
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    accEvent = false;
    attachInterrupt(digitalPinToInterrupt(interruptPin), motion, RISING);   
  }
}

void setInterrupt(byte threshold){
//writeRegister(MPU6050_SIGNAL_PATH_RESET, 0b00000111);  // not(?) needed
//writeRegister(MPU6050_INT_PIN_CFG, 1<<MPU6050_ACTL); // 1<<MPU6050_LATCH_INT_EN
  writeRegister(MPU6050_ACCEL_CONFIG, 0b00000001);
  writeRegister(MPU6050_WOM_THR, threshold); 
  writeRegister(MPU6050_MOT_DUR, 0b00000001);  // set duration (LSB = 1 ms)
//writeRegister(MPU6050_ACCEL_INTEL_CTRL, 0x15);  // not needed (?)
  writeRegister(MPU6050_INT_ENABLE, 1<<MPU6050_WOM_EN);
}

void writeRegister(uint16_t reg, byte value){
  Wire.beginTransmission(MPU6050_ADDR);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission();
}

void motion(){
  accEvent = true;
  detachInterrupt(2);
}

 

Libraries for the MPU6050

No library I have found really takes full advantage of the features of the MPU6050. The interrupts are just an example. I would like to create a more complete library. However, the effort is considerable and most of you are likely to get along with the basic features. Maybe I will come back to that.

Adafruit MPU6050

The most complete library I have found is that of Adafruit. You can download it directly from GitHub here or install it via the library manager in the Arduino IDE.

Basic reading sketch

The best way to start is with the included sample basic_readings.ino. It reads the acceleration, temperature and gyroscope values. You can set the measuring ranges and a low-pass filter (setFilterBandwith()) for the sensors. I will come to the filter below. Here’s the unchanged sketch:

// Basic demo for accelerometer readings from Adafruit MPU6050

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");

  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  Serial.print("Accelerometer range set to: ");
  switch (mpu.getAccelerometerRange()) {
  case MPU6050_RANGE_2_G:
    Serial.println("+-2G");
    break;
  case MPU6050_RANGE_4_G:
    Serial.println("+-4G");
    break;
  case MPU6050_RANGE_8_G:
    Serial.println("+-8G");
    break;
  case MPU6050_RANGE_16_G:
    Serial.println("+-16G");
    break;
  }
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  Serial.print("Gyro range set to: ");
  switch (mpu.getGyroRange()) {
  case MPU6050_RANGE_250_DEG:
    Serial.println("+- 250 deg/s");
    break;
  case MPU6050_RANGE_500_DEG:
    Serial.println("+- 500 deg/s");
    break;
  case MPU6050_RANGE_1000_DEG:
    Serial.println("+- 1000 deg/s");
    break;
  case MPU6050_RANGE_2000_DEG:
    Serial.println("+- 2000 deg/s");
    break;
  }

  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  Serial.print("Filter bandwidth set to: ");
  switch (mpu.getFilterBandwidth()) {
  case MPU6050_BAND_260_HZ:
    Serial.println("260 Hz");
    break;
  case MPU6050_BAND_184_HZ:
    Serial.println("184 Hz");
    break;
  case MPU6050_BAND_94_HZ:
    Serial.println("94 Hz");
    break;
  case MPU6050_BAND_44_HZ:
    Serial.println("44 Hz");
    break;
  case MPU6050_BAND_21_HZ:
    Serial.println("21 Hz");
    break;
  case MPU6050_BAND_10_HZ:
    Serial.println("10 Hz");
    break;
  case MPU6050_BAND_5_HZ:
    Serial.println("5 Hz");
    break;
  }

  Serial.println("");
  delay(100);
}

void loop() {

  /* Get new sensor events with the readings */
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  /* Print out the values */
  Serial.print("Acceleration X: ");
  Serial.print(a.acceleration.x);
  Serial.print(", Y: ");
  Serial.print(a.acceleration.y);
  Serial.print(", Z: ");
  Serial.print(a.acceleration.z);
  Serial.println(" m/s^2");

  Serial.print("Rotation X: ");
  Serial.print(g.gyro.x);
  Serial.print(", Y: ");
  Serial.print(g.gyro.y);
  Serial.print(", Z: ");
  Serial.print(g.gyro.z);
  Serial.println(" rad/s");

  Serial.print("Temperature: ");
  Serial.print(temp.temperature);
  Serial.println(" degC");

  Serial.println("");
  delay(500);
}

 

Note that the results are output in m/s2 or rad/s. Here I positioned the module in three different ways: 1) z-axis in the direction of the vertical, 2) x-axis in the direction of the vertical and finally 3) y-axis in the direction of the vertical.

Output of basic_readings.ino
Output of basic_readings.ino

If you want to convert angular velocities to degrees/s:

2\pi\cdot rad = 360° \;\; \Rightarrow\;\;1°=\frac{2\pi\cdot rad}{360}

For the conversion of the acceleration values to g, divide the values by 9.81.

Plotter Sketch

Especially with angular velocities, you may not only want to determine individual values, but also track the progression. The sketch plotter.ino is suitable for this purpose, which I also print here unchanged:

// Basic demo for accelerometer readings from Adafruit MPU6050

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

void setup(void) {
  Serial.begin(115200);
  while (!Serial) {
    delay(10); // will pause Zero, Leonardo, etc until serial console opens
  }

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }

  mpu.setAccelerometerRange(MPU6050_RANGE_16_G);
  mpu.setGyroRange(MPU6050_RANGE_250_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  Serial.println("");
  delay(100);
}

void loop() {

  /* Get new sensor events with the readings */
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  /* Print out the values */
  Serial.print(a.acceleration.x);
  Serial.print(",");
  Serial.print(a.acceleration.y);
  Serial.print(",");
  Serial.print(a.acceleration.z);
  Serial.print(", ");
  Serial.print(g.gyro.x);
  Serial.print(",");
  Serial.print(g.gyro.y);
  Serial.print(",");
  Serial.print(g.gyro.z);
  Serial.println("");

  delay(10);
}

 

Upload the sketch and then select the serial plotter instead of the serial monitor. Here I turned the MPU6050 several times by 90°. The gyroscope peaks are the small pink and orange peaks between the bigger accelerometer peaks:

Plotter output
Plotter output

Cycle and Filter Bandwith

I would like to mention two parameters whose effect is illustrated by the following sketch. This sketch is from me, so it’s not part of the library’s sample sketch.

The function setCycleRate(frequency) causes the MPU6050 to go to sleep and wake up at the specified frequency to record a set of readings. This saves considerable power. Strictly speaking, the function only sets the frequency. It is activated with enableCycle(true).   If you pass “false”, it becomes inactive.

The function setFilterBandwith(bandwith) dampens the fluctuation of the measured value. If you upload the sketch with the parameters I have selected (see line 58/84) and tilt your MPU6050, you will see that the readings are very sluggish. If you use the cycle function, you should set the bandwidth high. For example, change the value to 260 Hz and see what happens.

// Basic demo for cycle and filter bandwith from Adafruit MPU6050

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");

  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  Serial.print("Accelerometer range set to: ");
  switch (mpu.getAccelerometerRange()) {
  case MPU6050_RANGE_2_G:
    Serial.println("+-2G");
    break;
  case MPU6050_RANGE_4_G:
    Serial.println("+-4G");
    break;
  case MPU6050_RANGE_8_G:
    Serial.println("+-8G");
    break;
  case MPU6050_RANGE_16_G:
    Serial.println("+-16G");
    break;
  }
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  Serial.print("Gyro range set to: ");
  switch (mpu.getGyroRange()) {
  case MPU6050_RANGE_250_DEG:
    Serial.println("+- 250 deg/s");
    break;
  case MPU6050_RANGE_500_DEG:
    Serial.println("+- 500 deg/s");
    break;
  case MPU6050_RANGE_1000_DEG:
    Serial.println("+- 1000 deg/s");
    break;
  case MPU6050_RANGE_2000_DEG:
    Serial.println("+- 2000 deg/s");
    break;
  }

  mpu.setFilterBandwidth(MPU6050_BAND_10_HZ);
  Serial.print("Filter bandwidth set to: ");
  switch (mpu.getFilterBandwidth()) {
  case MPU6050_BAND_260_HZ:
    Serial.println("260 Hz");
    break;
  case MPU6050_BAND_184_HZ:
    Serial.println("184 Hz");
    break;
  case MPU6050_BAND_94_HZ:
    Serial.println("94 Hz");
    break;
  case MPU6050_BAND_44_HZ:
    Serial.println("44 Hz");
    break;
  case MPU6050_BAND_21_HZ:
    Serial.println("21 Hz");
    break;
  case MPU6050_BAND_10_HZ:
    Serial.println("10 Hz");
    break;
  case MPU6050_BAND_5_HZ:
    Serial.println("5 Hz");
    break;
  }

  mpu.setCycleRate(MPU6050_CYCLE_5_HZ);
  Serial.print("Cycle rate set to: ");
  switch (mpu.getCycleRate()) {
  case MPU6050_CYCLE_1_25_HZ:
    Serial.println("1.25 Hz");
    break;
  case MPU6050_CYCLE_5_HZ:
    Serial.println("5 Hz");
    break;
  case MPU6050_CYCLE_20_HZ:
    Serial.println("20 Hz");
    break;
  case MPU6050_CYCLE_40_HZ:
    Serial.println("40 Hz");
    break;
  }
  
  mpu.enableCycle(true);
 
  Serial.println("");
  delay(100);
}

void loop() {

  /* Get new sensor events with the readings */
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  /* Print out the values */
  Serial.print("Acceleration X: ");
  Serial.print(a.acceleration.x);
  Serial.print(", Y: ");
  Serial.print(a.acceleration.y);
  Serial.print(", Z: ");
  Serial.print(a.acceleration.z);
  Serial.println(" m/s^2");

  Serial.print("Rotation X: ");
  Serial.print(g.gyro.x);
  Serial.print(", Y: ");
  Serial.print(g.gyro.y);
  Serial.print(", Z: ");
  Serial.print(g.gyro.z);
  Serial.println(" rad/s");

  Serial.print("Temperature: ");
  Serial.print(temp.temperature);
  Serial.println(" degC");

  Serial.println("");
  delay(500);
}

More information can be found in this Adafruit tutorial on the MPU6050. There are also a number of other example sketches.  

MPU6050 light

Very interesting is also the library MPU6050_light, which you can find here on GitHub or install via the Arduino IDE. It is kept simple (just “light”, as the name suggests). But it offers the possibility to output tilts, which it calculates from the (earth) acceleration data. A prerequisite for reliable data is that the movements are slow, so that the acceleration due to gravity is the decisive variable. Here is an exemplary output of the sample sketch getAngle.ino. I flipped the xy plane back and forth. This works quite well, but I wouldn’t dispose of my spirit level.

Output of GetAngle.ino of the MPU6050 light library
Output of GetAngle.ino of the MPU6050 light library

Leave a Reply

Your email address will not be published. Required fields are marked *