How to calculate distance based on phone acceleration
Asked Answered
I

2

17

I want to build something like this but using an android phone: http://www.youtube.com/watch?v=WOt9mb5QqRs

I've already built an app that sends sensor information via socket (still looking for a good websocket implementation for android). I intend to use that information to interact with a web app, so for example i would be able to move an image based on the phone movement. The problem is that I tried to calculate distance based on the accelerometer data but the results are really bad. I wonder if anyone could help me with the correct equation, but first of all, is it possible to do this?

Till now I'm using the following equations:

velocity = acceleration * time;

distance = velocity * time + (acceleration * time^2) / 2;

then I translate distance from meters per second to pixels based on monitor screen resolution.

that's calculated with javascript in the browser every time i receive sensor data, which is every ~80ms.

Idioplasm answered 1/12, 2010 at 21:8 Comment(0)
C
27

The basics is simple. In the analog world you use continuous math which is:

velocity = integrate(acceleration)
distance = integrate(velocity)

and in the digital world it is even easier, you use discrete math where integration becomes summation:

velocity = sum(acceleration)
distance = sum(velocity)

Just keep adding up all the values of acceleration you read and you eventually get distance.

The big problem with this is that on planet Earth there is a constant acceleration downwards of approximately 10m/s/s due to gravity. Figuring out which part of your vector is gravity is the hard part.

BTW, gravity is how accelerometers can detect tilt. So however you do it, unless you can calculate the tilt independently of the accelerometers (for example with the help of gyros) your code will mostly be measuring tilt instead of distance.


HA! I just realized from my last statement that a lot of iPhone apps won't work in space :-P


Additional answer:

Based on a "comment" posted by the OP (as an answer either below or above this answer) it looks like I need to provide further explanation. The implementation is really-really simple that people not familiar with the maths will think it must be more complicated than that. The pseudocode is as follows:

// Set distance to zero at start-up:
var distance_X = 0
var velocity_X = 0

function update_acceleration_X (acceleration_X) {
    velocity_X = velocity_X + acceleration_X
    distance_X = distance_X + velocity_X
}

// To use the distance value just read the distance_X variable:
function get_distance_X_and_reset () {
    x = distance_X
    distance_X = 0
    return x
}

Distance is always measured from where the software first starts unless you reset the distance variable to zero. The accelerometer must constantly be read (preferably at the rate the accelerometer itself measures forces) and the values of velocity and distance updated accordingly. When you want to know the distance from the starting point just read the distance variable.

Several things: any amount of tilt, no matter how slight, will add drift. Meaning that there will always be a small amount of constant acceleration in one direction or the other unless the angle of tilt itself is constantly tracked. Even nuclear submarines, equipped with high precision accelerometers and gyros because GPS doesn't work under water, need to periodically surface and sync with GPS to correct this drift.

Second, the accelerometer measures force, not movement. Any kind of force is measured. I mentioned gravity but it also measures bumps caused by friction with a table, your pulse as your heartbeat and breathing cause your hand to shake slightly, anything. The good news is that over the long run all these forces will average out and the formula will still be correct. But in the short run it means your reading is going to be noisy. There are a lot of tricks people have come up with to minimize this noise using things like Weiner and Kalman filters.

Third, as you may have noticed, the accelerometer reading is not constant. I don't simply mean that the values are different each time you read them, that is obvious, but it also changes values in-between readings. Every value we miss affects our accuracy so it is important to read the values as often as possible. Now, the good news is that in the long run all these errors caused by missing values should average out as they are mostly caused by jerky movements or vibrations and our formula is again still correct. But it means again that in the short run this adds noise to our system. If you use a good perdictive filter like a Kalman filter then it should be able to account for this but weaker filters may need some help. One way of doing this is to average out each acceleration reading with the previous reading. Note that it must be the previous "real" reading, not the previous averaged reading.

More accuracy than this goes into the realm of Inertial Measurement Units (IMU) and inertial guidance and a lot of fairly hairy vector and matrix maths. There are open source projects doing this though (less than 10 years ago this stuff was strictly military since, you know, submarines and cruise missiles use them).

These Sparkfun articles have some nice links at the bottom and some reference code:

http://www.sparkfun.com/products/9268

http://www.sparkfun.com/products/8454

Hope all this helps. And if anyone else have links to any article which may help please comment.


Example

Of course if you want real units you need to scale for sample rate. For example accelerating at 9m/s/s for 80ms means your velocity is (9m/s/s * 0.08s) = 0.72m/s. The above pseudocode is simplified assuming you don't care about units. The final values will still represent distance as a number it's just that the number has little relation to any real world unit of measurement. You can simply apply a scaling function at the end calibrated to your pixel valus. Anyway, here's an example with real-world units to clarify what's happening:

given the following acceleration readings:
9m/s/s
3m/s/s
0m/s/s
0m/s/s
0m/s/s
-5m/s/s
-7m/s/s

assuming an 80ms sample rate
we can derive the following velocities:
0.72m/s (what you get from accelerating 9m/s for 80ms)
0.96m/s
0.96m/s
0.96m/s
0.96m/s
0.56m/s
0m/s

from that we can derive the following distances:
57.6mm (what you get from moving at 0.72m/s for 80ms)
134.4mm
211.2mm
288mm
364.8mm
409.6mm

Now, if you take the derived distances and do a reverse calculation as per usual (v = (s2-s1)/t and a = (v2-v1)/t) you should get the acceleration readings back.

Choosy answered 1/12, 2010 at 21:19 Comment(11)
ok now i can comment, it doesn't make any sense, how is that velocity (being initially 0) equals acceleration?? what about time? accelerating 9m/s² indicates that the phone will reach that velociy in one second but i'm measuring the velocity every ~80msIdioplasm
That's just how the physics works. Maybe you've forgotten that velocity is simply the integral of acceleration. When time becomes discrete, integration becomes summation.Choosy
Summing up values which are time and value discrete is not the same as integration. You have to consider the time/interval between the acceleration values.Haunch
@Choosy : you say you are accelerating from 0 to 9m/s2 in 0-80ms. But to calculate the distance you are doing - v=9*0.80, d=v*0.80. v is the final velocity at the 80th ms. And you are calculating distance by multiplying the final velocity to 80 ms.Shellback
@Ashwin: For one interval of reading yes, you'd have to calculate average velocity. But for a large enough number of readings (such as continuously reading an accelerometer) simple summation of acceleration quickly converges to the sum of average velocities. You can try it out yourself with the above data and see what effect it has to the distance calculations.Choosy
@Choosy : shouldn't this be more accurate - #12926959 . Still I am not getting the answer:P. But I hope it is logically correct.Shellback
@Ashwin: I'd strongly suggest trying my method as a test to see if the calculation end up agreeing to real-world length. Then compare it to your code. That is to say, remove the 0.5 form your code and try it again.Choosy
@Choosy : I tried removing the 0.5(I still do not understand teh reason to do it). Still I values are considerably lower than the actual values, even though they have have increased because of removing the 0.5.Shellback
+1 very clearly explained answer, thanks. don't forget when summing values, you should multiply by the time-delta since the last sample i.e. v += a * (t(n) - t(n-1)). also remember to convert the timestamp from nanoseconds to seconds!Ninny
I doubt this simple formula works; at least not on a mobile app. I have an accelerometer based app and integrated the acceleration and never got the right answer. I havent seen any app on App stores which can do this and I assume it wont be this simple.Peptonize
@Peptonize This formula is indeed to simple and naive to work. It basically has too much assumptions that makes it not practical.Ameliaamelie
M
2

Max velocity = time * acceleration.
Average velocity = Max velocity / 2.
Distance travelled = Average velocity * time.


Distance travelled = time * time * acceleration / 2.

Magic answered 1/12, 2010 at 21:23 Comment(2)
this is the correct answer. the above answer is wrong. He says you are accelerating from 0 to 9m/s2 in 0-80ms. But to calculate the distance he is. v=9*0.80, d=v*0.80. v is the final velocity at the 80th ms. And he is calculating distance by multiplying the final velocity to 80ms.Shellback
@Shellback I know this is really old, but he is actually right! Look up Riemann sums. The answer above is wrong because it deals with the case of continuous acceleration and not discretely measured intervals as is the case with the phone. Cheers.Myotome

© 2022 - 2024 — McMap. All rights reserved.