Go Down

Topic: Difficuly getting difference of MPU6050 values over time (Read 367 times) previous topic - next topic

eezJerome

Hello

So in a nutshell, I want to find the change of the raw values from my MPU6050 over some amount of sample time. I thought of applying a simple difference formula (x2 - x1, etc) but for some reason I am not getting anything useful. In more detail, the values I am working with are float type

Would love any help I can get


Code: [Select]

// here i have previously declared values "realacc"
// basically the raw values are converted to m/s2

int sampletime = 50;

void accel_getDelta() {
  currenttime = millis();
  float x1 = realaccx;
  float y1 = realaccy;
  float z1 = realaccz;

  if (currenttime - prevtime > sampletime) {
    float x2 = realaccx;
    float y2 = realaccy;
    float z2 = realaccz;
    Serial.print(x2 - x1); Serial.print("\t  ");
    Serial.print(y2 - y1); Serial.print("\t  ");
    Serial.print(z2 - z1); Serial.print("\t");
    Serial.println(" ");

    prevtime = currenttime;
  }

}

pylon

First: post complete code!

I hope you see that in your code fragment you should get more or less an output of 0 because the time difference between the two measurements is only a few microseconds.

Idahowalker

#2
Apr 18, 2019, 06:27 pm Last Edit: Apr 18, 2019, 06:32 pm by Idahowalker
You are using which board?

from that code snippet, use micros() instead of millis().

I use an ESP32, the measurements and calculations take less then a mS, with interrupts on, I frequently get new triggers in less then a mS. Using mS that would give times of 0. Times of 0 in the MahonyQuaternionUpdate calculations, give wild fluctuations of data.

I use
Code: [Select]

 TimeNow = micros()/1000000.0f;
        deltat = ( TimeNow - TimePast);
at the beginning of the loop but after a confirmed data read.

At the end of the code, I use
Code: [Select]
TimePast = TimeNow;

The variables are initialized with
Code: [Select]

  float TimePast = micros()/1000000.0f;
  float TimeNow = micros()/1000000.0f;



eezJerome

First: post complete code!

I hope you see that in your code fragment you should get more or less an output of 0 because the time difference between the two measurements is only a few microseconds.
You are very right -- all I get is zero after zero. It's cool how you knew that :)

My code is messy but here:

Code: [Select]

#include <I2Cdev.h>
#include <MPU6050.h>


// declaring sensor module
MPU6050 mpu;

// defining vars for raw values
const float g = 9.80665;
int16_t
rawaccx, rawaccy, rawaccz,
         rawgyrx, rawgyry, rawgyrz;

float
time, prevtime, currenttime;

int i;
float pi = 180 / 3.141592654;

//acceleration conversion factor; raw_value / 1671 = m/s2 value
const int convraw = 1671;


float
realaccx, realaccy, realaccz;


void setup() {
  Wire.begin();
  Serial.begin(115200);

  mpu.initialize();

  //  51  -40 -19 -4280  -3452 1475
  mpu.setXGyroOffset(51); //this was at 220
  mpu.setYGyroOffset(40); //76
  mpu.setZGyroOffset(-19); //-85
  //these are ones I put
  mpu.setXAccelOffset(-4280);
  mpu.setYAccelOffset(-3452);
  mpu.setZAccelOffset(1475);

  mpu.setDLPFMode(MPU6050_DLPF_BW_42); // 42hz digital low pass filter

}

void loop() {
  mpu.getMotion6(&rawaccx, &rawaccy, &rawaccz, &rawgyrx, &rawgyry, &rawgyrz);
  getaccel(rawaccx, rawaccy, rawaccz);  // just to print this function
  getgyr(rawgyrx, rawgyry, rawgyrz);

 
//  Serial.print(realaccx); Serial.print(" \t");
//  Serial.print(realaccy); Serial.print("      \t");
//  Serial.print(realaccz); Serial.print("      \t");

//  accel_getDelta();

}

// converts raw accelerometer data to m/s/s
float getaccel(float x, float y, float z) {
  realaccx = x / convraw;
  realaccy = y / convraw;
  realaccz = z / convraw;
}

}

int sampletime = 50; // arbitrary sample time value; was initially at 10

float accel_getDelta() {
  currenttime = millis();
  float x1 = realaccx;
  float y1 = realaccy;
  float z1 = realaccz;

  if (currenttime - prevtime > sampletime) {
    float x2 = realaccx;
    float y2 = realaccy;
    float z2 = realaccz;
   
      Serial.print(x2 - x1); Serial.print("\t  ");
      Serial.print(y2 - y1); Serial.print("\t  ");
      Serial.print(z2 - z1); Serial.print("\t");
      Serial.println(" ");
  prevtime = currenttime;
  }


You are using which board?

from that code snippet, use micros() instead of millis().

I use an ESP32, the measurements and calculations take less then a mS, with interrupts on, I frequently get new triggers in less then a mS. Using mS that would give times of 0. Times of 0 in the MahonyQuaternionUpdate calculations, give wild fluctuations of data.

I use
Code: [Select]

 TimeNow = micros()/1000000.0f;
        deltat = ( TimeNow - TimePast);
at the beginning of the loop but after a confirmed data read.

At the end of the code, I use
Code: [Select]
TimePast = TimeNow;

The variables are initialized with
Code: [Select]

  float TimePast = micros()/1000000.0f;
  float TimeNow = micros()/1000000.0f;



I use Arduino Nano, and wow this seems very helpful. I'll implement this and report results.


eezJerome

Alright so I implemented the micros() idea but I'm still getting a string of zeroes.

Here's how I did it; it's the same code as above except for this excerpt
Code: [Select]

int sampletime = 5000; // changed to be for micros()

float accel_getDelta() {
  currenttime = micros()/1000000.0f;
  float x1 = realaccx;
  float y1 = realaccy;
  float z1 = realaccz;

  float deltat = (currenttime - prevtime);
  // I really think the issue is in this if() statement; something doesnt seem right...
  if (deltat > sampletime) {
    Serial.print(realaccx - x1); Serial.print("\t  ");
    Serial.print(realaccy - y1); Serial.print("\t  ");
    Serial.print(realaccz - z1); Serial.print("\t  ");
    Serial.println(currenttime); Serial.print("\t");
    Serial.println(" ");
    prevtime = currenttime;
  }
}

Idahowalker

Look at how to use millis() for timing and you should be able to see your issue.

jremington

Quote
it's the same code as above except for this excerpt
Same mistake. You read the acceleration, then read it again a microsecond later and print the difference.

Try something like this instead (but you REALLY SHOULD use long integer variables with millis() or micros()).

Code: [Select]
float accel_getDelta() {
  static float x1=0, y1=0, z1=0;
  currenttime = micros()/1000000.0f;
  float deltat = (currenttime - prevtime);

  if (deltat > sampletime) {
    prevtime = currenttime;
    Serial.print(realaccx - x1); Serial.print("\t  ");
    Serial.print(realaccy - y1); Serial.print("\t  ");
    Serial.print(realaccz - z1); Serial.print("\t  ");
    Serial.println(currenttime); Serial.print("\t");
    Serial.println(" ");

    x1 = realaccx;
    y1 = realaccy;
    z1 = realaccz;
  }
}


Study this Blink without Delay tutorial.

eezJerome

Same mistake. You read the acceleration, then read it again a microsecond later and print the difference.

Try something like this instead (but you REALLY SHOULD use long integer variables with millis() or micros()).

Code: [Select]
float accel_getDelta() {
  static float x1=0, y1=0, z1=0;
  currenttime = micros()/1000000.0f;
  float deltat = (currenttime - prevtime);

  if (deltat > sampletime) {
    prevtime = currenttime;
    Serial.print(realaccx - x1); Serial.print("\t  ");
    Serial.print(realaccy - y1); Serial.print("\t  ");
    Serial.print(realaccz - z1); Serial.print("\t  ");
    Serial.println(currenttime); Serial.print("\t");
    Serial.println(" ");

    x1 = realaccx;
    y1 = realaccy;
    z1 = realaccz;
  }
}


Study this Blink without Delay tutorial.
I apologize for the late reply; I've been busy with other things. Thank you for the help, but this time there's nothing getting printed. The code provided by jremington does not print anything to the monitor.

For the time being I'll take the time to read over the tutorial as well as other related sources/codes.

Look at how to use millis() for timing and you should be able to see your issue.
I'll look into proper usage of timing. Thank you

eezJerome

Alright so I did some reading over and I edited like one line of code from jremington. What I noticed is that removing the part with "1000000.0f" allows me to print my data, and it seems a bit iffy (because when I take raw values the differences are no greater than 0.01 due to filtering, among other things). It pretty much ruins the purpose of taking the change of the acceleration values if it's printing something like 0.3 differences.

Might it be that the decimals are shifted or something?

Here's what I used that "works"

Code: [Select]

/*............................................*/

unsigned long prevtime = 0;
int sampletime = 50;

long accel_getDelta(){
  static long x1=0, y1=0, z1=0;
  unsigned long currenttime = micros();//1000000.0f;
  float deltat = (currenttime - prevtime);

  if (deltat > sampletime){
    prevtime = currenttime;
   
    Serial.print(realaccx - x1); Serial.print("\t "); 
    Serial.print(realaccy - y1); Serial.print("\t ");
    Serial.print(realaccz - z1); Serial.print("\t ");
    Serial.println(currenttime); Serial.print("\t ");
    Serial.println(" ");

    x1 = realaccx;
    y1 = realaccy;
    z1 = realaccz;
  }
}

jremington

Don't use floats or ints for time! Variables used with millis() and micros() should be unsigned long, including "sampletime".
Code: [Select]
int sampletime = 50;
...
 unsigned long currenttime = micros();
 float deltat = (currenttime - prevtime);
 if (deltat > sampletime){


It makes absolutely no sense to print every 50 microseconds, as printing a few characters takes milliseconds.
 

eezJerome

It makes absolutely no sense to print every 50 microseconds, as printing a few characters takes milliseconds.
  
Thanks for that note. I guess we've solved my issue. Thank you very much :)

Additionally, what would be a more appropriate sample time? I would like the lowest possible but anything you guys deem more useful and essentially better is welcome.

However, now i'm curious: is there a resource that can show me the execution time of Arduino? All I know is that since Arduino uses a 16MHz oscillator, that it can perform 16 million tasks a second [?]

Thanks in advanced.

jremington

#11
Apr 22, 2019, 04:50 pm Last Edit: Apr 22, 2019, 04:56 pm by jremington
The MPU6050 data sheet explains the available sample rates. This statement in your code limits the sample rate:
Code: [Select]
mpu.setDLPFMode(MPU6050_DLPF_BW_42); // 42hz digital low pass filter

The execution time of the Arduino is not the issue here, but the 16 MHz clock rate is the maximum number of machine instructions per second.

Idahowalker

Do note, if you decide to use a data filter scheme that integrates time, such as a https://os.mbed.com/users/onehorse/ Sebastian Madgwick's open-source IMU fusion filter. You will want your uS or mS in a float format.

eezJerome

The MPU6050 data sheet explains the available sample rates. This statement in your code limits the sample rate:
Code: [Select]
mpu.setDLPFMode(MPU6050_DLPF_BW_42); // 42hz digital low pass filter

The execution time of the Arduino is not the issue here, but the 16 MHz clock rate is the maximum number of machine instructions per second.
Do note, if you decide to use a data filter scheme that integrates time, such as a https://os.mbed.com/users/onehorse/ Sebastian Madgwick's open-source IMU fusion filter. You will want your uS or mS in a float format.
All acknowledged, thank you very much!

Alright, one last question. I read here (http://www.chrobotics.com/library/accel-position-velocity) that even though I can gather data in very small time samples (theoretically), I am limited by the speed of how the serial monitor outputs the data. So basically, I might not really be reading data at a time interval I provided, rather it will be the bounds of the serial monitor I have to compensate for.

Thanks

jremington

#14
Apr 23, 2019, 04:20 am Last Edit: Apr 23, 2019, 04:20 am by jremington
Quote
I might not really be reading data at a time interval I provided
You need to write the program so that it reads samples at the correct intervals.

This is not a problem if you have read the MPU6050 data sheet carefully, and have set up the sensor appropriately.

Go Up