java - 如何根据加速度估计角度以及根据 3 维角度估计加速度?

标签 java math trigonometry accelerometer kalman-filter

我在很多论坛上看到了几个与此相关的问题,但没有一个问题能够让我足够清楚或足够精确地满足我的需求。或者我只是不理解它们,这是另一种可能性。

好吧,考虑设备(不是 Android 设备,这里不需要实时处理)采取的几个加速度计测量(3 维)(m/s^2)。我正在从文本文件中读取这些值,并且需要将它们转换为度数。

我尝试的第一个代码是:

   private static final double G = 9.81;
   private static final double RAD_TO_DEG = 180.0 / Math.PI;
    
   private double[] calculateAngles(double acX, double acY, double acZ) {
        
       double accelX = acX * G;
       double accelY = acY * G;
       double accelZ = acZ * G;

       double angleX = Math.atan2(accelX, Math.sqrt(accelY * accelY + accelZ * accelZ)) * RAD_TO_DEG;
       double angleY = Math.atan2(accelY, Math.sqrt(accelX * accelX + accelZ * accelZ)) * RAD_TO_DEG;
       double angleZ = Math.atan2(Math.sqrt(accelX * accelX + accelY * accelY), accelZ) * RAD_TO_DEG;
        
       return new double[] { angleX, angleY, angleZ };
   }

这段代码“似乎”给了我一个很好的结果。至少,可信。我将加速度计放在固定位置,注意到随机测量给出的 3 个角度(更新:我说的是偏航、俯仰和滚动),转动加速度计90°(大约),其中一个角度将其值增加了或多或少 90°。

尽管如此,我尝试的逆运算根本不起作用:

private static final double RAD_TO_DEG = 180.0 / Math.PI;
private static double[] calculateAccelerations(double angleX, double angleY, double angleZ) {

        // Convertir les angles en radians
        double radianAngleX = angleX * DEG_TO_RAD;
        double radianAngleY = angleY * DEG_TO_RAD;
        double radianAngleZ = angleZ * DEG_TO_RAD;

        double accelX = Math.tan(radianAngleX) / Math.sqrt(1.0 + Math.tan(radianAngleX) * Math.tan(radianAngleX) + Math.tan(radianAngleY) * Math.tan(radianAngleY));
        double accelY = Math.tan(radianAngleY) / Math.sqrt(1.0 + Math.tan(radianAngleX) * Math.tan(radianAngleX) + Math.tan(radianAngleY) * Math.tan(radianAngleY));
        double accelZ = Math.tan(radianAngleZ) * Math.sqrt(1.0 + Math.tan(radianAngleX) * Math.tan(radianAngleX) + Math.tan(radianAngleY) * Math.tan(radianAngleY));

        return new double[]{accelX/G, accelY/G, accelZ/G};
    }

如果我获取初始加速度计值,估计偏航、俯仰和滚动,将它们转换为加速度...怎么说...发明这些值会更准确。第一个问题是……为什么?我在这里看不到我的错误。

在谷歌上搜索替代方案,卡尔曼滤波器是我能找到的最相关的结果。我在 common-math3 (Apache) 中找到了一个实现,但我不明白它是如何工作的,也不明白它是否真的适用于此。

我需要读取这些加速度计值,并估计加速度计以不同方式定位时的这些值。为此,我需要能够“估计”加速度计的位置,添加需要添加的角度以实际改变其方向,然后返回加速度计值。

最好是 Java 建议,但欢迎任何帮助,包括不可知的解释!

最佳答案

首先,您想要测量什么角度?根据您在 calculateAngles 中的计算,您似乎正在计算的是:

angleX
“x”加速度计测量值与地板之间的角度。 (也就是说,当“x”测量垂直指向上方时,您得到 90°,当“x”测量指向地平线时,您得到 0°,当“x”测量指向地板时,您得到 -90 °)
angleY
“y”加速度计测量值与地面之间的角度。 (也就是说,当“y”测量笔直向上时,您会得到 90° 等,与“x”相同)
angleZ
“z”加速度计测量值与直线之间的角度。 (也就是说,当“z”测量垂直指向上方时,您得到 0°,当“z”测量指向地平线时,您得到 90°,当“z”测量指向地板时,您得到 180° )

鉴于您的后续评论,我将假设这些实际上是您希望测量并从那里继续的角度。

现在,由于您在该方法中使用的函数 (atan2),将所有三个加速度测量值乘以同一个常数不会产生任何效果;因此,在calculateAngles中可以省略* G;步骤。

首先,我将该函数更改为:

   private double[] calculateAngles(double acX, double acY, double acZ) {
       double angleX = Math.atan2(acX, Math.sqrt(acY * acY + acZ * acZ)) * RAD_TO_DEG;
       double angleY = Math.atan2(acY, Math.sqrt(acX * acX + acZ * acZ)) * RAD_TO_DEG;
       double angleZ = Math.atan2(Math.sqrt(acX * acX + acY * acY), acZ) * RAD_TO_DEG;
        
       return new double[] { angleX, angleY, angleZ };
   }

现在,为了反转计算,我们需要利用这样一个事实:完成后,三个加速度的平方和应等于 G 平方。另外,我们想利用这样的事实来反转

 angle = Math.atan2(y, x);

您通常不应使用 tan 函数,而应使用:

 x = Math.cos(angle);
 y = Math.sin(angle);

 // then multiple x and y by some scaling factor

所以:

private static double[] calculateAccelerations(double angleX, double angleY, double angleZ) {

    // Convertir les angles en radians
    double radianAngleX = angleX * DEG_TO_RAD;
    double radianAngleY = angleY * DEG_TO_RAD;
    double radianAngleZ = angleZ * DEG_TO_RAD;

    double acX = Math.sin(radianAngleX);
    double acY = Math.sin(radianAngleY);
    double acZ = Math.cos(radianAngleZ);

    // use this if you need the sum of the acceleration squared to be G squared
    //double scaling = G / Math.sqrt(acX*acX + acY*acY + acZ*acZ);
    // EDIT Cheloute: with scaling = 1, that works perfectly for my use case
    double scaling = 1;

    return new double[]{acX*scaling, acY*scaling, acZ*scaling};
}

请注意,尽管 calculateAccelerations 函数会返回任意三个输入角度的值,但这并不意味着任何三个角度组合实际上都是有效的;例如,根据您设置测量的方式,angleY 仅限于 -abs(abs(angleX)-90)abs( abs(angleX)-90),并且给定 angleXangleY,我很确定可以确定 angleZ 或至少将其范围缩小到只有两种可能性。

但是,如果您输入来自 calculateAnglescalculateAccelerations 角度,您应该会得到原始加速度,或者足够接近。

关于java - 如何根据加速度估计角度以及根据 3 维角度估计加速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76771227/

相关文章:

java - Spring JSON 转换器。如何绑定(bind)不同类型

java - 一次为所有客户端定义/mp-rest/url Quarkus YAML

java - 在 Spring Cloud AWS 中禁用 Cloudformation

java - 如何在不实际序列化对象的情况下估计 Java 中对象的序列化大小?

C# 完美数练习

linux - 在算术表达式中,为什么递增变量会修改原始变量而其他操作不会?

math - 使用已知距离的其他两个点找到三角形的第三个点

Java 如果一个数字是-0

equation - python 中的 sin 方程不断返回错误的答案

c - arctan(x) 函数给出错误答案