指南针和加速度计精度
我在 Android 中制作了自己的应用程序,它使用指南针和加速计传感器来显示设备的旋转和倾斜度数。我初始化了我需要的所有监听器和对象(我遵循了一些教程),现在我可以按照我的意愿捕获学位。问题在于传感器返回的测量结果不准确。我的意思是,即使我尝试对从传感器捕获的度数值进行四舍五入,它们也会每秒在 -/+ 7(或 8)度之间振荡,即使我呆在远离任何干扰源的草地上。我想要的是精确的度数测量,类似于对从传感器收到的值进行四舍五入的方法。
float[] mags = null;
float[] accels = null;
float[] R = new float[matrix_size];
float[] outR = new float[matrix_size];
float[] I = new float[matrix_size];
float[] values = null;
private void startSensor() {
sensorMan.registerListener(this, sensorMan.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
sensorMan.registerListener(this, sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
return;
}
switch (event.sensor.getType()) {
case Sensor.TYPE_MAGNETIC_FIELD:
mags = event.values.clone();
break;
case Sensor.TYPE_ACCELEROMETER:
accels = event.values.clone();
break;
}
if (mags != null && accels != null) {
SensorManager.getRotationMatrix(R, I, accels, mags);
// Correct if screen is in Landscape
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X,
SensorManager.AXIS_Z, outR);
SensorManager.getOrientation(outR, values);
azimuth = (float) Math.round((Math.toDegrees(values[0]))*7)/7;
azimuth = ( azimuth + 360)%360;
//here is inclination. The problem is just the same with compass
//inclination=-Math.round((float) (values[1]*(360/(2*Math.PI))));
//other code to update my view
//in azimuth i have the degree value. It changes continuously
//even if i aim still the same direction
}
}
i made my own application in Android that use compass and accelerometer sensors to display the degrees of rotation and inclination of my device. I initialized all the listener and objects i needed (i followed some tutorials), and now i can catch the degrees as i wished. The problem is that the measures that sensors return aren't accurate. I mean even if i try to round the values of degrees i catch from the sensor, they oscillate between -/+ 7 (or 8) degrees every fraction of a second, even if i stay in a grass field away from any disturbing source. What i want to have is a accurate measure of the degrees, something like a method to round the values i recieve from the sensors.
float[] mags = null;
float[] accels = null;
float[] R = new float[matrix_size];
float[] outR = new float[matrix_size];
float[] I = new float[matrix_size];
float[] values = null;
private void startSensor() {
sensorMan.registerListener(this, sensorMan.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI);
sensorMan.registerListener(this, sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) {
return;
}
switch (event.sensor.getType()) {
case Sensor.TYPE_MAGNETIC_FIELD:
mags = event.values.clone();
break;
case Sensor.TYPE_ACCELEROMETER:
accels = event.values.clone();
break;
}
if (mags != null && accels != null) {
SensorManager.getRotationMatrix(R, I, accels, mags);
// Correct if screen is in Landscape
SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X,
SensorManager.AXIS_Z, outR);
SensorManager.getOrientation(outR, values);
azimuth = (float) Math.round((Math.toDegrees(values[0]))*7)/7;
azimuth = ( azimuth + 360)%360;
//here is inclination. The problem is just the same with compass
//inclination=-Math.round((float) (values[1]*(360/(2*Math.PI))));
//other code to update my view
//in azimuth i have the degree value. It changes continuously
//even if i aim still the same direction
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
平滑来自传感器的数据
请在此处查看我的答案:我运行的 在将加速度计和磁力计事件值传递给
SensorManager.getRotationMatrix()
之前,会对其进行过滤。我认为该算法的优点是不必保留大量历史值,只需保留先前的低通输出数组。该算法源自此维基百科条目: http://en.wikipedia.org/wiki /低通滤波器#Algorithmic_implementation
See my answer here: Smoothing data from a sensor
I run this filter on both the accelerometer and magetometer event values before passing them to
SensorManager.getRotationMatrix()
. I think this algorithm has the advantage of not having to keep a large array of historic values, just the prior low-pass output array.The algorithm was derived from this Wikipedia entry: http://en.wikipedia.org/wiki/Low-pass_filter#Algorithmic_implementation
您所看到的是真实的东西 - 大多数手机上的方向传感器只能为您提供粗略的指南针方向。
如果你想平滑显示的值,以便它给你一些看起来不会随机变化的东西,我建议实现 http://en.wikipedia.org/wiki/Moving_average 或 Java 中针对该方向结果的其他平滑滤波器。
为了获得最高性能,您可以使用 NDK 编写过滤器并使用 Boost Accumulators 库: http://www.boost.org/doc/libs/1_46_1/doc/html/accumulators.html
What you're seeing is the real thing- the orientation sensors on most phones are only good enough to give you a rough compass heading.
If you want to smooth the displayed value out so it gives you something that's doesn't appear to change randomly I recommend implementing a http://en.wikipedia.org/wiki/Moving_average or other smoothing filter in Java on that orientation result.
For the highest performance you could write the filter using the NDK and use the Boost Accumulators library: http://www.boost.org/doc/libs/1_46_1/doc/html/accumulators.html
我使用卡尔曼滤波器从这里做到了这一点:
Greg Czerniak 的网站
我正在将数据发送到 udp 端口并使用 python 在 PC 上进行平滑处理。
但我想你可以在那里找到 java/android 的卡尔曼滤波器实现。
I did this using a Kalman filter from here:
Greg Czerniak's Website
I'm sending data to a udp port and smoothing it on the PC using python.
But I guess you can find a Kalman filter implementation for java/android out there.