
设备中的三自由度Orientation
Sensor就是一个可以识别设备相对于地面,绕x、y、z轴转动角度的感应器(自己的理解,不够严谨)。智能手机,平板电脑有了它,可以实现很多好玩的应用,比如说指南针等。
我们可以用一个磁场感应器(magnetic sensor)来实现。
磁场感应器是用来测量磁场感应强度的。一个3轴的磁sensor
IC可以得到当前环境下X、Y和Z方向上的磁场感应强度,对于Android中间层来说就是读取该感应器测量到的这3个值。当需要时,上报给上层应用程序。磁感应强度的单位是T(特斯拉)或者是Gs(高斯),1T等于10000Gs。
先来看看android定义的坐标系,在/hardware/libhardware/include/hardware/sensors.h中有个图。
图中表示设备的正上方是y轴方向,右边是x轴方向,垂直设备屏幕平面向上的是Z轴方向,这个很重要。因为应用程序就是根据这样的定义来写的,所以我们报给应用的数据要跟这个定义符合。还需要清楚磁sensor芯片贴在板上的坐标系。我们从芯片读出数据后要把芯片的坐标系转换为设备的实际坐标系。除非芯片贴在板上刚好跟设备的x、y、z轴方向刚好一致(去感谢你的硬件工程师吧)。
Orientation Sensor的实现是根据磁场感应强度的3个值计算出另外3个值。当需要时,我们计算出这3个值上报给应用程序,Orientation
Sensor的功能就实现了。
这3个值具体含义和计算方法是:
1. azimuth 方位角:就是绕z轴转动的角度,0度=正北,(假设Y轴指向地磁正北方,直升机正前方的方向如下图)
90度=正东,
180度=正南,
270度=正西。
求x和y方向的磁感应强度的反正切,就可以得到方位角(算法看后面poll函数中的代码)。要实现指南针,只需要这个就可以了(不考虑设备非水平的情况);
2. pitch 仰俯:绕X轴转动的角度 (-180<=pitch<=180), 如果设备水平放置,前方向下俯就是正,如图:
求z和x的反正切可得到此值。
sensors.h中还定义了其他各种sensor。要实现的就是这两个:
#define SENSOR_TYPE_MAGNETIC_FIELD 2
#define SENSOR_TYPE_ORIENTATION 3
在/hardware/sensors/sensors.cpp 中添加对MAGNETIC_FIELD和ORIENTATION 的支持
Android上层应用apk到G-sensor driver的大致流程: Android HAL层,即硬件抽象层,是Google响应厂家“希望不公开源码”的要求推出的新概念 1,源代码和目标位置 源代码: /hardware/libhardware目录,该目录的目录结构如下: /hardware/libhardware/hardware.c编译成libhardware.so,目标位置为/system/lib目录 /hardware/libhardware/include/hardware目录下包含如下头文件: hardware.h 通用硬件模块头文件 copybit.h copybit模块头文件 gralloc.h gralloc模块头文件 qemud.h qemud模块头文件 sensors.h 传感器模块头文件 /hardware/libhardware/modules目录下定义了很多硬件模块 这些硬件模块都编译成xxx.xxx.so,目标位置为/system/lib/hw目录 2,Android对于Sensor的API定义在 hardware/libhardware/include/hardware/sensor.h中,要求在sensor.so提供以下8个API函数 [控制方面] int (*open_data_source)(struct sensors_control_device_t *dev) int (*activate)(struct sensors_control_device_t *dev, int handle, int enabled) int (*set_delay)(struct sensors_control_device_t *dev, int32_t ms) int (*wake)(struct sensors_control_device_t *dev) [数据方面] int (*data_open)(struct sensors_data_device_t *dev, int fd) int (*data_close)(struct sensors_data_device_t *dev) int (*poll)(struct sensors_data_device_t *dev, sensors_data_t* data) [模块方面] int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t const** list) 在Java层Sensor的状态控制由SensorService来负责,它的java代码和JNI代码分别位于: frameworks/base/services/java/com/Android/server/SensorService.java frameworks/base/services/jni/com_Android_server_SensorService.cpp 在Java层Sensor的数据控制由SensorManager来负责,它的java代码和JNI代码分别位于: frameworks/base/core/java/Android/hardware/SensorManager.java frameworks/base/core/jni/Android_hardware_SensorManager.cpp Android framework中与sensor通信的是sensorService.java和sensorManager.java。 sensorService.java的具体通信是通过JNI调用sensorService.cpp中的方法实现的。 sensorManager.java的具体通信是通过JNI调用sensorManager.cpp中的方法实现的。 sensorService.cpp和sensorManger.cpp通过hardware.c与sensor.so通信。其中sensorService.cpp实现对sensor的状态控制,sensorManger.cpp实现对sensor的数据控制。 sensor.so通过ioctl控制sensor driver的状态,通过打开sensor driver对应的设备文件读取G-sensor采集的数据。 Android SDK提供了4个类来于sensor通信,分别为 sensor,sensorEvent,sensorEventListener,sensorManager。其中 sensorEventListener用来在sensorManager中注册需要监听的sensor类型。 sensorManager.java提供registrater(),unregistrater()接口供sensorEventListener使用。 sensorManager.java不断轮询从sensor.so中取数据。取到数据后送给负责监听此类型sensor的 sensorEventListener.java。sensorEventListener.java通过在sensorManager.java中注册可以监听特定类型的sensor传来的数据。 系统启动时执行systemProcess,会启动sensorService.java,在sensorService.java的构造函数中调用JNI方法_sensor_control_init()。 sensorService.cpp中相应的方法Android_int()会被执行。该函数会调用hardware.c中的方法hw_get_module()此函数又通过调用load()函数在system/lib/hw下查找sensor.so 查找时会根据harware.c中定义好的sensor.*.so的扩展名的顺序查找,找到第一个匹配的时候即停止,并将该sensor.so中定义好的一个全局变量HAL_MODULE_INFO_SYM带回。该变量包含的一个 重要信息是它的一个成员结构变量中包含的一个函数指针open,该指针所指函数会对一个device结构变量赋值,从而带出sensorService.cpp和sensorManager.cpp与sensor通信所需要的全部信息。 device结构变量有两种变体分别供sensorService.cpp和sensorManaer.cpp使用。其中主要是一些函数指针指向与sensor通信的函数。 sensorService.cpp和sensorManager.cpp在得到HAL_MODULE_INFO_SYM结构后都会调用 sensors.h的inline函数open()通过HAL_MODULE_INFO_SYM的open函数指针将所需的device信息取回。 系统在启动activityManager.java时,它会启动sensorManager.java,它也会调用hardware.c中的方法hw_get_module()带回HAL_MODULE_INFO_SYM。目前很多应用已经实现了摇一摇功能,这里通过讲解该功能的原理及实现回顾一下加速度传感器的使用:1.首先获得传感器管理器的实例
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE)
2.通过传感器管理器获得加速传感器
accelerateSensor = getSensorManager(context).getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
3.注册加速传感器的监听器
sensorManager.registerListener(listener, sensor, rate)
参数说明:
listener:加速传感器监听器实例
sensor :加速传感器实例,实现摇一摇使用的是accelerateSensor
rate :感应器反应速度,有四个常量共选择
SENSOR_DELAY_NORMAL:匹配屏幕方向的变化,默认传感器速度
SENSOR_DELAY_UI:匹配用户接口
如果更新UI建议使用SENSOR_DELAY_GAME:
匹配游戏,游戏开发建议使用SENSOR_DELAY_FASTEST.:匹配所能达到的最快
根据情况选择,一般情况选择第一种就可以
传感器监听器:SensorEventListener有两个回调方法
onSensorChanged(SensorEvent event)和onAccuracyChanged(Sensor sensor, int accuracy)
第一个是传感器值变化的相应方法
第二个是反应速度变化的相应方法
两个方法会同时被调用
onSensorChanged(SensorEvent event) 介绍
nSensorChanged(SensorEvent event)
event的实例的values变量非常重要,根据传感器的不同,里面的值代表的含义也不相同,以加速传感器为例:
values该变量的类型是float[]数组,最多有三个元素:
float x = values[0] 代表X轴
float y = values[1] 代表Y轴
float z = values[2] 代表Y轴
X轴的方向是沿着屏幕的水平方向从左向右。如果手机不是正方形的话,较短的边需要水平放置,较长的边需要垂直放置。Y轴的方向是从屏幕的左下角开始沿着屏幕的垂直方向指向屏幕的顶端。将手机平放在桌子上,Z轴的方向是从手机里指向天空。
我们判断手机是否摇一摇,只要x,y,z轴,达到设定的阀值时就表示摇一摇。
@Override
public void onSensorChanged(SensorEvent event) {
int sensorType = event.sensor.getType()
//values[0]:X轴,values[1]:Y轴,values[2]:Z轴
float[] values = event.values
float x = values[0]
float y = values[1]
float z = values[2]
Log.i(TAG, "x:" + x + "y:" + y + "z:" + z)
Log.i(TAG, "Math.abs(x):" + Math.abs(x) + "Math.abs(y):" +Math.abs(y) + "Math.abs(z):" + Math.abs(z))
if(sensorType == Sensor.TYPE_ACCELEROMETER){
int value = 15//摇一摇阀值,不同手机能达到的最大值不同,如某品牌手机只能达到20
if(x >= value || x <= -value || y >= value || y <= -value || z >= value || z <= -value){
Log.i(TAG, "检测到摇动")
//播放动画,更新界面,并进行对应的业务 *** 作
}
}
很早之前我写过:
为了增强程序的健壮性,需要判断并防止摇一摇事件同一时间多次被触发:
float[] values = event.values
float x = values[0]
float y = values[1]
float z = values[2]
Log.i(TAG, "onSensorChanged:" + "x:" + x + ",y:" + y + ",z:" + z)
if (x >= 15 || x <= -15 || y >= 15 || y <= -15 || z >= 15 || z <= -15) {
if (allowShake()) {//判断是否为重复晃动
Log.e(TAG, "摇一摇,摇一摇")
new AllowShake().start()
} else {
Log.e(TAG, "2s 后再次允许摇动")
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)