In today’s post, I explain the use of quaternions for rotations.

Background

What’s a quaternion?

A quaternion is a 4-element vector, typically represented as [w,i,j,k]\begin{bmatrix} w, i, j, k \end{bmatrix}. (ww can go on either the start or the end of the vector.)

In our very limited context, a quaternion can be used to represent a vector, and a rotation about that vector.

Diagram of a quaternion, showing the i, j, and k components along with a rotation

With this system, we can represent any rotation.

Why not Euler angles?

Euler angles (roll, pitch, and yaw) have three issues I care about:

  • Gimbal lock - when applying rotations, if two axes become aligned, they’re the same axis now and a degree of rotation freedom is lost permanently :(
  • Interpolation troubles - because each axis interpolates by itself, the most direct path isn’t always taken. This matters a LOT for control systems.
  • Poorly documented conventions - Since it matters in what order you apply each Euler angle (roll, pitch, yaw), it’s necessary to define and stick to a convention. There is no universal convention, which opens up the possibility of misinterpretation.

Quaternions solve all of these troubles, while being mathematically beautiful.

How do I make one?

A detailed analysis of quaternion math is both beyond the scope of this article and my knowledge. Therefore, I will stick to practicals.

To represent a rotation of θ\theta about a unit vector [ux,uy,uz]\begin{bmatrix} u_x, u_y, u_z \end{bmatrix}, use the half-angle theorem:

q=[cos⁡θ2uxsin⁡θ2uysin⁡θ2uzsin⁡θ2]q=\begin{bmatrix} \cos\frac{\theta}{2} & u_x\sin\frac{\theta}{2} & u_y\sin\frac{\theta}{2} & u_z\sin\frac{\theta}{2} \end{bmatrix}

which can also be represented as:

q=cos⁡θ2+uxsin⁡θ2i^+uysin⁡θ2j^+uzsin⁡θ2k^q = \cos\frac{\theta}{2} + u_x\sin\frac{\theta}{2}\hat{i} + u_y\sin\frac{\theta}{2}\hat{j} + u_z\sin\frac{\theta}{2}\hat{k}

which will be important very shortly.

How do I rotate a vector using a quaternion?

You need a base vector, vv, and a rotation to apply, qq. The rotated quaternion, v′v', is defined as follows:

v′=qvq∗v' = qvq^*

(q∗q^* is the conjugate of qq, which just means that the imaginary components i,j,ki, j, k of qq have their signs flipped. This conjugate multiplication also ensures we end up with a rotated Cartesian vector, and not another quaternion!)

This begs a VERY important question:

How do I multiply two quaternions together?!

It’s easy to see how to add quaternions together (you do it piecewise, like ordinary vectors), but surely piecewise multiplication will leave a horrifying mess of ijijs, wkwks, et cetera. This is where Sir William Rowan Hamilton innovated when he invented quaternions, and quaternion multiplication is aptly done via the “Hamilton product”:

Multiply the quaternions piecewise, and then simplify using the following brilliant identities:

i2=j2=k2=1i^2=j^2=k^2=1 ij=k,ji=−kij=k, ji=-k jk=i,kj=−ijk=i, kj=-i ki=j,ik=−jki=j, ik=-j

The result is your new rotated quaternion!

Rotation Example

Say that we wanted to rotate a vector v=[100]v=\begin{bmatrix} 1 & 0 & 0 \end{bmatrix} by 90 degrees around the yy axis [010]\begin{bmatrix} 0 & 1 & 0 \end{bmatrix} (as in this Stack Exchange post):

What we’re solving for is v′=qvq∗v' = qvq^*, so we need to find qq and q∗q^* and then conduct a couple Hamilton products.

Our desired rotation quaternion is defined with half angles:

q=cos⁡90∘2+0i^+sin⁡90∘2j^+0k^q = \cos\frac{90^\circ}{2} + 0\hat{i} + \sin\frac{90^\circ}{2}\hat{j} + 0\hat{k} q=0.707+0.707j^q = 0.707+0.707\hat{j}

We’ll need the conjugate later, which is just qq with its imaginary parts negated:

q∗=0.707−0.707j^q^* = 0.707-0.707\hat{j}

The first Hamilton product we’ll carry out is qvqv, as follows:

(0.707+0.707j^)(1i^)(0.707+0.707\hat{j})(1\hat{i}) 0.707i^+0.707j^i^0.707\hat{i}+0.707\hat{j}\hat{i}

which, using the identities above, simplifies to:

0.707i^−0.707k^0.707\hat{i}-0.707\hat{k}

Now we can solve for v′v' by multiplying by q∗q^*:

v′=(0.707i^−0.707k^)(0.707−0.707j^)v'=(0.707\hat{i}-0.707\hat{k})(0.707-0.707\hat{j}) v′=(0.707i^)(0.707)−(0.707i^)(0.707j^)−(0.707k^)(0.707)+(0.707k^)(0.707j^)v'= (0.707\hat{i})(0.707) - (0.707\hat{i})(0.707\hat{j}) - (0.707\hat{k})(0.707) + (0.707\hat{k})(0.707\hat{j}) v′=0.5i^−0.5i^j^−0.5k^+0.5k^j^v'= 0.5\hat{i} - 0.5\hat{i}\hat{j} - 0.5\hat{k} + 0.5\hat{k}\hat{j}

Simplifying once again using the quaternion identities:

v′=0.5i^−0.5k^−0.5k^−0.5i^v'= 0.5\hat{i} - 0.5\hat{k} - 0.5\hat{k} - 0.5\hat{i} v′=−k^=[00−1]v'= -\hat{k} = \begin{bmatrix}0 & 0 & -1\end{bmatrix}

This matches up perfectly with what we expect: the xx axis rotated by 90 degrees around the yy axis is equal to the negative zz axis.

Thanks for reading!