Android官方文档之Location and Sensors APIs(下)

本文将介绍运动传感器(Motion Sensors)、位置传感器(Position Sensors)、环境传感器(Environment Sensors)。
如需访问官方原文,您可以点击这些链接:


运动传感器(Motion Sensors)


Android中提供了大量运动传感器,其中有两个是硬件驱动型的:加速计(accelerometer) 和 陀螺仪(gyroscope);有三个是软件和硬件联合驱动型的: 重力仪(gravity)、 线性加速器(linear acceleration)、旋转向量传感器(rotation vector sensors)。软件驱动型的传感器具有更高的灵活性,因为它可以从不同的硬件驱动型的传感器获取数据并进行组合计算(The availability of the software-based sensors is more variable because they often rely on one or more hardware sensors to derive their data)。


运动传感器可以监测设备的倾斜、摇动、旋转 和 摇摆 等( tilt, shake, rotation, or swing)。这些运动通常来自用户的动作,如在游戏中操纵一辆汽车或一个小球;当然运动传感器也可以监测设备相对于周围环境的变化,如设备在汽车中 等。对于第一种情况,传感器监测的是设备自身的相对运动,而后者监测的则是相对于地面的相对运动。为了监测位置,运动传感器还可以与其他传感器配合使用,如地磁传感器。


所有传感器都会将监测的数据封装在SensorEvent类中的多维数组中。比如,加速器监测的加速力(F=m*a^2)可以分解为三维坐标系的三个方向,即三组值。这些数据会被存储在float型的数组中。下表列出了Android中运动传感器的回传值的存储形式:

运动传感器类型(Sensor)回传的数据(Sensor event data)描述(Description)单位(Units of measure)
加速器TYPE_ACCELEROMETERSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2]分别表示:x方向的加速度(包含重力加速度)、y方向的加速度(包含重力加速度)、z方向的加速度(包含重力加速度)m/s^2
重力仪TYPE_GRAVITYSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2]分别表示:x方向的加速度、y方向的加速度、z方向的加速度m/s^2
陀螺仪TYPE_GYROSCOPESensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2]分别表示:x方向的转动速率、 y方向的转动速率、z方向的转动速率rad/s
无标定陀螺仪TYPE_GYROSCOPE_UNCALIBRATEDSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2] SensorEvent.values[3] SensorEvent.values[4] SensorEvent.values[5]分别表示:x方向的转动速率(无温漂补偿)、y方向的转动速率(无温漂补偿)、z方向的转动速率(无温漂补偿)、x方向的飘移估计值、y方向的飘移估计值、z方向的飘移估计值rad/s
线性加速器TYPE_LINEAR_ACCELERATIONSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2]SensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2]分别表示:x方向的加速度(包含重力加速度)、y方向的加速度(包含重力加速度)、z方向的加速度(包含重力加速度)
旋转向量TYPE_ROTATION_VECTORSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2] SensorEvent.values[3]分别表示:x方向的旋转向量矢量和(x * sin(θ/2))、y方向的旋转向量矢量和(y * sin(θ/2))、z方向的旋转向量矢量和(z * sin(θ/2))无单位
计步器TYPE_STEP_COUNTERSensorEvent.values[0]从最近一次开机到当前为止的用户的步数单位:步数

旋转向量传感器和重力传感器最为常用( rotation vector sensor and the gravity sensor),其中前者可以监测手势、监测角度变化 等。该传感器可以替代加速器、地磁仪或方向传感器。

Android传感器开源项目(Android Open Source Project Sensors)

Android传感器开源项目(Android Open Source Project Sensors,简称AOSP)提供了三种软件驱动型的传感器。分别是:重力传感器、线性加速器 和 旋转向量传感器。这些传感器支持Android 4.0及以上版本,并提供了更高的稳定性。


使用加速器(Using the Accelerometer)


获取加速器实例的方式如下:

private SensorManager mSensorManager;
private Sensor mSensor;
  ...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

设备受到的加速度与其受力的关系如下:

Ad = - ∑Fs / mass

考虑到设备还受到重力影响:

Ad = -g - ∑F / mass

当设备静止时,上述公式的g = 9.81 m/s2,当设备自由下落时, g = 0 m/s2。所以为了测量实际的加速度,必须排除g的影响。这可以通过一个高通滤波器实现(achieved by applying a high-pass filter)。相反,使用低通滤波器可以过滤其他因素而只剩重力加速度g。

具体方式如下:

public 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.8;

  // 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];
}

当设备放在水平桌面时:

  • 从左向右移动设备,则x方向的加速度为正值;

  • 从底部向顶部移动设备,则y方向的加速度为正值;

  • 从下向上以加速度A的大小抛出设备时,则z方向的加速度为A+9.81,那么设备的相对加速度为A - 9.81。(排除重力加速度的影响)

  • 设备静止时垂直地面方向的相对加速度为-9.81 m/s2。(排除重力加速度的影响)


使用重力传感器(Using the Gravity Sensor)


获取重力传感器实例的方式如下:

private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);

使用陀螺仪(Using the Gyroscope)


陀螺仪实例的获取方式如下:

private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);

对于陀螺仪,从x,y,z轴的负方向向正方向看去,顺时针转动为正值,反之为负值。


使用方式如下:

// 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;

public 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 sample
    float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);

    // Normalize the rotation vector if it's big enough to get the axis
    // (that is, EPSILON should represent your maximum allowable margin of error)
    if (omegaMagnitude > EPSILON) {
      axisX /= omegaMagnitude;
      axisY /= omegaMagnitude;
      axisZ /= omegaMagnitude;
    }

    // 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 = sin(thetaOverTwo);
    float cosThetaOverTwo = 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);
    // User code should concatenate the delta rotation we computed with the current rotation
    // in order to get the updated rotation.
    // rotationCurrent = rotationCurrent * deltaRotationMatrix;
   }
}

位置传感器(Position Sensors)


Android中提供了两类位置传感器用于确定当前设备的位置:加速器和地磁仪(the geomagnetic field sensor and the accelerometer)。Android还提供了用于监测设备与周围物体距离的传感器(如手机贴近耳朵时点灭屏幕),即接近度传感器(proximity sensor)。磁力仪和接近度传感器都是硬件驱动型的,下表列举了各种位置传感器回传值所代表的意义:


位置传感器(Sensor)回传值(Sensor event data)描述(Description)单位(Units of measure)
游戏类型的旋转向量传感器TYPE_GAME_ROTATION_VECTORSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2]分别表示:x方向的转动向量(x * sin(θ/2))、y方向的转动向量(y * sin(θ/2))、z方向的转动向量(z * sin(θ/2))无单位
地磁类型的旋转向量传感器TYPE_GEOMAGNETIC_ROTATION_VECTOR同上同上同上
磁力仪TYPE_MAGNETIC_FIELD同上分别表示:x方向受到的磁场强度、y方向受到的磁场强度、z方向受到的磁场强度μT 微特斯拉
无标定的磁力仪TYPE_MAGNETIC_FIELD_UNCALIBRATEDSensorEvent.values[0] SensorEvent.values[1] SensorEvent.values[2] SensorEvent.values[3] SensorEvent.values[4] SensorEvent.values[5]分别表示:x方向受到的磁场强度(无硬铁校准)、y方向受到的磁场强度(无硬铁校准)、z方向受到的磁场强度(无硬铁校准)、沿x轴铁偏差校准、沿y轴铁偏差校准、沿z轴铁偏差校准同上
接近度传感器TYPE_PROXIMITYSensorEvent.values[0]与物体的距离厘米 cm

计算设备的方向(Computing the Device’s Orientation)

下面的代码演示了如何检测设备的朝向:

private SensorManager mSensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
mSensorManager.getRotationMatrix(rotationMatrix, null,
  accelerometerReading, magnetometerReading);

// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
mSensorManager.getOrientation(rotationMatrix, orientationAngles);

获得的结果如下:

  • 方位角(Azimuth ):与z轴负方向的夹角。即手机的罗盘方向与北极点的夹角( This is the angle between the device’s current compass direction and magnetic north. If the top edge of the device faces magnetic north)。如果设备的顶部朝向正北,则该角度为0;若朝向正南,角度为180;朝向正东,为90度;正西为270度

  • 倾斜角(Pitch ):与x轴正方向的夹角。即手机屏幕的平行线与地面的平行线的夹角( This is the angle between a plane parallel to the device’s screen and a plane parallel to the ground)。若将设备水平拿在手上,并将设备尾部朝向自己,这时若将设备旋转:头部慢慢朝向地面,此时该角度将成为正值,即0到90度(If you hold the device parallel to the ground with the bottom edge closest to you and tilt the top edge of the device toward the ground, the pitch angle becomes positive)。相反,若将头部慢慢朝向天空,此时将变为负值,即0到-90度。该角度的范围是-180到+180度。

  • 滚动角(Roll ):与y轴正方向的夹角。即手机屏幕的垂线与地面垂线的夹角(This is the angle between a plane perpendicular to the device’s screen and a plane perpendicular to the ground)。若将设备水平拿在手上,并将设备尾部朝向自己,这时若将设备旋转:左侧慢慢朝向地面,此时该角度将成为正值,即0到90度。若是右侧慢慢朝向地面,此时该角度将成为负值,即0到-90度。该角度的变化为-90度到+90度。


与其他传感器不同,获取方向传感器使用的是getRotationMatrix()方法与getOrientation()方法。示例如下:

public class SensorActivity extends Activity implements SensorEventListener {

  private SensorManager mSensorManager;
  private final float[] mAccelerometerReading = new float[3];
  private final float[] mMagnetometerReading = new float[3];

  private final float[] mRotationMatrix = new float[9];
  private final float[] mOrientationAngles = new float[3];

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
  }

  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
    // Do something here if sensor accuracy changes.
    // You must implement this callback in your code.
  }

  @Override
  protected void onResume() {
    super.onResume();

    // Get updates from the accelerometer and magnetometer at a constant rate.
    // To make batch operations more efficient and reduce power consumption,
    // provide support for delaying updates to the application.
    //
    // In this example, the sensor reporting delay is small enough such that
    // the application receives an update before the system checks the sensor
    // readings again.
    mSensorManager.registerListener(this, Sensor.TYPE_ACCELEROMETER,
      SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
    mSensorManager.registerListener(this, Sensor.TYPE_MAGNETIC_FIELD,
      SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
  }

  @Override
  protected void onPause() {
    super.onPause();

    // Don't receive any more updates from either sensor.
    mSensorManager.unregisterListener(this);
  }

  // Get readings from accelerometer and magnetometer. To simplify calculations,
  // consider storing these readings as unit vectors.
  @Override
  public void onSensorChanged(SensorEvent event) {
    if (event.sensor == Sensor.TYPE_ACCELEROMETER) {
      System.arraycopy(event.values, 0, mAccelerometerReading,
        0, mAccelerometerReading.length);
    }
    else if (event.sensor == Sensor.TYPE_MAGNETIC_FIELD) {
      System.arraycopy(event.values, 0, mMagnetometerReading,
        0, mMagnetometerReading.length);
    }
  }

  // Compute the three orientation angles based on the most recent readings from
  // the device's accelerometer and magnetometer.
  public void updateOrientationAngles() {
    // Update rotation matrix, which is needed to update orientation angles.
    mSensorManager.getRotationMatrix(mRotationMatrix, null,
      mAccelerometerReading, mMagnetometerReading);

    // "mRotationMatrix" now has up-to-date information.

    mSensorManager.getOrientation(mRotationMatrix, mOrientationAngles);

    // "mOrientationAngles" now has up-to-date information.
  }
}

使用接近度传感器(Using the Proximity Sensor)

获取接近度传感器实例的方式如下:

private SensorManager mSensorManager;
private Sensor mSensor;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

该传感器通常用于监测用户打电话时,耳朵距离设备的距离。大部分接近度传感器会返回距离的绝对值,单位是cm,而少数传感器仅会返回代表距离物体远近的boolean值。下面的例子演示了如何应用该传感器:

public class SensorActivity extends Activity implements SensorEventListener {
  private SensorManager mSensorManager;
  private Sensor mProximity;

  @Override
  public final void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Get an instance of the sensor service, and use that to get an instance of
    // a particular sensor.
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mProximity = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
  }

  @Override
  public final void onAccuracyChanged(Sensor sensor, int accuracy) {
    // Do something here if sensor accuracy changes.
  }

  @Override
  public final void onSensorChanged(SensorEvent event) {
    float distance = event.values[0];
    // Do something with this sensor data.
  }

  @Override
  protected void onResume() {
    // Register a listener for the sensor.
    super.onResume();
    mSensorManager.registerListener(this, mProximity, SensorManager.SENSOR_DELAY_NORMAL);
  }

  @Override
  protected void onPause() {
    // Be sure to unregister the sensor when the activity pauses.
    super.onPause();
    mSensorManager.unregisterListener(this);
  }
}

环境传感器(Environment Sensors)


通过环境传感器,您可以获取设备所处环境的湿度、温度、光照强度、大气压力等等。

与其他传感器不同的是,环境传感器并不返回一组数据,而且没有低通和高通滤波器,如下表所示:

传感器(Sensor)回传数据(Sensor event data)单位(Units of measure)描述(Data description)
温度传感器TYPE_AMBIENT_TEMPERATUREevent.values[0]°C温度
光强传感器TYPE_LIGHTevent.values[0]勒克斯lx光强
压力传感器TYPE_PRESSUREevent.values[0]百帕 或 毫巴(hPa or mbar)大气压强
相对湿度传感器TYPE_RELATIVE_HUMIDITYevent.values[0]%相对湿度

使用光线、压力和温度传感器(Using the Light, Pressure, and Temperature Sensors)

示例如下:

public class SensorActivity extends Activity implements SensorEventListener {
  private SensorManager mSensorManager;
  private Sensor mPressure;

  @Override
  public final void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    // Get an instance of the sensor service, and use that to get an instance of
    // a particular sensor.
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mPressure = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
  }

  @Override
  public final void onAccuracyChanged(Sensor sensor, int accuracy) {
    // Do something here if sensor accuracy changes.
  }

  @Override
  public final void onSensorChanged(SensorEvent event) {
    float millibars_of_pressure = event.values[0];
    // Do something with this sensor data.
  }

  @Override
  protected void onResume() {
    // Register a listener for the sensor.
    super.onResume();
    mSensorManager.registerListener(this, mPressure, SensorManager.SENSOR_DELAY_NORMAL);
  }

  @Override
  protected void onPause() {
    // Be sure to unregister the sensor when the activity pauses.
    super.onPause();
    mSensorManager.unregisterListener(this);
  }
}

使用湿度传感器(Using the Humidity Sensor)

使用湿度传感器与光照传感器 等环境传感器的方式一致。若您的设备上同时包含了湿度传感器与温度传感器,那么可以利用这两个传感器返回的值计算露点(Dew point)和绝对湿度( absolute humidity):

  • 露点(Dew point):露点,也称冷凝点,表示水蒸气冷凝成液态水所需要的温度。露点的计算公式如下:
    这里写图片描述

其中:

  • td表示露点温度,单位是摄氏度;

  • t表示当前温度,单位是摄氏度;

  • RH表示相对湿度,值为百分比形式(%);

  • m = 17.62;

  • Tn = 243.12;


  • 绝对湿度(Absolute humidity):表示标准状态下(760mmHg)每立方米湿空气中所含水蒸汽的重量。绝对湿度的计算公式如下:
    这里写图片描述

其中:

  • dv表示绝对湿度,单位是g/m^3,克/立方米。

  • t表示当前环境温度;

  • RH表示相对湿度,值为百分比形式(%);

  • m = 17.62

  • Tn = 243.12 摄氏度

  • A = 6.112 hPa

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值