Android加速度计校准?

Posted

技术标签:

【中文标题】Android加速度计校准?【英文标题】:Android accelerometer calibration? 【发布时间】:2017-09-07 21:47:18 【问题描述】:

TL;DR

我从Sensor.TYPE_ACCELEROMETER 得到的加速度计值怎么会有轻微偏移?我指的不是重力,而是一些因轴和手机而异的小误差。

我可以校准加速度计吗?或者是否有补偿这些错误的标准方法?

我正在开发一款需要尽可能精确地测量加速度(主要是垂直加速度,即与重力方向相同)的应用。

我已经做了很多测试,结果我从Sensor.TYPE_ACCELEROMETER 得到的原始值是关闭的。如果我让手机放在一个完全水平的表面上,屏幕朝上,加速度计显示的 Z 值为 9.0,应该是 9.81 左右。同样,如果我将手机置于纵向或横向模式,X 和 Y 加速度计值显示大约 9.6。而不是 9.81。

这当然会影响我的垂直加速度,因为我使用SensorManager.getRotationMatrixFromVector() 来计算垂直加速度,从而导致垂直加速度根据设备的旋转而偏离不同的量。

现在,在有人开枪并提到我应该尝试使用Sensor.TYPE_LINEAR_ACCELERATION 之前,我必须指出我实际上也在这样做,与TYPE_ACCELERATION 平行。然后通过使用重力传感器计算垂直加速度(as described in this answer)。有趣的是,我得到的结果与使用原始加速度计、SensorManager.getRotationMatrixFromVector() 和矩阵乘法(最后减去重力)的方法完全相同。

我能够在任何旋转中为固定电话获得几乎完全为零的垂直加速度的唯一方法是获取原始加速度计值,添加偏移量(来自早期的观察,即X+0.21Y+0.21 和 @ 987654330@) 然后执行旋转矩阵的东西来获得世界坐标系的加速度。请注意,因为不仅仅是计算出的垂直加速度是错误的 - 它实际上是来自Sensor.TYPE_ACCELEROMETER 的原始值,我认为它不包括陀螺仪传感器等其他错误源?

我在两部不同的手机(三星 Galaxy S5 和索尼 Xperia Z3 compact)上对此进行了测试,两者都有这些加速度计值偏差 - 但当然两部手机上的值不同。

Sensor.TYPE_ACCELEROMETER 的值怎么会关闭,有没有比简单地观察它们偏离重力的程度并在使用它们之前将差异添加到值更好的“校准”加速度计的方法?

【问题讨论】:

这称为零偏移、偏移或偏差。如果设备保持静止,则平均加速度计测量值应为 (0, 0, -/+SensorManager.GRAVITY_EARTH m/s²) [取决于坐标系的用手习惯],否则,加速度计传感器有偏差。添加/减去偏移量以“纠正”偏差是要走的路:)! 【参考方案1】:

您应该校准 3 个加速度计的增益、偏移和角度。

很遗憾,这里无法深入整个主题。 我会写一个简短的介绍,描述基本概念,然后我会发布一个实现校准的简单 Clinometer 代码的链接。

校准例程可以在您选择的不同正交位置使用 7 个错误(计算大量样本的平均值)来完成,以便获得加速度计的所有 +-0 和 +-g 值。例如:

第 1 步 = 平躺 第 2 步 = 旋转 180° 第 3 步 = 左侧卧 第 4 步 = 旋转 180° 第 5 步 = 垂直放置 第 6 步 = 倒转 180° 第 7 步 = 面朝下躺下

然后您可以使用 7 个测量值mean[][] 来计算偏移和增益:

calibrationOffset[0] = (mean[0][2] + mean[0][3]) / 2;
calibrationOffset[1] = (mean[1][4] + mean[1][5]) / 2;
calibrationOffset[2] = (mean[2][0] + mean[2][6]) / 2;

calibrationGain[0] = (mean[0][2] - mean[0][3]) / (STANDARD_GRAVITY * 2);
calibrationGain[1] = (mean[1][4] - mean[1][5]) / (STANDARD_GRAVITY * 2);
calibrationGain[2] = (mean[2][0] - mean[2][6]) / (STANDARD_GRAVITY * 2);

使用mean[axis][step] 的值,其中STANDARD_GRAVITY = 9.81。 然后将增益和偏移校正应用于测量:

for (int i = 0; i < 7; i++) 
    mean[0][i] = (mean[0][i] - calibrationOffset[0]) / calibrationGain[0];
    mean[1][i] = (mean[1][i] - calibrationOffset[1]) / calibrationGain[1];
    mean[2][i] = (mean[2][i] - calibrationOffset[2]) / calibrationGain[2];

最后计算校正角度:

for (int i = 0; i < 7; i++) 
    angle[0][i] = (float) (Math.toDegrees(Math.asin(mean[0][i]
        / Math.sqrt(mean[0][i] * mean[0][i] + mean[1][i] * mean[1][i] + mean[2][i] * mean[2][i]))));
    angle[1][i] = (float) (Math.toDegrees(Math.asin(mean[1][i]
        / Math.sqrt(mean[0][i] * mean[0][i] + mean[1][i] * mean[1][i] + mean[2][i] * mean[2][i]))));
    angle[2][i] = (float) (Math.toDegrees(Math.asin(mean[2][i]
        / Math.sqrt(mean[0][i] * mean[0][i] + mean[1][i] * mean[1][i] + mean[2][i] * mean[2][i]))));


calibrationAngle[2] =  (angle[0][0] + angle[0][1])/2;       // angle 0 = X axis
calibrationAngle[1] = -(angle[1][0] + angle[1][1])/2;       // angle 1 = Y axis
calibrationAngle[0] = -(angle[1][3] - angle[1][2])/2;       // angle 2 = Z axis

您可以在此开源 Clinometer 应用程序中找到简单但完整的 3 轴校准实现:https://github.com/BasicAirData/Clinometer。 如果你想尝试的话,还有APK和Google Play Store的链接。

您可以在CalibrationActivity.java 中找到校准程序; 校准参数在ClinometerActivity.java中应用。

此外,您可以在此处找到一篇非常好的技术文章,加深了 3 轴校准:https://www.digikey.it/it/articles/using-an-accelerometer-for-inclination-sensing。

【讨论】:

以上是关于Android加速度计校准?的主要内容,如果未能解决你的问题,请参考以下文章

校准加速度计

MMA8451重力加速度计通过写内部校准寄存器进行校准

Android 加速度计精度(惯性导航)

Android 加速度计精度(惯性导航)

如何进行 MPU6050 加速度计温度校准?

在 Arduino 中校准 Adafruit LSM303