安卓指南针似乎不可靠。

11
我最近开发了一个小型的指南针应用程序,代码已经可以正常运行,但是指南针读数似乎不太准确。在校准两部手机之后,我的第一个测试结果是将手机放在平面上,查看读数,然后水平翻转手机放在相同的平面上(180度),但是读数并没有改变180度,而是接近240度。
我随后对比测试了普通指南针和我的应用程序读数,有时候读数看起来很接近,但在其他情况下,读数会偏差50度以上。我甚至尝试将手机和指南针放在地板上,远离任何磁性干扰,但结果相同(请注意,我也让指南针和手机保持距离,并通过书本边缘将它们定位在同一方向上)。
我将应用程序安装到了另一部手机上(第一部为Nexus S,第二部为Motorola Droid 1)。两部手机之间的差异在某些点上是相等的,但在大多数情况下,它们的差异在50到15度之间。
我查看了文档,并查阅了许多论坛帖子,但没有发现任何与我类似的结果。可能是我的代码存在一些小错误导致读数出现错误,或者存在一些已记录的错误,我没有注意到。
非常感谢任何见解或建议!
下面是我的SensorEventListener类中onSensorChanged代码。
public void onSensorChanged(SensorEvent event)
    {
        // If the sensor data is unreliable return
        if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        {
            Toast.makeText(main.this, "Sensor Status Unreliable",Toast.LENGTH_SHORT).show();
        }





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

        if (m_vfgravity != null && m_vfgeomag != null)
        {
            if(SensorManager.getRotationMatrix(m_vfinR, m_vfI, m_vfgravity, m_vfgeomag))
            {
                SensorManager.getOrientation(m_vfinR, m_vforientVals);

                m_fCompBearing = (float) Math.round((Math.toDegrees(m_vforientVals[0])) *2)/2;

                //convert to 0-360 from -180-180
                if(m_fCompBearing < 0.0)
                {
                    m_fCompBearing = 360 + m_fCompBearing;
                }


                mCompHead.setText("" + (int)m_fCompBearing);
            }

            calcOffset();   
            rotateCmp();
        }
    }

我的代码在活动的onCreate方法中

    mSMngr = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mSListener = new cSensorListener();

    mSMngr.registerListener(mSListener,
            mSMngr.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
            SensorManager.SENSOR_DELAY_UI);
    mSMngr.registerListener(mSListener,
            mSMngr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
            SensorManager.SENSOR_DELAY_UI);

提前致谢!

编辑:我还尝试了使用Droid X,但效果最差...当手机旋转约45度(围绕z轴旋转计算机坐标系)时,指南针的方向可能会改变超过180度。实际上,当以相同方向旋转时,该方向值与其他手机相反。即使在设置中进行校准,这是唯一会产生此结果的手机。同时,有一个指南针动态壁纸我用来测试也没有同样的问题。因此,我认为在软件中应该有一些可以避免这个问题的解决方法。


你确定是Android的问题而不是硬件问题吗? - Jim Clay
一个明显的差异来源可能是磁北极和真北极。顺便说一下,我的基本 garmin gps 设备如果你在原地转圈不动,它会指向正前方。使用这些基本的 GPS 设备的唯一方法是将其指向行进方向并向前移动。这可能与您的问题无关,但是? - JAL
首先感谢您的快速回答。传感器管理器始终应返回磁北,GPS会返回真北,因为它使用基于真北的纬度/经度运动方向。至于它是否是硬件问题,这是可能的,但我见过一些应用程序在所有设备上返回类似的结果,想知道它们是如何做到的。我也测试了DroidX,结果差异很大,我的指南针图像甚至朝相反方向旋转? - ocross
3个回答

34
尽管作者回答了自己的问题,但我必须在这里发表意见,以强调安卓平台上任何指南针功能的几乎完全无用性。 我得出的结论是,任何依赖安卓指南针应用程序的人都会遇到麻烦,它们都不能可靠地工作,而这不是开发者的错。 谷歌和制造商根本没有提供一种可靠获取这些设备的精确度的方法,甚至不能确定其精确度是否可靠,这更糟糕,因为有时它们是可靠的,而很多时候它们不可靠,如果有人信任这些设备进行真正的导航定位,那么上帝保佑他们!作者认为他得到更好结果的原因可能是他们对已弃用的方向传感器使用了相当好的噪声滤波器(为什么他们不能在更新的方法上这样做我不知道),并且在单个设备上经过校准的受限测试中,这似乎有效,但在使用多个设备的领域测试中,我发现大部分可靠性总是值得怀疑。 首先,从磁性和方向传感器产生的噪声是可怕的,是的,这可以通过适当的DSP技术克服,并且随着2.3和启用陀螺仪的电话,整体情况将变得更好,但谷歌和制造商浪费了如此多的开发人员时间进行低劣的硬件和软件输出实现真是太丢人了。其次,我测试了至少18个已经放置适当的DSP过滤器的电话,虽然这清除了噪声,但对于准确性没有帮助,即使是同一型号的手机也有不同的输出(尽管有些型号似乎比其他型号更好)第三,您很少能确定传感器是否校准,即使进行抽波状图案并不一定会校准手机,而用户永远不知道它是否工作,除非您有指南针进行验证,但这有点毫无意义。 注意:您可以将磁性传感器相互乘以并相加,并取该sqrt(x * x + y * y + z * z)的平方根,确保它在25到65之间左右,这是您可以用来检测异常场的一个指标,但它并不完全可靠,比没有好吧。第四,许多手机无论是否校准,都可能完全不可靠,这不仅限于型号类型,而且可能是生产商在质量保证方面做得不好。我真的不知道为什么,但我可以说,3个HTC ARIA产生了非常不同的结果(其中一个偏离30度,另一个50度,第三个几乎准确),Incredible、Nexus等也是如此。
我测试了18个手机,如果您能正确校准,很多手机都可以接近准确,但其中许多需要尝试2-10次才能校准成功(我们在每次校准尝试后使用高精度指南针进行验证),而且有时它们根本无法校准。
注意:您必须考虑磁偏角以获得真正的北向偏移,如果您可以访问当前GPS坐标、高度、时间等API,则可以在Android中执行此操作。问题并不是磁偏角,如果您正在将其与指南针进行比较,那么这也不是一个问题,因为它也会受到局部磁场的影响。
第五,每个经过测试的手机在冷启动时始终需要进行校准步骤,包括X、Incredible、Aria、Nexus和Thunderbolt。换句话说,在开始传感器监听时,95%的时间都需要进行校准步骤(即使是坏了的时钟一天也会显示正确两次),所以如果您要添加此功能,我建议告诉用户在每个监听器事件开始时进行校准。
如果您让传感器处于运行状态(对电池不利),那么可能需要重新校准,这种方法对此很有效。
总之,当它们工作时,它们似乎很酷,但您永远无法确定方位角的准确性,这使它们非常不可靠,对于任何实际工作都是没有用的。
个人而言,我会在移动时使用GPS方向,然后尽可能使用旋转向量方法,这可能不是完美的,但肯定比当前手机系列中用于方位角的糟糕实现要好得多。

非常抱歉回复过长,但是我花了将近一个月的时间试图在一位专业的DSP工程师的帮助下让这个工作起来,并且我们已经基本上放弃了安卓平台在这方面的应用。

在我看来,“有时候它能正常工作,有时候又不行,除非你有真正的罗盘,否则你永远无法确定”的免责声明应该放在每个罗盘应用程序中。


2
是的,我同意你的观点。我得出结论,你必须认识到,在大多数设备上(只测试了6个),读数似乎会有一个+-30度的误差范围,它在一个范围内保持稳定,大约为10左右。至于我为什么说方向传感器是解决方法,是因为Droid X根本不起作用。当其他设备的误差较小时,读数与正确值相差甚远,而切换到方向传感器后,X的工作方式类似于其他设备。降噪效果很好,但在获取值后,我已经自己进行了低通滤波。 - ocross
这种类型的帖子既是福音又是诅咒:我原本打算依靠加速度计来确定方向(另一种不太可靠的方法),但我想知道从一开始就切换到磁力计来确定方向是否更好。由于我需要逐步准确地读取方向,加速度计不起作用,指南针似乎也不起作用,那还剩下什么呢?GPS足够可靠吗?即使有天际线干扰? - ravemir
1
@ravemir 请记住,情况正在变得越来越好。真正的问题是它不是普遍适用的(有些手机很好,而其他手机则很差),这才是真正的问题。如果你移动的速度比几英里/小时或几公里/小时快,并且信号良好,GPS就可以使用,但只有在你考虑前进方向时才有效(当然,如果你能获得旋转向量等,向右移动时向左转弯是行不通的)。你需要良好的传感器和传感器融合才能使所有这些可靠地工作,这正在发生,但你不能指望它已经到位了。 - Idistic
方向确实是向前的方向,但我不确定奔跑是否构成了“比几英里每小时更快”的概念。如果确实如此,那么我肯定浪费了很多时间在一些不值得的事情上 xD - ravemir
我对你的误差边界印象深刻 - 在步行或驾车时,我通常会忽略手机指南针标记,因为它通常与实际方向相差40-80度,有时甚至更多。 - nsandersen
显示剩余2条评论

3
经过多次测试和调试,我得出结论:正如你们中的一些人所提到的那样,我的Droid 1和Nexus S之间的差异纯粹是硬件差异和磁干扰。
然而,Droid X是一个不同的问题,无论我尝试什么,都无法从使用getRotationMatrix和getOrientation推荐的方式中获得正确的读数,即使添加了重新映射坐标函数。因此,在经过一些试验后没有成功,我想我会尝试一下方向传感器的方法。
谷歌表示,这种方法已被弃用,他们建议按照我最初开始的方式进行操作,然而,我尝试了所有类型的组合,但没有成功。所以,我决定忽略他们的警告并使用方向传感器……它起作用了。为什么?我不知道,Droid X比我的Droid 1更新,所以它不应该与使用旧代码有关。然而,这解释了为什么罗盘应用程序编写目标为1.6将起作用,而我的应用程序使用“推荐方式”却无法工作。
如果有人知道更好的方法,请告诉我,或者如果您知道一种可以使用getRotationMatrix和getOrientation的方法,请告诉我。
否则,对于任何遇到像我一样困难的人,这里是最后起作用的代码。
我的传感器变化函数。
        switch (event.sensor.getType())
        {
        case Sensor.TYPE_ORIENTATION:
            m_vforientVals = event.values.clone();
            break;
        }

        if(m_vforientVals != null)
        {
            m_fCompBearing = m_vforientVals[0];             


            mCompHead.setText("" + (int)m_fCompBearing);

            calcOffset();   
            rotateCmp();
        }

并初始化传感器监听器

    mSMngr.registerListener(mSListener,mSMngr.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                            SensorManager.SENSOR_DELAY_NORMAL);

2

我认为你的代码没有问题,如果代码有错误,我相信两个设备都会受到影响。我认为是设备硬件引起了差异。

你是否通过在手机上画八字形来“校准”两个罗盘?许多罗盘应用程序都建议这样做,包括Symbian设备附带的地图软件。这可能有效。


谢谢你的回复,你提到了一个很好的观点——校准可以产生很大的差异,使罗盘不可靠。不幸的是,在测试之前,我忘记了提及这一步骤(我现在已经编辑了)。我将再试一次,并进行更长时间的校准,以查看是否有更好的结果。 - ocross

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