Articulated systems
A robot arm, a leg, a pendulum chain — these are articulated systems: rigid
links connected by joints. In DART 7 you build one as a Multibody: a tree of
links joined by joints, owned by the world.
Building a multibody
Add a multibody to the world, then add links. The first link is the root; every
later link names its parent and the JointSpec that connects it. A
JointSpec describes the joint’s type, axis, and where it sits relative to the
parent:
import dartpy as dart
import numpy as np
def translation(x, y, z):
t = np.eye(4)
t[:3, 3] = (x, y, z)
return t
world = dart.World()
robot = world.add_multibody("arm")
# Root link.
base = robot.add_link("base")
# Upper arm on a revolute (hinge) shoulder, one metre out from the base.
upper = robot.add_link(
"upper_arm",
parent=base,
joint=dart.JointSpec(
name="shoulder",
type=dart.JointType.REVOLUTE,
axis=(0.0, 1.0, 0.0),
transform_from_parent=translation(1.0, 0.0, 0.0),
),
)
upper.mass = 2.0
upper.inertia = ((0.10, 0.0, 0.0), (0.0, 0.20, 0.0), (0.0, 0.0, 0.30))
# Forearm on a 2-axis universal wrist.
fore = robot.add_link(
"forearm",
parent=upper,
joint=dart.JointSpec(
name="wrist",
type=dart.JointType.UNIVERSAL,
axis=(0.0, 0.0, 1.0),
axis2=(0.0, 1.0, 0.0),
transform_from_parent=translation(1.0, 0.0, 0.0),
),
)
fore.mass = 1.0
fore.inertia = ((0.05, 0.0, 0.0), (0.0, 0.05, 0.0), (0.0, 0.0, 0.05))
world.enter_simulation_mode()
This arm has three degrees of freedom: a 1-DOF revolute shoulder plus a 2-DOF
universal wrist. robot.num_dofs reports the total generalized-coordinate count
for the tree.
Links
A link is a rigid body inside the multibody tree. It carries inertial properties and acts as a frame you can query:
upper.mass # link mass
upper.inertia # 3x3 inertia tensor
upper.translation # world-frame position of the link
upper.parent_joint # the joint connecting it to its parent
Joints
A joint defines how a link can move relative to its parent. You reach a
joint through its child link’s parent_joint, then read or write its
generalized state:
shoulder = upper.parent_joint
shoulder.position # generalized position(s)
shoulder.velocity # generalized velocity(ies)
shoulder.damping_coefficient # viscous damping
Common joint types include REVOLUTE (a hinge, 1 DOF), UNIVERSAL (2 DOF), and
others selected through dart.JointType. The axis (and axis2 for two-axis
joints) sets the direction of motion, and transform_from_parent places the
joint frame relative to the parent link.
Trees and closed loops
A Multibody is a tree: each link has exactly one parent joint, which keeps
articulated dynamics fast and well-conditioned. Mechanisms with closed loops —
four-bar linkages, parallel arms — are modeled by adding explicit loop
closures on top of the tree rather than by forcing a second parent. Loop
closure is an advanced, still-maturing area of the DART 7 API; for now, build the
tree and consult the
simulation API design notes
for the current state of closed-chain support.
Next
Bodies now move and collide. The next section explains how DART finds and resolves those collisions: collisions & contacts.