Android上方位角/偏航和滚动的方向传感器值不一致

gis*_*ing 5 android orientation android-sensors sensormanager

我无法获得良好的方向传感器读数.传感器读数似乎不可靠,因此我针对两个免费传感器测试应用程序(传感器测试仪(Dicotomica)传感器监测(R软件))测试了我的代码.我发现虽然我的读数经常与传感器测试应用程序一致,但偶尔方位角/偏航和滚动的值差异高达40度,尽管音高读数大多是一致的.两个免费的应用程序似乎总是彼此一致.

我将我的代码放入一个微小的Android活动中,并得到了同样的不一致.代码如下:

public class MainActivity extends Activity implements  SensorEventListener {

    private SensorManager mSensorManager;
    private float[] AccelerometerValues;
    private float[] MagneticFieldValues;
    private float[] RotationMatrix;
    private long nextRefreshTime;           // used to ensure dump to LogCat occurs no more than 4 times a second
    private DecimalFormat df;               // used for dumping sensors to LogCat

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mSensorManager = (SensorManager)getSystemService(android.content.Context.SENSOR_SERVICE);
        Sensor SensorAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensorManager.registerListener(this, SensorAccelerometer, SensorManager.SENSOR_DELAY_UI);  
        Sensor SensorMagField = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        mSensorManager.registerListener(this, SensorMagField, SensorManager.SENSOR_DELAY_UI);
        AccelerometerValues = new float[3];
        MagneticFieldValues = new float[3];
        RotationMatrix = new float[9];
        nextRefreshTime = 0;
        df = new DecimalFormat("#.00");
    }

    @Override
    public void onSensorChanged(SensorEvent event) {

        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
            System.arraycopy(event.values, 0, AccelerometerValues, 0, AccelerometerValues.length);
        else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
                System.arraycopy(event.values, 0, MagneticFieldValues, 0, MagneticFieldValues.length);

        if (AccelerometerValues != null && MagneticFieldValues != null) {
            if(SensorManager.getRotationMatrix(RotationMatrix, null, AccelerometerValues, MagneticFieldValues)) {
                float[] OrientationValues = new float[3];
                SensorManager.getOrientation(RotationMatrix, OrientationValues);

                // chance conventions to match sample apps
                if (OrientationValues[0] < 0) OrientationValues[0] += 2*(float)Math.PI;
                OrientationValues[2] *= -1;

                // dump to logcat 4 times a second
                long currentTimeMillis = System.currentTimeMillis();
                if (currentTimeMillis > nextRefreshTime) {
                    nextRefreshTime = currentTimeMillis+250;
                    Log.i("Sensors",    // arrange output so that numbers line up in columns :-)
                            "(" + AngleToStr(OrientationValues[0]) + "," + AngleToStr(OrientationValues[1]) + "," + AngleToStr(OrientationValues[2])
                            + ") ("+FloatToStr(AccelerometerValues[0]) + "," + FloatToStr(AccelerometerValues[1]) + "," + FloatToStr(AccelerometerValues[2])
                            + ") ("+FloatToStr(MagneticFieldValues[0]) + "," + FloatToStr(MagneticFieldValues[1]) + "," + FloatToStr(MagneticFieldValues[2])+")");
                }               
            }
        }               
    }

    private String AngleToStr(double AngleInRadians) {
        String Str = "   "+Integer.toString((int)Math.toDegrees(AngleInRadians));
        return Str.substring(Str.length() - 3);
    }
    private String FloatToStr(float flt) {
        String Str = "      "+df.format(flt);
        return Str.substring(Str.length() - 6);
    }   

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mSensorManager.unregisterListener(this);
    }

    @Override
    public void onAccuracyChanged(Sensor arg0, int arg1) { }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}
Run Code Online (Sandbox Code Playgroud)

我正在使用运行Jelly Bean 4.1.1的Galaxy Note 2.谁能告诉我我做错了什么?

2013年3月24日更新:更多信息.(1)我在清单中禁用了纵向和横向之间的切换,因此getWindowManager().getDefaultDisplay().getRotation()始终为零.因此我不认为remapCoordSystem会对此有所帮助,因为那是用于切换轴的,而我所看到的错误不是大错误,它们更加微妙.(2)我检查了准确度灵敏度,当两个传感器声称具有高精度时会出现不一致.

作为我看到的不一致的一个例子,当上面的代码给我(方位角,俯仰,滚动)=(235,-52,-11)时,两个免费应用程序显示相似的值.但是当我看到(278,-58,-52)应用程序显示(256,-58,-26)时,方位角和滚动都有很大差异,尽管音高似乎没问题.

Sto*_*lly 6

我认为在设备不平坦时定义方向角的最佳方法是使用更合适的角坐标系,而不是从SensorManager.getOrientation(...). 我建议我在 math.stackexchange.com 上描述的那个。我还在这里的答案中放了一些实现它的代码。除了方位角的良好定义外,它还对俯仰角进行了更好的定义,该方法将其定义为从水平面旋转,而不管旋转沿哪个轴发生。

您可以从我在第一段中提供的两个链接中获得完整的详细信息。但是,总而言之,SensorManager.getRotationMatrix(...) 中的旋转矩阵R

旋转矩阵R的定义

其中(E X,E ÿ,E Ž),(N X,N ÿ,N Ž)和(G X,G ÿ,G Ž)是由于东,北指向矢量,并且在重力的方向。然后你想要的方位角由下式给出

方位角 phi 的定义

  • @Hoosier 好问题,因为正如您所说,通常的反正切返回 -90 到 90 度区域内的数字。答案是使用 Atan2 (http://en.wikipedia.org/wiki/Atan2),它在我使用的两种语言(即 C# 和 Java)中都可用。 (2认同)
  • 谢谢。它是这样工作的。mAzimuthAngleNotFlat = (int) Math.toDegrees(Math .atan2((rotationMatrix[1] - rotationMatrix[3]), (rotationMatrix[0] + rotationMatrix[4]))); if (mAzimuthAngleNotFlat &lt; 0) { mAzimuthAngleNotFlat += 360; } (2认同)

Hoa*_*yen 5

这一切都取决于设备的方向.如果设备不平坦并且有一些旋转,即不完全是纵向横向,则方位角是错误的.在这种情况下,你必须remapCoordSystem先打电话getOrientation.您还应该至少过滤加速度计值.
有关更多详细信息,请参阅我的答案,将磁场X,Y,Z值从设备转换为全局参考系
.有关平直度的含义,请参阅如何使用Android中的加速度计测量手机在XY平面中的倾斜度

您应该按照以下方式测试您的应用:

  1. 将您的设备平放并启动您的应用,并将您的价值与其他应用进行比较.每次读数大约30秒,并且在此步骤中不要移动设备.
    我对这一步的猜测:你的价值应该与其他应用价值差异很小,但它在开始时可能不如其他应用程序稳定.

  2. 在您的应用程序运行时,将设备旋转到新位置,等待值稳定(不必是相同的值,但变化大约是1或2度).在相同位置将您的值与其他应用值进行比较.重复相同的事情,但旋转时其他应用程序正在运行.
    我对此步骤的猜测:您的稳定值应与其他应用程序值略有不同,但您的值变得稳定需要更长时间.此外,当停在新位置时,您的应用程序的前几个值与稳定值之间的差异要大于另一个.

  3. 现在将以下代码放在注释// dump到logcat之前,然后像对着方向一样将其记录为
    float rotation =(float)Math.atan2(RotationMatrix [6],RotationMatrix [7]);
    将设备竖直放置在盒子中,使其无法旋转.确保上面给出的旋转值尽可能接近0(它会稍微跳一下).
    现在重复步骤1和2,设备直立.
    我的猜测是你的结果与我对上面步骤1和2的猜测相同.

  4. 将您的设备倾斜竖直放置在一个盒子中,这样它就不能再进一步旋转.确保上面给出的旋转值尽可能接近25或-25(它会略微跳跃).
    现在重复步骤1,设备直立倾斜.
    我的猜测是你的结果与其他应用程序完全不同.
    您可以使用不同的旋转值重复步骤4.

如果我的猜测是对的,我会给你解释.与此同时,您可以在磁场,旋转矩阵和全局坐标中阅读我的答案