方位角/偏航和横滚Android上不一致的方位传感器值(Inconsistent orientati

2019-08-17 19:29发布

我无法获得良好的方向传感器读数。 该传感器读数显得不可靠,所以我测试我的代码对两个自由传感器测试应用( 传感器测试仪(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;
    }

}

我使用的是Galaxy Note的2运行果冻豆4.1.1。 谁能告诉我,我做错了什么?

更新24-MAR-2013:更多的信息。 (1)我在清单纵向和横向之间切换禁用,所以getWindowManager()。getDefaultDisplay()。getRotation()始终为零。 因此,我不认为remapCoordSystem将帮助这里,因为这是用于开关的轴,而说我看到的错误都没有大的失误,他们更微妙。 (2)我们检查的准确性灵敏度,并且当两个传感器声称具有高的精度发生不一致。

作为我看到的不一致的一个例子中,当上述代码给我(方位角,俯仰,滚动)=(235,-52,-11),则两个自由应用上显示相似的值。 但是,当我看到(278,-58,-52)的应用上显示(256,-58,-26),在这两个方位和滚动这么大的差异,但好像间距确定。

Answer 1:

我想定义你的方向的最好办法角度时,该设备是不平坦的是使用标准的欧拉角,你从得到一个更合适的角度坐标系SensorManager.getOrientation(...) 我认为,我描述了一个在这里math.stackexchange.com 。 我也把一些代码,不会实现它的答案在这里 。 除了方位的一个很好的定义,它也有桨距角,其中该方法定义为旋转出水平平面,而不管其中的轴线发生沿着旋转的一个更好的定义。

你可以从我在第一段已经给这两个环节的全部细节。 但是,总的来说,从SensorManager.getRotationMatrix你的旋转矩阵R(...)是

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



Answer 2:

这一切都依赖于设备的方向 。 如果设备不平整且有一定的旋转 ,即不太纵向横向 ,然后方位角是错误的。 你必须调用remapCoordSystem调用之前getOrientation在这种情况下。 你也应该至少过滤加速计值。
欲了解更多详情请参阅我的答案在转换磁场X,Y,Z值从设备到全局参考坐标
而对于平整度的含义看到如何在Android中使用加速度计来测量手机在XY平面倾斜

您应该测试您的应用程序如下:

  1. 把你的设备平坦,开始您的应用程序,并与其他应用比较你的价值。 给每个读数约30秒,并在此步骤中不要移动设备。
    我给这一步的猜测:您的值应该差别不大从其他应用价值,但它可能是在开始的时候比其他应用程序不太稳定。

  2. 当你的应用程序正在运行,旋转你的设备到新的位置,等到成为稳定的值(不必是相同的值,但变化是大约1或2度)。 在同一位置的值进行比较的其他应用价值。 重复同样的事情,但与其他应用程序运行时旋转。
    我给这一步的猜测:你的稳定值应该差别不大从其他应用程序的值,但它需要更长的时间你的价值,成为稳定。 此外,当停在新位置的前几个值和稳定值之间的差额是您的应用程序比另一个大。

  3. 现在,把下面的代码之前的注释//转储到logcat的和记录它,你的方向做
    浮旋转=(浮点)Math.atan2(RotationMatrix [6],RotationMatrix [7]);
    把你的设备在直立的位置在一个盒子里,这样它不能转动。 确保上面给出的旋转值是接近0越好(它会跳一点点)。
    与直立的设备重复步骤1和2现在。
    我的猜测是,你的结果会是一样的我猜测上述步骤1和2。

  4. 把你的设备倾斜的直立的位置在一个盒子里,这样它不能进一步旋转。 确保上面给出的旋转值是接近25或-25越好(它会跳一点点)。
    现在直立倾斜设备重复步骤1。
    我的猜测是,你的结果将是从其他应用程序完全不同。
    你可以重复使用不同的旋转值第4步。

如果我的猜测是正确的回来,我会给你解释。 与此同时,你可以在阅读我的回答磁场,旋转矩阵全局坐标



Answer 3:

我能回答这个问题的一部分。 一切都会好起来当设备在桌子上放平,但是当它是直立并且间距为正负90度,那么你会遇到万向锁 。 发生这种情况时,方位和轧辊是不确定的。 在这种情况下方位和滚动意思是一样的,如果你看看数学,你会看到一个显示azumith +卷被定义(当间距= +90度)或方位角卷被定义(当间距= -90度),但他们两个都没有对自己的定义。 在你给的例子,发现和方位+卷约你的应用程序和其他应用程序之间的相同。

此外,您还可以使用Android Sensor.TYPE_GRAVITY,这样你就不需要在加速度计读数使用低通滤波器。 Sensor.TYPE_GRAVITY是从其他传感器计算,试图消除加速度的从加速度传感器的影响的传感器。 但是,如果你想你的应用程序上推出Sensor.TYPE_GRAVITY之前老版Android上运行,那么你就需要自己做的工作。



Answer 4:

@Stochastically说的getOrientation(),使用方法:

azimuth = atan2((Ey-Nx), (Ex-Ny))

但是,如果你看一下Android的实现,它实际上是

azimuth = atan2(Ey, Ny)

这也将会给你值的-180到180的范围内。

下面是SensorManager.class给出的源代码

public static float[] getOrientation(float[] R, float values[]) {
    /*
     * 4x4 (length=16) case:
     *   /  R[ 0]   R[ 1]   R[ 2]   0  \
     *   |  R[ 4]   R[ 5]   R[ 6]   0  |
     *   |  R[ 8]   R[ 9]   R[10]   0  |
     *   \      0       0       0   1  /
     *
     * 3x3 (length=9) case:
     *   /  R[ 0]   R[ 1]   R[ 2]  \
     *   |  R[ 3]   R[ 4]   R[ 5]  |
     *   \  R[ 6]   R[ 7]   R[ 8]  /
     *
     */
    if (R.length == 9) {
        values[0] = (float)Math.atan2(R[1], R[4]);
        values[1] = (float)Math.asin(-R[7]);
        values[2] = (float)Math.atan2(-R[6], R[8]);
    } else {
        values[0] = (float)Math.atan2(R[1], R[5]);
        values[1] = (float)Math.asin(-R[9]);
        values[2] = (float)Math.atan2(-R[8], R[10]);
    }
    return values;
}


文章来源: Inconsistent orientation sensor values on Android for azimuth/yaw and roll