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

2023-11-21

我无法获得良好的方向传感器读数。传感器读数似乎不可靠,因此我针对两个免费的传感器测试应用程序测试了我的代码(传感器测试仪(Dicotomica) and 传感器监控(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;
    }

}

我使用的是运行 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),方位角和滚动角差异很大,尽管俯仰角似乎还不错。


我认为当设备不平坦时定义方向角的最佳方法是使用更合适的角度坐标系,即您从标准欧拉角获得的角度坐标系SensorManager.getOrientation(...)。我建议我所描述的那个在 math.stackexchange.com 上。我还放置了一些实现它的代码这里有一个答案。除了方位角的良好定义之外,它还对俯仰角有更好的定义,该方法将俯仰角定义为水平面之外的旋转,无论旋转沿哪个轴发生。

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

Definition of rotation matrix R

where (Ex, Ey, Ez), (Nx, Ny, Nz) and (Gx, Gy, Gz) are vectors pointing due East, North, and in the direction of Gravity. Then the azimuth angle that you want is given by

Definition of azimuth angle phi

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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