简介

坐标系

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. ubuntu下使用C语言开发一个cgi程序

    主要步骤是: 1. 开发一个C程序(在标准输出中输出HTML字符串) 2. 复制到apache2的cgi-bin目录去 3. 在httpd.conf中开启cgi功能(我似乎没用到,也可以使用cgi) ...

  2. 转:使用Mongo Connector和Elasticsearch实现模糊匹配

    原文来自于:http://www.csdn.net/article/2014-09-01/2821485-how-to-perform-fuzzy-matching-with-mongo-connec ...

  3. BZOJ 1025 游戏

    Description windy学会了一种游戏.对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应.最开始windy把数字按顺序1,2,3,……,N写一排在纸上.然后再在这一排下面写上它们对 ...

  4. Dp解决数组中连续子数组的最大和

    #include<iostream> ];     ;i<size;i++)     {           TempSum = CurSum;           )        ...

  5. 图论(网络流):SPOJ OPTM - Optimal Marks

    OPTM - Optimal Marks You are given an undirected graph G(V, E). Each vertex has a mark which is an i ...

  6. 图论(2-sat):Priest John's Busiest Day

    Priest John's Busiest Day   Description John is the only priest in his town. September 1st is the Jo ...

  7. wchar_t与char、wstring与string的相互转换

    个人倾向于使用优秀的开源库做这个. 最近使用boost进行转换,代码极其简单: boost::filesystem::path src(wchar_t); char = src.string().c_ ...

  8. 数据结构——POJ 1686 Lazy Math Instructor 栈的应用

    Description A math instructor is too lazy to grade a question in the exam papers in which students a ...

  9. cf601A The Two Routes

    A. The Two Routes time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  10. A Mini Locomotive(动态规划 01)

     /*  题意:选出3个连续的 数的个数  为K的区间,使他们的和最大 分析: dp[j][i]=max(dp[j-k][i-1]+value[j],dp[j-1][i]);   dp[j][i]:从 ...