TL;DR
How come the accelerometer values I get from
Sensor.TYPE_ACCELEROMETER
are slightly offset? I don't mean by gravity, but by some small error that varies from axis to axis and phone to phone.Can I calibrate the accelerometer? Or is there a standard way of compensating for these errors?
我正在开发一个需要尽可能精确的加速度测量的应用程序(主要是垂直加速度,即与重力方向相同)。
我做了很多测试,结果发现我从
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.21
、 Y+0.21
和 Z+0.81
)然后执行旋转矩阵的东西来获得世界坐标系的加速度。请注意,因为不仅仅是计算出的垂直加速度是错误的 - 它实际上是来自 Sensor.TYPE_ACCELEROMETER
的原始值。 ,我认为不包括陀螺仪传感器等其他误差源?我已经在两款不同的手机(三星 Galaxy S5 和索尼 Xperia Z3 紧凑型)上对此进行了测试,两者都有这些加速度计值偏差——但当然两部手机上的值不一样。
Sensor.TYPE_ACCELEROMETER
的值怎么来的?关闭了,有没有更好的方法来“校准”加速度计,而不是简单地观察它们偏离重力的程度并在使用它们之前将差异添加到值上?
最佳答案
您应该校准 3 个加速度计的增益、偏移和角度。
不幸的是,这里不可能加深整个话题。
我将写一个简短的介绍,描述基本概念,然后我将发布一个实现校准的简单 Clinometer 代码的链接。
校准程序可以在您选择的不同正交位置使用 7 个错误(计算大量样本的平均值)来完成,以便获得加速度计的所有 +-0 和 +-g 值。例如:
然后您可以使用 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加速度计校准?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43364006/