18

Can anyone help on removing the g factor from accelerometer readings?

I am using SensorEventListener with onSensorChanged() method for getting Sensor.TYPE_ACCELEROMETER data. I need only pure acceleration values in all directions. So at any state if the device is stable (or in constant speed), it should give (0.0,0.0,0.0) roughly.

Currently, depending on its pitch and roll, it gives me variable output depending on the g forces acting on each axis.

I hope there is some formula to remove this, as I also get orientation values (pitch and roll) from Sensor.TYPE_ORIENTATION listener. I have used some but it didn't work.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Pritam
  • 2,367
  • 5
  • 34
  • 50

7 Answers7

12

You can use a low-pass filter.

Do this for each of your sensor values:

g = 0.9 * g + 0.1 * v

Where v is your current sensor value and g is a global variable initially set to zero. Mind that you'll need as many g variables as you have axes.

With v = v - g you can eliminate the gravity factor from your sensor value.

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
  • 2
    Note that this can be rewritten as `g = (1-a)*g + a*v`, where `a` is a variable between 0 and 1 that controls the cutoff of the filter. – Drew Noakes Jun 17 '14 at 20:56
  • 11
    I don't understand this. How does adding a low-pass filter *remove* a constant bias? Wouldn't you want a high-pass? – matth Aug 11 '15 at 04:28
  • 6
    This computation does not work, because it assumes that the orientation of the device does not change over time, which is extremely rare. – fishinear Jan 30 '16 at 13:36
  • It work as capacitor (which is a part of RC filter in radioelectronics) - major part (0.9g) clowly changes (charge of capacitor), but impact of oscillating part (0.1) is considerable only when of the same sign and not zero many times – Alex Shutov Jan 12 '17 at 11:44
  • Note that the filter will respond quickly or slowly depending on your sampling rate (i.e. the SENSOR_DELAY_XXX setting) – Sarsaparilla Apr 17 '18 at 04:27
12

Use Sensor.TYPE_LINEAR_ACCELERATION instead of Sensor.TYPE_ACCELEROMETER

Rathore
  • 1,926
  • 3
  • 19
  • 29
8

Take a look of the following link.

http://developer.android.com/reference/android/hardware/SensorEvent.html

Johnny
  • 105
  • 1
  • 2
  • Actually the computations in that Android documentation are incorrect, because they assume that the orientation of the device does not change. And that, of course, is extremely rare in practice. – fishinear Jan 30 '16 at 13:35
6

Just subtract out g (~9.8m/s^2) times the z direction of the rotation matrix. Or to be more explicit about it, let

a = your accelerometer reading,
R = your rotation matrix (as a 9-long vector).

Then what you want is

(a[0]-g*R[6], a[1]-g*R[7], a[2]-g*R[8]).
  • 1
    This is correct, but computing the rotation matrix is a bit hard for a new comer. Search for Direction Cosine Matrix if you want more details. – xryl669 May 25 '16 at 12:38
  • 1
    Do you subtract it from the Z only? What about X and Y? – rclai Aug 26 '16 at 13:36
  • 3
    @rclai as long as it is facing with the Z direction down at all time, just subtracting it from Z should be enough. Once the device tilts, the data will be off, sinec gravity isn't pulling for Z only. – Mathieu Brouwers Nov 23 '16 at 12:42
  • @Theodore Sternberg Could you please provide a source of explanation as to what us the rotation matrix you are referring to? I have searched and saw that there is a mathimatical concept but fail to see how to implement it in a physical aspect. – Ofek Glick Jun 22 '22 at 18:12
4

Differentiating with respect to time a function of time rids you of the constants.

So by taking the derivative of the accelerometer's signal you'll get the "Jerk", which you can then re-integrate in order to get the non-constant part of the acceleration you're looking for.

In Layman's terms, take a sample from the accelerometer every 1 second, and subtract it from the previous sample. If the answer is (very close to) zero, you're not accelerating relatively to earth. If the result is non-zero, integrate it (in this case, multiply by one second), you have your acceleration.

Two things, though : -Look out for noise in the signal, round off your input. -Don't expect hyper-accurate results from on-chip accelerometers. You can use them to detect shaking, changes in orientation, but not really for knowing how many G's you're experiencing while making sharp turns in your car.

cxnull
  • 184
  • 1
  • 6
3

One way (for devices only with accelerometer) is to remove gravity vector from accelerometer data by subtracting the values that would come in static case for same orientation. But as orientation is again calculated by taking acceleration readings and not independently, its not very accurate.

Gyroscope may help in this case. But few androids still have a true gyroscope. And using its raw readings is not so simple.

Pritam
  • 2,367
  • 5
  • 34
  • 50
1

you need to assume two coordinate systems: 1- fixed global system. 2- moving coordinate system in which the origin moves & rotates as sensor does. in global system, g is always parallel to z axis but in moving system it is not. so all you have to do is to compute 3*3 rotation matrix from orientation angles or yaw, pitch & roll. (you can find formulas everywhere). then multiply this rotation matrix by 3*1 acceleration vector measured by sensor. this will transform coordinates and declare the values in fixed global system. the only thing afterward is to simply subtract g from z value.