Speeding up MPU 6050 data collection

Hello, I am using an Arduino UNO to collect data from an accelerometer/gyroscope sensor (MPU6050) and velocity from an IR sensor on an RC car. I am running into the problem where my code is running very slow when I am collecting data from the MPU6050. In my data collecting loop, I am jumping to two different functions. One collects velocity data from the IR sensor and the other function collects accelerations from the MPU 6050. I have this loop continuously for 0.2 seconds and then I take all the data gathered and do calculations from it. I am able to get over 25,000 values when using just the velocity function and commenting out the MPU function loop. However, when I have the MPU function running as well, I only collect 34 values during that 0.2 second span. How can I speed up my data collecting from the MPU 6050 sensor. Is the library I am using limiting my speed to get data?
This is my while loop that restarts every 0.2 seconds and the two functions are inside.

start_time=millis();             //Set start time equal to the current time on Arduino
   end_time=start_time+iteration;   //Set end time to be greater than start time by the iteration value set above

   while (millis()<end_time){       //Run this loop until iteration time is complete
    mpuFunction();                  //Jump to mpuFunciton
    velocityFunction();             //Jump to Velocity Function 
   }

Below is my mpuFuntion

void mpuFunction(){
  
    mpu.read();
    // Get new sensor events with the readings 
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);
    
    total_Acc_X=total_Acc_X+a.acceleration.x;
    total_Acc_Y=total_Acc_Y+a.acceleration.y;
    total_Acc_Z=total_Acc_Z+a.acceleration.z;

    total_Gyro_X=total_Gyro_X+g.gyro.x;
    total_Gyro_Y=total_Gyro_Y+g.gyro.y;
    total_Gyro_Z=total_Gyro_Z+g.gyro.z;

    count++    //Increase count everytime loop is ran
}

Thanks for any help you can give.

Please follow the guidelines in the first topic "How to use this Forum", especially #7.
Using the dumb mobile for the moment I can't download that code, so no help from me today.

Sorry for that. I added my code properly.

Fine, You found out how to post code.
Sorry, but next finger. Always post the entire code. Else, You will be the best to find the bug.
Try again, and please post new information in Your latest reply. That makes new helpers catch the latest info faster.

Here is the entire code. I didnt post the whole code before because it said there was too many characters in my post.

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
Adafruit_MPU6050 mpu;
File myFile;

const int buttonPin = 7;          // pushbutton pin
bool buttonState = 0;             // pushbutton status

const int red =  2;              // failed connection LED pin
const int green =  3;            // Connection complete LED pin
const int yellow =  4;           // Calibtating LED pin
const int greencomplete =  5;    // Program complete LED pin

float errorx; float errory; float errorz;                                   //Individual Acceleration error values
float errorgyrox; float errorgyroy; float errorgyroz;                       //Individual Gyroscope error values
float AverageErrorAccX; float AverageErrorAccY; float AverageErrorAccZ;     //Average Acceleration error values
float AverageErrorGyroX; float AverageErrorGyroY; float AverageErrorGyroZ;  //Average Gyroscope error values

float total_Acc_X; float total_Acc_Y; float total_Acc_Z;      //Added total of all Acceleration values
float cal_Acc_X; float cal_Acc_Y; float cal_Acc_Z;            //Total divided by count amount

float total_Gyro_X; float total_Gyro_Y; float total_Gyro_Z;   //Added total of all Gyro values
float cal_Gyro_X; float cal_Gyro_Y; float cal_Gyro_Z;         //Total divided by count amount
  
int count;  //Number of loop iterations for function loop
float rps;  //Revolutions per second

int sensor = 9;                //IR sensor pin
unsigned long start_time = 0; unsigned long end_time = 0;
int steps=0;        //number of sensor steps per iterations (restarts)
int total_Steps=0;  //Total number of sensor steps 

bool sensorState=0;            //IR sensor state
bool prevSensorState=0;        //Previous IR sensor state

void setup(void) {

 const int red =  2;              // failed connection LED pin
 const int green =  3;            // Connection complete LED pin
 pinMode(red, OUTPUT);            // initialize LED pins
 pinMode(green, OUTPUT);
 pinMode(yellow, OUTPUT);
 pinMode(greencomplete, OUTPUT);
 pinMode(buttonPin, INPUT);       // initialize pushbutton pin 
 
 pinMode(sensor,INPUT_PULLUP); //initialize sensor pin
 
 float ErrorAccX=0; float ErrorAccY=0; float ErrorAccZ=0;        //Total Acceleration error values  
 float ErrorGyroX=0; float ErrorGyroY=0; float ErrorGyroZ=0;     //Total Gyroscope error values
 int c; //Number of calibration loops
 int x; //Error value counter

  Serial.begin(9600);
 if (!SD.begin(10)) {
    digitalWrite(red, HIGH);                    //if no connection to sd card
    while (1);
    }
    
  myFile = SD.open("SDTEST1.txt", FILE_WRITE);    // open the file
  if (!myFile) {
    digitalWrite(red, HIGH);                      // if the file doesnt open
    } 

  if (!mpu.begin()) {
    digitalWrite(red, HIGH);                    // if no connection to mpu5060 sensor
    while (1);
    }
  
  digitalWrite(green, HIGH);

  //Setting up MPU sensor
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  switch (mpu.getAccelerometerRange()) {
  case MPU6050_RANGE_8_G:
    break;
  }
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  switch (mpu.getGyroRange()) {
  case MPU6050_RANGE_500_DEG:
    break;
  }
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);
  switch (mpu.getFilterBandwidth()) {
  case MPU6050_BAND_21_HZ:
    break;
  }
  
delay (500); //5 second delay for car to stabilize on level ground
  x=0;
  c=56;
 //take error data from function for 56 iterations
 //Blinks yellow LED 4 times during calibration
 while (x<c) {  
  if (x<(c/8) ||((x>=3*c/8) && (x<4*c/8 ))||((x>=5*c/8) && (x<6*c/8 )) ){
       digitalWrite(yellow, HIGH);
  }
  else {
       digitalWrite(yellow, LOW);
  }
  calculate_error();                    //Enter Calculate error funtion
  ErrorAccX=(ErrorAccX+errorx);         //Take values from funtion and add to total
  ErrorAccY=(ErrorAccY+errory);
  ErrorAccZ=(ErrorAccZ+errorz);
  ErrorGyroX=(ErrorGyroX+errorgyrox);
  ErrorGyroY=(ErrorGyroY+errorgyroy);
  ErrorGyroZ=(ErrorGyroZ+errorgyroz);
  
  delay (50);
  x++;
 }
 
 //Take total error divided by number of readings
 AverageErrorAccX=ErrorAccX/x;
 AverageErrorAccY=ErrorAccY/x;
 AverageErrorAccZ=ErrorAccZ/x;
 AverageErrorGyroX=ErrorGyroX/x;
 AverageErrorGyroY=ErrorGyroY/x;
 AverageErrorGyroZ=ErrorGyroZ/x;

}

void loop(){

  float iteration=200;    //time for loop to run and then present readings in SD card
  float mph; float mps;   //miles per hour and meters per second variables
  
while (digitalRead(buttonPin) == LOW) {             //While button is not pressed
   steps =0;                                        //Set step counter to 0
   count=0;                                         //Number of times loop runs during the iteration time set
   total_Acc_X=0;  total_Acc_Y=0;  total_Acc_Z=0;   //Set total acceleration values gathered to 0
   cal_Acc_X=0;  cal_Acc_Y=0;  cal_Acc_Z=0;         //Set calculated acceleration value to 0

   total_Gyro_X=0; total_Gyro_Y=0; total_Gyro_Z=0; //Set total Gyro values gathered to 0
   cal_Gyro_X=0;  cal_Gyro_Y=0;  cal_Gyro_Z=0;     //Set calculated gyro value to 0
    
   digitalWrite(yellow, HIGH);                     //Leave yellow lED on so you know program is running

   start_time=millis();             //Set start time equal to the current time on Arduion
   end_time=start_time+iteration;   //Set end time to be greater than start time by the iteration value set above

   while (millis()<end_time){       //Run this loop until iteration time is complete
    mpuFunction();                  //Jump to mpuFunciton
    velocityFunction();             //Jump to Velocity Function 
   }
   Serial.println(count);
    cal_Acc_X=total_Acc_X/count;    //Take the total amount of Acceration values added up and divide by the amount of loops ran 
    cal_Acc_Y=total_Acc_Y/count;
    cal_Acc_Z=total_Acc_Z/count;

    cal_Gyro_X=total_Gyro_X/count;  //Take the total amount of Gyro values added up and divide by the amount of loops ran
    cal_Gyro_Y=total_Gyro_Y/count;
    cal_Gyro_Z=total_Gyro_Z/count;

    rps=((1000/iteration)*steps/6); //Calculate number of revolutions per second of driveshaft
    mps=117*rps/1000;               //meters per second conversion
    mph=mps*2.237;                  //mph conversion
    
    //Print out the values to SD card
  
    myFile.print(cal_Acc_X-AverageErrorAccX);
    myFile.print("\t");
    myFile.print(cal_Acc_Y-AverageErrorAccY);
    myFile.print("\t");
    myFile.print(cal_Acc_Z-AverageErrorAccZ+9.81);
    myFile.print("\t"); 
    myFile.print(cal_Gyro_X-AverageErrorGyroX);
    myFile.print("\t"); 
    myFile.print(cal_Gyro_Y-AverageErrorGyroY);
    myFile.print("\t"); 
    myFile.print(cal_Gyro_Z-AverageErrorGyroZ);
    myFile.print("\t");
    myFile.print(mps);
    myFile.print("\t");
    myFile.print(count);
    myFile.print("\t");
    myFile.println(millis());
 }
myFile.close();                     //Close SD file once button is pressed

digitalWrite(greencomplete, HIGH);  //Turn on green LED to show test is complete
for (;;);                           //Exit void loop
}

//Gather error data for calibration
void calculate_error() {
     mpu.read();

  //Get new sensor events with the readings 
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);
  
  errorx=a.acceleration.x;
  errory=a.acceleration.y;
  errorz=a.acceleration.z;
  errorgyrox=g.gyro.x;
  errorgyroy=g.gyro.y;
  errorgyroz=g.gyro.z;
}

//Gather Acceleration Data
void mpuFunction(){
  
    mpu.read();
    // Get new sensor events with the readings 
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);
    
   total_Acc_X=total_Acc_X+a.acceleration.x;
    total_Acc_Y=total_Acc_Y+a.acceleration.y;
    total_Acc_Z=total_Acc_Z+a.acceleration.z;

    total_Gyro_X=total_Gyro_X+g.gyro.x;
    total_Gyro_Y=total_Gyro_Y+g.gyro.y;
    total_Gyro_Z=total_Gyro_Z+g.gyro.z;

    //count++    //Increase count everytime loop is ran
}

//Gather Velocity data
void velocityFunction(){
  sensorState=digitalRead(sensor);        //Read if sensor is HIGH or LOW
  if (sensorState != prevSensorState){    //If Sensor state is different than previous, then enter if statement
    if (sensorState==HIGH){               //If sensor is HIGH, add a step to steps and Total steps
      steps++;
      total_Steps++;
      }
    }
prevSensorState=sensorState;              //Set previous sensor state to the current sensor state
count++;
}

You are performing a lot of floating point arithmetic’s and that costs time.
Suppose the MPU could deliver integers. Then accumulating integers during the data collection and when the measuring time is out, convert the final accumulated values to float and write to the file.

I tried commenting out all the variable transfers for that function and made it only one integer value transferring between the functions and it still ran at the same speed. Only 34 loop iterations in 0.2 seconds. Could it be in the MPU library? Should I try a different MPU library?

Take a dive into the data sheet of the MPU and check things out. I have no idea whether different modes can be selected, what response time they have etc.

How do you deal with the 5V (Uno) to 3.3V mismatch with the MPU-6050? You should be using a level shifter, or a 3.3V Arduino.

You don’t need a library for the MPU-6050, and I generally avoid the Adafruit libraries, because they are very bloaty, and Adafruit makes too many assumptions about what people want to do.

If you are happy with the default settings, the following minimal code reads out all parameters at about 500 Hz:
If not, change settings in setup().

// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include<Wire.h>
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;

unsigned long now, last;
unsigned int loops = 0;
void setup() {
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
  last = millis();
}

void loop() {
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14); // request a total of 14 registers
  int t = Wire.read();
  AcX = (t << 8) | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  t = Wire.read();
  AcY = (t << 8) | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  t = Wire.read();
  AcZ = (t << 8) | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  t = Wire.read();
  Tmp = (t << 8) | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  t = Wire.read();
  GyX = (t << 8) | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  t = Wire.read();
  GyY = (t << 8) | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  t = Wire.read();
  GyZ = (t << 8) | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  t = Wire.read();
  loops++;
  now = millis();
  if (now - last > 1000UL) {
    Serial.print("AcX = "); Serial.print(AcX);
    Serial.print(" | AcY = "); Serial.print(AcY);
    Serial.print(" | AcZ = "); Serial.print(AcZ);
    Serial.print(" | Tmp = "); Serial.print(Tmp / 340.00 + 36.53); //equation for temperature in degrees C from datasheet
    Serial.print(" | GyX = "); Serial.print(GyX);
    Serial.print(" | GyY = "); Serial.print(GyY);
    Serial.print(" | GyZ = "); Serial.print(GyZ);
    Serial.print(", loops = "); Serial.println(loops);
    loops = 0;
    last = now;
  }
}

jremington:
How do you deal with the 5V (Uno) to 3.3V mismatch with the MPU-6050? You should be using a level shifter, or a 3.3V Arduino.

I have it hooked into the 3.3V pin for the arduino. It has been working fine.

I will give that code a try and see if it works. I would really love to avoid using that library all together. Thanks!

The sensor may work for a while, the way you have it, but don't expect it to last. The instant you expose SDA or SCL or the address pin to 5V, it will be destroyed.

You REALLY do need to pay attention, and use a 3.3V Arduino or level shifters.

jremington:
You REALLY do need to pay attention, and use a 3.3V Arduino or level shifters.

So using the 3.3V pin on the arduino is still not safe? or are you saying that if I accidently use the 5V pin I will destroy it?

The outputs SCL and SDA of a 5 volt Arduino reaches 5 volt. That is bad for the 3.3 volt 6050.

Railroader:
The outpurs SCL and SDA of a 5 vilt Arduino reaches 5 volt. That is bad for the 3.3 volt 6050.

Oh ok I understand. I will do something about that.

jremington:
You don't need a library for the MPU-6050, and I generally avoid the Adafruit libraries, because they are very bloaty, and Adafruit makes too many assumptions about what people want to do.

If you are happy with the default settings, the following minimal code reads out all parameters at about 500 Hz:
If not, change settings in setup().

I got the code to work. However, it is printing very large values for each reading on the board. What is it actually printing? It is definitely not acceleration in g's.

Can You post this last code, just to be sure?

It is definitely not acceleration in g's.

Of course not. Those are raw sensor values. The data sheet explains how to scale to conventional units. If you don't want to use libraries, you have to learn how the sensor works and what it is telling you.

Hint: When the sensor is held still, the acceleration along any vertical axis is 1 g, by definition.

Railroader:
Can You post this last code, just to be sure?

// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include<Wire.h>
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;

unsigned long now, last;
unsigned int loops = 0;
void setup() {
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
  last = millis();
}

void loop() {
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14); // request a total of 14 registers
  int t = Wire.read();
  AcX = (t << 8) | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  t = Wire.read();
  AcY = (t << 8) | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  t = Wire.read();
  AcZ = (t << 8) | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  t = Wire.read();
  Tmp = (t << 8) | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  t = Wire.read();
  GyX = (t << 8) | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  t = Wire.read();
  GyY = (t << 8) | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  t = Wire.read();
  GyZ = (t << 8) | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  t = Wire.read();
  loops++;
  now = millis();
  if (now - last > 1000UL) {
    Serial.print("AcX = "); Serial.print(AcX);
    Serial.print(" | AcY = "); Serial.print(AcY);
    Serial.print(" | AcZ = "); Serial.print(AcZ);
    Serial.print(" | Tmp = "); Serial.print(Tmp / 340.00 + 36.53); //equation for temperature in degrees C from datasheet
    Serial.print(" | GyX = "); Serial.print(GyX);
    Serial.print(" | GyY = "); Serial.print(GyY);
    Serial.print(" | GyZ = "); Serial.print(GyZ);
    Serial.print(", loops = "); Serial.println(loops);
    loops = 0;
    last = now;
  }
}

Here is the code I am using. Copied from the previous post

I'll take a closer look tomorrow. (Late here now.)
How fast are the readings now?

jremington:
Of course not. Those are raw sensor values. The data sheet explains how to scale to conventional units. If you don't want to use libraries, you have to learn how the sensor works and what it is telling you.

Ok that makes sense. Thats what I was thinking. Thanks.

Railroader:
I'll take a closer look tomorrow. (Late here now.)
How fast are the readings now?

With the code posted, I am reading 110 loops per 0.2 seconds. So it is definitely an improvement. Just not enough for what I need.

Hi,
Can you tell us the application of your code?
Why do you need fast acquisition?

Thanks.. Tom.. :slight_smile: