web-dev-qa-db-ja.com

Androidコンパスを含む電話の向きの概要

私はしばらくの間、Android方位センサーを回避しようとしていました。それを理解したと思っていました。それから、私は理解していなかったことに気付きました。気分が良くなりましたが、まだ100%ではありません。部分的に間違っている場合や空白を埋めた場合に、人々が私を修正できるように願っています。

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

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

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

今、誰かがあなたを今、あなたが東に面しているようにロータリーで90度回転させると想像してください。 Y軸を中心に回転しています。生物学的に検出できないため、この軸は異なります。一定の角度で傾いていることはわかっていますが、惑星の磁北極に対する方向はわかりません。代わりに、外部ツールを使用する必要があります...磁気コンパス。これにより、どの方向を向いているかを確認できます。同じことが携帯電話にも当てはまります。

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

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

だから私は(つまり、私は知らない)理由Androidは3番目の加速度計の読み取りではなく方位角(コンパス方位)を与える。コンパス方位がより有用であるということだ。タイプ_TYPE_MAGNETIC_FIELD_のSensorEventsのリスナーをシステムに登録する必要があるように見えるので、なぜこのタイプのセンサーが非推奨になったのかわからない。イベントの_value[]_配列を渡す必要があるSensorManger.getRotationMatrix(..)メソッドを使用して回転行列(以下を参照)を取得し、それをSensorManager.getOrientation(..)メソッドに渡しますAndroidチームが非推奨になった理由_Sensor.TYPE_ORIENTATION_?それは効率的なことですか?それは、同様の---(question へのコメントの1つで暗示されているものですが、 developmentで別のタイプのリスナーを登録する必要があります/samples/Compass/src/com/example/Android/compass/CompassActivity.Java の例。

次に、回転行列について説明します。 (これは私が最も不確かな場所です)したがって、上記のAndroidドキュメントからの3つの数字があり、それらをA、B、Cと呼びます。

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

B = SensorEvent APIが使用する座標系

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

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

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

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

106
Tim

One Screen Turn 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]);
        }
    }
}
26
Levi Blackstone

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

ピッチは同じで、90度のピッチアップは重力のすべての成分をyレジスタに入れます。

ヨー/ヘッディング/方位角は重力に影響を与えません。常に重力に直角であるため、どの方向から重力に直面しても測定できません。

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

3
Craig

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

まだ横向きですが、デバイスが背面にあると、センサーは0〜360を示します。ポートレートモードでは、背中に横になり、ポートレートで立ち上がる両方で0-360を実行します。

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

0
hopeless bob

これを見てください: Stackoverflow.com:Q.5202147

3つの図A、B、Cまでは、ほとんど正しいようです。その後、混乱してしまいます。

0
TheCodeArtist