# Working with Articulations and Kinematic Chains in the Newton Engine

> Master articulations and kinematic chains in the Newton engine. Use ArticulationView for high-performance joint manipulation across multiple simulation worlds.

- Repository: [Newton Physics/newton](https://github.com/newton-physics/newton)
- Tags: tutorial
- Published: 2026-03-19

---

**Use `ArticulationView` to create tensor-friendly, batched views of rigid-body articulations for high-performance manipulation of joints, DOFs, and kinematic chains across multiple simulation worlds.**

The Newton physics engine manages complex robotic systems through a specialized selection interface designed for batch operations. When working with articulations and kinematic chains in the Newton engine, developers leverage the `ArticulationView` class to build compact, regular memory layouts that treat selected bodies as dense tensors indexed by world and articulation instance.

## Understanding ArticulationView Architecture

### Public API and Internal Implementation

The public interface lives in [`newton/selection.py`](https://github.com/newton-physics/newton/blob/main/newton/selection.py), which re-exports the implementation from the internal utility module:

```python

# newton/selection.py

from ._src.utils.selection import ArticulationView

```

The core logic resides in [`newton/_src/utils/selection.py`](https://github.com/newton-physics/newton/blob/main/newton/_src/utils/selection.py) at lines 31-45, where the `ArticulationView` class parses the model, applies pattern-based filters, and computes contiguous or strided layouts for joints, DOFs, links, shapes, and MuJoCo tendons.

### Core Data Structures

The view relies on two primary internal structures to describe memory layouts:

**`FrequencyLayout`** (lines 12-28): Describes the offset, stride-between-worlds, stride-within-worlds, and selected indices for a specific attribute frequency (e.g., `JOINT`, `BODY`, `SHAPE`).

**`Slice`** (lines 93-105): A hashable mimic of Python's `slice` object used for caching computed layouts.

### Selection Workflow

The `ArticulationView` constructor executes a nine-step validation and layout process:

1. **Pattern matching**: `find_matching_ids` (lines 63-76) scans `model.articulation_label` against the user's glob pattern, returning per-world groups and global IDs.

2. **Validation**: Articulations must be either all per-world or all global; mixed selection raises `ValueError`. Uniform articulation counts per world are enforced.

3. **Template articulation**: The first matching articulation (`arti_0`) serves as a template to infer joint/link/shape ordering.

4. **Metadata gathering**: Loops over template joints to collect IDs, names, types, DOF ranges, and associated link/shape IDs.

5. **Stride computation**: Calculates outer stride (distance between consecutive worlds) and inner stride (distance between articulations within a world). Non-uniform strides raise `ValueError`.

6. **Filtering**: Applies `include_*`, `exclude_*`, and `*_types` arguments to build sets of selected indices.

7. **Layout creation**: Generates `FrequencyLayout` objects for `JOINT`, `JOINT_DOF`, `JOINT_COORD`, `BODY`, `SHAPE`, and `"mujoco:tendon"` when present.

8. **Mask building**: Creates `self.articulation_mask` boolean array for fast kernel masking.

9. **Property exposure**: Exposes `body_names`, `body_shapes` as aliases for link data and records contiguity flags (`self.joints_contiguous`, etc.) for optimization hints.

## Creating and Configuring Articulation Views

Instantiate a view by passing a `Model` instance and a selection pattern. Optional filters refine the selection to specific joints or links:

```python
import newton as nt

model = nt.load_model("my_robot.usd")
view = nt.selection.ArticulationView(
    model,
    pattern="robot*",                   # select articulations with labels starting with "robot"

    include_joints=["hip*", "knee"],    # only hip and knee joints

    exclude_links=["base_link"],        # omit the base link from the view

)

print("Selected joints:", view.joint_names)
print("Selected links :", view.link_names)

```

The view prints a concise summary when `verbose=True` (default follows `wp.config.verbose`).

## Reading and Writing Joint DOFs

The view provides tensor-friendly accessors for degrees of freedom (DOF) that maintain the `(worlds, articulations, dof)` layout:

```python
state = nt.State(model)

# Get DOF positions for all worlds/articulations in the view

q = view.get_dof_positions(state)    # shape: (worlds, artics, dof)

# Zero the first DOF of every articulation

q_np = q.numpy()
q_np[..., 0] = 0.0
view.set_dof_positions(state, q_np)  # writes back to the state

```

Internally, `get_dof_positions` calls `_get_attribute_array("joint_position", state)` (lines 84-119), which resolves the dotted attribute name to the `JOINT_DOF` frequency layout and returns a Warp array view respecting the computed strides.

## Accessing MuJoCo Tendon Attributes

When the model contains MuJoCo tendons, the view automatically creates a `"mujoco:tendon"` layout. Access tendon-specific attributes using dotted notation:

```python

# Read tendon stiffness (custom frequency)

tendon_stiff = view.get_attribute("mujoco.tendon_stiffness", state)
print("Tendon names:", view.tendon_names)
print("Stiffness shape:", tendon_stiff.shape)   # (worlds, artics, tendons)

```

The `_get_attribute_array` method handles the translation from `"mujoco.tendon_stiffness"` to the internal `"mujoco:tendon"` frequency, verifying that the view actually contains tendon data before returning the array view.

## Using Views in Warp Kernels

`ArticulationView` objects can be passed directly to Warp kernels, enabling GPU-accelerated manipulation of articulation data:

```python
@wp.kernel
def apply_ctrl(values: wp.array2d(dtype=float), view: nt.selection.ArticulationView):
    # values: (world, dof) control signal

    # Set joint torque directly through the view

    torque = view._get_attribute_array("joint_torque", ctrl)
    torque[:] = values

# Launch kernel

wp.launch(apply_ctrl, dim=(worlds, dof_per_articulation),
          inputs=[control_signal, view])

```

The kernel receives a **contiguous** `torque` array when the view's joint layout is contiguous; otherwise, the underlying strides are handled automatically by the Warp array view.

## Key Source Files

| File | Role | Direct link |
|------|------|-------------|
| [`newton/selection.py`](https://github.com/newton-physics/newton/blob/main/newton/selection.py) | Public re‑export of `ArticulationView` | [selection.py](https://github.com/newton-physics/newton/blob/main/newton/selection.py) |
| [`newton/_src/utils/selection.py`](https://github.com/newton-physics/newton/blob/main/newton/_src/utils/selection.py) | Full implementation of `ArticulationView`, layout computation, tendon handling | [selection.py (internal)](https://github.com/newton-physics/newton/blob/main/newton/_src/utils/selection.py) |
| [`newton/_src/sim.py`](https://github.com/newton-physics/newton/blob/main/newton/_src/sim.py) | Defines `Model`, `State`, `Control` and the `get_attribute_frequency` helper used by the view | [sim.py](https://github.com/newton-physics/newton/blob/main/newton/_src/sim.py) |
| [`newton/tests/test_kinematics.py`](https://github.com/newton-physics/newton/blob/main/newton/tests/test_kinematics.py) | Unit test that exercises `ArticulationView` for joint position / velocity extraction | [test_kinematics.py](https://github.com/newton-physics/newton/blob/main/newton/tests/test_kinematics.py) |
| [`newton/tests/test_selection.py`](https://github.com/newton-physics/newton/blob/main/newton/tests/test_selection.py) | Comprehensive tests covering filtering, tendon discovery, and layout validation | [test_selection.py](https://github.com/newton-physics/newton/blob/main/newton/tests/test_selection.py) |

## Summary

- **ArticulationView** creates tensor-friendly views of kinematic chains within Newton's `Model`, enabling batched operations across multiple worlds and robot instances.
- The class computes **strided layouts** for joints, DOFs, links, shapes, and MuJoCo tendons, ensuring efficient GPU access through Warp arrays.
- **Pattern matching** via `find_matching_ids` supports glob-style selection of articulations, with validation ensuring uniform per-world or global indexing.
- **Attribute access** uses `_get_attribute_array` to resolve dotted names (e.g., `mujoco.tendon_stiffness`) into frequency-specific layouts, returning contiguous or strided Warp views.
- The implementation spans [`newton/_src/utils/selection.py`](https://github.com/newton-physics/newton/blob/main/newton/_src/utils/selection.py) (core logic) and [`newton/selection.py`](https://github.com/newton-physics/newton/blob/main/newton/selection.py) (public API), with comprehensive test coverage in [`test_selection.py`](https://github.com/newton-physics/newton/blob/main/test_selection.py).

## Frequently Asked Questions

### What is the difference between global and per-world articulations in Newton?

Newton supports two indexing modes for articulations: **per-world** articulations exist independently within each simulation world, while **global** articulations share a single index across all worlds. `ArticulationView` requires that selected articulations be uniformly one mode or the other; mixing global and per-world indices raises a `ValueError` during construction.

### How does ArticulationView handle non-contiguous memory layouts?

The view automatically detects contiguity via flags like `self.joints_contiguous`. When data is contiguous, `ArticulationView` returns dense Warp arrays for maximum kernel performance. For non-contiguous selections, the view computes custom strides and offsets through `FrequencyLayout`, allowing kernels to access scattered data correctly without manual index translation.

### Can I filter articulations by specific joint types or link names?

Yes. The constructor accepts `include_joints`, `exclude_joints`, `include_links`, `exclude_links`, and type filters. These arguments apply after the initial pattern match, creating a subset view that only exposes the requested joints or links while maintaining the same tensor structure for the selected elements.

### What is the performance cost of using ArticulationView in simulation loops?

`ArticulationView` incurs a one-time setup cost during construction to compute layouts and validate selections. At runtime, attribute access via `_get_attribute_array` returns zero-copy Warp array views, meaning there is no per-step overhead for GPU kernels. The view's boolean mask (`articulation_mask`) enables fast filtering in parallel kernels without host-device synchronization.