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:
- get rotation matrix (
float[16]
so it could be used later byandroid.opengl.Matrix
class) fromSensorManager.getRotationMatrix()
(usingSENSOR.TYPE_GRAVITY
andSENSOR.TYPE_MAGNETIC_FIELD
sensors values as parameters), - use
android.opengl.Matrix.invertM()
on the rotation matrix to invert it (not transpose!), - use
Sensor.TYPE_LINEAR_ACCELERATION
sensor to get linear acceleration vector (in device's coord. sys.), - 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!