0

我正在构建一个 Android 应用程序,它将设备的罗盘度数记录到一个文件中。有两种方法可以获得这个学位:

方法一:

SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor orientationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
mSensorManager.registerListener(this, orientationSensor, SensorManager.SENSOR_DELAY_NORMAL);


public void onSensorChanged(SensorEvent event) {
    float azimuthInDegrees = event.values[0]
}

方法二:

SensorManager mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL);
mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL);

float[] mGravity;
float[] mGeomagnetic;

public void onSensorChanged(SensorEvent event) {
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        mGravity = event.values.clone();
    }


    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
        mGeomagnetic = event.values.clone();
    }

    if (mGravity != null && mGeomagnetic != null) {
        float R[] = new float[9];
        float I[] = new float[9];
        boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic);
        if (success) {
            float orientation[] = new float[3];
        SensorManager.getOrientation(R, orientation);   

        float azimuthInDegress = ((float) Math.toDegrees(orientation[0]) + 360) % 360;
        }
    }
}

我尝试了这两种方法,将我的设备放在北方方向并做一个完整的顺时针 360 度循环,然后再次在北方方向结束。

方法 1返回以下记录的 JSON 数据:

[
   {
      "start time":"25-03-2013 20:42:11.071",
      "direction":"N",
      "end time":"25-03-2013 20:42:14.711"
   },
   {
      "start time":"25-03-2013 20:42:14.781",
      "direction":"NE",
      "end time":"25-03-2013 20:42:18.842"
   },
   {
      "start time":"25-03-2013 20:42:18.912",
      "direction":"E",
      "end time":"25-03-2013 20:42:21.643"
   },
   {
      "start time":"25-03-2013 20:42:21.712",
      "direction":"SE",
      "end time":"25-03-2013 20:42:25.072"
   },
   {
      "start time":"25-03-2013 20:42:25.142",
      "direction":"S",
      "end time":"25-03-2013 20:42:27.524"
   },
   {
      "start time":"25-03-2013 20:42:27.593",
      "direction":"SW",
      "end time":"25-03-2013 20:42:30.113"
   },
   {
      "start time":"25-03-2013 20:42:30.184",
      "direction":"W",
      "end time":"25-03-2013 20:42:32.773"
   },
   {
      "start time":"25-03-2013 20:42:32.843",
      "direction":"NW",
      "end time":"25-03-2013 20:42:34.943"
   },
   {
      "start time":"25-03-2013 20:42:35.013",
      "direction":"N",
      "end time":"25-03-2013 20:42:37.394"
   }
]

方法 2返回日志以下 JSON 数据:

[
   {
      "start time":"25-03-2013 20:36:07.337",
      "direction":"N",
      "end time":"25-03-2013 20:36:09.728"
   },
   {
      "start time":"25-03-2013 20:36:09.741",
      "direction":"NE",
      "end time":"25-03-2013 20:36:13.832"
   },
   {
      "start time":"25-03-2013 20:36:13.832",
      "direction":"E",
      "end time":"25-03-2013 20:36:16.689"
   },
   {
      "start time":"25-03-2013 20:36:16.754",
      "direction":"SE",
      "end time":"25-03-2013 20:36:16.754"
   },
   {
      "start time":"25-03-2013 20:36:16.819",
      "direction":"E",
      "end time":"25-03-2013 20:36:16.819"
   },
   {
      "start time":"25-03-2013 20:36:16.819",
      "direction":"SE",
      "end time":"25-03-2013 20:36:16.819"
   },
   {
      "start time":"25-03-2013 20:36:16.884",
      "direction":"E",
      "end time":"25-03-2013 20:36:17.014"
   },
   {
      "start time":"25-03-2013 20:36:17.014",
      "direction":"SE",
      "end time":"25-03-2013 20:36:19.546"
   },
   {
      "start time":"25-03-2013 20:36:19.546",
      "direction":"S",
      "end time":"25-03-2013 20:36:22.338"
   },
   {
      "start time":"25-03-2013 20:36:22.338",
      "direction":"SW",
      "end time":"25-03-2013 20:36:25.260"
   },
   {
      "start time":"25-03-2013 20:36:25.324",
      "direction":"W",
      "end time":"25-03-2013 20:36:25.324"
   },
   {
      "start time":"25-03-2013 20:36:25.324",
      "direction":"SW",
      "end time":"25-03-2013 20:36:25.390"
   },
   {
      "start time":"25-03-2013 20:36:25.390",
      "direction":"W",
      "end time":"25-03-2013 20:36:27.987"
   },
   {
      "start time":"25-03-2013 20:36:28.051",
      "direction":"NW",
      "end time":"25-03-2013 20:36:28.128"
   },
   {
      "start time":"25-03-2013 20:36:28.181",
      "direction":"W",
      "end time":"25-03-2013 20:36:28.181"
   },
   {
      "start time":"25-03-2013 20:36:28.181",
      "direction":"NW",
      "end time":"25-03-2013 20:36:28.181"
   },
   {
      "start time":"25-03-2013 20:36:28.246",
      "direction":"W",
      "end time":"25-03-2013 20:36:28.246"
   },
   {
      "start time":"25-03-2013 20:36:28.246",
      "direction":"NW",
      "end time":"25-03-2013 20:36:30.974"
   },
   {
      "start time":"25-03-2013 20:36:31.038",
      "direction":"N",
      "end time":"25-03-2013 20:36:36.233"
   }
]

如您所见,尽管我从北到北直接转了一圈,但第二种方法的结果不如第一种方法顺利。我更喜欢使用第一种方法,但问题是它已被弃用。另一方面,第二种方法不记录平滑数据。在你们看来我该怎么办?

4

1 回答 1

2

为了能够计算旋转矩阵,getRotationMatrix假设中的重力参数仅为重力加速度。即如果 ( w_1 , w_2 , w_3 ) 是世界基,w_1是指向的单位向量EASTw_2是指向的单位向量NORTHw_3是指向SKY的单位向量,则假设重力参数是标量倍数w_3向量
结果不平滑的原因是当设备旋转时,设备的加速度现在包括非重力加速度。加速度计值现在不再准确地近似重力。因此,词基不能准确表示。该getOrientation方法通过将设备单元y轴正交投影到w_1w_2平面(东-北平面)上来计算方位角,然后计算得到的向量和w_2(北)向量之间的角度。因此,如果w_1w_2w_3未准确表示,则您的结果将不准确。
为了提高精度,您需要对加速度计进行滤波,以消除除重力之外的其他加速度。为此,最简单的方法是低通滤波器。
对于 API > 8,TYPE_GRAVITY我很确定 android 提供的只是过滤的加速度计值,过滤方法可能是某种 KALMAN 过滤器。使用TYPE_GRAVITY可将低通滤波器的结果提高 10 度。
此外,为了消除波动,人们会保留结果的历史记录并对其进行平均。您可以将旋转矩阵保存在列表中然后平均或保存方位角然后平均。如果你平均方位角,你必须小心,因为它们是周期性的。您可以使用以下方法对它们进行平均。

public static final float averageAngle(float[] terms, int totalTerm)
{
    float sumSin = 0;
    float sumCos = 0;
    for (int i = 0; i < totalTerm; i++)
    {
        sumSin += Math.sin(terms[i]);
        sumCos += Math.cos(terms[i]);
    }
    return (float) Math.atan2(sumSin / totalTerm, sumCos / totalTerm);
}

注意:我认为原因TYPE_ORIENTATION是贬值,因为它仅在设备平坦或接近平坦时才提供正常意义上的方向。它使结果返回getOrientation. 现在,如果设备是垂直且旋转的,例如在 POTRAIT 和 LANDSCAPE 之间的中间,则getRotation返回方位角作为y 轴投影到w_1w_2平面所指向的方向。不是后置摄像头指向的方向,是-z轴的方向. 人们不理解这一点并在所有情况下都使用,因此 android 贬值了。如果您仍在使用它,您会感到惊讶,因为手机制造商以不同的方式实施它。HTC 和摩托罗拉会给你完全不同的结果。您可以从我的回答
获得更多信息

于 2013-03-25T23:08:53.673 回答