Continuous control environments and MuJoCo Python bindings for physics-based simulation and Reinforcement Learning
—
Object-oriented library for creating, manipulating, and composing MuJoCo MJCF (MuJoCo XML Configuration Format) models programmatically. Provides high-level abstractions for model elements while maintaining full compatibility with MuJoCo's XML format and enabling complex model composition.
Load MJCF models from various sources with full element hierarchy support.
def from_xml_string(xml_string: str) -> 'RootElement':
"""
Parse MJCF model from XML string.
Parameters:
- xml_string: Complete MJCF XML content as string
Returns:
RootElement representing the parsed model
Example:
>>> xml = '<mujoco><worldbody><body name="box"/></worldbody></mujoco>'
>>> model = mjcf.from_xml_string(xml)
"""
def from_path(path: str) -> 'RootElement':
"""
Parse MJCF model from file path.
Parameters:
- path: Path to MJCF XML file
Returns:
RootElement representing the loaded model
Example:
>>> model = mjcf.from_path('/path/to/model.xml')
"""
def from_file(file_object) -> 'RootElement':
"""
Parse MJCF model from file object.
Parameters:
- file_object: Open file object containing MJCF XML
Returns:
RootElement representing the parsed model
"""Core classes for representing MJCF model structure and hierarchy.
class RootElement:
"""
Root element of an MJCF model representing the complete model hierarchy.
Provides access to all model components and enables model-level operations
like compilation, attachment, and asset management.
"""
@property
def worldbody(self) -> 'Element':
"""Access to the worldbody element."""
@property
def asset(self) -> 'Element':
"""Access to the asset element."""
@property
def actuator(self) -> 'Element':
"""Access to actuator definitions."""
@property
def sensor(self) -> 'Element':
"""Access to sensor definitions."""
def find_all(self, tag: str) -> list:
"""
Find all elements with specified tag.
Parameters:
- tag: Element tag name to search for
Returns:
List of matching Element instances
"""
def compile_model(self) -> 'Physics':
"""
Compile MJCF model to Physics instance.
Returns:
Physics instance ready for simulation
"""
class Element:
"""
Base class for MJCF elements supporting attribute access and hierarchy.
Represents individual MJCF elements with dynamic attribute access,
parent-child relationships, and element-specific operations.
"""
@property
def tag(self) -> str:
"""Element tag name."""
@property
def parent(self) -> 'Element':
"""Parent element in hierarchy."""
def add(self, tag: str, **attributes) -> 'Element':
"""
Add child element with specified tag and attributes.
Parameters:
- tag: Child element tag name
- **attributes: Element attributes as keyword arguments
Returns:
Newly created child Element
Example:
>>> body = worldbody.add('body', name='box', pos=[0, 0, 1])
>>> geom = body.add('geom', type='box', size=[0.1, 0.1, 0.1])
"""
def remove(self) -> None:
"""Remove this element from parent."""
def find(self, tag: str, name: str = None) -> 'Element':
"""
Find first child element matching criteria.
Parameters:
- tag: Element tag to search for
- name: Optional name attribute to match
Returns:
First matching Element or None
"""
def find_all(self, tag: str) -> list:
"""
Find all child elements with specified tag.
Parameters:
- tag: Element tag to search for
Returns:
List of matching child Elements
"""Handle external assets like meshes, textures, and materials.
class Asset:
"""
Represents MJCF asset with file path and metadata.
Handles asset file paths, automatic copying, and asset referencing
within MJCF models.
"""
@property
def path(self) -> str:
"""Asset file path."""
@property
def prefix(self) -> str:
"""Asset name prefix for namespacing."""
def export_with_assets(model: 'RootElement', out_dir: str,
model_filename: str = 'model.xml') -> None:
"""
Export model with all referenced assets to directory.
Parameters:
- model: RootElement to export
- out_dir: Output directory path
- model_filename: Name for main model file (default: 'model.xml')
Creates directory containing model XML and all asset files with
correct relative paths preserved.
"""
def export_with_assets_as_zip(model: 'RootElement', zip_path: str,
model_filename: str = 'model.xml') -> None:
"""
Export model with assets as ZIP archive.
Parameters:
- model: RootElement to export
- zip_path: Output ZIP file path
- model_filename: Name for main model file (default: 'model.xml')
Creates ZIP archive containing model and all assets.
"""Tools for combining and modifying MJCF models.
def get_attachment_frame(element: 'Element') -> 'Element':
"""
Get attachment frame for element composition.
Parameters:
- element: Element to get attachment frame for
Returns:
Element representing the attachment frame
"""
def get_frame_freejoint(frame: 'Element') -> 'Element':
"""
Get free joint associated with frame.
Parameters:
- frame: Frame element
Returns:
Associated free joint Element or None
"""
def get_frame_joints(frame: 'Element') -> list:
"""
Get all joints associated with frame.
Parameters:
- frame: Frame element
Returns:
List of joint Elements
"""
def get_freejoint(body: 'Element') -> 'Element':
"""
Get free joint for body element.
Parameters:
- body: Body element
Returns:
Associated free joint Element or None
"""
def commit_defaults(root: 'RootElement') -> None:
"""
Commit default values throughout model hierarchy.
Parameters:
- root: Root element to process
Applies default values to all elements recursively.
"""PREFIX_SEPARATOR: str
"""Separator used in element name prefixing for model composition."""
class Physics:
"""MJCF-specific physics instance with enhanced model access."""
def bind(self, element: 'Element') -> object:
"""
Bind MJCF element to physics data.
Parameters:
- element: MJCF element to bind
Returns:
Bound physics data object
"""from dm_control import mjcf
# Create new model
model = mjcf.RootElement()
# Add basic structure
worldbody = model.worldbody
# Create a simple pendulum
pendulum_body = worldbody.add('body', name='pendulum', pos=[0, 0, 1])
pendulum_body.add('joint', name='hinge', type='hinge', axis=[0, 1, 0])
pendulum_body.add('geom', name='bob', type='sphere', size=[0.05],
rgba=[1, 0, 0, 1])
# Add actuator
model.actuator.add('motor', name='motor', joint='hinge', gear=[1])
# Compile to physics
physics = model.compile_model()# Load existing model
model = mjcf.from_path('/path/to/robot.xml')
# Find and modify elements
arm = model.find('body', name='arm')
if arm:
# Add new sensor
arm.add('site', name='wrist_site', pos=[0, 0, 0.1])
model.sensor.add('touch', name='wrist_sensor', site='wrist_site')
# Add new actuator
model.actuator.add('position', name='new_actuator',
joint='elbow_joint', kp=100)# Load base robot
robot = mjcf.from_path('/path/to/base_robot.xml')
# Load tool model
tool = mjcf.from_path('/path/to/tool.xml')
# Get attachment point
attachment_frame = robot.find('site', name='end_effector')
# Attach tool to robot (conceptual - actual attachment may require
# more complex operations depending on model structure)
if attachment_frame:
# This would typically involve more complex attachment logic
pass# Create model with assets
model = mjcf.RootElement()
# Add mesh asset
model.asset.add('mesh', name='custom_mesh', file='path/to/mesh.stl')
# Use asset in geometry
body = model.worldbody.add('body', name='custom_body')
body.add('geom', name='mesh_geom', type='mesh', mesh='custom_mesh')
# Export with assets
mjcf.export_with_assets(model, '/output/directory/')
# Or export as ZIP
mjcf.export_with_assets_as_zip(model, '/output/model.zip')# Create complex hierarchy
model = mjcf.from_path('/path/to/base.xml')
# Find all bodies
bodies = model.find_all('body')
for body in bodies:
print(f"Body: {body.name}, Mass: {body.get('mass', 'default')}")
# Add sensors to all bodies
for i, body in enumerate(bodies):
if body.name: # Only named bodies
site_name = f"{body.name}_site"
sensor_name = f"{body.name}_sensor"
body.add('site', name=site_name, pos=[0, 0, 0])
model.sensor.add('accelerometer', name=sensor_name, site=site_name)
# Commit defaults to finalize
mjcf.commit_defaults(model)# Create model and compile
model = mjcf.from_path('/path/to/model.xml')
physics = model.compile_model()
# Bind MJCF elements to physics data
hinge_joint = model.find('joint', name='hinge')
if hinge_joint:
joint_data = physics.bind(hinge_joint)
# Use bound data for direct physics accessInstall with Tessl CLI
npx tessl i tessl/pypi-dm-control