Rigid Body Constraints

Rigid body constraints restrict and drive rigid body motion: they attach bodies, build joints, add springs, and control velocity.

Each add_constraint_*() call returns a handle for adjusting parameters, enabling/disabling, labeling, or querying the constraint violation.

// Global defaults used by subsequently created hard constraints.
simulation.rigidbodies->set_default_constraint_stiffness(1e6);
simulation.rigidbodies->set_default_constraint_distance_tolerance(1e-3); // m
simulation.rigidbodies->set_default_constraint_angle_tolerance(1.0);     // deg

// Example: a hinge joint between two rigid bodies.
auto hinge = simulation.rigidbodies->add_constraint_hinge(
    body_a,
    body_b,
    pivot_point,   // world-space point at creation time
    hinge_axis     // world-space direction at creation time
);

hinge.set_stiffness(1e8);
hinge.set_tolerance_in_m(1e-4);
hinge.set_tolerance_in_deg(0.1);
hinge.set_label("main_hinge");

How constraints work

STARK rigid body constraints are implemented as energy terms in the global optimization problem. Most rigid body constraints are defined from points or directions given in world coordinates at creation time.

Hard constraints use finite stiffness with a tolerance. After convergence, STARK checks the violation and hardens stiffness if the tolerance is exceeded, avoiding the need to manually tune very large stiffness values.

There are two important categories:

  • Primitive constraints are the actual energy terms registered in SymX.

  • Composed constraints are convenience joints built by combining primitive constraints.

Common handle operations

All constraint handles support basic operations such as:

constraint.set_label("name"); // Used for traceability
constraint.enable(true);      // activate
constraint.enable(false);     // deactivate

Hard positional constraints usually provide:

constraint.set_stiffness(1e8);
constraint.set_tolerance_in_m(1e-4);

Hard directional constraints usually provide:

constraint.set_stiffness(1e8);
constraint.set_tolerance_in_deg(1.0);

Velocity controllers and springs expose their physical parameters directly, such as target velocity, maximum force, maximum torque, damping, or rest length.

Primitive Constraints

Primitive constraints are the low-level constraint energies implemented by STARK. The higher-level joints later in this page are built from these pieces.

Global Point

Fixes one body-local point to a target point in world space.

auto c = simulation.rigidbodies->add_constraint_global_point(
    body,
    world_point
);

Global Direction

Aligns one body-local direction with a target direction in world space.

auto c = simulation.rigidbodies->add_constraint_global_direction(
    body,
    world_direction
);

Point

Constrains one point on body A to coincide with one point on body B. This is the primitive ball-joint constraint.

auto c = simulation.rigidbodies->add_constraint_point(
    body_a,
    body_b,
    world_point
);

Point on Axis

Constrains a point on body B to lie on an axis attached to body A.

auto c = simulation.rigidbodies->add_constraint_point_on_axis(
    body_a,
    body_b,
    world_point,
    world_axis
);

Distance

Constrains the distance between two body-local points to remain equal to the distance at creation time.

auto c = simulation.rigidbodies->add_constraint_distance(
    body_a,
    body_b,
    point_on_a_world,
    point_on_b_world
);

Distance Limits

Constrains the distance between two body-local points to remain inside an interval.

auto c = simulation.rigidbodies->add_constraint_distance_limits(
    body_a,
    body_b,
    point_on_a_world,
    point_on_b_world,
    min_distance,
    max_distance
);

Direction

Aligns one body-local direction on body A with one body-local direction on body B.

auto c = simulation.rigidbodies->add_constraint_direction(
    body_a,
    body_b,
    world_direction
);

Angle Limit

Restricts the angle between two body-local directions.

auto c = simulation.rigidbodies->add_constraint_angle_limit(
    body_a,
    body_b,
    world_direction,
    admissible_angle_deg
);

Damped Spring

Adds a damped linear spring between two body-local points.

auto spring = simulation.rigidbodies->add_constraint_spring(
    body_a,
    body_b,
    point_on_a_world,
    point_on_b_world,
    stiffness,
    damping        // optional, default 0.0
);

Linear Velocity

Drives the relative linear velocity of body B with respect to body A along a direction attached to body A.

auto c = simulation.rigidbodies->add_constraint_linear_velocity(
    body_a,
    body_b,
    world_direction,
    target_v,       // m/s
    max_abs_force,  // N
    delay           // optional, default 0.01 s
);

Angular Velocity

Drives the relative angular velocity of body B with respect to body A around a direction attached to body A.

auto c = simulation.rigidbodies->add_constraint_angular_velocity(
    body_a,
    body_b,
    world_axis,
    target_w,        // rad/s
    max_abs_torque,  // Nm
    delay            // optional, default 0.01 s
);

Composed Constraints

Composed constraints are convenience APIs that combine primitive constraints. They return composed handles that forward stiffness, tolerance, label, and activation changes to the underlying primitives.

Fix

Fixes a rigid body in world space by combining one global point constraint with two global direction constraints.

auto fix = simulation.rigidbodies->add_constraint_fix(body);

The body is fixed at its current pose at creation time.The typical scripting pattern: create a fix, then update its target transformation each step.

auto fix = simulation.rigidbodies->add_constraint_fix(body);

simulation.add_time_event(0.0, duration, [&](double t) {
    fix.set_transformation(
        Eigen::Vector3d(0.0, 0.0, 0.2 * t),  // target translation
        30.0 * t,                             // angle in degrees
        Eigen::Vector3d::UnitZ()              // rotation axis
    );
});

Attachment

Rigidly attaches two bodies together, producing a zero-DOF joint.

auto attachment = simulation.rigidbodies->add_constraint_attachment(
    body_a,
    body_b
);

The attachment is created at the midpoint between the current body translations and locks the relative orientation with two direction constraints.

Point with Angle Limit

Combines a point constraint with an angular range limit.

auto joint = simulation.rigidbodies->add_constraint_point_with_angle_limit(
    body_a,
    body_b,
    pivot_point,
    limit_axis,
    admissible_angle_deg
);

Conceptually, this behaves like a ball joint with an angular cone limit.

Hinge

Creates a one-DOF hinge joint: the bodies share a pivot point and may rotate relative to each other around the hinge axis.

auto hinge = simulation.rigidbodies->add_constraint_hinge(
    body_a,
    body_b,
    pivot_point,
    hinge_axis
);

Hinge with Angle Limit

Creates a hinge joint with a symmetric angular limit around the hinge axis.

auto hinge = simulation.rigidbodies->add_constraint_hinge_with_angle_limit(
    body_a,
    body_b,
    pivot_point,
    hinge_axis,
    admissible_angle_deg
);

Spring with Limits

Adds a damped spring and additionally constrains its length to remain inside a prescribed interval.

auto spring = simulation.rigidbodies->add_constraint_spring_with_limits(
    body_a,
    body_b,
    point_on_a_world,
    point_on_b_world,
    spring_stiffness,
    min_length,
    max_length,
    damping             // optional, default 0.0
);

The spring stiffness and the hard distance-limit stiffness are independent. The composed handle exposes set_spring_stiffness() for the spring and set_stiffness() for the distance limits.

Slider

Creates a slider-like joint where a point on one body can move along an axis attached to the other body.

auto slider = simulation.rigidbodies->add_constraint_slider(
    body_a,
    body_b,
    pivot_point,
    slide_axis
);

This permits sliding along the axis while keeping the corresponding body directions aligned.

Prismatic Slider

Creates a stricter prismatic joint by adding an additional orthogonal direction lock to the slider.

auto slider = simulation.rigidbodies->add_constraint_prismatic_slider(
    body_a,
    body_b,
    pivot_point,
    slide_axis
);

This keeps the bodies aligned as a prismatic pair while allowing translation along the slide axis.

Prismatic Press

Creates a prismatic slider driven by a force-limited linear velocity controller.

auto press = simulation.rigidbodies->add_constraint_prismatic_press(
    body_a,
    body_b,
    pivot_point,
    slide_axis,
    target_v,
    max_force,
    delay       // optional, default 0.01 s
);

This is useful for grippers, presses, pistons, and other constrained linear actuators.

Motor

Creates a hinge driven by a torque-limited angular velocity controller.

auto motor = simulation.rigidbodies->add_constraint_motor(
    body_a,
    body_b,
    pivot_point,
    rotation_axis,
    target_w,
    max_torque,
    delay       // optional, default 0.01 s
);

This is the standard rigid body rotational motor.