physicalai-mujoco-so101-plugin 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 (69) hide show
  1. physicalai_mujoco_so101_plugin-0.1.0/.gitignore +219 -0
  2. physicalai_mujoco_so101_plugin-0.1.0/PKG-INFO +285 -0
  3. physicalai_mujoco_so101_plugin-0.1.0/README.md +259 -0
  4. physicalai_mujoco_so101_plugin-0.1.0/pyproject.toml +56 -0
  5. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/__init__.py +29 -0
  6. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/__main__.py +308 -0
  7. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/_urdf.py +21 -0
  8. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/constants.py +42 -0
  9. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/http_server.py +314 -0
  10. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/mujoco_robot.py +885 -0
  11. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/scene_registry.py +360 -0
  12. physicalai_mujoco_so101_plugin-0.1.0/src/physicalai_mujoco_so101_plugin/studio_catalog.py +261 -0
  13. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/garment_fold/scene.xml +30 -0
  14. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/garment_fold_mesh/mini.xml +11 -0
  15. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/garment_fold_mesh/scene.xml +30 -0
  16. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/garment_fold_mesh/scene_base.xml +30 -0
  17. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/garment_fold_mesh/scene_e.xml +30 -0
  18. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/garment_fold_mesh/scene_self.xml +30 -0
  19. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/pick_lift/scene.xml +27 -0
  20. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/pick_place/scene.xml +23 -0
  21. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/single_pick_place/scene.xml +23 -0
  22. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/cup.stl +0 -0
  23. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_atlas.png +0 -0
  24. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_cube.obj +88 -0
  25. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_face_1.png +0 -0
  26. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_face_2.png +0 -0
  27. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_face_3.png +0 -0
  28. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_face_4.png +0 -0
  29. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_face_5.png +0 -0
  30. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/die_face_6.png +0 -0
  31. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/wood1.png +0 -0
  32. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/wood4.png +0 -0
  33. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/wood5.png +0 -0
  34. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/assets/wood_floor.png +0 -0
  35. physicalai_mujoco_so101_plugin-0.1.0/urdf/scenes/yahtzee/scene.xml +67 -0
  36. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/base_motor_holder_so101_v1.part +14 -0
  37. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/base_motor_holder_so101_v1.stl +0 -0
  38. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/base_so101_v2.part +14 -0
  39. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/base_so101_v2.stl +0 -0
  40. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/garment_PL_019.obj +1642 -0
  41. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/motor_holder_so101_base_v1.part +14 -0
  42. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/motor_holder_so101_base_v1.stl +0 -0
  43. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/motor_holder_so101_wrist_v1.part +14 -0
  44. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/motor_holder_so101_wrist_v1.stl +0 -0
  45. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/moving_jaw_so101_v1.part +14 -0
  46. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/moving_jaw_so101_v1.stl +0 -0
  47. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/rotation_pitch_so101_v1.part +14 -0
  48. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/rotation_pitch_so101_v1.stl +0 -0
  49. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/sts3215_03a_no_horn_v1.part +14 -0
  50. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/sts3215_03a_no_horn_v1.stl +0 -0
  51. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/sts3215_03a_v1.part +14 -0
  52. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/sts3215_03a_v1.stl +0 -0
  53. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/under_arm_so101_v1.part +14 -0
  54. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/under_arm_so101_v1.stl +0 -0
  55. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/upper_arm_so101_v1.part +14 -0
  56. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/upper_arm_so101_v1.stl +0 -0
  57. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/waveshare_mounting_plate_so101_v2.part +14 -0
  58. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/waveshare_mounting_plate_so101_v2.stl +0 -0
  59. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/wrist_roll_follower_so101_v1.part +14 -0
  60. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/wrist_roll_follower_so101_v1.stl +0 -0
  61. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/wrist_roll_pitch_so101_v2.part +14 -0
  62. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/assets/wrist_roll_pitch_so101_v2.stl +0 -0
  63. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/so101.xml +189 -0
  64. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/so101_dual.urdf +877 -0
  65. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/so101_new_calib.urdf +453 -0
  66. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/so101_robot_bodies.xml +89 -0
  67. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101/so101_robot_config.xml +75 -0
  68. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101_dual/so101_dual_robot_bodies.xml +154 -0
  69. physicalai_mujoco_so101_plugin-0.1.0/urdf/so101_dual/so101_dual_robot_config.xml +81 -0
@@ -0,0 +1,219 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+
161
+ # mkdocs documentation
162
+ /site
163
+
164
+ # mypy
165
+ .mypy_cache/
166
+ .dmypy.json
167
+ dmypy.json
168
+
169
+ # Pyre type checker
170
+ .pyre/
171
+
172
+ # pytype static type analyzer
173
+ .pytype/
174
+
175
+ # Cython debug symbols
176
+ cython_debug/
177
+
178
+ # PyCharm
179
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
180
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
181
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
182
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
183
+ .idea/
184
+
185
+ # Abstra
186
+ # Abstra is an AI-powered process automation framework.
187
+ # Ignore directories containing user credentials, local state, and settings.
188
+ # Learn more at https://abstra.io/docs
189
+ .abstra/
190
+
191
+ # Visual Studio Code
192
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
193
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
194
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
195
+ # you could uncomment the following to ignore the entire vscode folder
196
+ .vscode/
197
+
198
+ # Ruff stuff:
199
+ .ruff_cache/
200
+
201
+ # PyPI configuration file
202
+ .pypirc
203
+
204
+ # Marimo
205
+ marimo/_static/
206
+ marimo/_lsp/
207
+ __marimo__/
208
+
209
+ # Streamlit
210
+ .streamlit/secrets.toml
211
+
212
+ # Misc
213
+ .DS_Store
214
+
215
+ # MuJoCo runtime logs
216
+ MUJOCO_LOG.TXT
217
+
218
+
219
+ tmp/
@@ -0,0 +1,285 @@
1
+ Metadata-Version: 2.5
2
+ Name: physicalai-mujoco-so101-plugin
3
+ Version: 0.1.0
4
+ Summary: MuJoCo SO-101 simulation plugin for PhysicalAI Studio
5
+ Project-URL: Homepage, https://github.com/MarkRedeman/physicalai-plugins
6
+ Project-URL: Repository, https://github.com/MarkRedeman/physicalai-plugins
7
+ Project-URL: Issues, https://github.com/MarkRedeman/physicalai-plugins/issues
8
+ License-Expression: Apache-2.0
9
+ Requires-Python: >=3.12
10
+ Requires-Dist: defusedxml>=0.7.1
11
+ Requires-Dist: fastapi>=0.115
12
+ Requires-Dist: loguru>=0.7
13
+ Requires-Dist: mujoco>=3.1.0
14
+ Requires-Dist: numpy>=1.24
15
+ Requires-Dist: opencv-python-headless>=4.10
16
+ Requires-Dist: physicalai-studio-plugin
17
+ Requires-Dist: physicalai[transport]>=0.1.1
18
+ Requires-Dist: pydantic>=2.0
19
+ Requires-Dist: pyfakewebcam>=0.1.0
20
+ Requires-Dist: uvicorn>=0.30
21
+ Provides-Extra: tests
22
+ Requires-Dist: httpx>=0.27; extra == 'tests'
23
+ Requires-Dist: pytest; extra == 'tests'
24
+ Requires-Dist: pytest-asyncio; extra == 'tests'
25
+ Description-Content-Type: text/markdown
26
+
27
+ # PhysicalAI MuJoCo SO-101 Plugin
28
+
29
+ MuJoCo SO-101 simulation plugin for PhysicalAI Studio. Part of the [physicalai-plugins](https://github.com/MarkRedeman/physicalai-plugins) monorepo.
30
+
31
+ This plugin lets you run a virtual SO-101 robot as a PhysicalAI transport owner, then connect to it from Studio exactly like real hardware.
32
+
33
+ ## Features
34
+
35
+ - Run a virtual SO-101 as a PhysicalAI transport owner
36
+ - MuJoCo interactive viewer
37
+ - Camera streams over HTTP (MJPEG) and optional v4l2loopback
38
+ - REST control server (scenes, reset, shutdown)
39
+ - Built-in task scenes
40
+
41
+ ## Screenshots
42
+
43
+ _Placeholder images — replace them with real screenshots._
44
+
45
+ ![MuJoCo SO-101 in the PhysicalAI Studio robot catalog](https://raw.githubusercontent.com/MarkRedeman/physicalai-plugins/main/screenshots/studio-catalog.png)
46
+
47
+ ![Connecting to the MuJoCo SO-101 in PhysicalAI Studio](https://raw.githubusercontent.com/MarkRedeman/physicalai-plugins/main/packages/physicalai-mujoco-so101-plugin/screenshots/studio.png)
48
+
49
+ ![MuJoCo viewer with a pick-and-place scene](https://raw.githubusercontent.com/MarkRedeman/physicalai-plugins/main/packages/physicalai-mujoco-so101-plugin/screenshots/viewer.png)
50
+
51
+ ![MJPEG camera stream in a browser](https://raw.githubusercontent.com/MarkRedeman/physicalai-plugins/main/packages/physicalai-mujoco-so101-plugin/screenshots/mjpeg.png)
52
+
53
+ ## What this is for
54
+
55
+ - Teleoperating a virtual SO-101 from PhysicalAI Studio.
56
+ - Testing robot setup, task logic, and control flows without physical hardware.
57
+ - Playing back policy/inference outputs in a simulated scene while monitoring robot + camera streams.
58
+ - Developing workflows where Studio, transport, and robot APIs stay identical between sim and real deployments.
59
+
60
+ ## Quick start
61
+
62
+ From the repo root:
63
+
64
+ ```bash
65
+ uv run --no-sync physicalai-mujoco-so101 start
66
+ ```
67
+
68
+ By default this starts:
69
+
70
+ - A MuJoCo SO-101 owner named `mujoco-so101`
71
+ - Viewer window enabled
72
+ - Camera streams served over HTTP (MJPEG + REST control server on port `8080`)
73
+ - Control rate `50 Hz`
74
+ - Substeps `10`
75
+
76
+ Then open PhysicalAI Studio and connect to the robot type `MuJoCo SO-101 Follower` with name `mujoco-so101`.
77
+
78
+ ### CLI teleoperation (self-relay)
79
+
80
+ With the owner running, you can also relay the simulation back to itself using
81
+ the [PhysicalAI CLI](https://github.com/openvinotoolkit/physicalai):
82
+
83
+ ```bash
84
+ uv run physicalai run --config packages/physicalai-mujoco-so101-plugin/examples/runtime/teleop.yaml
85
+ ```
86
+
87
+ Press `Ctrl+C` to stop.
88
+
89
+ View the camera streams in a browser or with `curl`:
90
+
91
+ ```bash
92
+ curl http://127.0.0.1:8080/health
93
+ ```
94
+
95
+ MJPEG stream URLs are `http://127.0.0.1:8080/cameras/<name>/mjpeg` (e.g. open
96
+ `http://127.0.0.1:8080/cameras/overview/mjpeg` in a browser, or play it in VLC).
97
+
98
+ ## CLI options
99
+
100
+ ```bash
101
+ uv run --no-sync physicalai-mujoco-so101 start --help
102
+ ```
103
+
104
+ Common options:
105
+
106
+ - `--name <robot-name>`: transport name (must match Studio payload)
107
+ - `--model <path>`: custom XML/URDF path (bypasses scene resolution)
108
+ - `--scene <name>`: scene name (`single_pick_place`, `pick_lift`, `pick_place`, or `yahtzee`, default `single_pick_place`)
109
+ - `--no-gui`: disable MuJoCo interactive viewer
110
+ - `--no-cameras`: disable camera rendering entirely (HTTP streams and v4l2loopback)
111
+ - `--http-host <host>`: host for the camera/control HTTP server (default `127.0.0.1`)
112
+ - `--http-port <port>`: port for the camera/control HTTP server (default `8080`)
113
+ - `--no-http`: disable the camera/control HTTP server
114
+ - `--v4l2`: also publish cameras to v4l2loopback devices (requires `modprobe v4l2loopback`)
115
+ - `--rate-hz <float>`: owner loop frequency
116
+ - `--substeps <int>`: MuJoCo steps per control cycle
117
+ - `--idle-timeout <seconds>`: seconds with zero subscribers before self-exit
118
+ (default `10` without HTTP, disabled when HTTP is enabled so stream viewers keep the sim alive)
119
+ - `--allow-remote`: allow non-loopback zenoh connections
120
+
121
+ ## Cameras over HTTP (default)
122
+
123
+ The plugin renders two camera feeds and serves them over HTTP:
124
+
125
+ - `wrist` -> `http://127.0.0.1:8080/cameras/wrist/mjpeg`
126
+ - `overview` -> `http://127.0.0.1:8080/cameras/overview/mjpeg`
127
+
128
+ Each camera is also available as a single JPEG snapshot at
129
+ `http://127.0.0.1:8080/cameras/<name>/frame.jpg`.
130
+
131
+ ### REST control API
132
+
133
+ The HTTP server exposes control endpoints for resetting and switching scenes:
134
+
135
+ ```bash
136
+ # List available scenes and the current one
137
+ curl http://127.0.0.1:8080/scenes
138
+
139
+ # Switch to another scene
140
+ curl -X POST http://127.0.0.1:8080/scenes/pick_place
141
+
142
+ # Reset/randomize the current scene
143
+ curl -X POST http://127.0.0.1:8080/reset
144
+
145
+ # Stop the simulation owner
146
+ curl -X POST http://127.0.0.1:8080/shutdown
147
+ ```
148
+
149
+ | Endpoint | Method | Description |
150
+ | --------------------------- | ------ | --------------------------------------------- |
151
+ | `/` | GET | Service info, endpoint index |
152
+ | `/health` | GET | Sim status: connected, current scene, cameras |
153
+ | `/cameras` | GET | Camera list with stream/snapshot URLs |
154
+ | `/cameras/{name}/mjpeg` | GET | MJPEG stream (`multipart/x-mixed-replace`) |
155
+ | `/cameras/{name}/frame.jpg` | GET | Latest frame as a JPEG snapshot |
156
+ | `/scenes` | GET | Current scene and available scene IDs |
157
+ | `/scenes/{scene_id}` | POST | Switch to another registered scene |
158
+ | `/reset` | POST | Reset/randomize the current scene |
159
+ | `/shutdown` | POST | Gracefully stop the simulation owner |
160
+
161
+ Because the owner process is detached, stopping the CLI with `Ctrl+C` does not
162
+ stop the simulation. Use `POST /shutdown`, `--idle-timeout`, or kill the owner
163
+ process directly.
164
+
165
+ ## Cameras and v4l2loopback (opt-in)
166
+
167
+ For workflows that need a webcam-visible device, pass `--v4l2` to publish the
168
+ same camera feeds to v4l2loopback devices:
169
+
170
+ - `wrist` -> `/dev/video<wrist-video-id>` (default `/dev/video60`)
171
+ - `overview` -> `/dev/video<overview-video-id>` (default `/dev/video62`)
172
+
173
+ Example with custom IDs:
174
+
175
+ ```bash
176
+ uv run --no-sync physicalai-mujoco-so101 start --v4l2 --wrist-video-id 70 --overview-video-id 71
177
+ ```
178
+
179
+ ### One-time setup (Linux)
180
+
181
+ Install and load v4l2loopback:
182
+
183
+ ```bash
184
+ sudo modprobe v4l2loopback exclusive_caps=1 video_nr=60,61
185
+ ```
186
+
187
+ If you use custom camera IDs, use matching `video_nr` values. Example:
188
+
189
+ ```bash
190
+ sudo modprobe v4l2loopback exclusive_caps=1 video_nr=70,71
191
+ ```
192
+
193
+ If the module is already loaded with different params, unload and reload:
194
+
195
+ ```bash
196
+ sudo rmmod v4l2loopback
197
+ sudo modprobe v4l2loopback exclusive_caps=1 video_nr=60,61
198
+ ```
199
+
200
+ ### Verify devices
201
+
202
+ ```bash
203
+ ls /dev/video60 /dev/video61
204
+ ```
205
+
206
+ For custom IDs, verify those device nodes instead.
207
+
208
+ Optional sanity checks:
209
+
210
+ ```bash
211
+ v4l2-ctl --all -d /dev/video60
212
+ v4l2-ctl --all -d /dev/video61
213
+ ```
214
+
215
+ ## Troubleshooting
216
+
217
+ ### HTTP server unavailable or port already in use
218
+
219
+ - The camera/control server binds to `--http-host`/`--http-port` (default `127.0.0.1:8080`).
220
+ - If the port is taken the simulation continues without HTTP and logs a warning — pass a different `--http-port`.
221
+ - When running multiple simulations, give each a distinct `--http-port`.
222
+
223
+ ### `Camera '<name>' unavailable` or invalid argument on `/dev/video*` (with `--v4l2`)
224
+
225
+ - Ensure v4l2loopback is loaded with `exclusive_caps=1`
226
+ - Ensure the configured video devices exist (default `/dev/video60`, `/dev/video62`)
227
+ - Check permissions on device nodes
228
+
229
+ ### Viewer opens but has Wayland warnings (`libdecor`, window position)
230
+
231
+ These warnings are typically non-fatal on Wayland and can be ignored if simulation continues.
232
+
233
+ ### Camera/control server is not started
234
+
235
+ - Confirm the sim is running and the port is free: `curl http://127.0.0.1:8080/health`
236
+ - `--no-http` or `--http-port 0` disables the server; `--no-cameras` disables all camera rendering
237
+
238
+ ## Using with Studio teleop and inference playback
239
+
240
+ Typical workflow:
241
+
242
+ 1. Start simulation owner: `physicalai-mujoco-so101 start`
243
+ 2. Connect from PhysicalAI Studio (`MuJoCo SO-101 Follower`)
244
+ 3. Teleoperate in Studio and observe state/cameras
245
+ 4. Run policy inference and play action outputs into the same simulated robot
246
+
247
+ Because this uses PhysicalAI transport + Studio catalog integration, you can iterate on control and inference loops in simulation before moving to hardware.
248
+
249
+ ## Scenes
250
+
251
+ The plugin ships with built-in scenes that provide different environments for the robot:
252
+
253
+ | Scene ID | Description | Free objects | Target |
254
+ | ----------------------------- | ------------------------------------- | --------------- | ----------- |
255
+ | `single_pick_place` (default) | One block and a target disc | 1 cube | target disc |
256
+ | `pick_lift` | Three colored cubes and a target disc | 3 cubes | target disc |
257
+ | `pick_place` | A cube, a cylinder, and a target zone | cube + cylinder | target zone |
258
+ | `yahtzee` | Six dice and a cup | 6 dice | cup |
259
+
260
+ Start with a specific scene:
261
+
262
+ ```bash
263
+ uv run --no-sync physicalai-mujoco-so101 start --scene pick_place
264
+ ```
265
+
266
+ ### Keyboard shortcut: cycle scenes
267
+
268
+ When the MuJoCo viewer is open, press **`n`** (next scene) to cycle through available scenes. The scene switches at the next control cycle:
269
+
270
+ - Loads the new scene XML
271
+ - Updates the existing viewer with the new environment
272
+ - Resets block joints, target bodies, and spawn parameters
273
+
274
+ `--model` bypasses scene resolution entirely; only the exported scene XML path is loaded, and scene cycling is unavailable.
275
+
276
+ ## Current status and future improvements
277
+
278
+ Planned/desired improvements:
279
+
280
+ - More configurable camera presets (pose/FOV/fps via CLI or payload)
281
+ - Scene randomization presets (object layouts, target marker variants, textures)
282
+ - RTSP streaming sink (the frame-buffer plumbing is sink-agnostic; an RTSP
283
+ server such as `aiortsp` or MediaMTX can consume the same buffers later)
284
+ - Optional richer sensor streams (depth/segmentation style outputs)
285
+ - Additional sample tasks and policy playback recipes in this package