101

私はしばらくの間、Androidの方向センサーの周りを頭を抱えようとしてきました。 私はそれを理解していると思った。それから、私は気付かなかった。今私は(希望)私は再びそれのために良い感じがあると思うが、私はまだ100%ではない。私はそれについての不気味な理解を説明しようとしてくれるでしょう。もし私が間違っていたり、空白を記入したら、人々は私を正すことができます。コンパスを含むAndroidの携帯電話の向きの概要

私は経度0度(緯度経度)と緯度0度(赤道)に立っていると想像します。この場所は実際にはアフリカの海岸の海にありますが、私には耐えられます。私は電話の底が私の足を指すように私の顔の前に私の電話を保持する;私はノース(グリニッジを目指している)に向かっているので、電話の右側は東をアフリカに向ける。この姿勢(下の図を参照)では、私はX軸がEastを指しており、Z軸がSouthを指しており、Y軸が空を指しています。

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

私がそれを得る前に、上記の方向に立っている0度の緯度と経度で、想像上の地面に立っていると想像してください。あなたが目隠しされ、あなたの靴が遊び場のロータリーに固定されていると想像してください。誰かがあなたを背中に押しつけると、(北に向かって)前方に倒れ、両手を倒して倒れます。同様に誰かがあなたの肩を左に押した場合、あなたの右手に転がってしまいます。あなたの内耳には「重力センサー」(youtube clip)があります。これは、あなたが前進/後退しているか、左/右に落ちているのか、下降しているのか(または上に!)検出できます。したがって、人間は、電話機と同じX軸およびZ軸の周りの整列および回転を検出することができます。

今、誰かがロータリーであなたを90度回転させて、今は東向きになっているとします。あなたはY軸を中心に回転しています。この軸は生物学的にそれを検出できないために異なっている。私たちはある程度の角度を持っていることは分かっていますが、惑星の北極磁場に関連する方向はわかりません。 代わりに、外部ツール、つまり磁気コンパスを使用する必要があります。これにより、我々はどの方向を向いているかを確かめることができます。私たちの電話でも同じことが言えます。

携帯電話にも3軸加速度計が搭載されています。私はいいえアイデアが実際にどのように動作するかを私が視覚化する方法は、空から落ちる一定で均一な「雨」としての重力を想像し、雨の量を検出できるチューブとして上の図の軸を想像することですスルー。電話機が直立状態になると、すべての雨がY字管を通って流れます。電話機が徐々に回転して画面が空に向かうと、Yを流れる雨量はゼロに減少しますが、Zを通る音量は最大雨量が流れるまで徐々に増加します。同様に、電話機の側面に先端を置くと、Xチューブは最終的に最大の雨量を集めます。したがって、3つのチューブを流れる雨量を測定することによって、携帯電話の向きに応じて、向きを計算することができます。

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

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

私は今、回転行列についてお話したいと思います。 (これは私が最も不確かなところです) 上記のAndroidドキュメントの3つの数字は、A、B、Cとなります。

A = SensorManger.getRotationMatrix世界座標系

B = Coordinate system used by the SensorEvent API.

C = SensorManager.getOrientation(..)メソッドフィギュア

だから私の理解では、Aは、私が道を指し推定する「世界座標系」を表していることです惑星上の位置は(緯度、経度)結合として与えられますe(オプション)(高度)。 Xは"easting"の座標であり、Yは"northing"の座標である。 Zは空を指し、高度を表します。

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

私は今すぐ中止する方がいいと思う。私は私が台無しや人々を助けてきたところの人が私に教えてくれるを期待する前に私が言ったように

+25

私は本当にこの質問が好きです。私はそれに答えることはできませんが、私はそれが好きです。 –

+4

ティム、あなたは答えを得たことがありますか?私は同じように私の頭を掻いてきました。これは私が今までに見た中でもっともよく書かれていないAPIの1つです。 –

+0

本当に私は恐れています。私は上に移動しなければならなかった。いつか私はこの問題に戻るでしょう。 – Tim

答えて

24

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]); 
     } 
    } 
} 
+4

ちょうど、方位、ピッチ、およびロールが廃止されたOrientationSensorから出てくるものと同じではないことに言及してください。 'orientation [0] = orientation [0]> = 0?方位[0]:方位[0] + 360;方位角を正規化し、if(方位[1] = -90){ \t \t \t方位[1] + =(-2 *(90 +方位[1 ]))); \t \t}そうであれば(方位[1]> = 90){ \t \t \t方位[1] + =(2 *(90 - 方位[1]))。 \t \t} 'は、ピッチ –

+0

@RafaelTを正規化し、ロールを正規化しますか?それとも意味がないのですか? – Matthias

+0

@RafaelT:方位角の正規化に影響があるようです:値は[-180,180]から[0、360]になります。しかし、私が得たピッチ値はすでに[-90,90]であるので、あなたが提案する正規化は効果がありません。 – Matthias

0

はこれを見ている(さらにまたは混乱し人々を!):Stackoverflow.com: Q.5202147

をあなたがするまで、主に右のように見えます3ダイアグラムA、B、C。 その後、あなたは混乱してしまいます。

+0

私は見ています。ありがとう – Tim

3

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

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

ヨー/見出し/方位は、重力に影響を与えません、それはので、あなたが重力に直面している方法に関係なくimeasurableなり、重力に対して直角に常にあります。

これは、あなたが評価するためにコンパスが必要な理由ですか、それはおそらく意味がありますか?

0

私はこの問題を抱えていたので、異なる方向に何が起こっているのかを調べました。 デバイスが横置きでマウントされている場合、コンパスからの「度」は、時計回りに0-275(西と北の間)の269を上回り、-90から0に逆算され、その後、転送269 270から0からの風景ではなく、0から360までを与えるデバイスは、その戻って私のセンサーに横たわって-90

まだなります。 とポートレートモードでは0〜360の両方を背中に置き、肖像画の上に立ちます。

誰かを助ける希望