代码之家  ›  专栏  ›  技术社区  ›  gisking

当我的Android设备不平坦时,我应该如何计算方位角、俯仰角和方向?

  •  15
  • gisking  · 技术社区  · 11 年前

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

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

    3 回复  |  直到 11 年前
        1
  •  11
  •   Hoan Nguyen    11 年前

    当设备不平整时,您必须拨打 remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR); 打电话之前 getOrientation .

    这个 azimuth 退货依据 获取方向 通过正交投影设备单元获得 Y axis 走向世界 East-North plane 然后计算得到的投影矢量与北轴之间的角度。

    现在我们通常认为方向是背面摄像头指向的方向。这就是 -Z 哪里 Z 是指向屏幕外的设备轴。当设备是平的时,我们不会考虑方向,也不会接受任何给定的东西。但当它不平坦时,我们预计它是 -Z 但是 获取方向 计算 Y轴 ,因此我们需要交换 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
    }
    

    上面的倾斜度是设备屏幕和世界东-北平面之间的角度。它显示了设备的倾斜程度。

        2
  •  8
  •   Community Egal    7 年前

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

    你可以从我在第一段中给出的两个链接中获得完整的细节。然而,总的来说,你的轮换矩阵 R 来自SensorManager.getRotationMatrix(…)为

    equation with definition of R matrix

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

    equation defining the azimuth angle

        3
  •  0
  •   Mick    3 年前

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

    首先,有一个谷歌代码实验室提供了一个示例应用程序——我发现完整的示例应用程序对理解设备行为非常有用。

    应用程序显示如下所示:

    enter image description here

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

    特别是,这可以让你进行以下实验(这比描述更容易…):

    • 把你的设备平放在桌子上,在平放的时候在桌子上旋转,从桌子上抬起顶部和底部(即,将显示器的顶部(你的前置摄像头通常在那里),同时将底部(如果你有主页按钮的话,你的主页按钮通常在这里)留在桌子上。同样,抬起设备的左边缘和右边缘。观察应用程序中的方位角、俯仰和滚转值。

    • 将你的设备以人像模式靠在衣柜门上,然后再次尝试移动它。打开门也可以看到效果。旋转到横向以查看差异。

    我想你可以从上面看到的关键一点是,当平面时,一切都很简单,工作得很好,而当不平面时,每件事都很复杂,相互关联。

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

     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)
                }
            }