首页 > Android 中 getAngleChange 如何使用?

Android 中 getAngleChange 如何使用?

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 这个方法使用的方式有问题?

请大家赐教~

【热门文章】
【热门文章】