欧拉角是按照既定的顺序,如依次绕z,y,x分别旋转一个固定角度,使用roll,yaw ,pitch分别表示物体绕,x,y,z的旋转角度,可以完成一个坐标系转换成另一个坐标系。
但是在安卓中,这里的角度定义有所不同,原文如下:
Note: This definition is different from yaw, pitch and roll used in aviation where the X axis is along the long side of the plane (tail to nose).
也就是说,X轴与航空系统所定义的不同。安卓里的X轴是短边。
具体如下图:
注: 图中旋转方向只是示意方向,不是指定的正方向!!!
当手机坐标系与地球坐标系重合时,三个角度都为0。
- Azimuth:绕z轴旋转,磁北与y轴的夹角,顺时针增大,0到359度。
- Pitch:绕x轴旋转的角度,即手机上下旋转,y轴往z轴方向为正。-180到180度。
- Roll:绕y轴旋转的角度, 即手机的左右旋转,顺时针为正,-90到90度。
看一下getgetOrientation()方法,求出手机坐标系相对于世界坐标系三个轴的旋转角。
public static float[] getOrientation(float[] R, float[] values) {
/*
* 4x4 (length=16) case:
* / R[ 0] R[ 1] R[ 2] 0 \
* | R[ 4] R[ 5] R[ 6] 0 |
* | R[ 8] R[ 9] R[10] 0 |
* \ 0 0 0 1 /
*
* 3x3 (length=9) case://上篇文章讲到的旋转矩阵
* / R[ 0] R[ 1] R[ 2] \
* | R[ 3] R[ 4] R[ 5] |
* \ R[ 6] R[ 7] R[ 8] /
*
*/
if (R.length == 9) {
values[0] = (float) Math.atan2(R[1], R[4]);//azimuth
values[1] = (float) Math.asin(-R[7]);//pitch
values[2] = (float) Math.atan2(-R[6], R[8]);//roll
} else {
values[0] = (float) Math.atan2(R[1], R[5]);
values[1] = (float) Math.asin(-R[9]);
values[2] = (float) Math.atan2(-R[8], R[10]);
}
return values;
}
这里三个角的计算不大好理解,我画几个示意图大致讲一下我的看法。
还望大家一起讨论。
首先复习一下上一节R矩阵的内容:
R[0] = Hx; R[1] = Hy; R[2] = Hz;//【地球坐标系】X方向,指东
R[3] = Mx; R[4] = My; R[5] = Mz;//【地球坐标系】Y方向,指北
R[6] = Ax; R[7] = Ay; R[8] = Az;//【地球坐标系】Z反方向,向下
首先看azimuth,代码如下:
values[0] = (float) Math.atan2(R[1], R[4]);
也就是arctan2(Hy,My)。 Hy是【地球坐标系】指向东的单位向量在【手机坐标系】Y轴上的分量。
同样地,My是【地球坐标系】指向北的单位向量在【手机坐标系】Y轴上的分量。
azimuth是绕z轴旋转,磁北与y轴的夹角,顺时针增大,0到359度。这里用了atan2函数,因为atan只可以表示
−90o到90o
−
90
o
到
90
o
,atan2可以表示
−180o到180o
−
180
o
到
180
o
。具体详细的区别可以看这里。
示意图如下:
pitch的代码如下:
values[1] = (float) Math.asin(-R[7]);
也就是arcsin(-Ay).Ay是【地球坐标系】指向下(重力)的单位向量在【手机坐标系】Y轴上的分量。示意图如下:
roll的代码如下:
values[2] = (float) Math.atan2(-R[6], R[8]);
也就是arctan2(-Ax,Az).Ax【地球坐标系】指向下(重力)的单位向量在【手机坐标系】x轴上的分量。Az是【地球坐标系】指向下(重力)的单位向量在【手机坐标系】z轴上z的分量。
示意图如下:
这里需要指出的是,这个图的俯视方向是沿着y轴的正方向,所以本来是顺时针为正,这里是逆时针为负,所以也要加负号。