Skip to content

Module pyastrobee.utils.poses

Class/functions for managing poses and conversions between different representations

Our default representation of a pose will be position (xyz) + quaternion (xyzw)

View Source
"""Class/functions for managing poses and conversions between different representations

Our default representation of a pose will be position (xyz) + quaternion (xyzw)

"""

import numpy as np

import numpy.typing as npt

import pytransform3d.trajectories as pt

from pyastrobee.utils import rotations as rts

from pyastrobee.utils import transformations as tfs

from pyastrobee.utils import quaternions as qts

def check_pos_euler_xyz(pose: npt.ArrayLike) -> bool:

    """Checks to see if a position + Euler XYZ pose is valid

    Args:

        pose (npt.ArrayLike): Position + Euler XYZ pose, shape = (6,)

    Returns:

        bool: Whether or not the pose is valid

    """

    return len(pose) == 6

def check_pos_quat(pose: npt.ArrayLike) -> bool:

    """Checks to see if a position + XYZW quaternion pose is valid

    Args:

        pose (npt.ArrayLike): Position + XYZW quaternion pose

    Returns:

        bool: Whether or not the pose is valid

    """

    return len(pose) == 7

def pos_euler_xyz_to_tmat(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + Euler pose to a transformation matrix

    Args:

        pose (npt.ArrayLike): Position + Euler XYZ pose, shape = (6,)

    Returns:

        np.ndarray: Transformation matrix, shape (4,4)

    """

    if not check_pos_euler_xyz(pose):

        raise ValueError(f"Invalid position + euler pose.\nGot: {pose}")

    pos = pose[:3]

    orn = pose[3:]

    rmat = rts.euler_xyz_to_rmat(orn)

    return tfs.make_transform_mat(rmat, pos)

def pos_euler_xyz_to_pos_quat(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + Euler pose to a position + XYZW quaternion pose

    Args:

        pose (npt.ArrayLike): Position + Euler XYZ pose, shape = (6,)

    Returns:

        np.ndarray: Position + XYZW quaternion pose, shape = (7,)

    """

    if not check_pos_euler_xyz(pose):

        raise ValueError(f"Invalid position + euler pose.\nGot: {pose}")

    pos = pose[:3]

    orn = pose[3:]

    quat = rts.euler_xyz_to_quat(orn)

    return np.array([*pos, *quat])

def tmat_to_pos_euler_xyz(tmat: np.ndarray) -> np.ndarray:

    """Converts a transformation matrix to a position + Euler pose

    Args:

        pose (npt.ArrayLike): Transformation matrix, shape (4,4)

    Returns:

        np.ndarray: Position + Euler XYZ pose, shape = (6,)

    """

    if not tfs.check_transform_mat(tmat):

        raise ValueError(f"Invalid transformation matrix.\nGot: {tmat}")

    rmat = tmat[:3, :3]

    pos = tmat[:3, 3]

    orn = rts.rmat_to_euler_xyz(rmat)

    return np.array([*pos, *orn])

def tmat_to_pos_quat(tmat: np.ndarray) -> np.ndarray:

    """Converts a transformation matrix to a position + XYZW quaternion pose

    Args:

        pose (npt.ArrayLike): Transformation matrix, shape (4,4)

    Returns:

        np.ndarray: Position + XYZW quaternion pose, shape = (7,)

    """

    if not tfs.check_transform_mat(tmat):

        raise ValueError(f"Invalid transformation matrix.\nGot: {tmat}")

    rmat = tmat[:3, :3]

    pos = tmat[:3, 3]

    quat = rts.rmat_to_quat(rmat)

    return np.array([*pos, *quat])

def pos_quat_to_tmat(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + XYZW quaternion pose to a transformation matrix

    Args:

        pose (npt.ArrayLike): Position + XYZW quaternion pose, shape = (7,)

    Returns:

        np.ndarray: Transformation matrix, shape (4,4)

    """

    if not check_pos_quat(pose):

        raise ValueError(f"Invalid position + quaternion pose.\nGot: {pose}")

    pos = pose[:3]

    quat = pose[3:]

    rmat = rts.quat_to_rmat(quat)

    return tfs.make_transform_mat(rmat, pos)

def batched_pos_quats_to_tmats(poses: npt.ArrayLike) -> np.ndarray:

    """Converts a array of position + quaternion poses to an array of transformation matrices

    Args:

        poses (npt.ArrayLike): Position + quaternion poses, shape (n, 7)

    Returns:

        np.ndarray: Transformation matrices, shape (n, 4, 4)

    """

    # Assume poses is of shape (n, 7). If not, see if we can fix it, or raise an error

    poses = np.atleast_2d(poses)

    n_rows, n_cols = poses.shape

    if n_cols != 7 and n_rows == 7:

        print("Warning: you might have passed in the transpose of the pose array")

        poses = poses.T

    elif n_cols != 7 and n_rows != 7:

        raise ValueError(

            f"Invalid input shape: {poses.shape} Must be an array of position/quaternion poses"

        )

    # Convert XYZW poses to WXYZ for pytransform3d's quaternion convention

    wxyz_pqs = np.zeros_like(poses)

    wxyz_pqs[:, :3] = poses[:, :3]  # x, y, z

    wxyz_pqs[:, 3] = poses[:, -1]  # qw

    wxyz_pqs[:, 4:] = poses[:, 3:-1]  # qx, qy, qz

    # Use the batched conversion from pytransform3d since this is more efficient than a loop

    return pt.transforms_from_pqs(wxyz_pqs)

def pos_quat_to_pos_euler_xyz(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + XYZW quaternion pose to a position + Euler pose

    Args:

        pose (npt.ArrayLike): Position + XYZW quaternion pose, shape = (7,)

    Returns:

        np.ndarray: Position + Euler XYZ pose, shape = (6,)

    """

    if not check_pos_quat(pose):

        raise ValueError(f"Invalid position + quaternion pose.\nGot: {pose}")

    pos = pose[:3]

    quat = pose[3:]

    orn = rts.quat_to_euler_xyz(quat)

    return np.array([*pos, *orn])

def add_global_pose_delta(pose: npt.ArrayLike, pose_delta: npt.ArrayLike) -> np.ndarray:

    """Adds a world-frame "delta" to a pose

    Args:

        pose (npt.ArrayLike): Original reference pose (position + quaternion), shape (7,)

        pose_delta (npt.ArrayLike): Delta to add to the pose (position + quaternion), shape (7,)

    Returns:

        np.ndarray: Position + quaternion pose with the delta applied, shape (7,)

    """

    if not check_pos_quat(pose) or not check_pos_quat(pose_delta):

        raise ValueError(

            f"Invalid inputs: Not position/quaternion form.\nGot: {pose}\nAnd: {pose_delta}"

        )

    new_pos = pose[:3] + pose_delta[:3]

    new_orn = qts.combine_quaternions(pose[3:], pose_delta[3:])

    return np.array([*new_pos, *new_orn])

def add_local_pose_delta(pose: npt.ArrayLike, pose_delta: npt.ArrayLike) -> np.ndarray:

    """Adds a local (robot)-frame "delta" to a pose

    Args:

        pose (npt.ArrayLike): Original reference pose (position + quaternion), shape (7,)

        pose_delta (npt.ArrayLike): Delta to add to the pose (position + quaternion), shape (7,)

    Returns:

        np.ndarray: Position + quaternion pose with the delta applied, shape (7,)

    """

    if not check_pos_quat(pose) or not check_pos_quat(pose_delta):

        raise ValueError(

            f"Invalid inputs: Not position/quaternion form.\nGot: {pose}\nAnd: {pose_delta}"

        )

    T_R2W = pos_quat_to_tmat(pose)  # Robot to world

    T_D2R = pos_quat_to_tmat(pose_delta)  # Delta to robot

    T_D2W = T_R2W @ T_D2R  # Delta to world

    return tmat_to_pos_quat(T_D2W)

def pose_derivatives(

    poses: np.ndarray, dt: float

) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:

    """Calculates the linear/angular first and second derivatives of a sequence of poses

    Args:

        poses (np.ndarray): Sequence of position + XYZW quaternion poses, shape (n, 7)

        dt (float): Timestep between poses, in seconds

    Returns:

        tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:

            np.ndarray: Linear velocities, shape (n, 3)

            np.ndarray: Angular velocities, shape (n, 3)

            np.ndarray: Linear accelerations, shape (n, 3)

            np.ndarray: Angular accelerations, shape (n, 3)

    """

    if poses.shape[-1] != 7:

        raise ValueError(

            f"Invalid pose array: must be shape (n, 7). Got: {poses.shape}"

        )

    positions = poses[:, :3]

    quaternions = poses[:, 3:]

    velocities = np.gradient(positions, dt, axis=0)

    accels = np.gradient(velocities, dt, axis=0)

    omegas = qts.quats_to_angular_velocities(quaternions, dt)

    alphas = np.gradient(omegas, dt, axis=0)

    return velocities, omegas, accels, alphas

Functions

add_global_pose_delta

def add_global_pose_delta(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]],
    pose_delta: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Adds a world-frame "delta" to a pose

Parameters:

Name Type Description Default
pose npt.ArrayLike Original reference pose (position + quaternion), shape (7,) None
pose_delta npt.ArrayLike Delta to add to the pose (position + quaternion), shape (7,) None

Returns:

Type Description
np.ndarray Position + quaternion pose with the delta applied, shape (7,)
View Source
def add_global_pose_delta(pose: npt.ArrayLike, pose_delta: npt.ArrayLike) -> np.ndarray:

    """Adds a world-frame "delta" to a pose

    Args:

        pose (npt.ArrayLike): Original reference pose (position + quaternion), shape (7,)

        pose_delta (npt.ArrayLike): Delta to add to the pose (position + quaternion), shape (7,)

    Returns:

        np.ndarray: Position + quaternion pose with the delta applied, shape (7,)

    """

    if not check_pos_quat(pose) or not check_pos_quat(pose_delta):

        raise ValueError(

            f"Invalid inputs: Not position/quaternion form.\nGot: {pose}\nAnd: {pose_delta}"

        )

    new_pos = pose[:3] + pose_delta[:3]

    new_orn = qts.combine_quaternions(pose[3:], pose_delta[3:])

    return np.array([*new_pos, *new_orn])

add_local_pose_delta

def add_local_pose_delta(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]],
    pose_delta: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Adds a local (robot)-frame "delta" to a pose

Parameters:

Name Type Description Default
pose npt.ArrayLike Original reference pose (position + quaternion), shape (7,) None
pose_delta npt.ArrayLike Delta to add to the pose (position + quaternion), shape (7,) None

Returns:

Type Description
np.ndarray Position + quaternion pose with the delta applied, shape (7,)
View Source
def add_local_pose_delta(pose: npt.ArrayLike, pose_delta: npt.ArrayLike) -> np.ndarray:

    """Adds a local (robot)-frame "delta" to a pose

    Args:

        pose (npt.ArrayLike): Original reference pose (position + quaternion), shape (7,)

        pose_delta (npt.ArrayLike): Delta to add to the pose (position + quaternion), shape (7,)

    Returns:

        np.ndarray: Position + quaternion pose with the delta applied, shape (7,)

    """

    if not check_pos_quat(pose) or not check_pos_quat(pose_delta):

        raise ValueError(

            f"Invalid inputs: Not position/quaternion form.\nGot: {pose}\nAnd: {pose_delta}"

        )

    T_R2W = pos_quat_to_tmat(pose)  # Robot to world

    T_D2R = pos_quat_to_tmat(pose_delta)  # Delta to robot

    T_D2W = T_R2W @ T_D2R  # Delta to world

    return tmat_to_pos_quat(T_D2W)

batched_pos_quats_to_tmats

def batched_pos_quats_to_tmats(
    poses: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Converts a array of position + quaternion poses to an array of transformation matrices

Parameters:

Name Type Description Default
poses npt.ArrayLike Position + quaternion poses, shape (n, 7) None

Returns:

Type Description
np.ndarray Transformation matrices, shape (n, 4, 4)
View Source
def batched_pos_quats_to_tmats(poses: npt.ArrayLike) -> np.ndarray:

    """Converts a array of position + quaternion poses to an array of transformation matrices

    Args:

        poses (npt.ArrayLike): Position + quaternion poses, shape (n, 7)

    Returns:

        np.ndarray: Transformation matrices, shape (n, 4, 4)

    """

    # Assume poses is of shape (n, 7). If not, see if we can fix it, or raise an error

    poses = np.atleast_2d(poses)

    n_rows, n_cols = poses.shape

    if n_cols != 7 and n_rows == 7:

        print("Warning: you might have passed in the transpose of the pose array")

        poses = poses.T

    elif n_cols != 7 and n_rows != 7:

        raise ValueError(

            f"Invalid input shape: {poses.shape} Must be an array of position/quaternion poses"

        )

    # Convert XYZW poses to WXYZ for pytransform3d's quaternion convention

    wxyz_pqs = np.zeros_like(poses)

    wxyz_pqs[:, :3] = poses[:, :3]  # x, y, z

    wxyz_pqs[:, 3] = poses[:, -1]  # qw

    wxyz_pqs[:, 4:] = poses[:, 3:-1]  # qx, qy, qz

    # Use the batched conversion from pytransform3d since this is more efficient than a loop

    return pt.transforms_from_pqs(wxyz_pqs)

check_pos_euler_xyz

def check_pos_euler_xyz(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> bool

Checks to see if a position + Euler XYZ pose is valid

Parameters:

Name Type Description Default
pose npt.ArrayLike Position + Euler XYZ pose, shape = (6,) None

Returns:

Type Description
bool Whether or not the pose is valid
View Source
def check_pos_euler_xyz(pose: npt.ArrayLike) -> bool:

    """Checks to see if a position + Euler XYZ pose is valid

    Args:

        pose (npt.ArrayLike): Position + Euler XYZ pose, shape = (6,)

    Returns:

        bool: Whether or not the pose is valid

    """

    return len(pose) == 6

check_pos_quat

def check_pos_quat(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> bool

Checks to see if a position + XYZW quaternion pose is valid

Parameters:

Name Type Description Default
pose npt.ArrayLike Position + XYZW quaternion pose None

Returns:

Type Description
bool Whether or not the pose is valid
View Source
def check_pos_quat(pose: npt.ArrayLike) -> bool:

    """Checks to see if a position + XYZW quaternion pose is valid

    Args:

        pose (npt.ArrayLike): Position + XYZW quaternion pose

    Returns:

        bool: Whether or not the pose is valid

    """

    return len(pose) == 7

pos_euler_xyz_to_pos_quat

def pos_euler_xyz_to_pos_quat(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Converts a position + Euler pose to a position + XYZW quaternion pose

Parameters:

Name Type Description Default
pose npt.ArrayLike Position + Euler XYZ pose, shape = (6,) None

Returns:

Type Description
np.ndarray Position + XYZW quaternion pose, shape = (7,)
View Source
def pos_euler_xyz_to_pos_quat(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + Euler pose to a position + XYZW quaternion pose

    Args:

        pose (npt.ArrayLike): Position + Euler XYZ pose, shape = (6,)

    Returns:

        np.ndarray: Position + XYZW quaternion pose, shape = (7,)

    """

    if not check_pos_euler_xyz(pose):

        raise ValueError(f"Invalid position + euler pose.\nGot: {pose}")

    pos = pose[:3]

    orn = pose[3:]

    quat = rts.euler_xyz_to_quat(orn)

    return np.array([*pos, *quat])

pos_euler_xyz_to_tmat

def pos_euler_xyz_to_tmat(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Converts a position + Euler pose to a transformation matrix

Parameters:

Name Type Description Default
pose npt.ArrayLike Position + Euler XYZ pose, shape = (6,) None

Returns:

Type Description
np.ndarray Transformation matrix, shape (4,4)
View Source
def pos_euler_xyz_to_tmat(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + Euler pose to a transformation matrix

    Args:

        pose (npt.ArrayLike): Position + Euler XYZ pose, shape = (6,)

    Returns:

        np.ndarray: Transformation matrix, shape (4,4)

    """

    if not check_pos_euler_xyz(pose):

        raise ValueError(f"Invalid position + euler pose.\nGot: {pose}")

    pos = pose[:3]

    orn = pose[3:]

    rmat = rts.euler_xyz_to_rmat(orn)

    return tfs.make_transform_mat(rmat, pos)

pos_quat_to_pos_euler_xyz

def pos_quat_to_pos_euler_xyz(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Converts a position + XYZW quaternion pose to a position + Euler pose

Parameters:

Name Type Description Default
pose npt.ArrayLike Position + XYZW quaternion pose, shape = (7,) None

Returns:

Type Description
np.ndarray Position + Euler XYZ pose, shape = (6,)
View Source
def pos_quat_to_pos_euler_xyz(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + XYZW quaternion pose to a position + Euler pose

    Args:

        pose (npt.ArrayLike): Position + XYZW quaternion pose, shape = (7,)

    Returns:

        np.ndarray: Position + Euler XYZ pose, shape = (6,)

    """

    if not check_pos_quat(pose):

        raise ValueError(f"Invalid position + quaternion pose.\nGot: {pose}")

    pos = pose[:3]

    quat = pose[3:]

    orn = rts.quat_to_euler_xyz(quat)

    return np.array([*pos, *orn])

pos_quat_to_tmat

def pos_quat_to_tmat(
    pose: Union[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]], numpy._typing._nested_sequence._NestedSequence[numpy._typing._array_like._SupportsArray[numpy.dtype[Any]]], bool, int, float, complex, str, bytes, numpy._typing._nested_sequence._NestedSequence[Union[bool, int, float, complex, str, bytes]]]
) -> numpy.ndarray

Converts a position + XYZW quaternion pose to a transformation matrix

Parameters:

Name Type Description Default
pose npt.ArrayLike Position + XYZW quaternion pose, shape = (7,) None

Returns:

Type Description
np.ndarray Transformation matrix, shape (4,4)
View Source
def pos_quat_to_tmat(pose: npt.ArrayLike) -> np.ndarray:

    """Converts a position + XYZW quaternion pose to a transformation matrix

    Args:

        pose (npt.ArrayLike): Position + XYZW quaternion pose, shape = (7,)

    Returns:

        np.ndarray: Transformation matrix, shape (4,4)

    """

    if not check_pos_quat(pose):

        raise ValueError(f"Invalid position + quaternion pose.\nGot: {pose}")

    pos = pose[:3]

    quat = pose[3:]

    rmat = rts.quat_to_rmat(quat)

    return tfs.make_transform_mat(rmat, pos)

pose_derivatives

def pose_derivatives(
    poses: numpy.ndarray,
    dt: float
) -> tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]

Calculates the linear/angular first and second derivatives of a sequence of poses

Parameters:

Name Type Description Default
poses np.ndarray Sequence of position + XYZW quaternion poses, shape (n, 7) None
dt float Timestep between poses, in seconds None

Returns:

Type Description
tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray] np.ndarray: Linear velocities, shape (n, 3)
np.ndarray: Angular velocities, shape (n, 3)
np.ndarray: Linear accelerations, shape (n, 3)
np.ndarray: Angular accelerations, shape (n, 3)
View Source
def pose_derivatives(

    poses: np.ndarray, dt: float

) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:

    """Calculates the linear/angular first and second derivatives of a sequence of poses

    Args:

        poses (np.ndarray): Sequence of position + XYZW quaternion poses, shape (n, 7)

        dt (float): Timestep between poses, in seconds

    Returns:

        tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:

            np.ndarray: Linear velocities, shape (n, 3)

            np.ndarray: Angular velocities, shape (n, 3)

            np.ndarray: Linear accelerations, shape (n, 3)

            np.ndarray: Angular accelerations, shape (n, 3)

    """

    if poses.shape[-1] != 7:

        raise ValueError(

            f"Invalid pose array: must be shape (n, 7). Got: {poses.shape}"

        )

    positions = poses[:, :3]

    quaternions = poses[:, 3:]

    velocities = np.gradient(positions, dt, axis=0)

    accels = np.gradient(velocities, dt, axis=0)

    omegas = qts.quats_to_angular_velocities(quaternions, dt)

    alphas = np.gradient(omegas, dt, axis=0)

    return velocities, omegas, accels, alphas

tmat_to_pos_euler_xyz

def tmat_to_pos_euler_xyz(
    tmat: numpy.ndarray
) -> numpy.ndarray

Converts a transformation matrix to a position + Euler pose

Parameters:

Name Type Description Default
pose npt.ArrayLike Transformation matrix, shape (4,4) None

Returns:

Type Description
np.ndarray Position + Euler XYZ pose, shape = (6,)
View Source
def tmat_to_pos_euler_xyz(tmat: np.ndarray) -> np.ndarray:

    """Converts a transformation matrix to a position + Euler pose

    Args:

        pose (npt.ArrayLike): Transformation matrix, shape (4,4)

    Returns:

        np.ndarray: Position + Euler XYZ pose, shape = (6,)

    """

    if not tfs.check_transform_mat(tmat):

        raise ValueError(f"Invalid transformation matrix.\nGot: {tmat}")

    rmat = tmat[:3, :3]

    pos = tmat[:3, 3]

    orn = rts.rmat_to_euler_xyz(rmat)

    return np.array([*pos, *orn])

tmat_to_pos_quat

def tmat_to_pos_quat(
    tmat: numpy.ndarray
) -> numpy.ndarray

Converts a transformation matrix to a position + XYZW quaternion pose

Parameters:

Name Type Description Default
pose npt.ArrayLike Transformation matrix, shape (4,4) None

Returns:

Type Description
np.ndarray Position + XYZW quaternion pose, shape = (7,)
View Source
def tmat_to_pos_quat(tmat: np.ndarray) -> np.ndarray:

    """Converts a transformation matrix to a position + XYZW quaternion pose

    Args:

        pose (npt.ArrayLike): Transformation matrix, shape (4,4)

    Returns:

        np.ndarray: Position + XYZW quaternion pose, shape = (7,)

    """

    if not tfs.check_transform_mat(tmat):

        raise ValueError(f"Invalid transformation matrix.\nGot: {tmat}")

    rmat = tmat[:3, :3]

    pos = tmat[:3, 3]

    quat = rts.rmat_to_quat(rmat)

    return np.array([*pos, *quat])