手机方向不同会导致指南针方向不同

7
我的增强现实应用需要相机视图的指南针方位,有很多获取传感器管理器方向的例子。然而,我发现结果值取决于手机方向,右侧旋转的横向与左侧旋转的横向相比,大约会有10度的差异(ROTATION_0和ROTATION_180之间的差异较小,但仍不同)。这种差异足以破坏任何AR效果。
这是校准问题吗?(我不确定自己是否正确地进行了8字形操作——我已经尝试了在YouTube上找到的各种方法)。
为什么会有这样的差别?旋转矩阵的问题吗?我可以将应用限制为单一方向,但仍然担心指南针读数不太准确(即使经过滤波后它相对稳定)。
public void onSensorChanged(SensorEvent event) {
        if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
            return;
        }

        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)  mGravity = event.values;
        if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mGeomagnetic = event.values;

        if (mGravity != null && mGeomagnetic != null) {

            float[] rotationMatrixA = mRotationMatrixA;
            if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) {

                float[] rotationMatrixB = mRotationMatrixB;

                Display display = getWindowManager().getDefaultDisplay(); 
                int deviceRot = display.getRotation();

                switch (deviceRot)
                {
                // portrait - normal
                case Surface.ROTATION_0: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        rotationMatrixB);
                break;
                // rotated left (landscape - keys to bottom)
                case Surface.ROTATION_90: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_Z, SensorManager.AXIS_MINUS_X,
                        rotationMatrixB); 
                break;
                // upside down
                case Surface.ROTATION_180: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_X, SensorManager.AXIS_Z,
                        rotationMatrixB); 
                break;
                // rotated right
                case Surface.ROTATION_270: SensorManager.remapCoordinateSystem(rotationMatrixA,
                        SensorManager.AXIS_MINUS_Z, SensorManager.AXIS_X,
                        rotationMatrixB); 
                break;

                default:  break;
                }

                float[] dv = new float[3]; 
                SensorManager.getOrientation(rotationMatrixB, dv);
                // add to smoothing filter
                fd.AddLatest((double)dv[0]); 
            }
            mDraw.invalidate();     
        }
    }
2个回答

10

试试这个

public void onSensorChanged(SensorEvent event) {
    if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
        return;
    }

    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)  mGravity = event.values.clone ();
    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) mGeomagnetic =  event.values.clone ();

    if (mGravity != null && mGeomagnetic != null) {

        float[] rotationMatrixA = mRotationMatrixA;
        if (SensorManager.getRotationMatrix(rotationMatrixA, null, mGravity, mGeomagnetic)) {

            float[] rotationMatrixB = mRotationMatrixB;
            SensorManager.remapCoordinateSystem(rotationMatrixA,
                    SensorManager.AXIS_X, SensorManager.AXIS_Z,
                    rotationMatrixB);
            float[] dv = new float[3]; 
            SensorManager.getOrientation(rotationMatrixB, dv);
            // add to smoothing filter
            fd.AddLatest((double)dv[0]); 
        }
        mDraw.invalidate();     
    }
}
你不需要使用switch语句,有很多人在stackoverflow上对getRotationMatrix、remapCoordinateSystem和getOrientation存在混淆。 我可能会在不久的将来编写这些内容的详细解释。

哇!我在 Stack Overflow 上搜索了 2 个多小时,有很多错误的答案。你的是第一个真正对我起作用的。感谢你。 - BoD
我复制并编辑了这篇文章。我没有意识到Mush的mGravity = event.values,它应该是event.values.clone()。mGeomagnetic也是如此。 - Hoan Nguyen
SensorManager.remapCoordinateSystem 是解决方案。谢谢。 - Douglas Nassif Roma Junior
@Mark Kranzler 的回答是错误的。问题要求相机视图的方向,即设备 -z 轴的方向。getOrientation 返回方位角作为 y 轴的方向。因此,您需要 remapCoordinateSystem。无论设备的方向如何,设备 z 轴的指向都相同。也就是说,无论设备处于纵向、横向还是介于两者之间,z 轴都指向同一方向。因此,不需要考虑设备的方向。 - Hoan Nguyen
如果您的手机处于横屏状态且设备屏幕指向您(横向方向的 AR 功能正常运行),则此答案是正确的。如果您的手机在横向桌面上放置,则无法使用。Hoan Nyugen,我也阅读了您关于罗盘的几乎所有帖子,并查看了“dsensor”代码,这确实很有教育意义。您能否分享如何在设备平放或屏幕垂直于地面时实现纵向和横向方向? - Thracian
如果手机平放,则不重新映射坐标。在这里发生的是,getOrientation的值[0]是设备y轴和磁北极之间的角度。当您像上面那样重新映射坐标时,getOrientation中的值[0]是负设备z轴与磁北极之间的角度。如果手机平放,则设备z轴的负值指向天空或大地,因此讨论这个方向和磁北极之间的角度是没有意义的。 - Hoan Nguyen

1

Hoan的回答实际上是不正确的,因为它没有考虑到显示旋转。这个才是正确的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接