I am rotating n 3D shape using Euler angles in the order of XYZ meaning that the object is first rotated along the X
axis, then Y
and then Z
. I want to convert the Euler angle to Quaternion and then get the same Euler angles back from the Quaternion using some [preferably] Python code or just some pseudocode or algorithm. Below, I have some code that converts Euler angle to Quaternion and then converts the Quaternion to get Euler angles. However, this does not give me the same Euler angles.
I think the problem is I don't know how to associate yaw, pitch and roll to X, Y an Z axes. Also, I don't know how to change order of conversions in the code to correctly convert the Euler angles to Quaternion and then convert the Quaternion to Euler angle so that I am able to get the same Euler angle back. Can someone help me with this?
And here's the code I used:
This function converts Euler angles to Quaternions:
def euler_to_quaternion(yaw, pitch, roll):
qx = np.sin(roll/2) * np.cos(pitch/2) * np.cos(yaw/2) - np.cos(roll/2) * np.sin(pitch/2) * np.sin(yaw/2)
qy = np.cos(roll/2) * np.sin(pitch/2) * np.cos(yaw/2) + np.sin(roll/2) * np.cos(pitch/2) * np.sin(yaw/2)
qz = np.cos(roll/2) * np.cos(pitch/2) * np.sin(yaw/2) - np.sin(roll/2) * np.sin(pitch/2) * np.cos(yaw/2)
qw = np.cos(roll/2) * np.cos(pitch/2) * np.cos(yaw/2) + np.sin(roll/2) * np.sin(pitch/2) * np.sin(yaw/2)
return [qx, qy, qz, qw]
And this converts Quaternions to Euler angles:
def quaternion_to_euler(x, y, z, w):
import math
t0 = +2.0 * (w * x + y * z)
t1 = +1.0 - 2.0 * (x * x + y * y)
X = math.degrees(math.atan2(t0, t1))
t2 = +2.0 * (w * y - z * x)
t2 = +1.0 if t2 > +1.0 else t2
t2 = -1.0 if t2 < -1.0 else t2
Y = math.degrees(math.asin(t2))
t3 = +2.0 * (w * z + x * y)
t4 = +1.0 - 2.0 * (y * y + z * z)
Z = math.degrees(math.atan2(t3, t4))
return X, Y, Z
And I use them as follow:
import numpy as np
euler_Original = np.random.random(3) * 360).tolist() # Generate random rotation angles for XYZ within the range [0, 360)
quat = euler_to_quaternion(euler_Original[0], euler_Original[1], euler_Original[2]) # Convert to Quaternion
newEulerRot = quaternion_to_euler(quat[0], quat[1], quat[2], quat[3]) #Convert the Quaternion to Euler angles
print (euler_Original)
print (newEulerRot)
The print statements print different numbers for euler_Original
and newEulerRot
which I don't want to be the case. For example if euler_original
contains numbers like (0.2, 1.12, 2.31)
in radians I get this Quaternion --> [0.749, 0.290, -0.449, 0.389]
and converting the Quaternion to Euler angles gives me this --> (132.35, 64.17, 11.45)
which is pretty wrong. I wonder how I can fix this?
Although I'm interested in getting the above code to work by making changes to it but, I would rather learn how to set up the equations correctly. This way I would know how I can get the correct Quaternions even if the order of rotations (XYZ --> YZX etc) for applying Euler angles is changed.
We can use Rotation
from scipy.spatial.transform
.
from scipy.spatial.transform import Rotation
# Create a rotation object from Euler angles specifying axes of rotation
rot = Rotation.from_euler('xyz', [90, 45, 30], degrees=True)
# Convert to quaternions and print
rot_quat = rot.as_quat()
print(rot_quat)
The result would be:
[ 0.56098553 0.43045933 -0.09229596 0.70105738]
Then, you can also get it back in Euler angles:
print(rot.as_euler('xyz', degrees=True))
Which results in:
[90. 45. 30.]
As a final check, create a rotation object from the quaternions calculated above and get it as Euler angles:
rot = Rotation.from_quat(rot_quat)
# Convert the rotation to Euler angles given the axes of rotation
print(rot.as_euler('xyz', degrees=True))
Which results in:
[90. 45. 30.]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With