在Android中获取方向向量

在Android中获取方向向量,android,vector,accelerometer,sensors,gyroscope,Android,Vector,Accelerometer,Sensors,Gyroscope,如何获得表示设备背面相对于地球坐标指向的方向向量 例如,如果将其放在桌子上(屏幕朝上),则其读数应为[0,0,-1],如果垂直放置,则其读数应为[1,0,0],以此类推 我知道如何从航向、俯仰和横滚计算它,只要它们是相对于地球坐标的。这里我要说清楚的不是角速度,而是相对于与地球相切的平面的实际电流角。因此,如果设备保持垂直并朝北,角度“alpha”应为0或360,角度“beta”应为90,“gamma”应为0。我也不知道如何得到这些值 我已经读了一整天的API,我仍然找不到如何得到这些东西 pu

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

例如,如果将其放在桌子上(屏幕朝上),则其读数应为[0,0,-1],如果垂直放置,则其读数应为[1,0,0],以此类推

我知道如何从航向、俯仰和横滚计算它,只要它们是相对于地球坐标的。这里我要说清楚的不是角速度,而是相对于与地球相切的平面的实际电流角。因此,如果设备保持垂直并朝北,角度“alpha”应为0或360,角度“beta”应为90,“gamma”应为0。我也不知道如何得到这些值

我已经读了一整天的API,我仍然找不到如何得到这些东西

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

感谢您的帮助。

SensorManager.getRotationMatrix()完成了下面概述的工作,在我发现这一点之前编写。我会留下补充的解释,因为如果你想纠正磁北和正北之间的差异,你仍然需要它

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

注意: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()
正在执行的操作的其他信息如下


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

我还要补充一点,上面的讨论假设磁强计矢量指向北方。我想(从高中科学开始!)它实际上是朝着磁性南部,但手边没有设备,所以不能尝试。当然,磁北/磁南与真的相差0到180度,这取决于你在地球上的位置。您可以检索GPS坐标并计算实际偏移

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

阅读本页:

在API 8及以上版本中,存在通过组合所有可用传感器和适当过滤器的输入而生成的“虚拟”传感器。“TYPE_ORIENTATION”(类型_方向)传感器为您提供设备的整个方向,但由于某些方向的故障状态,此接口不推荐使用。新的传感器是类型_旋转_矢量(API 9及以上),它以四元数的形式为您的设备提供方向。这确实是最好的传感器,但背后的数学计算有点繁重

否则,您需要调用SensorManager.getRotationMatrix(),传递最新的重力和磁强计数据。这将返回一个旋转矩阵,该矩阵可用于将向量从设备坐标转换为世界坐标,或将向量从世界坐标转换为世界坐标(只需转置矩阵即可反转)

getOrientation()函数可以为您提供航向、俯仰和侧倾,但它们与类型_方向传感器具有相同的故障状态

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

非常感谢,这真的很有帮助。你们两个都给出了这么好的答案,我真希望有办法把他们两个都选出来。看起来我只需要传感器就可以得到重力矢量。输入重力-他们为我做了这项工作。我希望得到一个“北”向量也一样容易。我最后用你的解释得到了它。结果是,我将重力传感器和磁场传感器返回的值直接传递到getRotationMatrix()中,它会解决所有问题。然后把这个矩阵乘以[0,0,-1],得到了dv。谢谢你的回答-我有两个问题,如果我使用类型旋转向量,量子数是用世界坐标表示的吗?它已经被整合了,还是我必须整合它才能得到当前的向量?我相信设备的世界坐标。已转换为单位四元数,有时省略w项。老实说,我自己从来没有用过。我上面显示的代码来自我为1.5版编写的飞行导航应用程序,在新传感器类型可用之前。