Import upstream snapshot c19f713c415a699a79d71cd96aa13c3104a05047
nightly / Test against latest dependencies (py3.10) (push) Has been cancelled
nightly / Test against latest dependencies (py3.13) (push) Has been cancelled
tests / tests (3.13, locked) (push) Has been cancelled
tests / tests (3.13, unlocked) (push) Has been cancelled
tests / pyright (3.10) (push) Has been cancelled
tests / lint-format (push) Has been cancelled
tests / tests (3.10, locked) (push) Has been cancelled
tests / tests (3.11, locked) (push) Has been cancelled
tests / tests (3.12, locked) (push) Has been cancelled
tests / pyright (3.11) (push) Has been cancelled
tests / pyright (3.12) (push) Has been cancelled
tests / pyright (3.13) (push) Has been cancelled
tests / ty-check (3.10) (push) Has been cancelled
tests / ty-check (3.11) (push) Has been cancelled
tests / ty-check (3.12) (push) Has been cancelled
tests / ty-check (3.13) (push) Has been cancelled
tests / stubs (push) Has been cancelled
tests / smoke-test (push) Has been cancelled
Docker / check_paths (push) Has been cancelled
Docker / build (push) Has been cancelled
docs / build (push) Has been cancelled
nightly / Test against latest dependencies (py3.10) (push) Has been cancelled
nightly / Test against latest dependencies (py3.13) (push) Has been cancelled
tests / tests (3.13, locked) (push) Has been cancelled
tests / tests (3.13, unlocked) (push) Has been cancelled
tests / pyright (3.10) (push) Has been cancelled
tests / lint-format (push) Has been cancelled
tests / tests (3.10, locked) (push) Has been cancelled
tests / tests (3.11, locked) (push) Has been cancelled
tests / tests (3.12, locked) (push) Has been cancelled
tests / pyright (3.11) (push) Has been cancelled
tests / pyright (3.12) (push) Has been cancelled
tests / pyright (3.13) (push) Has been cancelled
tests / ty-check (3.10) (push) Has been cancelled
tests / ty-check (3.11) (push) Has been cancelled
tests / ty-check (3.12) (push) Has been cancelled
tests / ty-check (3.13) (push) Has been cancelled
tests / stubs (push) Has been cancelled
tests / smoke-test (push) Has been cancelled
Docker / check_paths (push) Has been cancelled
Docker / build (push) Has been cancelled
docs / build (push) Has been cancelled
Upstream: https://github.com/michaelgillett/mjlab Upstream-Commit: c19f713c415a699a79d71cd96aa13c3104a05047 Upstream-Branch: main
This commit is contained in:
@@ -0,0 +1,546 @@
|
||||
.. _faq:
|
||||
|
||||
FAQ & Troubleshooting
|
||||
=====================
|
||||
|
||||
This page collects common questions about **platform support**, **performance**,
|
||||
**training stability**, and **visualization**, along with practical debugging
|
||||
tips and links to further resources.
|
||||
|
||||
Platform Support
|
||||
----------------
|
||||
|
||||
Does it work on macOS?
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yes, but only with limited performance. mjlab runs on macOS
|
||||
using **CPU-only** execution through MuJoCo Warp.
|
||||
|
||||
- **Training is not recommended on macOS**, as it lacks GPU acceleration.
|
||||
- **Evaluation works**, but is significantly slower than on Linux with CUDA.
|
||||
|
||||
For serious training workloads, we strongly recommend **Linux with an NVIDIA GPU**.
|
||||
|
||||
Does it work on Windows?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
We have performed preliminary testing on **Windows** and **WSL**, but some
|
||||
workflows are not guaranteed to be stable.
|
||||
|
||||
- Windows support may **lag behind** Linux.
|
||||
- Windows will be **tested less frequently**, since Linux is the primary
|
||||
development and deployment platform.
|
||||
- Community contributions that improve Windows support are very welcome.
|
||||
|
||||
CUDA Compatibility
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Not all CUDA versions are supported by MuJoCo Warp.
|
||||
|
||||
- See `mujoco_warp#101 <https://github.com/google-deepmind/mujoco_warp/issues/101>`_
|
||||
for details on CUDA compatibility.
|
||||
- **Recommended**: CUDA **12.4+** (for conditional execution support in CUDA
|
||||
graphs).
|
||||
|
||||
How do I run on CPU without touching the GPU?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Passing ``device="cpu"`` puts all mjlab computation on the CPU, but it does
|
||||
**not** stop Warp from initializing the GPU. The first time Warp's runtime
|
||||
comes up, it eagerly enumerates and creates a CUDA context on **every**
|
||||
visible device, regardless of which device you requested. So on a machine
|
||||
with a visible GPU, a ``device="cpu"`` run still claims VRAM.
|
||||
|
||||
This happens inside Warp and cannot be prevented from Python once the
|
||||
package is imported. To keep the process entirely off the GPU, hide the
|
||||
devices from CUDA before launching:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
CUDA_VISIBLE_DEVICES="" uv run train.py ...
|
||||
|
||||
With no visible CUDA devices, Warp initializes CPU-only and never allocates
|
||||
on the GPU. See `issue #949
|
||||
<https://github.com/mujocolab/mjlab/issues/949>`_ for background.
|
||||
|
||||
Performance
|
||||
-----------
|
||||
|
||||
Is it faster than Isaac Lab?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Based on our experience over the last few months, mjlab is **on par or
|
||||
faster** than Isaac Lab.
|
||||
|
||||
What GPU do you recommend?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
- **RTX 40-series GPUs** (or newer)
|
||||
- **L40s, H100**
|
||||
|
||||
Does mjlab support multi-GPU training?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yes, mjlab supports **multi-GPU distributed training** using
|
||||
`torchrunx <https://github.com/apoorvkh/torchrunx>`_.
|
||||
|
||||
- Use ``--gpu-ids "[0, 1]"`` (or ``--gpu-ids all``) when running the ``train``
|
||||
command.
|
||||
- See the :doc:`training/distributed_training` for configuration details and examples.
|
||||
|
||||
Training & Debugging
|
||||
--------------------
|
||||
|
||||
My training crashes with NaN errors
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A typical error when using ``rsl_rl`` looks like:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
RuntimeError: normal expects all elements of std >= 0.0
|
||||
|
||||
This occurs when NaN/Inf values in the **physics state** propagate to the
|
||||
policy network, causing its output standard deviation to become negative or NaN.
|
||||
|
||||
There are many possible causes, including potential bugs in **MuJoCo Warp**
|
||||
(which is still in beta). mjlab offers two complementary mechanisms to help
|
||||
you handle this:
|
||||
|
||||
1. **For training stability** - NaN termination
|
||||
|
||||
Add a ``nan_detection`` termination to reset environments that hit NaN:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from mjlab.envs.mdp import terminations as mdp_term
|
||||
from mjlab.managers.termination_manager import TerminationTermCfg
|
||||
|
||||
# In your ManagerBasedRlEnvCfg subclass:
|
||||
terminations = {
|
||||
# Your other terminations...
|
||||
"nan_term": TerminationTermCfg(func=mdp_term.nan_detection),
|
||||
}
|
||||
|
||||
This marks NaN environments as terminated so they can reset while training
|
||||
continues. Terminations are logged as
|
||||
``Episode_Termination/nan_term`` in your metrics.
|
||||
|
||||
.. warning::
|
||||
|
||||
This is a **band-aid solution**. If NaNs correlate with your task objective
|
||||
(for example, NaNs occur exactly when the agent tries to grasp an object),
|
||||
the policy will never learn to complete that part of the task. Always
|
||||
investigate the **root cause** using ``nan_guard`` in addition to this
|
||||
termination.
|
||||
|
||||
2. **For debugging** - NaN guard
|
||||
|
||||
Enable ``nan_guard`` to capture the simulation state when NaNs occur:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
uv run train.py --enable-nan-guard True
|
||||
|
||||
See the :doc:`NaN Guard documentation <debugging/nan_guard>` for details.
|
||||
|
||||
The ``nan_guard`` tool makes it easier to:
|
||||
|
||||
- Inspect the simulation state at the moment NaNs appear.
|
||||
- Build a minimal reproducible example (MRE).
|
||||
- Report potential framework bugs to the
|
||||
`MuJoCo Warp team <https://github.com/google-deepmind/mujoco_warp/issues>`_.
|
||||
|
||||
Reporting well-isolated issues helps improve the framework for everyone.
|
||||
|
||||
How can I inspect the generated scene XML?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use the ``export-scene`` script to write the full scene (XML and mesh assets)
|
||||
to a directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
uv run export-scene g1 --output-dir /tmp/g1
|
||||
|
||||
The exported ``scene.xml`` can be loaded directly in MuJoCo for visual
|
||||
inspection or diffing. This is useful for verifying that task configuration
|
||||
and physics are set up correctly, and for creating minimal reproducible
|
||||
examples to share with mjlab or MuJoCo Warp developers. The script accepts task IDs,
|
||||
entity aliases (``g1``, ``go1``, ``yam``), or arbitrary import paths. See
|
||||
:doc:`debugging/export_scene` for full details.
|
||||
|
||||
My contact sensor misses collisions when using decimation
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
With ``decimation > 1`` the physics runs multiple substeps per policy
|
||||
step. A brief contact (e.g. a self collision or an illegal ground touch)
|
||||
can appear and disappear within the substep loop, so by the time the
|
||||
sensor is read, ``found`` is zero and the event is invisible to
|
||||
rewards and terminations.
|
||||
|
||||
Set ``history_length`` on the ``ContactSensorCfg`` equal to your
|
||||
decimation value. The sensor then stores force, torque, and distance
|
||||
for the last *N* substeps. Your reward or termination function can
|
||||
inspect the history to detect contacts that would otherwise be missed:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ContactSensorCfg(
|
||||
name="self_collision",
|
||||
...,
|
||||
fields=("found", "force"),
|
||||
history_length=4, # matches decimation=4
|
||||
)
|
||||
|
||||
# In the reward/termination function:
|
||||
force_mag = torch.norm(sensor.data.force_history, dim=-1) # [B, N, H]
|
||||
had_contact = (force_mag > 10.0).any(dim=1).any(dim=-1) # [B]
|
||||
|
||||
See :ref:`contact-sensor-history` for full details.
|
||||
|
||||
.. note::
|
||||
|
||||
Feet ground sensors with ``track_air_time=True`` already accumulate
|
||||
contact state across substeps, so they do not need history.
|
||||
|
||||
.. _faq-sim-forward:
|
||||
|
||||
When do I need to call ``sim.forward()``?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Short answer: you almost certainly don't.
|
||||
|
||||
``sim.forward()`` wraps MuJoCo's ``mj_forward``, which runs the full forward
|
||||
dynamics pipeline (kinematics, contacts, forces, constraint solving, sensors)
|
||||
but skips integration, leaving ``qpos``/``qvel`` unchanged. It brings all
|
||||
derived quantities in ``mjData`` (``xpos``, ``xquat``, ``site_xpos``,
|
||||
``cvel``, ``sensordata``, etc.) into a consistent state with the current
|
||||
``qpos``/``qvel``.
|
||||
The environment's ``step()`` method calls it once per step, right before
|
||||
observation computation, so observations and commands always see fresh
|
||||
derived quantities. Termination, reward, and step/interval events run
|
||||
*before* this call and therefore see derived quantities that are stale by
|
||||
one physics substep, a deliberate tradeoff that avoids a second
|
||||
``forward()`` call while keeping the MDP well-defined (the staleness is
|
||||
consistent across all envs and all steps). Because events run before the
|
||||
call, any state they write (e.g. a velocity push) is refreshed by it and
|
||||
visible to the same step's observations.
|
||||
|
||||
The one case where this matters is if you write an event or command that
|
||||
both writes state and reads derived quantities in the same function. For
|
||||
example, if Event A calls ``entity.write_root_velocity_to_sim()`` (which
|
||||
modifies ``qvel``) and then immediately reads ``entity.data.root_link_vel_w``
|
||||
(which comes from ``cvel``), the read will see stale values from before the
|
||||
write.
|
||||
|
||||
.. warning::
|
||||
|
||||
Write methods (``write_root_state_to_sim``, ``write_joint_state_to_sim``,
|
||||
etc.) modify ``qpos``/``qvel`` directly. Read properties
|
||||
(``root_link_pose_w``, ``body_link_vel_w``, etc.) return derived
|
||||
quantities that are only current as of the last ``sim.forward()`` call.
|
||||
If you need to write then read in the same function, call
|
||||
``env.sim.forward()`` between them.
|
||||
|
||||
For a deeper explanation, see `Discussion #289
|
||||
<https://github.com/mujocolab/mjlab/discussions/289>`_.
|
||||
|
||||
Why aren't my training runs reproducible even with a fixed seed?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
MuJoCo Warp does not yet guarantee determinism, so running the same
|
||||
simulation with identical inputs may produce slightly different outputs.
|
||||
This is a known limitation being tracked in
|
||||
`mujoco_warp#562 <https://github.com/google-deepmind/mujoco_warp/issues/562>`_.
|
||||
|
||||
Until determinism is implemented upstream, mjlab training runs will not be
|
||||
perfectly reproducible even when setting a seed.
|
||||
|
||||
My XML ``<option>`` flags are not taking effect
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If you set simulation options like ``<flag contact="disable"/>`` in your
|
||||
entity XML, they will be silently ignored. This is because mjlab composes
|
||||
scenes by attaching entity specs into a parent scene spec using
|
||||
``MjSpec.attach()``, which does not propagate ``<option>`` settings from
|
||||
the child to the parent. This is a MuJoCo design decision: there is no
|
||||
sensible way to merge engine options (timestep, gravity, solver settings,
|
||||
etc.) across multiple attached models.
|
||||
|
||||
To configure simulation options, use :class:`~mjlab.sim.sim.MujocoCfg` in
|
||||
your task's Python config:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from mjlab.sim.sim import MujocoCfg, SimulationCfg
|
||||
|
||||
sim=SimulationCfg(
|
||||
mujoco=MujocoCfg(
|
||||
disableflags=("contact",),
|
||||
# timestep=0.01, gravity=(0, 0, -9.81), etc.
|
||||
),
|
||||
)
|
||||
|
||||
``MujocoCfg`` applies options directly to the compiled model, so they
|
||||
always take effect. mjlab will emit a warning if it detects non-default
|
||||
``<option>`` fields on an attached entity spec.
|
||||
|
||||
Rendering & Visualization
|
||||
-------------------------
|
||||
|
||||
What visualization options are available?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
mjlab currently supports two visualizers for policy evaluation and
|
||||
debugging:
|
||||
|
||||
- **Native MuJoCo visualizer** - the built-in visualizer that ships with MuJoCo.
|
||||
- **Viser** - `Viser <https://github.com/nerfstudio-project/viser>`_,
|
||||
a web-based 3D visualization tool.
|
||||
|
||||
We are exploring **training-time visualization** (e.g., live rollout viewers),
|
||||
but this is not yet available.
|
||||
|
||||
As an alternative, mjlab supports **video logging to Weights & Biases
|
||||
(W&B)**, so you can monitor rollout videos directly in the experiment dashboard.
|
||||
|
||||
How many environments can I visualize at once?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Viewers render a small number of environments for performance reasons.
|
||||
|
||||
- **Offscreen renderer** (for video recording): Renders the tracked
|
||||
environment plus its nearest neighbors. The count is controlled by
|
||||
``ViewerConfig.max_extra_envs`` (default 2).
|
||||
- **Native/Viser viewers**: Limited by MuJoCo's geometry buffer
|
||||
(default 10,000 geoms). The viewer shows whichever environments fit
|
||||
within the geometry budget.
|
||||
|
||||
Why are my fixed-base robots all stacked at the origin instead of in a grid?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Fixed-base robots require an **explicit reset event** to position them at
|
||||
their ``env_origins``. If your robots appear stacked at (0, 0, 0):
|
||||
|
||||
**Common causes:**
|
||||
|
||||
1. **Missing reset event** - Most common issue.
|
||||
2. **env_spacing is 0 or very small** - Check your ``SceneCfg(env_spacing=...)``.
|
||||
Even with proper reset events, if ``env_spacing=0.0``, all robots will
|
||||
be at the same position. If ``env_spacing`` is very small (e.g., 0.01),
|
||||
they'll be clustered in a tiny area that looks like a line from a distance.
|
||||
|
||||
**Solution**: Add a reset event that calls ``reset_root_state_uniform``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# In your ManagerBasedRlEnvCfg
|
||||
events = {
|
||||
# For positioning the base of the robot at env_origins.
|
||||
"reset_base": EventTermCfg(
|
||||
func=mdp.reset_root_state_uniform,
|
||||
mode="reset",
|
||||
params={
|
||||
"pose_range": {}, # Empty = use default pose + env_origins
|
||||
"velocity_range": {},
|
||||
},
|
||||
),
|
||||
# ... other events
|
||||
}
|
||||
|
||||
This pattern is used in the example manipulation task (see ``lift_cube_env_cfg.py:85-94``).
|
||||
|
||||
**Why this is needed**: Fixed-base robots are automatically wrapped in mocap
|
||||
bodies by ``auto_wrap_fixed_base_mocap()``, but mocap positioning only happens
|
||||
when you explicitly call a reset event. The ``env_origins`` offset is applied
|
||||
inside ``reset_root_state_uniform()`` at line 131 of ``envs/mdp/events.py``.
|
||||
|
||||
See `issue #560 <https://github.com/mujocolab/mjlab/issues/560>`_ for examples.
|
||||
|
||||
How does env_origins determine robot layout?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Robot spacing depends on your terrain configuration:
|
||||
|
||||
**Plane terrain** (``terrain_type="plane"``):
|
||||
- Creates an approximately square grid automatically
|
||||
- Grid size: ``ceil(sqrt(num_envs))`` rows x cols
|
||||
- Spacing controlled by ``env_spacing`` parameter (default: 2.0m)
|
||||
- Examples with ``env_spacing=2.0``:
|
||||
- 32 envs → 7x5 grid spanning 12m x 8m
|
||||
- 4096 envs → 64x64 grid spanning 126m x 126m
|
||||
- **Important**: If ``env_spacing=0``, all robots will be at (0, 0, 0)
|
||||
- Implementation: ``terrain_importer.py:_compute_env_origins_grid()``
|
||||
|
||||
**Procedural terrain** (``terrain_type="generator"``):
|
||||
- Origins loaded from pre-generated terrain sub-patches
|
||||
- Grid size: ``TerrainGeneratorCfg.num_rows x num_cols``
|
||||
- Row index = difficulty level (curriculum mode)
|
||||
- Column index = terrain type variant
|
||||
- **Important allocation behavior**: Columns (terrain types) are evenly distributed
|
||||
across environments, but rows (difficulty levels) are randomly sampled. This means
|
||||
multiple environments can spawn on the same (row, col) patch, leaving others unoccupied,
|
||||
even when ``num_envs > num_patches``.
|
||||
- Example: 5x5 grid (25 patches), 100 envs → each column gets exactly 20 envs,
|
||||
but those 20 are randomly distributed across 5 rows, so some patches remain empty.
|
||||
- Supports ``randomize_env_origins()`` to shuffle positions during training
|
||||
|
||||
How do I ensure each terrain type gets its own column?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Set ``curriculum=True`` in your ``TerrainGeneratorCfg``. This makes column
|
||||
allocation deterministic, with each column getting one terrain type based on
|
||||
normalized proportions.
|
||||
|
||||
Example with 2 terrain types:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
TerrainGeneratorCfg(
|
||||
num_rows=3,
|
||||
num_cols=2,
|
||||
curriculum=True, # Required for deterministic column allocation!
|
||||
sub_terrains={
|
||||
"flat": BoxFlatTerrainCfg(proportion=0.5), # Gets column 0
|
||||
"pillars": HfDiscreteObstaclesTerrainCfg(
|
||||
proportion=0.5, # Gets column 1
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
Without ``curriculum=True``, every patch is randomly sampled and you'll get
|
||||
a random mix of both terrain types scattered across all patches.
|
||||
|
||||
**Note**: When ``num_cols`` equals the number of terrain types, each terrain
|
||||
gets exactly one column regardless of proportion values (they're normalized).
|
||||
When ``num_cols > num_terrain_types``, proportions determine how many columns
|
||||
each terrain type occupies.
|
||||
|
||||
What is flat patch sampling and how does it affect robot spawning?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Flat patch sampling detects flat regions on heightfield terrains where robots
|
||||
can safely spawn. It uses morphological filtering on the heightfield to find
|
||||
circular areas where height variation is within a tolerance.
|
||||
|
||||
Configure it on any sub-terrain via ``flat_patch_sampling``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from mjlab.terrains.terrain_generator import FlatPatchSamplingCfg
|
||||
|
||||
"obstacles": HfDiscreteObstaclesTerrainCfg(
|
||||
...,
|
||||
flat_patch_sampling={
|
||||
"spawn": FlatPatchSamplingCfg(
|
||||
num_patches=10, # patches to sample per sub-terrain
|
||||
patch_radius=0.5, # flatness check radius (meters)
|
||||
max_height_diff=0.05, # max height variation within radius
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
Then use ``reset_root_state_from_flat_patches`` as your reset event to spawn
|
||||
robots on detected patches instead of at the sub-terrain center.
|
||||
|
||||
**Key details:**
|
||||
|
||||
- Only heightfield (``Hf*``) terrains support actual flat patch detection.
|
||||
Box terrains (``Box*``) don't have heightfield data to analyze.
|
||||
- If any sub-terrain in the grid configures ``flat_patch_sampling``, the
|
||||
flat patches array is allocated for **all** cells. Sub-terrains that don't
|
||||
produce patches have their slots filled with the sub-terrain's spawn origin,
|
||||
so ``reset_root_state_from_flat_patches`` always gets valid positions.
|
||||
- Without ``flat_patch_sampling``, use ``reset_root_state_uniform`` which
|
||||
spawns at the sub-terrain origin (``env_origins``) plus an optional random
|
||||
offset.
|
||||
|
||||
Development & Extensions
|
||||
------------------------
|
||||
|
||||
Can I develop custom tasks in my own repository?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Yes, mjlab has a **plugin system** that lets you develop tasks in separate
|
||||
repositories while still integrating seamlessly with the core:
|
||||
|
||||
- Your tasks appear as regular entries for the ``train`` and ``play`` commands.
|
||||
- You can version and maintain your task repositories independently.
|
||||
|
||||
A complete guide will be available in a future release.
|
||||
|
||||
Assets & Compatibility
|
||||
----------------------
|
||||
|
||||
What robots are included?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
mjlab includes two **reference robots**:
|
||||
|
||||
- **Unitree Go1** (quadruped).
|
||||
- **Unitree G1** (humanoid).
|
||||
|
||||
These robots serve as:
|
||||
|
||||
- Minimal examples for **robot integration**.
|
||||
- Stable, well-tested baselines for **benchmark tasks**.
|
||||
|
||||
To keep the core library lean, we do **not** plan to aggressively expand the
|
||||
built-in robot library. Additional robots may be provided in separate
|
||||
repositories or community-maintained packages.
|
||||
|
||||
Can I use USD or URDF models?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
No, mjlab expects **MJCF (MuJoCo XML)** models.
|
||||
|
||||
- You will need to **convert** USD or URDF assets to MJCF.
|
||||
- For many common robots, you can directly use
|
||||
`MuJoCo Menagerie <https://github.com/google-deepmind/mujoco_menagerie>`_,
|
||||
which ships high-quality MJCF models and assets.
|
||||
|
||||
Getting Help
|
||||
------------
|
||||
|
||||
GitHub Issues
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Use GitHub issues for:
|
||||
|
||||
- **Bug reports**
|
||||
- **Performance regressions**
|
||||
- **Documentation gaps**
|
||||
|
||||
When filing a bug, please include:
|
||||
|
||||
- CUDA driver and runtime versions
|
||||
- GPU model
|
||||
- A minimal reproduction script
|
||||
- Complete error logs and stack traces
|
||||
- Appropriate labels (for example: ``bug``, ``performance``, ``docs``)
|
||||
|
||||
`Open an issue <https://github.com/mujocolab/mjlab/issues>`_
|
||||
|
||||
Discussions
|
||||
~~~~~~~~~~~
|
||||
|
||||
Use GitHub Discussions for:
|
||||
|
||||
- Usage questions (config, debugging, best practices)
|
||||
- Performance tuning tips
|
||||
- Asset conversion and modeling questions
|
||||
- Design discussions and roadmap ideas
|
||||
|
||||
`Start a discussion <https://github.com/mujocolab/mjlab/discussions>`_
|
||||
|
||||
Known Limitations
|
||||
-----------------
|
||||
|
||||
We're tracking missing features for the stable release in
|
||||
https://github.com/mujocolab/mjlab/issues/100. Check our
|
||||
`open issues <https://github.com/mujocolab/mjlab/issues>`_ to see what's actively
|
||||
being worked on.
|
||||
|
||||
If something isn't working or if we've missed something, please
|
||||
`file a bug report <https://github.com/mujocolab/mjlab/issues/new>`_.
|
||||
Reference in New Issue
Block a user