Skip to content

trusty.affine

Affine (articulated) bodies.

VelocityPenaltyMode

Bases: Enum

Cubic class-attribute instance-attribute

Cubic = 0

Quadratic class-attribute instance-attribute

Quadratic = 1

Barrier class-attribute instance-attribute

Barrier = 2

MuscleModel

Bases: Enum

Hill class-attribute instance-attribute

Hill = 0

Polynomial class-attribute instance-attribute

Polynomial = 1

add_affine_body

add_affine_body(
    world: World,
    V: ndarray[float64, (N, 3)],
    F: ndarray[int32, (N, M)],
    density: float = 1000.0,
    stiffness: float = 100000000.0,
    *,
    friction_mu: float = 0.0,
) -> int

Add a near-rigid affine body from a closed, outward-wound triangle surface mesh (V: (n,3), F: (m,3)). stiffness (Pa) is the orthogonality rigidity -- large values are effectively rigid. friction_mu is the body's surface Coulomb coefficient (>= 0); 0 is frictionless.

add_spherical_joint

add_spherical_joint(
    world: World,
    body_i: int,
    anchor: tuple[float, float, float],
    body_j: int | None = None,
    stiffness: float = 100000000.0,
) -> int

Spherical (ball) joint: pin anchor (rest world coords) on body_i to body_j, or to its fixed rest position if body_j is omitted. Free relative rotation.

add_revolute_joint

add_revolute_joint(
    world: World,
    body_i: int,
    axis_p0: tuple[float, float, float],
    axis_p1: tuple[float, float, float],
    body_j: int | None = None,
    stiffness: float = 100000000.0,
) -> int

Revolute (hinge) joint: pin the axis line through axis_p0/axis_p1 between body_i and body_j (grounded if omitted). One rotational DOF about that axis.

add_fixed_joint

add_fixed_joint(
    world: World,
    body_i: int,
    origin: tuple[float, float, float],
    axis_u: tuple[float, float, float],
    axis_v: tuple[float, float, float],
    body_j: int | None = None,
    stiffness: float = 1000000.0,
) -> int

Fixed (weld) joint: rigidly weld body_i to body_j (grounded if omitted), fully constraining their relative rigid pose. Pins the 3-point frame origin, origin + axis_u, origin + axis_v (rest world coords; axis_u, axis_v are non-collinear offset vectors). The welded pair is auto-excluded from contact. Each affine body keeps its residual deformation DOF, so a soft body welded under a stiff one stays pose-locked but still deformable.

add_prismatic_joint

add_prismatic_joint(
    world: World,
    body_i: int,
    anchor: tuple[float, float, float],
    axis: tuple[float, float, float],
    body_j: int | None = None,
    stiffness: float = 100000000.0,
) -> int

Prismatic (slider) joint: lock body_i's orientation relative to body_j (the world if omitted) and let anchor slide only along a rail with direction axis fixed in body_j's frame. anchor and axis are rest world coordinates. The joint coordinate (actuator target / value, limits) is the slide in m along the rail, measured in body_j's frame, 0 at rest. A body-body pair is excluded from contact.

add_actuator

add_actuator(
    world: World, joint: int, stiffness: float = 1000000.0
) -> int

Add a position-target actuator to an existing joint (the handle returned by add_*_joint). A separate energy term layered on the joint that drives its free DOF(s) toward a target set each control step with an implicit PD servo of gain stiffness. Set the command via affine.set_actuator_target / affine.set_actuator_rotation.

add_joint_limit

add_joint_limit(
    world: World,
    joint: int,
    lo: float,
    hi: float,
    margin: float = 0.05,
    stiffness: float = 1000.0,
) -> int

Add a joint-limit barrier (C2 clamped log-barrier) to a revolute or prismatic joint, confining its coordinate to [lo, hi] (revolute angle in rad, must be within (-pi, pi); prismatic slide in m). margin is the activation distance from each limit. Stops over-travel without a wrap-through; spherical joints are unsupported.

add_joint_velocity_limit

add_joint_velocity_limit(
    world: World,
    joint: int,
    omega_max: float,
    stiffness: float = 1000000.0,
    mode: VelocityPenaltyMode = VelocityPenaltyMode.Barrier,
    barrier_width_fraction: float = 0.25,
) -> int

Add a velocity limit to a revolute, prismatic, or spherical joint, capping its rate at omega_max (revolute rad/s, prismatic m/s, spherical angular-velocity magnitude rad/s) on the integrator-consistent joint velocity. mode is VelocityPenaltyMode.Barrier (the default HARD cap), .Quadratic (a soft cap: firmer than Cubic, no asymptote), .Cubic (C2 but soft near the cap). The barrier is a clamped log-barrier that activates barrier_width_fraction * omega_max below the wall and carries an analytic step filter, so Newton sees the cap before it steps through it, and the rate never exceeds omega_max. Fixed (weld) joints are unsupported.

add_line_muscle

add_line_muscle(
    world: World,
    bodies: Sequence[int],
    points: ndarray[float64, (N, 3)],
    f_max: float,
    l_opt: float,
    l_tendon_slack: float,
    pennation: float = 0.0,
    activation: float = 0.0,
    model: MuscleModel = MuscleModel.Hill,
) -> int

Add a Hill-type line muscle through points (n,3 rest world coords) on bodies (one affine body per point; consecutive points may share a body), spanning >= 2 distinct bodies. Hill params: f_max (N), l_opt (optimal fiber length, m), l_tendon_slack (m), pennation (rad). activation in [0,1] is the live command. model selects the force-length law (MuscleModel.Hill, the default, or MuscleModel.Polynomial -- a well-conditioned no-exp variant). Segments are straight -- wrap surfaces are not implemented. Set activation via affine.set_muscle_activation.

num_bodies

num_bodies(world: World) -> int

Number of affine bodies in the world.

bodies

bodies(world: World) -> set

Every affine body in the world, as a set -- there is no i-th body. Iterate it, or hold the handle add_affine_body returned.

surface

surface(
    world: World, body: int
) -> tuple[
    ndarray[float64, (N, 3)], ndarray[int32, (N, M)]
]

Current world-space (V, F) triangle surface of affine body body. The rest surface before the first step.

center_of_mass

center_of_mass(
    world: World, body: int
) -> ndarray[float64, (3,)]

Rest-frame centre of mass (3,) of affine body body, in meters. Computed from its rest surface at creation and constant for the body's life; the body's 12 affine DOFs are taken about it.

num_actuators

num_actuators(world: World) -> int

Number of affine actuators in the world.

set_actuator_target

set_actuator_target(
    world: World, actuator: int, value: float
) -> None

Set the position target of a revolute (relative angle, rad) or prismatic (slide distance, m) actuator. Held until changed.

set_actuator_rotation

set_actuator_rotation(
    world: World,
    actuator: int,
    rotvec: tuple[float, float, float],
) -> None

Set the target relative orientation of a spherical actuator, as a rotation vector (axis * angle, rad).

set_velocity

set_velocity(
    world: World,
    body: int,
    v: ndarray[float64, (3,)],
    omega: ndarray[float64, (3,)] | None = None,
) -> None

Set affine body body's rigid velocity: centre-of-mass velocity v (m/s, world) and angular velocity omega about the centre of mass (rad/s, world; None = no spin). A material point at x moves at v + omega x (x - c), c the body's current centre of mass; any deformation rate is zeroed. Applied at the next step(); only this body's history is rewritten, and the integrator is unchanged.

actuator_value

actuator_value(world: World, actuator: int) -> float

Current scalar coordinate of a revolute (angle, rad) or prismatic (slide, m) actuator, from the accepted state -- the RL observation. Zero (the joint's rest configuration) before the first step.

actuator_target

actuator_target(world: World, actuator: int) -> float

Current target of a revolute (rad) or prismatic (m) actuator.

num_muscles

num_muscles(world: World) -> int

Number of affine line muscles in the world.

set_muscle_activation

set_muscle_activation(
    world: World, muscle: int, activation: float
) -> None

Set the activation (command, typically in [0,1]) of line muscle muscle, the handle add_line_muscle returned. Held until changed.

muscle_activation

muscle_activation(world: World, muscle: int) -> float

Current activation of line muscle muscle.

muscle_length

muscle_length(world: World, muscle: int) -> float

Muscle-tendon length (m) of line muscle muscle from the accepted state; its rest path length before the first step.

muscle_force

muscle_force(world: World, muscle: int) -> float

Tension (N) of line muscle muscle at its published length; zero before the first step.

muscle_path

muscle_path(
    world: World, muscle: int
) -> ndarray[float64, (N, 3)]

Current world-space via-point polyline (n,3) of line muscle muscle; its rest points before the first step.