从欧拉ZXZ旋转转换为固定轴XYZ旋转

6
我遇到的问题是,需要将XYZ固定轴旋转转换为绕Z、X'和Z''的欧拉旋转。
以下是相关矩阵:
X: X Y: Y Z: Z 将它们组合在一起,即Rz(psi) Ry(phi) Rx(theta) = Rxyz(theta,phi,psi),则得到:
Rxyz: Rxyz 我想要的特定欧拉角的旋转矩阵为:
Euler: Euler 所以我的最初计划是比较矩阵元素,并从中提取所需的角度。我制定了下面这个计划: Code 但是在某些情况下,这种方法行不通。最明显的情况是当Cos(theta)Cos(phi)=1时;因为此时Cos(beta)=1,所以Sin[beta]=0。其中Sin(beta)代表代码中的s2。这种情况只会在Cos(theta)和cos(phi)=+/-1时出现。
因此,我可以很快排除可能的情况;当theta或phi=0、180、360、540等时,Cos(theta)和Cos(phi)为+/-1。所以我只需要针对这些情况进行不同的处理。
最终,我得到了以下代码:
public static double[] ZXZtoEuler(double θ, double φ, double ψ){

    θ *= Math.PI/180.0;
    φ *= Math.PI/180.0;
    ψ *= Math.PI/180.0;

    double α = -1;
    double β = -1;
    double γ = -1;

    double c2 = Math.cos(θ) * Math.cos(φ);

    β = Math.acos(r(c2));

    if(eq(c2,1) || eq(c2,-1)){
        if(eq(Math.cos(θ),1)){
            if(eq(Math.cos(φ),1)){
                α = 0.0;
                γ = ψ;
            }else if(eq(Math.cos(φ),-1)){
                α = 0.0;
                γ = Math.PI - ψ;
            }
        }else if(eq(Math.cos(θ),-1)){
            if(eq(Math.cos(φ),1)){
                α = 0.0;
                γ = -ψ;
            }else if(eq(Math.cos(φ),-1)){
                α = 0.0;
                γ = ψ + Math.PI;
            }
        }
    }else{

        //original way

        double s2 = Math.sin(β);

        double c3 = ( Math.sin(θ) * Math.cos(φ) )/ s2;
        double s1 = ( Math.sin(θ) * Math.sin(ψ) + Math.cos(θ) * Math.sin(φ) * Math.cos(ψ) )/s2;

        γ = Math.acos(r(c3));
        α = Math.asin(r(s1));

    }

    α *= 180/Math.PI;
    β *= 180/Math.PI;
    γ *= 180/Math.PI;

    return new double[] {r(α), r(β), r(γ)};
}

r和eq只是两个简单的函数;

public static double r(double a){
    double prec = 1000000000.0;
    return Math.round(a*prec)/prec;
}

static double thresh = 1E-4;
public static boolean eq(double a, double b){
    return (Math.abs(a-b) < thresh);
}

eq 是用来测试比较数字的,r 是为了防止浮点误差将数字推出 Math.acos / Math.asin 的范围而导致 NaN 结果;

也就是说,每隔一段时间,我会得到类似 Math.acos(1.000000000000000004) 等结果。

它考虑了绕 x 和 y 旋转导致 c2==1 的四种情况。

但现在问题出现了:

我上面所做的一切对我来说是有意义的,但它并没有给出正确的角度;

以下是一些输出,每对中,第一个是 theta phi psi 角度,第二个是相应的 alpha beta gamma 线。忽略舍入误差,某些角度似乎偏差大约

[0.0, 0.0, 0.0] - correct!
[0.0, 0.0, 0.0]

[0.0, 0.0, 45.0] - correct!
[0.0, 0.0, 45.0]

[0.0, 0.0, 90.0] - correct!
[0.0, 0.0, 90.0]

[0.0, 0.0, 135.0] - correct!
[0.0, 0.0, 135.0]

[0.0, 0.0, 180.0] - correct
[0.0, 0.0, 180.0]

[0.0, 0.0, 225.0] - correct
[0.0, 0.0, 225.0]

[0.0, 0.0, 270.0] - correct
[0.0, 0.0, 270.0]

[0.0, 0.0, 315.0] - correct
[0.0, 0.0, 315.0]

[0.0, 45.0, 0.0] - incorrect: should be [90, 45, -90]
[90.0, 44.999982, 90.0]

[0.0, 45.0, 45.0]
[45.000018, 44.999982, 90.0]

[0.0, 45.0, 90.0]
[0.0, 44.999982, 90.0]

[0.0, 45.0, 135.0]
[-45.000018, 44.999982, 90.0]

[0.0, 45.0, 180.0]
[-90.0, 44.999982, 90.0]

[0.0, 45.0, 225.0]
[-45.000018, 44.999982, 90.0]

[0.0, 45.0, 270.0]
[0.0, 44.999982, 90.0]

[0.0, 45.0, 315.0]
[45.000018, 44.999982, 90.0]

[0.0, 90.0, 0.0]
[90.0, 90.0, 90.0]

[0.0, 90.0, 45.0]
[45.000018, 90.0, 90.0]

[0.0, 90.0, 90.0]
[0.0, 90.0, 90.0]

[0.0, 90.0, 135.0]
[-45.000018, 90.0, 90.0]

[0.0, 90.0, 180.0]
[-90.0, 90.0, 90.0]

[0.0, 90.0, 225.0]
[-45.000018, 90.0, 90.0]

我认为问题出在Math.acos和Math.asin的工作方式上,有人能想到解决办法吗?
编辑:Math.asin和Math.acos返回- pi / 2到pi / 2和0到pi之间的值。这是不含糊的,所以我认为问题不在这里。似乎我在数学方面可能有些错误,但我看不出我的推理中哪里有漏洞...
编辑2:对于任何不知道欧拉旋转如何工作的人,它是这样的:
即,围绕Z旋转,然后围绕新的X轴(X')旋转,最后围绕新的Z''轴旋转。

欧拉角在90度时存在歧义 - 如果我正确理解你的轴,我认为0/45/0等同于90/45/-90。 - Drew Hall
欧拉角绕Z轴、X'轴和Z''轴旋转,因此0/45/0表示绕X轴旋转45度,而90/45/-90则旋转坐标轴,使得X'轴与Y轴相同。90/45/-90是绕Y轴旋转45度的结果。 - will
1个回答

1

我尚未完全弄清楚这个问题,但有一件事我注意到了:你在使用反余弦/反正弦函数时,好像把余弦/正弦函数当作是双射函数,只需要取它们的反函数。然而,在取反余弦时,要考虑到弧函数的通解。例如,当 cos y = x 时,会有两个(实际上是无限多个)解:

  • y = arccos x + 2kPI,其中 k 属于 Z
  • y = 2PI - arccos x + 2kPI,k 如上所述

k=-1 时,最后一个等式变为

  • y = -arccos x

所以总的来说,y = +- arccos x。这本质上归结为 cos 关于 x=0 轴对称。类似的论证也适用于 arcsin,导致 y = PI - asin x(在 sin y = x 的一般解中,k=0

这立即适用于您的代码。语句 γ = Math.acos(r(c3)); 必须以某种方式考虑符号。我对此有困难,必须有一个标准来排除“不正确”的解决方案。


我也注意到了这一点,每次使用acos/asin时都需要筛选出不正确的答案,这似乎是一个艰巨的任务 - 我想象中需要在4个可能的答案上运行一个小测试套件来解决+/-歧义所带来的问题,然后选择有效的答案。每次都运行测试套件会破坏解决方案的简洁性,这也不是我太喜欢的。 - will
我也在这里提出了问题,http://math.stackexchange.com/questions/122162/convert-from-fixed-axis-xyz-rotations-to-euler-zxz-rotations并决定使用ZXZ旋转而不是欧拉的Z''X'Z。但仍然不是理想的解决方案。 - will
所以我最终阅读了所有这些不好的东西。找到了如何做到这一点,并在此处回答:http://math.stackexchange.com/a/637534/27211。 - will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接