0

デバイスのコンパスの度数をファイルに記録する Android アプリケーションを作成しています。この度数を取得するには、次の 2 つの方法があります。

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

ご覧のとおり、2 番目の方法の結果は最初の方法ほどスムーズではありませんが、北から北へ 1 回転しました。私は最初の方法を使用することを好みますが、問題はそれが推奨されていないことです。一方、2 番目の方法では、滑らかなデータはログに記録されません。皆さんの意見では、私は何をすべきですか?

4

1 に答える 1

2

回転行列を計算できるようにするために、 の重力パラメータはgetRotationMatrix重力加速度のみであると想定されています。つまり、( w_1w_2w_3 ) が世界基底で、w_1が指す単位ベクトルEASTw_2が指す単位ベクトルNORTHw_3がSKY​​ を指す単位ベクトルである場合、重力パラメータはスカラー倍数であると想定されます。w_3ベクトルの。
デバイスを回転させたときにデバイスの加速度に非重力加速度が含まれるようになったため、結果がスムーズにならない理由。加速度計の値は、重力を正確に近似しなくなりました。したがって、単語の基礎は正確に表現されていません。このgetOrientationメソッドは、デバイス ユニットのy 軸w_1w_2平面 (東北平面) に正射影して方位角を計算し、結果のベクトルとw_2 (北) ベクトルの間の角度を計算します。したがって、w_1w_2w_3が正確に表現されていない場合、結果は正確になりません。
精度を向上させるには、加速度計をフィルター処理して、重力以外の他の加速度を除去する必要があります。このための最も簡単な方法は、ローパス フィルターです。
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の中間にある場合、 w_1w_2平面への y 軸の投影が指しているgetRotation方向として方位角を返します。-z 軸の方向であるバック カメラが指している方向ではありません。. 人々はこれを理解しておらず、すべての場合に使用されているため、Android は減価償却されています。携帯電話のメーカーが異なる方法で実装しているため、まだ使用している場合は驚くでしょう。HTC と Motorola では、まったく異なる結果が得られます。デバイスの磁場 X、Y、Z 値をグローバル基準フレームに変換するおよび磁場、回転行列、グローバル座標
で、私の回答から詳細情報を得ることができます。

于 2013-03-25T23:08:53.673 に答える