|
| 1 | +# SuperDex Backend |
| 2 | + |
| 3 | +SuperDex is an optional CPU physics adapter owned by `unisim.backend.superdex`. |
| 4 | +The initial UniLab owner is the fixed-base `FR3JointTarget` task: |
| 5 | +`src/unilab/conf/ppo/task/fr3_joint_target/superdex.yaml`. It uses seven torque |
| 6 | +actions, 21 observation values, joint-state resets and the standard NumPy |
| 7 | +manager runtime. Its support level is **Configured**; bounded rollout or short |
| 8 | +training checks do not establish full-training performance or platform support. |
| 9 | +The implementation is tracked in [#1534](https://github.com/Motphys/UniLab/issues/1534) |
| 10 | +under [roadmap #1533](https://github.com/Motphys/UniLab/issues/1533). |
| 11 | + |
| 12 | +## Local Development Setup |
| 13 | + |
| 14 | +This development profile uses locally linked UniSim and UniLab checkouts; it |
| 15 | +does not require a new published version. SuperDex Physics/Robotics 1.0.0 requires |
| 16 | +Python 3.12. CPU physics does not require CUDA. Native rendering and video are |
| 17 | +not part of the FR3 owner; training defaults to `no_play=true`. |
| 18 | + |
| 19 | +In the UniLab checkout, use an existing Python 3.12 virtual environment or create |
| 20 | +one, then install the local packages: |
| 21 | + |
| 22 | +For the temporary local SuperDex source build used by this roadmap, first run: |
| 23 | + |
| 24 | +```bash |
| 25 | +bash scripts/tools/setup_superdex_env.sh |
| 26 | +source ~/.cache/unisim/superdex/env.sh |
| 27 | +``` |
| 28 | + |
| 29 | +With no arguments the script clones the modified |
| 30 | +`unilabsim/project_superdex` integration branch, installs the public SuperDex |
| 31 | +Python facade, builds `mochi_physics_pybind` and `superdex_robotics_pybind` in |
| 32 | +Release mode, and installs the local UniSim/UniRL/UniLab checkouts editable. It |
| 33 | +does not publish or install a SuperDex wheel from PyPI. The generated |
| 34 | +`env.sh` exports the assets and native-extension paths. Re-run the script after |
| 35 | +changing the SuperDex checkout; CMake reuses the existing build directory. |
| 36 | + |
| 37 | +```bash |
| 38 | +uv venv --python 3.12 |
| 39 | +export UNILAB_LOCAL_UNISIM=/absolute/path/to/unisim |
| 40 | +uv pip install -e "${UNILAB_LOCAL_UNISIM}[superdex,mujoco]" -e . --group pyproject.toml:dev |
| 41 | +export UV_NO_SYNC=1 |
| 42 | +export SUPERDEX_ASSETS_PATH=/absolute/path/to/project_superdex/assets |
| 43 | +``` |
| 44 | + |
| 45 | +`UNILAB_LOCAL_UNISIM` enables the repository's local dependency validation: |
| 46 | +tests require an editable installation and check that its metadata and imported |
| 47 | +module point to exactly that checkout. Without this variable, the normal |
| 48 | +indexed-release requirement remains in force. `UV_NO_SYNC=1` preserves the local |
| 49 | +links when running existing Make targets; `uv sync` would re-resolve the locked |
| 50 | +release profile. |
| 51 | + |
| 52 | +Native FR3 assets remain in the upstream SuperDex checkout. The asset hub |
| 53 | +registers `bots/arms/fr3_v2/fr3_v2.superdex_bot`, checking its collision SDF, |
| 54 | +render files, `LICENSE` and `NOTICE` before constructing physics. No native |
| 55 | +robot binaries are bundled or downloaded by UniLab. Set |
| 56 | +`env.superdex_assets_root=/absolute/path/to/project_superdex/assets` to override |
| 57 | +`SUPERDEX_ASSETS_PATH` for a specific owner invocation. |
| 58 | + |
| 59 | +## Run the FR3 Task |
| 60 | + |
| 61 | +```bash |
| 62 | +uv run --no-sync train --algo ppo --task fr3_joint_target --sim superdex \ |
| 63 | + algo.max_iterations=2 algo.num_steps_per_env=16 \ |
| 64 | + algo.algorithm.num_learning_epochs=1 |
| 65 | +``` |
| 66 | + |
| 67 | +The target joint positions, rewards, reset ranges and action scales live in the |
| 68 | +task's `base.yaml`. The torque bounds `[20,20,20,20,5,5,5]` Nm are an explicit |
| 69 | +research profile, not rated hardware limits. `superdex_effort_limits` declares |
| 70 | +the same bounds at the native backend boundary. The SDK remains single-threaded; |
| 71 | +the native scene executor below owns all supported CPU parallelism. |
| 72 | + |
| 73 | +## Default CPU Environment Parallelism |
| 74 | + |
| 75 | +The backend uses SuperDex's source-built `SceneBatchExecutor`, a persistent C++ |
| 76 | +thread pool that owns the barrier across independent scenes. Each substep writes |
| 77 | +batched generalized forces, advances scenes, and returns articulated/link state, |
| 78 | +contact sensors and solver status without per-environment Python binding calls. |
| 79 | +Asset materialization, reset and cache-frame transforms remain owned by the |
| 80 | +UniSim adapter. This is CPU thread parallelism, not GPU physics, and it does |
| 81 | +not change the PPO/APPO collector, learner or policy contracts. The decision is |
| 82 | +recorded in {doc}`/adr/ADR-0009-superdex-persistent-cpu-workers` and |
| 83 | +[unisim#41](https://github.com/unilabsim/unisim/issues/41). |
| 84 | + |
| 85 | +Both task owners select automatic workers by default: |
| 86 | + |
| 87 | +| Owner option | Meaning | |
| 88 | +| --- | --- | |
| 89 | +| `env.superdex_num_workers=0` | Automatic: `min(available physical CPU cores, num_envs)` | |
| 90 | +| `env.superdex_num_workers=1` | One native C++ scene worker | |
| 91 | +| `env.superdex_num_workers=K` | Explicit C++ worker count, capped at `num_envs` | |
| 92 | + |
| 93 | +A native scene's `DebugDraw` state is thread-affine, so the batched mode is |
| 94 | +incompatible with an attached native SuperDex debugger: the adapter fails |
| 95 | +closed with an actionable error when a debugger client connects. To debug with |
| 96 | +the native debugger, run `env.superdex_execution_mode=serial`, which steps |
| 97 | +every scene on the environment thread and never builds the native worker pool |
| 98 | +([unisim#55](https://github.com/unilabsim/unisim/issues/55)). Serial mode is a |
| 99 | +debugging profile, not a performance configuration. |
| 100 | + |
| 101 | +`eval --sim superdex --render-mode interactive` renders through the native |
| 102 | +SuperDex (Polyscope) viewer instead of the MuJoCo viewer path. The owner layer |
| 103 | +automatically switches the env to `superdex_execution_mode=serial`, and the CLI |
| 104 | +forces `training.play_env_num=1` because the viewer draws exactly one scene; |
| 105 | +an explicit `training.play_env_num=...` override is preserved. |
| 106 | + |
| 107 | +With 1024 environments on a 16-core/32-thread host, automatic selection yields |
| 108 | +16 workers. Concurrent multi-rank collectors are assigned whole physical-core |
| 109 | +groups, including their logical siblings, so ranks do not split an SMT core. |
| 110 | +`training.dp_collector_cpu_ids` may instead provide one explicit CPU-id list |
| 111 | +per rank. The selected block is applied before SuperDex materializes its native |
| 112 | +worker pool. |
| 113 | + |
| 114 | +For every physics substep, the host runs the pre-step control callback, enters |
| 115 | +the native batch barrier, then publishes the refreshed batch before the next |
| 116 | +callback. Selected reset preserves caller row order and leaves unselected |
| 117 | +environments unchanged. A native worker failure closes the executor and reports |
| 118 | +the failure; it does not silently return stale state or switch to serial. |
| 119 | +Closing an environment joins its C++ workers before scenes are destroyed. |
| 120 | + |
| 121 | +Worker count alone is not evidence of speedup. Throughput comparisons must use |
| 122 | +the same model, control sequence, batch size and substeps, and report complete |
| 123 | +backend/env time, startup, RSS, CPU use and actual worker count. Count environment |
| 124 | +control steps, not physics substeps. Existing contact approximations are unchanged. |
| 125 | + |
| 126 | +The fixed root still has a named entity and readable body state. Reset terms |
| 127 | +write joint state; they do not request a floating-root layout. The task does |
| 128 | +not require contact sensors, cameras, site Jacobians or runtime material DR. |
| 129 | +SuperDex has no native renderer. Its default record playback uses the offline |
| 130 | +MuJoCo renderer with the authored MJCF visual model while SuperDex remains the |
| 131 | +physics backend. `.superdex_bot` scenes must provide `visual_model_file` for |
| 132 | +this path. Selecting playback mode `none` skips playback entirely; it is not |
| 133 | +evidence that a checkpoint has executed a rollout. |
| 134 | + |
| 135 | +`superdex_allow_contact_approximation` defaults to `false`. It is reserved for |
| 136 | +explicitly audited MJCF conversion profiles: enabling it accepts a warning about |
| 137 | +contact/material approximation, including missing torsional/rolling friction |
| 138 | +equivalence. It does not establish arbitrary MJCF task compatibility. |
| 139 | +Contact queries report the last completed solver step. Reset clears this state; |
| 140 | +it does not provide a fresh geometric overlap test until a positive physics step |
| 141 | +has completed. Kinematic body/joint getters are refreshed immediately at reset. |
| 142 | + |
| 143 | +## Validation and Ownership |
| 144 | + |
| 145 | +The `go2_joystick_flat/superdex` PPO owner is a research sim2sim profile. It |
| 146 | +inherits the MuJoCo owner, preserving 49 actor observations, 52 critic |
| 147 | +observations, 12 position-target actions, normalization, network dimensions and |
| 148 | +control timing. It disables runtime PD gain randomization and explicitly opts |
| 149 | +into contact approximation. The adapter's cold-path MJCF conversion is restricted; |
| 150 | +this owner does not imply arbitrary scene support or equivalent walking behavior. |
| 151 | + |
| 152 | +Create a small source checkpoint with the MuJoCo owner, then pass its path to the |
| 153 | +optional checkpoint test: |
| 154 | + |
| 155 | +```bash |
| 156 | +uv run --no-sync train --algo ppo --task go2_joystick_flat --sim mujoco \ |
| 157 | + algo.num_envs=2 algo.max_iterations=2 algo.num_steps_per_env=16 \ |
| 158 | + algo.algorithm.num_mini_batches=1 algo.algorithm.num_learning_epochs=1 \ |
| 159 | + training.device=cpu training.no_play=true |
| 160 | +export UNILAB_SUPERDEX_GO2_CHECKPOINT=/absolute/path/to/source/run/model_1.pt |
| 161 | +uv run --no-sync pytest tests/envs/test_go2_superdex.py -q |
| 162 | +``` |
| 163 | + |
| 164 | +This validates the source `run_config.json` before environment construction, |
| 165 | +checks rejection of changed policy action semantics, loads the actual policy |
| 166 | +through the production playback session and executes 64 SuperDex control steps |
| 167 | +without a renderer. It checks finite values and interface compatibility; a |
| 168 | +two-iteration checkpoint is not expected to walk reliably. |
| 169 | + |
| 170 | +```bash |
| 171 | +uv run --no-sync pytest tests/assets/test_superdex_assets.py \ |
| 172 | + tests/envs/test_fr3_superdex.py tests/test_cli_runtime_requirements.py -q |
| 173 | +``` |
| 174 | + |
| 175 | +The optional native tests require the SDK and `SUPERDEX_ASSETS_PATH`; they cover |
| 176 | +finite rollout data, selected reset isolation, immediate observation refresh |
| 177 | +and a spawned `EnvFactory`. Missing runtime/assets produce an explicit skip; |
| 178 | +such a run is not native validation. The base asset/config tests need no native |
| 179 | +asset checkout. |
| 180 | + |
| 181 | +Engine conversion and physics live in UniSim; asset registration, Hydra and task |
| 182 | +terms remain in UniLab. See |
| 183 | +{doc}`/adr/ADR-0007-unisim-extraction-boundary`, |
| 184 | +{doc}`/adr/ADR-0006-community-manager-api-on-numpy-runtime` and |
| 185 | +{doc}`/adr/ADR-0002-backend-capability-boundary-for-play-and-snapshot`. |
0 commit comments