2013-07-31 47 views
8

我的AR視圖像一個指南針一樣,真的很煩人。因此,當我用縱向手持手機(以便屏幕指向我的臉)時,我將remapCoordinateSystem稱爲手持縱向時的音高爲0。然後,方位角(指南針功能)是完美的,但只要我傾斜手機,方位角就會被破壞,如果我向前彎曲,方位角會增加,如果我向後彎曲,則會減小。Android getOrientation當手機傾斜時,方位角會被污染

我使用2個傳感器來獲取讀數,Sensor.TYPE_MAGNETIC_FIELDSensor.TYPE_GRAVITY

我使用了一個非常基本的低通濾波器,它通過一個常數alpha實現,並直接用於傳感器的讀取值。

這裏是我的代碼:

float[] rotationMatrix = new float[9]; 
SensorManager.getRotationMatrix(rotationMatrix, null, gravitymeterValues, 
    magnetometerValues); 

float[] remappedRotationMatrix = new float[9]; 

SensorManager.remapCoordinateSystem(rotationMatrix, SensorManager.AXIS_X, 
    SensorManager.AXIS_Z, remappedRotationMatrix); 

float results[] = new float[3]; 
SensorManager.getOrientation(remappedRotationMatrix, results); 

float azimuth = (float) (results[0] * 180/Math.PI); 
if (azimuth < 0) { 
    azimuth += 360; 
} 

float pitch = (float) (results[1] * 180/Math.PI); 
float roll = (float) (results[2] * 180/Math.PI); 

正如你看到的,這裏沒有魔法。當重力計值和磁力計值準備好使用時,我稱這段代碼。

我的問題是,如何在傾斜手機時阻止方位角變得瘋狂?

我在谷歌Play商店,指南針檢查了一個免費的應用程序,它並沒有解決這個問題,但我希望有一個解決方案。

我有2個解決方案,記住:

  1. 充分利用AR視圖只能工作在非常constrainted俯仰角,現在我有這樣的事情pitch >= -5 && pitch <= 30。如果未填滿,則會向用戶顯示一個屏幕,要求他/她將手機旋轉至肖像。

  2. 不知何故使用音高壓制方位角,這看起來像一個漂亮的設備特定的解決方案,但當然我很樂意提供建議。

我還可以補充一點,我一直在尋找一個體面的解決辦法了幾個小時,我還沒有發現任何給了我比2沒有更好的辦法)在這裏。

在此先感謝!

+0

你是什麼低通濾波器?使用TYPE_GRAVITY時不需要過濾。 –

+0

@HoanNguyen我是否需要低通'Sensor.TYPE_MAGNETIC_FIELD'?現在我低通'Sensor.TYPE_MAGNETIC_FIELD'和'Sensor.TYPE_GRAVITY'。 –

+1

不,使用低通濾波器是爲了消除x和y方向上的加速度。 getRotationMatrix要求第三個參數接近z方向上的加速度。如果使用TYPE_GRAVItY,則不需要低通濾波器,但許多設備不具有TYPE_GRAVITY,因此對於沒有TYPE_GRAVITY的設備,您需要使用TYPE_ACCELEROMETER和低通濾波器。 –

回答

14

有關完整的代碼中看到https://github.com/hoananguyen/dsensor
保持一個歷史平均出來的,我不知道俯仰和滾轉的正確解釋,因此下面的代碼是唯一的方位。

類成員

private List<float[]> mRotHist = new ArrayList<float[]>(); 
private int mRotHistIndex; 
// Change the value so that the azimuth is stable and fit your requirement 
private int mHistoryMaxLength = 40; 
float[] mGravity; 
float[] mMagnetic; 
float[] mRotationMatrix = new float[9]; 
// the direction of the back camera, only valid if the device is tilted up by 
// at least 25 degrees. 
private float mFacing = Float.NAN; 

public static final float TWENTY_FIVE_DEGREE_IN_RADIAN = 0.436332313f; 
public static final float ONE_FIFTY_FIVE_DEGREE_IN_RADIAN = 2.7052603f; 

onSensorChanged

@Override 
public void onSensorChanged(SensorEvent event) 
{ 
    if (event.sensor.getType() == Sensor.TYPE_GRAVITY) 
    { 
     mGravity = event.values.clone(); 
    } 
    else 
    { 
     mMagnetic = event.values.clone(); 
    } 

    if (mGravity != null && mMagnetic != null) 
    { 
      if (SensorManager.getRotationMatrix(mRotationMatrix, null, mGravity, mMagnetic)) 
      { 
       // inclination is the degree of tilt by the device independent of orientation (portrait or landscape) 
       // if less than 25 or more than 155 degrees the device is considered lying flat 
       float inclination = (float) Math.acos(mRotationMatrix[8]); 
       if (inclination < TWENTY_FIVE_DEGREE_IN_RADIAN 
         || inclination > ONE_FIFTY_FIVE_DEGREE_IN_RADIAN) 
       { 
        // mFacing is undefined, so we need to clear the history 
        clearRotHist(); 
        mFacing = Float.NaN; 
       } 
       else 
       { 
        setRotHist(); 
        // mFacing = azimuth is in radian 
        mFacing = findFacing(); 
       } 
      } 
    } 
} 

private void clearRotHist() 
{ 
    if (DEBUG) {Log.d(TAG, "clearRotHist()");} 
    mRotHist.clear(); 
    mRotHistIndex = 0; 
} 

private void setRotHist() 
{ 
    if (DEBUG) {Log.d(TAG, "setRotHist()");} 
    float[] hist = mRotationMatrix.clone(); 
    if (mRotHist.size() == mHistoryMaxLength) 
    { 
     mRotHist.remove(mRotHistIndex); 
    } 
    mRotHist.add(mRotHistIndex++, hist); 
    mRotHistIndex %= mHistoryMaxLength; 
} 

private float findFacing() 
{ 
    if (DEBUG) {Log.d(TAG, "findFacing()");} 
    float[] averageRotHist = average(mRotHist); 
    return (float) Math.atan2(-averageRotHist[2], -averageRotHist[5]); 
} 

public float[] average(List<float[]> values) 
{ 
    float[] result = new float[9]; 
    for (float[] value : values) 
    { 
     for (int i = 0; i < 9; i++) 
     { 
      result[i] += value[i]; 
     } 
    } 

    for (int i = 0; i < 9; i++) 
    { 
     result[i] = result[i]/values.size(); 
    } 

    return result; 
} 
+0

好東西!現在我的方位要好得多,現在唯一的問題是快速移動它跳得很快,但我想你必須忍受這一點。非常感謝您的代碼。還有一個問題:傳感器的更新率是多少? UI /遊戲/哪一個?謝謝 –

+2

我使用Normal,這對我的目的來說已經足夠了。 –

+0

您是否在指南針應用程序中使用此代碼?我使用用戶界面,這是非常頻繁的,順便說一句,我的代碼非常棒! –