位置和传感器:运动传感器

Android平台提供了几个可让您监控设备运动的传感器。


传感器的可能结构因传感器类型而异:

1、重力,线性加速度,旋转矢量,显着运动,步进计数器和步进检测器传感器都是基于硬件或基于软件的。

2、加速度传感器和陀螺仪传感器总是基于硬件。


大多数Android设备都有一个加速度计,现在许多的加速度计包括一个陀螺仪。 基于软件的传感器的可用性更为可变,因为它们通常依赖于一个或多个硬件传感器来导出其数据。 根据设备,这些基于软件的传感器可以从加速度计和磁力计或陀螺仪中导出数据。


运动传感器可用于监控设备的运动,如倾斜,摇摆,旋转或摆动。 运动通常是直接用户输入的反映(例如,用户在游戏中指导汽车或控制游戏中的球的用户),但也可以反映设备所在的物理环境 (例如,在驾驶您的汽车时与您一起移动)。 在第一种情况下,您将监控相对于设备的参考系或运动参考系的运动; 在第二种情况下,您正在监测相对于世界参考框架的运动。 运动传感器本身通常不用于监视设备位置,但是它们可以与其他传感器(例如地磁场传感器)一起使用,以确定设备相对于世界参考系的位置(有关详细信息,请参阅位置传感器)。


所有运动传感器返回每个SensorEvent的传感器值的多维数组。 例如,在单个传感器事件期间,加速度计返回三个坐标轴的加速力数据,陀螺仪返回三个坐标轴的旋转数据速率。 这些数据值与其他SensorEvent参数一起以float数组(值)返回。 表1总结了Android平台上提供的运动传感器。


表1. Android平台支持的运动传感器。

传感器 传感器事件数据 描述 测量单位
TYPE_ACCELEROMETER SensorEvent.values[0] 沿x轴的加速度(包括重力)。 m/s2
SensorEvent.values[1] 沿y轴的加速度(包括重力)。
SensorEvent.values[2] 沿z轴的加速度(包括重力)。
TYPE_GRAVITY SensorEvent.values[0] 沿x轴的重力。 m/s2
SensorEvent.values[1] 沿y轴的重力。
SensorEvent.values[2] 沿z轴的重力。
TYPE_GYROSCOPE SensorEvent.values[0] 绕x轴旋转的速度。 rad/s
SensorEvent.values[1] 绕y轴旋转的速度。
SensorEvent.values[2] 绕z轴旋转的速度。
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] 围绕x轴的旋转速度(无漂移补偿)。 rad/s
SensorEvent.values[1] 围绕y轴的旋转速度(无漂移补偿)。
SensorEvent.values[2] 围绕z轴的旋转速度(无漂移补偿)。
SensorEvent.values[3] 估计围绕x轴的漂移。
SensorEvent.values[4] 估计围绕y轴的漂移。
SensorEvent.values[5] 估计围绕z轴的漂移。
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] 沿x轴的加速度(不包括重力)。 m/s2
SensorEvent.values[1] 沿y轴的加速度(不包括重力)。
SensorEvent.values[2] 沿z轴的加速度(不包括重力)。
TYPE_ROTATION_VECTOR SensorEvent.values[0] 沿x轴的旋转矢量分量(x * sin(θ/ 2))。 Unitless
SensorEvent.values[1] 沿y轴的旋转矢量分量(x * sin(θ/ 2))。
SensorEvent.values[2] 沿z轴的旋转矢量分量(x * sin(θ/ 2))。
SensorEvent.values[3] 旋转矢量的标量分量((cos(θ/ 2))。1
TYPE_SIGNIFICANT_MOTION N/A N/A N/A
TYPE_STEP_COUNTER SensorEvent.values[0] 传感器激活后用户自上次重启以来所采取的步骤数。 Steps
TYPE_STEP_DETECTOR N/A N/A N/A
注释1:标量组件是一个可选值。


旋转矢量传感器和重力传感器是用于运动检测和监控的最常用的传感器。 旋转矢量传感器是特别通用的,并且可以用于广泛的运动相关任务,例如检测手势,监测角度变化和监测相对方位变化。 例如,如果您正在开发游戏,增强现实应用程序,二维或三维罗盘或相机稳定应用程序,则旋转矢量传感器是理想的。 在大多数情况下,使用这些传感器是比使用加速度计和地磁场传感器或方位传感器更好的选择。


一)、Android开源项目传感器

Android开源项目(AOSP)提供三个基于软件的运动传感器:重力传感器,线性加速度传感器和旋转矢量传感器。 这些传感器在Android 4.0中更新,现在使用设备的陀螺仪(除了其他传感器)以提高稳定性和性能。 如果要尝试这些传感器,可以使用getVendor()方法和getVersion()方法(供应商是Google Inc.;版本号为3)来标识它们。 由供应商和版本号识别这些传感器是必要的,因为Android系统认为这三个传感器是二次传感器。 例如,如果设备制造商提供自己的重力传感器,则AOSP重力传感器显示为二次重力传感器。 这些传感器中的所有三个都依赖于陀螺仪:如果设备没有陀螺仪,则这些传感器不会显示并且不可用。



一、使用重力传感器

重力传感器提供指示重力的方向和大小的三维矢量。 通常,该传感器用于确定设备在空间中的相对方向。 以下代码显示了如何获取默认重力传感器的实例:

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

单位与加速度传感器(m / s2)使用的单位相同,坐标系与加速度传感器使用的坐标系相同。


注意:当设备静止时,重力传感器的输出应与加速度计的输出相同。



二、使用线性加速度计

线性加速度传感器为您提供了一个三维向量,表示每个设备轴的加速度,不包括重力。 您可以使用此值执行手势检测。 该值还可以作为使用航位推算的惯性导航系统的输入。 以下代码显示了如何获取默认线性加速度传感器的实例:

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

从概念上讲,该传感器根据以下关系为您提供加速数据:

linear acceleration = acceleration - acceleration due to gravity

当您想要在不受重力影响的情况下获得加速度数据时,通常使用此传感器。 例如,您可以使用此传感器来查看您的车辆有多快。 线性加速度传感器始终具有偏移量,需要移除。 最简单的方法是在您的应用程序中构建一个校准步骤。 在校准期间,您可以要求用户将设备设置在桌面上,然后读取所有三个轴的偏移量。 然后,您可以从加速度传感器的直接读数中减去该偏移量,以获得实际的线性加速度。


传感器坐标系与加速度传感器使用的坐标系统相同,测量单位(m / s2)也是如此。



三、使用旋转矢量传感器

旋转矢量表示装置作为角度和轴的组合的取向,其中装置已绕轴线(x,y或z)旋转角度θ。 以下代码显示了如何获取默认旋转矢量传感器的实例:

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

旋转矢量的三个要素表示如下:

x*sin(θ/2)
y*sin(θ/2)
z*sin(θ/2)

其中旋转矢量的大小等于sin(θ/ 2),并且旋转矢量的方向等于旋转轴的方向。


旋转矢量的三个要素等于单位四元数的最后三个分量(cos(θ/ 2),x * sin(θ/ 2),y * sin(θ/ 2),z * sin2))。 旋转矢量的元素是无单位的。 x,y和z轴的定义方式与加速度传感器相同。 参考坐标系被定义为直接正交基准(见图1)。 该坐标系具有以下特点:

1、X被定义为矢量积Y x Z.它在设备的当前位置处与地面相切,并且大约东近点。

2、Y在设备的当前位置与地面相切,并指向地磁北极。

3、Z指向天空,垂直于地平面。



Android SDK提供了一个示例应用程序,显示如何使用旋转矢量传感器。 示例应用程序位于API演示代码(OS - RotationVectorDemo)中。



四、使用显式运动传感器

每次检测到显着的运动时,有效的运动传感器触发事件,然后它会自动禁用。 一个重要动议是可能导致用户位置变化的动议; 例如步行,骑自行车或坐在移动的汽车中。 以下代码显示了如何获取默认的重要运动传感器的实例以及如何注册事件侦听器:

private SensorManager mSensorManager;
private Sensor mSensor;
private TriggerEventListener mTriggerEventListener;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

mTriggerEventListener = new TriggerEventListener() {
    @Override
    public void onTrigger(TriggerEvent event) {
        // Do work
    }
};

mSensorManager.requestTriggerSensor(mTriggerEventListener, mSensor);

有关更多信息,请参阅 TriggerEventListener



五、使用步进传感器

步进计数器传感器提供了在传感器被激活时自上次重新启动以来用户执行的步骤数。 步数计数器具有更多的延迟(最多10秒),但比步进检测器传感器更准确。 以下代码显示了如何获取默认步进计数器传感器的实例:

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

要在运行应用程序的设备上保存电池,您应该使用JobScheduler类以特定间隔从步数传感器中检索当前值。 虽然不同类型的应用程序需要不同的传感器读取间隔,但您应该尽可能长的时间间隔,除非您的应用程序需要传感器的实时数据。



六、使用步进检测器传感器

每次用户步进时,步进检测器传感器触发事件。 延迟预计将在2秒以下。 以下代码显示了如何获取默认步进探测器传感器的实例:

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


七、使用原始数据

以下传感器为您的应用程序提供了应用于设备的线性和旋转力的原始数据。 为了有效地使用这些传感器的值,您需要滤除环境中的因素,如重力。 您可能还需要对值趋势应用平滑算法以减少噪声。


一)、使用加速度计

加速度传感器测量施加到设备的加速度,包括重力。 以下代码显示了如何获取默认加速度传感器的实例:

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

在概念上,加速度传感器通过使用以下关系测量施加到传感器本身的力(Fs)来确定施加到设备(Ad)的加速度:

Ad = - ∑Fs / mass
然而,根据以下关系,重力总是影响测量的加速度:
Ad = -g - ∑F / mass
因此,当设备坐在桌子上(而不是加速)时,加速度计读取g = 9.81 m / s2的大小。 类似地,当装置自由落体并因此以9.81m / s2迅速地向地面加速时,其加速度计读取g = 0m / s2的大小。 因此,为了测量装置的实际加速度,必须从加速度计数据中去除重力的贡献。 这可以通过应用高通滤波器来实现。 相反,可以使用低通滤波器来隔离重力。 以下示例显示如何执行此操作:
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];
}

注意:您可以使用许多不同的技术来过滤传感器数据。 上面的代码示例使用一个简单的滤波常量(alpha)创建一个低通滤波器。 该滤波常数是从时间常数(t)导出的,这是滤波器增加传感器事件的延迟和传感器的事件传送速率(dt)的粗略表示。 代码示例使用0.8的alpha值作为演示目的。 如果您使用此过滤方法,则可能需要选择不同的Alpha值。
 
加速度计使用标准传感器坐标系。 实际上,这意味着当设备以自然方向平放在桌子上时,适用以下条件:
1、如果您在左侧推动设备(所以向右移动),x加速度值为正。
2、如果您将设备推向底部(因此远离您),则y加速度值为正。
3、如果以A m / s2的加速度将设备推向天空,z加速度值等于A + 9.81,这对应于设备的加速度(+ A m / s2)减去重力( - 9.81 m / s2)。
4、固定装置的加速度值为+9.81,对应于装置的加速度(0 m / s2减去重力,即-9.81 m / s2)。
 
一般来说,如果您正在监控设备运动,加速度计是一个很好的传感器。 几乎每个Android手机和平板电脑都有一个加速度计,它比其他运动传感器使用的功率要低10倍。 一个缺点是您可能需要实施低通和高通滤波器来消除重力并减少噪音。
 
Android SDK提供了一个示例应用程序,显示如何使用加速度传感器(加速度计播放)。
 
二)、使用陀螺仪
陀螺仪测量围绕设备x,y和z轴的rad / s的旋转速率。 以下代码显示了如何获取默认陀螺仪的实例:
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;
   }
}

标准陀螺仪提供原始旋转数据,无需对噪声和漂移(偏置)进行任何滤波或校正。 在实践中,陀螺仪的噪声和漂移会引入需要补偿的误差。 您通常通过监测其他传感器(如重力传感器或加速度计)来确定漂移(偏差)和噪声。
使用未校准的陀螺仪
未校准的陀螺仪与陀螺仪类似,不同之处在于旋转速率不适用陀螺漂移补偿。 工厂校准和温度补偿仍然适用于旋转速率。 未校准的陀螺仪可用于后处理和熔接取向数据。 通常,gyroscope_event.values [0]将接近uncalibrated_gyroscope_event.values [0] - uncalibrated_gyroscope_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_GYROSCOPE_UNCALIBRATED);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值