2

I am trying to understand quaternion rotations and have written these two code snippets to rotate a unit vector along the X-axis to the Y-axis.

// Approach 1
Eigen::Vector3f a(1,0,0), b(0,1,0);
Eigen::Quaternionf qr;
qr.setFromTwoVectors(a,b);

// Approach 2
Eigen::Quaternionf q1(0,1,0,0), q2(0,0,1,0), qr_alt;

qr_alt = q1.inverse() * q2;    // q2 = q1 * delta_q (delta_q = rotation quaternion)

However, these two quaternions are not the same. When converted to Euler angles, qr_alt results in pi radians in yaw while qr correctly results in pi/2 radians in yaw.

What is the correct way to calculate the rotation angle between two quaternions?

  • 1
    The x, y, z parts of a quaternion contain the axis of rotation (multiplied by the sine of the half-angle), not the starting or ending vectors to be rotated. Thus your Approach 2 is invalid for what you are attempting to do. Use Approach 1. If you wanted to construct qr manually, you would need to find the axis of rotation (using cross product of a and b) and angle of rotation (using dot product of a and b) and then piece things together into the appropriate components. – James Tursa Jul 07 '22 at 16:52
  • Your first approach finds a quaternion which rotates vector `a` to vector `b`, i.e. `qr * a == b` (ignoring the lengths of `a` and `b`). The second approach finds the rotation between to quaternions, i.e. `q1 * qr_alt == q2`. – chtz Jul 07 '22 at 18:43
  • 1
    @chtz qr * a is not how you use a quaternion to rotate a vector. The correct form is either qr * a * inv(qr) == b or inv(qr) * a * qr == b depending on the quaternion convention of qr. I'm not familiar with Eigen to know which of these forms matches the quaternion convention in Eigen, but it will be one of them and not qr * a. (Note: using the vector part of the quaternion multiply result when comparing to a vector) – James Tursa Jul 07 '22 at 19:53
  • @JamesTursa, thanks for your answer. I understood that my construction of the quaternions from the two vectors was incorrect. A supplementary query that I have is how do we find a quaternion `qr` that rotates a quaternion `q1` to take it to `q2`? For vectors it is clear as you mentioned: `b = q * a * inv(qr)`. Btw, with respect to Eigen, `b = qr * a` is actually an overloaded operator which implements the actual mathematical equation. – Simit Pradhan Jul 08 '22 at 04:46
  • @JamesTursa Eigen overloads `Quaternion * Vector3` to do a rotation (something equivalent to `(q * [a; 0] * q.inverse()).vec()`, assuming `q` is a unit quaternion). – chtz Jul 08 '22 at 06:40
  • @chtz Aha! Your comment makes sense to me now. Not being an Eigen user, I didn't know that operation was overloaded. As an aside, it seems a poor choice to me to overload the * operator since there are other quaternion * vector operations that one would not want overloaded such as a quaternion derivative 0.5 * q * w, where w is a body rate vector. IMO it would have been better to overload a different operator such as < or > that didn't have any other use. Nevertheless, it is what it is I guess. – James Tursa Jul 08 '22 at 15:51
  • @JamesTursa Yes, `Eigen::Quaternion` is basically `SO3_represented_by_a_unit_quaternion` (e.g., it does not even allow standard quaternion addition and some operations can behave very wrong for non-unit quaternions). – chtz Jul 08 '22 at 17:10

0 Answers0