Get Euler Yaw angle of an Android Device

2020-07-23 09:08发布

问题:

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?

回答1:

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 and TYPE_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])

  • Using 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 the azymuth 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 subsequent azymuths 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 initial azymuth 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).