# MetaSkeleton and ReferentialSkeleton in DART: A Practical Guide for Robotics Developers

> Explore MetaSkeleton and ReferentialSkeleton in DART. Discover how these DART features enable generic algorithms for partial models and multi-robot assemblies, enhancing robotics development.

- Repository: [DART: Dynamic Animation and Robotics Toolkit/dart](https://github.com/dartsim/dart)
- Tags: how-to-guide
- Published: 2026-02-28

---

**MetaSkeleton is a pure abstract interface that defines the complete kinematics and dynamics API for any collection of bodies, while ReferentialSkeleton is a concrete implementation that creates non-owning views onto subsets of one or more Skeletons, enabling generic algorithms to work on partial models or multi-robot assemblies without modification.**

The `MetaSkeleton` and `ReferentialSkeleton` classes in the [dartsim/dart](https://github.com/dartsim/dart) physics engine provide powerful abstractions for writing generic robotics algorithms. These interfaces allow you to write controllers, planners, and simulators that operate on any collection of body nodes and joints—whether that is a full robot model or just a view onto a specific subset—without requiring code changes between different use cases.

## What is MetaSkeleton in DART?

`MetaSkeleton` is a **pure abstract base class** defined in [[`dart/dynamics/meta_skeleton.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/meta_skeleton.hpp)](https://github.com/dartsim/dart/blob/main/dart/dynamics/meta_skeleton.hpp) that specifies the complete public API for querying the structural hierarchy, kinematic state, and dynamic properties of a set of bodies. Because it owns no data itself, it serves as a universal interface that concrete skeleton implementations must satisfy.

### Core Capabilities of MetaSkeleton

The interface provides several categories of functionality essential for robotics algorithms:

- **Structural queries** – Methods like `getNumBodyNodes()`, `getBodyNode(i)`, and `hasJoint(j)` provide read-only or mutable access to the underlying graph of **BodyNode**, **Joint**, and **DegreeOfFreedom** objects. This enables generic iteration over robot components regardless of the concrete container type.

- **State access** – Uniform getters and setters such as `getPositions()` and `setCommands()` allow algorithms to read and write generalized coordinates, velocities, and forces through a consistent interface.

- **Jacobians and dynamics** – The class declares methods including `getJacobian()`, `getWorldJacobian()`, `getMassMatrix()`, and `getCOM()`, ensuring that the same mathematical operations work identically whether operating on a full robot or a sub-model.

- **Signals and cloning** – `MetaSkeleton` provides `NameChangedSignal` for event notification and `cloneMetaSkeleton()` for creating independent copies, which is useful for thread-safe simulations or temporary "what-if" modeling.

- **Threading support** – The `getLockableReference()` method returns a `LockableReference` that protects concurrent access to underlying data structures, making the interface safe for multithreaded simulation environments.

### Why Use the Abstract Interface

Algorithms written against `MetaSkeletonPtr` or `MetaSkeleton&` are **implementation-agnostic**. A controller that accepts a `MetaSkeleton` works unchanged whether it receives a full `Skeleton` owning all bodies, a `Group` representing just a robot arm, or a custom view spanning multiple robots. This decouples your algorithmic code from the specific model structure.

## What is ReferentialSkeleton in DART?

`ReferentialSkeleton` is an **abstract concrete subclass** of `MetaSkeleton` defined in [[`dart/dynamics/referential_skeleton.hpp`](https://github.com/dartsim/dart/blob/main/dart/dynamics/referential_skeleton.hpp)](https://github.com/dartsim/dart/blob/main/dart/dynamics/referential_skeleton.hpp). Unlike `Skeleton`, which owns its components, `ReferentialSkeleton` implements the `MetaSkeleton` API by holding references—via `shared_ptr` or `weak_ptr`—to body nodes, joints, and DoFs from one or more existing `Skeleton` objects.

### Key Characteristics of ReferentialSkeleton

- **Non-owning views** – The class does not take ownership of the underlying bodies; it merely references them. The original `Skeleton` objects remain responsible for memory management and lifecycle.

- **Multi-skeleton aggregation** – A single `ReferentialSkeleton` can combine components from several different `Skeleton` instances, enabling coordinated control of multi-robot systems or bimanual manipulation scenarios.

- **Cache-aware implementation** – The class internally caches mass-matrix-related data and provides `updateCaches()` to refresh these structures when the underlying skeleton changes. Note that `getMass()` computes total mass in linear time (O(N)) because the view may span multiple skeletons with disjoint structures.

- **Concrete derived classes** – Higher-level utilities such as `Group` and `Linkage` inherit from `ReferentialSkeleton`. These classes provide user-friendly constructors while leveraging the view-based architecture.

### When to Choose ReferentialSkeleton

Use `ReferentialSkeleton` when you need to operate on **partial models** or **cross-robot coordination**:

- **Sub-model operations** – Control or analyze only a subset of a robot (e.g., an arm, hand, or kinematic chain) without copying the entire model or modifying the original `Skeleton`.

- **Multi-robot views** – Create a single interface that combines bodies from different robots, such as treating two independent manipulators as a single dual-arm system for coordinated planning.

- **High-level API building** – Build custom "virtual robots" using `Group` (user-defined collections) or `Linkage` (fixed-topology subsets) to expose simplified interfaces to motion planners or trajectory optimizers.

## Comparing Skeleton Types in DART

Understanding the relationship between these classes helps you select the appropriate abstraction for your use case:

- **`Skeleton`** – **Owns** its `BodyNode`s, `Joint`s, and `DoF`s. Use this for full robot models, simulation worlds, and loading from URDF/SDF files.

- **`MetaSkeleton`** – **Owns nothing** (pure interface). Use this as the parameter type for generic algorithms that need to query or control any collection of bodies.

- **`ReferentialSkeleton`** – **References** components from one or more `Skeleton`s. Use this for lightweight views, sub-models, or combining multiple robots into a single control interface.

## Practical Code Examples

The following examples demonstrate typical workflows using these abstractions.

### Example 1: Generic Algorithm Using MetaSkeleton

Write a controller that works on any skeleton implementation:

```cpp
#include <dart/dynamics/MetaSkeleton.hpp>

// A simple controller that drives all joints to a target position
void setTarget(dart::dynamics::MetaSkeletonPtr ms,
               const Eigen::VectorXd& target)
{
    assert(target.size() == ms->getNumDofs());
    ms->setPositions(target);  // Works for Skeleton or ReferentialSkeleton
}

```

This function accepts either a full `Skeleton` or a `ReferentialSkeleton` view without requiring template parameters or overloaded variants.

### Example 2: Building a Group (Concrete ReferentialSkeleton)

Create a view representing just the left arm of a humanoid robot:

```cpp
#include <dart/dynamics/Group.hpp>
#include <dart/dynamics/Skeleton.hpp>

auto robot = dart::dynamics::Skeleton::create("humanoid");
// ... load URDF/SDF ...

// Create a Group that only contains the right leg
auto rightLeg = std::make_shared<dart::dynamics::Group>("right_leg");

// Register body nodes; joints and DoFs are registered automatically
rightLeg->registerComponent(robot->getBodyNode("r_hip"));
rightLeg->registerComponent(robot->getBodyNode("r_knee"));
rightLeg->registerComponent(robot->getBodyNode("r_ankle"));

// Use the group like a normal skeleton
Eigen::VectorXd q = rightLeg->getPositions();
rightLeg->setCommands(Eigen::VectorXd::Zero(rightLeg->getNumDofs()));

```

Because `Group` inherits from `ReferentialSkeleton`, it provides all Jacobian, dynamics, and state-access methods while operating only on the selected subset.

### Example 3: Combining Multiple Robots via Custom ReferentialSkeleton

Implement a custom view that aggregates two independent robots:

```cpp
#include <dart/dynamics/ReferentialSkeleton.hpp>
#include <dart/dynamics/Skeleton.hpp>

class DualRobotView : public dart::dynamics::ReferentialSkeleton
{
public:
    DualRobotView(dart::dynamics::SkeletonPtr a,
                  dart::dynamics::SkeletonPtr b)
    {
        registerSkeleton(a.get());
        registerSkeleton(b.get());

        // Aggregate all body nodes from both robots
        for (std::size_t i = 0; i < a->getNumBodyNodes(); ++i)
            registerComponent(a->getBodyNode(i));
        for (std::size_t i = 0; i < b->getNumBodyNodes(); ++i)
            registerComponent(b->getBodyNode(i));

        // Refresh internal caches so Jacobians compute correctly
        updateCaches();
    }
};

// Usage
auto robotA = dart::dynamics::Skeleton::create("A");
auto robotB = dart::dynamics::Skeleton::create("B");
auto view = std::make_shared<DualRobotView>(robotA, robotB);
std::cout << "Total DoFs in view: " << view->getNumDofs() << std::endl;

```

This approach creates a unified `MetaSkeleton` interface spanning multiple independent models, useful for decentralized control algorithms that treat separate robots as a single kinematic chain.

## Summary

- **`MetaSkeleton`** provides a pure abstract interface in [`meta_skeleton.hpp`](https://github.com/dartsim/dart/blob/main/meta_skeleton.hpp) that decouples algorithms from concrete skeleton implementations, supporting generic controllers and planners.

- **`ReferentialSkeleton`** in [`referential_skeleton.hpp`](https://github.com/dartsim/dart/blob/main/referential_skeleton.hpp) implements this interface using non-owning references, enabling lightweight views onto partial models or multi-robot assemblies.

- **Use `Skeleton`** for complete robot models that own their data; **use `MetaSkeleton`** as the parameter type for generic code; **use `ReferentialSkeleton`** (via `Group`, `Linkage`, or custom subclasses) when you need views, subsets, or combined robot models.

- Key methods for views include `registerComponent()`, `registerSkeleton()`, and `updateCaches()` to maintain correct dynamic computations across referenced bodies.

## Frequently Asked Questions

### What is the difference between Skeleton and MetaSkeleton in DART?

`Skeleton` is a concrete class that owns its `BodyNode`s, `Joint`s, and degrees of freedom, managing their memory and lifecycle. `MetaSkeleton` is a pure abstract base class that defines the API for querying and controlling these components but owns nothing. `Skeleton` inherits from `MetaSkeleton`, allowing you to pass a `Skeleton` to any function expecting a `MetaSkeleton` reference or pointer.

### When should I use ReferentialSkeleton instead of a full Skeleton?

Use `ReferentialSkeleton` when you need to operate on a subset of bodies (such as a single arm of a humanoid) or combine bodies from multiple `Skeleton` instances without copying the underlying model data. It is ideal for creating lightweight views for controllers, avoiding the memory overhead of duplicating complex robot models while maintaining full access to kinematic and dynamic queries.

### How do I ensure thread safety when using MetaSkeleton across multiple threads?

Call `getLockableReference()` on your `MetaSkeleton` instance to obtain a `LockableReference` object. This reference provides mutex protection for the underlying data structures, ensuring that concurrent reads and writes to positions, velocities, or forces remain consistent. This mechanism is essential for multithreaded simulation environments where physics steps and controller updates run on separate threads.

### Can I clone a MetaSkeleton to create an independent copy for optimization or prediction?

Yes. The `MetaSkeleton` interface declares `cloneMetaSkeleton()`, which produces an identical but independent copy of the skeleton structure and state. This is particularly useful for creating temporary "what-if" scenarios in trajectory optimization, predictive control, or parallel simulation runs where you need to explore possible future states without affecting the original model.