Android 中的 getAngleChange 这个方法,为什么有时候可以获得正确的角度变化,有时候得到的结果却是完全错误的呢?
这是 SensorManager.getAngleChange 的源码:
/** Helper function to compute the angle change between two rotation matrices.
* Given a current rotation matrix (R) and a previous rotation matrix
* (prevR) computes the intrinsic rotation around the z, x, and y axes which
* transforms prevR to R.
* outputs a 3 element vector containing the z, x, and y angle
* change at indexes 0, 1, and 2 respectively.
* <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix
* depending on the length of the passed array:
* <p>If the array length is 9, then the array elements represent this matrix
* <pre>
* / R[ 0] R[ 1] R[ 2] \
* | R[ 3] R[ 4] R[ 5] |
* \ R[ 6] R[ 7] R[ 8] /
*</pre>
* <p>If the array length is 16, then the array elements represent this matrix
* <pre>
* / R[ 0] R[ 1] R[ 2] R[ 3] \
* | R[ 4] R[ 5] R[ 6] R[ 7] |
* | R[ 8] R[ 9] R[10] R[11] |
* \ R[12] R[13] R[14] R[15] /
*</pre>
*
* See {@link #getOrientation} for more detailed definition of the output.
*
* @param R current rotation matrix
* @param prevR previous rotation matrix
* @param angleChange an an array of floats (z, x, and y) in which the angle change
* (in radians) is stored
*/
public static float[] getAngleChange(float[] R, float[] prevR) {
float[] angleChange = new float[3];
float rd1 = 0, rd4 = 0, rd6 = 0, rd7 = 0, rd8 = 0;
float ri0 = 0, ri1 = 0, ri2 = 0, ri3 = 0, ri4 = 0, ri5 = 0, ri6 = 0, ri7 = 0, ri8 = 0;
float pri0 = 0, pri1 = 0, pri2 = 0, pri3 = 0, pri4 = 0, pri5 = 0, pri6 = 0, pri7 = 0, pri8 = 0;
if (R.length == 9) {
ri0 = R[0];
ri1 = R[1];
ri2 = R[2];
ri3 = R[3];
ri4 = R[4];
ri5 = R[5];
ri6 = R[6];
ri7 = R[7];
ri8 = R[8];
} else if (R.length == 16) {
ri0 = R[0];
ri1 = R[1];
ri2 = R[2];
ri3 = R[4];
ri4 = R[5];
ri5 = R[6];
ri6 = R[8];
ri7 = R[9];
ri8 = R[10];
}
if (prevR.length == 9) {
pri0 = prevR[0];
pri1 = prevR[1];
pri2 = prevR[2];
pri3 = prevR[3];
pri4 = prevR[4];
pri5 = prevR[5];
pri6 = prevR[6];
pri7 = prevR[7];
pri8 = prevR[8];
} else if (prevR.length == 16) {
pri0 = prevR[0];
pri1 = prevR[1];
pri2 = prevR[2];
pri3 = prevR[4];
pri4 = prevR[5];
pri5 = prevR[6];
pri6 = prevR[8];
pri7 = prevR[9];
pri8 = prevR[10];
}
// calculate the parts of the rotation difference matrix we need
// rd[i][j] = pri[0][i] * ri[0][j] + pri[1][i] * ri[1][j] + pri[2][i] * ri[2][j];
rd1 = pri0 * ri1 + pri3 * ri4 + pri6 * ri7; //rd[0][1]
rd4 = pri1 * ri1 + pri4 * ri4 + pri7 * ri7; //rd[1][2]
rd6 = pri2 * ri0 + pri5 * ri3 + pri8 * ri6; //rd[2][0]
rd7 = pri2 * ri1 + pri5 * ri4 + pri8 * ri7; //rd[2][3]
rd8 = pri2 * ri2 + pri5 * ri5 + pri8 * ri8; //rd[2][4]
angleChange[0] = (float) Math.atan2(rd1, rd4);
angleChange[1] = (float) Math.asin(-rd7);
angleChange[2] = (float) Math.atan2(-rd6, rd8);
return angleChange;
}
文档说的比较明白,就是输入两个旋转矩阵 R,然后可以得到这两个 R 所代表的角度的变换角度(R 通过 SensorManager.getRotationMatrix 这个方法获得)。
然后这是我的一些实验结果(角度都被我转成角度制,转置时将 R 看成 3x3 的矩阵进行转置,可以看到将 R 转置后有时候结果是对的[虽然文档没说要转置,我们还是试了一下]):
较为正确的结果:
不靠谱的结果:
采集数据的时候,当传感器触发事件的时候,调用以下代码的 calcOrientation 方法:
private float[] accelerometerValues = new float[3];
private float[] magneticFieldValues = new float[3];
private float[] _R = new float[9];
private float[] api2Angles = new float[3];
private void calcOrientation() {
boolean success = SensorManager.getRotationMatrix(_R, null, accelerometerValues, magneticFieldValues);
if (success) {
SensorManager.getOrientation(_R, api2Angles);
}
}
public float[] getApi2Angles(){
return api2Angles;
}
public float[] getRValues(){
return _R;
}
保存的时候通过下面的代码保存到某个文件:
...
float[] api2_angles = preview.getApi2Angles();
float[] _R = preview.getRValues();
// 将 api2_angles 和 _R 保存到某个文件中
...
所以,问题到底在哪里呢?是数据采集的时候出了问题(比如保存的时候 calcOrientation 正在计算,导致了读取的数据是有问题的?这个我不确定),还是我的 getAngleChange 这个方法使用的方式有问题?
请大家赐教~