# Getting the rotation angle along a single local axis from a quaternion

In short: How can I get a single angle along a local (body-fixed) axis from a quaternion?

(Click for 3D view)

In not-so-short: I am using an IMU with filtering to track the orientation of someone's upper leg. I end up with a quaternion describing the rotation from world frame to the leg frame (local frame, or body-fixed frame). But I only need a single angle from this quaternion: the swing angle (hip flexion). This is the angle around local +z (not as in the picture).

In more general terms: imagine I have an arbitrary rotation (see picture) and some local axis (the translucent blue line), how can I find the angle between the rotated frame and the original frame along this axis?

In the posted example I would expect to find about +170 degrees (sign based on right-hand rule from the selected rotation axis).

I think I found a solution. The procedure:

1. Choose a world axis perpendicular to the interesting axis (in the picture I want to know the angle around local +Z, so I now chose the X axis.
2. Express the unit vector of the chosen axis in the local frame, here: $$\hat{x}^{bf} = \mathrm{R}\hat{x}^W$$
3. Project the unit vector onto the plane perpendicular to the rotation axis, here: $$v = \begin{pmatrix}\hat{x}^{bf}_x \\ \hat{x}^{bf}_y \\ 0\end{pmatrix}$$
4. Now get the angle from this projected vector, relative to the local +x axis: $$\theta = \mathrm{atan2}(v_y, v_x)$$

You will get a singularity when the rotated axis is opposite the world axis. You can choose a unit vector on the axis where this is least likely.

Rough code example (assuming some rotation library is present):

float getLegAngle(const float quat[4]) {
float v[3] = {0.0, 0.0, -1.0}; // Get angle between vector pointing
// down and the same vector but rotated

float quat_conj[4]; // quat rotates the frame to the world
quaternionConjugate(quat, quat_conj);

rotateVectorByQuaternion(v, quat_conj);