android Motion Senor API 简介
作者:裘德超
目前,大多数Android手机手机都内置了很多传感器,大家熟知的有重力传感器,亮度传感器,加速度传感器等。本文将为大家介绍Android系统中的运动传感器。
Android系统为用户提供了多个运动传感器,其中,加速度传感器和陀螺仪传感器经常是由硬件实现,而重力传感器,线形加速度传感器,旋转向量传感器一般是由软件实现出来的,由软件实现的模拟传感器从一个或多个硬件传感器中获取数据来模拟该虚拟传感器。对于每一个传感器事件,运动传感器都返回一个多维数组,其中包含了传感器感知的数据。下表总结了Android平台中的所有运动传感器:
与传感器有关的类主要包含在android.hardware包中。
SensorManager:可以用来管理Android设备中指出的所有的传感器。
Sensor:具体的传感器,例如重力传感器,陀螺仪传感器。
通过SensorManager类的registerListener方法可以监听某一个传感器,当被监测的传感器的检测到数据变化时就会产生一个事件,回调该传感器的监听器,我们可以在回调方法中执行相应的操作应对数据的变化。
下面是测试程序的布局:首先是一个用于显示当前机器包含的所有硬件传感器和软件传感器的列表。然后分别是重力传感器,加速度传感器(包括重力),线性加速度传感器(不包括重力),陀螺仪传感器,旋转向量传感器的检测到的数据的显示窗口。
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:fadingEdge="vertical"android:scrollbars="vertical" ><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="vertical" ><TextViewandroid:id="@+id/metaPromt"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="metaPromt" /><TextViewandroid:id="@+id/gravityPromt"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="gravityPromt" /><TextViewandroid:id="@+id/accelerometerPromt"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="accelerometerPromt" /><TextViewandroid:id="@+id/linearAccelerometerPromt"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="linearAccelerometerPromt" /><TextViewandroid:id="@+id/gyroscopePromt"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="gyroscopePromt" /><TextViewandroid:id="@+id/rotationVectorPromt"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="rotationVectorPromt" /></LinearLayout>
</ScrollView>
src/org/reno/ MotionSensorsActivity.java
package org.reno;import java.util.List;import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;public class MotionSensorsActivity extends Activity {private SensorManager mSensorManager;private Sensor gravitySensor;private Sensor accelerometerSensor;private Sensor gyroscopeSensor;private Sensor linearAccelerometeSensor;private Sensor rotationVectorSensor;private TextView metaPromt;private TextView gravityPromt;private TextView accelerometerPromt;private TextView linearAccelerometerPromt;private TextView gyroscopePromt;private TextView rotationVectorPromt;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);metaPromt = (TextView) findViewById(R.id.metaPromt);// 从传感器管理器中获得全部的传感器列表List<Sensor> allSensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);// 显示有多少个传感器metaPromt.setText("经检测该手机有" + allSensors.size() + "个传感器,他们分别是:\n");// 显示每个传感器的具体信息for (Sensor s : allSensors) {String tempString = "\n" + " 设备名称:" + s.getName() + "\n"+ " 设备版本:" + s.getVersion() + "\n" + " 供应商:"+ s.getVendor() + "\n";switch (s.getType()) {case Sensor.TYPE_ACCELEROMETER:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 加速度传感器accelerometer" + tempString);break;case Sensor.TYPE_MAGNETIC_FIELD:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 电磁场传感器magnetic field" + tempString);break;case Sensor.TYPE_ORIENTATION:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 方向传感器orientation" + tempString);break;case Sensor.TYPE_GYROSCOPE:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 陀螺仪传感器gyroscope" + tempString);break;case Sensor.TYPE_LIGHT:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 环境光线传感器light" + tempString);break;case Sensor.TYPE_PRESSURE:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 压力传感器pressure" + tempString);break;case Sensor.TYPE_TEMPERATURE:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 温度传感器temperature" + tempString);break;case Sensor.TYPE_PROXIMITY:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 距离传感器proximity" + tempString);break;case Sensor.TYPE_GRAVITY:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 重力传感器gravity" + tempString);break;case Sensor.TYPE_ROTATION_VECTOR:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 旋转向量传感器:RotationVector" + tempString);break;default:metaPromt.setText(metaPromt.getText().toString() + s.getType()+ " 未知传感器" + tempString);break;}}gravitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);linearAccelerometeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);rotationVectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);gravityPromt = (TextView) findViewById(R.id.gravityPromt);accelerometerPromt = (TextView) findViewById(R.id.accelerometerPromt);linearAccelerometerPromt = (TextView) findViewById(R.id.linearAccelerometerPromt);gyroscopePromt = (TextView) findViewById(R.id.gyroscopePromt);rotationVectorPromt = (TextView) findViewById(R.id.rotationVectorPromt);mSensorManager.registerListener(new SensorEventListener() {float[] gravity = new float[3];float[] linear_acceleration = new float[3];@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {// In this example, alpha is calculated as t / (t + dT),// where t is the low-pass filter's time-constant and// dT is the event delivery rate.final float alpha = 0.8f;// Isolate the force of gravity with the low-pass filter.gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];// Remove the gravity contribution with the high-pass filter.linear_acceleration[0] = event.values[0] - gravity[0];linear_acceleration[1] = event.values[1] - gravity[1];linear_acceleration[2] = event.values[2] - gravity[2];gravityPromt.setText("gravityPromt: x="+ (int) linear_acceleration[0] + "," + "y="+ (int) linear_acceleration[1] + "," + "z="+ (int) linear_acceleration[2]);}}, gravitySensor, SensorManager.SENSOR_DELAY_GAME);mSensorManager.registerListener(new SensorEventListener() {float[] gravity = new float[3];float[] linear_acceleration = new float[3];@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {// In this example, alpha is calculated as t / (t + dT),// where t is the low-pass filter's time-constant and// dT is the event delivery rate.final float alpha = 0.8f;// Isolate the force of gravity with the low-pass filter.gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];// Remove the gravity contribution with the high-pass filter.linear_acceleration[0] = event.values[0] - gravity[0];linear_acceleration[1] = event.values[1] - gravity[1];linear_acceleration[2] = event.values[2] - gravity[2];accelerometerPromt.setText("accelerometerPromt: x="+ (int) linear_acceleration[0] + "," + "y="+ (int) linear_acceleration[1] + "," + "z="+ (int) linear_acceleration[2]);}}, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);mSensorManager.registerListener(new SensorEventListener() {@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {linearAccelerometerPromt.setText("linearAccelerometerPromt: x="+ (int) event.values[0] + "," + "y="+ (int) event.values[1] + "," + "z="+ (int) event.values[2]);}}, linearAccelerometeSensor, SensorManager.SENSOR_DELAY_GAME);mSensorManager.registerListener(new SensorEventListener() {// Create a constant to convert nanoseconds to seconds.private static final float NS2S = 1.0f / 1000000000.0f;private final float[] deltaRotationVector = new float[4];private float timestamp;@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// TODO Auto-generated method stub}@Overridepublic void onSensorChanged(SensorEvent event) {// This timestep's delta rotation to be multiplied by the// current rotation// after computing it from the gyro sample data.if (timestamp != 0) {final float dT = (event.timestamp - timestamp) * NS2S;// Axis of the rotation sample, not normalized yet.float axisX = event.values[0];float axisY = event.values[1];float axisZ = event.values[2];// Calculate the angular speed of the samplefloat omegaMagnitude = (float) Math.sqrt(axisX * axisX+ axisY * axisY + axisZ * axisZ);// Integrate around this axis with the angular speed by the// timestep// in order to get a delta rotation from this sample over// the timestep// We will convert this axis-angle representation of the// delta rotation// into a quaternion before turning it into the rotation// matrix.float thetaOverTwo = omegaMagnitude * dT / 2.0f;float sinThetaOverTwo = (float) Math.sin(thetaOverTwo);float cosThetaOverTwo = (float) Math.cos(thetaOverTwo);deltaRotationVector[0] = sinThetaOverTwo * axisX;deltaRotationVector[1] = sinThetaOverTwo * axisY;deltaRotationVector[2] = sinThetaOverTwo * axisZ;deltaRotationVector[3] = cosThetaOverTwo;}timestamp = event.timestamp;float[] deltaRotationMatrix = new float[9];SensorManager.getRotationMatrixFromVector(deltaRotationMatrix,deltaRotationVector);String promt = "";for (int i = 0; i < deltaRotationMatrix.length; i++) {promt += deltaRotationMatrix[i] + "\n";}gyroscopePromt.setText("gyroscopePromt: \n" + promt);// User code should concatenate the delta rotation we computed// with the current rotation// in order to get the updated rotation.// rotationCurrent = rotationCurrent * deltaRotationMatrix;}}, gyroscopeSensor, SensorManager.SENSOR_DELAY_GAME);mSensorManager.registerListener(new SensorEventListener() {private final float[] deltaRotationVector = new float[4];@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}@Overridepublic void onSensorChanged(SensorEvent event) {deltaRotationVector[0] = event.values[0];deltaRotationVector[1] = event.values[1];deltaRotationVector[2] = event.values[2];// deltaRotationVector[3] = event.values[3];float[] deltaRotationMatrix = new float[9];SensorManager.getRotationMatrixFromVector(deltaRotationMatrix,deltaRotationVector);String promt = "";for (int i = 0; i < deltaRotationMatrix.length; i++) {promt += deltaRotationMatrix[i] + "\n";}rotationVectorPromt.setText("rotationVectorPromt: \n" + promt);}}, rotationVectorSensor, SensorManager.SENSOR_DELAY_GAME);}
}
程序首先调用
(SensorManager)getSystemService(Context.SENSOR_SERVICE);
获取系统的传感器服务并且赋值给传感器管理器,然后通过调用
mSensorManager.getSensorList(Sensor.TYPE_ALL);
获取系统中所有类型的传感器。然后遍历所有的传感器,并且显示传感器的名称,制造商等信息。
然后调用mSensorManager.registerListener()方法监听某个传感器,当传感器检测到变化时会自动调用所注册的监听器的onSensorChanged(SensorEvent event)方法,其中event变量中包含了传感器检测到的数据,关于各个数据的作用见上文中的表一。
关于坐标系:
手机放桌面上,把手机往左边移动,那么x轴上的加速度为正,把手机往前移动,那么y轴的加速度为正,把手机往空中向上移动,那么z轴的加速度为正。
故对于加速度传感器,由于传感器默认当做自由落体运动时的加速度为0,所以手机静止时,加速度传感器返回的数据为0 –(-9.8)(即重力加速度g)。当手机以a的加速度向上移动时,加速度返回的数据为a-(-9.8)。然而由于我们的意识中当手机静止时的加速度应该为0。所以我们需要从系统返回的数据中过滤掉重力的作用。
关于陀螺仪传感器,由于传感器返回的event变量中的event.values数组中返回的分别是x, y, z轴中的角速度。所以我们需要算出这三个角速度的算数平方和的根,从而得出整体的角速度。然后把这个角速度乘以上次测量和本次测量之间的时间,算出手机总共旋转的角度,然后通过公式:
x*sin(θ/2)
y*sin(θ/2)
z*sin(θ/2)
算出手机在各个轴上旋转的角度。
执行效果:
由于本程序中同时监听的传感器过多,并且陀螺仪传感器和旋转向量传感器中涉及到了复杂的浮点数运算,所以会比较卡。
SourceCode下载链接:
https://github.com/renoqiu/MotionSensorTest
参考链接:
http://developer.android.com/guide/topics/sensors/sensors_motion.html
http://disanji.net/2011/02/21/android-sensor-programming-1/
android Motion Senor API 简介相关推荐
- 【Android UI】Path 测量 PathMeasure ② ( PathMeasure API 简介 | nextContour 函数 | getPosTan 函数 ★ | 曲线切线处理 )
文章目录 一.PathMeasure API 简介 1.nextContour 函数 2.getPosTan 函数 ★ 一.PathMeasure API 简介 PathMeasure 官方文档 : ...
- 如何获取用户的地理位置-浏览器地理位置(Geolocation)API 简介
如何获取用户的地理位置-浏览器地理位置(Geolocation)API 简介 一.总结 一句话总结:Geolocation API(地理位置应用程序接口)提供了一个可以准确知道浏览器用户当前位置的方法 ...
- USB OTG to PC USB API简介
USB OTG to PC USB API简介 本API分为四部分:Linux或Android内核 (主要是gadget驱动).linux端API及其DEMO.Windows 驱动.Windows A ...
- 《Android开源库 ~ 1》 GitHub Android Libraries Top 100 简介
转载自GitHub Android Libraries Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据 GitH ...
- GitHub Android Librarys Top 100 简介
GitHub Android Librarys Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索J ...
- Android渲染画面,Android系统图像渲染简介
原标题:Android系统图像渲染简介 Android系统UI从绘制到显示至屏幕一般为如图过程:先从相应的图片解码获得位图数据放到内存.然后使用图形引擎将位图数据按一定方式,渲染到可用于显示的图形内存 ...
- 【uni-app教程】UniAPP 常用组件和 常用 API 简介# 知心姐姐聊天案例
五.UniAPP 常用组件简介 uni-app 为开发者提供了一系列基础组件,类似 HTML 里的基础标签元素,但 uni-app 的组件与 HTML 不同,而是与小程序相同,更适合手机端使用. 虽然 ...
- 线程编程常见API简介(中)
2019独角兽企业重金招聘Python工程师标准>>> 一.概述 在<线程编程常见API简介(上) >中讲述了有关线程创建过程中常用的 API 的使用方法,本节继续讲述有 ...
- Android中所有API和对应权限的数据结构构建
#写在前面的话 这是一篇有毒博客,我觉得,读者慎入. 我想说,那个最底下的广告怎么去,辣眼睛- T -T 当然,你也可以帮我点下我的,在这里跪谢大家 https://www.captainbed.ne ...
最新文章
- Python:一行代码将以e为结尾的科学计算法类型的数值转为小数点类型数值
- Leaflet中实现添加比例尺控件与自定义版权控件与链接
- ASP.NET Core 之 Identity 入门(三)
- 多态性——vptr和vtable
- jsessionid 在谷歌一直变_谷歌相册也要收费,这次我全靠这些云盘救命
- 六石管理学:学习指教欢迎,刺探情报免了
- JVM(四)—一道面试题搞懂JVM类加载机制
- POS收单地区代码表(2015年3月版)
- 常用收藏(自己用的)
- html动画 箭头线条,html – 悬停时动画的箭头线
- 视频技术系列 - 分析业内数字版权管理DRM技术
- Apache commons-exec的使用
- 同学,主业和副业如何选?
- xampp 403 禁止访问 问题解决
- 相关分析怎么进行?有哪些条件?
- 淘宝京东类电商评论标签化的思路
- JavaScript中的jQuery
- excel导入非法字符处理,form表单等提交参数前后去除空白处理
- 一文读懂阿里云挑战 AWS 的底气 | 2018•大复盘
- iconfont的基本使用
热门文章
- 小程序报错:(“ errMsg “:“ navigateTo : fail can not navigateTo a tabbar page “}
- 重启服务器后,tomcat自动重启
- LVGL lv_calendar日历(21)
- Windows:Arm,我们不合适
- 二维数组作为函数参数传递
- MTSC2018 测试开发大会视频公开(含 PPT)| 年度福利
- 三星和亚马逊合作共推Kindle电子书阅读应用
- 微型计算机的接口包括什么,微机原理与接口
- Kamailio vs OpenSIPS
- C语言 一维数组换位问题