gpt4 book ai didi

c++ - 从欧拉角到四元数

转载 作者:行者123 更新时间:2023-11-28 01:20:22 29 4
gpt4 key购买 nike

我正在研究平面运动的模拟。现在,我使用欧拉角将“ body 框架”转换为“世界框架”并且效果很好。

enter image description here

最近我了解了四元数及其相对于旋转矩阵(万向节锁)的优势,并尝试使用模拟器中的偏航/俯仰/滚动角度来实现它。

四元数

如果我理解正确的话,四元数代表两件事。它有一个 x, y,z 组件,代表将发生旋转的轴。它还有一个 w 分量,表示围绕该轴发生的旋转量。简而言之,一个 vector 和一个 float 。四元数可以表示为 4 元素 vector :

q=[w,x,y,z]

要计算结果(完全旋转后),方程使用:

p'=qpq'

地点:

p=[0,x,y,z]-方向 vector

q=[w,x,y,z]-旋转

q'=[w,-x,-y,-z]

算法

  1. 创建四元数:

使用 wikipedia我通过围绕 3 个轴 (q) 旋转来创建四元数:

Quaterniond toQuaternion(double yaw, double pitch, double roll) // yaw (Z), pitch (Y), roll (X)
{
//Degree to radius:
yaw = yaw * M_PI / 180;
pitch = pitch * M_PI / 180;
roll = roll * M_PI / 180;


// Abbreviations for the various angular functions
double cy = cos(yaw * 0.5);
double sy = sin(yaw * 0.5);
double cp = cos(pitch * 0.5);
double sp = sin(pitch * 0.5);
double cr = cos(roll * 0.5);
double sr = sin(roll * 0.5);

Quaterniond q;
q.w = cy * cp * cr + sy * sp * sr;
q.x = cy * cp * sr - sy * sp * cr;
q.y = sy * cp * sr + cy * sp * cr;
q.z = sy * cp * cr - cy * sp * sr;
return q;
}
  1. 定义平面方向(航向) vector :

    p = [0,1,0,0]

  2. 计算 Hamilton product :

    p'=qpq'

    q'= [w, -qx, -qy, -qz]

    p' = (H(H(q, p), q')

Quaterniond HamiltonProduct(Quaterniond u, Quaterniond v)
{
Quaterniond result;

result.w = u.w*v.w - u.x*v.x - u.y*v.y - u.z*v.z;
result.x = u.w*v.x + u.x*v.w + u.y*v.z - u.z*v.y;
result.y = u.w*v.y - u.x*v.z + u.y*v.w + u.z*v.x;
result.z = u.w*v.z + u.x*v.y - u.y*v.x + u.z*v.w;

return result;

}

结果

我的结果将是一个 vector :

v=[p'x,p'y,p'z]

它工作正常但与欧拉角旋转(万向节锁定)相同。是因为我在这里也使用了欧拉角吗?如果不绕 3 个轴旋转,我真的不知道它应该如何工作。我应该分别绕每个轴旋转吗?

对于理解这个问题的任何建议和帮助,我将不胜感激。

编辑(应用程序如何工作)

<强>1。我的应用程序基于数据流,这意味着每 1 毫秒检查一次是否有新数据(平面的新方向)。

示例:

在开始时 pitch/roll/yaw = 0,在 1ms 偏航改变 10 度后,应用程序读取 pitch=0,roll=0,偏航 = 10。在接下来的 1 毫秒后,偏航再次改变 20 度。因此输入数据将如下所示:pitch=0, roll=0, yaw = 30

<强>2。创建方向四元数 - p

在开始时,我定义了我的飞机的方向(头部)在 X 轴上。所以我本地的方向是v=[1,0,0]四元数 (my p) 是p=[0,1,0,0]

Vector3 LocalDirection, GlobalDirection; //head
Quaterniond p,P,q, Q, pq; //P = p', Q=q'


LocalDirection.x = 1;
LocalDirection.y = 0;
LocalDirection.z = 0;

p.w = 0;
p.x = direction.x;
p.y = direction.y;
p.z = direction.z;

<强>3。创建旋转

在每 1 毫秒 之后,我检查来自数据流的旋转角度 (Euler),并使用 toQuaternion 计算 q

q = toQuaternion(yaw, pitch, roll); // create quaternion after rotation


Q.w = q.w;
Q.x = -q.x;
Q.y = -q.y;
Q.z = -q.z;

<强>4。计算“世界方向”

使用 Hamilton 积 我计算旋转后的四元数,这是我的全局方向:

pq = HamiltonProduct(q, p); 

P = HamiltonProduct(pq, Q);

GlobalDirection.x = P.x;
GlobalDirection.y = P.y;
GlobalDirection.z = P.z;

<强>5。每 1 毫秒

重复 3-4 次

最佳答案

您的模拟似乎每帧都使用欧拉角来旋转对象。然后将这些角度转换为四元数。这不会解决万向节锁定问题。

当您将欧拉角添加到欧拉角时,万向节锁随时可能发生。从本地空间到世界空间时,仅仅解决这个问题是不够的。您还需要您的模拟在帧之间使用四元数。

基本上每次您的对象改变其旋转时,将当前旋转转换为四元数,乘以新的旋转增量,并将结果转换回欧拉角或您用来存储旋转的任何值。

我建议重写您的应用程序以仅使用四元数。每当用户进行输入或您的游戏的某些其他逻辑想要旋转某些内容时,您会立即将该输入转换为四元数并将其输入模拟。

有了 toQuaternionHamiltonProduct,您就拥有了所需的所有工具。


EDIT 作为对您解释应用程序工作原理的编辑的回应。

At the begging pitch/roll/yaw = 0, after 1ms yaw is changed by 10 degree so application reads pitch=0, roll=0, yaw = 10. After next 1ms yaw is changed again by 20 degrees. So input data will look like this: pitch=0, roll=0, yaw = 30.

这就是万向节锁定发生的地方。在计算旋转后您转换为四元数。那是错的。您需要在这第一步中使用四元数。不要在 1ms yaw 改变 10 度后,应用程序读取 pitch=0,roll=0,yaw = 10,执行此操作:

  1. 将旋转存储为四元数,而不是欧拉角;
  2. 将 10 度偏航转弯转换为四元数;
  3. 将存储的四元数与10度偏航四元数相乘;
  4. 存储结果。

澄清一下:您的第 2、3 和 4 步没问题。问题出在第 1 步。


旁注,这是:

It has an x, y, and z component, which represents the axis about which a rotation will occur. It also has a w component, which represents the amount of rotation which will occur about this axis

不完全正确。四元数的分量不是直接的轴和角度,它们是 sin(angle/2) * axiscos(angle/2)(这是你的 toQuaternion 方法产生)。这很重要,因为它为您提供了构成 4D sphere 的漂亮单位四元数。表面上的每个点(表面空间?)代表 3D 空间中的旋转,完美地允许在任意两个旋转之间进行平滑插值。

关于c++ - 从欧拉角到四元数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56576403/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com