How to read Android accelerometer values in a stable and accurate way?

前端 未结 1 1528
执念已碎
执念已碎 2020-12-17 05:11

In a my project I am trying to control a car using data obtained through the accelerometer of an Android device. (Left, Right, Forward, Reverse). Even though I have managed

1条回答
  •  情歌与酒
    2020-12-17 05:45

    Old question, but I'm answering here for the sake of others that find this question.

    First off, following @andrew-morton link is exactly what I needed, but was in pseudo code, so here is Java for Android!

    Second: If you can (you're min API Lvl is 9 or higher), simply use the Sensor.TYPE_GRAVITY. As it is already smoothed out. If you need to support older API Lvls (like I had to), this code should do the trick!

    Lastly: This code snippet is somewhat modified from what I am using it for, if you want to use this for yourself, you'll need to create a getter for the Vector3 gravity.

    Notes: I've found that a rolling average of 5 (MAX_SAMPLE_SIZE) is quite smooth. 10 is even more smooth, but you start to notice lag.

    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[] 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();
                rollingAverage[1] = new ArrayList();
                rollingAverage[2] = new ArrayList();
    
                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 roll(List list, float newMember){
            if(list.size() == MAX_SAMPLE_SIZE){
                list.remove(0);
            }
            list.add(newMember);
            return list;
        }
    
        public float averageList(List 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 讨论(0)
提交回复
热议问题