Hello,
I’m trying to interpret and use data from a Sparkfun KX132 accelerometer to calculate velocity and displacement of the sensor. I read that accelerometers sense acceleration, but I’m not sure how to use the data. Depending on the orientation of the sensor, the KX132 outputs floats from -1 to 1 for each axis.
I am using the following expressions to calculate velocity and displacement:
vx = vx + ax * dt
x = vx * dt
Where ax is the x-axis data from the sensor, dt is the time elapsed between each instance the Arduino reads data from the sensor, vx is velocity, and x is displacement. However, I’m not getting the intended reading/value from vx; it doesn’t seem to correlate with the linear movement of the sensor at all. Am I using the correct sensor for what I’m trying to accomplish, or is there an error in my calculation? Below is the code I have. Any help would be greatly appreciated. Thank you.
#include <Wire.h>
#include <SparkFun_KX13X.h>
SparkFun_KX132 kxAccel;
outputData data;
float x[5];
float xAvg = 0;
float vx = 0;
float ax = 0;
float xPos = 0;
const float dt = 100;
int points = 0;
int i = 0;
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("Welcome.");
while (!Serial)
delay(50);
if (!kxAccel.begin()) {
Serial.println("Could not communicate with the the KX13X. Freezing.");
while (1)
;
}
Serial.println("Ready.");
if (kxAccel.softwareReset())
Serial.println("Reset.");
delay(5);
kxAccel.enableAccel(false);
kxAccel.setRange(SFE_KX132_RANGE16G);
kxAccel.enableDataEngine();
kxAccel.enableAccel();
}
void loop() {
if (kxAccel.dataReady()) {
kxAccel.getAccelData(&data);
if (i < 5) {
x[i] = data.xData;
i++;
} else {
for (int ind = 0; ind < 5; ind++) {
xAvg += x[ind];
}
xAvg /= 5;
if (xAvg > -0.02 && xAvg < 0.02) xAvg = 0.0;
vx = vx + xAvg * dt; // vx = vx + ax * dt
xPos = vx * dt // x = vx * dt
Serial.print(xAvg);
Serial.print(", ");
Serial.print(vx);
Serial.print(", ");
Serial.println(xPos);
clearValues();
}
}
delay(20);
}
void clearValues() {
for (int ind = 0; ind < 5; ind++) {
x[ind] = 0;
}
xAvg = 0;
i = 0;
}
It is not clear that you are correctly integrating the acceleration and velocity. Why is dt set to 100? What is the correct scale factor for standard units of velocity and position?
Regardless, for several reasons, it is not practical to estimate position or velocity with data from consumer grade accelerometers. They are noisy and inaccurate, but the biggest problem is that the measurement includes the acceleration due to gravity, which must be very accurately subtracted from the total acceleration. In turn, that requires knowing the 3D orientation of the sensor extremely accurately.
This blog post goes over the problem and gives some examples: https://web.archive.org/web/20180112063 … n-velocity
Hi,
Thank you for your response. The value dt was set to 100 to represent 100ms. To handle the margin of error, I’m taking five readings at a time, and averaging them. I noticed even with that in place, the readings came out to 0.1 or -0.1 when still, on a flat surface, so I implemented the code```
if (xAvg > -0.02 && xAvg < 0.02) xAvg = 0.0;
Thank you.
In standard units, 100 milliseconds would be represented by 0.1 (as a floating point constant) and 1 “g” from the accelerometer is 9.8 m/s/s. If you use those units, velocity would be m/s and distance would be m.
However, since you are printing intermediate results in the loop and printing takes a variable amount of time, the integration interval is not 100 milliseconds. For accurate integration, the integration interval must be measured, using the built in millis() or micros() functions.
the readings came out to 0.1 or -0.1 when still, on a flat surface
Then you need to calibrate the accelerometer to remove the offsets, or the surface is not flat and you are measuring some component of gravity along the horizontal axes. In either case, this if statement will cause the integrated values to be wrong:
if (xAvg > -0.02 && xAvg < 0.02) xAvg = 0.0;
The gist of the blog article I linked above is that it is not possible to accurately subtract out the acceleration due to gravity, if the 3D orientation of the sensor is not accurately known.
Okay, thank you for your help.
Hi,
I have two follow up questions:
-
How would one determine the 3D orientation of the sensor?
-
Are there any alternative sensors that could calculate displacement (in all three axis, down to the millimeter)?
I have a follow up question in regard to this accelerometer. The library example takes inputs every 20 ms. Is it feasible to take inputs at a smaller interval?