2013-01-21 66 views
4

在我的應用程序中,我想顯示設備的方向,如北,南,東,西。爲此,我使用加速計和磁性傳感器,並嘗試使用以下代碼。使用傳感器的方向

public class MainActivity extends Activity implements SensorEventListener 
{ 

public static float swRoll; 
public static float swPitch; 
public static float swAzimuth; 


public static SensorManager mSensorManager; 
public static Sensor accelerometer; 
public static Sensor magnetometer; 

public static float[] mAccelerometer = null; 
public static float[] mGeomagnetic = null; 


public void onAccuracyChanged(Sensor sensor, int accuracy) { 
} 

@Override 
public void onSensorChanged(SensorEvent event) 
{ 
    // onSensorChanged gets called for each sensor so we have to remember the values 
    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) 
    { 
     mAccelerometer = event.values; 
    } 

    if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) 
    { 
     mGeomagnetic = event.values; 
    } 

    if (mAccelerometer != null && mGeomagnetic != null) 
    { 
     float R[] = new float[9]; 
     float I[] = new float[9]; 
     boolean success = SensorManager.getRotationMatrix(R, I, mAccelerometer, mGeomagnetic); 

     if (success) 
     { 
      float orientation[] = new float[3]; 
      SensorManager.getOrientation(R, orientation); 
      // at this point, orientation contains the azimuth(direction), pitch and roll values. 
      double azimuth = 180 * orientation[0]/Math.PI; 
      //double pitch = 180 * orientation[1]/Math.PI; 
      //double roll = 180 * orientation[2]/Math.PI; 

      Toast.makeText(getApplicationContext(), "azimuth: "+azimuth, Toast.LENGTH_SHORT).show(); 
      //Toast.makeText(getApplicationContext(), "pitch: "+pitch, Toast.LENGTH_SHORT).show(); 
      //Toast.makeText(getApplicationContext(), "roll: "+roll, Toast.LENGTH_SHORT).show(); 
     } 
    } 
} 



@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); 
    accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 
    magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); 
} 

@Override 
protected void onResume() { 
    super.onResume(); 

    mSensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_GAME); 
    mSensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_GAME); 
} 

@Override 
protected void onPause() { 
    super.onPause(); 
    mSensorManager.unregisterListener(this, accelerometer); 
    mSensorManager.unregisterListener(this, magnetometer); 
} 
} 

我看了一些文章,並且知道方位角值是用來獲取方向的。但它沒有顯示出適當的值,即它總是顯示在任何方向上的值在103到140之間。我正在使用三星Galaxy S進行測試。我出錯的地方。 任何幫助將不勝感激......謝謝

+0

可以任何一個給我答案...請 –

回答

6

編輯:我要保持這個答案,因爲這裏沒有其他答案,但我的直覺再次看着這個代碼可能不起作用好。使用風險自負,如果有人給出一個體面的答案,我會刪除這個

這是我爲自己使用寫的指南針傳感器。它的工作,有點。實際上它需要更好的濾波 - 來自傳感器的結果非常嘈雜,我在它上面建立了一個濾波器來減緩更新並改進了它,但是如果要在生產中使用,它需要更好的濾波器

package com.gabesechan.android.reusable.sensor; 

import java.lang.ref.WeakReference; 
import java.util.HashSet; 


import android.content.Context; 
import android.hardware.Sensor; 
import android.hardware.SensorEvent; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorManager; 
import android.os.Handler; 
import android.os.Message; 

public class CompassSensor { 

SensorManager sm; 
int lastDirection = -1; 
int lastPitch; 
int lastRoll; 
boolean firstReading = true; 
HashSet<CompassListener> listeners = new HashSet<CompassListener>(); 

static CompassSensor mInstance; 

public static CompassSensor getInstance(Context ctx){ 
    if(mInstance == null){ 
     mInstance = new CompassSensor(ctx); 
    } 
    return mInstance; 
} 

private CompassSensor(Context ctx){ 
    sm = (SensorManager) ctx.getSystemService(Context.SENSOR_SERVICE); 
    onResume(); 
} 

public void onResume(){ 
    sm.registerListener(sensorListener, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); 
    sm.registerListener(sensorListener, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_UI); 
    firstReading = true; 
    //Restart the timer only if we have listeners 
    if(listeners.size()>0){ 
     handler.sendMessageDelayed(Message.obtain(handler, 1),1000); 
    } 
} 

public void onPause(){ 
    sm.unregisterListener(sensorListener); 
    handler.removeMessages(1); 
} 

private final SensorEventListener sensorListener = new SensorEventListener(){ 
    float accelerometerValues[] = null; 
    float geomagneticMatrix[] = null; 
    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 && event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) { 

      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 = normalizeDegrees(filterChange((int)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; 
      } 
     } 
    } 

    public void onAccuracyChanged(Sensor sensor, int accuracy) { 

    } 
}; 


//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 static final int MAX_CHANGE = 3; 
private int filterChange(int newDir){ 
    newDir = normalizeDegrees(newDir); 
    //On the first reading, assume it's right. Otherwise NW readings take forever to ramp up 
    if(firstReading){ 
     firstReading = false; 
     return newDir; 
    }  

    //Figure out how many degrees to move 
    int delta = newDir - lastDirection; 
    int normalizedDelta = normalizeDegrees(delta); 
    int change = Math.min(Math.abs(delta),MAX_CHANGE); 

    //We always want to move in the direction of lower distance. So if newDir is lower and delta is less than half a circle, lower lastDir 
    // Same if newDir is higher but the delta is more than half a circle (you'd be faster in the other direction going lower). 
    if(normalizedDelta > 180){ 
     change = -change; 
    } 

    return lastDirection+change; 
} 

public void addListener(CompassListener listener){ 
    if(listeners.size() == 0){ 
     //Start the timer on first listener 
     handler.sendMessageDelayed(Message.obtain(handler, 1),1000); 
    } 
    listeners.add(listener); 
} 

public void removeListener(CompassListener listener){ 
    listeners.remove(listener); 
    if(listeners.size() == 0){ 
     handler.removeMessages(1); 
    } 

} 

public int getLastDirection(){ 
    return lastDirection; 
} 
public int getLastPitch(){ 
    return lastPitch; 
} 
public int getLastRoll(){ 
    return lastPitch; 
} 

private void callListeners(){ 
    for(CompassListener listener: listeners){ 
     listener.onDirectionChanged(lastDirection, lastPitch, lastRoll); 
    }    

} 

//This handler is run every 1s, and updates the listeners 
//Static class because otherwise we leak, Eclipse told me so 
static class IncomingHandler extends Handler { 
    private final WeakReference<CompassSensor> compassSensor; 

    IncomingHandler(CompassSensor sensor) { 
     compassSensor = new WeakReference<CompassSensor>(sensor); 
    } 
    @Override 
    public void handleMessage(Message msg) 
    { 
     CompassSensor sensor = compassSensor.get(); 
     if (sensor != null) { 
       sensor.callListeners(); 
     } 
     sendMessageDelayed(Message.obtain(this, 1), 1000); 
    } 
} 

IncomingHandler handler = new IncomingHandler(this); 

public interface CompassListener { 
    void onDirectionChanged(int direction, int pitch, int roll); 
} 

} 
+0

謝謝...我會試試這個.. –