iter
iter

Reputation: 4313

SciPy rotation matrix from/as Euler angles

I'm working with Euler angles and SciPy's implementation of them. I'm having a hard time understanding how SciPy initializes rotations matrices from Eulers, or how it represents matrices as Eulers, or both. From reading the documentation, I would assume that a single call

from_euler("ZYX", (yaw, pitch, roll))

is equivalent to a multiplication of three matrices computed from one axis each, but a simple test invalidates this assumption:

from scipy.spatial.transform import Rotation as R

def r1(roll, pitch, yaw):
    r = R.from_euler("ZYX", (yaw, pitch, roll), degrees=True)
    yaw, pitch, roll = r.as_euler("ZYX", degrees=True)
    print(f"r:{roll:5.1f} p:{pitch:5.1f} y:{yaw:5.1f}")

def r2(roll, pitch, yaw):
    r = R.from_euler("ZYX", (0, 0, roll), degrees=True) * \
        R.from_euler("ZYX", (0, pitch, 0), degrees=True) * \
        R.from_euler("ZYX", (yaw, 0, 0), degrees=True)
    yaw, pitch, roll = r.as_euler("ZYX", degrees=True)
    print(f"r:{roll:5.1f} p:{pitch:5.1f} y:{yaw:5.1f}")

r1(35, 25, 115)  # as expected: "r:  35.0 p: 25.0 y: 115.0"
r2(35, 25, 115)  # surprising:  "r:   5.5 p:-41.8 y: 120.9"

I would be grateful for any pointers to documentation that can elaborate further on who SciPy does, or, alternatively, the obvious-to-everyone-else thing I'm missing about rotation matrices.

Upvotes: 0

Views: 3405

Answers (1)

PumpkinQ
PumpkinQ

Reputation: 91

Maybe try:

from scipy.spatial.transform import Rotation as R

def r1(roll, pitch, yaw):
    r = R.from_euler("ZYX", (yaw, pitch, roll), degrees=True)
    yaw, pitch, roll = r.as_euler("ZYX", degrees=True)
    print(f"r:{roll:5.1f} p:{pitch:5.1f} y:{yaw:5.1f}")

def r2(roll, pitch, yaw):
    r = R.from_euler("ZYX", (0, 0, roll), degrees=True) * \
        R.from_euler("ZYX", (0, pitch, 0), degrees=True) * \
        R.from_euler("ZYX", (yaw, 0, 0), degrees=True)
    yaw, pitch, roll = r.as_euler("ZYX", degrees=True)
    print(f"r:{roll:5.1f} p:{pitch:5.1f} y:{yaw:5.1f}")

# solution
def r3(roll, pitch, yaw):
    r = R.from_euler("ZYX", (yaw, 0, 0), degrees=True) * \
        R.from_euler("ZYX", (0, pitch, 0), degrees=True) * \
        R.from_euler("ZYX", (0, 0, roll), degrees=True)
    yaw, pitch, roll = r.as_euler("ZYX", degrees=True)
    print(f"r:{roll:5.1f} p:{pitch:5.1f} y:{yaw:5.1f}")

r1(35, 25, 115)  # as expected: "r:  35.0 p: 25.0 y: 115.0"
r2(35, 25, 115)  # surprising:  "r:   5.5 p:-41.8 y: 120.9"
r3(35, 25, 115)  # as expected: "r:  35.0 p: 25.0 y: 115.0"

Upvotes: 3

Related Questions