Configuration
MuJoCo ROS configuration is intentionally parameter-driven. Launch files load YAML into the ROS parameter server, the server reads those parameters during setup and reload, and plugins receive their own nested configuration through MujocoPlugins.
Runtime Options
Runtime Options are the typed contract for reading and updating active MuJoCo
mjOption fields. ROS 1 exposes the same field names through dynamic
reconfigure. ROS 2 exposes them as regular node parameters. Python exposes
env.runtime_options and env.apply_runtime_options({...}).
Supported field names match RuntimeOptionsSnapshot:
Enumerations:
integrator,cone,jacobian,solverScalars:
timestep,iterations,tolerance,ls_iterations,ls_tolerance,noslip_iterations,noslip_tolerance,ccd_iterations,ccd_tolerance,sdf_iterations,sdf_initpoints,density,viscosity,impratio,marginSpace-delimited arrays:
gravity,wind,magnetic,solimp,solref,frictionDisable flags:
constraint_disabled,equality_disabled,frictionloss_disabled,limit_disabled,contact_disabled,passive_disabled,gravity_disabled,clampctrl_disabled,warmstart_disabled,filterparent_disabled,actuation_disabled,refsafe_disabled,sensor_disabled,midphase_disabled,eulerdamp_disabledEnable flags:
override_contacts,energy,fwd_inv,inv_discrete,multiccd,island
Legacy short names such as ls_iter, noslip_tol, and ccd_iter are
still accepted by the parser.
Updates use one transaction boundary. A rejected patch leaves every effective
field unchanged and does not advance the Options Epoch. Validation failures
identify the offending field. Python raises ValueError with
field + ": " + message; C++ and ROS adapters surface the same text.
During the Loading Window — from a model replacement request through completion
of model setup and generation activation — GetRuntimeOptions and
ApplyRuntimeOptions reject with Runtime Options unavailable during
Loading Window. Python raises RuntimeError with that message. Startup-only
patches may be supplied before the first model load through constructor
runtime_options or SetPendingRuntimeOptions; after loading begins that
path closes with Runtime Options startup options are unavailable after
loading begins.
Camera Configuration
MuJoCo cameras can publish ROS image streams without loading the sensors plugin.
Configure each named camera under cam_config/<camera_name>:
cam_config:
workspace_cam:
stream_type: 7
frequency: 15
width: 720
height: 480
use_segid: true
topic: cameras/workspace_cam
name_rgb: rgb
name_depth: depth
name_segment: segmented
stream_type is a bit mask: RGB is 1, depth is 2, and segmentation is 4.
Add values to enable multiple streams; 7 enables all three.
The default topic layout is:
cameras/<camera_name>/rgb/image_rawcameras/<camera_name>/rgb/camera_infocameras/<camera_name>/depth/image_rawcameras/<camera_name>/depth/camera_infocameras/<camera_name>/segmented/image_rawcameras/<camera_name>/segmented/camera_info
Relative topic values are resolved in the server namespace.
Absolute topics are used as provided. Rendering is lazy: an offscreen camera only renders the streams that currently have image or camera-info subscribers.
Python offscreen consumers add demand independently from ROS subscribers.
OffscreenCameraConfig::EnableFrames registers the same kind of RenderCore consumer for plugin and
in-process callers. SetGeomGroup and SetVisualFlag do not register one. Their requests use the same
RenderCore capture as ROS publication. A
Python request can therefore force a capture without replacing the configured
ROS cadence. When both paths consume a frame, the camera-specific capture
identity is shared.
Python borrowed frames are read-only NumPy views backed by a frame lease. The lease keeps the committed storage alive for the borrowed-view context. Use the copying buffer API when the data must remain stable across later captures, camera resize, or reload. Reload advances the frame generation and invalidates old Python camera handles. A borrowed view already acquired keeps its lease and remains readable. Acquire a new handle after reload.
Requesting RGB, depth, or segmentation when that plane is not enabled by
stream_type is a terminal error. It does not produce an empty frame.
Offscreen RenderCore and Frame Boundary
Offscreen rendering is coordinated by the core package through RenderCore,
which owns the Render Backend and the transport-neutral Frame Boundary.
The standalone mujoco_ros_render_core library links mujoco::mujoco and
the selected offscreen graphics target (EGL, OSMesa, GLFW when ANY/GUI
resolves to a hidden GLFW context, or none). Its public include graph does not
depend on ROS headers, MujocoEnv, pluginlib, or the visible viewer GLFW
stack. Visible GUI rendering remains outside this target.
Configure visible GLFW GUI with WITH_GUI (ON or OFF) and the
offscreen backend with OFFSCREEN_BACKEND (ANY, EGL, OSMESA, or
DISABLE). OFFSCREEN_BACKEND never accepts GLFW; with
WITH_GUI=ON the default ANY resolves to a hidden GLFW window/context
owned by the RenderCore thread (hosted CI uses Xvfb). ANY selects EGL
instead only when a /dev/dri/renderD* node exists and a probe finds a
non-software renderer. WITH_GUI=ON with OFFSCREEN_BACKEND=OSMESA fails
at configure time because OSMesa and the viewer’s libGL conflict in one
process; use EGL or ANY. With WITH_GUI=OFF, ANY prefers EGL,
then OSMesa. With WITH_GUI=OFF, when neither EGL nor OSMesa is available
and DISABLE is not selected, offscreen rendering is disabled rather than
silently falling back to another backend.
When the offscreen backend is EGL, teardown destroys the EGL context and
surface but does not call eglTerminate on the process display, so later
initialize or reload can reuse it. When a visible GLFW viewer shares the
process with an EGL RenderCore, the last GLFW library release also skips
glfwTerminate so viewer shutdown does not poison EGL GL state.
The Frame Boundary owns a bounded pool of frame slots and byte storage. Model
load and camera reconfiguration compute required capacity from camera layout and
Python history depth. When configured demand exceeds the RenderCore budget,
model setup fails loudly with an explicit error such as configured frame slot
capacity ... exceeds RenderCore frame boundary budget ... or configured
frame byte capacity ... exceeds RenderCore frame boundary byte budget .... The
server does not substitute empty frames or shrink history silently.
At runtime, capacity pressure is reported through explicit non-terminal
FrameStatusCode values such as kFrameSlotsExhausted (no free slot for a
new capture) and kGenerationCapacityExhausted (retained old-generation
leases block reconfiguration). These are not collapsed into
kTerminalError; rendering may remain unavailable until leases release and
the caller retries.
The render_backpressure_policy setting controls what happens when a
capture cannot obtain its bounded frame capacity. It defaults to drop,
which keeps physics submission non-blocking. wait_for_slot is opt-in:
the physics-side submission waits until capacity is available, while the
RenderCore render thread remains non-blocking. The wait is outside
physics_thread_mutex_ and is interrupted by cancellation, reload,
shutdown, or changing the policy back to drop. ROS 1 dynamic reconfigure,
ROS 2 parameters, and Python accept exactly drop and wait_for_slot;
invalid values are rejected without changing the effective policy.
Backend and graphics-context integrity failures are terminal. Examples include
render backend is disabled, backend is not initialized, and
graphics context initialization failed. Consumers observe these through
FrameStatusCode::kTerminalError, kBackendFailure, or
kBackendUnavailable (see IsContextIntegrityFailure) rather than blank
images.
Initial Joint States
Initial joint states are configured as maps from MuJoCo joint names to string values:
initial_joint_positions:
joint_map:
hinge_joint: "0.0"
ball_joint: "1 0 0 0"
free_joint: "0 0 1 1 0 0 0"
initial_joint_velocities:
joint_map:
hinge_joint: "0.0"
ball_joint: "0 0 0"
free_joint: "0 0 0 0 0 0"
The values are applied when the model loads, resets, reloads, or when load_initial_joint_states is called.
Evaluation Mode
eval_mode restricts operations that should not be available during evaluation.
Requests that change simulation state include an admin_hash field; in evaluation mode the request hash must match the server’s configured hash.
The sensors plugin also suppresses ground-truth topics in evaluation mode.