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),这里就不列出来了。
- Android开发:按一定频率同时获取多个传感器数据
- Android 手机获取加速度传感器加速度数据并自定义采样频率
- Android开发传感器应用---获取方向传感器
- android 获取所有传感器数据
- Android动态获取传感器数据
- Android传感器学习之加速度传感器数据获取
- Android之使用传感器获取相应数据
- Android之使用传感器获取相应数据
- Android之使用传感器获取相应数据
- Android之使用传感器获取相应数据
- Android开发传感器应用---获取加速度
- Windows传感器编程之获取传感器数据
- android获取传感器列表
- Android获取传感器列表
- android光传感器数据的获取及储存
- android传感器学习之获取手机传感器
- android传感器学习之获取手机传感器
- jsoup抓取网页上的数据,Android同时获取数据
- Tuhdo emacs 学习笔记
- windows内核驱动内存管理之Lookaside使用
- 一周乱弹(3.27 )1,copyProperties 比较2, java Object... objects 可变参数
- .Net AOP(二)远程代理Remoting/RealProxy
- 数字反演
- Android开发:按一定频率同时获取多个传感器数据
- BZOJ 1997 HNOI 2010 Planar 2-SAT
- 在c代码中使用logcat
- C++ 利于宏模拟C#的正则表达式
- HDU 1059 Dividing(多重背包)
- Android中序列化的实现?使用Serializable还是Parcelable
- 数学归纳法初探
- Android.mk内容介绍
- JavaScript作用域和执行环境