Android开发——使用传感器

1.Sensor相关的类:SensorSensorManager

  • Sensor(点击可查看官方文档,需要梯子)

常用传感器类型

  • TYPE_ALL——A constant describing all sensor types.
  • TYPE_ACCELEROMETE
  • TYPE_LINEAR_ACCELERATION
  • TYPE_GRAVITY
  • TYPE_GYROSCOPE
  • TYPE_MAGNETIC_FIELD
  • TYPE_ORIENTATION——已弃用
  • TYPE_MOTION_DETECT——Requires API level 24 (Android 7.0, Nougat)
  • TYPE_SIGNIFICANT_MOTION
  • TYPE_STATIONARY_DETECT
  • TYPE_STEP_COUNTER
  • TYPE_STEP_DETECTOR
  • TYPE_HEART_BEAT——A constant describing a motion detect sensor.Requires API level 24 (Android 7.0, Nougat)
  • TYPE_HEART_RATE
  • TYPE_PRESSURE
  • TYPE_PROXIMITY
  • TYPE_TEMPERATURE——已弃用
  • TYPE_AMBIENT_TEMPERATURE
  • TYPE_RELATIVE_HUMIDITY
  • TYPE_LIGHT

常用传感器方法:

  • getVendor()——传感器生产商
  • getName()——传感器名称
  • getId()——传感器ID,Requires API level 24 (Android 7.0, Nougat)
  • getType()——传感器类型
  • getStringType()——传感器类型
  • getVersion()——传感器版本号
  • getResolution()——传感器精度
  • isWakeUpSensor()——Returns true if the sensor is a wake-up sensor.

Always make sure to disable sensors you don't need, especially when your activity is paused. Failing to do so can drain the battery in just a few hours.
Note that the system will not disable sensors automatically when the screen turns off.

常量值

  • GRAVITY_EARTH Value——9.80665f
  • STANDARD_GRAVITY——9.80665f
  • PRESSURE_STANDARD_ATMOSPHERE——1013.25f(hPa)
  • SENSOR_ALL——A constant that includes all sensors
  • SENSOR_ACCELEROMETER
  • SENSOR_MAGNETIC_FIELD——All values are in micro-Tesla (uT) and measure the ambient magnetic field in the X, Y and -Z axis.
  • SENSOR_ORIENTATION
  • SENSOR_ORIENTATION_RAW
  • SENSOR_PROXIMITY
  • SENSOR_TEMPERATURE
  • SENSOR_LIGHT
  • SENSOR_DELAY_FASTEST——get sensor data as fast as possible(费电!)
  • SENSOR_DELAY_GAME——rate suitable for games(实时性要求)
  • SENSOR_DELAY_NORMAL——rate (default) suitable for screen orientation changes(默认)
  • SENSOR_DELAY_UI——rate suitable for the user interface(延迟较大)

常用方法:

  • int getSensors()——return available sensors
  • getSensorList(type: Int)——return a list of sensors matching the asked type:MutableList<Sensor>.
  • getDefaultSensor(type: Int)——return default sensor
  • getDefaultSensor(type: Int, wakeUp: Boolean)
  • registerListener(listener: SensorListener, sensors: Int)——Registers a SensorListener for given sensors.
  • registerListener(listener: SensorListener, sensors: Int, rate: Int)——Registers a SensorListener for given sensors.
  • registerListener(listener: SensorEventListener, sensor: Sensor, samplingPeriodUs: Int)——Registers a SensorEventListener for the given sensor at the given sampling frequency.
  • unregisterListener(listener: SensorListener)——Unregisters a listener for all sensors.
  • unregisterListener(listener: SensorListener, sensors: Int)——Unregisters a listener for the sensors with which it is registered.
  • unregisterListener(listener: SensorEventListener)——Unregisters a listener for all sensors. 
  • unregisterListener(listener: SensorEventListener, sensor: Sensor)——Unregisters a listener for the sensors with which it is registered.

 2.传感器数据处理:SensorEvent属性

  • accuracy——The accuracy of this event.
  • sensor——The sensor that generated this event.
  • timestamp——The time in nanosecond at which the event happened.
  • values——The length and contents of the values array depends on which sensor type is being monitored

Sensor.TYPE_ACCELEROMETER: All values are in SI units (m/s^2)

  • values[0]: Acceleration minus Gx on the x-axis
  • values[1]: Acceleration minus Gy on the y-axis
  • values[2]: Acceleration minus Gz on the z-axis
传感器坐标系

 

3.接口:SensorListenerSensorEventListener (点击可查看官方文档,需要梯子)

以下两个方法在SensorListener中已弃用,可以在SensorEvenListener中使用

  • int onAccuracyChanged(sensor: Int, accuracy: Int) This class was deprecated in API level 21.
  • int onSensorChanged(sensor: Int, values: FloatArray) This class was deprecated in API level 21.

4.使用传感器

1)调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取SensorManager对象

2)调用SensorManager的getDefaultSensor(int type)方法来获取指定类型的传感器

3)在Activity的onResume()方法中调用registerListener(SensorEventListener listener,Sensor sensor,int rate)为指定的传感器注册监听器,Android系统会通过传感器获取外界环境的数据,并将数据传给监听器的监听方法

5.列出手机所有传感器信息代码

package com.lee.sensor;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.TextView;

import java.util.List;

public class ListAllSensorsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_all_sensors);

        // 从系统服务中获得传感器管理器
        SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        // 从传感器管理器中获得全部的传感器列表
        List<Sensor> allSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
        // 保存每个传感器的信息
        StringBuilder sensorsInfo = new StringBuilder("手机有"+allSensors.size()+"个传感器,分别是:\n\n");
        for(Sensor s:allSensors){
            switch(s.getType()){
                case Sensor.TYPE_ACCELEROMETER:
                    sensorsInfo.append("加速度传感器");
                    break;
                case Sensor.TYPE_LINEAR_ACCELERATION:
                    sensorsInfo.append("线性加速度传感器");
                    break;
                case Sensor.TYPE_GRAVITY:
                    sensorsInfo.append("重力传感器");
                    break;
                case Sensor.TYPE_GYROSCOPE:
                    sensorsInfo.append("陀螺仪传感器");
                    break;
                case Sensor.TYPE_ORIENTATION:
                    sensorsInfo.append("方向传感器");
                    break;
                case Sensor.TYPE_MOTION_DETECT:
                    sensorsInfo.append("运动状态检测传感器");
                    break;
                case Sensor.TYPE_SIGNIFICANT_MOTION:
                    sensorsInfo.append("剧烈运动检测传感器");
                    break;
                case Sensor.TYPE_STATIONARY_DETECT:
                    sensorsInfo.append("静止状态检测传感器");
                    break;
                case Sensor.TYPE_STEP_COUNTER:
                    sensorsInfo.append("步数计数器");
                    break;
                case Sensor.TYPE_STEP_DETECTOR:
                    sensorsInfo.append("步伐检测器");
                    break;
                case Sensor.TYPE_MAGNETIC_FIELD:
                    sensorsInfo.append("电磁场传感器");
                    break;
                case Sensor.TYPE_LIGHT:
                    sensorsInfo.append("环境光线传感器");
                    break;
                case Sensor.TYPE_PRESSURE:
                    sensorsInfo.append("压力传感器");
                    break;
                case Sensor.TYPE_PROXIMITY:
                    sensorsInfo.append("距离传感器");
                    break;
                case Sensor.TYPE_AMBIENT_TEMPERATURE:
                    sensorsInfo.append("温度传感器");
                    break;
                case Sensor.TYPE_RELATIVE_HUMIDITY:
                    sensorsInfo.append("相对湿度传感器");
                    break;
                default:
                    sensorsInfo.append("未知传感器");
                    break;
            }
            sensorsInfo.append("\n设备类型码:").append(s.getType())
                    .append("\n设备名称:").append(s.getName())
                    .append("\n设备版本:").append(s.getVersion())
                    .append("\n供应商:").append(s.getVendor())
                    .append("\n\n");
        }
        // 显示所有传感器的信息
        TextView textView = findViewById(R.id.sensors_list_tv);
        textView.setText(sensorsInfo);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context=".ListAllSensorsActivity"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/sensors_list_tv"
        android:layout_marginTop="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</ScrollView>

6.测试加速度,线性加速度,重力加速度,陀螺仪,电磁场传感器代码

package com.lee.sensor;

import android.app.Activity;
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 TestSensorActivity extends Activity implements SensorEventListener {

    private SensorManager mSensorManager;
    private TextView mTextViewAcceleration;
    private TextView mTextViewLinearAcceleration;
    private TextView mTextViewGravity;
    private TextView mTextViewGyroscope;
    private TextView mTextViewMagneticField;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_sensor);

        mTextViewAcceleration = findViewById(R.id.accelerometer_tv);
        mTextViewLinearAcceleration = findViewById(R.id.linear_accelerometer_tv);
        mTextViewGravity = findViewById(R.id.gravity_tv);
        mTextViewGyroscope = findViewById(R.id.gyroscope_tv);
        mTextViewMagneticField = findViewById(R.id.magnetic_field_tv);

        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);  // 获取SensorManager服务
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 为加速度传感器注册监听器
        mSensorManager.registerListener(TestSensorActivity.this,
                                        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                                        SensorManager.SENSOR_DELAY_UI);
        // 为线性加速度传感器注册监听器
        mSensorManager.registerListener(TestSensorActivity.this,
                                        mSensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION),
                                        SensorManager.SENSOR_DELAY_UI);
        // 为重力加速度传感器注册监听器
        mSensorManager.registerListener(TestSensorActivity.this, 
                                        mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY), 
                                        SensorManager.SENSOR_DELAY_UI);
        // 为陀螺仪传感器注册监听器
        mSensorManager.registerListener(TestSensorActivity.this, 
                                        mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE), 
                                        SensorManager.SENSOR_DELAY_UI);
        // 为电磁场传感器注册监听器
        mSensorManager.registerListener(TestSensorActivity.this, 
                                        mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                                        SensorManager.SENSOR_DELAY_UI);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 取消注册所有传感器
        mSensorManager.unregisterListener(TestSensorActivity.this);
    }

    // 当传感器的值改变时回调此方法
    @Override
    public void onSensorChanged(SensorEvent event) {
        StringBuilder str = new StringBuilder();
        switch (event.sensor.getType()) {
            case Sensor.TYPE_ACCELEROMETER:
                str.append("X方向上的加速度:");
                str.append(event.values[0]);
                str.append("\nY方向上的加速度:");
                str.append(event.values[1]);
                str.append("\nZ方向上的加速度:");
                str.append(event.values[2]);
                mTextViewAcceleration.setText(str);
                break;
            case Sensor.TYPE_LINEAR_ACCELERATION:
                str.append("X方向上的线性加速度:");
                str.append(event.values[0]);
                str.append("\nY方向上的线性加速度:");
                str.append(event.values[1]);
                str.append("\nZ方向上的线性加速度:");
                str.append(event.values[2]);
                mTextViewLinearAcceleration.setText(str);
                break;
            case Sensor.TYPE_GRAVITY:
                str.append("X方向上的重力加速度:");
                str.append(event.values[0]);
                str.append("\nY方向上的重力加速度:");
                str.append(event.values[1]);
                str.append("\nZ方向上的重力加速度:");
                str.append(event.values[2]);
                mTextViewGravity.setText(str);
                break;
            case Sensor.TYPE_GYROSCOPE:
                str.append("绕X轴旋转的角速度:");
                str.append(event.values[0]);
                str.append("\n绕Y轴旋转的角速度:");
                str.append(event.values[1]);
                str.append("\n绕Z轴旋转的角速度:");
                str.append(event.values[2]);
                mTextViewGyroscope.setText(str);
                break;
            case Sensor.TYPE_MAGNETIC_FIELD:
                str.append("X方向上的磁感应强度:");
                str.append(event.values[0]);
                str.append("\nY方向上的磁感应强度:");
                str.append(event.values[1]);
                str.append("\nZ方向上的磁感应强度:");
                str.append(event.values[2]);
                mTextViewMagneticField.setText(str);
                break;
        }
    }

    // 当传感器精度改变时回调此方法
    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }
}
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context=".TestSensorActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/acceleration_sensor"
            android:textSize="15dp" />

        <TextView
            android:id="@+id/accelerometer_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/linear_acceleration_sensor"
            android:textSize="15dp" />

        <TextView
            android:id="@+id/linear_accelerometer_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/gravity_sensor"
            android:textSize="15dp" />

        <TextView
            android:id="@+id/gravity_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/gyroscope_sensor"
            android:textSize="15dp" />

        <TextView
            android:id="@+id/gyroscope_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/magnetic_field_sensor"
            android:textSize="15dp" />

        <TextView
            android:id="@+id/magnetic_field_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="@string/orientation_sensor"
            android:textSize="15dp" />

        <TextView
            android:id="@+id/orientation_tv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textSize="15dp" />
    </LinearLayout>
</ScrollView>

7.方向传感器

先看下地理坐标系和设备坐标系的区别:

TYPE_ORIENTATION并非真实的传感器,而是由其他传感器模拟而来。

Sensor.TYPE_ORIENTATION: All values are angles in degrees.

  • values[0]: Azimuth, angle between the magnetic north direction and the y-axis, around the z-axis (0 to 359). 0=North, 90=East, 180=South, 270=West
  • values[1]: Pitch, rotation around x-axis (-180 to 180), with positive values when the z-axis moves toward the y-axis.
  • values[2]: Roll, rotation around the y-axis (-90 to 90) increasing as the device moves clockwise.
  • Note: This definition is different from yaw, pitch and roll used in aviation where the X axis is along the long side of the plane (tail to nose).
  • Note: This sensor type exists for legacy reasons, please use rotation vector sensor type and getRotationMatrix() in conjunction with remapCoordinateSystem() and getOrientation() to compute these values instead.
  • Important note: For historical reasons the roll angle is positive in the clockwise direction (mathematically speaking, it should be positive in the counter-clockwise direction).
package com.lee.sensor;

import android.app.Activity;
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 OrientationActivity extends Activity {
    private SensorManager mSensorManager;
    private MySensorEventListener mListener;
    private TextView mTextViewOrientation;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_orientation);

        mTextViewOrientation = findViewById(R.id.orientation_tv);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);  // 获取SensorManager服务
        mListener = new MySensorEventListener();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(mListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
                                        SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 取消注册所有传感器
        mSensorManager.unregisterListener(mListener);
    }

    class MySensorEventListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {
            StringBuilder str = new StringBuilder();
            str.append("绕Z轴旋转的角度/方位角:");
            str.append(event.values[0]);
            str.append("\n绕X轴旋转的角度/倾斜角:");
            str.append(event.values[1]);
            str.append("\n绕Y轴旋转的角度/滚动角:");
            str.append(event.values[2]);
            mTextViewOrientation.setText(str);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    }
}

不过,TYPE_ORIENTATAION 已被标记为过时,Android推荐使用SensorManager的方法 getOrientation() 来获取方向数据。

public static float[] getOrientation (float[] R, float[] values)

  • R is a rotation matrix
  • values holds the results
  • values[0]: Azimuth(方位角), angle of rotation about the -z axis. This value represents the angle between the device's y axis and the magnetic north pole. When facing north, this angle is 0, when facing south, this angle is π. Likewise, when facing east, this angle is π/2, and when facing west, this angle is -π/2. The range of values is -π to π.
  • values[1]: Pitch(倾斜角), angle of rotation about the x axis. This value represents the angle between a plane parallel to the device's screen and a plane parallel to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the top edge of the device toward the ground creates a positive pitch angle. The range of values is -π to π.
  • values[2]: Roll(滚动角), angle of rotation about the y axis. This value represents the angle between a plane perpendicular to the device's screen and a plane perpendicular to the ground. Assuming that the bottom edge of the device faces the user and that the screen is face-up, tilting the left edge of the device toward the ground creates a positive roll angle. The range of values is -π/2 to π/2.

该方法的第一个参数R为旋转矩阵,可通过SensorManager的 getRotationMatrix() 获得,第二个参数保存函数计算所得的方向数据。

public static boolean getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic)

  • This method computes the inclination matrix I as well as the rotation matrix R transforming a vector from the device coordinate system to the world's coordinate system which is defined as a direct orthonormal basis.R is the identity matrix when the device is aligned with the world's coordinate system, that is, when the device's X axis points toward East, the Y axis points to the North Pole and the device is facing the sky.
  • R is an array of 9 floats holding the rotation matrix R when this function returns. R can be null.
  • I  is an array of 9 floats holding the rotation matrix I when this function returns. I can be null.
  • gravity is an array of 3 floats containing the gravity vector expressed in the device's coordinate.You can simply use the values returned by a SensorEvent of a Sensor of typeTYPE_ACCELEROMETER.
  • geomagnetic is an array of 3 floats containing the geomagnetic vector expressed in the device's coordinate.You can simply use the values returned by a SensorEvent of a Sensor of typeTYPE_MAGNETIC_FIELD.

getRotationMatrix()源码

public static boolean getRotationMatrix(float[] R, float[] I,
        float[] gravity, float[] geomagnetic) {
    // TODO: move this to native code for efficiency
    float Ax = gravity[0];
    float Ay = gravity[1];
    float Az = gravity[2];

    final float normsqA = (Ax * Ax + Ay * Ay + Az * Az);
    final float g = 9.81f;
    final float freeFallGravitySquared = 0.01f * g * g;
    if (normsqA < freeFallGravitySquared) {
        // gravity less than 10% of normal value
        return false;
    }

    final float Ex = geomagnetic[0];
    final float Ey = geomagnetic[1];
    final float Ez = geomagnetic[2];
    float Hx = Ey * Az - Ez * Ay;
    float Hy = Ez * Ax - Ex * Az;
    float Hz = Ex * Ay - Ey * Ax;
    final float normH = (float) Math.sqrt(Hx * Hx + Hy * Hy + Hz * Hz);

    if (normH < 0.1f) {
        // device is close to free fall (or in space?), or close to
        // magnetic north pole. Typical values are  > 100.
        return false;
    }
    final float invH = 1.0f / normH;
    Hx *= invH;
    Hy *= invH;
    Hz *= invH;
    final float invA = 1.0f / (float) Math.sqrt(Ax * Ax + Ay * Ay + Az * Az);
    Ax *= invA;
    Ay *= invA;
    Az *= invA;
    final float Mx = Ay * Hz - Az * Hy;
    final float My = Az * Hx - Ax * Hz;
    final float Mz = Ax * Hy - Ay * Hx;
    if (R != null) {
        if (R.length == 9) {
            R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
            R[3] = Mx;     R[4] = My;     R[5] = Mz;
            R[6] = Ax;     R[7] = Ay;     R[8] = Az;
        } else if (R.length == 16) {
            ...
        }
    }
    if (I != null) {
        ...
    }
    return true;
}

代码中首先对加速度g和磁力计m数据做了一个差乘,得出一个水平东西方向we的向量(差乘的定义)。经过这个运算,本来只有一个平面的向量,变成了三个三维立体平面的向量,从而可以用来计算设备的方向。源码中后面又做了一次差乘,是用计算出的水平东西方向we的向量和重力向量g做的差乘,这次运算重新得出一个水平南北sn方向的向量,最后旋转矩阵中用这三个向量(两个计算出的水平向量、一个重力向量)构成。详细推导参考文章

getOrientation()源码:

public static float[] getOrientation(float[] R, float[] values) {
    /*
     * 4x4 (length=16) case:
     *   /  R[ 0]   R[ 1]   R[ 2]   0  \
     *   |  R[ 4]   R[ 5]   R[ 6]   0  |
     *   |  R[ 8]   R[ 9]   R[10]   0  |
     *   \      0       0       0   1  /
     *
     * 3x3 (length=9) case:
     *   /  R[ 0]   R[ 1]   R[ 2]  \
     *   |  R[ 3]   R[ 4]   R[ 5]  |
     *   \  R[ 6]   R[ 7]   R[ 8]  /
     *
     */
    if (R.length == 9) {
        values[0] = (float) Math.atan2(R[1], R[4]);
        values[1] = (float) Math.asin(-R[7]);
        values[2] = (float) Math.atan2(-R[6], R[8]);
    } else {
        ...
    }

    return values;
}

实现代码: 

package com.lee.sensor;

import android.app.Activity;
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 OrientationActivity extends Activity {
    private SensorManager mSensorManager;
    private MySensorEventListener mListener;
    private TextView mTextViewOrientation;

    private float[] accelerometerValues = new float[3];
    private float[] magneticFieldValues = new float[3];
    private float[] orientationValues = new float[3];
    private float[] rotationMatrix = new float[9];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_orientation);

        mTextViewOrientation = findViewById(R.id.orientation_tv);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);  // 获取SensorManager服务
        mListener = new MySensorEventListener();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(mListener, mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
                                        SensorManager.SENSOR_DELAY_NORMAL);
        mSensorManager.registerListener(mListener, mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                                        SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 取消注册所有传感器
        mSensorManager.unregisterListener(mListener);
    }

    class MySensorEventListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {
            switch (event.sensor.getType()) {
                case Sensor.TYPE_ACCELEROMETER:
                    accelerometerValues = event.values;
                    break;
                case Sensor.TYPE_MAGNETIC_FIELD:
                    magneticFieldValues = event.values;
                    break;
            }
            SensorManager.getRotationMatrix(rotationMatrix, null,
                                            accelerometerValues, magneticFieldValues);
            SensorManager.getOrientation(rotationMatrix, orientationValues);
            orientationValues[0] = (float) Math.toDegrees(orientationValues[0]);
            orientationValues[1] = (float) Math.toDegrees(orientationValues[1]);
            orientationValues[2] = (float) Math.toDegrees(orientationValues[2]);
            StringBuilder str = new StringBuilder();
            str.append("绕Z轴旋转的角度/方位角:");
            str.append(orientationValues[0]);
            str.append("\n绕X轴旋转的角度/倾斜角:");
            str.append(orientationValues[1]);
            str.append("\n绕Y轴旋转的角度/滚动角:");
            str.append(orientationValues[2]);
            mTextViewOrientation.setText(str);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    }
}

一个小坑:实现代码中getRotationMatrix()的第三个参数是传入一个加速度传感器的数据,内部计算时需要的是重力传感器,在手机保持静止的状态下,加速度传感器可以当作重力传感器使用。但是当人手持手机行走时,加速度的数值就不等于重力传感器的数值,所计算出来的方向波动较大。解决方法是,第三个参数传入重力传感器的数据。

package com.lee.sensor;

import android.app.Activity;
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 OrientationActivity extends Activity {
    private SensorManager mSensorManager;
    private MySensorEventListener mListener;
    private TextView mTextViewOrientation;

    private float[] gravityValues = new float[3];
    private float[] magneticFieldValues = new float[3];
    private float[] orientationValues = new float[3];
    private float[] rotationMatrix = new float[9];

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_orientation);

        mTextViewOrientation = findViewById(R.id.orientation_tv);
        mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);  // 获取SensorManager服务
        mListener = new MySensorEventListener();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mSensorManager.registerListener(mListener, mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
                                        SensorManager.SENSOR_DELAY_NORMAL);
        mSensorManager.registerListener(mListener, mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                                        SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // 取消注册所有传感器
        mSensorManager.unregisterListener(mListener);
    }

    class MySensorEventListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {
            switch (event.sensor.getType()) {
                case Sensor.TYPE_GRAVITY:
                    gravityValues = event.values;
                    break;
                case Sensor.TYPE_MAGNETIC_FIELD:
                    magneticFieldValues = event.values;
                    break;                 
            }
            SensorManager.getRotationMatrix(rotationMatrix, null,
                                            gravityValues, magneticFieldValues);
            SensorManager.getOrientation(rotationMatrix, orientationValues);
            orientationValues[0] = (float) Math.toDegrees(orientationValues[0]);
            orientationValues[1] = (float) Math.toDegrees(orientationValues[1]);
            orientationValues[2] = (float) Math.toDegrees(orientationValues[2]);
            StringBuilder str = new StringBuilder();
            str.append("绕Z轴旋转的角度/方位角:");
            str.append(orientationValues[0]);
            str.append("\n绕X轴旋转的角度/倾斜角:");
            str.append(orientationValues[1]);
            str.append("\n绕Y轴旋转的角度/滚动角:");
            str.append(orientationValues[2]);
            mTextViewOrientation.setText(str);
        }

        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    }
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
BLE(低功耗蓝牙)是一种通过蓝牙无线技术进行低功耗通信的协议。它是在传统蓝牙(Classic Bluetooth)的基础上发展而来,主要用于物联网、智能家居和健康追踪等领域。 BLE主要特点有以下几个方面: 1. 低功耗:BLE采用了一种优化的通信方式,使设备在通信过程中的功耗大大降低,从而延长了设备的电池寿命,这对于需要长时间运行的设备非常重要。 2. 简化传输:BLE使用了一种称为GATT(通用属性)的协议,将数据分为服务和特征,通过读、写或订阅操作来传输数据,这种简化了传输过程,减少了额外的开销。 3. 快速连接:BLE的连接速度比传统蓝牙更快,可以在几十毫秒内建立连接,这对于移动设备和传感器等需要快速响应的设备非常重要。 4. 多设备连接:BLE支持同时连接多个设备,可以通过同一个移动设备与多个BLE设备进行通信,提高了系统的灵活性和可扩展性。 Android提供了一套完整的BLE开发API,开发者可以使用这些API来实现BLE通信功能。在Android中,开发BLE应用涉及到四个主要组件:BLE设备扫描、设备连接、数据传输和GATT服务管理。 开发者可以使用Android的BluetoothAdapter类来进行设备扫描和连接操作,可以通过BluetoothGatt类来进行GATT服务的操作,包括读、写、订阅等。 总之,BLE作为一种低功耗的蓝牙通信协议,在物联网和智能设备领域应用广泛。在Android平台上进行BLE开发,可以借助Android提供的API,快速实现BLE通信功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值