Joints between objects
MVSim supports joint constraints between any two Simulable objects
(vehicles, blocks, or a mix of both). Joints are backed by Box2D joint
primitives and are solved together with the rest of the physics each time step.
Typical use-cases include tractor-trailer articulation, tow ropes, coupled robots, and passive trailers pulled by a powered vehicle.
Note
<joint> tags must appear after all referenced <vehicle> and
<block> tags in the world file, because the bodies need to exist before
they can be connected.
Joint types
Two joint types are currently available, selected via the type attribute:
distance— rope / distance constraintA distance joint (
b2DistanceJoint) that allows the two anchor points to be closer thanmax_lengthbut never farther apart, like a rope or cable. Settingstiffnessanddampingto zero (the default) gives a rigid length limit; non-zero values make the constraint springy.revolute— pin / hinge constraintA revolute joint (
b2RevoluteJoint) that forces two anchor points to remain coincident and allows only relative rotation around that shared point. Optional angle limits prevent excessive articulation (e.g. jack-knifing).
Common attributes
Every <joint> tag requires the following attributes:
type:
"distance"or"revolute".body_a: Name of the first
Simulableobject (itsnameattribute).body_b: Name of the second
Simulableobject.anchor_a:
"x y"offset in body_a’s local coordinate frame.anchor_b:
"x y"offset in body_b’s local coordinate frame.
Distance joint attributes
These attributes are only used when type="distance":
max_length (required): Maximum distance (metres) between anchors.
min_length (optional, default 0): Minimum distance. Zero means the bodies can touch.
stiffness (optional, default 0): Spring stiffness (N/m). Zero gives a rigid limit.
damping (optional, default 0): Damping coefficient (N·s/m).
Revolute joint attributes
These attributes are only used when type="revolute":
enable_limit (optional, default false): Whether angular limits are enforced.
lower_angle_deg (optional, default 0): Lower angular limit in degrees (only if
enable_limit="true").upper_angle_deg (optional, default 0): Upper angular limit in degrees.
Visualization
Joints are rendered in the 3-D GUI automatically:
Distance joints: Yellow line between the two world-space anchor points.
Revolute joints: Red line between anchors plus a small cross marker at the pivot.
Examples
Rope between two blocks:
<joint type="distance"
body_a="cargo_a" anchor_a="-0.5 0.0"
body_b="cargo_b" anchor_b=" 0.5 0.0"
max_length="3.0"
/>
Pin joint for a tractor-trailer (with angle limits):
<joint type="revolute"
body_a="tractor" anchor_a="-1.5 0.0"
body_b="trailer" anchor_b=" 1.0 0.0"
enable_limit="true"
lower_angle_deg="-75"
upper_angle_deg="75"
/>
Springy tow line:
<joint type="distance"
body_a="truck" anchor_a="-1.0 0.0"
body_b="caravan" anchor_b=" 1.2 0.0"
max_length="2.5"
stiffness="500.0"
damping="50.0"
/>
Passive (unpowered) trailers
A common pattern is a trailer that has no motor of its own and is pulled
entirely through a joint. To achieve this, define the trailer as a normal
vehicle with a raw controller and leave all torque values at zero:
<vehicle:class name="trailer_class">
<dynamics class="differential_4_wheels">
<chassis mass="300" zmin="0.05" zmax="0.6">
<!-- shape polygon ... -->
</chassis>
<!-- define 4 passive wheels here -->
<controller class="raw">
<l_torque>0</l_torque>
<r_torque>0</r_torque>
</controller>
</dynamics>
</vehicle:class>
<vehicle name="trailer" class="trailer_class">
<init_pose>-2.8 0 0</init_pose>
</vehicle>
<!-- Connect tractor rear to trailer front -->
<joint type="revolute"
body_a="tractor" anchor_a="-0.8 0.0"
body_b="trailer" anchor_b=" 2.0 0.0"
enable_limit="true"
lower_angle_deg="-75" upper_angle_deg="75"
/>
Tip
Position both bodies so their anchor points overlap at \(t=0\); this avoids a sudden impulse on the first simulation step.