Quaternion to Euler angles

linear algebrarotationsvectors

I want to be able to convert between euler and quaternions. I've tried many different approaches, but none enables me to convert from euler to quaternion and back. The most promising formula was presented here: How to convert Euler angles to Quaternions and get the same Euler angles back from Quaternions?.

However it still doesn't give me full solution to my problem. It works when converting from euler to quaternion and from the same quaternion back to euler, but when I create a quaternion from axis angle using this equation:

qx = ax * sin(angle/2)
qy = ay * sin(angle/2)
qz = az * sin(angle/2)
qw = cos(angle/2)

and convert it to euler angles I get completly wrong results.

Assume that I have 3 vectors: $a, b$ and $r$
$a = [1, 2, 3]$
$r = [\pi/2, \pi/4, \pi/2]$
$b = a$ rotated by $r = [3.0, 2.12, 0.7]$

I calculate axis of the rotation using cross product of $a$ and $b$
Now I calculate angle between vectors using dot product
I calculate quaternion from axis and angle using formula above
$$q = [0.91, -0.19, 0.32, -0.15]$$
When I convert q to euler angles using code from link above I get
$$[-28.42, 32.25, -32.29]$$
Rotating my vector $[1, 2, 3]$ with those angles does not give the same result as rotating it with r, so the conversion is not working properly.
However rotating $[1, 2, 3]$ with quaternion $q$ gives me the same result rotating it with angles $q$, so the conversion must be wrong.

On the other hand, converting $r$ to quaternion and back using code from the link does give me correct angles, so where is the problem with those formulas?
I want to be able to calculate $q$ and $r$ knowing only $a$ and $b$.

Best Answer

I think the most we can be expected to do here at math.se is to determine what, in fact, the correct quaternion for the Euler angle representation is supposed to be. If there is some flaw in the code you'll have to take that question to a programming stackexchange.

But as for the mathematical part of this task:

I interpreted $r = [pi/2, pi/4, pi/2]$ as "rotate by $\pi/2$ on the x axis, then by $\pi/4$ on the $y$ axis, then by $\pi/2$ on the $z$ axis."

Using the theory involved in converting axis-angle to quaternions, one can convert those three easily as $\cos(\theta/2)+\sin(\theta/2)u$ where $u$ is the unit vector pointing along the axis of rotation.

I used the numpy-quaternion library in python to check that these were correct:

>>> x
quaternion(0.707106781186548, 0.707106781186547, 0, 0)
>>> y
quaternion(0.923879532511287, 0, 0.38268343236509, 0)
>>> z
quaternion(0.707106781186548, 0, 0, 0.707106781186547)
>>> q=z*y*x
>>> q*a*q.inverse()
quaternion(-4.44089209850063e-16, 3, 2.12132034355964, 0.707106781186548)

Since that latter part (-4.44089209850063e-16, 3, 2.12132034355964, 0.707106781186548) matches what you reported, I surmise I'm on the right track. (Really it should be $(0, 3,3/\sqrt{2},\sqrt{2}/2)$)

But

>>> q
quaternion(0.653281482438188, 0.270598050073099, 0.653281482438188, 0.270598050073098)

does not match your prediction of what the quaternion ought to be. The angle there in the w position is a dead giveaway that something isn't right. Given that you're working with the wrong quaternion, you would naturally not get back your correct Euler representation when applying the conversion code.

I'll leave it to you to work out the bug with however you're finding the quaternion, and you can also check to see if this quaternion I'm giving you does successfully convert back using your library.

The library does have an implementation of as_euler_angles and from_euler_angles but I believe it uses the z-y-z convention, so it will not help us if you are using the x-y-z convention.


How would you calculate q knowing only vectors a and b?

There are a couple ways to do that! Neither will be with Euler angles, that's for sure!

I would like to also emphasize here that there is not a unique quaternion rotating $a$ onto $b$. After finding any single quaternion that does so, you can tack on any rotation around the axis determined by $b$, and you get another solution.

Here's a way close to what you were trying, I think, which leverages the fact that quaternion multiplication computes the dot and cross products for you:

  1. Normalize $a$ and $b$.
  2. Represent $a$ and $b$ as quaternions with zero real part.
  3. Compute $ab=\alpha +\beta u$ where $\alpha,\beta$ are real and $u$ is a unit length quaternion with zero real part.
  4. It's known that $\alpha=-\cos(\theta)$ and $\beta=\sin(\theta)$ where $\theta$ is the angle between $a$ and $b$, and $u$ is the unit normal.
  5. Use half-angle identities to write $\cos(\theta/2)+\sin(\theta/2)u$

A second way, which is more in the program of working with quaternions, is to anticipate needing $\theta/2$, and observe that (after normalizing $a$ and $b$!) the angle between $a$ and $a+b$ is half the angle between $a$ and $b$. Explicitly:

  1. Normalize $a$ and $b$.
  2. Compute $a+b$ and normalize it. That's your quaternion rotation.

I will illustrate Method #2 since it is simpler:

>>> q2 = (a.normalized()+b.normalized()).normalized()
>>> q2
quaternion(-6.49653805396711e-17, 0.58515612718089, 0.602903962777294, 0.542309061781284)
>>> q2*a*q2.inverse()
quaternion(-1.11022302462516e-16, 3, 2.12132034355964, 0.707106781186548)

Observe that this second quaternion is substantially different from the first one we computed, with a different axis and angle.


Epilogue

Whoever wrote the documentation for numpy-quaternion is my kind of person:

Help on function as_euler_angles in module quaternion:

as_euler_angles(q)
    Open Pandora's Box

    If somebody is trying to make you use Euler angles, tell them no, and
    walk away, and go and tell your mum.

    You don't want to use Euler angles.  They are awful.  Stay away.  It's
    one thing to convert from Euler angles to quaternions; at least you're
    moving in the right direction.  But to go the other way?!  It's just not
    right.

[...]
 NOTE: Before opening an issue reporting something "wrong" with this
    function, be sure to read all of the following page, *especially* the
    very last section about opening issues or pull requests.
    <https://github.com/moble/quaternion/wiki/Euler-angles-are-horrible>
[...]

    Raises
    ------
    AllHell
        ...if you try to actually use Euler angles, when you could have
        been using quaternions like a sensible person.
(END)