2013-04-07 57 views
2

在我的項目中,我試圖使用通過Android設備的加速計獲取的數據來控制汽車。 (左,右,前進,後退)。即使我設法從加速度計讀取數值,即使設備處於穩定位置,讀數也會經常發生變化。有人能爲我提供一個更好的方式來做到這一點嗎?如何以穩定和準確的方式讀取Android加速度計值?

以下是我已經使用

import android.content.Context; 
import android.hardware.Sensor; 
import android.hardware.SensorEvent; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorManager; 

public class AccelerometerService { 
    private static SensorManager sensorManager; 
    private static SensorEventListener sensorEventListener; 
    private static boolean started = false; 

    private static float[] accelerometer = new float[3]; 
    private static float[] magneticField = new float[3]; 

    private static float[] rotationMatrix = new float[9]; 
    private static float[] inclinationMatrix = new float[9]; 
    private static float[] attitude = new float[3]; 

    private final static double RAD2DEG = 180/Math.PI; 

    private static int initialAzimuth = 0; 
    private static int initialPitch = 0; 
    private static int initialRoll = 0; 

    private static int[] attitudeInDegrees = new int[3]; 

    public static void start(final Context applicationContext) { 
     if(started) { 
      return; 
     } 

     sensorManager = (SensorManager) applicationContext 
       .getSystemService(Context.SENSOR_SERVICE); 

     sensorEventListener = new SensorEventListener() { 

      @Override 
      public void onSensorChanged(SensorEvent event) { 

       int type = event.sensor.getType(); 
       if(type == Sensor.TYPE_MAGNETIC_FIELD) { 
        magneticField = event.values.clone(); 
       } 
       if(type == Sensor.TYPE_ACCELEROMETER) { 
        accelerometer = event.values.clone(); 
       } 

       SensorManager.getRotationMatrix(rotationMatrix, inclinationMatrix, accelerometer, magneticField); 
       SensorManager.getOrientation(rotationMatrix, attitude); 

       attitudeInDegrees[0] = (int) Math.round(attitude[0] * RAD2DEG); //azimuth 
       attitudeInDegrees[1] = (int) Math.round(attitude[1] * RAD2DEG);  //pitch 
       attitudeInDegrees[2] = (int) Math.round(attitude[2] * RAD2DEG);  //roll 
      } 

      @Override 
      public void onAccuracyChanged(Sensor sensor, int accuracy) { 

      } 
     }; 
     sensorManager.registerListener(sensorEventListener, 
       sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
       SensorManager.SENSOR_DELAY_UI); 
     sensorManager.registerListener(sensorEventListener, 
       sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), 
       SensorManager.SENSOR_DELAY_UI); 

     started = true; 
    } 

    public static boolean getStarted() { 
     return started; 
    } 

    public static void stop() { 
     if(started) { 
     sensorManager.unregisterListener(sensorEventListener); 
     started = false; 
     } 
    } 
} 
+2

這聽起來像你想要平滑數據:http://stackoverflow.com/questions/4611599/help-smoothing-data-from-a-sensor – 2013-04-07 15:44:18

+1

多少波動,你得到什麼? – 2013-04-07 15:45:54

+1

您可以使用「卡爾曼濾波器」 http://stackoverflow.com/questions/1638864/filtering-accelerometer-data-noise – serhiisavruk 2013-04-07 15:48:29

回答

9

老問題的代碼,但是我在這裏回答爲別人認爲找到這一問題的緣故。

首先,遵循@ andrew-morton鏈接正是我所需要的,但是在僞代碼中,所以這裏是適用於Android的Java!第二:如果你可以(你最小的API Lvl是9或更高),只需使用Sensor.TYPE_GRAVITY即可。因爲它已經平滑了。如果您需要支持較舊的API Lvls(就像我必須的那樣),那麼這段代碼應該可以做到!

最後:這段代碼與我使用的代碼段有所不同,如果你想自己使用它,你需要爲Vector3重力創建一個getter。

備註: 我發現滾動平均值5(MAX_SAMPLE_SIZE)非常平滑。 10更加流暢,但你開始注意到滯後。

import android.hardware.Sensor; 
import android.hardware.SensorEvent; 
import android.hardware.SensorEventListener; 
import android.hardware.SensorManager; 
import java.util.ArrayList; 
import java.util.List; 

/** 
* Created by andy on 6/14/14. 
*/ 
public class AndroidGravityUpdate implements SensorEventListener { 
    private SensorManager sensorManager; 
    Vector3 gravity; 
    List<Float>[] rollingAverage = new List[3]; 

    private static final int MAX_SAMPLE_SIZE = 5; 

    AndroidGravityUpdate(SensorManager sensorManager) { 
     this.gravity = new Vector3(); 
     this.sensorManager = sensorManager; 

     if(sensorManager.getSensorList(Sensor.TYPE_GRAVITY).size() > 0){ 
      sensorManager.registerListener(
        this, 
        sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY), 
        SensorManager.SENSOR_DELAY_GAME 
      ); 
     } else if(sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() > 0) { 
      rollingAverage[0] = new ArrayList<Float>(); 
      rollingAverage[1] = new ArrayList<Float>(); 
      rollingAverage[2] = new ArrayList<Float>(); 

      sensorManager.registerListener(
        this, 
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
        SensorManager.SENSOR_DELAY_GAME 
       ); 
     } 

    } 

    @Override 
    public void onSensorChanged(SensorEvent event) { 
     if (event.sensor.getType()==Sensor.TYPE_GRAVITY){ 
      gravity.z = event.values[0]; 
      gravity.x = event.values[1]; 
      gravity.y = - event.values[2]; 
     } 
     else if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER) { 
      //For whatever reason, my Samsung only has "Accelerometer" 
      // But it is incredibly rough, so attempting to smooth 
      // it out with rolling averages. 
      rollingAverage[0] = roll(rollingAverage[0], event.values[0]); 
      rollingAverage[1] = roll(rollingAverage[1], event.values[1]); 
      rollingAverage[2] = roll(rollingAverage[2], -event.values[2]); 

      gravity.z = averageList(rollingAverage[0]); 
      gravity.x = averageList(rollingAverage[1]); 
      gravity.y = averageList(rollingAverage[2]); 
     } 
    } 

    public List<Float> roll(List<Float> list, float newMember){ 
     if(list.size() == MAX_SAMPLE_SIZE){ 
      list.remove(0); 
     } 
     list.add(newMember); 
     return list; 
    } 

    public float averageList(List<Float> tallyUp){ 

     float total=0; 
     for(float item : tallyUp){ 
      total+=item; 
     } 
     total = total/tallyUp.size(); 

     return total; 
    } 

    @Override 
    public void onAccuracyChanged(Sensor sensor, int accuracy) { 

    } 
} 

class Vector3 { 
    float x; 
    float y; 
    float z; 
} 
+0

謝謝你,它有點救了我的命。 – 2015-05-04 12:13:45

+0

你也可以用它來做磁傳感器嗎? – 2017-01-12 03:38:41

+0

您需要對其進行修改以符合您的需求,但沒有理由不能在磁性傳感器上添加滾動平均值。 – CenterOrbit 2017-01-12 16:46:06