13

如何获得表示设备背面相对于地球坐标指向的方向的方向矢量?

例如,如果放在桌子上(屏幕朝上),它应该显示为 [0,0,-1],如果垂直朝北放置,它应该显示为 [1,0,0],等等。

我知道如何从航向、俯仰和滚动计算它,只要它们是相对于地球坐标的。在这里要清楚,我不是在寻找角速度,而是在寻找相对于与地球相切的平面的实际当前角度。因此,如果设备垂直并朝北,角度“alpha”应该是 0 或 360,角度“beta”应该是 90,而“gamma”应该是 0。我不知道如何获得这些值任何一个。

我整天都在阅读 API,但我仍然找不到如何获得这些东西。

public void onSensorChanged(SensorEvent event) {
    // ?    
}

感谢您的任何见解。

4

2 回答 2

9

阅读此页面:http: //developer.android.com/reference/android/hardware/Sensor.html

在 API 8 及更高版本中,存在“虚拟”传感器,它们是通过组合所有可用传感器和适当过滤器的输入而生成的。“TYPE_ORIENTATION”传感器为您提供设备的整体方向,但由于某些方向的故障状态,此界面已被弃用。新传感器是 TYPE_ROTATION_VECTOR(API 9 及更高版本),它将您的设备方向作为四元数。这确实是最好的传感器,但它背后的数学有点沉重。

如果做不到这一点,你要做的是调用 SensorManager.getRotationMatrix(),传递最新的重力和磁力计数据。这将返回一个旋转矩阵,可用于将向量从设备坐标转换为世界坐标,反之亦然(只需转置矩阵以反转它)。

getOrientation() 函数可以为您提供航向、俯仰和滚动,但这些具有与 TYPE_ORIENTATION 传感器相同的故障状态。

Examples:

  Device flat on a table, top facing north:
    1  0  0
    0  1  0
    0  0  1

  Tilted up 30 degrees (rotated about X axis)
    1   0      0
    0   0.86  -0.5
    0   0.5    0.86

  Device vertical (rotated about X axis), facing north:
    1  0  0
    0  0 -1
    0  1  0

  Device flat on a table, top facing west:
    0 -1  0
    1  0  0
    0  0  1

  Device rotated about its Y axis, onto its left side, top
  facing north:
    0  0 -1
    0  1  0
    1  0  0

以下是一些您可能会觉得有用的示例代码:

public void onSensorChanged(SensorEvent event) {
    long now = event.timestamp;     // ns

    switch( event.sensor.getType() ) {
      case Sensor.TYPE_ACCELEROMETER:
        gData[0] = event.values[0];
        gData[1] = event.values[1];
        gData[2] = event.values[2];
        break;
      case Sensor.TYPE_MAGNETIC_FIELD:
        mData[0] = event.values[0];
        mData[1] = event.values[1];
        mData[2] = event.values[2];
        haveData = true;
        break;
    }

    if( haveData ) {
        double dt = (now - last_time) * .000000001;

        SensorManager.getRotationMatrix(R1, Imat, gData, mData);
        getOrientation(R1, orientation);
        pfdView.newOrientation(orientation[2], (float)dt);


        Log.d(TAG, "yaw: " + (int)(orientation[0]*DEG));
        Log.d(TAG, "pitch: " + (int)(orientation[1]*DEG));
        Log.d(TAG, "roll: " + (int)(orientation[2]*DEG));

        acft.compass = orientation[0];

        last_time = now;
    }
}
于 2012-06-17T04:16:14.113 回答
9

SensorManager.getRotationMatrix()做了下面概述的,在我发现之前写的。我会留下附加的解释,因为如果你想纠正磁北和真北之间的差异,你仍然需要它。

粗略的算法是获取旋转矩阵,将向量乘以[0,0,-1]它,然后将其调整到您的坐标系。为什么?Android 文档给出了设备和世界的坐标系

设备世界

注意[0,0,-1]Android 设备坐标点垂直向后远离屏幕。如果您将旋转矩阵 R 乘以该向量,[0,0,-1]则当设备按您希望的面朝上放在桌子上时,您将获得世界坐标。当它直立朝北时,你会得到[0,-1,0],这表明你已经选择了一个坐标系,x并且y相对于 Android 系统进行了交换,但这只是约定的改变。

注意R * [0,0,-1]^T只是R否定的第三列。从这里我得到伪代码:

getRotationMatrix(R);
Let v = first three elements of third column of R.
swap v[0] and v[1]

这应该得到你想要的。

以下是有关正在执行的操作的其他信息getRotationMatrix()


您需要加速度计数据来确定“向下”方向,并且需要磁力计数据来确定“北”方向。您必须假设加速度计仅感应重力(设备静止或以稳定的速度移动)。然后您需要将磁力计矢量投影到垂直于重力矢量的平面上(因为磁场通常不与地球表面相切)。这为您提供了两个轴。第三个是正交的,因此可以通过叉积计算。这为您提供了设备系统中的地球坐标矢量。看起来你想要相反的:地球坐标中的设备坐标。为此,只需构建方向余弦矩阵并反转。

我将补充一点,上述讨论假设磁力计矢量指向北方。我认为(来自高中科学!)它实际上是朝着磁南方向,但手头没有设备所以不能尝试。当然,根据您在地球上的位置,磁北/南与真实的差异为零到 180 度。您可以检索 GPS 坐标并计算实际偏移量。

如果您不熟悉执行这些操作所需的数学,我可以进一步解释,但必须稍后再说。

于 2012-06-17T03:03:08.887 回答