【问题标题】:How should I calculate azimuth, pitch, orientation when my Android device isn't flat?当我的 Android 设备不平坦时,我应该如何计算方位角、俯仰角、方向?
【发布时间】:2021-04-07 22:39:34
【问题描述】:

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

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

【问题讨论】:

    标签: android orientation sensors


    【解决方案1】:

    当设备不平整时,您必须先调用remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);,然后再调用getOrientation

    getOrientation返回的azimuth是通过将设备单元Y axis正交投影到世界East-North plane然后计算得到的投影向量与北轴之间的角度得到的。

    现在我们通常认为方向是后置摄像头指向的方向。那是-Z 的方向,其中Z 是指向屏幕外的设备轴。当设备是扁平的时,我们不会考虑方向并接受任何给定的东西。但是当它不平坦时,我们预计它是-Z 的方向。但是getOrientation计算Y axis的方向,因此我们需要在调用getOrientation之前交换Y and Z axes。这正是remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR) 所做的,它保持X axis 完整并映射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
    }
    

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

    【讨论】:

    • 感谢您的回复。但是,这不是这两个免费传感器应用程序正在做的事情,因为当倾斜度超过 25(或 155 度)时,根据您的建议,由于轴的切换,俯仰和横滚数字会跳跃。免费传感器应用程序的俯仰和横滚数字不会跳跃。此外,轴到 AXIS_X 和 AXIS_Z 的切换仅对一个方向的倾斜是正确的,对于其他方向的倾斜,它会导致不正确的方位角跳跃(尽管毫无疑问,通过调整切换到的轴可能是正确的)。跨度>
    • 用于不调用 remap 的俯仰和横滚值,仅用于方位角。我不明白你向另一个方向倾斜是什么意思?如果您的意思是屏幕不面向您,那么方向肯定与屏幕面向您时的方向相反。
    • 感谢您的想法,但其他答案似乎提供了更一致的方法。
    • 这是几乎所有关于 AR 应用程序的文章中都写的通用方法,也从 Play 商店的一些 3D 指南针中检查了它。每个应用程序都提供相同的方位角,但在设备平坦时获得的值之间存在差异。相差约10度。我还没能解决这个问题。当设备放在表面上或平放时,您不会得到相同的结果。
    【解决方案2】:

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

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

    其中 (Ex, Ey, Ez), (Nx, Ny, Nz) 和 (Gx, Gy, Gz) 是指向正东、正北和重力方向的向量。然后你想要的方位角由

    给出

    【讨论】:

    • 不幸的是,这不适用于我从SensorManager.getRotationMatrixFromVector(使用传感器TYPE_ROTATION_VECTOR)获得的旋转矩阵。当我计算 double a = Math.toDegrees(Math.atan((r[1] - r[3]) / (r[0] + r[4])));(其中 r 是旋转矩阵)时,我总是以 -90 a 的角度结束
    【解决方案3】:

    我将使用 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)
                }
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多