14

私はAndroidの重力センサーと磁場センサーを使用して、SensorManager.getRotationMatrixとSensorManager.getOrientationを介して向きを計算しています。これにより、方位角、ピッチ、および方向の数値がわかります。デバイスがテーブルの上に平らに置かれているとき、結果は賢明に見えます。

ただし、マニフェストで縦向きと横向きの切り替えを無効にしているため、getWindowManager()。getDefaultDisplay()。getRotation()は常にゼロです。デバイスを90度回転させて垂直に立てると、問題が発生します。数字がかなり間違っているように見えることもありますが、これはジンバルロックに関連していることに気づきました。ただし、他のアプリにはこの問題はないようです。たとえば、自分のアプリを2つの無料のセンサーテストアプリ(Sensor Tester(Dicotomica)Sensor Monitoring(Rのソフトウェア))と比較しました。デバイスが平らな場合、私のアプリはこれらのアプリに同意しますが、デバイスを垂直位置に回転させると、大きな違いが生じる可能性があります。2つのアプリは互いに一致しているようですが、

4

3 に答える 3

11

デバイスがフラットでない場合は、を呼び出すremapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);前に呼び出す必要がありますgetOrientation

によるazimuthリターンgetOrientationは、デバイスユニットY axisを世界に直交East-North plane投影し、結果の投影ベクトルと北軸の間の角度を計算することによって得られます。

現在、私たちは通常、方向をバックカメラが指している方向と考えています。これは、デバイスの軸が画面の外を向いている方向-ZですZ。デバイスがフラットな場合、方向を考えず、与えられたものを受け入れます。しかし、それが平坦でない場合、それはの方向であると予想し-Zます。ただしgetOrientation、の方向を計算するため、を呼び出す前にY axisを交換する必要があります。それはまさにそれが行うことです、それは無傷と地図を保ちます。 Y and Z axesgetOrientationremapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR)X axisZ to Y

では、いつすべきかどうかをどうやって知るのでしょうかremap。あなたはチェックすることによってそれを行うことができます

float inclination = (float) Math.acos(rotationMatrix[8]);
if (result.inclination < TWENTY_FIVE_DEGREE_IN_RADIAN 
            || result.inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN)
{
    // device is flat just call getOrientation
}
else
{
    // call remap
}

上の傾斜は、デバイス画面と世界の東北面の間の角度です。デバイスがどれだけ傾いているかを示します。

于 2013-03-27T00:27:26.903 に答える
8

デバイスがフラットでないときに方向角を定義する最良の方法は、から得られる標準のオイラー角よりも適切な角度座標系を使用することだと思いますSensorManager.getOrientation(...)。私はここmath.stackexchange.comで説明するものを提案します。私はまた、それを実装するいくつかのコードをここの答えに入れました。方位角の適切な定義とは別に、ピッチ角の定義もあります。これは、Math.acos(rotationMatrix[8])ここで別の回答に記載されている角度とまったく同じです。

私が最初の段落で与えた2つのリンクから完全な詳細を得ることができます。ただし、要約すると、SensorManager.getRotationMatrix(...)からの回転行列Rは

R行列の定義を持つ方程式

ここで、(E x、E y、E z)、(N x、N y、N z)および(G x、G y、G z)は、真東、北、および重力の方向を指すベクトルです。次に、必要な方位角は次の式で与えられます。

方位角を定義する方程式

于 2013-05-06T11:47:54.300 に答える
0

Hoanの回答を使用して、私に役立つ例を追加します。また、現在利用可能で、ジャイロセンサーを使用する必要のあるアプリを調べるときに役立つ可能性のあるいくつかの新しいリソースを強調します。

まず、サンプルアプリで利用できるGoogle Codeラボがあります。完成したサンプルアプリは、デバイスの動作を理解するのに非常に役立ちます。

アプリの表示は次のようになります。

ここに画像の説明を入力してください

コードラボと最終的なアプリのバージョンは、次のリンクから入手できます(執筆時点)。

特に、これにより次のように実験することができます(説明するよりも簡単です...):

  • デバイスをテーブルの上に平らに置き、平らな状態でテーブルを回転させて上下に持ち上げてみます(つまり、フロントカメラが通常あるディスプレイの上部をテーブルから持ち上げ、ホームボタンの下部を残します)通常は、テーブルに1つある場合です。同様に、デバイスの左端と右端を持ち上げます。アプリで方位角、ピッチ、ロールの値を確認します。

  • デバイスをポートレートモードのワードローブドアに当てて、もう一度動かしてみてください。ドアを開けて効果も確認してください。横向きに回転して違いを確認します。

上記からわかると思う重要なことは、すべてが非常に単純で、フラットの場合はうまく機能し、フラットでない場合はすべてが複雑で相互に関連しているということです。

特に、縦向きモードで垂直のときにピッチとロールを表示する必要があるユースケースを見ると、次のことがうまくいきました。

 when (event?.sensor?.type) {
            Sensor.TYPE_ROTATION_VECTOR -> {

                // Calculate the rotation matrix
                val rotMatrix = FloatArray(9)
                var rotationMatrixAdjusted = FloatArray(9)
                val azimuthChanged: (Float) -> Unit
                val orientation = FloatArray(3)
                SensorManager.getRotationMatrixFromVector(rotMatrix, event.values);
                SensorManager.remapCoordinateSystem(rotMatrix,
                        SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X,
                        rotationMatrixAdjusted);
                SensorManager.getOrientation(rotationMatrixAdjusted, orientation)

                val rollAngleRadians = orientation[1]
                val pitchAngleRadians = orientation[2]
                              
                //Report results back to listener
                thisListener.onRollPitchEvent(rollAngleRadians, pitchAngleRadians)
            }
        }
于 2021-04-07T14:27:33.690 に答える