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

标签 android orientation android-sensors sensormanager

我无法获得良好的方向传感器读数。传感器读数似乎不可靠,因此我针对两个免费的传感器测试应用程序(Sensor Tester (Dicotomica)Sensor Monitoring (R's Software))测试了我的代码。我发现虽然我的读数通常与传感器测试应用程序一致,但方位角/偏航和横滚的值偶尔会相差高达 40 度,尽管俯仰读数基本一致。这两个免费应用程序似乎总是相互一致。

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

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) 我在 list 中禁用了纵向和横向之间的切换,因此 getWindowManager().getDefaultDisplay().getRotation() 始终为零。因此,我认为 remapCoordSystem 在这里不会有帮助,因为那是为了切换轴,而我看到的错误并不是大错误,它们要微妙得多。 (2) 我检查了精度灵敏度,当两个传感器都声称具有高精度时会出现不一致。

作为我看到的不一致的一个例子,当上面的代码给我 (azimuth,pitch,roll) = (235,-52,-11) 时,这两个免费应用程序显示相似的值。但是当我看到 (278, -58, -52) 应用程序显示 (256, -58, -26) 时,方位角和横滚角差异如此之大,尽管俯仰似乎没问题。

最佳答案

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

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

Definition of rotation matrix R

其中 (Ex, Ey, Ez), (Nx, N>y, Nz) 和 (Gx, Gy, Gz) 是矢量指向正东、正北和重力方向。然后你想要的方位角由下式给出

Definition of azimuth angle phi

关于android - Android 上的方位角/偏航和滚动方向传感器值不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15537125/

相关文章:

Android:SensorEvent 的 TYPE_PRESSURE 值在哪里?

android - 如何在获得加速度计测量值的同时获得方位角!ORIENTATION vs ACCELEROMETER

java - java中有没有存储条件语句的方法?

java - 从 Android 手机发送字符串到 PC

swift - 自动布局 [Snapkit] 更改旋转约束

swift - 改变方向时无法让 shouldautorotate 触发

java - Android 加速计 - 动态时间扭曲

android - 在 android studio 中导入并开发一个 ionic 项目

android - flutter : How to prevent rebuild of whole Reorderable Listview?

ios - 处理先前 UIViewController 的方向