Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Google deepmind Dm control MJCF Attach

From Leeroopedia
Metadata
Knowledge Sources dm_control
Domains Physics Simulation, Robotics, Model Composition
Last Updated 2026-02-15 00:00 GMT

Overview

Concrete tool for composing multiple MJCF models into a single unified model via site.attach() and root.include_copy(), with automatic namespace scoping managed by the NameScope class.

Description

The MJCF Attach implementation provides two composition mechanisms:

1. site_element.attach(other_model)

This is the primary composition API, defined on _AttachableElement (which backs <site> and <worldbody> elements). The method:

  1. Validates that other_model is an RootElement, is not already attached, and is not the same model.
  2. Performs a dry run of the full attachment to detect any attribute conflicts before committing.
  3. Assigns a unique scope name if the child model's name already exists in the parent's namescope. A numeric suffix (e.g., model_1, model_2) is appended automatically.
  4. Sets other_model.namescope.parent = self.namescope, establishing the hierarchical prefix chain.
  5. Creates an _AttachmentFrame -- a specialized <body> element that inherits the site's position, orientation, and other spatial attributes. The frame is inserted as a sibling of the site, immediately after it (and after any existing attachment frames).
  6. Calls self.root._attach(other_model, exclude_worldbody=True) to merge all non-worldbody sections (actuators, sensors, defaults, etc.) into the parent model.
  7. Returns the attachment frame, which the caller can use to add joints or freejoints to give the attached model degrees of freedom.

2. root.include_copy(other_model, override_attributes=False)

This method copies all elements from other_model into the current model without creating a separate name scope. It uses the Copier class to deep-copy elements and then updates all internal references. This is the programmatic equivalent of the MJCF <include> directive.

3. root.detach()

Reverses a previous attachment by removing the child model's name scope from the parent and cleaning up the attachment frame.

NameScope (dm_control/mjcf/namescope.py) is the supporting data structure. Each scope maintains dictionaries of identifiers keyed by namespace (e.g., 'body', 'joint', 'geom'). The full_prefix() method computes the hierarchical prefix by walking up the parent chain and concatenating scope names with / separators. A revision counter is incremented on every structural change, enabling efficient cache invalidation for computed identifiers.

Usage

Use attach() to compose models with namespace isolation. Use include_copy() for flat merging without scoping. Use detach() to reverse an attachment.

Code Reference

Property Value
Source Location dm_control/mjcf/element.py:L986-1042 (attach), dm_control/mjcf/element.py:L1045-1105 (_AttachmentFrame), dm_control/mjcf/element.py:L1212-1268 (RootElement.attach, include_copy, detach), dm_control/mjcf/namescope.py:L1-215
Signature (attach) attach(attachment: RootElement) -> _AttachmentFrame
Signature (include_copy) include_copy(other: RootElement, override_attributes=False) -> None
Signature (detach) detach() -> None
Import from dm_control import mjcf

I/O Contract

Inputs (attach):

Parameter Type Description
attachment mjcf.RootElement The child model to attach. Must not already be attached elsewhere.

Inputs (include_copy):

Parameter Type Description
other mjcf.RootElement The model whose elements are copied into self.
override_attributes bool If True, conflicting attribute values in the source override those in the target.

Outputs:

Output Type Description
return value (attach) mjcf.Element (_AttachmentFrame) The attachment frame body; joints or freejoints can be added to it.
return value (include_copy) None Elements are copied in place.
side effect structural The child model's namescope becomes a child of the parent's namescope; all identifiers in the child gain a hierarchical prefix.

Usage Examples

from dm_control import mjcf

# Create an arena model
arena = mjcf.RootElement(model='arena')
arena.worldbody.add('geom', type='plane', size=[5, 5, 0.1])
spawn_site = arena.worldbody.add('site', name='spawn',
                                  pos=[0, 0, 0.5])

# Create a robot model
robot = mjcf.RootElement(model='robot')
torso = robot.worldbody.add('body', name='torso')
torso.add('geom', type='box', size=[0.1, 0.1, 0.1], mass=1.0)
torso.add('joint', name='slide_x', type='slide', axis=[1, 0, 0])
robot.actuator.add('motor', name='motor_x', joint='slide_x')

# Attach the robot to the arena at the spawn site
attachment_frame = spawn_site.attach(robot)

# Optionally add a freejoint to give the robot full freedom
attachment_frame.add('freejoint', name='root')

# Attach a second copy -- automatically gets scope name 'robot_1'
robot2 = mjcf.RootElement(model='robot')
torso2 = robot2.worldbody.add('body', name='torso')
torso2.add('geom', type='sphere', size=[0.05], mass=0.5)
spawn_site2 = arena.worldbody.add('site', name='spawn2',
                                   pos=[1, 0, 0.5])
spawn_site2.attach(robot2)

# Verify identifiers are properly scoped
print(arena.to_xml_string())
# Bodies will be named 'robot/torso' and 'robot_1/torso'

# Detach a model
robot.detach()

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment