2012-09-04 56 views
0

我試圖在Android中獲取相機的方向。我有一些代碼可以在肖像中完美運行(我通過慢慢轉圈並相互更新1秒來測試它),但它在風景中根本不起作用 - 數字似乎隨機變化。從肖像切換到風景後,它也完全不適用。這是我的代碼從橫向模式或翻轉方向後的傳感器獲取方向

public void onSensorChanged(SensorEvent event) { 

    switch (event.sensor.getType()) { 
    case Sensor.TYPE_ACCELEROMETER: 
     accelerometerValues = event.values.clone(); 

     break; 
    case Sensor.TYPE_MAGNETIC_FIELD: 
     geomagneticMatrix = event.values.clone(); 
     break; 
    default: 
     break; 
    } 

    if (geomagneticMatrix != null && accelerometerValues != null) { 

     float[] R = new float[16]; 
     float[] I = new float[16]; 
     float[] outR = new float[16]; 

     //Get the rotation matrix, then remap it from camera surface to world coordinates 
     SensorManager.getRotationMatrix(R, I, accelerometerValues, geomagneticMatrix); 
     SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR); 
     float values[] = new float[4]; 
     SensorManager.getOrientation(outR,values); 
     float direction = normalizeDegrees((float) Math.toDegrees(values[0])); 
     float pitch = normalizeDegrees((float) Math.toDegrees(values[1])); 
     float roll = normalizeDegrees((float) Math.toDegrees(values[2])); 

     if((int)direction != (int)lastDirection){ 
      lastDirection = direction; 
      for(CompassListener listener: listeners){ 
       listener.onDirectionChanged(lastDirection, pitch, roll); 
      } 
     } 
    } 
} 

任何想法我做錯了什麼?我坦率地承認,我不會100%明白這一點。我也不知道Google爲什麼棄用定位傳感器 - 這似乎是一種普遍的想法。

回答

1

您是否考慮過,當您從縱向更改爲橫向時,加速計軸會發生變化?像Y軸變成Z軸等等。這可能是奇怪行爲的一個來源。

+0

我想到了這一點。這裏是y軸和x軸切換(z始終在屏幕外)。但是,這看起來沒有正確地移動 - 我已經將全部3個投影到了屏幕上,並且它們都沒有正確移動。即使工作方向也像瘋了一樣跳躍 - 在轉彎後以1秒的間隔取樣可能導致180,320,280,220,180,300,...的讀數應該是200。 –

0

我似乎已經解決了它,或者至少改進了它,直到我知道什麼是問題。我加入了一個濾波器,以便不用傳遞單個傳感器讀數,而是記住最後的讀數並對其應用增量。每個新的傳感器點允許添加最多5度。這完全濾除了奇怪的跳躍,並強制它收斂到一個值。我感到偶爾會有奇怪的跳躍,但我認爲我需要的是更復雜的過濾器。新代碼:

public void onSensorChanged(SensorEvent event) { 
    if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE) 
     return; 

    switch (event.sensor.getType()) { 
    case Sensor.TYPE_ACCELEROMETER: 
     accelerometerValues = event.values.clone(); 

     break; 
    case Sensor.TYPE_MAGNETIC_FIELD: 
     geomagneticMatrix = event.values.clone(); 
     break; 
    } 

    if (geomagneticMatrix != null && accelerometerValues != null) { 

     float[] R = new float[16]; 
     float[] I = new float[16]; 
     float[] outR = new float[16]; 

     //Get the rotation matrix, then remap it from camera surface to world coordinates 
     SensorManager.getRotationMatrix(R, I, accelerometerValues, geomagneticMatrix); 
     SensorManager.remapCoordinateSystem(R, SensorManager.AXIS_X, SensorManager.AXIS_Z, outR); 
     float values[] = new float[4]; 
     SensorManager.getOrientation(outR,values); 

     int direction = filterChange(normalizeDegrees(Math.toDegrees(values[0]))); 
     int pitch = normalizeDegrees(Math.toDegrees(values[1])); 
     int roll = normalizeDegrees(Math.toDegrees(values[2])); 
     if((int)direction != (int)lastDirection){ 
      lastDirection = (int)direction; 
      lastPitch = (int)pitch; 
      lastRoll = (int)roll; 
      for(CompassListener listener: listeners){ 
       listener.onDirectionChanged(lastDirection, pitch, roll); 
      } 
     } 
    } 
} 

//Normalize a degree from 0 to 360 instead of -180 to 180 
private int normalizeDegrees(double rads){ 
    return (int)((rads+360)%360); 
} 

//We want to ignore large bumps in individual readings. So we're going to cap the number of degrees we can change per report 
private int filterChange(int newDir){ 
    int change = newDir - lastDirection; 
    int circularChange = newDir-(lastDirection+360); 
    int smallestChange; 
    if(Math.abs(change) < Math.abs(circularChange)){ 
     smallestChange = change; 
    } 
    else{ 
     smallestChange = circularChange; 
    } 
    smallestChange = Math.max(Math.min(change,5),-5); 
    return lastDirection+smallestChange; 
} 
+0

快速評論 - 值3和-3似乎提供了相當不錯的反彈保護。 –