DART 7 · in development You are reading the documentation for DART 7, an in-progress redesign that is not yet recommended for production use. Looking for the current stable release? See the DART 6 LTS documentation.

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.

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.