DART Dynamics Module Exploration
July 7, 2026 · View on GitHub
Overview
This document provides an exploration of the core dynamics classes in DART (Dynamic Animation and Robotics Toolkit), located in the dart/dynamics directory.
Theory Reference: For the mathematical foundations (Lagrangian dynamics, equations of motion, recursive algorithms), see
docs/background/dynamics/— derived from C. Karen Liu and Sumit Jain's tutorial on multibody dynamics.
Coding Conventions
- Follow
CONTRIBUTING.mdfor formatting (two-space indentation, camelCase functions, PascalCase classes, no cuddled braces). - Always wrap conditional bodies in braces, even when the branch contains a single statement. This keeps future edits safe and matches the repository style enforced in current work.
Core Dynamics Classes
Algorithm-Centric Articulated Dynamics
RNEA and ABA traversal control flow lives in an internal algorithm layer that
operates through SkeletonDynamicsView, an adapter over the existing
Skeleton, BodyNode, and Joint pass kernels. Public Skeleton dynamics
entry points dispatch through this internal layer, so traversal order is not
duplicated across classes. The adapter keeps existing dirty caches and
soft-body overrides in the object-backed path while exposing indexed phases
that can be reused by future packed, cache-friendly, or SIMD-ready model
layouts.
Correctness and performance are evidence requirements for this layer. Unit
tests compare direct and batched ABA/RNEA adapter execution against explicit
legacy-recursion references and zero-DoF paths. The bm_dynamics_cache
legacy-reference, direct, uniform-batch, and heterogeneous-batch ABA/RNEA
benchmarks are the required local evidence before claiming a workload-specific
performance win or migrating more algorithms onto the abstraction. Extend the
adapter vocabulary before exposing new public BodyNode or Joint API.
1. Skeleton (Skeleton.hpp)
File Path: dart/dynamics/skeleton.hpp
Purpose: The Skeleton class represents a complete articulated rigid body system. It is the top-level container that manages the entire kinematic tree.
Key Features:
- Hierarchical Structure: Contains multiple trees of interconnected BodyNodes and Joints
- State Management: Manages positions, velocities, accelerations, forces, and commands for all degrees of freedom
- Configuration: Provides
Configurationstruct for joint configurations (positions, velocities, accelerations, forces, commands) - Properties:
- Name management
- Self-collision checking (with adjacent body checking option)
- Mobile/immobile status (for forward dynamics)
- Time step and gravity settings
Key Methods:
- Structure:
createJointAndBodyNodePair()- Creates Joint and BodyNode pairs - Kinematics:
computeForwardKinematics()- Computes transforms, velocities, and accelerations - Dynamics:
computeForwardDynamics()- Solves equations of motion forward in timecomputeInverseDynamics()- Computes required forces/torques for desired motion
- Equations of Motion:
getMassMatrix(),getInvMassMatrix()- Mass matrix operationsgetCoriolisForces(),getGravityForces()- Force vector computationsgetExternalForces(),getConstraintForces()- External and constraint forces
- Jacobians: Various Jacobian computation methods for kinematics analysis
- Center of Mass:
getCOM(),getCOMLinearVelocity(),getCOMJacobian()- COM-related functions - Integration:
integratePositions(),integrateVelocities()- Euler integration - Impulse-based Dynamics: Support for constraint impulses and impulse-based forward dynamics
Internal Structure:
- Manages multiple trees (allows for disconnected kinematic structures)
- Uses
DataCachefor computational efficiency - Implements dirty flags for lazy evaluation
- Support for IK (Inverse Kinematics) module
2. BodyNode (BodyNode.hpp)
File Path: dart/dynamics/body_node.hpp
Purpose: Represents a single rigid body (link) in the articulated system. BodyNodes are hierarchically connected through Joints.
Key Features:
-
Physical Properties:
- Mass
- Moment of inertia (spatial inertia)
- Center of mass (local COM)
- Friction and restitution coefficients (deprecated, now per-ShapeNode)
-
Kinematic Properties:
- Transform relative to parent
- Spatial velocity and acceleration
- Partial acceleration
- Body Jacobians (body frame and world frame)
-
Dynamic Properties:
- External forces and torques
- Body forces (transmitted from parent)
- Articulated body inertia
- Bias forces and impulses
-
Structural Properties:
- Parent and child BodyNodes
- Parent Joint
- Index within Skeleton and tree
- Gravity mode flag
- Collidable flag
Key Methods:
-
Property Management:
setMass(),getMass()setMomentOfInertia(),getMomentOfInertia()setLocalCOM(),getLocalCOM()setInertia(),getInertia()computeInertiaFromShapeNodes()- Aggregate ShapeNode inertias given a per-shape mass provider (handy for importers and tooling).
-
Kinematics:
getRelativeTransform()- Transform relative to parentgetJacobian(),getWorldJacobian()- Various Jacobian formsgetCOM(),getCOMLinearVelocity()- Center of mass kinematics
-
Dynamics:
addExtForce(),addExtTorque()- Apply external forcesgetBodyForce()- Get transmitted body forcecomputeKineticEnergy(),computePotentialEnergy()- Energy calculations
-
Structure Manipulation:
moveTo(),split(),copyTo(),copyAs()- Tree restructuring operationscreateChildJointAndBodyNodePair()- Create child nodesremove()- Remove subtree
-
ShapeNode Management:
createShapeNode()- Attach collision/visual shapesgetNumShapeNodesWith<Aspect>()/getShapeNodeWith<Aspect>(index)- Query shapes with specific aspectseachShapeNodeWith<Aspect>()- Iterate over shapesShapeNode::computeTransformedInertia()- Build adynamics::Inertiawith the ShapeNode’s relative transform already applied (useful when pulling mass properties from geometry).
-
Specialized Nodes:
- EndEffector support
- Marker support
Internal Dynamics Routines:
updateTransform(),updateVelocity()- Kinematic updatesupdateArtInertia()- Articulated body inertia computationupdateBiasForce(),updateBiasImpulse()- Bias force updatesupdateAccelerationFD(),updateAccelerationID()- Forward/Inverse dynamicsupdateMassMatrix(),aggregateMassMatrix()- Mass matrix assembly
3. Joint (Joint.hpp)
File Path: dart/dynamics/joint.hpp
Purpose: Abstract base class representing a kinematic constraint between two BodyNodes. Defines the degrees of freedom and their constraints.
Key Features:
-
Actuator Types:
FORCE- Force-controlled (dynamic)PASSIVE- No actuation (dynamic)SERVO- Servo-controlledMIMIC- Mimics another jointACCELERATION- Acceleration-controlled (kinematic)VELOCITY- Velocity-controlled (kinematic)LOCKED- Fixed (kinematic)
-
Degree of Freedom Management:
- Multiple DOFs per joint
- Position, velocity, acceleration, force for each DOF
- Position/velocity/acceleration/force limits
- Initial values for reset
-
Transformations:
- Transform from parent BodyNode to Joint
- Transform from child BodyNode to Joint
- Relative transform between parent and child
Key Methods (All Pure Virtual):
-
DOF Access:
getNumDofs()- Number of degrees of freedomgetDof(index)- Access specific DOFsetDofName(),getDofName()- DOF naming
-
Position Control:
setPosition(),getPosition()setPositionLowerLimit(),setPositionUpperLimit()isCyclic()- Check if DOF wraps aroundresetPosition(),setInitialPosition()
-
Velocity Control:
setVelocity(),getVelocity()setVelocityLowerLimit(),setVelocityUpperLimit()resetVelocity(),setInitialVelocity()
-
Acceleration Control:
setAcceleration(),getAcceleration()setAccelerationLowerLimit(),setAccelerationUpperLimit()resetAccelerations()
-
Force Control:
setForce(),getForce()setForceLowerLimit(),setForceUpperLimit()resetForces()
-
Commands:
setCommand(),getCommand()- Set desired commandsresetCommands()
-
Passive Forces:
setSpringStiffness(),getSpringStiffness()setRestPosition(),getRestPosition()setDampingCoefficient(),getDampingCoefficient()setCoulombFriction(),getCoulombFriction()
-
Kinematics:
getRelativeTransform()- Transform between bodiesgetRelativeSpatialVelocity(),getRelativeSpatialAcceleration()getRelativeJacobian(),getRelativeJacobianTimeDeriv()
-
Integration:
integratePositions(),integrateVelocities()getPositionDifferences()- Configuration space differences
-
Energy:
computePotentialEnergy()- Spring potential energy
-
Constraint Impulses:
setConstraintImpulse(),getConstraintImpulse()setVelocityChange(),getVelocityChange()
Mimic Joint Feature:
- Allows a joint to mimic the motion of another joint
- Supports different multipliers and offsets per DOF
- Useful for coupled mechanisms
Joint::setUseCouplerConstraint(true)swaps the legacy servo-style mimic motor for a bilateralCouplerConstraint, so both the reference and dependent joints feel equal-and-opposite impulses. Leave it disabled to keep the original MimicMotorConstraint behavior.- URDF
<transmission>blocks of typeSimpleTransmissionare parsed into coupled mimic joints when multiple joints share the same actuator; the gear ratio is derived from each joint'smechanicalReduction.
Internal Update Methods:
updateRelativeTransform(),updateRelativeSpatialVelocity()updateRelativeSpatialAcceleration(),updateRelativePrimaryAcceleration()updateRelativeJacobian(),updateRelativeJacobianTimeDeriv()- Various forward/inverse dynamics update methods
4. DegreeOfFreedom (DegreeOfFreedom.hpp)
File Path: dart/dynamics/degree_of_freedom.hpp
Purpose: Proxy class for accessing individual degrees of freedom (generalized coordinates). Provides a unified interface to control single DOFs.
Key Features:
-
Naming: Automatic naming based on Joint, with option to preserve custom names
-
Indexing:
- Index within Skeleton
- Index within tree
- Index within Joint
- Tree index
-
Properties: Access to all properties of a single DOF
- Commands
- Position (with limits)
- Velocity (with limits)
- Acceleration (with limits)
- Force (with limits)
- Initial values
- Passive force parameters (spring, damping, friction)
Key Methods:
-
Naming:
setName(),getName()preserveName()- Prevent automatic renaming
-
Indexing:
getIndexInSkeleton(),getIndexInTree(),getIndexInJoint()getTreeIndex()
-
State Access: Similar to Joint methods but for single DOF
- Position:
setPosition(),getPosition(), etc. - Velocity:
setVelocity(),getVelocity(), etc. - Acceleration, Force, Command methods
- Limits and initial values
- Position:
-
Relationships:
getJoint()- Parent JointgetSkeleton()- Parent SkeletongetChildBodyNode(),getParentBodyNode()- Connected bodies
Usage Pattern:
// Access DOF through Skeleton or Joint
DegreeOfFreedom* dof = skeleton->getDof(index);
dof->setPosition(value);
double pos = dof->getPosition();
5. Inertia (Inertia.hpp)
File Path: dart/dynamics/inertia.hpp
Purpose: Represents the inertial properties of a rigid body (mass, center of mass, moment of inertia).
Key Features:
-
Minimal Parameters:
- Mass
- Center of mass (3D vector)
- Moment of inertia (6 parameters: Ixx, Iyy, Izz, Ixy, Ixz, Iyz)
-
Spatial Inertia Tensor: 6x6 matrix representation for spatial dynamics
-
Validation: Methods to verify physical validity of inertia parameters
Key Capabilities:
- Manage minimal mass properties (mass, COM, moment of inertia) or work directly with the 6x6 spatial inertia tensor for Featherstone-style algorithms.
- Convert between parameter sets on demand; the class keeps the spatial tensor and scalar parameters in sync regardless of which representation is modified.
- Re-express an inertia in another frame using a provided transform, which internally applies the spatial adjoint to the tensor and updates the derived COM and moment quantities.
- Validate inputs (moments/spatial tensor) against physical constraints so that downstream dynamics code can safely assume well-formed inertias.
Physical Constraints:
- Mass must be positive
- Moment of inertia must be positive semi-definite
- Triangle inequality for principal moments
6. Shape (Shape.hpp)
File Path: dart/dynamics/shape.hpp
Purpose: Abstract base class for geometric shapes used for collision detection and visualization.
Key Features:
-
Shape Types: (legacy enumeration; prefer
Shape::getType()for new code)- Primitive shapes: Sphere, Box, Ellipsoid, Cylinder, Capsule, Cone, Pyramid
- Complex shapes: Mesh, SoftMesh, MultiSphere, HeightMap, LineSegment, Plane
-
Data Variance: Hints for renderers about what might change
STATIC- Nothing changesDYNAMIC_TRANSFORM- Transform might changeDYNAMIC_PRIMITIVE- Primitive properties might changeDYNAMIC_COLOR- Color/texture might changeDYNAMIC_VERTICES- Mesh vertices might changeDYNAMIC_ELEMENTS- Mesh topology might changeDYNAMIC- Everything might change
-
Bounding Box: Automatic computation for efficient collision detection
-
Volume: Automatic computation for mass properties
-
Inertia: Can compute inertia tensor from mass or density
Key Methods:
-
Type:
getType()- String representing shape typeis<Type>()- Template method for type checking (from Castable)
-
Geometry:
getBoundingBox()- Axis-aligned bounding boxgetVolume()- Enclosed volumecomputeInertia()- Inertia tensor computationcomputeInertiaFromDensity(),computeInertiaFromMass()
-
Data Variance:
setDataVariance(),getDataVariance()addDataVariance(),removeDataVariance()checkDataVariance()
-
Updates:
refreshData()- Update shape dataincrementVersion()- Notify subscribers of changes
-
Cloning:
clone()- Deep copy the shape
Usage: Shapes are typically attached to BodyNodes via ShapeNodes, which add additional aspects like visual appearance, collision properties, etc.
Key Relationships
Skeleton
├── Contains multiple BodyNode trees
├── Manages all Joint objects
└── Provides global DOF indexing
BodyNode (hierarchical tree structure)
├── Connected to parent BodyNode via parent Joint
├── Has multiple child BodyNodes (via child Joints)
├── Contains Inertia object (mass properties)
├── Has attached ShapeNodes (for collision/visualization)
│ └── Each ShapeNode references a Shape object
├── Has attached EndEffectors (for manipulation)
└── Has attached Markers (for tracking)
Joint (connection between BodyNodes)
├── Connects parent BodyNode to child BodyNode
├── Defines relative transformation
├── Contains multiple DegreeOfFreedom objects
└── Specifies motion constraints
DegreeOfFreedom
├── Belongs to a specific Joint
├── Represents a single generalized coordinate
└── Provides unified interface to DOF properties
Dynamics Computation Flow
Forward Kinematics
- Start from root BodyNode
- For each BodyNode in tree order:
- Update Joint transform (
updateRelativeTransform()) - Update BodyNode world transform
- Update spatial velocities
- Update spatial accelerations
- Update Joint transform (
Inverse Dynamics
- Forward kinematics (compute transforms, velocities, accelerations)
- Backward recursion from leaves to root:
- Compute spatial forces at each BodyNode
- Project forces to joint space to get required torques
Forward Dynamics
- Forward kinematics (transforms and velocities)
- Forward pass (root to leaves):
- Compute articulated body inertias
- Compute bias forces
- Backward pass (leaves to root):
- Compute joint accelerations
- Forward pass (root to leaves):
- Update body accelerations
Impulse-based Dynamics
Similar to forward dynamics but works with impulses and velocity changes instead of forces and accelerations. Used for contact resolution.
Important Design Patterns
1. Lazy Evaluation
- Uses dirty flags to avoid redundant computations
- Jacobians, mass matrices, force vectors are computed only when needed
- Example:
mNeedTransformUpdate,mIsBodyJacobianDirty
2. Aspect-Oriented Programming
- Uses Aspects to add properties/behaviors to classes
- Example: ShapeNode can have VisualAspect, CollisionAspect, DynamicsAspect
3. Smart Pointers
- Uses std::shared_ptr and std::weak_ptr for memory management
- Defines type aliases like SkeletonPtr, BodyNodePtr, etc.
4. Composite Pattern
- Skeleton contains trees of BodyNodes
- Each BodyNode can have multiple children
- Properties can be aggregated from components
5. Template Specialization
- GenericJoint
provides concrete joint types - TemplatedJacobianNode
provides Jacobian functionality
Common Joint Types (Derived from Joint)
While not in the files we examined, DART provides several concrete Joint types:
RevoluteJoint- 1-DOF rotational jointPrismaticJoint- 1-DOF translational jointUniversalJoint- 2-DOF joint (2 perpendicular revolute axes)BallJoint- 3-DOF rotational jointFreeJoint- 6-DOF joint (full spatial freedom)WeldJoint- 0-DOF joint (fixed connection)TranslationalJoint- 3-DOF translational jointPlanarJoint- 3-DOF planar joint (2 translations + 1 rotation)EulerJoint,QuaternionJoint- Various 3-DOF rotational representations
BallJoint and FreeJoint generalized positions use a coordinate chart (default:
exp-map/angle-axis). You can switch to Euler XYZ/ZYX via
setCoordinateChart(...) on each joint.
Usage Example (Conceptual)
// Create a skeleton
auto skeleton = Skeleton::create("MyRobot");
// Create root body and joint
auto [rootJoint, rootBody] = skeleton->createJointAndBodyNodePair<FreeJoint>();
rootBody->setMass(1.0);
rootBody->setMomentOfInertia(Ixx, Iyy, Izz);
// Add a child body
auto [joint1, body1] = rootBody->createChildJointAndBodyNodePair<RevoluteJoint>();
body1->setMass(0.5);
// Set joint properties
joint1->setPosition(0, 0.5); // Set position of first DOF
joint1->setPositionLimits(0, -dart::math::pi, dart::math::pi); // Set limits
// Add a shape for visualization/collision
auto shape = std::make_shared<BoxShape>(Eigen::Vector3d(0.1, 0.1, 0.5));
auto shapeNode = body1->createShapeNode(shape);
// Compute dynamics
skeleton->setGravity(Eigen::Vector3d(0, 0, -9.81));
skeleton->computeForwardDynamics();
// Access computed results
const Eigen::MatrixXd& M = skeleton->getMassMatrix();
const Eigen::VectorXd& C = skeleton->getCoriolisForces();
const Eigen::VectorXd& g = skeleton->getGravityForces();
MeshShape and TriMesh
Design Decision: MeshShape internally uses dart::math::TriMesh<double> for mesh representation instead of Assimp's aiScene*. This decouples mesh data from the loading library (Assimp), enabling format-agnostic mesh handling. The deprecated aiScene* API is maintained for backward compatibility via lazy on-demand conversion while DART 7 clean-break gates are being closed. For Filament rendering, materials/textures are accessed through getMaterials() (Assimp-free), while scene graph hierarchy uses the deprecated getMesh() only where source formats still require it. See dart/dynamics/mesh_shape.hpp and dart/io/mesh_loader.hpp for implementation.
PolygonMesh: dart::math::PolygonMesh<S> stores variable-length polygon faces (quads, n-gons) and provides deterministic triangulation via ear clipping. This preserves original mesh topology for rendering/export while the collision layer uses the triangulated TriMesh. See dart/math/polygon_mesh.hpp.
Summary
The DART dynamics module provides a comprehensive framework for:
- Modeling articulated rigid body systems with arbitrary topology
- Kinematics - Computing positions, velocities, accelerations, and Jacobians
- Dynamics - Computing forces, torques, mass matrices, and solving equations of motion
- Collision - Representing shapes and handling collision detection
- Constraints - Handling joint limits, contacts, and other constraints
- Control - Supporting various actuation models and control strategies
The modular design with clear separation between kinematics, dynamics, and geometry makes it suitable for robotics simulation, animation, and control applications.