简介

坐标系

x轴:从左到右
y轴:从下到上
z轴:从内到外
这个坐标系与Android 2D API中的不同,传感器中的返回值都以此坐标系为准。

SENSOR_TYPE_ACCELEROMETER       1 //加速度
SENSOR_TYPE_MAGNETIC_FIELD      2 //磁力
SENSOR_TYPE_ORIENTATION         3 //方向
SENSOR_TYPE_GYROSCOPE           4 //陀螺仪
SENSOR_TYPE_LIGHT               5 //光线感应
SENSOR_TYPE_PRESSURE            6 //压力
SENSOR_TYPE_TEMPERATURE         7 //温度
SENSOR_TYPE_PROXIMITY           8 //接近
SENSOR_TYPE_GRAVITY             9 //重力
SENSOR_TYPE_LINEAR_ACCELERATION 10//线性加速度
SENSOR_TYPE_ROTATION_VECTOR     11//旋转矢量

API概况
sensor相关API被放到了android.hardware包下,主要使用的类有Sensor、SensorEvent、SensorManager及SensorEventListener接口。
SensorManager顺其自然的担任起管理的工作,负责注册监听某Sensor的状态;Sensor的数据通过SensorEvent返回。
  • Sensor: 表示传感器的类,它保存有传感器名称,厂商,版本,精确度等信息
  • SensorEvent:表示传感器事件,它可以保存传感器的值,传感器类型,时间戳等信息
  • SensorEventListener:用于接收传感器来自SensorManager的通知,当传感器发生变化时,它包含两个回调函数
  • SensorManager:SensorManager让你可以访问手机的全部传感器
  • SensorListener:已废除
注意:应当始终保证在不需要使用传感器的时候禁用传感器,特别是当你的activity【暂停】的时候。没有这样做将会导致电池只能使用很少几个小时。记住,系统不会在屏幕关闭的时候自动禁用传感器。

延迟时间的精密度参数如下:
SensorManager.SENSOR_DELAY_FASTEST     0ms
SensorManager.SENSOR_DELAY_GAME        20ms
SensorManager.SENSOR_DELAY_UI              60ms
SensorManager.SENSOR_DELAY_NORMAL   200ms
因为感应检测Sensor的服务是否频繁和快慢都与电池参量的消耗有关,同时也会影响处理的效率,所以兼顾到消耗电池和处理效率的平衡,需要根据应用系统的需求来做适当的设置。

加速度

加速度传感器的背景
这里的加速度特指重力加速度,所以在【静止时】重力传感器的返回值与加速度传感器值相同。
地表上静止物体的重力加速度约为9.8 m/s^2.
借用SensorManager中的常量:
public static final float STANDARD_GRAVITY = 9.80665F;

我们可以借助三轴上的值来确定设备的状态,比如:
  • 将手机平放在桌面上,x轴默认为0,y轴默认0,z轴默认9.81。
  • 将手机朝下放在桌面上,z轴为-9.81。
  • 将手机向左倾斜,x轴为正值;当x轴的值接近重力加速度时,说明设备的左边朝下。
  • 将手机向右倾斜,x轴为负值;当x轴的值接近负的g值时,说明设备的右边朝下。
  • 将手机向上倾斜,y轴为负值;当y轴的值接近负的g值时,说明设备的上边朝下。
  • 将手机向下倾斜,y轴为正值;当y轴的值接近g值时,说明设备的下边超下。

地磁

磁场传感器主要读取的是磁场的变化,通过该传感器便可开发出指南针、罗盘等磁场应用。
该传感器读取的数据同样是空间坐标系三个方向的磁场值,其数据单位为T。
磁场传感器可以用来检测磁场大小,和加速度传感器一样,有x、y、z轴三个方向,单位为uT(microteslas),即微特斯拉。
磁场传感器也称为compass(指南针),在uses-feature中使用Android.hardware.sensor.compass作为其名字。
可以拿着手机到处测测,在电器附近不同位置,值还是相差巨大的。
不过单看磁场数值其实也看不出所以然。

方向

安卓平台提供了2个传感器用于让我们判断设备的位置,分别是【地磁场传感器】和【方向传感器】。关于Orientation Sensor在官方文档中的概述里有这样一句话:
The orientation sensor is software-based and derives its data from the accelerometer and the geomagnetic field sensor. 方向传感器是基于软件的,并且它的数据是通过【加速度传感器】和【磁场传感器】共同获得的。

  • 第一个元素azimuth,【z轴旋转角度】,手机由水平正北放置时开始顺时针旋转,z的值变化情况为0~360/0;表示指向地心的【方位角】
  • 第二个元素pitch,【x轴旋转角度】,手机由水平正北放置时开始顺时针旋转,x的值变化情况为0~-180/180~0;表示前后旋转的【仰俯角】
  • 第三个元素roll,【y轴旋转角度】,手机由水平正北放置时开始顺时针旋转,y的值变化情况为0~90~0~-90~0;表示左右旋转的【翻转角】
一定要清楚,上面的值都是【旋转】角度,上面的总结是没有错的,如果你觉得错了,那就是没有理解【旋转】的意思。
当手机顶部指向正北方时,方向值为0;顶部指向正东方时,方向值为90;顶部指向正南方时,方向值为180;顶部指向正西方时,方向值为270。

磁场+加速度代替方向传感器

在最新版的SDK中,使用Orientation传感器会看到这么一句话“This constant is deprecated. use SensorManager.getOrientation() instead. ”
即这种方式已过期,不建议使用!Google建议我们在应用程序中使用SensorManager.getOrientation()来获得原始数据。
public static float[] getOrientation (float[] R, float[] values)
  • 第一个参数是R[] 是一个旋转矩阵,用来保存磁场和加速度的数据,可以理解为这个函数的传入值,通过它这个函数给你求出方位角。
  • 第二个参数就是这个函数的输出了,他有函数自动为我们填充,这就是我们想要的。
输出值values各个元素的含义
  • values[0]  :方向角,但用(磁场+加速度)得到的数据范围是(-180~180),也就是说,0表示正北,90表示正东,180/-180表示正南,-90表示正西。而直接通过方向感应器数据范围是(0~359)360/0表示正北,90表示正东,180表示正南,270表示正西。
  • values[1]  pitch 倾斜角,即由静止状态开始,前后翻转,手机顶部往上抬起(0~-90),手机尾部往上抬起(0~90)
  • values[2]  roll 旋转角,即由静止状态开始,左右翻转,手机左侧抬起(0~90),手机右侧抬起(0~-90)
现在问题是这个R[]怎么获取,其实他是通过函数getRotationMatrix得到的。
看看getRotationMatrix的定义:
public static boolean getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic)
  • 第一个就是我们需要填充的R数组,大小是9
  • 第二个是一个转换矩阵,将磁场数据转换进实际的重力坐标中,一般默认情况下可以设置为null
  • 第三个是一个大小为3的数组,表示从加速度感应器获取来的数据,在onSensorChanged中
  • 第四个是一个大小为3的数组,表示从磁场感应器获取来的数据,在onSensorChanged中

加速度示例

public class AccelerometerActivity extends ListActivity implements SensorEventListener {
    private TextView tv_info;
    private SensorManager sm;//传感器管理器
    private Vibrator vibrator;//震动
    private long lastTime = System.currentTimeMillis();
    private static final int UPTATE_INTERVAL_TIME = 3500;// 两次检测的时间间隔  
    private static final float MEDUMVALUE = SensorManager.STANDARD_GRAVITY + 8.5f;//标准值为9.80665
    private static final float SENSEVALUE = SensorManager.STANDARD_GRAVITY - 0.5f;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = { "注册,摇一摇,检测手机屏幕方向", "取消注册", };
        tv_info = new TextView(this);
        tv_info.setTextColor(Color.BLUE);
        tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
        tv_info.setPadding(20, 10, 20, 10);
        getListView().addFooterView(tv_info);
        setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array))));
        sm = (SensorManager) getSystemService(SENSOR_SERVICE);
        vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);//权限【android.permission.VIBRATE】
    }
    protected void onResume() {
        super.onResume();
        if (sm != null) sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
    }
    protected void onPause() {//保证在不需要使用传感器的时候禁用传感器
        super.onPause();
        if (sm != null) sm.unregisterListener(this);
    }
    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
        case 0:
            if (sm != null) sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);//设置获取传感器信息的频率
            break;
        case 1://Accelerometer 加速度传感器,32
            if (sm != null) sm.unregisterListener(this);
            break;
        }
    }
    @Override
    public void onSensorChanged(SensorEvent event) {//在感应检测到Sensor的值有变化时会被调用到
        //实时检测,震动
        if (Math.abs(event.values[0]) > MEDUMVALUE || Math.abs(event.values[1]) > MEDUMVALUE || Math.abs(event.values[2]) > MEDUMVALUE) vibrator.vibrate(200);
        //抽样检测
        if (System.currentTimeMillis() - lastTime < UPTATE_INTERVAL_TIME) return;
        lastTime = System.currentTimeMillis();// 现在的时间变成last时间
        tv_info.setText("传感器类型 " + event.sensor.getName() + "\n时间戳 " + event.timestamp + "\n精度 " + event.accuracy + //
                "\nx轴方向的值,右侧向上时为正 " + event.values[0] + "\ny轴方向的值,前侧向上时为正 " + event.values[1] + "\nz轴方向的值,屏幕向上时为正 " + event.values[2]);
        //检测手机屏幕方向
        if (event.values[0] > SENSEVALUE) Toast.makeText(this, "屏幕朝左,重力指向设备左边", Toast.LENGTH_SHORT).show();
        else if (event.values[0] < -SENSEVALUE) Toast.makeText(this, "屏幕朝右,重力指向设备右边", Toast.LENGTH_SHORT).show();
        else if (event.values[1] > SENSEVALUE) Toast.makeText(this, "屏幕朝前,重力指向设备下边", Toast.LENGTH_SHORT).show();
        else if (event.values[1] < -SENSEVALUE) Toast.makeText(this, "屏幕朝后,重力指向设备上边", Toast.LENGTH_SHORT).show();
        else if (event.values[2] > SENSEVALUE) Toast.makeText(this, "屏幕朝上", Toast.LENGTH_SHORT).show();
        else if (event.values[2] < -SENSEVALUE) Toast.makeText(this, "屏幕朝下", Toast.LENGTH_SHORT).show();
    }
    @Override
    public void onAccuracyChanged(Sensor paramSensor, int paramInt) {//在感应检测到Sensor的精密度有变化时被调用到
    }
}

方向示例

public class OrientationActivity2 extends Activity implements SensorEventListener {
    private TextView tv_info;
    private TextView tv_orientation;
    private ImageView iv;
    private SensorManager sm;//传感器管理器
    private float[] accelValues = new float[3];
    private float[] magValues = new float[3];
    private long lastTime = System.currentTimeMillis();
    private static final int UPTATE_INTERVAL_TIME = 500;// 两次检测的时间间隔  
    private float lastRotateDegree;
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_info = (TextView) findViewById(R.id.tv_info);
        tv_orientation = (TextView) findViewById(R.id.tv_orientation);
        iv = (ImageView) findViewById(R.id.iv);
        sm = (SensorManager) getSystemService(SENSOR_SERVICE);
    }
    protected void onResume() {
        super.onResume();
        if (sm != null) {
            sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_NORMAL);
            sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
        }
    }
    protected void onPause() {//保证在不需要使用传感器的时候禁用传感器
        super.onPause();
        if (sm != null) sm.unregisterListener(this);
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        switch (event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            accelValues = event.values;
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            magValues = event.values;
            break;
        }
        tv_info.setText("传感器类型 " + event.sensor.getName() + "\n获取到的值\n" + event.values[0] + "\n" + event.values[1] + "\n" + event.values[2]);
        if (System.currentTimeMillis() - lastTime < UPTATE_INTERVAL_TIME) return;
        lastTime = System.currentTimeMillis();// 现在的时间变成last时间
        calculateOrientation();
    }
    @Override
    public void onAccuracyChanged(Sensor paramSensor, int paramInt) {
    }

    private void calculateOrientation() {
        float[] R = new float[9];//旋转数组
        float[] values = new float[3];//模拟方向传感器的数据
        //要填充的旋转数组;将磁场数据转换进实际的重力坐标中,一般默认情况下可以设置为null;加速度传感器数据;地磁传感器数据 
        SensorManager.getRotationMatrix(R, null, accelValues, magValues);
        SensorManager.getOrientation(R, values);
        //将弧度转化为角度后输出  
        tv_orientation.setText("角度\n");
        for (float value : values) {
            value = (float) Math.toDegrees(value);
            tv_orientation.append(value + "\n");
        }
        float value = -(float) Math.toDegrees(values[0]);
        if (Math.abs(value - lastRotateDegree) > 1) {
            //旋转补间动画
            RotateAnimation animation = new RotateAnimation(lastRotateDegree, value, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            animation.setFillAfter(true);
            iv.startAnimation(animation);
            lastRotateDegree = value;
        }
        value = -value;
        if (value >= -10 && value < 10) {
            tv_orientation.append("正北");
        } else if (value >= 10 && value < 80) {
            tv_orientation.append("东北");
        } else if (value >= 80 && value <= 100) {
            tv_orientation.append("正东");
        } else if (value >= 100 && value < 170) {
            tv_orientation.append("东南");
        } else if ((value >= 170 && value <= 180) || (value) >= -180 && value < -170) {
            tv_orientation.append("正南");
        } else if (value >= -170 && value < -100) {
            tv_orientation.append("西南");
        } else if (value >= -100 && value < -80) {
            tv_orientation.append("正西");
        } else if (value >= -80 && value < -10) {
            tv_orientation.append("西北");
        }
    }
}

附件列表

传感器 Sensor 加速度【示例】的更多相关文章

  1. 利用传感器(sensor)实现微信摇一摇动画

    所需要的权限: <uses-permission android:name="android.permission.VIBRATE"></uses-permiss ...

  2. 16、传感器(Sensor)

    一.什么是传感器 传感器是一种物理装置或生物器官,能够探测.感受外界的信号.物理条件(如光.热.湿度)或化学组成(如烟雾),并将探知的信息传递给其他装置或器官.国家标准GB7665—87对传感器的定义 ...

  3. 温湿度传感器DHT11程序示例

    DHT11概述 HT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器. 它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性.传感器包括一个电阻式 ...

  4. ADXL3xx: 读取 ADXL3xx 加速度传感器

    原文链接:https://www.arduino.cc/en/Tutorial/ADXL3xx ADXL3xx加速度传感器 本教程将为你展示如何读取Analog Devices的ADXL3xx系列加速 ...

  5. Android加速度传感器实现“摇一摇”,带手机振动

    由于代码有点多,所以就分开写了,注释还算详细,方便学习 Activity package com.lmw.android.test;   import android.app.Activity; im ...

  6. 玩转Android之加速度传感器的使用,模仿微信摇一摇

    Android系统带的传感器有很多种,最常见的莫过于微信的摇一摇了,那么今天我们就来看看Anroid中传感器的使用,做一个类似于微信摇一摇的效果. OK ,废话不多说,我们就先来看看效果图吧: 当我摇 ...

  7. 与众不同 windows phone (18) - Device(设备)之加速度传感器, 数字罗盘传感器

    原文:与众不同 windows phone (18) - Device(设备)之加速度传感器, 数字罗盘传感器 [索引页][源码下载] 与众不同 windows phone (18) - Device ...

  8. Sensor传感器(摇一摇)

    <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content ...

  9. Android根据加速度和地磁场传感器实现自动对焦

    在相机预览开始后新建AutoFocusManage对象即可,传入context和camera. 注意,在停止预览或者关闭相机时需调用方法中unregisterListener方法. 目前实现是当前方向 ...

随机推荐

  1. odoo view field option, action flage 参数

    options JSON object specifying configuration option for the field's widget (including default widget ...

  2. MySQL zip版安装配置

    文章出处:http://www.cnblogs.com/winstic/,请保留此连接 这段时间在学习Python 数据库操作知识,简单整理MySQL zip文件安装方法 下载 在MySQL官网htt ...

  3. Linux系统管理技术手册——第6章 添加新用户

    6.1/etc/passwd文件 用户登录时Linux识别用户的文件/etc/passwd /etc/passwd包括7个字段: 登录名(不超过32位,使用NIS系统后不超过8位) 经过加密的口令或口 ...

  4. 递归删除.DS_Store文件

    删除svn文件 sudo find . -name ".DS_Store" -exec rm -r {} \; sudo find . -name ".git" ...

  5. go语言细节

    1 数组与字符串为值类型,切片.映射.通道为值类型,赋值需注意. package main import ( "fmt" ) func main() { //数组 a1 := [] ...

  6. PSoC电容式触摸感应技术

    PSoC是由Cypress半导体公司推出的具有数字和模拟混合处理能力的可编程片上系统芯片,某些系列的PSoC(如CY8C21X34系列),由于其内部配备的特殊资源,使得它可以很容易地实现电容式触摸感应 ...

  7. Java中的属性与字段的区别

    Java中属性和字段的区别  Java中的属性,通常可以理解为其属名性时根据get和set方法名得出的. 其规则是:去掉get或set后其剩余的字符串,如果第二个字母是小写的,则把第一个字母也变成小写 ...

  8. [置顶] export命令-linux

    export 命令 功能说明: 设置或显示环境变量. 语 法: export [-fnp][变量名称]=[变量设置值] 补充说明: 在shell中执行程序时,shell会提供一组环境变量. expor ...

  9. Linux Shell编程(9)——特殊变量类型

    局部变量局部变量只在代码块或一个函数里有效 (参考函数里的局部变量)环境变量这种变量会影响Shell的行为和用户接口 在大多数情况下,每个进程都会有一个"环境表", 它由一组由进程 ...

  10. 使用XRDP实现Windows远程桌面Linux系统

    一般情况下我们用ssh客户端远程登陆Linux系统,至于图形界面下的linux远程登陆工具,我们一般都会想到vnc,但它的安全性不够,在这里,我将介绍XRDP的安装配置方法.我们可以很方便的通过Win ...