从四元数中提取偏航

Ven*_*atu 26 math xna quaternions

我有一个旋转四元数,想要提取围绕向上轴(偏航)的旋转角度.我正在使用XNA,据我所知,没有内置功能.做这个的最好方式是什么?

感谢任何帮助,Venatu

JCo*_*per 32

旋转的四元数表示是轴和角度的变化.因此,如果围绕轴x,y,z旋转r弧度,则四元数q为:

q[0] = cos(r/2);
q[1] = sin(r/2)*x;
q[2] = sin(r/2)*y;
q[3] = sin(r/2)*z;
Run Code Online (Sandbox Code Playgroud)

如果要创建仅围绕y轴旋转的四元数,则将xz轴调零,然后重新标准化四元数:

q[1] = 0;
q[3] = 0;
double mag = sqrt(q[0]*q[0] + q[2]*q[2]);
q[0] /= mag;
q[2] /= mag;
Run Code Online (Sandbox Code Playgroud)

如果你想要得到的角度:

double ang = 2*acos(q[0]);
Run Code Online (Sandbox Code Playgroud)

这假定存储四元数表示:w,x,y,z.如果q [0]和q [2]都为零或接近它,则生成的四元数应为{1,0,0,0}.

  • @AlexanderPacha它不能完全提取音高或滚动.原因是"偏航"通常被定义为围绕世界"向上"轴的旋转.但俯仰和滚动是相对于物体的内轴定义的.当一个工艺品投球时,无论翅膀与哪个世界轴线对齐,它都围绕着自己的翅膀.由于四元数通常在世界坐标中,因此需要额外的步骤将事物转换为对象本地参考框架. (8认同)
  • NB如果你只是对ang感兴趣,那么你可以直接计算`atan(q[2],q[0])而不是计算`2*acos(q0/sqrt(q0*q0+q2*q2))` *2` 也已经标准化为 [-pi, pi]。 (2认同)

the*_*bit 25

给出四元数q,你可以像这样计算滚动,俯仰和偏航:

var yaw = atan2(2.0*(q.y*q.z + q.w*q.x), q.w*q.w - q.x*q.x - q.y*q.y + q.z*q.z);
var pitch = asin(-2.0*(q.x*q.z - q.w*q.y));
var roll = atan2(2.0*(q.x*q.y + q.w*q.z), q.w*q.w + q.x*q.x - q.y*q.y - q.z*q.z);
Run Code Online (Sandbox Code Playgroud)

这应该适合xyz阶的内在tait-bryan旋转.对于其他旋转指令,必须使用外部和适当的欧拉旋转其他转换.

  • 我只是仔细检查过,但这实际上是我的工作代码,将Quaternion-Values转换为Yaw,Pitch,Roll,以便在Maya中使用.首先尝试了普遍接受的方法,但它没有按预期工作!在投票之前你可能最好先尝试一下...... (2认同)
  • 嗯,目前它返回了一些奇怪的结果:如果我稍微偏转我的相机,只有偏航会发生变化,这正是我所期望的。如果我再推销它,返回的每个组件都会发生变化,这是出乎意料的。例如,如果我偏航和倾斜我的凸轮 0.3 弧度,我希望这将返回 0.3 为 botch 和 0 滚动,但每个组件对我来说都有一个奇怪的数字;S (2认同)
  • 有些可能会使用不同的分配顺序:滚动、偏航、俯仰 - 取决于坐标系。 (2认同)
  • 我在这里发布了我的具体问题:http://stackoverflow.com/questions/23310299/quaternion-from-tait-bryan-angles 终止“欧拉角”让我感到非常困惑,直到维基百科澄清它我正在寻找“Tait- Bryan”角度(XYZ 旋转,而不是 XYX)。 (2认同)
  • 等等,"飞机主轴"又有什么不同?我以为它是一样的.上帝......谁制定了这些条款...... (2认同)

Shi*_*hah 10

注意:我已经根据维基百科的方程Pixhawk 的文档验证了下面的代码,它是正确的。

如果您正在使用无人机/航空,以下是代码(直接取自DJI SDK)。这里 q0, q1, q2, q3 分别对应四元数的 w,x,y,z 分量。另请注意,偏航、俯仰、滚转在某些文献中可分别称为航向、姿态和坡度。

float roll  = atan2(2.0 * (q.q3 * q.q2 + q.q0 * q.q1) , 1.0 - 2.0 * (q.q1 * q.q1 + q.q2 * q.q2));
float pitch = asin(2.0 * (q.q2 * q.q0 - q.q3 * q.q1));
float yaw   = atan2(2.0 * (q.q3 * q.q0 + q.q1 * q.q2) , - 1.0 + 2.0 * (q.q0 * q.q0 + q.q1 * q.q1));
Run Code Online (Sandbox Code Playgroud)

如果您需要计算所有 3 个,那么您可以使用以下函数避免重新计算常用术语:

//Source: http://docs.ros.org/latest-lts/api/dji_sdk_lib/html/DJI__Flight_8cpp_source.html#l00152
EulerianAngle Flight::toEulerianAngle(QuaternionData data)
{
    EulerianAngle ans;

    double q2sqr = data.q2 * data.q2;
    double t0 = -2.0 * (q2sqr + data.q3 * data.q3) + 1.0;
    double t1 = +2.0 * (data.q1 * data.q2 + data.q0 * data.q3);
    double t2 = -2.0 * (data.q1 * data.q3 - data.q0 * data.q2);
    double t3 = +2.0 * (data.q2 * data.q3 + data.q0 * data.q1);
    double t4 = -2.0 * (data.q1 * data.q1 + q2sqr) + 1.0;

    t2 = t2 > 1.0 ? 1.0 : t2;
    t2 = t2 < -1.0 ? -1.0 : t2;

    ans.pitch = asin(t2);
    ans.roll = atan2(t3, t4);
    ans.yaw = atan2(t1, t0);

    return ans;
}

QuaternionData Flight::toQuaternion(EulerianAngle data)
{
    QuaternionData ans;
    double t0 = cos(data.yaw * 0.5);
    double t1 = sin(data.yaw * 0.5);
    double t2 = cos(data.roll * 0.5);
    double t3 = sin(data.roll * 0.5);
    double t4 = cos(data.pitch * 0.5);
    double t5 = sin(data.pitch * 0.5);

    ans.q0 = t2 * t4 * t0 + t3 * t5 * t1;
    ans.q1 = t3 * t4 * t0 - t2 * t5 * t1;
    ans.q2 = t2 * t5 * t0 + t3 * t4 * t1;
    ans.q3 = t2 * t4 * t1 - t3 * t5 * t0;
    return ans;
}
Run Code Online (Sandbox Code Playgroud)

关于特征库的说明

如果您使用 Eigen 库,它有另一种方法来进行这种转换,但是,这可能不像上面的直接代码那样优化:

  Vector3d euler = quaternion.toRotationMatrix().eulerAngles(2, 1, 0);
  yaw = euler[0]; pitch = euler[1]; roll = euler[2];
Run Code Online (Sandbox Code Playgroud)

  • @thewhiteambit 我写这个答案的原因是为了帮助其他人节省一些时间来编写我自己编写的代码。toEularianAngle() 确实消除了一个冗余(q2sqr),它更干净,并且远非您声称的“无耻复制”。toQuternion() 使其更加完整。 (2认同)