web-dev-qa-db-ja.com

デバイスの座標系から絶対座標系への加速

私のAndroidデバイスから、(デバイスの座標系の)線形加速度値の配列と(地球の座標系の)絶対方位値の配列を読み取ることができます。必要なのは、後者の座標系における線形加速度値。

どうすれば変換できますか?

[〜#〜] edit [〜#〜] ALiのコメントでのコメントの後:

わかったので、私が正しく理解していれば、線形加速度を測定するとき、測定値は地球の座標系で与えられるため、電話の位置はまったく問題ではありません。正しい?

しかし、私は電話をさまざまな位置に置き、さまざまな軸で加速度を得たテストを実行しました。 3組の写真があります。最初の写真はデバイスの配置方法(ペイントの「マスタースキル」で申し訳ありません)を示し、2番目の写真は線形accによって提供されたデータからの読み取り値を示しています。センサー:

  1. 左側に置かれたデバイス

first positionfirst readings

  1. 仰向けに横たわるデバイス

second positionsecond readings

  1. デバイススタンディング

enter image description hereenter image description here

そして今-3番目のケースでは、デバイスの位置は関係ないので、なぜY軸ではな​​くZ軸に沿って加速度が発生するのでしょうか。

26
alex

ようやく解決しました!したがって、加速度ベクトル地球の座標系を取得するには、次のようにする必要があります。

  1. SensorManager.getRotationMatrix()から回転行列(_float[16]_を使用して、後で_Android.opengl.Matrix_クラスで使用できるようにする)(_SENSOR.TYPE_GRAVITY_および_SENSOR.TYPE_MAGNETIC_FIELD_センサー値をパラメーターとして使用)、
  2. 転置行列でAndroid.opengl.Matrix.invertM()を使用して反転します(転置ではありません)。
  3. _Sensor.TYPE_LINEAR_ACCELERATION_センサーを使用して、線形加速度ベクトルを取得します(デバイスの座標系)。
  4. Android.opengl.Matrix.multiplyMV()を使用して、回転行列に線形加速度ベクトルを乗算します。

そして、あなたはそれを持っています!他の人のために貴重な時間を節約したいと思います。

ヒントを提供してくれたEdward FalkとALiに感謝します!!

42
alex

@alexの答えに基づいて、ここにコードスニペットがあります:

private float[] gravityValues = null;
private float[] magneticValues = null;

 @Override
    public void onSensorChanged(SensorEvent event) {
        if ((gravityValues != null) && (magneticValues != null) 
            && (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)) {

            float[] deviceRelativeAcceleration = new float[4];
            deviceRelativeAcceleration[0] = event.values[0];
            deviceRelativeAcceleration[1] = event.values[1];
            deviceRelativeAcceleration[2] = event.values[2];
            deviceRelativeAcceleration[3] = 0;

            // Change the device relative acceleration values to earth relative values
            // X axis -> East
            // Y axis -> North Pole
            // Z axis -> Sky

            float[] R = new float[16], I = new float[16], earthAcc = new float[16];

            SensorManager.getRotationMatrix(R, I, gravityValues, magneticValues);

            float[] inv = new float[16];

            Android.opengl.Matrix.invertM(inv, 0, R, 0);
            Android.opengl.Matrix.multiplyMV(earthAcc, 0, inv, 0, deviceRelativeAcceleration, 0);
           Log.d("Acceleration", "Values: (" + earthAcc[0] + ", " + earthAcc[1] + ", " + earthAcc[2] + ")");                

        } else if (event.sensor.getType() == Sensor.TYPE_GRAVITY) {
            gravityValues = event.values;
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            magneticValues = event.values;
        } 
   }
15
orak

ドキュメントによると 電話の座標系で線形加速度が得られます。

任意のベクトルを電話の座標系から地球の座標系に変換するには、回転行列を掛けます。 getRotationMatrix() から回転行列を取得できます。

(おそらく、この乗算を実行する関数がすでに存在しますが、Androidプログラミングを実行しておらず、そのAPIに精通していません。)

回転行列に関する素晴らしいチュートリアルは、 方向余弦行列IMU:理論 の原稿です。幸運を!

4
Ali

まず、Androidで実際の慣性ナビゲーションを実行しようとしている場合は、作業が中断されます。スマートフォンで使用される安価な小さなセンサーは、十分に正確ではありません。とはいえ、建物の中など、短い距離での慣性航法については、興味深い研究が行われてきました。おそらくあなたが掘り下げることができる主題に関する論文があるでしょう。 Googleの「Motion Interface Developers Conference」では、何か便利なものがあるかもしれません。これは、Invensenseが数か月前に開催した会議です。

第2に、線形加速度はデバイス座標であり、世界座標ではありません。自分で変換する必要があります。つまり、デバイスの3次元方向を知る必要があります。

やりたいことは、Androidの仮想センサーTYPE_GRAVITYおよびTYPE_LINEAR_ACCELERATIONをサポートするバージョンを使用することです。ジャイロを備えたデバイスを使用して、かなり正確で正確な測定値を取得する必要があります。

内部的には、システムはジャイロ、加速度計、磁力計を組み合わせて、デバイスの向きの真の値を導き出します。これにより、加速度計デバイスが重力コンポーネントと加速度コンポーネントに効果的に分割されます。

つまり、TYPE_GRAVITY、TYPE_LINEAR_ACCELERATION、およびTYPE_MAGNETOMETERのセンサーリスナーを設定する必要があります。重力と磁力計のデータをSensorManagerへの入力として使用します。 getRotationMatrix()は、世界座標をデバイス座標に、またはその逆に変換する回転行列を取得します。この場合、「versa」の部分が必要になります。つまり、線形加速度入力に方向行列の転置を掛けて、線形加速度入力を世界座標に変換します。

1
Edward Falk