位置和传感器:位置传感器

Android平台提供两个传感器,您可以确定设备的位置:地磁场传感器和加速度计。 Android平台还提供了一个传感器,可让您确定设备的面部与物体(称为接近传感器)的距离。 地磁场传感器和接近传感器是基于硬件的。 大多数手机和平板电脑制造商都包括地磁场传感器。 同样,手机制造商通常包括一个接近传感器来确定手机何时被保持靠近用户的脸部(例如在电话呼叫期间)。 要确定设备的方向,您可以使用设备加速度计和地磁场传感器的读数。


注意:在Android 2.2(API 8级)中,方向传感器已被弃用,Android 4.4W(API级别20)中的方向传感器类型已弃用。


位置传感器可用于确定设备在世界范围内的参考物理位置。 例如,您可以将地磁场传感器与加速度计结合使用,以确定设备相对于磁北极的位置。 您还可以使用这些传感器来确定设备在应用程序参考框架中的方向。 位置传感器通常不用于监视设备的运动或运动,例如抖动,倾斜或推力(有关更多信息,请参阅运动传感器)。


地磁场传感器和加速度计返回每个SensorEvent的传感器值的多维数组。 例如,地磁场传感器在单个传感器事件期间为三个坐标轴中的每一个提供地磁场强度值。 同样,加速度计传感器测量在传感器事件期间施加到设备的加速度。 有关传感器使用的坐标系的更多信息,请参阅传感器坐标系。 接近传感器为每个传感器事件提供单个值。 表1总结了Android平台支持的位置传感器。


表1. Android平台支持的位置传感器。

传感器 传感器事件数据 描述 测量单位
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] 沿x轴的旋转矢量分量(x * sin(θ/ 2))。 Unitless
SensorEvent.values[1] 沿y轴的旋转矢量分量(y * sin(θ/ 2))。
SensorEvent.values[2] 沿z轴的旋转矢量分量(z * sin(θ/ 2))。
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] 沿x轴的旋转矢量分量(x * sin(θ/ 2))。 Unitless
SensorEvent.values[1] 沿y轴的旋转矢量分量(y* sin(θ/ 2))。
SensorEvent.values[2] 沿z轴的旋转矢量分量(z * sin(θ/ 2))。
TYPE_MAGNETIC_FIELD SensorEvent.values[0] 沿x轴的地磁场强度。 μT
SensorEvent.values[1] 沿y轴的地磁场强度。
SensorEvent.values[2] 沿z轴的地磁场强度。
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] 沿x轴的地磁场强度(不含硬铁校准)。 μT
SensorEvent.values[1] 沿y轴的地磁场强度(不含硬铁校准)。
SensorEvent.values[2] 沿z轴的地磁场强度(不含硬铁校准)。
SensorEvent.values[3] 沿x轴的铁偏差估计。
SensorEvent.values[4] 沿y轴的铁偏差估计。
SensorEvent.values[5] 沿z轴的铁偏差估计。
TYPE_ORIENTATION1 SensorEvent.values[0] 方位角(围绕z轴的角度)。 Degrees
SensorEvent.values[1] 间距(围绕x轴的角度)。
SensorEvent.values[2] 滚动(围绕y轴的角度)。
TYPE_PROXIMITY SensorEvent.values[0] 距离物体。2 cm
注释1:该传感器在Android 2.2(API级别8)中已弃用,并且此传感器类型已在Android 4.4W(API级别20)中弃用。 传感器框架提供了用于获取设备方向的替代方法,这在计算设备方向中有所讨论。

注释2:一些接近传感器仅提供代表近和远的二进制值。



一、使用游戏旋转矢量传感器

游戏旋转矢量传感器与旋转矢量传感器相同,但不使用地磁场。 因此,Y轴不指向北,而是指向其他参考。 允许该参考值与陀螺仪绕Z轴漂移相同的数量级。


由于游戏旋转矢量传感器不使用磁场,相对旋转更准确,不受磁场变化的影响。 如果您不在乎北方的地方,在游戏中使用此传感器,并且正常的旋转矢量不符合您的需要,因为它依赖于磁场。


以下代码显示如何获取默认游戏旋转矢量传感器的实例:

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



二、使用地磁旋转矢量传感器

地磁旋转矢量传感器类似于旋转矢量传感器,但它使用磁力计而不是陀螺仪。 该传感器的精度低于正常旋转矢量传感器,但功耗降低。 如果您想在背景中收集一些旋转信息,而不会耗尽太多电池,则只能使用此传感器。 当成批一起使用时,该传感器是最有用的。


以下代码显示如何获取默认地磁旋转矢量传感器的实例:

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


三、计算设备的方向

通过计算设备的方向,您可以监视设备相对于地球参考系(特别是磁北极)的位置。 以下代码显示了如何计算设备的方向:

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

该系统通过使用设备的地磁场传感器与设备的加速度计相结合来计算取向角度。 使用这两个硬件传感器,系统提供以下三个定向角度的数据:

1、方位角(围绕-z轴的旋转度)。 这是设备当前的罗盘方向与磁北的角度。 如果设备的顶边朝向磁北,方位角为0度; 如果顶边朝南,方位角为180度。 类似地,如果顶部边缘朝向东边,则方位角为90度,如果顶部边缘向西,方位角为270度。


2、间距(绕x轴旋转的程度)。 这是平行于设备屏幕的平面与平行于地面的平面之间的角度。 如果您将设备平行于地面,底边最接近您,并将设备的顶部边缘朝向地面倾斜,则俯仰角变为正。 相反方向倾斜 - 将设备的顶部边缘移离地面,会使桨距角变为负。 值的范围为-180度至180度。


3、卷(绕y轴旋转的程度)。 这是垂直于设备屏幕的平面与垂直于地面的平面之间的角度。 如果您将设备平行于地面,底边最接近您,并将设备的左边缘朝向地面倾斜,则倾斜角度将变为正值。 向相反方向倾斜 - 将设备的右边缘朝向地面移动 - 导致滚动角变为负。 值的范围为-90度至90度。


注意:传感器的滚动定义已经改变,以反映地理传感器生态系统中绝大多数的实施。


请注意,这些角度与航空中使用的坐标系不同(用于偏航,俯仰和俯仰)。 在航空系统中,x轴沿着飞机的长边,从尾部到鼻子。


方位传感器通过处理来自加速度计和地磁场传感器的原始传感器数据来得出其数据。 由于所涉及的重处理,定向传感器的精度和精度降低。 具体来说,只有当滚动角度为0时,该传感器才可靠。因此,Android 2.2(API 8级)中的方向传感器已被弃用,Android 4.4W(API 20级)中的方向传感器类型已被弃用。 而不是使用方向传感器的原始数据,我们建议您将getRotationMatrix()方法与getOrientation()方法结合使用来计算方位值,如以下代码示例所示。 作为此过程的一部分,您可以使用remapCoordinateSystem()方法将方向值转换为应用程序的参考框架。

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.
  }
}

除了将传感器的坐标系转换为应用程序的参考系之外,您通常不需要对设备的原始方位角进行任何数据处理或过滤。



四、使用地磁场传感器

地磁场传感器可以监测地球磁场的变化。 以下代码显示了如何获取默认地磁场传感器的实例:

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

该传感器为三个坐标轴中的每一个提供原始场强数据(μT)。 通常,您不需要直接使用此传感器。 相反,您可以使用旋转矢量传感器来确定原始旋转运动,或者可以使用加速度计和地磁场传感器以及getRotationMatrix()方法来获取旋转矩阵和倾斜矩阵。 然后,您可以使用这些矩阵与getOrientation()和getInclination()方法来获取方位角和地磁倾角数据。


注意:在测试您的应用程序时,您可以通过以图8模式挥舞设备来提高传感器的准确度。



五、使用未校准的磁强计

未校准的磁力计类似于地磁场传感器,除了没有硬铁校准应用于磁场。 工厂校准和温度补偿仍然适用于磁场。 未校准的磁力计可用于处理不良硬铁的估计。 一般来说,geomagneticsensor_event.values [0]将接近uncalibrated_magnetometer_event.values [0] - uncalibrated_magnetometer_event.values [3]。 那是,

calibrated_x ~= uncalibrated_x - bias_estimate_x


注意:未校准的传感器提供更多的原始结果,并且可能包含一些偏差,但是它们的测量包含通过校准应用校正的跳跃较少。 一些应用可能更喜欢这些未校准的结果更平滑和更可靠。 例如,如果应用程序试图进行自己的传感器融合,引入校准可能会使结果失真。


除了磁场之外,未校准的磁力计还提供每个轴上估计的硬铁偏压。 以下代码显示了如何获取默认的未校准磁强计的实例:

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


六、使用接近传感器

接近传感器允许您确定物体距离设备有多远。 以下代码显示了如何获取默认接近传感器的实例:

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

接近传感器通常用于确定人的头部距手机设备的面部有多远(例如,当用户正在进行或接收电话时)。 大多数接近传感器返回绝对距离(cm),但有些仅返回近似值和远值。 以下代码显示了如何使用接近传感器:

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);
  }
}

注意:一些接近传感器返回表示“近”或“远”的二进制值。 在这种情况下,传感器通常在远状态报告其最大范围值,并且在近状态下报告较小的值。 通常,远值为> 5厘米,但这可能因传感器而异。 您可以使用getMaximumRange()方法确定传感器的最大范围。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值