21

I am developing an application for Android where I need to remove gravity from accelerometer readings. I have read multiple discussions on this problem, I have also found an algorithm here, but I didn't really understand it.

I want to filter gravity from each axis, not from the total acceleration.

Could you please help me out? My code should be something like:

public void onSensorChanged(SensorEvent sensorEvent) {
    float vals[] = sensorEvent.values;
    float accelerationX = filterGravity(vals[0]);
    float accelerationY = filterGravity(vals[1]);
    float accelerationZ = filterGravity(vals[2]);
}

What code should I place in the filterGravity() method?

Gabriel
  • 2,054
  • 4
  • 26
  • 34

4 Answers4

26

For a basic solution you would need a low pass filter other approaches like a Kalman filter are pretty tough regarding the maths behind. A simple example for Android is one click away from your link at http://developer.android.com/reference/android/hardware/SensorEvent.html#values.

Simply spoken a low pass filter builds a weighted average from all your history values. If you have for example a filtering factor of 0.1 it means that 10% of your current value is added to the previous mean value: newMeanValue = 10% of currentValue + 90% of oldMeanValue. That means even if there is an abrupt peak it will only push your mean value slowly because of the 10%.

Kay
  • 12,918
  • 4
  • 55
  • 77
  • 1
    @Kay Sorry, I wanted to UPvote your answer. Please add a dot to your last sentence (or do some editing) so my downvote becomes an upvote. Sorry... – Ali Sep 28 '11 at 18:41
  • @Ali: dot added, no problem :-) – Kay Sep 28 '11 at 20:34
  • @Kay The site should support such an undo feature. Perhaps I will bring it up on metastackoverflow. – Ali Sep 30 '11 at 13:23
  • @Ali http://meta.stackexchange.com/questions/19940/undo-a-up-down-vote-after-a-comment-is-left It has status-declined but I just upvoted it. Maybe it will be realised one day. – Kay Sep 30 '11 at 14:02
14

Linear acceleration is what you need. Check Sensor.TYPE_LINEAR_ACCELERATION here.

Ali
  • 56,466
  • 29
  • 168
  • 265
  • Thank you very much. This would accomplish my problem. However, this is supported only since API level 9. Is there a way to implement this in earlier API versions? – Gabriel Aug 02 '11 at 16:08
  • @Gabriel I am afraid not. There is some heavy math behind this, fusing the accelerometer, gyro and compass data. Here is an interesting video on sensor fusion: http://www.youtube.com/watch?v=C7JQ7Rpwn2k – Ali Aug 02 '11 at 17:04
10

If you do not have a phone with TYPE_LINEAR_ACCELERATION, you are stuck with TYPE_ACCELERATION, which cannot separate gravity (tilt) from linear acceleration.

One option is to apply the low-pass filter. Another approach is using sensor fusion if the gyroscope is available. Both approaches have their advantages and disadvantages.

I have lots of working examples in the open source project Acceleration Explorer.

Kaleb
  • 1,855
  • 1
  • 18
  • 24
  • Hi Kaleb, i'm currently working on java application similar to your FusedLinearAcceleration android app with difference, that I cannot use android virtual sensors to compute gravity. I ported some methods from sensorManager, but I can't find algorithm to get gravity vector. I found that this can be achieved using quaternions, and changed/wrote something like this: https://gist.github.com/Bresiu/c0a69552881b8df34a2e. But it gives bad results - gravity is compensate only from z axis (rest code is based on your application). Do you have some hints, what can be wrong? My code: http://goo.gl/5jmlvY – Bresiu Jul 02 '14 at 14:44
  • @Bresiu: The only virtual sensor that FusedLinearAcceleration uses is Sensor.TYPE_GRAVITY and you can change it to Sensor.TYPE_ACCELERATION. However, if you have a device with a gyroscope, Sensor.TYPE_GRAVITY should be implemented. You can look at this blog article (http://www.kircherelectronics.com/blog/index.php/11-android/sensors/17-gyroscope-linear-acceleration), which elaborates on the code you posted (and my code). It may help as it covers the gravity vector. Keep in mind that if you are trying to measure anything during dynamic acceleration (like a car), it will need modification. – Kaleb Jul 02 '14 at 17:02
  • I have a device with gyroscope, accelerometer and magnetometer, so I'm looking for some sensor fusion for best results. I saw your other apps, and FusedLinear seems most accurate. I will keep searching... – Bresiu Jul 03 '14 at 12:05
  • FusedLinearAcceleration is about as good as it gets. It is very difficult to differentiate tilt/static acceleration from dynamic/linear acceleration. Since the accelerometer compensates for the gyroscopes drift via some sort of fusion (usually a complementary filter), dynamic/linear acceleration can cause erroneous drift compensations in the gyroscope. Feedback loops are a problem with all sensor fusions. Sensor.TYPE_LINEAR_ACCELERATION has this problem, too. It is useless for measuring dynamic/linear acceleration. – Kaleb Jul 03 '14 at 15:43
-2

Not too sure what you are trying to acomplish but if you are look for the magnitude (which will give a result between 0 and 1) then all you do is divide the result by 10

public void onSensorChanged(SensorEvent sensorEvent) {
float vals[] = sensorEvent.values;
float accelerationX = (vals[0]/10);
float accelerationY = (vals[1]/10);
float accelerationZ = (vals[2]/10);

}

In a game environment when the sensor is at full tilt your object will be at its maximum speed

Chris
  • 1,766
  • 1
  • 21
  • 36