【Sensors】运动传感器(3)

2023-01-31 01:01:36 sensors 运动 传感器

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

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

重力,线性加速度,旋转矢量,显着运动,步进计数器和步进检测器传感器基于硬件或基于软件。
加速计和陀螺仪传感器始终基于硬件。
大多数由Android设备驱动的设备都有一个加速计,而且现在很多设备都包含一个陀螺仪。基于软件的传感器的可用性更加可变,因为它们通常依靠一个或多个硬件传感器来获取其数据。根据设备的不同,这些基于软件的传感器可以从加速计和磁力计或陀螺仪获取数据。

运动传感器可用于监视设备移动,如倾斜,摇晃,旋转或摆动。该移动通常是直接用户输入的反映(例如,用户在游戏中操纵汽车或在游戏中控制球的用户),但它也可以反映设备所处的物理环境(例如,在开车的时候随身携带)。在第一种情况下,您正在监视相对于设备参考帧或应用程序参考帧的运动; 在第二种情况下,您正在监视相对于世界参照系的运动。运动传感器本身通常不用于监测设备位置,但它们可以与其他传感器(如地磁场传感器)一起使用,以确定设备相对于世界的位置。位置传感器了解更多信息)。

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

表1. Android平台支持的运动传感器
【Sensors】运动传感器(3)
【Sensors】运动传感器(3)
【Sensors】运动传感器(3)

1标量组件是一个可选值。

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

Android开源项目传感器

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

使用重力传感器


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

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

这些单位与加速度传感器(m / s 2)所使用的单位相同,且坐标系与加速度传感器使用的坐标系相同。

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

使用线性加速度计


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

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

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

线性加速度=加速度 - 重力加速度

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

传感器坐标系与加速度传感器使用的坐标系相同,测量单位(m / s 2)也一样。

使用旋转矢量传感器


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

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

旋转矢量的三个要素表示如下
【Sensors】运动传感器(3)
在旋转矢量的大小等于sin(θ/ 2)的情况下,旋转矢量的方向等于旋转轴的方向。

【Sensors】运动传感器(3)
图1.旋转矢量传感器使用的坐标系。

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

X被定义为向量乘积Y x Z.它与设备当前位置的地面相切,并且点约为东。
Y在设备当前位置与地面相切,并指向地磁北极。
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);

【Sensors】运动传感器(3)

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值。

加速度计使用标准的传感器坐标系。实际上,这意味着当设备以自然方向平放在桌子上时,下列条件适用:

  • 如果将设备推到左侧(所以它向右移动),则x加速度值为正值。
  • 如果您将设备推到底部(使其远离您),则y加速度值为正数。
  • 如果以A m / s 2的加速度将设备推向天空,则z加速度值等于A + 9.81,其对应于设备的加速度(+ A m / s 2)减去重力(-9.81米/秒2)。
  • 固定装置将具有+9.81的加速度值,其对应于装置的加速度(0m / s 2减去重力,即-9.81m / s 2)。
    一般来说,如果您正在监视设备运动,则加速计是一个很好的传感器。几乎所有基于Android的手机和平板电脑都有一个加速度计,它比其他运动传感器的功耗低大约10倍。一个缺点是您可能必须使用低通和高通滤波器来消除重力并减少噪音。

Android SDK提供了一个示例应用程序,显示如何使用加速度传感器(Accelerometer Play)

使用陀螺仪

陀螺仪以设备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);

其他代码示例


该AccelerometerPlay样品和 Android的BatchStepSensor样品进一步证明使用覆盖此页面上的API。

你也应该阅读

  • 传感器
  • 传感器概述
  • 位置传感器
  • 环境传感器

    Lastest Update:2018.04.24

联系我

QQ:94297366
微信打赏:https://pan.baidu.com/s/1dSBXk3eFZu3mAMkw3xu9KQ

公众号推荐:

【Sensors】运动传感器(3)

相关文章