Reputation: 1329
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?
Upvotes: 14
Views: 33400
Reputation: 21
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.
Upvotes: 2
Reputation: 40391
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.
Upvotes: 9
Reputation: 9668
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!
Upvotes: 5
Reputation: 21
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.
Upvotes: 2
Reputation: 13458
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.
Upvotes: 2
Reputation: 94804
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.
Upvotes: 8
Reputation: 10584
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.
Upvotes: -2
Reputation: 128
v = Integral(a) ?
Generally though, I'd think the inaccuracies in the accelerometers would make this quite tough
Upvotes: 1