Tuomas Siipola Articles Projects

Converting rotation matrices to angles

Rotation matrices are great for carrying out calculations, but in many situations, working with angles is more convenient. Constructing rotation matrices from angles is straightforward because that's how they're defined but getting back the angles can be tricky. In this article, we're taking a look how to convert an arbitrary rotation matrix to angles.

In two dimensions

Let's start in two dimensions with the following rotation matrix:

\[ R = \begin{bmatrix} r_{11} & r_{12} \\ r_{21} & r_{22} \end{bmatrix} \]

Looking at the definition of counterclockwise rotation matrix, we know that there's some angle \(\theta\) we need to find:

\[ R = \begin{bmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{bmatrix} \]

In order to solve the unknown angle, it can be helpful to understand what the rotation matrix represents. Columns of the rotation matrix are vectors \((r_{11},r_{21})\) and \((r_{12},r_{22})\) which are the basis vectors \((1,0)\) and \((0,1)\) rotated by angle \(\theta\):

Based on the picture, we can find \(\theta\) using some trigonometry:

\[\tan\theta = \frac{r_{21}}{r_{11}}\] \[\theta = \arctan\left(\frac{r_{21}}{r_{11}}\right)\]

However, this will only work when \(-90\degree < \theta < 90\degree\). Instead of \(\arctan\), we can use arctan2 which works in the full range \(-180\degree < \theta \leq 180\degree\):

\[\theta = \text{arctan2}(r_{21}, r_{11})\]

Most programming languages should have arctan2 or atan2 function in their standard library.

In three dimensions

Next, let's move up to the three dimensions with the following rotation matrix:

\[ R = \begin{bmatrix} r_{11} & r_{12} & r_{13}\\ r_{21} & r_{22} & r_{23} \\ r_{31} & r_{32} & r_{33} \end{bmatrix} \]

In three dimensions, rotation is commonly represented as Euler angles \(\psi\), \(\theta\) and \(\phi\) which describe the rotation of x, y and z axis respectively. In other words, the rotation consists of two-dimensional rotations around different axes:

\[ R_x = \small\begin{bmatrix} 1 & 0 & 0\\ 0 & \cos\psi & -\sin\psi \\ 0 & \sin\psi & \cos\psi \end{bmatrix} \enspace R_y = \small\begin{bmatrix} \cos\theta & 0 & \sin\theta \\ 0 & 1 & 0 \\ -\sin\theta & 0 & \cos\theta \end{bmatrix} \enspace R_z = \small\begin{bmatrix} \cos\phi & -\sin\phi & 0 \\ \sin\phi & \cos\phi & 0 \\ 0 & 0 & 1 \end{bmatrix} \]

The order in which the rotations are applied matters. We're going to use the natural order \(R_x\), \(R_y\) and \(R_z\) which can be combined into a single rotation matrix:

\[ \begin{aligned} R &= R_zR_yR_x \\ &= \small\begin{bmatrix} \cos\theta\cos\phi & \sin\psi\sin\theta\cos\phi-\cos\psi\sin\phi & \cos\psi\sin\theta\cos\phi+\sin\psi\sin\phi \\ \cos\theta\sin\phi & \sin\psi\sin\theta\sin\phi+\cos\psi\cos\phi & \cos\psi\sin\theta\sin\phi-\sin\psi\cos\phi \\ -\sin\theta & \sin\psi\cos\theta & \cos\psi\cos\theta \end{bmatrix} \end{aligned} \]

Solving the unknown angles is more complicated than in the two-dimensional case. Luckily, Slabaugh (n.d.) has published the following solution which takes into account different edge cases:

\[ \begin{aligned} & \textbf{if } r_{31} \neq \pm 1 \textbf{ then}\\ & \quad\theta_1 \gets -\arcsin(r_{31})\\ & \quad\theta_2 \gets \pi - \theta_1\\ & \quad\psi_1 \gets \text{arctan2}\small\left(\frac{r_{32}}{\cos\theta_1},\frac{r_{33}}{\cos\theta_1}\right)\\ & \quad\psi_2 \gets \text{arctan2}\small\left(\frac{r_{32}}{\cos\theta_2},\frac{r_{33}}{\cos\theta_2}\right)\\ & \quad\phi_1 \gets \text{arctan2}\small\left(\frac{r_{21}}{\cos\theta_1},\frac{r_{11}}{\cos\theta_1}\right)\\ & \quad\phi_2 \gets \text{arctan2}\small\left(\frac{r_{21}}{\cos\theta_2},\frac{r_{11}}{\cos\theta_2}\right)\\ & \textbf{else}\\ & \quad\phi \gets \text{any angle e.g. 0}\\ & \quad\textbf{if } r_{31} = -1 \textbf{ then}\\ & \quad\quad\theta \gets \pi/2\\ & \quad\quad\psi \gets \phi + \text{arctan2}(r_{12},r_{13})\\ & \quad\textbf{else}\\ & \quad\quad\theta \gets -\pi/2\\ & \quad\quad\psi \gets -\phi + \text{arctan2}(-r_{12},-r_{13})\\ & \quad\textbf{end if}\\ & \textbf{end if} \end{aligned} \]

In the general case, there two solutions \(\psi_1\), \(\theta_1\), \(\phi_1\) and \(\psi_2\), \(\theta_2\), \(\phi_2\) which result in the same rotation. Here's an animation to illustrate the two solutions for rotating an object 180 degrees around the z axis:

However, when \(\theta = \pm90\degree\) there are an infinite number of solutions. This phenomenon is known as gimbal lock. For example, we get the same rotation when \(\theta=-90\degree\) and \(\psi=\phi=\alpha\) where \(\alpha\) can be any angle: