14

3 つの回転値 (アジマス、ピッチ、ロール) を取得するには 2 つの方法があります。

1 つは、タイプ TYPE_ORIENTATION のリスナーを登録することです。これは最も簡単な方法であり、ドキュメントに記載されているように、すべての回転から正しい範囲の値を取得します: 方位角: [0, 359] ピッチ: [-180, 180] ロール: [-90, 90]

もう 1 つは、初めて見たときに理解するのが最も正確で複雑です。Androidが推奨しているので使いたいのですが、値が違います。

方位角: [-180, 180]。-180/180 は S、0 i N、90 E、および -90 Wです。
ピッチ: [-90, 90]。90 は 90、-90 は -90、0 は 0 ですが、-180/180 (画面を下にして横になっている) は 0
です。ロール: [-180, 180]。

同じ値を取得する必要がありますが、小数を使用しますよね?

次のコードがあります。

aValues = new float[3];
mValues = new float[3];

sensorListener = new SensorEventListener (){
    public void onSensorChanged (SensorEvent event){
        switch (event.sensor.getType ()){
            case Sensor.TYPE_ACCELEROMETER:
                aValues = event.values.clone ();
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                mValues = event.values.clone ();
                break;
        }

        float[] R = new float[16];
        float[] orientationValues = new float[3];

        SensorManager.getRotationMatrix (R, null, aValues, mValues);
        SensorManager.getOrientation (R, orientationValues);

        orientationValues[0] = (float)Math.toDegrees (orientationValues[0]);
        orientationValues[1] = (float)Math.toDegrees (orientationValues[1]);
        orientationValues[2] = (float)Math.toDegrees (orientationValues[2]);

        azimuthText.setText ("azimuth: " + orientationValues[0]);
        pitchText.setText ("pitch: " + orientationValues[1]);
        rollText.setText ("roll: " + orientationValues[2]);
    }

    public void onAccuracyChanged (Sensor sensor, int accuracy){}
};

助けてください。とてもイライラします。

それらの値で処理する必要がありますか、それとも何か間違っていますか?

ありがとう。

4

3 に答える 3

21

ここでスレッドネクロマンサーをプレイしていることは知っていますが、最近はこのようなものに取り組んでいるので、2¢を投入すると思いました。

このデバイスにはコンパスや傾斜計が含まれていないため、方位角、ピッチ、またはロールを直接測定することはありません。(私たちはそれらをオイラー角と呼びます、ところで)。代わりに、加速度計と磁力計を使用します。どちらも3空間XYZベクトルを生成します。これらは、方位角などの値を計算するために使用されます。

ベクトルはデバイスの座標空間にあります。

デバイス座標

世界座標では、Yが北を向き、Xが東を向き、Zが上を向きます。

世界座標

したがって、デバイスの「ニュートラル」方向は、デバイスの上部が北を向くように、テーブルの裏側で平らになります。

加速度計は「UP」方向のベクトルを生成します。磁力計は「北」方向のベクトルを生成します。(北半球では、伏角のためにこれは下向きになる傾向があることに注意してください。)

加速度計ベクトルと磁力計ベクトルは、SensorManager.getRotationMatrix()を介して数学的に組み合わせることができます。これは、デバイス座標のベクトルをワールド座標に、またはその逆にマップする3x3行列を返します。ニュートラル位置にあるデバイスの場合、この関数は単位行列を返します。

このマトリックスは、画面の向きによって変化しません。これは、アプリケーションが方向を認識し、それに応じて補正する必要があることを意味します。

SensorManager.getOrientation()は、変換行列を受け取り、方位角、ピッチ、およびロールの値を計算します。これらは、ニュートラル位置にあるデバイスを基準にして取得されます。

この関数を呼び出すことと、TYPE_ORIENTATIONセンサーを使用することの違いは、関数で最初に行列を操作できることを除いて、わかりません。

デバイスが90°またはその近くで上に傾けられている場合、オイラー角の使用は崩壊します。これは数学的に退化したケースです。この領域では、デバイスは、方位角またはロールを変更しているかどうかをどのように認識しますか?

関数SensorManager.remapCoordinateSystem()を使用して、変換行列を操作し、デバイスの向きについて知っていることを補正できます。しかし、私の実験では、これがすべてのケースをカバーしているわけではなく、一般的なケースの一部もカバーしていないことが示されています。たとえば、直立した状態のデバイスに再マッピングする場合(たとえば、写真を撮る場合)、変換行列に次の行列を掛けます。

1 0 0
0 0 1
0 1 0

getOrientation()を呼び出す前に、これはremapCoordinateSystem()がサポートする方向の再マッピングの1つではありません[ここで何かを見逃した場合は、誰かが私を修正してください]。

さて、これはすべて、TYPE_ORIENTATIONセンサーまたはgetOrientation()のいずれかからオリエンテーションを使用している場合、おそらくそれが間違っているという長い間言われている方法です。オイラー角が実際に必要なのは、方向情報をユーザーフレンドリーな形式で表示したり、写真に注釈を付けたり、飛行計器のディスプレイを操作したりすることだけです。

デバイスの向きに関連する計算を実行する場合は、変換行列を使用してXYZベクトルを操作する方がほぼ確実に優れています。

コンサルタントとして働いていると、誰かがオイラー角に関する問題で私に来るときはいつでも、私はバックアップして彼らが本当に何をしようとしているのかを尋ね、代わりにベクトルでそれを行う方法を見つけます。

Looking back at your original question, getOrientation() should return three values in [-180 180] [-90 90] and [-180 180] (after converting from radians). In practice, we think of azimuth as numbers in [0 360), so you should simply add 360 to any negative numbers you receive. Your code looks correct as written. It would help if I knew exactly what results you were expecting and what you were getting instead.

追加するために編集:さらにいくつかの考え。最新バージョンのAndroidは、「センサーフュージョン」と呼ばれるものを使用します。これは、基本的に、利用可能なすべての入力(加速度計、磁力計、ジャイロ)が数学的なブラックボックス(通常はカルマンフィルターですが、ベンダーによって異なります)に結合されることを意味します。加速度、磁場、ジャイロ、重力、線形加速度、方向など、さまざまなセンサーがすべてこのブラックボックスからの出力として取得されます。

可能な限り、getRotationMatrix()への入力としてTYPE_ACCELEROMETERではなくTYPE_GRAVITYを使用する必要があります。

于 2012-07-18T20:57:43.780 に答える
7

私はここで暗闇の中で撮影しているかもしれませんが、あなたの質問を正しく理解していれば、なぜ[-179..179]代わりに[0..360]?

は整数 (整数)と-180同じであることに注意してください。+180180 + N*360N

つまり、方向センサーと同じ数値を取得したい場合は、次のようにすることができます。

// x = orientationValues[0];
// y = orientationValues[1];
// z = orientationValues[2];
x = (x + 360.0) % 360.0;
y = (y + 360.0) % 360.0;
z = (z + 360.0) % 360.0;

[0..360]これにより、必要に応じて範囲内の値が得られます。

于 2012-05-14T11:48:43.553 に答える
1

計算で 1 つの重要な計算が欠落しています。getRotationMatrixを実行した
remapCoordinateSystem呼び出し。

それをコードに追加すると、すべて問題ありません。
詳細については、こちらをご覧ください。

于 2011-03-05T06:29:59.703 に答える