108

私はしばらくの間、Androidの向きセンサーに頭を悩ませようとしてきました。わかったと思いました。それから私はそうしなかったことに気づきました。今、私は(願っています)私はそれに対して再び気分が良くなったと思いますが、それでも私は100%ではありません。私はそれについての私のパッチの理解を説明しようとします、そしてうまくいけば、私が部分的に間違っているか、空白を埋めるならば、人々が私を訂正することができるでしょう。

経度0度(本初子午線)と緯度0度(赤道)に立っていると思います。この場所は実際にはアフリカの沖合の海にありますが、私には耐えてください。電話の底が私の足を指すように、電話を顔の前に持っています。私は北を向いている(グリニッジを向いている)ので、電話の右側は東をアフリカに向けています。この方向(下の図を参照)では、X軸は東を指し、Z軸は南を指し、Y軸は空を指します。

これで、電話のセンサーを使用して、この状況でのデバイスの向き(場所ではなく)を把握できます。この部分はいつも私を混乱させてきました。おそらく、それが正しく機能することを受け入れる前に、何かがどのように機能するかを理解したかったからです。電話は2つの異なる技術の組み合わせを使用してその向きを解決しているようです。

その前に、緯度と経度が0度で、上記の方向に立っている架空の土地に戻って立っていることを想像してみてください。また、目隠しをして、靴が遊び場のラウンドアバウトに固定されていると想像してみてください。誰かがあなたを後ろに押し込んだ場合、あなたは前に(北に向かって)倒れ、両手を出してあなたの転倒を壊します。同様に、誰かがあなたの左肩を押した場合、あなたはあなたの右手に倒れます。内耳には「重力センサー」(youtubeクリップ)があり、前方/後方に落下しているか、左/右に落下しているか、落下(または上向き!!)しているかを検出できます。したがって、人間は電話と同じX軸とZ軸の周りの位置合わせと回転を検出できます。

ここで、誰かがラウンドアバウトであなたを90度回転させて、あなたが今東を向いていると想像してください。Y軸を中心に回転しています。この軸は、生物学的に検出できないため、異なります。ある程度の角度があることはわかっていますが、惑星の磁北極との関係で方向がわかりません。代わりに、外部ツール...磁気コンパスを使用する必要があります。これにより、私たちがどちらの方向を向いているかを確認できます。同じことが私たちの電話にも当てはまります。

現在、電話には3軸加速度計もあります。私は持っていませそれらが実際にどのように機能するかを考えますが、私が視覚化する方法は、重力を空から降る一定で均一な「雨」として想像し、上の図の軸を流れる雨の量を検出できるチューブとして想像することです。電話を直立させた状態で、すべての雨がY'チューブ'を通って流れます。画面が空に向くように電話を徐々に回転させると、Yを流れる雨の量はゼロに減少し、Zを流れる音量は、最大の雨が流れるまで着実に増加します。同様に、電話を横向きに傾けると、Xチューブは最終的に最大量の雨を集めます。したがって、3つのチューブを流れる雨の量を測定することにより、電話の向きに応じて、向きを計算できます。

電話には、通常のコンパスのように動作する電子コンパスもあります。その「仮想針」は磁北を指しています。Androidは、これら2つのセンサーからの情報をマージして、SensorEventTYPE_ORIENTATIONが生成されるたびに、values[3]配列の
値が[0]:方位角-(磁北の東にあるコンパス)
値[1]:ピッチ、x軸を中心とした回転(電話です)前傾または後傾)
値[2]:y軸を中心に回転、回転(電話は左側または右側に傾いています)

したがって、Androidが3番目の加速度計の読み取り値ではなく方位角(コンパス方位)を提供する理由は、コンパス方位の方が便利だからだと思います(つまり、わかりません)。SensorEventタイプのsのシステムにリスナーを登録する必要があるように思われるため、なぜこのタイプのセンサーが非推奨になったのかわかりませんTYPE_MAGNETIC_FIELD。イベントのvalue[]配列をメソッドに渡してSensorManger.getRotationMatrix(..)、回転行列(以下を参照)を取得し、それをメソッドに渡す必要がありSensorManager.getOrientation(..)ます。Androidチームが非推奨になった理由を誰かが知っていますSensor.TYPE_ORIENTATIONか?それは効率的なものですか?これは、同様の質問へのコメントの1つに含まれていることですが、別のタイプのリスナーを登録する必要があります。development / samples / Compass / src / com / example / android / compass/CompassActivity.javaの例。

ここで、回転行列について説明します。(これは私が最も確信が持てないところです)したがって、上記のAndroidドキュメントからの3つの図は、A、B、およびCと呼びます。

A = SensorManger.getRotationMatrix(..)メソッドの図であり、世界の座標系を表します

B = SensorEventAPIで使用される座標系。

C = SensorManager.getOrientation(..)メソッド図

したがって、私の理解では、Aは「世界の座標系」を表します。これは、惑星上の場所がオプションの(高度)との(緯度、経度)カップルとして与えられる方法を指していると思います。Xは「東」座標、Yは「北」座標です。Zは空を指し、高度を表します。

電話の座標系を図Bに示します。固定されています。そのY軸は常に上を指します。回転行列は電話によって常に計算されており、2つの間のマッピングが可能です。それで、回転行列がBの座標系をCに変換すると考えるのは正しいですか?したがって、SensorManager.getOrientation(..)メソッドを呼び出すときは、図Cに対応する値の配列を使用values[]します。電話が空を指す場合、回転行列は単位行列(数学的に1に相当する行列)です。これは、デバイスが位置合わせされているため、マッピングが不要であることを意味します。世界の座標系で。

Ok。今はやめたほうがいいと思います。私が前に言ったように、私がどこで人々を台無しにしたか、または人々を助けた(またはさらに人々を混乱させた!)人々が私に教えてくれることを願っています

4

4 に答える 4

27

One Screen Turns Deserves Another の記事をチェックしてみてください。回転行列が必要な理由を説明しています。

簡単に言えば、携帯電話のセンサーは、デバイスが回転している場合でも、常に同じ座標系を使用します。

単一の向きにロックされていないアプリケーションでは、デバイスを回転させると画面座標系が変化します。したがって、デバイスがデフォルトの表示モードから回転すると、センサーの座標系は画面の座標系と同じではなくなります。この場合の回転行列は、A を C に変換するために使用されます (B は常に固定されたままです)。

これを使用する方法を示すコード スニペットを次に示します。

SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);

//...
// The following code inside a class implementing a SensorEventListener
// ...

float[] inR = new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];

double azimuth = 0;
double pitch = 0;
double roll = 0;

public void onSensorChanged(SensorEvent sensorEvent) {
    // If the sensor data is unreliable return
    if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        return;

    // Gets the value of the sensor that has been changed
    switch (sensorEvent.sensor.getType()) {  
        case Sensor.TYPE_ACCELEROMETER:
            gravity = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomag = sensorEvent.values.clone();
            break;
    }

    // If gravity and geomag have values then find rotation matrix
    if (gravity != null && geomag != null) {

        // checks that the rotation matrix is found
        boolean success = SensorManager.getRotationMatrix(inR, I,
                                                          gravity, geomag);
        if (success) {
            SensorManager.getOrientation(inR, orientVals);
            azimuth = Math.toDegrees(orientVals[0]);
            pitch = Math.toDegrees(orientVals[1]);
            roll = Math.toDegrees(orientVals[2]);
        }
    }
}
于 2011-07-24T03:37:42.937 に答える
3

ロールは重力の関数で、90 度のロールはすべての重力を x レジスタに入れます。

ピッチは同じです。90 度ピッチを上げると、すべての重力成分が y レジスタに入力されます。

ヨー / ヘディング / アジマスは重力に影響を与えません。常に重力に対して直角であるため、どの方向を向いていても重力は測定できません。

これが、評価するためにコンパスが必要な理由です。おそらくそれは理にかなっていますか?

于 2011-11-25T15:16:35.437 に答える
0

私はこの問題を抱えていたので、さまざまな方向で何が起こるかを計画しました。デバイスが横向きに取り付けられている場合、たとえば車のマウントでは、コンパスからの「度」が 0 ~ 275 (時計回り) から 269 (西と北の間) を超えるように見える場合、-90 から 0 まで逆方向にカウントされます。 0 から 269 まで転送します。270 は -90 になります。

まだ横向きですが、デバイスを仰向けにすると、センサーは 0-360 を返します。縦向きモードでは、仰向けでも縦向きでも 0-360 で動作します。

誰かを助けることを願っています

于 2014-06-27T04:27:24.167 に答える