簡體   English   中英

Android磁力計返回非平滑數據

[英]Android magnetometer returning non-smooth data

我正在構建一個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"
   }
]

正如你所看到的,第二種方法的結果並不像第一種方法那樣平滑,盡管我從北到北直線轉彎。 我更喜歡使用第一種方法,但問題是它已被棄用。 另一方面,第二種方法不記錄平滑數據。 你覺得我該怎么辦?

為了能夠計算旋轉矩陣, getRotationMatrix的重力參數getRotationMatrix被假定為引力加速度。 也就是說,如果(W_1,W_2,w_3)是世界基礎,W_1是指向一個單位矢量EAST ,W_2是指向一個單位矢量NORTHw_3朝向SKY指向的單位矢量,則重力參數被假定為一w_3向量的標量倍數。
結果不順暢的原因是因為當設備旋轉時,設備的加速度現在包括非重力加速度。 加速度計值現在不再精確地接近重力。 因此,單詞基礎不准確表示。 getOrientation方法通過將設備單元y軸正交投影到w_1w_2平面(東 - 北平面) getOrientation計算方位角,然后計算結果矢量和w_2 (北)矢量之間的角度。 所以,如果W_1,W_2,w_3不准確表示,那么你的結果將不會被accurated。
為了提高精度,您需要過濾加速度計以消除引力旁邊的其他加速度。 為此,最簡單的方法是低通濾波器。
對於API> 8,android提供了TYPE_GRAVITY ,我很確定它只是過濾的加速度計值,過濾方法可能是某種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和摩托羅拉將給你完全不同的結果。
您可以從我的答案中獲得更多信息, 將磁場X,Y,Z值從設備轉換為全局參考系以及磁場,旋轉矩陣和全局坐標

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM