How to properly calculate linear acceleration using AcceleroMeter in Android
Categories:
Calculating Linear Acceleration with Android Accelerometer

Learn how to accurately derive linear acceleration from raw accelerometer data on Android devices, accounting for gravity and sensor noise.
Android devices come equipped with various sensors, including accelerometers, which measure the acceleration applied to the device. While raw accelerometer data provides the total acceleration (including gravity), many applications require linear acceleration – the acceleration due to motion, excluding the constant pull of gravity. This article will guide you through the process of properly calculating linear acceleration using the Android SensorManager
and filtering out gravitational forces.
Understanding Accelerometer Data
The TYPE_ACCELEROMETER
sensor in Android reports the sum of the acceleration of the device (m/s²) along the X, Y, and Z axes, including the force of gravity. Gravity itself is a form of acceleration, typically around 9.81 m/s² downwards. When the device is at rest on a flat surface, the accelerometer will report approximately [0, 0, 9.81]
m/s² (assuming Z is upwards) or [0, 0, -9.81]
m/s² (assuming Z is downwards), not [0, 0, 0]
. To get the true linear acceleration, we must subtract the gravitational component from the raw sensor readings.
flowchart TD A[Raw Accelerometer Data] --> B{Apply Low-Pass Filter for Gravity} B --> C[Estimate Gravity Vector] C --> D{Subtract Gravity from Raw Data} D --> E[Linear Acceleration]
Process for deriving linear acceleration from raw accelerometer data.
Implementing a Low-Pass Filter for Gravity
To isolate the gravity component, a common technique is to use a low-pass filter. A low-pass filter allows low-frequency signals (like gravity, which changes slowly) to pass through while attenuating high-frequency signals (like sudden movements). The Android documentation suggests a simple exponential moving average filter for this purpose. We maintain an estimate of the gravity vector and update it with each new accelerometer reading.
public class LinearAccelerationSensor implements SensorEventListener {
private static final float ALPHA = 0.8f; // Constant for the low-pass filter
private float[] gravity = new float[3];
private float[] linearAcceleration = new float[3];
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
// Isolate the force of gravity with the low-pass filter.
gravity[0] = ALPHA * gravity[0] + (1 - ALPHA) * event.values[0];
gravity[1] = ALPHA * gravity[1] + (1 - ALPHA) * event.values[1];
gravity[2] = ALPHA * gravity[2] + (1 - ALPHA) * event.values[2];
// Remove the gravity contribution with the high-pass filter.
linearAcceleration[0] = event.values[0] - gravity[0];
linearAcceleration[1] = event.values[1] - gravity[1];
linearAcceleration[2] = event.values[2] - gravity[2];
// Now 'linearAcceleration' contains the device's acceleration due to motion.
// You can use these values for your application logic.
// Log.d("LinearAccel", String.format("X: %.2f, Y: %.2f, Z: %.2f",
// linearAcceleration[0], linearAcceleration[1], linearAcceleration[2]));
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes.
}
public float[] getLinearAcceleration() {
return linearAcceleration;
}
}
Java code for a SensorEventListener
that calculates linear acceleration.
ALPHA
value in the low-pass filter determines the filter's responsiveness. A higher ALPHA
(closer to 1) means more smoothing and slower response to changes in gravity, while a lower ALPHA
(closer to 0) makes the filter more responsive but less effective at isolating gravity.Registering and Unregistering the Sensor Listener
To use the LinearAccelerationSensor
class, you need to register it with the Android SensorManager
when your activity or service starts and unregister it when it pauses or stops to conserve battery and system resources. This is typically done in the onResume()
and onPause()
lifecycle methods of an Activity
.
public class MainActivity extends AppCompatActivity {
private SensorManager sensorManager;
private Sensor accelerometer;
private LinearAccelerationSensor linearAccelerationSensor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager != null) {
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometer == null) {
// Device does not have an accelerometer
Log.e("Sensor", "Accelerometer not available!");
} else {
linearAccelerationSensor = new LinearAccelerationSensor();
}
}
}
@Override
protected void onResume() {
super.onResume();
if (accelerometer != null) {
sensorManager.registerListener(linearAccelerationSensor, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
}
}
@Override
protected void onPause() {
super.onPause();
if (accelerometer != null) {
sensorManager.unregisterListener(linearAccelerationSensor);
}
}
}
Example MainActivity
demonstrating sensor registration and unregistration.
onPause()
or onStop()
to prevent battery drain. Failing to do so can lead to significant power consumption, especially if your app is running in the background.