How to calculate forward speed, using MPU-6050?

I am improving a project, however, I’m stucked in while trying to calculate the forward speed(velocity) from MPU-6050(The kit I use is Nodemcu). I can get acceleration and gyro data with a good accuracy. I searched some useful things but I couldnt find anything about what I am exactly looking for. Here is my code block thus you can help me. Thank you for your help!!

#include <Wire.h>
#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>

// firebase url 
#define FIREBASE_HOST "xxxx"
//firebase realtime database token
#define FIREBASE_AUTH "xxx"

const char* ssid = "iPhone";
const char* password = "xxx";

// MPU6050 Slave Device Address
const uint8_t MPU6050SlaveAddress = 0x68;

// Select SDA and SCL pins for I2C communication 
const uint8_t scl = D6;
const uint8_t sda = D7;

// sensitivity scale factor respective to full scale setting provided in datasheet 
const uint16_t AccelScaleFactor = 16384;
const uint16_t GyroScaleFactor = 131;

// MPU6050 few configuration register addresses
const uint8_t MPU6050_REGISTER_SMPLRT_DIV   =  0x19;
const uint8_t MPU6050_REGISTER_USER_CTRL    =  0x6A;
const uint8_t MPU6050_REGISTER_PWR_MGMT_1   =  0x6B;
const uint8_t MPU6050_REGISTER_PWR_MGMT_2   =  0x6C;
const uint8_t MPU6050_REGISTER_CONFIG       =  0x1A;
const uint8_t MPU6050_REGISTER_GYRO_CONFIG  =  0x1B;
const uint8_t MPU6050_REGISTER_ACCEL_CONFIG =  0x1C;
const uint8_t MPU6050_REGISTER_FIFO_EN      =  0x23;
const uint8_t MPU6050_REGISTER_INT_ENABLE   =  0x38;
const uint8_t MPU6050_REGISTER_ACCEL_XOUT_H =  0x3B;
const uint8_t MPU6050_REGISTER_SIGNAL_PATH_RESET  = 0x68;

int16_t AccelX, AccelY, AccelZ, Temperature, GyroX, GyroY, GyroZ;

int velocity1;


void setup() {
  Serial.begin(115200);
  delay(10);

  Wire.begin(sda, scl);
  MPU6050_Init();
}

void loop() {


  double Ax, Ay, Az, T, Gx, Gy, Gz;

  Read_RawValue(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H);

  //divide each with their sensitivity scale factor
  Ax = (double)AccelX/AccelScaleFactor;
  Ay = (double)AccelY/AccelScaleFactor;
  Az = (double)AccelZ/AccelScaleFactor;
  T = (double)Temperature/340+36.53; //temperature formula
  Gx = (double)GyroX/GyroScaleFactor;
  Gy = (double)GyroY/GyroScaleFactor;
  Gz = (double)GyroZ/GyroScaleFactor;
  velocity1 =Ay*0.001; // v=v0+a.t (t is sampling rate which is 1 sec) (v0=0 in the begining)
    // Return the response


  //    Firebase.pushFloat("Accelerometer X",Ax);
  //    Firebase.pushFloat("Accelerometer Y",Ay);
  //    Firebase.pushFloat("Accelerometer Z",Az);
  //    Firebase.pushFloat("Temperature",T);
    //  Firebase.pushFloat("Gyro X",Gx);
      //Firebase.pushFloat("Gyro Y",Gy);
      //Firebase.pushFloat("Gyro Z",Gz);
      //Firebase.pushFloat("Speed",velocity1);

 // if (Firebase.failed())
 //{
   //   Serial.print("Database Connection Error:");
     // Serial.println(Firebase.error());  
      //return;
  //}  



  Serial.print("Ax: "); Serial.print(Ax);
  Serial.print(" Ay: "); Serial.print(Ay);
  Serial.print(" Az: "); Serial.print(Az);
  Serial.print(" T: "); Serial.print(T);
  Serial.print(" Gx: "); Serial.print(Gx);
  Serial.print(" Gy: "); Serial.print(Gy);
  Serial.print(" Gz: "); Serial.println(Gz);


  Serial.println("Speed"); Serial.println(velocity1);
 // Serial.println("" + String(Gz) + "; " + String(Gy) + "; " + String(Gx) + "; " + String(Ax) + "; " + String(Ay) + "; " + String(Az) + ";");

  delay(100);
}

void I2C_Write(uint8_t deviceAddress, uint8_t regAddress, uint8_t data){
  Wire.beginTransmission(deviceAddress);
  Wire.write(regAddress);
  Wire.write(data);
  Wire.endTransmission();
}

// read all 14 register
void Read_RawValue(uint8_t deviceAddress, uint8_t regAddress){
  Wire.beginTransmission(deviceAddress);
  Wire.write(regAddress);
  Wire.endTransmission();
  Wire.requestFrom(deviceAddress, (uint8_t)14);
  AccelX = (((int16_t)Wire.read()<<8) | Wire.read());
  AccelY = (((int16_t)Wire.read()<<8) | Wire.read());
  AccelZ = (((int16_t)Wire.read()<<8) | Wire.read());
  Temperature = (((int16_t)Wire.read()<<8) | Wire.read());
  GyroX = (((int16_t)Wire.read()<<8) | Wire.read());
  GyroY = (((int16_t)Wire.read()<<8) | Wire.read());
  GyroZ = (((int16_t)Wire.read()<<8) | Wire.read());
}

//configure MPU6050
void MPU6050_Init(){
  delay(150);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SMPLRT_DIV, 0x07);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_1, 0x01);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_PWR_MGMT_2, 0x00);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_CONFIG, 0x00);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_GYRO_CONFIG, 0x00);//set +/-250 degree/second full scale
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_CONFIG, 0x00);// set +/- 2g full scale
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_FIFO_EN, 0x00);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_INT_ENABLE, 0x01);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_SIGNAL_PATH_RESET, 0x00);
  I2C_Write(MPU6050SlaveAddress, MPU6050_REGISTER_USER_CTRL, 0x00);
}

Velocity is a timed accumulation of acceleration. I don't see anywhere in your code your are accumulating any acceleration values for any axis.

Paul

I dont know how to do it. Can you please describe it or show me writing a code about it? I am new on Arduino.

Don't bother, it won't work. See this explanation.

My supervisor asked me to calculate it so I have to calculate it even if it contains big errors which is mean low accuracy. If there is a way that is been tried, please show me.

From the most basic physics, (final velocity) = (acceleration)*(time) + (initial velocity), in the case of constant acceleration.

For changing acceleration, the above holds for short intervals, during which the acceleration can be assumed constant.

But do discuss the material in this article with your supervisor. He or she may learn something.

Hello! a0 and v0 are zero in the beginning.

void loop(){

time1=millis();
Read_RawValue(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H);

//calculating the sensor data

time2=millis();

axm=Ax9.8; // from g unit to m/s^2
aym=Ay
9.8;
azm=Az9.8;
v=v0+(aym+a0)/2
(time2-time1); //v0=0 and a0=0 in the beginning
v0=v; // given the previous v value to v0 for the next loop
a0=aym;
}

What do you think about this code? I am right?

I am gonna advise him about the article you shared.

What do you think about this code? I am right?

Not much, and no. Time is not treated correctly, among other problems.

Think about what happens in the likely event that it takes less than 1 millisecond to read out the accelerometer.

A better approach would be to read out the accelerometer several times during (for example) an 0.1 second interval, average the accelerations over the interval, and compute the new velocity at the end of the interval.

jremington:
Not much, and no. Time is not treated correctly, among other problems.

Think about what happens in the likely event that it takes less than 1 millisecond to read out the accelerometer.

A better approach would be to read out the accelerometer several times during (for example) an 0.1 second interval, average the accelerations over the interval, and compute the new velocity at the end of the interval.

More than 60 years since I studied that in calculus 1.

Paul

And it is still useful!

@morkocberk: I believe that Paul_KD7HB is hoping that you will study how to numerically integrate the acceleration, as there are better approaches than the one I suggested.

However, as you will see, none of them will work for more than a minute or two before the result becomes nonsensical.

jremington:
A better approach would be to read out the accelerometer several times during (for example) an 0.1 second interval, average the accelerations over the interval, and compute the new velocity at the end of the interval.

Thanks for showing me a way. At the end of the loop i use delay(100) code which it means wait for 0.1sec before start next loop and I read out the sensor data in the loop function. I am totally confused. Should I use “for” loop where I read out the accelerometer data? Like

void loop(){

for(int i=1;i<=100;i++){ // i was having a sample in 0.1sec(delay(100)), now I have a sample in 0.001sec

//calculate the acceleration

}

for(int i=1;i<=100;i++){

// averages of the acceleration
total+=a
}
average=total/100;
I am totally confused. Can you please tell me how to define time interval?

  if(millis()-lastTime>10){      
  Read_RawValue(MPU6050SlaveAddress, MPU6050_REGISTER_ACCEL_XOUT_H);
  
  //divide each with their sensitivity scale factor
  Ax = (double)AccelX/AccelScaleFactor;
  Ay = (double)AccelY/AccelScaleFactor;
  Az = (double)AccelZ/AccelScaleFactor;
  T = (double)Temperature/340+36.53; //temperature formula
  Gx = (double)GyroX/GyroScaleFactor;
  Gy = (double)GyroY/GyroScaleFactor;
  Gz = (double)GyroZ/GyroScaleFactor;
  totalAy+=Ay;
  counter++;
  if(counter==100){
    average=(double)totalAy/100;
    counter=0;
    totalAy=0;
  }
  lastTime=millis();
  }
  v=v0+(average+a0)/2*0.01; //v0=0 and a0=0 in the beginning
  v0=v; // given the previous v value to v0 for the next loop
  a0=average;

What about now?

You need to do some reading on numerical integration.