108

一段时间以来,我一直试图了解 Android 方向传感器。我以为我明白了。然后我意识到我没有。现在我想(希望)我再次对它有更好的感觉,但我仍然不是 100%。我将尝试解释我对它的不完整的理解,如果我在部分错误或填写任何空白处,希望人们能够纠正我。

我想我站在经度 0 度(本初子午线)和纬度 0 度(赤道)。这个位置实际上是在非洲海岸附近的海域,但请耐心等待。我把手机放在脸前,让手机底部指向我的脚;我面向北方(朝向格林威治),因此电话的右侧指向东方,指向非洲。在这个方向(参考下图)我有 X 轴指向东方,Z 轴指向南方,Y 轴指向天空。

现在,手机上的传感器允许您在这种情况下计算出设备的方向(而不是位置)。这部分一直让我感到困惑,可能是因为在我接受它确实有效之前,我想了解它是如何工作的。手机似乎使用两种不同技术的组合来确定其方向。

在我开始之前,想象一下你站在那块假想的 0 度纬度和经度的土地上,站在上面提到的方向。还想象一下,你被蒙上眼睛,你的鞋子被固定在操场上的环形交叉路口。如果有人从背后推你,你会向前(朝北)摔倒并伸出双手来阻止摔倒。同样,如果有人推你的左肩,你会用右手摔倒。您的内耳有“重力传感器” (youtube 剪辑),可让您检测您是向前/向后跌倒,还是向左/向右跌倒或跌倒(或向上!!)。因此,人类可以检测到与手机相同的 X 轴和 Z 轴周围的对齐和旋转。

现在想象有人现在在环形交叉路口将你旋转 90 度,这样你现在面向东方。您正在绕 Y 轴旋转。这个轴是不同的,因为我们无法从生物学上检测到它。我们知道我们有一定的角度,但我们不知道相对于地球磁北极的方向。相反,我们需要使用外部工具……磁罗盘。这使我们能够确定我们所面对的方向。我们的手机也是如此。

现在这款手机还配备了一个 3 轴加速度计。我没有了解它们实际上是如何工作的,但我想象它的方式是将重力想象为从天而降的恒定且均匀的“雨”,并将上图中的轴想象为可以检测流过的雨水量的管子。当手机直立时,所有的雨水都会流过 Y '管'。如果手机逐渐旋转,使其屏幕面向天空,流过 Y 的雨量将减少到零,而流过 Z 的音量将稳步增加,直到流过的雨量达到最大。同样,如果我们现在将手机倾斜到一侧,X 管最终将收集到最大量的雨水。因此,根据手机的方向,通过测量流过 3 个管子的雨水量,您可以计算出方向。

这款手机还有一个电子罗盘,其行为类似于普通罗盘——它的“虚拟指针”指向磁北。Android 会合并来自这两个传感器的信息,因此每当生成a SensorEventof时,数组都有 值 [0]:方位角 - (磁北以东的罗盘方位) 值 [1]:俯仰,绕 x 轴旋转(是手机向前或向后倾斜) 值[2]:滚动,围绕 y 轴旋转(手机是向左侧还是右侧倾斜)TYPE_ORIENTATIONvalues[3]


所以我认为(即我不知道)Android 给出方位角(罗盘方位)而不是第三个加速度计读数的原因是罗盘方位更有用。我不确定他们为什么不推荐使用这种类型的传感器,因为现在看来您需要为SensorEvents 类型的系统注册一个侦听器TYPE_MAGNETIC_FIELD。事件的value[]数组需要传递到SensorManger.getRotationMatrix(..)方法中以获取旋转矩阵(见下文),然后将其传递到SensorManager.getOrientation(..)方法中。有谁知道为什么Android团队不推荐使用Sensor.TYPE_ORIENTATION?是效率问题吗?这就是对类似问题的评论之一所暗示的内容,但您仍然需要在development/samples/Compass/src/com/example/android/compass/CompassActivity.java示例。

我现在想谈谈旋转矩阵。(这是我最不确定的地方)所以上面我们有来自 Android 文档的三个数字,我们将它们称为 A、B 和 C。

A = SensorManger.getRotationMatrix(..) 方法图,代表世界坐标系

B = SensorEvent API 使用的坐标系。

C= SensorManager.getOrientation(..) 方法图

所以我的理解是,A 代表“世界坐标系”,我认为它是指地球上的位置以(纬度,经度)和可选(高度)的形式给出的方式。X 是“东”坐标,Y 是“北”坐标。Z 指向天空,代表高度。

手机坐标系如图B所示是固定的。它的 Y 轴总是指向顶部。手机不断计算旋转矩阵,并允许两者之间的映射。那么我认为旋转矩阵将 B 的坐标系转换为 C 的想法是否正确?因此,当您调用SensorManager.getOrientation(..)方法时,您使用的values[]数组的值对应于图 C。当手机指向天空时,旋转矩阵是单位矩阵(矩阵数学等价于 1),这意味着在设备对齐时不需要映射与世界坐标系。

行。我想我现在最好停下来。就像我之前说的那样,我希望人们会告诉我我在哪里搞砸了或帮助了人们(或者让人们更加困惑!)

4

4 回答 4

27

您可能想查看One Screen Turn 值得另一篇文章。它解释了为什么需要旋转矩阵。

简而言之,手机的传感器始终使用相同的坐标系,即使在设备旋转时也是如此。

在未锁定到单一方向的应用程序中,屏幕坐标系会在您旋转设备时发生变化。因此,当设备从其默认视图模式旋转时,传感器坐标系不再与屏幕坐标系相同。在这种情况下,旋转矩阵用于将 A 转换为 C(B 始终保持固定)。

这是一个代码片段,向您展示如何使用它。

SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);

//...
// The following code inside a class implementing a SensorEventListener
// ...

float[] inR = new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];

double azimuth = 0;
double pitch = 0;
double roll = 0;

public void onSensorChanged(SensorEvent sensorEvent) {
    // If the sensor data is unreliable return
    if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        return;

    // Gets the value of the sensor that has been changed
    switch (sensorEvent.sensor.getType()) {  
        case Sensor.TYPE_ACCELEROMETER:
            gravity = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomag = sensorEvent.values.clone();
            break;
    }

    // If gravity and geomag have values then find rotation matrix
    if (gravity != null && geomag != null) {

        // checks that the rotation matrix is found
        boolean success = SensorManager.getRotationMatrix(inR, I,
                                                          gravity, geomag);
        if (success) {
            SensorManager.getOrientation(inR, orientVals);
            azimuth = Math.toDegrees(orientVals[0]);
            pitch = Math.toDegrees(orientVals[1]);
            roll = Math.toDegrees(orientVals[2]);
        }
    }
}
于 2011-07-24T03:37:42.937 回答
3

滚动是重力的函数,90 度滚动会将所有重力放入 x 寄存器。

俯仰是相同的,向上 90 度俯仰将所有重力分量放入 y 寄存器。

偏航/航向/方位角对重力没有影响,它始终与重力成直角,因此无论您以哪种方式面对重力都是不可测量的。

这就是为什么你需要一个指南针来评估,也许这有道理?

于 2011-11-25T15:16:35.437 回答
0

看看这个:Stackoverflow.com:Q.5202147

在 3 个图表 A、B、C 之前,您似乎大部分都是正确的。在那之后,你把自己弄糊涂了。

于 2011-03-05T14:53:14.570 回答
0

我遇到了这个问题,所以我绘制了不同方向发生的情况。如果设备以横向方式安装,例如在汽车安装中,指南针的“度数”似乎从 0-275(顺时针方向)超过 269(在西和北之间),它从 -90 倒数到 0,然后从 0 转发到 269。270 变为 -90

仍然在横向,但设备位于其背面,我的传感器给出 0-360。在纵向模式下,它可以在 0-360 之间运行,无论是仰卧还是纵向站立。

希望对某人有所帮助

于 2014-06-27T04:27:24.167 回答