Acceleration from device's coordinate system into absolute coordinate system Acceleration from device's coordinate system into absolute coordinate system android android

Acceleration from device's coordinate system into absolute coordinate system


I finally managed to solve it! So to get acceleration vector in Earth's coordinate system you need to:

  1. get rotation matrix (float[16] so it could be used later by android.opengl.Matrix class) from SensorManager.getRotationMatrix() (using SENSOR.TYPE_GRAVITY and SENSOR.TYPE_MAGNETIC_FIELD sensors values as parameters),
  2. use android.opengl.Matrix.invertM() on the rotation matrix to invert it (not transpose!),
  3. use Sensor.TYPE_LINEAR_ACCELERATION sensor to get linear acceleration vector (in device's coord. sys.),
  4. use android.opengl.Matrix.multiplyMV() to multiply the rotation matrix by linear acceleration vector.

And there you have it! I hope I will save some precious time for others.

Thanks for Edward Falk and Ali for hints!!


Based on @alex's answer, here is the code snippet:

private float[] gravityValues = null;private float[] magneticValues = null; @Override    public void onSensorChanged(SensorEvent event) {        if ((gravityValues != null) && (magneticValues != null)             && (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)) {            float[] deviceRelativeAcceleration = new float[4];            deviceRelativeAcceleration[0] = event.values[0];            deviceRelativeAcceleration[1] = event.values[1];            deviceRelativeAcceleration[2] = event.values[2];            deviceRelativeAcceleration[3] = 0;            // Change the device relative acceleration values to earth relative values            // X axis -> East            // Y axis -> North Pole            // Z axis -> Sky            float[] R = new float[16], I = new float[16], earthAcc = new float[16];            SensorManager.getRotationMatrix(R, I, gravityValues, magneticValues);            float[] inv = new float[16];            android.opengl.Matrix.invertM(inv, 0, R, 0);            android.opengl.Matrix.multiplyMV(earthAcc, 0, inv, 0, deviceRelativeAcceleration, 0);           Log.d("Acceleration", "Values: (" + earthAcc[0] + ", " + earthAcc[1] + ", " + earthAcc[2] + ")");                        } else if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {            gravityValues = event.values;        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {            magneticValues = event.values;        }    }


According to the documentation you get the linear acceleration in the phone's coordinate system.

You can transform any vector from the phone's coordinate system to the Earth's coordinate system by multiplying it with the rotation matrix. You can get the rotation matrix from getRotationMatrix().

(Perhaps there already is a function doing this multiplication for you but I don't do Android programming and I am not familiar with its API.)

A nice tutorial on the rotation matrix is the Direction Cosine Matrix IMU: Theory manuscript. Good luck!