如何从加速度估计角度和从三维角度估计加速度?

How to estimate angles from acceleration and acceleration from angles in 3 dimensions?

提问人:Cheloute 提问时间:7/26/2023 最后编辑:Cheloute 更新时间:7/27/2023 访问量:93

问:

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

好吧,考虑一下设备(不是 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 建议,但欢迎任何帮助,包括不可知论的解释!

java 数学 三角学 加速度计 卡尔曼滤波器

评论

0赞 Simon Goater 7/26/2023
我不明白 angleX-Z 是什么意思。你从大概是笛卡尔加速度acX-Z开始,是吗?您是否正在尝试计算球面极坐标中的加速度?
0赞 Cheloute 7/26/2023
嗨,如果不清楚,对不起。我认为这些角度/值在英语中的确切名称是偏航、滚动和俯仰。我需要的是从 3 维加速度推断出什么是偏航、滚动和俯仰,以及相反的情况。从给定的偏航、横滚和俯仰数据中推断出“可能”的加速度。加速度以 m/s^2 表示,偏航、俯仰和滚动以度表示。
0赞 Simon Goater 7/27/2023
对象在 3D 空间中有 6 个自由度,其中 3 个用于位置,3 个用于方向。以 m/s^2 为单位的加速度与位置有关。你确定你正在尝试做一些有意义的事情吗?

答:

2赞 Daniel Martin 7/27/2023 #1

首先,你希望你的角度测量什么?从您在 中的计算来看,您似乎在计算:calculateAngles

角度X
“X”加速度计测量值与地板之间的角度。(也就是说,当“x”测量值笔直向上时,你得到 90°,当“x”测量值指向地平线时,你得到 0°,当“x”测量值指向地板时,你得到 -90°)
角度Y
“Y”加速度计测量值与地板之间的角度。(也就是说,当“y”测量值笔直向上时,你会得到 90°,以此类推,与“x”相同)
角度Z
“Z”加速度计测量与直线向上之间的角度。(也就是说,当“z”测量值笔直向上时,你得到 0°,当“Z”测量值指向地平线时,你得到 90°,当“z”测量值指向地板时,你得到 180°)

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

现在,由于您在该方法中使用的函数 (),将所有三个加速度度量乘以相同的常数不起作用;因此,可以在 中省略该步骤。atan2* G;calculateAngles

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

   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};
}

请注意,尽管该函数会吐出任意三个输入角度的值,但这并不意味着任何三个角度组合实际上都是有效的;例如,您设置测量的方式仅限于介于 和 之间,我很确定可以确定或至少将其缩小到只有两种可能性。calculateAccelerationsangleY-abs(abs(angleX)-90)abs(abs(angleX)-90)angleXangleYangleZ

但是,如果您进给的角度,您应该恢复原始加速度,或者足够接近。calculateAccelerationscalculateAngles

评论

0赞 Cheloute 7/27/2023
您好,谢谢!试图澄清我在做什么......实际上,我不在乎任何绝对的“角度”值。我有 2 个不同的设备,其中 2 个不同的加速度计以不同的方式定位。如果我放设备以获得正确的结果,我需要做的是“转换”第二个设备发出的数据,就好像它的位置与第一个设备一样。如果我们将 2 个加速度计比作加黄油的面包片,第一个放在桌子上,黄油朝上,而第二个加速度计将在第一片左侧的较细的较长一侧,黄油看着第一片。
0赞 Daniel Martin 7/27/2023
啊,所以你的意思是你有三个来自位置 2 的物体的加速度计读数,并希望将它们转换为来自位置 1 的物体的三个加速度计读数,因为你有软件期望“dev 1”类型的读数,但在新版本的项目中,你只有位置 2 的东西。类似的东西?
0赞 Cheloute 7/27/2023
就是这样,是的。我想[尝试]在较新的设备上使用旧版应用程序,但我需要先调整这些数据。下一个陀螺仪数据,但那是另一回事了......第一次执行您的代码没有给我预期的结果,但这可能是由于比例因素。我需要做一些其他的尝试
0赞 Cheloute 7/27/2023
我的天啊!如果我将“缩放”更改为 1 而不是“G / Math.sqrt(acX acX + acYacY +acZ*acZ);”我得到完全相同的值!!谢谢你,所以muuuuch!!如果您同意,我会编辑您的答案以验证它,将当前的缩放值替换为 1