Skip to content

Twist3D

Represents a 3D twist: a linear velocity plus an angular velocity.

Parameters

FieldTypeDescription
datanp.ndarray | list | tupleArray-like input of shape (6,): [vx, vy, vz, wx, wy, wz], converted to a contiguous float32 array.

Raises

ExceptionCondition
TypeErrordata can't be converted to float32 (e.g. non-numeric elements)
ValueErrordata is not rank-1, or its shape isn't (6,)
ValueErrordata contains a non-finite value (NaN/Inf)

Attributes

AttributeTypeDescription
datanp.ndarrayDefensive copy of the underlying (6,) float32 array. Assigning a new value re-validates it the same way as construction.
shapetuple[int, ...]Always (6,).
ndimintAlways 1.
dtypenp.dtypeAlways float32.
sizeintAlways 6.

Methods

MethodDescription
to_numpy(copy=True)Returns the twist as np.ndarray. Pass copy=False for a reference to the internal array instead — faster, but mutating it mutates the Twist3D too.
copy()Returns a new Twist3D with an independent copy of the data.
Twist3D.coerce(value)Returns value unchanged if it's already a Twist3D; otherwise wraps an array-like into one. Raises TypeError for any other input.

Operators

OperationBehavior
t == otherTrue only if other is also a Twist3D with element-equal data. False for anything else.
len(t)Always 6.
np.asarray(t)Works directly via __array__. Always returns a copy; use to_numpy(copy=False) for a zero-copy view.
hash(t)Not supported — mutable via the data setter.

Visualization

datatypes.visualize(twist, entity_path=...) logs a static reference frame pinned at the world origin (labeled "origin"), then integrates the linear velocity v and angular velocity ω via the Rodrigues rotation formula over 100 synthetic timesteps (step=0.05s each) on a "time" sequence timeline, logging a moving frame at each step so the viewer can play back the resulting motion. Passing label="..." attaches a floating text label at the static origin frame.

Example

python
"""Demonstrates the Telekinesis Twist3D datatype."""

import time

import numpy as np
from loguru import logger
import rerun as rr

from telekinesis import datatypes

def twist3d_example():
    """Demonstrate creation, access, visualization, update, NumPy interop, and serialization."""

    # ======================= Create ============================================
    values = np.array([0.1, 0.0, 0.0, 0.0, 0.0, 0.2], dtype=np.float32)
    twist3d = datatypes.Twist3D(values)

    logger.info(f"Input values: {values}")
    logger.info(f"Created Twist3D: {twist3d}")

    # ======================= Inspect ===========================================
    data = twist3d.data
    shape = twist3d.shape
    size = twist3d.size
    dtype = twist3d.dtype
    ndim = twist3d.ndim
    numpy_array = twist3d.to_numpy()
    twist3d_copy = twist3d.copy()

    logger.info(f"shape={shape}, size={size}, ndim={ndim}, dtype={dtype}")
    logger.info(f"Twist3D data: {data}")
    logger.info(f"NumPy array: {numpy_array}")
    logger.info(f"Copied Twist3D: {twist3d_copy}")

    # ======================= Visualize =========================================
    rr.init("twist3d_example", spawn=True)
    datatypes.visualize(twist3d, entity_path="/Twist3D/main", label="Original Twist3D")

    # ======================= Update ============================================
    twist3d.data = np.array([0.0, 0.3, 0.0, 0.1, 0.0, 0.0], dtype=np.float32)

    logger.info(f"Updated Twist3D: {twist3d}")
    datatypes.visualize(twist3d, entity_path="/Twist3D/updated", label="Updated Twist3D")

    # ======================= NumPy Interop =====================================
    linear = numpy_array[:3]
    angular = numpy_array[3:]
    linear_speed = np.linalg.norm(linear)
    angular_speed = np.linalg.norm(angular)

    logger.info(f"Linear velocity (vx, vy, vz): {linear}")
    logger.info(f"Angular velocity (wx, wy, wz): {angular}")
    logger.info(f"linear_speed={linear_speed}, angular_speed={angular_speed}")

    # ======================= Serialize / Deserialize ===========================
    start = time.perf_counter()
    serialized = datatypes.serialize(twist3d)
    serialization_ms = (time.perf_counter() - start) * 1000

    start = time.perf_counter()
    deserialized = datatypes.deserialize(serialized)["param_0"]
    deserialization_ms = (time.perf_counter() - start) * 1000

    logger.info(f"Deserialized Twist3D: {deserialized}")
    logger.info(f"Round-trip successful: {deserialized == twist3d}")
    logger.info(f"Serialization time: {serialization_ms:.3f} ms")
    logger.info(f"Deserialization time: {deserialization_ms:.3f} ms")


if __name__ == "__main__":
    twist3d_example()