Jump to content
I2Cdevlib Forums

Recommended Posts

Hi, 

I am currently doing a project in which I need to capture the acceleration of a pivoted rotating wooden beam. From the acceleration, I need to determine the velocity. 

I am using Jeff's teapot sketch with the mpu6050 and I have managed to also include the acceleration in the teapotPacket to print acceleration in processing. I know that velocity is the first integral of acceleration. Such integral can be expressed as:
v = u + AT, where v is the current velocity, u is the velocity before, A is the acceleration and T is a time interval.

This is my code for the velocities in the three directions with sampling time of 1ms:

 

 vX = uX + (AX)*0.001; //vX = current velocity in the X direction, uX = velocity in the previous iteration, AX = acceleration in the x direc  uX = vX;                      //setting the current velocity as the previous velocity
    
      
 vY = uY + (AY)*0.001;
 uY = vY;
       
       
 vZ = uZ + (AZ)*0.001;
 uZ = vZ;
    
 
If I move the sensor say in the x direction, acceleration in the x direction increases and when I stop the sensor, acceleration becomes negative and converges to zero, as expected. The velocity seems to be calculated and printed right when increasing from zero to a particular value. Now my problem is, that when I stop moving the sensor, velocity does not go back to zero when the sensor is stationary, but it decreases by a small amount only (say it stops decreasing at 0.5m/s. This gets worse when the sensor is moved faster. 

It seems like the acceleration is read more than the deceleration (decreasing acceleration) and therefore, less negative values for acceleration are captured. 
 
Can anybody help me?

Thanks, Hatt
 

Share this post


Link to post
Share on other sites

Unfortunately you cannot do much about it. It is a well known issue.

A quote from wikipedia http://en.wikipedia.org/wiki/Inertial_navigation_system:

 

All inertial navigation systems suffer from integration drift: small errors in the measurement of acceleration and angular velocity are integrated into progressively larger errors in velocity, which are compounded into still greater errors in position.

You can find also useful information in this talk:

Especially parts starting at 18:40 (single integration) and 23:40 (double integration).

Share this post


Link to post
Share on other sites
Hi Kuba, Thankyou for your reply. I have done the following. I am saving the current acceleration, current velocity and previous velocity in arrays as follows;

 



float [] AccX = new float[time]; //array for the current acceleration after sampling
float [] AccY = new float[time];
float [] AccZ = new float[time];

float [] vXn = new float[time]; //array for the current velocity after integration
float [] vYn = new float[time];
float [] vZn = new float[time];

float AccXn; //float for the current acceleration
float AccYn;
float AccZn;

float v2XR; //float for the resulting velocity
float v2YR;
float v2ZR;

float v2XP; //float for the previous velocity
float v2YP;
float v2ZP;

float time = millis();
if(millis() % 1 == 0) //sampling at 1KHz
{
for(int n = 1; n<time; n++) //filling the arrays
{
AccX[n] = ActualAccelX2; //filling an array with current values of acceleration after sampling
AccY[n] = ActualAccelY2;
AccZ[n] = ActualAccelZ2;

AccXn = AccX[n]; //saving the current vaue of the acceleration array as float for the integration
AccYn = AccY[n];
AccZn = AccZ[n];

vXn[n] = vXn[n-1] + (AccX[n])*0.001; //integration
v2XR = (vXn[n]); //saving the current resultant velocity as a float
u2XP = vXn[n-1]; //saving the previous velocity as a float

vYn[n] = vYn[n-1] + (AccY[n])*0.001;
v2YR = (vYn[n]);
u2YP = vYn[n-1];

vZn[n] = vZn[n-1] + (AccZ[n])*0.001;
v2ZR = (vZn[n]);
u2ZP = vZn[n-1];
}
}


 

This returns exactly what I want. When I move the sensor, acceleration increases and so the velocity. When I stop moving the motor, velocity decreases to zero exactly. However, after I saw the video you posted, I am confused whether I am taking the good approach or not. The results returned looks good after doing some reverse engineering with a calculator (shown in the attached screenshot). Please can you verify whether I am right or wrong? 

 

15i0lew.jpg

 

Thanks in advance, Hatt

Share this post


Link to post
Share on other sites

Your code is very strange. The easiest way to do the integration is this:

float velocity = 0;
float currAccel;
float prevAccel = 0;
unsigned long prevTime = millis();
unsigned long currTime;

void loop() {
  //other stuff
  //refresh currAccel

  currTime = millis();
  velocity += (currAccel + prevAccel)/2*(currTime - prevTime)/1000; //1000 added to get the same units
  prevAccel = currAccel;
  prevTime = currTime;
}

But this will give you a "drift problem". The results won't be even close to good.
That are my results. Sensor was not moving during data integration.

drift.png
As you can see the velocity is growing despite the fact that MPU was stationary.

Share this post


Link to post
Share on other sites

I have tried something similar to your code earlier and I have noticed the velocity drift. In my latest code, I have the actual acceleration which is the acceleration minus gravity component rounded to 1 decimal place using nfc() multiplied by 9.81 to get real acceleration as follows;


String AccelX2i = nfc(AccelX2, 1); //This rounds up the acceleration to 1 decimal place and therefore I will always get the same absolute value during acceleration and decelleration, thus perfect cancellation
gravity2i[0] = nfc(gravity2[0], 1); //similar to previous line
ActualAccelX2=(float(AccelX2i)-float(gravity2i[0]))*9.81; //this gives me the real acceleration

By these three lines of code, I know I am reducing the accuracy of acceleration, but I am also eliminating the drift.

 

Then I am sampling the ActualAccelX2 data and store it in an array whose size increases with time. Also I am creating another array for the velocity;
 


float [] AccX = new float[time]; //array for the current acceleration after sampling
float [] vXn2 = new float[time]; //array for the current velocity
if(millis() % 1 == 0) //sampling at 1KHz
      {
        for(int n = 1; n<time; n++)
        {
          AccX2[n] = ActualAccelX2; //filling the array with the current accel
          vXn2[n] = vXn2[n-1] + (AccX2[n])*0.001; //vX2[n] is the current velocity, vX2[n-1] is the previous velocity and AccX2[n] is the current accel
        }    
      } 

This returns exactly what I need, but I am not sure if it is giving the correct values or not. If it is correct, then the drift is eliminated since the velocity always converges to zero when the sensor is stationary and increases as I start moving the sensor.

Thanks, Hatt.
 

Share this post


Link to post
Share on other sites
hatt0002,

 

I'm a newbie to the MPU6050 but was hoping you could elaborate on your code.

 

  1. Are you using AccelX2 as the true raw values from the accelerometer?
  2. nfc, is this a custom function I wasn't able to find anything about it
  3. gravity2, is this just gravity?

If you would be so kind to explain a little more in detail about where the variables are coming from and what that first block of code is doing.  I'm trying to get velocity which doesn't need to be super accurate and trying to figure RPM of my accelerometer that is spinning.

Share this post


Link to post
Share on other sites

yes, what is the nfc() function ? 

 

 

   // do the integral thing
        ax = (float(aaWorld.x)/16384)*G;   // convert to  cm / s 
        ay = (float(aaWorld.y)/16384)*G;
 
        Serial.print(ax); 
        Serial.print("\t"); 
        Serial.println(ay); 
       
        vx = prevVx + ((prevAx+ax)/2)*dt;
        vy = prevVy + ((prevAy+ay)/2)*dt; 
        prevPx = prevPx + ((prevVx+vx)/2)*dt; 
        prevPy = prevPy + ((prevVy+vy)/2)*dt;
        prevVx = vx; 
        prevVy = vy; 
        prevAx = ax; 
        prevAy = ay; 
 
I'm experiencing the drifting problem. Please advise !

Share this post


Link to post
Share on other sites

 Hey alex8toh, are you using which code? Are you experiecing the driting problem with the code given by hatt0002?

 

 

I need to do the same thing for a senior design project. Get the velocity from this MPU6050 sensor.

Share this post


Link to post
Share on other sites

Hello 

I am using MPU 5060 sensor to measure the speed of my car. I can get the acceleration values using the  OUTPUT_READABLE_REALACCEL function in the MPU6050_DMP6 which gives out 3 axis acceleration. 

I am not sure how can use acceleration data to calculate the speed.

 

I would appreciate any help.

Share this post


Link to post
Share on other sites

The accelerometer's bias error is a very well-known problem. To fix it, just read its values for, say, 10 seconds. Calculate the average of the 10-second signal. This value is the bias value of your accelerometer. Before you calculate the velocity of the movement, subtract the bias error from the accelerometer's values. This should give you a cleaner velocity profile.

Share this post


Link to post
Share on other sites

hello everyone, i have a project using an adxl345 for measure vibration velocity. i had read any references about that said is possible. but i am beginner at arduino. i dont know how to get velocity data with accelerometer. can you guys help me. thanks anyway.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...