12

次の方法で携帯電話の現在の向きを取得したい:

  1. getRotationMatrix()最初におよびを介して初期方向 (方位角) を取得しgetOrientation()ます。
  2. 時間の経過に伴うジャイロスコープの読み取りの統合を追加して、現在の向きを取得します。

電話の向き:

携帯電話の xy 平面は、地面と平行に固定されています。すなわち、「歩きながらテキストメッセージ」の向きです。

" getOrientation()" 返品:

Android API を使用すると、方位角、ピッチ、ロールなどの方向を から簡単に取得できますgetOrientation()

このメソッドは常にとの範囲内の値を返すことに注意してください。[0, -PI][o, PI]

私の問題:

で示されるジャイロスコープの読み取り値の統合はdR非常に大きい可能性があるため、 を実行するとCurrentOrientation += dR、との範囲CurrentOrientationを超える可能性があります。[0, -PI][o, PI]

[0, -PI]との範囲内で常に現在の向きを取得できるようにするには、どのような操作が必要[o, PI]ですか?

私はPythonで次のことを試しましたが、その正しさを非常に疑っています.

rotation = scipy.integrate.trapz(gyroSeries, timeSeries) # integration
if (headingDirection - rotation) < -np.pi:
    headingDirection += 2 * np.pi
elif (headingDirection - rotation) > np.pi:
    headingDirection -= 2 * np.pi
# Complementary Filter
headingDirection = ALPHA * (headingDirection - rotation) + (1 - ALPHA) * np.mean(azimuth[np.array(stepNo.tolist()) == i])
if headingDirection < -np.pi:
    headingDirection += 2 * np.pi
elif headingDirection > np.pi:
    headingDirection -= 2 * np.pi

備考

これは、次のトラブルメーカーが関係しているため、それほど単純ではありません。

  1. 方向センサーの読み取り値は から0に進み-PI、次に に直接ジャンプ+PI、徐々に に戻ります。0+PI/2
  2. ジャイロスコープの読み取りの統合も、いくつかの問題につながります。オリエンテーションに追加dRするか、または減算する必要がありますdR

確認済みの回答を提供する前に、まず Android ドキュメントを参照してください。

推定の答えは役に立ちません。

4

4 に答える 4

2

減価償却された「方向センサー」を避け、すでにジャイロスコープデータを使用している、Invensense の特別な融合アルゴリズムを既に実装している getRotationVector、getRotationMatrix などのセンサー融合メソッドを使用する必要があると思います。

単純なセンサー フュージョン アルゴリズムが必要な場合は、バランス フィルター ( http://www.filedump.net/dumped/filter1285099462.pdfを参照) を使用できます。アプローチは

http://postimg.org/image/9cu9dwn8z/

これは、ジャイロスコープを統合して角度を取得し、結果をハイパス フィルター処理してドリフトを除去し、平滑化された加速度計とコンパスの結果に追加します。統合されたハイパス フィルター処理されたジャイロ データと加速度計/コンパス データは、2 つの部分が 1 つになるように追加されるため、出力は意味のある単位で正確な推定値になります。バランス フィルタの場合、応答を調整するために時定数を微調整できます。時定数が短いほど応答性は良くなりますが、加速ノイズを多く通過させてしまいます。

これがどのように機能するかを確認するために、最新のジャイロ データ ポイント (rad/s) がジャイロに保存され、加速度計からの最新の角度測定値が angle_acc に保存され、dtis が最後のジャイロ データから現在までの時間であると想像してください。次に、新しい角度は次を使用して計算されます

角度 = b * (角度 + ジャイロ*dt) + (1 - b) *(angle_acc);

たとえば、b = 0.98 を試すことから始めることができます。また、次の測定が行われる前にジャイロが数度以上ドリフトしないように、おそらく高速ジャイロスコープ測定時間 dt を使用することをお勧めします。バランス フィルターは便利で簡単に実装できますが、理想的なセンサー フュージョン アプローチではありません。Invensense のアプローチには、いくつかの巧妙なアルゴリズムと、おそらく何らかの形式のカルマン フィルターが含まれます。

出典: Professional Android Sensor Programming、Adam Stroud。

于 2013-08-08T22:29:43.327 に答える
2

Android の方向検出の実装で処理できるようにすることをお勧めします。はい、取得する値は -PI から PI であり、それらを度 (0-360) に変換できます。いくつかの関連部分:

処理するデータの保存:

@Override
public void onSensorChanged(SensorEvent sensorEvent) {
    switch (sensorEvent.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            mAccValues[0] = sensorEvent.values[0];
            mAccValues[1] = sensorEvent.values[1];
            mAccValues[2] = sensorEvent.values[2];
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            mMagValues[0] = sensorEvent.values[0];
            mMagValues[1] = sensorEvent.values[1];
            mMagValues[2] = sensorEvent.values[2];
            break;
    }

}

ロール、ピッチ、ヨー (方位角) の計算。mRおよびmIは、回転行列と傾斜行列を保持するための arrys でmOあり、一時的な配列です。配列mResultsの末尾には度単位の値があります。

    private void updateData() {
    SensorManager.getRotationMatrix(mR, mI, mAccValues, mMagValues);

    /**
     * arg 2: what world(according to app) axis , device's x axis aligns with
     * arg 3: what world(according to app) axis , device's y axis aligns with
     * world x = app's x = app's east
     * world y = app's y = app's north
     * device x = device's left side = device's east
     * device y = device's top side  = device's north
     */

    switch (mDispRotation) {
        case Surface.ROTATION_90:
            SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X, mR2);
            break;
        case Surface.ROTATION_270:
            SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X, mR2);
            break;
        case Surface.ROTATION_180:
            SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y, mR2);
            break;
        case Surface.ROTATION_0:
        default:
            mR2 = mR;
    }

    SensorManager.getOrientation(mR2, mO);


    //--upside down when abs roll > 90--
    if (Math.abs(mO[2]) > PI_BY_TWO) {
        //--fix, azimuth always to true north, even when device upside down, realistic --
        mO[0] = -mO[0];

        //--fix, roll never upside down, even when device upside down, unrealistic --
        //mO[2] = mO[2] > 0 ? PI - mO[2] : - (PI - Math.abs(mO[2]));

        //--fix, pitch comes from opposite , when device goes upside down, realistic --
        mO[1] = -mO[1];
    }

    CircleUtils.convertRadToDegrees(mO, mOut);
    CircleUtils.normalize(mOut);

    //--write--
    mResults[0] = mOut[0];
    mResults[1] = mOut[1];
    mResults[2] = mOut[2];
}
于 2013-08-15T07:41:12.943 に答える