Writing Code to Convert Quaternions to Z-Y-X Euler Angles in Python
This article is a translated version of my original post on Qiita. Original (Japanese): https://qiita.com/segur/items/1772f0b842bfabab3c6e
Writing Code to Convert Quaternions to Z-Y-X Euler Angles in Python
I needed to calculate Z-Y-X Euler angles from quaternions.
Moreover, the task required me to write the code in Python 2.7, so I couldn't use handy tools like scipy.spatial.transform.Rotation.
When I did some research, I found a sample code in C++ on Wikipedia.
Wikipedia / Quaternion to Euler Angles Conversion
Writing in Python
Based on the Wikipedia sample code, I created a code in Python 2.7.
import math
import numpy as np
from pyquaternion import Quaternion
def quaternion_to_euler_zyx(q):
"""
Convert quaternion to Z-Y-X Euler angles.
Parameters
----------
q : Quaternion
Quaternion (in pyquaternion format)
Returns
-------
np.array
Z-Y-X Euler angles
"""
# roll : rotation around x-axis
sinr_cosp = 2 * (q[0] * q[1] + q[2] * q[3])
cosr_cosp = 1 - 2 * (q[1] * q[1] + q[2] * q[2])
roll = math.atan2(sinr_cosp, cosr_cosp)
# pitch : rotation around y-axis
sinp = 2 * (q[0] * q[2] - q[3] * q[1])
if math.fabs(sinp) >= 1:
pitch = math.copysign(math.pi / 2, sinp)
else:
pitch = math.asin(sinp)
# yaw : rotation around z-axis
siny_cosp = 2 * (q[0] * q[3] + q[1] * q[2])
cosy_cosp = 1 - 2 * (q[2] * q[2] + q[3] * q[3])
yaw = math.atan2(siny_cosp, cosy_cosp)
# Euler angles
return np.array([
math.degrees(roll),
math.degrees(pitch),
math.degrees(yaw)
])
Dependencies
NumPy 1.16.6
Used for vector calculations. Version 1.16.6 seems to be the latest one supporting Python 2.7.
PyQuaternion 0.9.5
PyQuaternion is used for quaternion calculations.
While numpy-quaternion might work better with NumPy, it could not be installed in the Python 2.7 environment.
Easier with SciPy in Python 3
Using scipy.spatial.transform.Rotation makes it simpler if you're using Python 3 or later.
import numpy as np
from pyquaternion import Quaternion
from scipy.spatial.transform import Rotation as R
def quaternion_to_euler_zyx(q):
r = R.from_quat([q[0], q[1], q[2], q[3]])
return r.as_euler('zyx', degrees=True)
Unfortunately, scipy.spatial.transform.Rotation does not support Python 2.7.
Conclusion
I'm mostly accustomed to dealing with Unity's Z-X-Y Euler angles, so working with Z-Y-X was quite confusing. I referred to the following articles while creating this post. Thank you for the detailed insights!