14

Using only the phone's (Android) built in accelerometer, how would I go about finding its velocity?

I have been tinkering with the maths of this but whatever function I come up with tends to lead to exponential growth of the velocity. I am working from the assumption that on startup of the App, the phone is at a standstill. This should definitely make finding the velocity (at least roughly) possible.

I have a decent background in physics and math too, so I shouldn't have any difficulty with any concepts here.

How should I do it?

duffymo
  • 305,152
  • 44
  • 369
  • 561
Mark D
  • 1,309
  • 4
  • 19
  • 38
  • @Ignacio What? Constant acceleration means velocity increases linearly. – Imran May 22 '11 at 02:40
  • Have you got any working solution, can you point me to that or share the code. – VenomVendor Mar 17 '13 at 15:44
  • Hi, did you ever consider closing this question? – Mr. Developerdude May 09 '16 at 19:28
  • 2
    Your phone uses sensors half the size of a pea that cost something like $2 and were made by etching tiny pieces of metal into the shapes of crude springs and weights. It's sufficient to know which way you're holding the phone, and whether it's being shaken. It will never make a decent inertial sensor package. Trust me, errors accumulate so fast that this is a hopeless problem to solve. (Source: I was in charge of the embedded firmware to do this on the Amazon Fire Phone when I worked at Amazon.) – Edward Falk Jun 14 '16 at 15:19
  • 2
    I just found this superb video explaining why this is hard: https://www.youtube.com/watch?v=C7JQ7Rpwn2k#t=23m20s – Edward Falk Jun 14 '16 at 15:37

8 Answers8

9

That will really depend on what the acceleration is and for how long. A mild, long acceleration could be measurable, but any sudden increase in acceleration, followed by a constant velocity, will make your measurements quite difficult and prone to error.

Assuming constant acceleration, the formula is extremely simple: a = (V1-V0)/t . So, knowing the time and the acceleration, and assuming V0 = 0, then V1 = a*t

In a more real world, you probably won't have a constant acceleration, so you should calculate Delta V for each measurement, and adding all those changes in velocity to get the final velocity. Always consider that you won't have a continuous acceleration data, so this is the most feasible way (i.e, real data vs integral math theory).

In any way, even in the best scenario, you will end up with a very high error margin, so I do not recommend this approach for any app that truly depends on real velocities.

Anurag Kalia
  • 4,668
  • 4
  • 21
  • 28
Aleadam
  • 40,203
  • 9
  • 86
  • 108
8

First, you have to remove the acceleration due to gravity from the accelerometer data. Then it's just a matter of integrating the acceleration to get the velocity. Don't forget that acceleration and velocity are properly vectors, not scalars, and that you will also have to track rotation of the phone in space to properly determine the orientation of the acceleration vector with respect to the calculated velocity vector.

Anomie
  • 92,546
  • 13
  • 126
  • 145
  • can you explain from coding perspective or point to a link where i can get more details about this. – VenomVendor Mar 17 '13 at 15:43
  • 5
    The TYPE_LINEAR_ACCELERATION sensor will give you acceleration with gravity filtered out, so that's nice. The TYPE_ROTATION_VECTOR will give you device orientation as a quaternion, which can easily be converted to a 3x3 rotation matrix. At every time slice, use the rotation matrix to convert the acceleration to a vector in 3-space. Integrate this over time to get acceleration (another vector) and integrate *that* to get position relative to the start position. (This all assumes initial velocity was zero.) Then go to the pub and have a pint because it's all hopeless with cheap sensors. – Edward Falk Jun 14 '16 at 15:13
5

There is nothing else to do but agree with the reasonable arguments put forward in all the great answers above, however if you are the pragmatic type like me, I need to come up with a solution that works somehow.

I suffered a similar problem to yours and I decided to make my own solution after not finding any on-line. I only needed a simple "tilt" input for controlling a game so this solution will probably NOT work for more complex needs, however I decided to share it in case others where looking for something similar.

NOTE: I have pasted my entire code here, and it is free to use for any purpose.

Basically what I do in my code is to look for accelerometer sensor. If not found, tilt feedback will be disabled. If accelerometer sensor is present, I look for magnetic field sensor, and if it is present, I get my tilt angle the recommended way by combining accelerometer and magnetic field data.

public TiltSensor(Context c) {
    man = (SensorManager) c.getSystemService(Context.SENSOR_SERVICE);
    mag_sensor = man.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
    acc_sensor = man.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    has_mag = man.registerListener(this, mag_sensor, delay);
    has_acc = man.registerListener(this, acc_sensor, delay);
    if (has_acc) {
        tiltAvailble = true;
        if (has_mag) {
            Log.d("TiltCalc", "Using accelerometer + compass.");
        }
        else {
            Log.d("TiltCalc", "Using only accelerometer.");
        }
    }
    else {
        tiltAvailble = false;
        Log.d("TiltCalc", "No acceptable hardware found, tilt not available.");
        //No use in having listeners registered
        pause();
    }
}

If however only the accelerometer sensor was present, I fall back to accumulating the acceleration, that is continuously damped (multiplied by 0.99) to remove any drift. For my simple tilt needs this works great.

@Override
public void onSensorChanged(SensorEvent e) {
    final float[] vals = e.values;
    final int type = e.sensor.getType();
    switch (type) {
        case (Sensor.TYPE_ACCELEROMETER): {
            needsRecalc = true;
            if (!has_mag) {
                System.arraycopy(accelerometer, 0, old_acc, 0, 3);
            }
            System.arraycopy(vals, 0, accelerometer, 0, 3);
            if (!has_mag) {
                for (int i = 0; i < 3; i++) {
                    //Accumulate changes
                    final float sensitivity = 0.08f;
                    dampened_acc[i] += (accelerometer[i] - old_acc[i]) * sensitivity;
                    //Even out drift over time
                    dampened_acc[i] *= 0.99;
                }
            }
        }
            break;
        case (Sensor.TYPE_MAGNETIC_FIELD): {
            needsRecalc = true;
            System.arraycopy(vals, 0, magnetic_field, 0, 3);
        }
            break;
    }
}

In conclusion I will just repeat that this is probably not "correct" in any way, it simply works as a simple input to a game. To use this code I simply do something like the following (yes magic constants are bad mkay):

Ship ship = mShipLayer.getShip();
mTiltSensor.getTilt(vals);
float deltaY = -vals[1] * 2;//1 is the index of the axis we are after
float offset = ((deltaY - (deltaY / 1.5f)));
if (null != ship) {
    ship.setOffset(offset);
}

Enjoi!

Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95
2

Gravity is going to destroy all of your measurements. The phone, at standstill, is experiencing a high constant upward (yes, UP) acceleration. An accelerometer can't distinguish between acceleration and gravity (technically, they are the same), so it would get to extremely high velocities after a few seconds. If you never tilt your accelerometer even slightly, then you can simply subtract the constant gravitional pull from the z-axis (or whichever axis is pointing up/down), but thats quite unlikely.

Basically, you have to use a complicated system of a gyroscope/magnetometor and an accelerometer to calculate the exact direction of gravity and then subtract the acceleration.

2

Integrating acceleration to get velocity is an unstable problem and your error will diverge after a couple of seconds or so. Phone accelerometers are also not very accurate, which doesn't help, and some of them don't allow you to distinguish between tilt and translation easily, in which case you're really in trouble.

Imran
  • 12,950
  • 8
  • 64
  • 79
2

The accelerometers in a phone are pretty much useless for such a task. You need highly accurate accelerometers with very low drift - something which is way beyond what you will find in a phone. At best you might get useful results for a few seconds, or if very lucky for a minute or two after which the results become meaningless.

Also, you need to have a three axis gyroscope which you would use to integrate the velocity in the right direction. Some phones have gyros, but they are even poorer than the accelerometers as far as drift and accuracy are concerned.

One possibly useful application though would be to use the accelerometers in conjunction with gyros or the magnetic compass to fill in for missing data from the GPS. Each time the GPS gives a good fix one would reset the initial conditions of position, speed and orientation and the accelerometers would provide the data until the next valid GPS fix.

Lister
  • 21
  • 1
  • Let's say that I want to get tilt information for controlling a game. In that scenario I will be able to make many assumptions. For example, I can assume the user is holding the device in a certain way. Would it not be possible then to smooth the data in a way that sudden changes would stand out and become useful as input to the game? – Mr. Developerdude Apr 06 '13 at 23:27
1

v = Integral(a) ?

Generally though, I'd think the inaccuracies in the accelerometers would make this quite tough

Andreas
  • 128
  • 1
  • 12
-2

If the phone is at standstil, you have ZERO acceleration, so your speed is 0. Probably you should find location data from GPS and get the associated time samples and compute velocity distance over time.

yogsma
  • 10,142
  • 31
  • 97
  • 154
  • Yes, the speed is 0 "on the startup of the App". I am calibrating it from this point. – Mark D May 22 '11 at 02:07
  • "Standing still" should actually be easy to detect. If the input from the accelerometer (use TYPE_LINEAR_ACCELERATION) is very constant, the phone is probably not being handled. – Edward Falk Jun 14 '16 at 15:24