urdf-mujoco-converter 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. urdf_mujoco_converter-0.1.0/.github/workflows/check.yml +18 -0
  2. urdf_mujoco_converter-0.1.0/.github/workflows/publish.yml +43 -0
  3. urdf_mujoco_converter-0.1.0/.gitignore +8 -0
  4. urdf_mujoco_converter-0.1.0/.python-version +1 -0
  5. urdf_mujoco_converter-0.1.0/AGENTS.md +11 -0
  6. urdf_mujoco_converter-0.1.0/PKG-INFO +58 -0
  7. urdf_mujoco_converter-0.1.0/README.md +43 -0
  8. urdf_mujoco_converter-0.1.0/docs/architecture.md +44 -0
  9. urdf_mujoco_converter-0.1.0/docs/conversion.md +279 -0
  10. urdf_mujoco_converter-0.1.0/docs/newton-compatibility.md +390 -0
  11. urdf_mujoco_converter-0.1.0/docs/publishing.md +26 -0
  12. urdf_mujoco_converter-0.1.0/examples/mimic.urdf +30 -0
  13. urdf_mujoco_converter-0.1.0/examples/physics.xml +12 -0
  14. urdf_mujoco_converter-0.1.0/justfile +11 -0
  15. urdf_mujoco_converter-0.1.0/pyproject.toml +53 -0
  16. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/__init__.py +13 -0
  17. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_common.py +97 -0
  18. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_config.py +553 -0
  19. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_convert.py +170 -0
  20. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_mesh.py +403 -0
  21. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_mjcf.py +305 -0
  22. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_urdf.py +92 -0
  23. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/_validation.py +166 -0
  24. urdf_mujoco_converter-0.1.0/src/urdf_mujoco_converter/cli.py +48 -0
  25. urdf_mujoco_converter-0.1.0/tests/test_conversion.py +396 -0
  26. urdf_mujoco_converter-0.1.0/tests/test_xml_config.py +207 -0
  27. urdf_mujoco_converter-0.1.0/tools/check_actuators.py +132 -0
  28. urdf_mujoco_converter-0.1.0/tools/check_newton.py +272 -0
  29. urdf_mujoco_converter-0.1.0/uv.lock +645 -0
@@ -0,0 +1,18 @@
1
+ name: Check
2
+ on: [push, pull_request]
3
+ jobs:
4
+ python:
5
+ runs-on: ubuntu-latest
6
+ strategy:
7
+ matrix:
8
+ python: ['3.11', '3.12']
9
+ env:
10
+ UV_PYTHON: ${{ matrix.python }}
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: astral-sh/setup-uv@v6
14
+ - run: uv sync --locked --python ${{ matrix.python }}
15
+ - run: uv run ruff check .
16
+ - run: uv run ruff format --check .
17
+ - run: uv run pytest
18
+ - run: uv build
@@ -0,0 +1,43 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags: ['v*']
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ if: startsWith(github.ref, 'refs/tags/v')
14
+ runs-on: ubuntu-latest
15
+ environment:
16
+ name: pypi
17
+ url: https://pypi.org/p/urdf-mujoco-converter
18
+ permissions:
19
+ contents: read
20
+ id-token: write
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: astral-sh/setup-uv@v6
24
+ - name: Verify release version
25
+ run: |
26
+ uv run --no-project --python 3.12 python - <<'PY'
27
+ import os
28
+ import tomllib
29
+ from pathlib import Path
30
+
31
+ version = tomllib.loads(Path('pyproject.toml').read_text())['project']['version']
32
+ assert os.environ['GITHUB_REF_NAME'] == f'v{version}', 'Tag must match project version'
33
+ PY
34
+ - run: uv sync --locked
35
+ - run: uv run ruff check .
36
+ - run: uv run ruff format --check .
37
+ - run: uv run pytest
38
+ - run: uv build
39
+ - uses: actions/upload-artifact@v4
40
+ with:
41
+ name: distributions
42
+ path: dist/*
43
+ - run: uv publish --trusted-publishing always
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ *.egg-info/
8
+ MUJOCO_LOG.TXT
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,11 @@
1
+ # Development rules
2
+
3
+ - Keep one URDF-to-MJCF conversion path and a small public Python interface.
4
+ - Follow Google Python Style Guide; use Google-style docstrings and type annotations.
5
+ - Use `uv` for environments, dependencies, tests, lint and builds.
6
+ - Keep physics explicit. Never invent inertials or silently drop articulation.
7
+ - Reject planar/floating URDF joints. Preserve scalar mimic, including valid chains.
8
+ - Keep scenes, root motion and controllers downstream. Accept explicitly authored native actuator XML; never choose drive gains or rewrite source geometry/inertials.
9
+ - Keep USD/Newton dependencies in separate integration environments.
10
+ - Run `just check` before handing off code changes.
11
+ - Do not commit or publish without user authorization.
@@ -0,0 +1,58 @@
1
+ Metadata-Version: 2.5
2
+ Name: urdf-mujoco-converter
3
+ Version: 0.1.0
4
+ Summary: Strict URDF to MJCF conversion with portable mesh assets.
5
+ Project-URL: Repository, https://github.com/ruziniuuuuu/urdf-mujoco-converter
6
+ Project-URL: Documentation, https://github.com/ruziniuuuuu/urdf-mujoco-converter/blob/main/docs/conversion.md
7
+ Project-URL: Issues, https://github.com/ruziniuuuuu/urdf-mujoco-converter/issues
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: mujoco<3.12,>=3.11
10
+ Requires-Dist: numpy<3,>=2
11
+ Requires-Dist: pillow<13,>=11
12
+ Requires-Dist: scipy<2,>=1.11
13
+ Requires-Dist: trimesh<5,>=4.6
14
+ Description-Content-Type: text/markdown
15
+
16
+ # urdf-mujoco-converter
17
+
18
+ Convert expanded URDF into validated MJCF with portable meshes and textures.
19
+ Preserves fixed frames, explicit inertials, scalar joints and mimic chains.
20
+ Requires Python 3.11+.
21
+
22
+ ```bash
23
+ uvx --from urdf-mujoco-converter==0.1.0 urdf-mujoco-converter \
24
+ robot.urdf output/robot --package robot_description=/path/to/robot_description \
25
+ --config physics.xml
26
+ ```
27
+
28
+ `uvx` installs the released tool in uv's cache; no project virtual environment or
29
+ source checkout is needed. Omit `--config` when no additional MJCF parameters are
30
+ required. Repeat it to compose native XML files. For a persistent CLI installation,
31
+ use `uv tool install urdf-mujoco-converter==0.1.0`.
32
+
33
+ ```python
34
+ from urdf_mujoco_converter import convert
35
+
36
+ result = convert(
37
+ "robot.urdf",
38
+ "output/robot",
39
+ packages={"robot_description": "/path/to/robot_description"},
40
+ config="physics.xml", # Optional native MJCF XML configuration.
41
+ )
42
+ print(result.mjcf_path)
43
+ ```
44
+
45
+ Output: `robot.xml`, `robot.meta.json`, `meshes/` and, when needed, `textures/`.
46
+ Each output directory belongs exclusively to one source URDF and is replaced
47
+ only after successful MuJoCo compilation.
48
+
49
+ OBJ, STL and static GLB are supported. `planar`/`floating` joints are errors.
50
+ Nonconvex collisions require explicit `--allow-convex-hull` approximation.
51
+ Native XML supplies explicit simulation settings, actuators and sensors.
52
+ Scenes, root motion and higher-level controllers remain downstream.
53
+
54
+ See [conversion contract](docs/conversion.md), [architecture](docs/architecture.md)
55
+ and [Newton/USD compatibility and checks](docs/newton-compatibility.md).
56
+
57
+ For development, clone the repository, run `uv sync --locked`, then `just check`
58
+ and `just build`. See [publishing](docs/publishing.md) for release maintenance.
@@ -0,0 +1,43 @@
1
+ # urdf-mujoco-converter
2
+
3
+ Convert expanded URDF into validated MJCF with portable meshes and textures.
4
+ Preserves fixed frames, explicit inertials, scalar joints and mimic chains.
5
+ Requires Python 3.11+.
6
+
7
+ ```bash
8
+ uvx --from urdf-mujoco-converter==0.1.0 urdf-mujoco-converter \
9
+ robot.urdf output/robot --package robot_description=/path/to/robot_description \
10
+ --config physics.xml
11
+ ```
12
+
13
+ `uvx` installs the released tool in uv's cache; no project virtual environment or
14
+ source checkout is needed. Omit `--config` when no additional MJCF parameters are
15
+ required. Repeat it to compose native XML files. For a persistent CLI installation,
16
+ use `uv tool install urdf-mujoco-converter==0.1.0`.
17
+
18
+ ```python
19
+ from urdf_mujoco_converter import convert
20
+
21
+ result = convert(
22
+ "robot.urdf",
23
+ "output/robot",
24
+ packages={"robot_description": "/path/to/robot_description"},
25
+ config="physics.xml", # Optional native MJCF XML configuration.
26
+ )
27
+ print(result.mjcf_path)
28
+ ```
29
+
30
+ Output: `robot.xml`, `robot.meta.json`, `meshes/` and, when needed, `textures/`.
31
+ Each output directory belongs exclusively to one source URDF and is replaced
32
+ only after successful MuJoCo compilation.
33
+
34
+ OBJ, STL and static GLB are supported. `planar`/`floating` joints are errors.
35
+ Nonconvex collisions require explicit `--allow-convex-hull` approximation.
36
+ Native XML supplies explicit simulation settings, actuators and sensors.
37
+ Scenes, root motion and higher-level controllers remain downstream.
38
+
39
+ See [conversion contract](docs/conversion.md), [architecture](docs/architecture.md)
40
+ and [Newton/USD compatibility and checks](docs/newton-compatibility.md).
41
+
42
+ For development, clone the repository, run `uv sync --locked`, then `just check`
43
+ and `just build`. See [publishing](docs/publishing.md) for release maintenance.
@@ -0,0 +1,44 @@
1
+ # Architecture
2
+
3
+ The public surface is `convert(...) -> ConversionResult`, `ConversionError` and
4
+ `Diagnostic` and `MjcfConfig`. The CLI only parses arguments, configures logging and calls that
5
+ function. Internal XML trees and implementation classes are private.
6
+
7
+ ```text
8
+ expanded URDF + optional scoped native XML fragments
9
+ -> validate graph, supported joints and mimic references
10
+ -> resolve local assets and export geometry/material parts
11
+ -> emit MJCF and source-joint metadata in a sibling staging directory
12
+ -> compose XML, resolve resources and enforce component ownership
13
+ -> compile with MuJoCo and verify source geometry/physics are unchanged
14
+ -> resolve equivalent native position damping to explicit kv
15
+ -> replace the directory owned by this source URDF
16
+ ```
17
+
18
+ | Module | Responsibility |
19
+ | --- | --- |
20
+ | `_convert.py` | Public operation, ownership checks, staging, compilation, publication |
21
+ | `_urdf.py` | URDF graph and mimic validation |
22
+ | `_mjcf.py` | Coordinates, inertials, joints, geometry bindings, metadata |
23
+ | `_mesh.py` | Resource resolution, scene transforms, material partitions, portable files |
24
+ | `_config.py` | Native XML composition, scoped names, references and resource closure |
25
+ | `_validation.py` | Native compilation, source invariants and actuator diagnostics |
26
+ | `_common.py` | Results, diagnostics and numeric/XML helpers |
27
+ | `cli.py` | Command-line arguments and exit status |
28
+
29
+ ElementTree is the source and destination representation. There is no second
30
+ robot IR, backend adapter hierarchy, plugin registry or configurable stage graph.
31
+ Per-conversion mesh/material caches belong to the exporter instance and cannot
32
+ leak across conversions. Adding another supported mesh format should extend this
33
+ boundary with representative tests, not add another conversion pipeline.
34
+
35
+ MuJoCo is a required validator. Newton and OpenUSD are optional integration tools
36
+ in separate environments, because their tested MuJoCo requirements differ.
37
+ `tools/check_newton.py` exercises the checked-in mimic example through both
38
+ import paths. It does not become a runtime dependency.
39
+
40
+ Use Google-style Python docstrings and typed interfaces. Run `just check` for
41
+ lint, formatting and behavioral tests, and `just build` for distribution artifacts.
42
+ Tests exercise `convert()` and compiled MuJoCo behavior. Asset-specific integration
43
+ results belong in the compatibility document; do not hardcode Galbot paths or
44
+ physical corrections into the converter.
@@ -0,0 +1,279 @@
1
+ # Conversion contract
2
+
3
+ ## Inputs and public API
4
+
5
+ ```python
6
+ convert(urdf_path, output_dir, *, config=None, packages=None,
7
+ allow_convex_hull=False) -> ConversionResult
8
+ ```
9
+
10
+ Input must be one expanded URDF file. Expand Xacro upstream; ROS is not required.
11
+ Relative resources resolve against the URDF directory, including legitimate `..`
12
+ references. Absolute local paths are accepted. `package://name/path` requires an
13
+ explicit `packages={"name": "/package/root"}` mapping and cannot escape that root.
14
+ Network URLs and missing resources are errors. GLB must embed buffers and images.
15
+
16
+ The result contains `mjcf_path`, `metadata_path`, `metadata` and `diagnostics`.
17
+ Invalid inputs raise `ConversionError`; filesystem failures may raise `OSError`.
18
+ The CLI accepts the same options through repeatable `--config`, repeatable
19
+ `--package NAME=PATH`, and `--allow-convex-hull`. Success prints the MJCF path to
20
+ stdout; diagnostics go to stderr; conversion failure exits with status 1.
21
+
22
+ ## Output and ownership
23
+
24
+ ```text
25
+ output_dir/
26
+ robot.xml
27
+ robot.meta.json
28
+ meshes/ # When mesh geometry exists.
29
+ textures/ # When textures exist.
30
+ ```
31
+
32
+ All file references in MJCF are relative and contained in this directory. Source
33
+ meshes are not modified. Generated filenames are unique sequential names, shared
34
+ within the conversion where possible. Output is movable without its source files.
35
+
36
+ A nonempty directory is replaceable only if its metadata identifies this generator
37
+ and the same absolute source URDF path. Never put hand-maintained files in it:
38
+ **the whole owned directory is replaced**. A different URDF must use a different
39
+ output directory. Input URDF/config/mesh/material resources cannot be inside the
40
+ output directory. Output-directory symlinks are rejected.
41
+
42
+ A sibling staging directory is compiled before publication. A sibling lock rejects
43
+ concurrent conversions to the same destination. Replacement uses a backup/rename
44
+ sequence with rollback if publication fails. This protects against normal
45
+ conversion errors; it is not a crash-durable filesystem transaction. If a process
46
+ is killed during publication, inspect sibling `.NAME.backup-*`/`.NAME.stage-*`
47
+ directories before removing the stale `.NAME.conversion.lock`. Do not remove the
48
+ lock while another conversion is active. Renaming a source file changes ownership.
49
+
50
+ ## Frames, physical data and joints
51
+
52
+ Units are metres, kilograms, seconds and radians. Link bodies retain original
53
+ names. Each child body uses the incoming URDF joint origin relative to its parent.
54
+ URDF RPY means `Rz(yaw) Ry(pitch) Rx(roll)`; MJCF quaternions use `w x y z`.
55
+ Joint axes are normalized in the joint/child-link frame; scalar joint refs are zero.
56
+ Fixed joints have no MJCF joint, but their link bodies remain, including massless
57
+ mounting frames. No free root joint or world anchor body is generated.
58
+ Actuators are added only when explicitly defined in the XML configuration.
59
+ The resulting root is stationary until the downstream loader adds motion.
60
+
61
+ Explicit mass and COM are preserved. Full symmetric inertias are rotated from the
62
+ URDF inertial frame into the link frame. No mesh-density inference, dummy mass or
63
+ automatic inertia balancing is used. Invalid positive-mass inertias are errors.
64
+ Zero-mass/zero-inertia fixed frames are allowed; missing moving-link physics must
65
+ still satisfy MuJoCo's actual compiler. Compilation is not physical calibration.
66
+
67
+ | URDF joint | Conversion |
68
+ | --- | --- |
69
+ | `fixed` | Body only; metadata maps to `[]` |
70
+ | `revolute` | Hinge with required ordered lower/upper limits |
71
+ | `continuous` | Unlimited hinge |
72
+ | `prismatic` | Slide with required ordered lower/upper limits |
73
+ | `planar`, `floating`, unknown | Explicit error before conversion |
74
+
75
+ Planar/floating are intentionally rejected, rather than approximated or ignored.
76
+ Compound mappings are possible in MuJoCo, but have different downstream import
77
+ semantics; see the compatibility document. Downstream root-motion configuration is
78
+ separate from support for these URDF joint types.
79
+
80
+ URDF joint damping maps to `damping`; friction maps to `frictionloss`. Effort and
81
+ velocity are source metadata only: the converter does not create control limits
82
+ or choose actuator gains. Explicit actuator XML controls clamping. Safety-controller, calibration, transmission, Gazebo and ros2_control
83
+ extensions are not converted and produce diagnostics when present.
84
+
85
+ Mimic maps to MJCF joint equality:
86
+
87
+ ```text
88
+ q_follower = offset + multiplier * q_leader
89
+ joint1 = follower; joint2 = leader; polycoef = [offset, multiplier, 0, 0, 0]
90
+ ```
91
+
92
+ Negative/zero multipliers, nonzero offsets and acyclic chains are supported.
93
+ Missing/fixed targets, cycles and mixing angular/linear joints are errors. Mimic
94
+ remains a **soft equality constraint**, not a reduced-coordinate substitution;
95
+ it retains scalar DOFs and may have numerical residuals. A nonzero offset may
96
+ make the all-zero initial state inconsistent. Choose a consistent initial pose
97
+ and solver parameters downstream; do not assume bit-exact kinematic coupling.
98
+ Conflicting follower/leader limits are not automatically reconciled.
99
+
100
+ ## Geometry and materials
101
+
102
+ Box, sphere and cylinder primitives are supported. Mesh inputs are OBJ, STL and
103
+ static GLB 2.0. Other mesh formats are explicitly rejected for now.
104
+
105
+ Scene instances and material partitions become separate geoms. Scene transforms
106
+ are applied before the URDF mesh scale, including nonuniform/negative scales;
107
+ normals use the inverse transpose and reflection winding is corrected. The URDF
108
+ visual/collision origin remains a geom transform. No surface simplification,
109
+ recentring or implicit unit conversion is applied.
110
+
111
+ Each exported OBJ contains one shape, with normals and UVs when available. A
112
+ single-triangle visual is subdivided into four triangles with interpolated UVs
113
+ and normals, preserving its surface, because MuJoCo requires four mesh vertices.
114
+ This produces an INFO diagnostic. Visual mesh assets use `inertia="shell"` so
115
+ planar surfaces compile; link inertias remain explicit (`inertiafromgeom=false`).
116
+
117
+ Visuals use `contype=0`, `conaffinity=0`, group 2. Collisions use group 3 and native
118
+ MuJoCo filtering. Each collision mesh/material part must be a closed convex solid.
119
+ Nonconvex/open collision meshes error by default. `allow_convex_hull=True` replaces
120
+ each offending part with a convex hull and emits a warning. It can fill holes and
121
+ bridge gaps; it does not perform convex decomposition. Even files named
122
+ `convex_hull` are checked. Provide separate convex parts upstream when appropriate.
123
+
124
+ Basic RGBA and base-color textures are retained. Textures become uniquely named
125
+ PNG files; OBJ material-library filenames are not relied on downstream. Explicit
126
+ URDF materials take precedence over mesh materials. GLTF PBR is approximated to
127
+ base color/texture with a warning: metallic/roughness, normal/emissive maps,
128
+ alpha modes and other lighting features are not reproduced. Color values follow
129
+ the mesh loader's basic-color interpretation, not a promise of colorimetric
130
+ identity across renderers. Mesh vertex/face colors must be uniform; varying colors
131
+ require a baked texture. Skinning, animation, morph targets, required GLTF
132
+ extensions, non-default UV sets and texture transforms are unsupported.
133
+
134
+ ## Native XML configuration
135
+
136
+ `config` accepts an XML path, a `MjcfConfig`, or a sequence of these. YAML and
137
+ Python property mappings are not accepted. CLI `--config` is repeatable.
138
+ Files use `<mujoco>` or `<mujocoinclude>` roots without attributes:
139
+
140
+ ```xml
141
+ <mujoco>
142
+ <option integrator="implicitfast" cone="elliptic" iterations="50">
143
+ <flag energy="enable"/>
144
+ </option>
145
+ <worldbody>
146
+ <body name="shoulder_link">
147
+ <joint name="shoulder" damping="0.5" armature="0.1"/>
148
+ <site name="tip" pos="0 0 0.1" size="0.01"/>
149
+ </body>
150
+ </worldbody>
151
+ <actuator>
152
+ <position name="shoulder_ctrl" joint="shoulder" kp="100"
153
+ dampratio="1" inheritrange="1" forcerange="-80 80"/>
154
+ </actuator>
155
+ <sensor><jointpos name="shoulder_position" joint="shoulder"/></sensor>
156
+ </mujoco>
157
+ ```
158
+
159
+ The XML layer does not maintain a physics-field whitelist. MuJoCo validates native
160
+ attributes, nested `option/flag`, defaults, actuator types, sensors, tendons,
161
+ contacts, equality constraints, custom data, keyframes and rendering settings.
162
+ Availability follows the installed MuJoCo version, within the source-authority
163
+ boundary below. Native `default` inheritance is retained: it does not override
164
+ attributes explicitly written on generated elements. Assign named classes or
165
+ explicitly update the relevant object. The compiler enables `autolimits` by
166
+ default; URDF joint limits remain explicit.
167
+
168
+ **Named updates are converter composition semantics, not native include semantics.**
169
+ A `worldbody/body` selects an existing URDF link body by name, without repeating
170
+ its full ancestry. Nested bodies must match their actual immediate parent.
171
+ Existing named joints/geoms update in place; missing targets fail. Geoms are named
172
+ `<link>_<visual|collision>_<URDF index>_<material part index>`, with zero-based indices.
173
+ Sites, cameras, lights and plugin attachments may be added to existing bodies.
174
+ Existing mimic equalities are named `mimic_<follower joint>` and may receive solver
175
+ parameters, but their joint references, polynomial and activation are protected.
176
+ New top-level definitions are added using ordinary MJCF elements. Duplicate names
177
+ or repeated assignments to the same setting fail, including across files; there
178
+ is no last-file-wins override mechanism.
179
+
180
+ URDF owns body/joint topology, geometry, frames, limits, mass and inertia. They
181
+ cannot be rewritten through XML configuration, including indirectly through
182
+ compiler/default settings. A native compilation before/after composition compares
183
+ source bodies, joints, geoms, meshes and mimic relations. New bodies/joints/geoms,
184
+ inertials, model attachment and deformable geometry belong in the source model or
185
+ a downstream scene, not this configuration layer. Invalid native features fail
186
+ compilation; nothing is silently omitted to make a model importable.
187
+
188
+ Use the optional descriptor for component ownership and repeated instances:
189
+
190
+ ```python
191
+ from urdf_mujoco_converter import MjcfConfig, convert
192
+
193
+ convert("robot.urdf", "output", config=[
194
+ "shared.xml",
195
+ MjcfConfig("hand.xml", prefix="left_", bodies=("palm", "finger")),
196
+ ])
197
+ ```
198
+
199
+ Here the expanded input URDF already contains `left_palm`, `left_finger`, etc.
200
+ The descriptor prefixes XML definitions and owned object references, including
201
+ mimic names, named default classes and typed sensor references. File paths and
202
+ plugin identifiers are not renamed. `bodies` declares unprefixed URDF links;
203
+ updates and references outside the component fail. Component defaults must be
204
+ named classes; `childclass` cannot leak into another component's descendants.
205
+ Global compiler/option/size/visual/statistic settings require a robot-wide or empty
206
+ body scope; keyframes require an unscoped document. Components may reference shared
207
+ assets/classes.
208
+
209
+ Local `<include file="..."/>` expands recursively, with cycle checking. Resources
210
+ resolve against the declaring XML file; compiler mesh/texture/asset directories
211
+ apply within that input document and are consumed during packaging. Assets are
212
+ copied into output `meshes/` or `textures/`; `strippath=true` is rejected because it
213
+ would break those references. Package URIs use the same explicit package map as
214
+ URDF resources. Missing files, input/output overlap and escaping package paths
215
+ fail. No network resources are fetched. Native plugin libraries must already be
216
+ registered in the runtime; they are not bundled as mesh resources.
217
+
218
+ Actuators use native clamping semantics and native `gear`, gains, transmission,
219
+ activation and control ranges. URDF effort/velocity metadata is not automatically
220
+ turned into motor limits. Position `inheritrange="1"` uses the current joint range;
221
+ force bounds must be explicit. A position servo does not enforce velocity limits.
222
+ Position damping ratios, including inherited defaults, are resolved by MuJoCo to
223
+ explicit `kv` before publication. This equivalence is logged and recorded; changing
224
+ downstream inertia does not retune the exported `kv` automatically.
225
+
226
+ See [examples/physics.xml](../examples/physics.xml). Native MJCF validity and
227
+ Newton/USD compatibility are separate requirements: run independent compatibility
228
+ checks for the intended downstream features; never silently discard unsupported
229
+ features or restrict the native configuration schema to Newton's current subset.
230
+
231
+ ## Metadata and diagnostics
232
+
233
+ ```json
234
+ {
235
+ "schema_version": 1,
236
+ "generated_by": "urdf-mujoco-converter",
237
+ "source_urdf": "/absolute/source/robot.urdf",
238
+ "joints": {
239
+ "shoulder": {
240
+ "urdf_type": "revolute",
241
+ "mjcf_joints": ["shoulder"],
242
+ "source_limits": {"effort": 80.0, "velocity": 2.0}
243
+ }
244
+ },
245
+ "diagnostics": []
246
+ }
247
+ ```
248
+
249
+ `source_urdf` is ownership/provenance, not a runtime resource dependency. Missing
250
+ source limit fields are omitted, not guessed. No unstable qpos/qvel indices are
251
+ stored. The sidecar is not automatically consumed by the USD converter or Newton.
252
+
253
+ `configuration` records input files, component scopes, prefixes and resource
254
+ dependencies. `simulation_profile.actuators` records compiled actuator names,
255
+ joint targets, gains, biases, clamping flags and ranges; multiple actuators on a
256
+ joint remain separate records. The final XML contains the complete native model.
257
+
258
+ Each diagnostic has `level`, `code`, `message`, `context`. Codes currently include
259
+ `xml_configuration`, `xml_parameter`, `resolved_damping_ratio`, `material_approximation`, `collision_convex_hull`,
260
+ `visual_triangle_subdivision`, `source_limits_metadata_only`, `downstream_extension`.
261
+ Identical notices are deduplicated per conversion. The library uses the standard
262
+ `urdf_mujoco_converter` logger without configuring global handlers; exceptions are
263
+ reported as ERROR by the CLI. Failed conversions return no success result.
264
+
265
+ An empty body scope (`bodies=()`) declares shared settings/assets without permission
266
+ to update or reference any URDF body, joint or geom. The asset library uses this
267
+ for its shared configuration; component files declare their owned bodies.
268
+
269
+ Native compilation is followed by a finite-number check: MuJoCo can warn and
270
+ accept NaN attributes, but the converter rejects nonfinite compiled fields.
271
+
272
+ In a separate Newton environment, `python tools/check_actuators.py MODEL.xml
273
+ MODEL.usda` compares joint-actuator gains, damping, transmissions, limits and
274
+ sampled forces through both import paths. It fails on mismatches or unsupported
275
+ transmissions/ambiguous targets. Importer warnings remain visible in its report;
276
+ this check does not certify other MJCF features or contact dynamics.
277
+
278
+ The same check is available as `just check-actuators NEWTON_PYTHON MODEL.xml MODEL.usda`,
279
+ where `NEWTON_PYTHON` is the Python executable in the separate Newton environment.