Android系统运动传感器
时间:2023-12-03 00:37:05
转自:https://blog.csdn.net/liang123l/article/details/53992197
Android该平台为您监控设备的运动提供了多种传感器。
传感器的结构因传感器类型而异:
- 重力、线性加速度、旋转矢量、重要运动、基于硬件或软件的步进检测传感器。
- 加速器和陀螺仪传感器始终以硬件为基础。
大多数Android现在大多数设备都有加速度计Android设备和陀螺仪。基于软件的传感器更可变,因为它们通常依靠一个或多个硬件传感器来导出数据。根据设备,这些基于软件的传感器可以从加速度计、磁力计或陀螺仪中导出数据。
运动传感器对监控设备(如运动、倾斜、摇摆、旋转或摇摆)非常有用。运动通常是用户直接输入的反应(例如,用户在游戏中操纵汽车或在游戏中控制用户的球),但它也可以反应设备所处于的物理环境(例如:在你驾驶汽车时设备与你一起移动)。在第一种情况下,您正在监控相对于设备或应用程序的参考框架的运动;在第二种情况下,您正在监控相对于世界参考框架的运动。运动传感器本身通常不用于监控设备的位置,但它们可以与其他传感器(如地磁场传感器)一起使用,以确定与世界参考系相比的设备位置(见位置传感器)。
所有运动传感器返回每个运动传感器SensorEvent传感器值的多维数组。例如,在单个传感器事件中,加速度计返回三个坐标轴的加速度数据,陀螺仪返回三个坐标轴的旋转速率数据。这些数据值和其他数据值SensorEvent参数一起在float返回数组(值)。表1总结Android运动传感器可用于平台。
表1Android平台上支持的运动传感器。
传感器 | 传感器事件数据 | 描述 | 计量单位 |
---|---|---|---|
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))。 | 无单位 |
SensorEvent.values[1] |
矢量分量沿y轴旋转(γ* SIN(θ/ 2))。 | ||
SensorEvent.values[2] |
矢量成分沿z轴旋转(Z * SIN(θ/ 2))。 | ||
SensorEvent.values[3] |
旋转矢量的标量重量((COS(θ/ 2))。 | ||
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 |
Android开源工程传感器
Android开源项目(AOSP)基于软件的运动传感器有三种:重力传感器、线性加速度传感器和旋转矢量传感器。这些传感器Android 4.为了提高稳定性和性能,0更新设备的陀螺仪(除其他传感器外)。如果你想尝试这些传感器,你可以识别它们getVendor()
的方法和getVersion()
方法(供应商为谷歌;版本号为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);
概念上,该传感器根据以下公式计算加速度数据:
线性加速度=加速度 - 重力加速度
当你想获得不受重力影响的加速度数据时,通常使用此传感器。例如,你可以使用这个传感器来看看你的车有多快。线性加速度传感器总是有偏移,你需要删除。最简单的方法是在一个应用程序中构建一个校准步骤。在校准期间,你可以要求用户在表格上设置设备,然后读取所有三个轴的偏移量。然后,您可以从加速度传感器的直接读数中减去该偏移量,以获得实际的线性加速度。
传感器坐标系与加速度传感器使用的坐标系相同,测量单位(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),并且旋转矢量的方向是等于旋转轴的方向。
图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 Demos代码中。
利用显著运动传感器
该显著运动传感器触发检测每次显著运动事件,然后自行禁用。一个显著运动,可能导致用户的位置变化的议案; 例如步行,骑自行车,或坐在行驶的汽车。下面的代码演示了如何获得默认显著运动传感器的一个实例,以及如何注册一个事件监听器:
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);
使用步进计数器传感器
步进计数器传感器提供从传感器被激活时的上次重新启动以来用户采取的步骤的数量。步进计数器具有更多的延迟(最多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);
概念上,加速度传感器确定被施加到一个装置(A中的加速度ð通过测量被施加到传感器本身(F上的力)小号使用以下关系):
Ad = - ∑Fs / mass
然而,在重力的作用根据以下关系总是影响所测量的加速度:
Ad = -g - ∑F / mass
因为这个原因,当装置坐在一个表(而不是加速)时,加速计读取g的大小= 9.81米/秒2。类似地,当设备处于自由下落,并在9.81米/秒朝向接地因此迅速加快2,其加速度计读出G = 0米/秒的数量级2。因此,测量设备的实际加速度,在重力的力的贡献必须来自加速度计的数据被删除。这可以通过应用高通滤波器来实现。相反,一个低通滤波器可以用来在重力的作用隔离。下面的例子演示了如何做到这一点:
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]; }
注意:您可以使用许多不同的技术来过滤传感器数据。上面的代码示例使用一个简单的过滤器常数(阿尔法)来创建一个低通滤波器。此滤波器常数从一个时间常数(t)的,它是延迟的粗略表示该滤波器增加了传感器事件,并且传感器的事件传递率(DT)的。该代码示例使用的0.8用于演示的alpha值。如果使用这种过滤方法可能需要选择不同的alpha值。
加速度计使用标准的传感器坐标系。在实践中,这意味着,当一个设备是在其自然取向的表平放以下条件适用:
- 如果按下设备上的左侧(所以它移动到右侧)中,x加速度值是正的。
- 如果按下设备上的底部(因此它移动远离您),在y加速度值是正的。
- 如果按设备向天宇米/秒的加速度2,Z轴加速度值等于A + 9.81,对应于设备的加速度(+ A米/秒2)减去重力(-9.81米/秒2)。
- 该固定设备将具有9.81的加速度值,其对应于该装置的加速度(0米/秒2的重力减去的力,这是-9.81米/秒2)。
一般来说,加速度计,如果要监视设备的运动一个很好用的传感器。几乎每一个Android平台的手机和平板电脑有一个加速度计,它使用较少的约10倍的功率比其它运动传感器。一个缺点是,你可能必须实现低通和高通滤波器来消除引力,降低噪音。
Android SDK中提供了一个示例应用程序,展示了如何使用加速度传感器(加速度计播放)。
使用陀螺仪
陀螺仪测量在弧度/秒的旋转围绕设备的x,y和z轴的速率。下面的代码展示了如何获得默认陀螺仪的实例:
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; } }
标准陀螺仪提供没有经过任何过滤或更正噪声和漂移(偏差)的原始数据旋转。在实践中,陀螺仪的噪声和漂移将引入需要被补偿的误差。通常你确定通过监控其它传感器,如重力传感器或加速度计的漂移(偏差)和噪音。
使用未校准陀螺仪
未校正陀螺仪是类似于陀螺仪,除了不陀螺漂移补偿被施加到旋转速率。工厂校准和温度补偿仍施加到旋转的速率。未校准陀螺仪是后处理和melding方向的数据是有用的。一般情况下, 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);