Android 加速度计校准?

Mag*_*s W 6 android accelerometer gyroscope android-sensors sensors

长话短说

为什么我得到的加速度计值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. 然后,通过使用重力传感器,我计算垂直加速度(如本答案中所述)。有趣的是,我得到的结果与使用原始加速度计SensorManager.getRotationMatrixFromVector()和矩阵乘法(最后减去重力)的方法完全相同。

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

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

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

Gra*_*ano 2

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

\n

不幸的是,不可能在这里加深整个主题。
\n我将写一个简短的介绍,描述基本概念,然后我将发布一个实现校准的简单测角仪代码的链接。

\n

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

\n
    \n
  • 步骤 1 = 平放
  • \n
  • 步骤 2 = 旋转 180\xc2\xb0
  • \n
  • 步骤 3 = 左侧躺
  • \n
  • 步骤 4 = 旋转 180\xc2\xb0
  • \n
  • 第 5 步 = 垂直放置
  • \n
  • 步骤 6 = 上下颠倒旋转 180\xc2\xb0
  • \n
  • 第 7 步 = 面朝下躺下
  • \n
\n

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

\n
calibrationOffset[0] = (mean[0][2] + mean[0][3]) / 2;\ncalibrationOffset[1] = (mean[1][4] + mean[1][5]) / 2;\ncalibrationOffset[2] = (mean[2][0] + mean[2][6]) / 2;\n\ncalibrationGain[0] = (mean[0][2] - mean[0][3]) / (STANDARD_GRAVITY * 2);\ncalibrationGain[1] = (mean[1][4] - mean[1][5]) / (STANDARD_GRAVITY * 2);\ncalibrationGain[2] = (mean[2][0] - mean[2][6]) / (STANDARD_GRAVITY * 2);\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
for (int i = 0; i < 7; i++) {\n    mean[0][i] = (mean[0][i] - calibrationOffset[0]) / calibrationGain[0];\n    mean[1][i] = (mean[1][i] - calibrationOffset[1]) / calibrationGain[1];\n    mean[2][i] = (mean[2][i] - calibrationOffset[2]) / calibrationGain[2];\n}\n
Run Code Online (Sandbox Code Playgroud)\n

最后计算校正角度:

\n
for (int i = 0; i < 7; i++) {\n    angle[0][i] = (float) (Math.toDegrees(Math.asin(mean[0][i]\n        / Math.sqrt(mean[0][i] * mean[0][i] + mean[1][i] * mean[1][i] + mean[2][i] * mean[2][i]))));\n    angle[1][i] = (float) (Math.toDegrees(Math.asin(mean[1][i]\n        / Math.sqrt(mean[0][i] * mean[0][i] + mean[1][i] * mean[1][i] + mean[2][i] * mean[2][i]))));\n    angle[2][i] = (float) (Math.toDegrees(Math.asin(mean[2][i]\n        / Math.sqrt(mean[0][i] * mean[0][i] + mean[1][i] * mean[1][i] + mean[2][i] * mean[2][i]))));\n}\n\ncalibrationAngle[2] =  (angle[0][0] + angle[0][1])/2;       // angle 0 = X axis\ncalibrationAngle[1] = -(angle[1][0] + angle[1][1])/2;       // angle 1 = Y axis\ncalibrationAngle[0] = -(angle[1][3] - angle[1][2])/2;       // angle 2 = Z axis\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
    \n
  • 您可以在中找到校准例程CalibrationActivity.java
  • \n
  • 校准参数应用于ClinometerActivity.java
  • \n
\n

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

\n