在Android上不一致的方向传感器的值方位/偏航和滚转传感器、方位、方向、偏航

2023-09-05 04:28:03 作者:醒悟了

我无法获得良好的方向传感器读数。该传感器读数显得不可靠的,所以我测试了我的code对两个自由传感器测试的应用程序(的传感器测试仪(Dicotomica)和的传感器监测(R的软件))。我发现,而我的读数通常同意传感器测试应用程序,偶尔为方位角/偏航和滚转高达40度不同的值,虽然音调读大多同意。这两个免费的应用程序似乎总是同意对方。

I’m having trouble getting good orientation sensor readings. The sensor readings seemed unreliable, so I tested my code against two free sensor test apps (Sensor Tester (Dicotomica) and Sensor Monitoring (R's Software)). I found that while my readings often agreed with the sensor test apps, occasionally the values for azimuth/yaw, and roll differed by up to 40 degrees, although the pitch reading mostly agreed. The two free apps always seemed to agree with each other.

我把我的code到一个微小的机器人活动,并得到了相同的不一致。在code是如下:

I put my code into a tiny Android activity and got the same inconsistency. The code is as follows:

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。谁能告诉我什么,我做错了什么?

I’m using a Galaxy Note 2 running Jelly Bean 4.1.1. Can anyone tell me what I’m doing wrong?

更新24-MAR-2013:更多信息。 (1)我有肖像和风景在清单中的禁用开关,所以getWindowManager()。getDefaultDisplay()。getRotation()始终为零。因此,我不认为remapCoordSystem会有所帮助,因为这对开关的轴,而说我看到的错误都没有大的失误,他们更微妙。 (2)我已经检查的准确性灵敏度,当两个传感器声称拥有高精度的矛盾发生。

Update 24-Mar-2013: More information. (1) I've disabled switches between portrait and landscape in the manifest, so getWindowManager().getDefaultDisplay().getRotation() is always zero. Hence I don't think remapCoordSystem would help here, because that's for switching axes, whereas the errors that I'm seeing aren't big errors, they're much more subtle. (2) I've checked the accuracy sensitivity, and the inconsistencies occur when both sensors claim to have high accuracy.

由于是我看到的不一致的例子,当code以上给我(方位角,俯仰,滚动)=(235,-52,-11),那么这两个免费的应用程序表现出相似的价值观。但是,当我看到(278,-58,-52)的应用程序显示(256,-58,-26),在这两个方位和滚这么大的差异,虽然间距似乎确定。

As an example of the inconsistencies that I'm seeing, when the code above give me (azimuth,pitch,roll) = (235,-52,-11) then the two free apps show similar values. But when I see (278, -58, -52) the apps show (256, -58, -26), so big differences in both Azimuth and roll, although pitch seems OK.

推荐答案

我想确定你的方向的最好办法角度时,该设备是不平坦是使用更合适的角度统筹制度,标准的欧拉角您从获得SensorManager.getOrientation(...)。我建议,我描述了一个here在math.stackexchange.com 。我也把一些code,它实现它的an回答这里。除了方位的一个很好的定义,它也有桨距角,​​其中该方法定义为旋转出水平面不论其轴线发生沿着旋转的一个更好的定义。

I think the best way of defining your orientation angles when the device isn't flat is to use a more appropriate angular co-ordinate system that the standard Euler angles that you get from SensorManager.getOrientation(...). I suggest the one that I describe here on math.stackexchange.com. I've also put some code that does implements it in an answer here. Apart from a good definition of azimuth, it also has a better definition of the pitch angle, which this methodology defines as rotation out of the horizontal plane irrespective of which axis the rotation occurs along.

您可以从我在第一段所给出的两个环节全部细节。但是,总的来说,你的旋转矩阵研究从SensorManager.getRotationMatrix(...)为

You can get full details from the two links that I've given in the first paragraph. However, in summary, your rotation matrix R from SensorManager.getRotationMatrix(...) is

其中,(E X ,E 是,E 以Z ),(N X ,N 是,N 以Z )和(G X ,G 是,G 以Z )是向量指向正东,北,并在重力的方向。然后你想要的方位角是由

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