14

我正在使用 Android 重力和磁场传感器通过 SensorManager.getRotationMatrix 和 SensorManager.getOrientation 计算方向。这给了我方位角、俯仰角和方向数字。当设备平放在桌子上时,结果看起来很合理。

但是,我在清单中禁用了纵向和横向之间的切换,因此 getWindowManager().getDefaultDisplay().getRotation() 始终为零。当我将设备旋转 90 度使其垂直站立时,我遇到了麻烦。有时数字看起来很不对劲,我意识到这与Gimbal lock有关。但是,其他应用程序似乎没有这个问题。例如,我将我的应用程序与两个免费的传感器测试应用程序(Sensor Tester (Dicotomica)Sensor Monitoring (R's Software))进行了比较。当设备平放时,我的应用程序与这些应用程序一致,但当我将设备旋转到垂直位置时,可能会有显着差异。这两个应用程序似乎彼此一致,

4

3 回答 3

11

当设备不平整时,您必须先打电话remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);再打电话getOrientation

通过将设备单元正交投影到世界中,然后计算生成的投影向量与北轴之间的角度 来获得azimuth返回值。getOrientationY axisEast-North plane

现在我们通常认为方向是后置摄像头指向的方向。那就是设备轴指向屏幕外的-Z方向Z。当设备是扁平的时,我们不会考虑方向并接受任何给定的东西。但是当它不平坦时,我们期望它是 的方向-Z。但是getOrientation计算 的方向Y axis,因此我们需要Y and Z axes在调用之前交换getOrientation。这正是remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR)它所做的,它保持X axis原样和 map Z to Y

现在,你怎么知道什么时候去remap或不去。你可以通过检查来做到这一点

float inclination = (float) Math.acos(rotationMatrix[8]);
if (result.inclination < TWENTY_FIVE_DEGREE_IN_RADIAN 
            || result.inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN)
{
    // device is flat just call getOrientation
}
else
{
    // call remap
}

上面的倾角是设备屏幕与世界东西平面的夹角。它显示了设备倾斜的程度。

于 2013-03-27T00:27:26.903 回答
8

我认为当设备不平坦时定义方向角的最佳方法是使用更合适的角度坐标系,即您从中获得的标准欧拉角SensorManager.getOrientation(...)。我建议我在 math.stackexchange.com 上描述的那个。我还在此处的答案中放了一些实现它的代码。除了方位角的良好定义外,它还定义了俯仰角,这正是Math.acos(rotationMatrix[8])此处另一个答案中提到的角度。

您可以从我在第一段中给出的两个链接中获得完整的详细信息。但是,总而言之,来自 SensorManager.getRotationMatrix(...)的旋转矩阵R是

具有 R 矩阵定义的方程

其中 (E x , E y , E z ), (N x , N y , N z ) 和 (G x , G y , G z ) 是指向正东、正北和重力方向的向量。然后你想要的方位角由下式给出

定义方位角的方程

于 2013-05-06T11:47:54.300 回答
0

我将添加一个对我有用的示例,使用 Hoan 的答案,并强调一些现在可用的新资源,在查看需要使用陀螺仪传感器的应用程序时可能会有所帮助。

首先,有一个带有示例应用程序的 Google 代码实验室 - 我发现完整的示例应用程序对于理解设备行为非常有用。

应用程序显示如下所示:

在此处输入图像描述

代码实验室和最终应用程序版本可在以下链接中获得(在撰写本文时):

特别是,这允许您进行如下实验(它比描述更容易做......):

  • 将您的设备平放在桌子上,并尝试在平放的情况下在桌子上旋转,抬起顶部和底部(即,将显示屏的顶部(通常是前置摄像头所在的位置)从桌子上抬起,同时离开底部,即主页按钮的位置通常是如果你有一个,在桌子上。同样,抬起设备的左右边缘。观察应用程序中的方位角、俯仰角和滚动值。

  • 将您的设备以纵向模式靠在衣柜门上,然后再次尝试移动它。开门见效。旋转到横向以查看差异。

我认为您可能从上面看到的关键是,一切都非常简单,并且在平坦时运行良好,而在不平坦时,一切都很复杂且相互关联。

具体来看一个用例,我必须在纵向模式下垂直显示俯仰和滚动,以下对我有用:

 when (event?.sensor?.type) {
            Sensor.TYPE_ROTATION_VECTOR -> {

                // Calculate the rotation matrix
                val rotMatrix = FloatArray(9)
                var rotationMatrixAdjusted = FloatArray(9)
                val azimuthChanged: (Float) -> Unit
                val orientation = FloatArray(3)
                SensorManager.getRotationMatrixFromVector(rotMatrix, event.values);
                SensorManager.remapCoordinateSystem(rotMatrix,
                        SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X,
                        rotationMatrixAdjusted);
                SensorManager.getOrientation(rotationMatrixAdjusted, orientation)

                val rollAngleRadians = orientation[1]
                val pitchAngleRadians = orientation[2]
                              
                //Report results back to listener
                thisListener.onRollPitchEvent(rollAngleRadians, pitchAngleRadians)
            }
        }
于 2021-04-07T14:27:33.690 回答