Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ MotrixLab 是构建在 MotrixSim 仿真后端之上的强化学习框架,提
- `motrix_rl_rslrl`:RSLRL PPO provider 插件(Torch)
- `motrix_deploy`:框架无关的 artifact、运行时契约与部署 CLI
- `motrix_deploy_mujoco`:SceneCfg 支撑的 MuJoCo 后端插件
- `motrix_deploy_motrixsim`:SceneCfg 支撑的原生 MotrixSim 部署后端插件
- `motrix_deploy_unitree`:Unitree SDK2 DDS 硬件后端插件
- `motrix_deploy_tasks`:具体部署任务实现

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ _Microduck locomotion policies trained with MotrixLab, rendered in MotrixRender

## What is MotrixLab?

**MotrixLab** is an open-source reinforcement learning framework for robot training, built on the high-performance [MotrixSim](https://github.com/Motphys/motrixsim-docs) physics engine. Define an environment once, train it with thousands of parallel environment instances using SKRL, RSL-RL, or the built-in FastSAC, and deploy the resulting policy to MuJoCo or Unitree hardware — all through a single command-line interface.
**MotrixLab** is an open-source reinforcement learning framework for robot training, built on the high-performance [MotrixSim](https://github.com/Motphys/motrixsim-docs) physics engine. Define an environment once, train it with thousands of parallel environment instances using SKRL, RSL-RL, or the built-in FastSAC, and deploy the resulting policy to MuJoCo, native MotrixSim, or Unitree hardware — all through a single command-line interface.

<div align="center">
<picture>
Expand All @@ -46,7 +46,7 @@ _Microduck locomotion policies trained with MotrixLab, rendered in MotrixRender
- **Unified Interface**: Provides a concise and unified reinforcement learning training and evaluation interface
- **Multi-framework Support**: Supports SKRL (JAX/PyTorch), RSLRL (PyTorch), and the built-in FastSAC implementation
- **Rich Environments**: Includes various robot simulation environments such as basic control, locomotion, and manipulation tasks
- **Sim-to-Real Deployment**: The same policy code deploys via the deploy CLI — Sim2Sim to MuJoCo, Sim2Real to real hardware
- **Sim-to-Real Deployment**: The same policy code deploys via the deploy CLI — Sim2Sim to MuJoCo or native MotrixSim, Sim2Real to real hardware
- **High-precision, High-performance Simulation**: Built on [MotrixSim](https://motrixsim.readthedocs.io/), a high-precision, high-performance physics engine
- **Visual Training**: Supports real-time rendering and training process visualization

Expand Down Expand Up @@ -180,6 +180,7 @@ MotrixLab is a [uv](https://docs.astral.sh/uv/) workspace with the following pac
| --- | --- | --- |
| **motrix_deploy** | `motrix-deploy` | Artifacts, control sessions, runtime contracts, and deployment CLI |
| **motrix_deploy_mujoco** | `motrix-deploy-mujoco` | MuJoCo deployment backend plugin |
| **motrix_deploy_motrixsim** | `motrix-deploy-motrixsim` | Native MotrixSim deployment backend plugin |
| **motrix_deploy_unitree** | `motrix-deploy-unitree` | Unitree SDK2 DDS hardware backend plugin |
| **motrix_deploy_tasks** | `motrix-deploy-tasks` | Walking tasks, deployment scenes, and installed Hydra recipes |
| **motrix_env_core** | `motrix-env-core` | Backend-agnostic environment framework, configuration, registry, and rendering |
Expand Down
5 changes: 3 additions & 2 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ _使用 MotrixLab 训练的 microduck 行走策略,由 MotrixRender 实时渲

## MotrixLab 是什么?

**MotrixLab** 是一个开源的机器人强化学习训练框架,构建于高性能的 [MotrixSim](https://github.com/Motphys/motrixsim-docs) 物理引擎之上。环境只需定义一次,即可通过 SKRL、RSLRL 或内置的 FastSAC 使用数千个并行环境实例进行训练,训练得到的策略可部署到 MuJoCo 或 Unitree 硬件 —— 全程只需一个命令行接口。
**MotrixLab** 是一个开源的机器人强化学习训练框架,构建于高性能的 [MotrixSim](https://github.com/Motphys/motrixsim-docs) 物理引擎之上。环境只需定义一次,即可通过 SKRL、RSLRL 或内置的 FastSAC 使用数千个并行环境实例进行训练,训练得到的策略可部署到 MuJoCo、原生 MotrixSim 或 Unitree 硬件 —— 全程只需一个命令行接口。

<div align="center">
<picture>
Expand All @@ -46,7 +46,7 @@ _使用 MotrixLab 训练的 microduck 行走策略,由 MotrixRender 实时渲
- **统一接口**: 提供简洁统一的强化学习训练和评估接口
- **多框架支持**: 支持 SKRL(JAX/PyTorch)、RSLRL(PyTorch)和内置 FastSAC 实现
- **丰富环境**: 包含基础控制、运动、操作等多种机器人仿真环境
- **Sim-to-Real 部署**: 同一套策略代码,通过部署 CLI Sim2Sim 到 MuJoCo 仿真、Sim2Real 到真实硬件
- **Sim-to-Real 部署**: 同一套策略代码,通过部署 CLI Sim2Sim 到 MuJoCo 或原生 MotrixSim 仿真、Sim2Real 到真实硬件
- **高精度高性能仿真**: 基于 [MotrixSim](https://motrixsim.readthedocs.io/) 高精度、高性能物理仿真引擎
- **可视化训练**: 支持实时渲染和训练过程可视化

Expand Down Expand Up @@ -180,6 +180,7 @@ MotrixLab 是一个 [uv](https://docs.astral.sh/uv/) workspace,包含以下 pa
| --- | --- | --- |
| **motrix_deploy** | `motrix-deploy` | artifact、控制会话、运行时契约与部署 CLI |
| **motrix_deploy_mujoco** | `motrix-deploy-mujoco` | MuJoCo 部署 backend plugin |
| **motrix_deploy_motrixsim** | `motrix-deploy-motrixsim` | 原生 MotrixSim 部署 backend plugin |
| **motrix_deploy_unitree** | `motrix-deploy-unitree` | Unitree SDK2 DDS 硬件 backend plugin |
| **motrix_deploy_tasks** | `motrix-deploy-tasks` | 行走任务、部署场景与安装的 Hydra 配方 |
| **motrix_env_core** | `motrix-env-core` | backend 无关的环境框架、配置、registry 与渲染 |
Expand Down
17 changes: 16 additions & 1 deletion docs/source/en/user_guide/tutorial/advanced/motrix_deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ runtime plugin for the target. The recipes work outside the repository without a
Task defaults select the Hydra runtime group (`sim` or `hardware`); you do not need a separate runtime override.
Common top-level settings are `artifact`, `duration_s`, and `command`. All target-specific settings live directly under
`runtime`. `runtime.kind` selects the simulation or hardware path; `runtime.backend` selects the plugin (`mujoco`
for simulation or `unitree_go2` for hardware). `runtime.backend` is a scalar string selector, not a nested configuration
or `motrixsim` for simulation, or `unitree_go2` for hardware). `runtime.backend` is a scalar string selector, not a nested configuration
mapping or Hydra group.

## 3. Check in MuJoCo
Expand Down Expand Up @@ -72,6 +72,21 @@ It creates a MuJoCo runtime with `create_simulation_runtime`, attaches a `Contro
inference, and robot commands; the runtime handles physics, timing, and the viewer. A raw ONNX file needs explicit task
preprocessing and action settings, whereas the artifact carries those settings for the CLI.

### Select native MotrixSim

With `motrix-deploy-motrixsim` installed, switch the backend to `motrixsim` to reuse the same artifact and scene recipe:

```bash
motrix-deploy task=go2-walk-flat/sim artifact=artifacts/go2-walk-flat.deploy \
runtime.backend=motrixsim runtime.viewer=true
```

The Python example also supports native MotrixSim:

```bash
python examples/deploy_to_sim.py --backend motrixsim
```

## 4. Run on the real robot

Suspend the robot, put it in low-level/debug mode, connect Ethernet, and keep an independent emergency stop and operator
Expand Down
17 changes: 16 additions & 1 deletion docs/source/zh_CN/user_guide/tutorial/advanced/motrix_deploy.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ artifact 包含 ONNX 策略、机器人与控制设置,以及任务规格。
部署场景和 Hydra 配方,以及目标对应的运行时插件。配方安装在插件中,在仓库外运行也不需要 workspace 配置路径。
任务 defaults 选择 Hydra 运行时组(`sim` 或 `hardware`),无需另行覆盖运行时组。
顶层公共设置为 `artifact`、`duration_s` 和 `command`。所有目标专用设置直接位于 `runtime` 下;
`runtime.kind` 选择仿真或硬件执行路径;`runtime.backend` 选择插件(仿真为 `mujoco`,硬件为 `unitree_go2`)。
`runtime.kind` 选择仿真或硬件执行路径;`runtime.backend` 选择插件(仿真为 `mujoco` 或 `motrixsim`,硬件为 `unitree_go2`)。
`runtime.backend` 是标量字符串选择器,不是嵌套配置映射或 Hydra 配置组。

## 3. 在 MuJoCo 中检查
Expand Down Expand Up @@ -67,6 +67,21 @@ python examples/deploy_to_sim.py --headless --steps 100
`ControlSession`,并在 `with runtime:` 中运行。控制会话负责输入、观察、推理和机器人指令;运行时负责物理推进、
调度和 viewer。直接使用 ONNX 文件时需要显式指定任务预处理和动作设置;artifact 则为 CLI 携带这些设置。

### 选择原生 MotrixSim

安装 `motrix-deploy-motrixsim` 后,将 backend 切换为 `motrixsim`,即可复用同一 artifact 和场景配方:

```bash
motrix-deploy task=go2-walk-flat/sim artifact=artifacts/go2-walk-flat.deploy \
runtime.backend=motrixsim runtime.viewer=true
```

Python 示例同样支持原生 MotrixSim:

```bash
python examples/deploy_to_sim.py --backend motrixsim
```

## 4. 运行真机

将机器人悬空,切换到低层/调试模式,连接网线,并准备好独立急停和操作人员。启动过程可能在遥控器 Start 门控前
Expand Down
6 changes: 4 additions & 2 deletions examples/deploy_to_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ class ExampleSceneObjsCfg(SceneObjsCfg):

def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--backend", choices=("mujoco",), default="mujoco", help="Simulation runtime plugin")
parser.add_argument(
"--backend", choices=("mujoco", "motrixsim"), default="mujoco", help="Simulation runtime plugin"
)
parser.add_argument("--headless", action="store_true", help="No window; run fixed-step without wall-clock pacing")
parser.add_argument("--steps", type=int, help="Headless control ticks; GUI mode runs until the window closes")
args = parser.parse_args()
Expand Down Expand Up @@ -65,7 +67,7 @@ def main() -> int:
haze=(0.1, 0.1, 0.1, 1.0),
tone_mapping="none",
),
system_camera=SystemCameraCfg(distance=3.0, elevation=-20.0, azimuth=90.0),
system_camera=SystemCameraCfg(lookat=(0.0, 0.0, 0.3), distance=3.0, elevation=-20.0, azimuth=90.0),
)
config = SimulationRuntimeConfig(
scene=scene,
Expand Down
12 changes: 0 additions & 12 deletions motrix_deploy/src/motrix_deploy/contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ class RobotCapabilities:
Attributes:
control_modes: Canonical joint command modes accepted by the backend.
state_fields: ``RobotState`` fields populated by every state sample.
privileged_state_fields: Subset of state_fields supplied as privileged simulator ground truth,
not measurements guaranteed to be available on hardware.
extra_sensors: Additional entries available in ``RobotState.extras``, mapped to their fixed shapes.
supports_rendering: Whether the backend can present a live viewer.
max_command_rate_hz: Highest command update rate accepted by the backend, or ``None`` when unconstrained.
Expand All @@ -273,7 +271,6 @@ class RobotCapabilities:
max_command_rate_hz: float | None = None
requires_enable: bool = False
stop_semantics: str = "hold_position"
privileged_state_fields: frozenset[str] = frozenset()

def __post_init__(self) -> None:
_validate_names(self.control_modes, path="capabilities.control_modes")
Expand All @@ -288,15 +285,6 @@ def __post_init__(self) -> None:
not isinstance(name, str) or not name for name in self.state_fields
):
raise ValidationError("capabilities.state_fields", "a frozenset of non-empty names", self.state_fields)
if (
not isinstance(self.privileged_state_fields, frozenset)
or not self.privileged_state_fields <= self.state_fields
):
raise ValidationError(
"capabilities.privileged_state_fields",
"a frozenset subset of state_fields",
self.privileged_state_fields,
)
if self.max_command_rate_hz is not None and self.max_command_rate_hz <= 0:
raise ValidationError("capabilities.max_command_rate_hz", "a positive value", self.max_command_rate_hz)
if not self.stop_semantics:
Expand Down
25 changes: 0 additions & 25 deletions motrix_deploy/tests/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,31 +131,6 @@ def test_robot_spec_rejects_invalid_arrays(field: str, value: np.ndarray, error_
robot_spec(**{field: value})


def test_privileged_capabilities_default_empty_and_require_available_fields() -> None:
capabilities = RobotCapabilities(control_modes=("joint_servo",), state_fields=frozenset({"base_position"}))
assert capabilities.privileged_state_fields == frozenset()
privileged = RobotCapabilities(
control_modes=("joint_servo",),
state_fields=frozenset({"base_position"}),
privileged_state_fields=frozenset({"base_position"}),
)
assert privileged.privileged_state_fields <= privileged.state_fields
with pytest.raises(ValidationError, match="capabilities.privileged_state_fields"):
RobotCapabilities(
control_modes=("joint_servo",),
state_fields=frozenset(),
privileged_state_fields=frozenset({"base_position"}),
)


@pytest.mark.parametrize("value", [{"base_position"}, frozenset({"unavailable"})])
def test_invalid_privileged_state_fields_are_rejected(value: object) -> None:
with pytest.raises(ValidationError, match="capabilities.privileged_state_fields"):
RobotCapabilities(
control_modes=("joint_servo",), state_fields=frozenset({"base_position"}), privileged_state_fields=value
)


def test_tensor_spec_requires_float32_fixed_shape() -> None:
with pytest.raises(ValidationError, match="tensor.dtype"):
TensorSpec(name="input", shape=(1, 4), dtype="float64")
Expand Down
20 changes: 0 additions & 20 deletions motrix_deploy/tests/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -696,26 +696,6 @@ def fail(state: RobotState) -> str | None:
assert backend.events[-2:] == ["stop", "close"]


@pytest.mark.parametrize("privileged", [False, True])
def test_backend_state_metadata_does_not_gate_task_execution(
manifest_factory: Callable[[], DeploymentManifest], privileged: bool
) -> None:
manifest = manifest_factory()
backend = EnablingBackend(manifest.robot)
backend._capabilities = RobotCapabilities(
control_modes=("joint_servo",),
state_fields=frozenset({"joint_position", "joint_velocity", "base_linear_velocity"}),
privileged_state_fields=frozenset({"base_linear_velocity"}) if privileged else frozenset(),
requires_enable=True,
)
runtime, control = _loop(manifest, backend)
result = runtime.run(control, steps=1)
assert result.success
assert len(backend.commands) == 1
assert backend.events.index("enable") < backend.events.index("write")
assert backend.events[-2:] == ["stop", "close"]


def test_required_enable_completes_before_first_policy_write(
manifest_factory: Callable[[], DeploymentManifest],
) -> None:
Expand Down
Loading
Loading