Android磁力计返回非平滑数据

时间:2013-03-25 20:09:01

标签: android orientation accelerometer magnetometer

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

方法1:

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]
}

方法2:

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"
   }
]

正如你所看到的,第二种方法的结果并不像第一种方法那样平滑,尽管我从北到北直线转弯。我更喜欢使用第一种方法,但问题是它已被弃用。另一方面,第二种方法不记录平滑数据。你觉得我该怎么办?

1 个答案:

答案 0 :(得分:2)

为了能够计算旋转矩阵,getRotationMatrix中的重力参数仅被假定为引力加速度。也就是说,如果( w_1 w_2 w_3 )是世界基础, w_1 是指向{的单位向量{1}}, w_2 是指向EAST的单位向量, w_3 是指向 SKY 的单位向量,然后是重力参数被假定为 w_3 向量的标量倍数 结果不顺畅的原因是因为当设备旋转时,设备的加速度现在包括非重力加速度。加速度计值现在不再精确地接近重力。因此,单词基础不准确表示。 NORTH方法通过将设备单位 y轴正交投影到 w_1 w_2 平面(东北方向)来计算方位角平面)然后计算得到的矢量和 w_2 (北)矢量之间的角度。因此,如果 w_1 w_2 w_3 未准确显示,则您的结果将无法控制。
为了提高精度,您需要过滤加速度计以消除引力旁边的其他加速度。为此,最简单的方法是低通滤波器 对于API> 8,android提供getOrientation我很确定只是过滤加速度计值,过滤方法可能是某种KALMAN过滤器。使用TYPE_GRAVITY可将低通滤波器的结果提高到10度 此外,为了消除波动,我们保留结果的历史并对其进行平均。您可以将旋转矩阵保存在列表中,然后平均或保存方位角,然后平均。如果平均方位角,则必须小心,因为它们具有周期性。您可以使用以下方法对它们进行平均。

TYPE_GRAVITY

注意:我认为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返回结果。现在,如果设备是垂直的并且旋转,例如POTRAIT和LANDSCAPE之间的中间部分,则getOrientation将方位角返回为 y轴投影到的方向。 w_1 w_2 飞机指向。它不是后置摄像头指向的方向,也就是 -z轴的方向。人们不理解这一点,并在所有情况下使用,因此android折旧。如果您仍在使用它,您会感到惊讶,因为手机制造商以不同的方式实施它。 HTC和摩托罗拉将给你完全不同的结果 您可以在我Convert magnetic field X, Y, Z values from device into global reference frameMagnetic Fields, Rotation Matrix And global coordinates

的回答中获得更多信息