Android:计算设备方向的问题

Posted

技术标签:

【中文标题】Android:计算设备方向的问题【英文标题】:Android: Problems calculating the Orientation of the Device 【发布时间】:2013-01-22 08:15:29 【问题描述】:

我正在尝试构建一个简单的增强现实应用程序,因此我开始使用传感器数据。

根据此线程 (android compass example) 和示例 (http://www.codingforandroid.com/2011/01/using-orientation-sensors-simple.html),使用 Sensor.TYPE_ACCELEROMETERSensor.TYPE_MAGNETIC_FIELD 计算方向不会'真的不合适。

所以我无法获得“好的”价值。方位角值根本没有任何意义,所以如果我只是将手机向上移动,值就会发生极大的变化。即使我只是旋转手机,这些值也不代表手机的方向。

有没有人有想法,根据给定的例子,谁来提高价值质量?

【问题讨论】:

【参考方案1】:

您以何种方式使用此示例应用程序?从所写的是这段代码,唯一支持的方向是纵向或平放在桌子上,这取决于设备。 “好”是什么意思?

旋转设备时值不是“好”是正常的,设备坐标系应该是纵向工作,或者我不知道是平坦的(Y轴垂直于屏幕向上,Z轴从屏幕中心指向屏幕外,X 轴垂直于 Y 轴,沿屏幕向右)。有了这个,旋转设备不会旋转设备坐标系,你必须重新映射它。

但是,如果您希望设备的标题是纵向的,这里有一段对我有用的代码:

@Override
public void onSensorChanged(SensorEvent event)

    // It is good practice to check that we received the proper sensor event
    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
    
        // Convert the rotation-vector to a 4x4 matrix.
        SensorManager.getRotationMatrixFromVector(mRotationMatrix,
                event.values);
        SensorManager
                .remapCoordinateSystem(mRotationMatrix,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        mRotationMatrix);
        SensorManager.getOrientation(mRotationMatrix, orientationVals);

        // Optionally convert the result from radians to degrees
        orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
        orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
        orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);

        tv.setText(" Yaw: " + orientationVals[0] + "\n Pitch: "
                + orientationVals[1] + "\n Roll (not used): "
                + orientationVals[2]);

    

您将在以下位置获得航向(或方位角):

orientationVals[0]

【讨论】:

作为记录,我用 3x3 矩阵尝试了这段代码,但它只适用于 4x4(又名 float[16])【参考方案2】:

Tíbó 的回答很好,但如果您记录滚动值,您会看到不规则的数字。 (滚动对 AR 浏览器很重要)

这是由于

SensorManager.remapCoordinateSystem(mRotationMatrix,
                    SensorManager.AXIS_X, SensorManager.AXIS_Z,
                    mRotationMatrix);

您必须使用不同的矩阵进出重映射。以下代码适用于我的正确滚动值:

@Override
public void onSensorChanged(SensorEvent event)

    // It is good practice to check that we received the proper sensor event
    if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
    
        // Convert the rotation-vector to a 4x4 matrix.
        SensorManager.getRotationMatrixFromVector(mRotationMatrixFromVector, event.values);
        SensorManager.remapCoordinateSystem(mRotationMatrixFromVector,
                    SensorManager.AXIS_X, SensorManager.AXIS_Z,
                    mRotationMatrix);
        SensorManager.getOrientation(mRotationMatrix, orientationVals);

        // Optionally convert the result from radians to degrees
        orientationVals[0] = (float) Math.toDegrees(orientationVals[0]);
        orientationVals[1] = (float) Math.toDegrees(orientationVals[1]);
        orientationVals[2] = (float) Math.toDegrees(orientationVals[2]);

        tv.setText(" Yaw: " + orientationVals[0] + "\n Pitch: "
                + orientationVals[1] + "\n Roll (not used): "
                + orientationVals[2]);

    

【讨论】:

是的,您可以查看源代码: public static boolean remapCoordinateSystem(float[] inR, int X, int Y, float[] outR) * @param outR * 转换后的旋转矩阵。 inR 和 outR 不应该是同一个 * 数组。【参考方案3】:

聚会可能迟到了。无论如何,这就是我如何获得方位角

private final int sensorType =  Sensor.TYPE_ROTATION_VECTOR;
float[] rotMat = new float[9];
float[] vals = new float[3];

@Override
public void onSensorChanged(SensorEvent event) 
    sensorHasChanged = false;
    if (event.sensor.getType() == sensorType)
        SensorManager.getRotationMatrixFromVector(rotMat,
                event.values);
        SensorManager
                .remapCoordinateSystem(rotMat,
                        SensorManager.AXIS_X, SensorManager.AXIS_Y,
                        rotMat);
        SensorManager.getOrientation(rotMat, vals);
        azimuth = deg(vals[0]); // in degrees [-180, +180]
        pitch = deg(vals[1]);
        roll = deg(vals[2]);
        sensorHasChanged = true;
    

希望对你有帮助

【讨论】:

remapCoordinateSystem 调用只是身份转换,所以它是多余的。更糟糕的是,它使用rotMat 进行输入和输出,文档明确指出您不应该这样做。【参考方案4】:

您是否尝试过组合(传感器融合)类型 Sensor.TYPE_ROTATION_VECTOR。这可能会产生更好的结果: 转到https://developer.android.com/reference/android/hardware/SensorEvent.html 并搜索“rotation_vector”。

【讨论】:

好的,有什么例子可以使用这个传感器吗?我得到 xsin(θ/2)、ysin(θ/2) 和 z*sin(θ/2) 的值。但是我如何获得价值,我需要建立我的指南针。我应该再次使用 getRotationMatrix 吗?感谢您的帮助。 "X定义为向量积YZ(在设备当前位置与地面相切,大致指向东)。Y在设备当前位置与地面相切,指向磁北。Z指向天空,垂直于地面。掸掉你的几何课书上的灰尘,或者用谷歌搜索一下:),你应该能弄明白的。【参考方案5】:

这是一个包含所有必要矩阵的 Kotlin 方法(由于某种原因,前面的答案忽略了数组大小,这很重要)

// This is determined from the deprecated Sensor.TYPE_ORIENTATION
var lastOrientation: FloatArray = FloatArray(3)
var lastHeading: Float = 0f
var currentHeading: Float = 0f

// This is from the non deprecated Sensor.TYPE_ROTATION_VECTOR
var lastVectorOrientation: FloatArray = FloatArray(5)
var lastVectorHeading: Float = 0f
var currentVectorHeading: Float = 0f

override fun onSensorChanged(event: SensorEvent) 
    when(event.sensor?.type) 
        null -> return
        Sensor.TYPE_ORIENTATION -> 
            lastOrientation = event.values
            lastHeading = currentHeading
            currentHeading = abs(event.values[0].roundToInt().toFloat())
        
        Sensor.TYPE_ROTATION_VECTOR -> 
            lastVectorOrientation = event.values
            lastVectorHeading = currentVectorHeading

            val tempRotationMatrix = FloatArray(9)
            val tempOrientationMatrix = FloatArray(3)
            getRotationMatrixFromVector(tempRotationMatrix, event.values)
            remapCoordinateSystem(tempRotationMatrix, AXIS_X, AXIS_Z, tempRotationMatrix)
            getOrientation(tempRotationMatrix, tempOrientationMatrix)
            currentVectorHeading = Math.toDegrees(tempOrientationMatrix[0].toDouble()).toFloat()
            
            if(currentVectorHeading < 0) 
                currentVectorHeading += 360f//heading = 360 - abs(neg heading), which is really 360 + (-heading)
            
        
        else -> return
    

我还包含了已弃用的 Sensor.TYPE_ORIENTATION 供任何想了解这两种方法之间差异的人使用。使用不推荐使用的方法与使用更新的方法时存在几个程度的差异。

【讨论】:

以上是关于Android:计算设备方向的问题的主要内容,如果未能解决你的问题,请参考以下文章

在android中查找设备的相对方向

固定方向Android上的设备旋转

Android 设备上的照片方向

锁定设备方向 - React Native (Android)

为啥此代码不会显示 Android 设备方向更改?

Android OpenGL表面崩溃在设备方向改变问题,怎么解决