【问题标题】:Different values between sensors TYPE_ACCELEROMETER/TYPE_MAGNETIC_FIELD and TYPE_ORIENTATION传感器 TYPE_ACCELEROMETER/TYPE_MAGNETIC_FIELD 和 TYPE_ORIENTATION 之间的不同值
【发布时间】:2010-11-13 19:55:05
【问题描述】:

有 2 种方法可以获得 3 个旋转值(方位角、俯仰角、滚动角)。

其中一个正在注册一个 TYPE_ORIENTATION 类型的侦听器。这是最简单的方法,正如文档所述,我从每次旋转中都得到了正确的值范围: 方位角:[0, 359] 音高:[-180, 180] 滚动:[-90, 90]

另一个,最精确和最复杂的,你第一次看到它就明白了。 Android推荐它,所以我想用它,但我得到不同的值。

方位角:[-180, 180]。 -180/180 是 S,0 i N,90 E 和 -90 W。
音高:[-90, 90]。 90 是 90,-90 是 -90,0 是 0 但 -180/180(屏幕朝下)是 0。
滚动:[-180, 180]。

我应该得到相同的值,但使用小数,对吧?

我有以下代码:

aValues = new float[3];
mValues = new float[3];

sensorListener = new SensorEventListener (){
    public void onSensorChanged (SensorEvent event){
        switch (event.sensor.getType ()){
            case Sensor.TYPE_ACCELEROMETER:
                aValues = event.values.clone ();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                mValues = event.values.clone ();
                break;
        }

        float[] R = new float[16];
        float[] orientationValues = new float[3];

        SensorManager.getRotationMatrix (R, null, aValues, mValues);
        SensorManager.getOrientation (R, orientationValues);

        orientationValues[0] = (float)Math.toDegrees (orientationValues[0]);
        orientationValues[1] = (float)Math.toDegrees (orientationValues[1]);
        orientationValues[2] = (float)Math.toDegrees (orientationValues[2]);

        azimuthText.setText ("azimuth: " + orientationValues[0]);
        pitchText.setText ("pitch: " + orientationValues[1]);
        rollText.setText ("roll: " + orientationValues[2]);
    }

    public void onAccuracyChanged (Sensor sensor, int accuracy){}
};

请帮忙。这很令人沮丧。

我必须以这些价值观对待还是我做错了什么?

谢谢。

【问题讨论】:

  • 我自己已经为此工作了大约 2 周。您的代码看起来应该是(根据我能够找到的文档),但正如您所指出的,它与 TYPE_ORIENTATION 传感器结果不匹配。检查orientationValues[0] 的负值并添加它似乎是一件简单的事情。但这还不够。您没有显示传感器更新的频率。我发现更快的更新可以获得更好的结果,即使 TYPE_ORIENTATION 结果看起来相当稳定。如果您想一起工作,请联系 davemac327@gmail.com
  • 所有传感器速度都是GAME,但我认为问题与速度无关。这很奇怪,因为所有博客和论坛(以及我正在阅读的书!)都以相同的方式实现传感器。
  • 好吧,每个人都说如何使用加速度计和磁场,但没有人说返回的值与 TYPE_ORIENTATION 不同,即使是官方文档也是如此。好工作的人。等待答案...
  • 看看我的问题here。它可能有用。

标签: android orientation sensors device-orientation


【解决方案1】:

我知道我在这里玩的是线程死灵法师,但我最近一直在研究这些东西,所以我想我会投入 2 美分。

该设备不包含指南针或倾角计,因此它不直接测量方位角、俯仰角或滚动。 (我们称这些欧拉角,顺便说一句)。相反,它使用加速度计和磁力计,两者都产生 3 空间 XYZ 矢量。这些用于计算方位角等值。

向量在设备坐标空间中:

世界坐标Y朝北,X朝东,Z朝上:

因此,设备的“中性”方向是平放在桌子上,设备顶部朝北。

加速度计产生一个“向上”方向的矢量。磁力计在“北”方向产生一个矢量。 (请注意,在北半球,由于magnetic dip,这往往会指向下方。)

加速度计矢量和磁力计矢量可以通过 SensorManager.getRotationMatrix() 进行数学组合,它返回一个 3x3 矩阵,该矩阵会将设备坐标中的矢量映射到世界坐标,反之亦然。对于处于中间位置的设备,此函数将返回单位矩阵。

此矩阵不随屏幕方向变化。这意味着您的应用程序需要了解方向并相应地进行补偿。

SensorManager.getOrientation() 采用变换矩阵并计算方位角、俯仰角和滚动值。这些是相对于处于中间位置的设备拍摄的。

我不知道调用这个函数和只使用 TYPE_ORIENTATION 传感器有什么区别,除了这个函数让你先操作矩阵。

如果设备向上倾斜 90° 或接近它,那么欧拉角的使用就会失效。这是数学上的退化情况。在这个领域,设备应该如何知道您是在改变方位角还是滚动?

函数 SensorManager.remapCoordinateSystem() 可用于操作变换矩阵,以补偿您可能知道的有关设备方向的信息。然而,我的实验表明,这并不涵盖所有情况,甚至不包括一些常见的情况。例如,如果您想为直立的设备重新映射(例如拍照),您需要将转换矩阵乘以该矩阵:

1 0 0
0 0 1
0 1 0

在调用 getOrientation() 之前,这不是 remapCoordinateSystem() 支持的方向重新映射之一[如果我在这里遗漏了什么,请有人纠正我]。

好的,所以这一直是一个冗长的说法,如果你使用方向,无论是来自 TYPE_ORIENTATION 传感器还是来自 getOrientation(),你可能做错了。您实际上需要欧拉角的唯一情况是以用户友好的形式显示方向信息、注释照片、驱动飞行仪表显示或类似的东西。

如果您想进行与设备方向相关的计算,几乎可以肯定的是,最好使用转换矩阵并使用 XYZ 向量。

作为一名顾问,每当有人向我提出涉及欧拉角的问题时,我都会支持并询问他们真正想要做什么,然后找到解决方法用向量代替。

回顾您最初的问题,getOrientation() 应该返回 [-180 180] [-90 90] 和 [-180 180] 中的三个值(从弧度转换后)。在实践中,我们将方位角视为 [0 360) 中的数字,因此您只需将 360 添加到您收到的任何负数。您的代码看起来是正确的。如果我确切地知道您所期望的结果以及您得到的结果,那将会有所帮助。

编辑添加:还有一些想法。现代版本的 Android 使用称为“传感器融合”的东西,这基本上意味着所有可用的输入——加速度计、磁力计、陀螺仪——都在一个数学黑盒中组合在一起(通常是卡尔曼滤波器,但取决于供应商)。所有不同的传感器——加速度、磁场、陀螺仪、重力、线性加速度和方向——都作为这个黑盒的输出。

尽可能使用 TYPE_GRAVITY 而不是 TYPE_ACCELEROMETER 作为 getRotationMatrix() 的输入。

【讨论】:

  • 谢谢你的解释,你能指导我这个问题吗? stackoverflow.com/questions/27137239/…
  • 我已经为这个问题添加了答案。你可能不会喜欢它;这是一个非常非常难以解决的问题。
【解决方案2】:

我在这里可能是在黑暗中拍摄,但如果我正确理解您的问题,您想知道为什么您得到[-179..179] 而不是[0..360]

请注意,-180+180180 + N*360 相同,其中 N 是一个整数(整数)。

换句话说,如果您想获得与方向传感器相同的数字,您可以这样做:

// x = orientationValues[0];
// y = orientationValues[1];
// z = orientationValues[2];
x = (x + 360.0) % 360.0;
y = (y + 360.0) % 360.0;
z = (z + 360.0) % 360.0;

这将为您提供所需的 [0..360] 范围内的值。

【讨论】:

  • 我不记得我是如何解决这个问题的 xD,但为你 +1! :P
【解决方案3】:

您的计算中缺少一项关键计算。
在您执行 getRotationMatrix 之后,remapCoordinateSystem 调用。

将其添加到您的代码中,一切都会好起来的。
你可以阅读更多关于它here

【讨论】:

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