Sensormanager is a class in Android that has a function getRotationMatrix
that calculates the rotation matrix and then getOrientation
obtains the direction of the device (heading angle, pitch angle, roll angle). function getRotationMatrix的源码如下所示,源码中虽然对该函数整体进行了解释,但是对代码中各个参数的计算没有说明,如为什么加速度的数值要和磁力计的数值做差乘。在网上各种搜索后,找到一段老外对这个问题的英文解释,很好的回答了上述问题。大意翻译(包括自己的理解)如下:加速度数值和磁力计数值均是向量,手机水平放置时,加速度读数实际上就是重力向量,方向是竖直朝下的;磁力计表示本地的磁场,不考虑环境影响及磁偏角的话,认为磁场方向是水平南北朝向的。因此,代码中首先对加速度和磁力计数据做了一个差乘,得出一个水平东西方向的向量(差乘的定义)。经过这个运算,本来只有一个平面的向量,变成了三个三维立体平面的向量,从而可以用来计算设备的方向。源码中后面又做了一次差乘,是用计算出的水平东西方向的向量和重力向量做的差乘,这次运算重新得出一个水平南北方向的向量,最后旋转矩阵中用这三个向量(两个计算出的水平向量、一个重力向量)构成。
1, Sensormanager.getrotationmatrix
Public Static BooleanGetrotationmatrix (float[] R,float[] I,float[] Gravity,float[] geomagnetic) { //Todo:move this to native code for efficiency floatAx = gravity[0]; floatAy = gravity[1]; floatAz = gravity[2]; Final floatEx = geomagnetic[0]; Final floatEy = geomagnetic[1]; Final floatEz = geomagnetic[2]; floatHx = ey*az-ez*Ay; floatHy = ez*ax-ex*Az; floatHz = ex*ay-ey*Ax; Final floatNORMH = (float) math.sqrt (hx*hx + hy*hy + hz*Hz); if(NORMH < 0.1f) { //device is close to free fall (or in space?), or close to//Magnetic North Pole. Typical values are >. return false; } Final floatINVH = 1.0f/NORMH; Hx*=INVH; Hy*=INVH; Hz*=INVH; Final floatInva = 1.0f/(float) math.sqrt (Ax*ax + Ay*ay + az*Az); Ax*=Inva; Ay*=Inva; Az*=Inva; Final floatMx = ay*hz-az*Hy; Final floatMy = az*hx-ax*Hz; Final floatMz = ax*hy-ay*Hx; if(R! =NULL) { if(R.length = = 9) {r[0] = Hx; R[1] = Hy; R[2] =Hz; r[3] = Mx; R[4] = My; R[5] =Mz; r[6] = Ax; R[7] = Ay; R[8] =Az; } Else if(R.length = = 16) {r[0] = Hx; R[1] = Hy; R[2] = Hz; R[3] = 0; r[4] = Mx; R[5] = My; R[6] = Mz; R[7] = 0; r[8] = Ax; R[9] = Ay; R[10] = Az; R[11] = 0; r[12] = 0; R[13] = 0; R[14] = 0; R[15] = 1; } } if(I! =NULL) { //compute the inclination matrix by projecting the geomagnetic//vector onto the Z (Gravity) and X (horizontal component//of geomagnetic vector) axes. Final floatINVe = 1.0f/(float) math.sqrt (Ex*ex + Ey*ey + ez*Ez); Final floatc = (ex*mx + ey*my + ez*mz) *INVe; Final floats = (Ex*ax + ey*ay + ez*az) *INVe; if(I.length = = 9) {i[0] = 1; I[1] = 0; I[2] = 0; i[3] = 0; I[4] = c; I[5] =s; i[6] = 0; I[7] =-s; I[8] =C; } Else if(I.length = = 16) {i[0] = 1; I[1] = 0; I[2] = 0; i[4] = 0; I[5] = c; I[6] =s; i[8] = 0; I[9] =-s; i[10]=C; i[3] = i[7] = i[11] = i[12] = i[13] = i[14] = 0; i[15] = 1; } } return true; }
2. English original explanation
If I Understand your problem correctly you want your phone to know its 3D orientation. You need at least, vectors to do. The XYZ accelerometer produces a gravity vector that goes straight down. An XYZ magnetometer can provide a second vector that's horizontally towards magnetic north and vertically downward in the Northen Hemisphere. The cross-product of these and vectors would be horizontal the magnetic east-west directions and the cross-product between The east-west vector and the gravity vector would be horizontal in the magnetic north-south directions. Formulas exist for converting magnetic to geographical North although I don ' t know them offhand. An XYZ accelerometer by itself produces just the gravity vector, which could allow you to use your cell phone as an electr Onic bi-directional level (lateral and axial to the orientation of the accelerometer).
Read more:https://www.physicsforums.com
Explanation of Sensormanager.getrotationmatrix function in Android