I'm trying to get yaw of an android device expressed in euler angles.
To be clear i dont want 'Azimuth' (which is the angle to magnetic north) I want the rotation of the 'z' axis of an android device as shown in this picture.
This (IMHO) should be the axis used in some car games to determine the amount of steering.
It is my understanding I could just use the Accelerometer values (without the magnetic fields) but I'm unable to get the determined value. (probably due to a lack of understanding of how rotation matrixes works).
Can someone point me toward the right direction?
If you want to calculate the rotation about the device z-axis independent of the device position (that is flat or not flat) then you have to keep track of a few things. If the app support both Portrait and Landscape then it is more complicated, I am going to give an answer when the activity is restricted to Portrait only.
So flat here means the pitch is less than 25 or more than 155 degrees and not flat otherwise.
When the device is in transition from flat to not flat and vice versa there probably some inconsistent in the UI.
Register for
TYPE_GRAVITY
andTYPE_MAGNETIC_FIELD
(needed for flat) and do the calculation below.getRotationMatrix
a[0] a[1] a[2]
a[3] a[4] a[5]
a[6] a[7] a[8]
Calculate
pitch = Math.asin(-R[7])
pitch
to determine the flatness of the device (I think you can use less than 45 and more than 135 to determine flatness, you just have to experiment to see if theazymuth
value is correct)if the device is not flat the rotation is Math.atan2(a[6], a[7])
If the device is flat to start with get the initial
azymuth = Math.atan2(R[1], R[4])
and then take the difference with subsequentazymuths
to get the rotation.If the device transition from flat to not flat there should be no problem the rotation is just the rotation for not flat above.
If the device transition from not flat to flat then you need to get the initial
azymuth
. This initialazymuth
can be set to the back camera direction Math.atan2(-a[2], -a[5]), if the device is upright and there is only rotation about the z-axis then this direction should not change. In reallity it will probably change by a few degrees so you will need to take the average.All the math except for Math.atan2(a[6], a[7]) is explained at Android: Algorithms for SensorManager.getRotationMatrix and SensorManager.getOrientation()
So let me give the explanation for finding the rotation when the device is not flat.
As explained in the link above you have to specify the fixed vector and the vector that varies that you want to calculate the angle between them. In this case the vector that varies is a vector lying in the device y-axis and the fixed vector is the projection of the gravity vector into the device xy-plane. In the rotation matrix above the last row is the normalize gravity vector in device coordinate, thus the projection to the device xy-plane is (a[6], a[7]). Now it is simple trigonometry to see that Math.atan2(a[6], a[7]) is the angle between the device y-axis and the gravity projection. (Draw picture if you do not see it).