android 指南针似乎不可靠
过去几天我一直在开发一个小型指南针应用程序,并且已经启动并运行了代码,但指南针读数似乎不准确。校准两部手机后,我的第一次测试发现了这一点,我只是将手机放在平坦的表面上查看读数,然后将其水平翻转并将其放在同一个平坦的表面上(180* 转),并且该值确实不改变 180* 它更接近 240*。
然后我将读数与指南针进行了比较,有时读数似乎很接近,但有时却相差 50* 以上。我什至尝试将手机和指南针放在地板上,以使指南针远离任何磁场干扰,并获得相同的结果(请注意,我还使指南针和手机分开,通过与书本边缘对齐来使它们保持在同一方向) 。
然后我将示例应用程序放在另一部手机上(第一部是 Nexus S,第二部是 Motorola droid 1)。两款手机之间的差异在某些点上是相等的,但在大多数点上相差 50 到 15 度之间。
我浏览了文档,还浏览了许多不同的论坛帖子,但没有看到任何人具有相同的结果。我的代码中可能存在一些小错误,导致我的阅读结果不正确,或者一些我没有看到的已记录的错误。
任何见解或建议将不胜感激!
这是我的 SensorEventListener 类中的传感器更改代码
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();
}
}
以及创建我的活动的代码
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 度以上,实际上是方向值当以相同方向旋转时,其移动方向与其他手机相反。这是唯一一款即使在设置中进行校准后也能产生此结果的手机。另外,他们是一个指南针动态壁纸,我测试它没有同样的问题。所以我认为我可以在软件中做一些事情来避免这种情况。
I have been working on a small compass app the past couple of days, and have gotten the code up and running, but it seems that the compass reading is not accurate. After calibrating both phones, my first test that i found this in what that i simply held the phone against and flat surface looked at the reading then flipped it horizontally and put it against the same flat surface (a 180* turn) and the value did not change 180* it was closer to 240*.
I then tested the reading vs a compass, at times the reading seemed to be close but at other points it was more than 50* off. I even tried to put my phone and compass on the floor to keep the compasses away from any magnetic interference with the same results (note i also keep the compass and phone apart keeping them in the same direction by lining up with edges of a book).
I then put the sample application on another phone (first was nexus S, second was Motorola droid 1). Between the two phones the difference ranges from being equal at some points but at most points being between 50 and 15 degrees off.
I have looked through the documentation and also looked through many different forum posts and I do not see anyone with the same results. There may be some small error in my code that is causing my reading to come out incorrectly, or some documented bug that I am not seeing.
Any insight or suggestions would be greatly appreciated!!
Heres my on sensor changed code in my SensorEventListener class
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();
}
}
And code in on create of my activity
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);
Thanks in advance!
Edit: also tried it with the droid X with the worst results yet... When the phone is rolled around 45 degrees (rotated around z axis a computer coordinate system) the compass heading returned can change over 180 degrees, in fact the heading value goes in the opposite direction of the other phones when spun in the same direction. This is the only phone that produces this result even after calibrating in the settings. Also their is a compass live wallpaper i test against that doesnt have the same issue. So I would assume there would be something i can do in software to avoid this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尽管作者回答了他自己的问题,但我还是必须在这里插话,只是为了强调 Android 平台上任何类型的指南针功能几乎完全无用。
我得出的结论是,任何依赖 Android 指南针应用程序的人都是自找麻烦,它们都不能可靠地工作,这不是开发人员的错。
谷歌和制造商根本没有提供一种方法来从这些设备获得可靠的准确性,甚至无法确定准确性是否可靠,这更糟糕,因为有时它们是可靠的,但很多时候它们不是,并且如果有人信任这些设备进行真正的定向运动愿上帝帮助他们。
作者可能认为他获得更好结果的原因是,他们在已弃用的方向传感器上使用了相当好的噪声滤波器(我无法理解为什么他们不能在较新的方法上做到这一点),并且在校准后在单个设备上进行了有限的测试。这似乎可行,但在使用许多设备的现场,我发现在大多数情况下,可靠性总是存在问题。
首先,磁性和方向传感器产生的噪音非常可怕,是的,这可以通过适当的 DSP 技术来克服,并且使用 2.3 和陀螺仪功能的手机,总体上会变得更好,但对 Google 和 Mfg 浪费如此多的开发人员时间感到羞耻硬件和软件输出的劣质实现。
,我已经测试了至少 18 款具有适当 DSP 滤波功能的手机,虽然这可以消除噪音,但对准确性没有帮助,即使是同一型号的手机也有不同的输出(尽管有些型号似乎比其他型号更好)。
其次 几乎无法确定传感器是否已校准,即使进行痉挛性的 8 字形运动也可能会或可能不会校准手机,用户永远不会真正知道它是否正常工作,除非你有一个指南针来验证,这是一种失败重点不是吗?
注意:您可以将磁传感器彼此相乘并求和,并取 sqrt(x*x+y*y+z*z) 的平方根,并确保它在 25 到 65 左右之间,这是您的一个指标可以用来检测异常场,但它并不完全可靠,我想总比没有好。
第四,许多手机完全不可靠,无论是否经过校准,这不仅限于型号类型,还可能是制造商的 QA 质量较差,我真的不知道为什么,但我可以说 3 款 HTC ARIA 产生了截然不同的结果(一部偏离了 30 度,另一部偏离了 50 度,第三部几乎准确无误)同样的事情,令人难以置信,Nexus 等。
我测试了 18 部手机,如果你可以校准的话,很多都非常接近准确正常,但其中许多尝试了 2-10 次(我们在每次校准尝试后都使用高精度指南针进行验证),并且有多次它们根本无法校准。
注意:您确实必须考虑真北偏移的赤纬,如果您可以访问当前的 GPS 坐标、海拔高度、一天中的时间等,则可以使用 Android 中的 API 来实现这一点。问题不是赤纬,如果您是与指南针相比,这无论如何都不是问题,因为它也会受到局部磁场的影响。
第五,冷启动总是需要我们测试的每部手机进行校准步骤,其中包括 X、令人难以置信的、Aria、Nexus 和 Thunderbolt。换句话说,第一次开始传感器监听时,95% 的时间都需要校准步骤(即使损坏的时钟每天也能正确两次),因此,如果您坚持添加此功能,我只会告诉您的用户在每个侦听器事件的开始。
如果您让传感器保持运行(对电池不利),那么您可能需要也可能不需要重新校准,具体取决于遇到的字段)上述方法可以正常工作。
最重要的是,当它们工作时,它们看起来很酷,但目前您永远无法确定方位角的准确性,这使得它们对于任何实际工作来说非常不可靠且无用。
就我个人而言,我会在移动时使用 GPS 方位,然后如果可能的话使用旋转矢量方法,它可能并不完美,但它会比当前手机中用于方位角的糟糕实现要好得多。
很抱歉冗长的回复,但我已经浪费了近一个月的时间试图在专家 DSP 工程师的帮助下让它工作,我们已经写了很多关于 Android 平台在这方面有用的文章。
我认为,“有时这有效,有时不行,除非你有真正的指南针,否则你永远无法确定”免责声明应该放在每个指南针应用程序中。
Even though the author answered his own question I have to chime in here just to reinforce the almost utter uselessness of any kind of compass functionality on the Android platform.
I have come to the conclusion that anyone that depends on an Android compass application is asking for trouble, none of them work reliably and it is not the fault of the developer.
Google and the mfg's simply have not provided a way to get reliable accuracy from these devices, or even to determine if the accuracy is reliable which is even worse because sometimes they are and many times they are not and if someone trusts these devices for real orienteering God help them.
The reason the author probably thinks he is getting better results is that they use a pretty good noise filter on the deprecated orientation sensor ( why they could not do this on the newer method is beyond me ) and in limited testing on a single device after calibration this will appear to work, but in the field using many devices I have found that for the most part the reliability is always in question.
First the noise generated from the magnetic and orientation sensors are horrible, yes this can be overcome with proper DSP techniques, and with 2.3 and gyro enabled phones it will get better overall, but shame on Google and the Mfg's for wasting so much developer time with shoddy implementations of hardware and software outputs.
Second, I have tested at least 18 phones with proper DSP filtering in place and while that cleans up the noise it does not help with accuracy, even the same model of phones have different outputs (though some models seem better than others)
Third you have little in the way of determining if the sensors are calibrated, even doing the spastic figure 8 motion may or may not calibrate the phone and the user never really knows if it's working or not, unless you have a compass to verify, which kind of defeats the point doesn't it?
NOTE: you can multiply and sum the magnetic sensors with each other and take the square root of that sqrt(x*x+y*y+z*z) and make sure it's between 25 and 65 or so, this is one indicator you can use to detect anomalous fields but it's not completely reliable, better than nothing I guess.
Fourth, many phones are completely unreliable, calibrated or not, which is not limited to model types but possibly shoddy QA on the part of the mfg, I really don't know why but I can say that 3 HTC ARIA's produced wildly different results (one 30 degrees off, the other 50, and a third almost spot on) same thing with incredible, nexus, etc.
I tested 18 phones and many were pretty close to accurate IF you could calibrate properly, but many of those took 2-10 try's ( we verified after each calibration attempt with a high precision compass ) and more than a few times they would simply NOT calibrate at all.
NOTE: you do have to account for declination for a true north offset, which you can do with the API in android if you have access to the current GPS coordinates, altitude, time of day etc. the problem was NOT declination and if you are comparing to a compass that's not an issue anyway since it will also be effected by local magnetic fields.
Fith, cold starts always require the calibration step on every phone we tested, which includes the X, the incredible, the Aria, the Nexus, and the Thunderbolt. In other words the first time you start sensor listening 95% of the time it will require a calibration step (even a broken clock is right twice a day) so if you insist on adding this functionality I would just tell your user to do it at the start of each listener event.
If you leave the senors running (bad for battery) then you may or may not have to re-calibrate depending on the fields it's encountered) the above method works ok for that.
The bottom line is that when they work they seem cool, but you can NEVER currently be sure of the accuracy of the azimuth, which makes them pretty unreliable and useless for any real work.
Personally I would use a GPS bearing while moving and then a rotation vector method if possible, it might not be perfect but it would be a heck of a lot better than the craptacular implementation that you have in the current line of phones for azimuth.
Sorry about the long winded reply but I have wasted almost a month on trying to get this to work with the help of an expert DSP engineer and we have pretty much written of the android platform as useful in this respect.
A "Sometimes this works, other times it won't, you can never be sure unless you have a real compass" disclaimer should be put in every compass application in my opinion.
经过大量测试和调试后。我得出的结论是,是的,正如你们中的一些人提到的,我的 droid 1 和 Nexus S 之间的差异纯粹是硬件差异和磁干扰。
然而,Droid X 是一个不同的问题,无论我尝试什么,即使添加了重新映射坐标功能,我也无法通过 getRotationMatrix 和 getOrientation 的推荐方式获得正确的读数。因此,经过一番修补但没有成功后,我想尝试一下方向传感器。
谷歌表示这种方式已被弃用,他们建议按照我开始的方式进行操作,但是我尝试了这种方式的所有类型的组合,但没有成功。所以我继续忽略他们的警告并使用方向传感器......并且它起作用了。为什么 ?我不知道,droid x 是比我的 droid 1 更新的操作系统,所以它不应该与使用遗留代码有关。然而,为什么写到目标 1.6 的指南针应用程序可以工作,而我的应用程序执行“推荐方式”却不起作用,这确实是有道理的。
如果有人有更好的方法来做到这一点,请告诉我,或者如果您知道一种使其与 getRotationMatrix 和 getOrientation 一起使用的方法,也请告诉我。
否则,对于像我一样遇到这堵砖墙的其他人来说,这里是最终为我工作的代码。
我的传感器发生变化
并初始化传感器侦听器
Well after much testing, and debugging. I came to the conclusion that yes as some of you mentioned the differences my droid 1 and Nexus S were purely hardware difference and magnetic interference.
However the Droid X was a different issue, whatever i tried i could not get the correct readings out of the recommended way with getRotationMatrix and getOrientation, even when added re-map coordinates function. So after some tinkering with no success i figured id give the Orientation sensor way a shot.
Google says that this way is deprecated and they recommend doing it the way i started off with, however i tried all types of combinations with that way with no success. So I went ahead and ignored thier warning and used the orientation sensor ... and it worked. Why ? i have no clue, the droid x is newer os than my droid 1 so it shouldn't have to do with using legacy code. However it does make sense why compass apps wrote to target 1.6 would work while my app doing the "recommended way" was not working.
If anyone has any better way to do this let me know, or if you know a way to make it work with getRotationMatrix and getOrientation also do tell.
Otherwise for anyone else who hits this brick wall as hard as I did heres the code that ended up working for me.
my on sensor changed
and initialize the sensor listener
你的代码对我来说看起来很好,如果你的代码中有错误,我很确定两个设备都会受到影响。我认为是设备中的硬件造成了差异。
您是否通过以 8 字形移动手机来“校准”两个指南针?许多指南针应用程序都建议这样做,包括 symbian 设备附带的地图软件。那可以工作
Your code looks fine to me, if there would be an error in your code I am pretty sure both devices would suffer from that. I think it's the hardware in the devices that's causing the differences.
Have you "calibrated" both compasses by moving the phone in figure eight shapes? Many compass apps suggest that, including the map software that comes with symbian devices. That could work