在纵向模式下测量设备的滚动时,如何才能获得更好的结果?

How can I better my results when measuring the roll of a device in portrait mode?

我正在尝试获取纵向设备的俯仰和滚动。 With the axes looking like this, it would be about the x and z axis respectively. Right now I'm using the SensorManager API to get the pitch, roll, and yaw of the device sitting flat, as is default.

当我尝试将旋转值从平面设备转换为垂直方向时,我遇到了其他 SO 用户所说的万向节锁定,这是欧拉角工作方式中固有的问题。问题是我已经尝试实施旋转矩阵 as other users have 来解决类似的问题,但即使如此我仍然遇到相同的万向节锁定问题。我已经包含了我的 onSensorChanged 方法,希望有人可以帮助找出问题所在。

public void onSensorChanged(SensorEvent se) {

    float degPitch = 0;
    float degRoll = 0;
    float degYaw = 0;
    float radPitch = 0;
    float radRoll = 0;
    float radYaw = 0;

    if (se.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        mAccelerometerResult = se.values;
        Log.d("onSensorChanged", "Accelerometer: " + mAccelerometerResult.length);
    }

    if (se.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
        mMagneticFieldResult = se.values;
        Log.d("onSensorChanged", "Magnetic Field: " + mMagneticFieldResult.length);
    }

    if (mAccelerometerResult != null && mMagneticFieldResult != null) {
        float[] rotation = new float[9];
        float[] inclination = new float[9];

        boolean rotationMatrixCheck = mSensorManager.getRotationMatrix(rotation, inclination, mAccelerometerResult, mMagneticFieldResult);

        if (rotationMatrixCheck) {

            float[] orientation = new float[3];
            mSensorManager.getOrientation(rotation, orientation);


            radYaw = orientation[0];      //Yaw = Z axis
            radPitch = orientation[1];      //Pitch = X axis
            radRoll = orientation[2];      //Roll = Y axis

            degYaw = round((float) Math.toDegrees(radYaw), 2);
            degPitch = round((float)Math.toDegrees(radPitch), 2);
            degRoll = round((float)Math.toDegrees(radRoll), 2);


            if ((counter % 10) == 0) {
                //mYawTextView.setText(degYaw + "°");
                mPitchTextView.setText(degPitch + "°");
                mRollTextView.setText(degRoll + "°");
                counter = 0;
            } else {
                counter++;
            }
        }
    }

此外,如果我可以围绕纵向轴进行良好的旋转,我什至不确定我是否理解我正在寻找的旋转值。如果我想要纵向滚动设备(关于原始图像的 z 轴),那仍然是设备平放的滚动(关于平面轴图像的 y 轴)吗?

如果能在这里分享任何见解,我们将不胜感激。

我找到了问题的解决方案。获取 3x3 网格中的旋转矩阵 returns 欧拉角中的旋转矩阵,如原始问题中所述。在 4x4 网格中获取矩阵 returns 旋转矩阵的四元数表示 (According to SO user Stochastically's answer found here).

此外,必须重新映射旋转矩阵坐标系才能在纵向模式下使用。评论的更改如下所示。

public void onSensorChanged(SensorEvent se) {

float degPitch = 0;
float degRoll = 0;
float degYaw = 0;
float radPitch = 0;
float radRoll = 0;
float radYaw = 0;

if (se.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
    mAccelerometerResult = se.values;
    Log.d("onSensorChanged", "Accelerometer: " + mAccelerometerResult.length);
}

if (se.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
    mMagneticFieldResult = se.values;
    Log.d("onSensorChanged", "Magnetic Field: " + mMagneticFieldResult.length);
}

if (mAccelerometerResult != null && mMagneticFieldResult != null) {

//~~~This is where the 3x3 matrix has changed to a 4x4.
    float[] rotation = new float[16];
    float[] inclination = new float[16];

    boolean rotationMatrixCheck = mSensorManager.getRotationMatrix(rotation, inclination, mAccelerometerResult, mMagneticFieldResult);

    if (rotationMatrixCheck) {

        float[] orientation = new float[3];

//~~~This is where the rotational matrix is remapped to be used in portrait mode.
        float[] remappedRotation = new float[16];
        SensorManager.remapCoordinateSystem(rotation, SensorManager.AXIS_X, SensorManager.AXIS_Z, remappedRotation);

        mSensorManager.getOrientation(rotation, orientation);


        radYaw = orientation[0];      //Yaw = Z axis
        radPitch = orientation[1];      //Pitch = X axis
        radRoll = orientation[2];      //Roll = Y axis

        degYaw = round((float) Math.toDegrees(radYaw), 2);
        degPitch = round((float)Math.toDegrees(radPitch), 2);
        degRoll = round((float)Math.toDegrees(radRoll), 2);


        if ((counter % 10) == 0) {
            //mYawTextView.setText(degYaw + "°");
            mPitchTextView.setText(degPitch + "°");
            mRollTextView.setText(degRoll + "°");
            counter = 0;
        } else {
            counter++;
        }
    }
}