Android开发:按一定频率同时获取多个传感器数据

来源:互联网 发布:淘宝评论怎么没有了 编辑:程序博客网 时间:2024/05/22 06:43

最近在做室内定位相关研究,希望通过手机传感器数据判断人的姿态和手机位置。之前很多研究只用到了加速度数据,但是判别的准确度偏低。本次我们的研究准备将加速度传感器、角速度传感器、方位传感器、压力传感器等数据结合起来,用于提高判别的准确度。
具体如何采集这些数据,网上并没有相关代码。在这里把自己的实现方法分享出来,供大家参考。
首先是建立加速度的类AccData(本文只涉及传感器数据采集相关代码,AccData类中从数据库获取数据的代码已经略去):

/** * Created by Maolin Liu on 2016/3/12. */public class AccData {    public long timestamp;    public double ax;    public double ay;    public double az;    public static final String TABLE_NAME = "AccData";    public static final String _ID = "_id";    public static final String TIMESTAMP = "timestamp";    public static final String AX = "ax";    public static final String AY = "ay";    public static final String AZ = "az";    //生成表的sql语句    public static String tableCreateSQL() {        StringBuffer sql = new StringBuffer();        sql.append("create table ");        sql.append(TABLE_NAME);        sql.append(" (");        sql.append(_ID);        sql.append(" integer primary key autoincrement,");        sql.append(TIMESTAMP);        sql.append(" long,");        sql.append(AX);        sql.append(" double,");        sql.append(AY);        sql.append(" double,");        sql.append(AZ);        sql.append(" double");        sql.append(" )");        return sql.toString();    }    public long insertDataBase(SQLiteDatabase sqLiteDatabase) {        ContentValues values = new ContentValues();        values.put(TIMESTAMP, timestamp);        values.put(AX, ax);        values.put(AY, ay);        values.put(AZ, az);        return(sqLiteDatabase.insert(TABLE_NAME, null, values));    }    public AccData clone() {        AccData accData = new AccData();        accData.timestamp = timestamp;        accData.ax = ax;        accData.ay = ay;        accData.az = az;        return accData;    }}

然后是加速度的SQLiteOpenHelper类,即AccDBOpenHelper:

/** * Created by Maolin Liu on 2016/3/12. */public class AccDBOpenHelper extends SQLiteOpenHelper {    private static final String DBNAME = "Acc Data.db3";    private static final int VERSION = 1;    public AccDBOpenHelper(Context context){        super(context,DBNAME,null,VERSION);    }    public AccDBOpenHelper(Context context, String name,SQLiteDatabase.CursorFactory factory, int version){        super(context, name, factory, version);        // TODO Auto-generated constructor stub    }    @Override    public void onCreate(SQLiteDatabase db){        db.execSQL(AccData.tableCreateSQL());    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){        System.out.println( "----------AccDBOpenHelper onUpdata Called----------" + oldVersion + "-->" + newVersion);    }}

按照和上面类似的方法为角速度数据、方位数据、压力数据建立数据类和对应的SQLiteOpenHelper类。
下面是具体的实现了。如果将采集数据的的代码放在Activity中,用户体验不是特别好。所以我们在后台Service中进行数据采集。需要注意几个地方,第一,往数据库中存储大量数据的时候最好添加事务,这样会提高存储效率;第二,方向数据要通过计算获得,而不是通过传感器直接获取,如果需要用到azimuth、pitch和roll数据需要特别注意这一点(详情点击:Android Orientation Sensor(方向传感器)详解与应用)。第三,API等级在19以上,可以自由设置传感器的采样频率,注意单位是微秒(10 -6秒)。
下面是Service具体代码:

/** * Created by Maolin Liu on 2016/3/12.   */public class DataAcquireService extends Service {    private SensorManager sensorManager;    private MySensorBinder mySensorBinder;    private Timer updateTimer;    private AccDBOpenHelper accDBOpenHelper;    private SQLiteDatabase accDB;    private List<AccData> accDataList;    private AccData accData;    private float accValues[];    private GyrDBOpenHelper gyrDBOpenHelper;    private SQLiteDatabase gyrDB;    private List<GyrData> gyrDataList;    private GyrData gyrData;    private float gyrValues[];    private MagAndOriDBOpenHelper magAndOriDBOpenHelper;    private SQLiteDatabase magAndOriDB;    private List<MagAndOriData> magAndOriDataList;    private MagAndOriData magAndOriData;    private PreDBOpenHelper preDBOpenHelper;    private SQLiteDatabase preDB;    private List<PreData> preDataList;    private PreData preData;    private float preValue;    private float magValues[];    private boolean isRecord ;             //开始存储或者关闭存储的Boolean值    public static final String ACTION_STATE_COLLECT_SERVICE = "edu.geosis.service.DATA_ACQUIRE_SERVICE";    @Override    public IBinder onBind(Intent intent) {        System.out.println("DataAcquireService is binded ! ");        return mySensorBinder;    }    @Override    public void onCreate() {        super.onCreate();        initializeVariables();                 }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        System.out.println("DataAcquireService is started ! ");        return super.onStartCommand(intent, flags, startId);    }    @Override    public void onDestroy() {        if (accDB != null && accDB.isOpen()) {            accDB.close();        }        if (gyrDB != null && gyrDB.isOpen()) {            gyrDB.close();        }        if (magAndOriDB != null && magAndOriDB.isOpen()) {            magAndOriDB.close();        }        if (preDB != null && preDB.isOpen()) {            preDB.close();        }        sensorManager.unregisterListener(mySensorListener);              System.out.println("DataAcquireService is destroyed ! ");        super.onDestroy();    }    @Override    public boolean onUnbind(Intent intent) {        System.out.println("DataAcquireService is onUnbinded ! ");        return super.onUnbind(intent);    }    @Override    public void onRebind(Intent intent) {        System.out.println("DataAcquireService is onRebinded ! ");        super.onRebind(intent);    }    private void initializeVariables() {        mySensorBinder = new MySensorBinder();        sensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);        accDBOpenHelper = new AccDBOpenHelper(this, "Acc Data.db3", null, 1);       //存储在默认路径下        accDB = accDBOpenHelper.getReadableDatabase();        accDataList = new ArrayList<AccData>();        accData = new AccData();        gyrDBOpenHelper = new GyrDBOpenHelper(this, "Gyr Data.db3", null, 1);        gyrDB = gyrDBOpenHelper.getReadableDatabase();        gyrDataList = new ArrayList<GyrData>();        gyrData = new GyrData();        magAndOriDBOpenHelper = new MagAndOriDBOpenHelper(this, "MagAndOri Data.db3", null, 1);             magAndOriDB = magAndOriDBOpenHelper.getReadableDatabase();        magAndOriDataList = new ArrayList<MagAndOriData>();        magAndOriData = new MagAndOriData();        preDBOpenHelper = new PreDBOpenHelper(this, "Pre Data.db3", null, 1);        preDB = preDBOpenHelper.getReadableDatabase();        preDataList = new ArrayList<PreData>();        preData = new PreData();        isRecord = false;    }    /**     * Service对应的Activity通过下面的Binder类对采集数据的过程进行控制     **/    public class MySensorBinder extends Binder {        public void startRecord() {            isRecord = true;        }        public void stopRecord() {            isRecord = false;        }        public void clearRecord() {            accDataList.clear();            gyrDataList.clear();            magAndOriDataList.clear();            preDataList.clear();        }        public boolean insertDB() {            //make clear whether it is "||" or "&&"            if (accDataList.isEmpty() && gyrDataList.isEmpty() && preDataList.isEmpty()&& magAndOriDataList.isEmpty()) {                return false;            } else {                //存储时开启事务能大大加快存储速度,否则一条一条地存储特别费时                accDB.beginTransaction();                try {                    for (AccData accData: accDataList) {                        accData.insertDataBase(accDB);                    }                    accDB.setTransactionSuccessful();                }                catch(Exception e) {                    e.printStackTrace();                    System.out.println("accData cannot insert into the database !");                }                finally {                    accDB.endTransaction();                }                gyrDB.beginTransaction();                try {                    for (GyrData gyrData: gyrDataList) {                        gyrData.insertDataBase(gyrDB);                    }                    gyrDB.setTransactionSuccessful();                }                catch(Exception e) {                    e.printStackTrace();                }                finally {                    gyrDB.endTransaction();                }                magAndOriDB.beginTransaction();                try {                    for (MagAndOriData magAndOriData: magAndOriDataList) {                        magAndOriData.insertDataBase(magAndOriDB);                    }                    magAndOriDB.setTransactionSuccessful();                }                catch(Exception e) {                    e.printStackTrace();                }                finally {                    magAndOriDB.endTransaction();                }                preDB.beginTransaction();                try {                    for (PreData preData: preDataList) {                        preData.insertDataBase(preDB);                    }                    preDB.setTransactionSuccessful();                }                catch(Exception e) {                    e.printStackTrace();                }                finally {                    preDB.endTransaction();                }                return true;            }        }        public void registerListener() {            boolean result =   sensorManager.registerListener(mySensorListener,                    sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),                    SensorManager.SENSOR_DELAY_GAME);                              //最后一个参数用于控制传感器数据获取的频率,频率可以自由调整            Log.d("maolin",""+result);   //LOG查看监听是否成功注册            sensorManager.registerListener(mySensorListener,                    sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),                    SensorManager.SENSOR_DELAY_GAME);            sensorManager.registerListener(mySensorListener,                    sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),                    SensorManager.SENSOR_DELAY_GAME);            sensorManager.registerListener(mySensorListener,                    sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),                    SensorManager.SENSOR_DELAY_GAME);        }        public void unregisterListener() {            sensorManager.unregisterListener(mySensorListener);            System.out.println("StateCollectService listener is unregistered ! ");        }    }    //下面是传感器变化监听的关键类    private SensorEventListener mySensorListener = new SensorEventListener() {        @Override        public void onSensorChanged(SensorEvent event) {            switch(event.sensor.getType()) {                case Sensor.TYPE_ACCELEROMETER:                    accValues = event.values.clone();                    synchronized (accData) {                        accData.timestamp = System.currentTimeMillis();                        accData.ax = accValues[0];                        accData.ay = accValues[1];                        accData.az = accValues[2];                        if (isRecord) {                            accDataList.add(accData.clone());                        }                    }                    break;                case Sensor.TYPE_GYROSCOPE:                    gyrValues = event.values.clone();                    synchronized (gyrData) {                        gyrData.timestamp = System.currentTimeMillis();                        gyrData.gx = gyrValues[0];                        gyrData.gy = gyrValues[1];                        gyrData.gz = gyrValues[2];                        if (isRecord) {                            gyrDataList.add(gyrData.clone());                        }                    }                    break;                case Sensor.TYPE_PRESSURE:                    preValue = event.values[0];                    synchronized (preData) {                        preData.timestamp = System.currentTimeMillis();                        preData.pressure = preValue;                        if (isRecord) {                            preDataList.add(preData.clone());                        }                    }                    break;                case Sensor.TYPE_MAGNETIC_FIELD:               //加速度、陀螺仪和气压计都可以直接获得,但是磁力计和方位角数据要通过计算才能得到                    magValues = event.values;                    break;            }        }        @Override        public void onAccuracyChanged(Sensor sensor, int i) {        }    };}

然后就是操作界面DataAcquireActivity :

/** * Created by GeoSIS on 2016/3/12. */public class DataAcquireActivity extends Activity {    private Chronometer chronometer = null;    //添加一个计时器,知道采集的时长;    private Button btnStart,btnEnd;    private ServiceConnection dataAcquireConnection;    private DataAcquireService.MySensorBinder mySensorBinder;    private ArrayList<Long> savedTime;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_data_acquire);        initializeVariables();        initializeButton();    }    @Override    protected void onStart() {        super.onStart();    }    @Override    protected void onRestart() {        super.onRestart();    }    @Override    protected void onResume() {        super.onResume();    }    @Override    protected void onPause() {        super.onPause();    }    @Override    protected void onStop() {        super.onStop();    }    @Override    protected void onDestroy() {        unbindService(dataAcquireConnection);        super.onDestroy();    }    private void initializeVariables() {        // TODO Auto-generated method stub        chronometer = (Chronometer)findViewById(R.id.chronometer);        btnStart    = (Button)findViewById(R.id.start_pick_up);        btnEnd      = (Button)findViewById(R.id.end_pick_up);    }    private void initializeButton() {        // TODO Auto-generated method stub        btnStart.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View arg0) {                // TODO Auto-generated method stub                chronometer.setBase(SystemClock.elapsedRealtime());                chronometer.start();                mySensorBinder.registerListener();                mySensorBinder.startRecord();                btnStart.setClickable(false);                                                 btnStart.setBackgroundColor(getResources().getColor(R.color.yellow));            }        });        btnEnd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View arg0) {                // TODO Auto-generated method stub                chronometer.stop();                mySensorBinder.stopRecord();                mySensorBinder.insertDB();                mySensorBinder.clearRecord();                mySensorBinder.unregisterListener();               finish();            }        });    }}

Activity对应的XML文件非常简单,上面只有一个计时器(Chronometer)、一个开始采集的按钮(Button)和一个结束采集的按钮(Button),这里就不列出来了。

2 1
原创粉丝点击