sim2bot 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 (35) hide show
  1. sim2bot-0.1.0/CHANGELOG.md +58 -0
  2. sim2bot-0.1.0/LICENSE +21 -0
  3. sim2bot-0.1.0/MANIFEST.in +11 -0
  4. sim2bot-0.1.0/PKG-INFO +226 -0
  5. sim2bot-0.1.0/README.md +183 -0
  6. sim2bot-0.1.0/fixtures/v1/base_velocity.json +8 -0
  7. sim2bot-0.1.0/fixtures/v1/camera_subscribe.json +9 -0
  8. sim2bot-0.1.0/fixtures/v1/camera_unsubscribe.json +4 -0
  9. sim2bot-0.1.0/fixtures/v1/gripper.json +5 -0
  10. sim2bot-0.1.0/fixtures/v1/hello_room.json +5 -0
  11. sim2bot-0.1.0/fixtures/v1/joint_position.json +5 -0
  12. sim2bot-0.1.0/fixtures/v1/joint_trajectory.json +9 -0
  13. sim2bot-0.1.0/fixtures/v1/joint_trajectory_stop.json +4 -0
  14. sim2bot-0.1.0/fixtures/v1/joint_velocity.json +13 -0
  15. sim2bot-0.1.0/fixtures/v1/marker.json +24 -0
  16. sim2bot-0.1.0/fixtures/v1/marker_clear.json +3 -0
  17. sim2bot-0.1.0/fixtures/v1/marker_delete.json +4 -0
  18. sim2bot-0.1.0/fixtures/v1/marker_points.json +31 -0
  19. sim2bot-0.1.0/fixtures/v1/reset.json +4 -0
  20. sim2bot-0.1.0/fixtures/v1/room_opening.json +5 -0
  21. sim2bot-0.1.0/fixtures/v1/stop.json +3 -0
  22. sim2bot-0.1.0/fixtures/v1/tcp_pose.json +8 -0
  23. sim2bot-0.1.0/fixtures/v1/tcp_pose_oriented.json +15 -0
  24. sim2bot-0.1.0/fixtures/v1/telemetry.json +24 -0
  25. sim2bot-0.1.0/pyproject.toml +59 -0
  26. sim2bot-0.1.0/setup.cfg +4 -0
  27. sim2bot-0.1.0/sim2bot/__init__.py +38 -0
  28. sim2bot-0.1.0/sim2bot/bridge.py +232 -0
  29. sim2bot-0.1.0/sim2bot/bridge_server.py +488 -0
  30. sim2bot-0.1.0/sim2bot/cli.py +292 -0
  31. sim2bot-0.1.0/sim2bot/client.py +1543 -0
  32. sim2bot-0.1.0/sim2bot.egg-info/SOURCES.txt +32 -0
  33. sim2bot-0.1.0/tests/test_bridge.py +278 -0
  34. sim2bot-0.1.0/tests/test_fixtures.py +255 -0
  35. sim2bot-0.1.0/tests/test_sdk.py +217 -0
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `sim2bot` package are recorded here. The format
4
+ follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions
5
+ follow [Semantic Versioning](https://semver.org/).
6
+
7
+ Each release states the Sim2Bot application versions it was verified against,
8
+ because the protocol is what the two share.
9
+
10
+ ## [Unreleased]
11
+
12
+ ## [0.1.0] — 2026-09-16
13
+
14
+ First public release: the client, the local bridge and the protocol fixtures,
15
+ extracted from the Sim2Bot monorepo.
16
+
17
+ ### Added
18
+
19
+ - `Robot` client: joint position and velocity targets, Cartesian targets via the
20
+ browser's IK, timed joint trajectories, gripper, mobile and aerial base
21
+ velocity, reset and stop.
22
+ - Telemetry with joint position, velocity, acceleration and jerk, TCP pose,
23
+ twist, acceleration and jerk, gripper state and room devices, read
24
+ latest-value.
25
+ - Camera subscriptions with JPEG and raw codecs, decoded to numpy images with
26
+ the `[cv2]` extra.
27
+ - Scene discovery (`describe`, `cameras`, `room_devices`) with stable robot IDs.
28
+ - Debug markers: spheres, boxes, arrows, lines, text, axes and point clouds.
29
+ - Rooms, so one script pairs with one browser tab.
30
+ - WebSocket, raw TCP and UDP control transports.
31
+ - The local bridge, runnable as `sim2bot bridge` or started automatically with
32
+ `Robot(auto_bridge=True)`.
33
+ - CLI: `bridge`, `doctor`, `list-robots`, `open`.
34
+ - `fixtures/v1/`, the published wire-format contract.
35
+
36
+ ### Changed
37
+
38
+ - `sim2bot open` now opens <https://app.sim2bot.com> by default. Set
39
+ `SIM2BOT_APP_URL` to point it elsewhere, such as a development server.
40
+
41
+ ### Verified against
42
+
43
+ **Protocol v1.** Sim2Bot is a hosted browser application, so everyone runs the
44
+ current build and there is no application version to pin. What is pinned is the
45
+ protocol, and `fixtures/v1/` is checked from both sides:
46
+
47
+ - this package's `tests/test_fixtures.py` asserts the client puts exactly those
48
+ messages on the wire and reads that telemetry back;
49
+ - the application's own suite asserts that the validator its socket handler
50
+ gates on accepts every one of them.
51
+
52
+ Both sides were run against these fixtures on 16 September 2026.
53
+
54
+ If the wire format ever changes incompatibly, this package gets a matching
55
+ release and the fixtures gain a `v2` directory. `v1` stays where it is.
56
+
57
+ [Unreleased]: https://github.com/Source-Robotics/sim2bot-python/compare/v0.1.0...HEAD
58
+ [0.1.0]: https://github.com/Source-Robotics/sim2bot-python/releases/tag/v0.1.0
sim2bot-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Source Robotics d.o.o.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,11 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include pyproject.toml
5
+ recursive-include sim2bot *.py
6
+ recursive-include fixtures *.json
7
+ prune sim2bot.egg-info
8
+ prune build
9
+ prune dist
10
+ global-exclude __pycache__
11
+ global-exclude *.py[cod]
sim2bot-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: sim2bot
3
+ Version: 0.1.0
4
+ Summary: Python client for the Sim2Bot browser robot simulator
5
+ Author-email: Source Robotics <info@source-robotics.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://sim2bot.com/
8
+ Project-URL: Documentation, https://docs.sim2bot.com/
9
+ Project-URL: Source, https://github.com/Source-Robotics/sim2bot-python
10
+ Project-URL: Issues, https://github.com/Source-Robotics/sim2bot-python/issues
11
+ Project-URL: Changelog, https://github.com/Source-Robotics/sim2bot-python/blob/main/CHANGELOG.md
12
+ Keywords: robotics,simulation,mujoco,bridge,sdk
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Environment :: Console
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Science/Research
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.9
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Topic :: Scientific/Engineering
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/markdown
28
+ License-File: LICENSE
29
+ Requires-Dist: fastapi>=0.110
30
+ Requires-Dist: uvicorn[standard]>=0.29
31
+ Requires-Dist: websockets>=12.0
32
+ Provides-Extra: cv2
33
+ Requires-Dist: opencv-python>=4.5; extra == "cv2"
34
+ Requires-Dist: numpy>=1.21; extra == "cv2"
35
+ Provides-Extra: av
36
+ Requires-Dist: av>=11; extra == "av"
37
+ Requires-Dist: numpy>=1.21; extra == "av"
38
+ Provides-Extra: dev
39
+ Requires-Dist: build>=1.2; extra == "dev"
40
+ Requires-Dist: pytest>=8; extra == "dev"
41
+ Requires-Dist: twine>=5; extra == "dev"
42
+ Dynamic: license-file
43
+
44
+ # sim2bot — Python client for the Sim2Bot simulator
45
+
46
+ [![CI](https://github.com/Source-Robotics/sim2bot-python/actions/workflows/ci.yml/badge.svg)](https://github.com/Source-Robotics/sim2bot-python/actions/workflows/ci.yml)
47
+ [![PyPI](https://img.shields.io/pypi/v/sim2bot.svg)](https://pypi.org/project/sim2bot/)
48
+ [![Python versions](https://img.shields.io/pypi/pyversions/sim2bot.svg)](https://pypi.org/project/sim2bot/)
49
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
50
+
51
+ Control a robot in [Sim2Bot](https://sim2bot.com/) from Python, the same way you
52
+ would talk to a real one: send joint or Cartesian targets, read telemetry, open
53
+ and close a gripper, subscribe to camera feeds.
54
+
55
+ ```python
56
+ from sim2bot import Robot
57
+
58
+ with Robot(auto_bridge=True, wait_for_sim=True) as robot:
59
+ arm = robot.describe()[0]
60
+ robot.move_to(arm.home)
61
+ robot.wait_until_reached(arm.home)
62
+ print(robot.state().q)
63
+ ```
64
+
65
+ ## How the pieces fit
66
+
67
+ Sim2Bot runs the physics (MuJoCo, compiled to WebAssembly) **in your browser**.
68
+ This package talks to that tab through a small local relay — the *bridge* — that
69
+ ships inside the package itself:
70
+
71
+ ```
72
+ your Python script ──► sim2bot bridge (localhost) ──► Sim2Bot tab in your browser
73
+ commands relay only MuJoCo physics
74
+ telemetry ◄── ◄── cameras, sensors
75
+ ```
76
+
77
+ The bridge forwards messages and holds no robot state of its own. Nothing about
78
+ your scene leaves your machine.
79
+
80
+ ## Install
81
+
82
+ ```sh
83
+ pip install sim2bot # control + telemetry
84
+ pip install "sim2bot[cv2]" # + camera frames decoded to numpy images
85
+ ```
86
+
87
+ Python 3.9 or newer.
88
+
89
+ ## First run
90
+
91
+ 1. Run your script. `auto_bridge=True` starts the local bridge if it is not
92
+ already running, and `wait_for_sim=True` waits for the browser.
93
+ 2. Open [app.sim2bot.com](https://app.sim2bot.com/), load a robot, and click
94
+ **Tools → Bridge → Connect**.
95
+
96
+ ```python
97
+ from sim2bot import Robot
98
+
99
+ with Robot(auto_bridge=True, wait_for_sim=True) as robot:
100
+ for info in robot.describe():
101
+ print(f"[{info.index}] {info.name} id={info.id} dof={info.dof}")
102
+ ```
103
+
104
+ `wait_for_sim=True` blocks until a simulator announces at least one robot; pass
105
+ `wait_for_sim_timeout=30` for a finite wait.
106
+
107
+ ## What you can do
108
+
109
+ ```python
110
+ from sim2bot import Robot
111
+
112
+ with Robot() as robot: # ws://localhost:8765/ws
113
+ info = robot.describe() # dof, home, limits, gripper, cameras, ...
114
+ print(info[0].index, info[0].id, info[0].name, info[0].dof)
115
+
116
+ robot.move_to(info[0].home) # joint position target
117
+ robot.set_velocity([0.1] * info[0].dof) # joint velocity target
118
+ robot.move_to_pose([0.45, 0.0, 0.35]) # Cartesian target, solved by browser IK
119
+ robot.move_trajectory([(0.0, q0), (1.5, q1)]) # timed joint trajectory
120
+ robot.stop()
121
+
122
+ state = robot.state()
123
+ print(state.q, state.qd, state.qdd, state.qddd) # position ... jerk
124
+ print(state.tcp, state.tcp_orientation) # TCP position + quaternion
125
+ print(state.tcp_linear_velocity, state.tcp_angular_velocity)
126
+
127
+ if info[0].has_gripper:
128
+ robot.gripper(1.0) # 0.0 closed .. 1.0 open
129
+
130
+ robot.base_velocity(vx=0.4, omega=0.35) # mobile / aerial bases
131
+
132
+ robot.marker("goal", "sphere", position=[0.45, 0, 0.35], scale=0.06)
133
+
134
+ for device in robot.room_devices(): # doors and windows in the scene
135
+ if device.motion == "actuated":
136
+ robot.set_room_opening(device.id, 1.0)
137
+
138
+ for cam in robot.cameras():
139
+ print(cam["id"], cam["label"])
140
+
141
+ with robot.camera("model:0", fps=30) as feed: # codec="raw" for lowest latency
142
+ frame = feed.read(timeout=2.0)
143
+ image = frame.image() # numpy BGR — needs the [cv2] extra
144
+ ```
145
+
146
+ Telemetry and camera reads are **latest-value, drop-don't-queue**: they return
147
+ the present, never a backlog.
148
+
149
+ Robot discovery gives you both `index` and `id`. Address commands by `index`
150
+ (`robot.move_to(q, robot=info.index)`); use `id` to recognise the same scene
151
+ robot across the app and your script.
152
+
153
+ Camera parameters you leave unset (`fps`, `width`, `height`, `quality`, `codec`)
154
+ inherit that camera's setting in the app, so your script overrides the GUI only
155
+ where it says so.
156
+
157
+ Runnable versions of all of this are in [`examples/`](examples/).
158
+
159
+ ## Command line
160
+
161
+ ```sh
162
+ sim2bot bridge # run the local bridge explicitly
163
+ sim2bot doctor # check bridge, browser, TCP/UDP, video, OpenCV
164
+ sim2bot list-robots # wait for the simulator and print index / id / name
165
+ sim2bot open # open the app (override with SIM2BOT_APP_URL)
166
+ ```
167
+
168
+ ## Transport
169
+
170
+ WebSocket by default. For a lower-latency control path with no TCP
171
+ head-of-line blocking:
172
+
173
+ ```python
174
+ Robot(transport="udp") # control + telemetry over UDP (8771)
175
+ ```
176
+
177
+ Camera frames always use the binary video WebSocket, because one frame is far
178
+ larger than a datagram. On localhost the two transports perform about the same;
179
+ UDP's advantage shows over a real network.
180
+
181
+ ## More than one simulator, and other machines
182
+
183
+ Use a room to pair one script with one browser tab:
184
+
185
+ ```python
186
+ Robot(room="bench-a") # or SIM2BOT_BRIDGE_ROOM=bench-a
187
+ ```
188
+
189
+ Without a room, commands go to the most recently connected tab.
190
+
191
+ Scripts on the same machine need no credentials. To drive the bridge from
192
+ another machine on the LAN, bind it to a LAN interface **with a token** — the
193
+ bridge refuses non-loopback clients otherwise:
194
+
195
+ ```sh
196
+ SIM2BOT_BRIDGE_TOKEN=choose-a-secret sim2bot bridge --host 0.0.0.0
197
+ ```
198
+
199
+ ```python
200
+ Robot(url="ws://192.168.1.42:8765/ws", api_key="choose-a-secret")
201
+ ```
202
+
203
+ ## Protocol
204
+
205
+ The wire format is documented in [`docs/protocol.md`](docs/protocol.md), and
206
+ [`fixtures/v1/`](fixtures/v1/) holds one example message per type. Those
207
+ fixtures are the contract: the tests here check this SDK against them, and the
208
+ Sim2Bot app checks its own implementation against the same files. If you are
209
+ writing a client in another language, implement against the fixtures.
210
+
211
+ ## Versions
212
+
213
+ The package version is the version to quote in a bug report. Each release says
214
+ which Sim2Bot app versions it is verified against in
215
+ [`CHANGELOG.md`](CHANGELOG.md).
216
+
217
+ ## Contributing
218
+
219
+ Issues and pull requests are welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md).
220
+ This repository holds the Python client, the relay and the protocol fixtures.
221
+ The Sim2Bot application itself is closed source, so bugs in the simulator, the
222
+ GUI or rendering are reported here but fixed there.
223
+
224
+ ## Licence
225
+
226
+ MIT — see [`LICENSE`](LICENSE).
@@ -0,0 +1,183 @@
1
+ # sim2bot — Python client for the Sim2Bot simulator
2
+
3
+ [![CI](https://github.com/Source-Robotics/sim2bot-python/actions/workflows/ci.yml/badge.svg)](https://github.com/Source-Robotics/sim2bot-python/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/sim2bot.svg)](https://pypi.org/project/sim2bot/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/sim2bot.svg)](https://pypi.org/project/sim2bot/)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
7
+
8
+ Control a robot in [Sim2Bot](https://sim2bot.com/) from Python, the same way you
9
+ would talk to a real one: send joint or Cartesian targets, read telemetry, open
10
+ and close a gripper, subscribe to camera feeds.
11
+
12
+ ```python
13
+ from sim2bot import Robot
14
+
15
+ with Robot(auto_bridge=True, wait_for_sim=True) as robot:
16
+ arm = robot.describe()[0]
17
+ robot.move_to(arm.home)
18
+ robot.wait_until_reached(arm.home)
19
+ print(robot.state().q)
20
+ ```
21
+
22
+ ## How the pieces fit
23
+
24
+ Sim2Bot runs the physics (MuJoCo, compiled to WebAssembly) **in your browser**.
25
+ This package talks to that tab through a small local relay — the *bridge* — that
26
+ ships inside the package itself:
27
+
28
+ ```
29
+ your Python script ──► sim2bot bridge (localhost) ──► Sim2Bot tab in your browser
30
+ commands relay only MuJoCo physics
31
+ telemetry ◄── ◄── cameras, sensors
32
+ ```
33
+
34
+ The bridge forwards messages and holds no robot state of its own. Nothing about
35
+ your scene leaves your machine.
36
+
37
+ ## Install
38
+
39
+ ```sh
40
+ pip install sim2bot # control + telemetry
41
+ pip install "sim2bot[cv2]" # + camera frames decoded to numpy images
42
+ ```
43
+
44
+ Python 3.9 or newer.
45
+
46
+ ## First run
47
+
48
+ 1. Run your script. `auto_bridge=True` starts the local bridge if it is not
49
+ already running, and `wait_for_sim=True` waits for the browser.
50
+ 2. Open [app.sim2bot.com](https://app.sim2bot.com/), load a robot, and click
51
+ **Tools → Bridge → Connect**.
52
+
53
+ ```python
54
+ from sim2bot import Robot
55
+
56
+ with Robot(auto_bridge=True, wait_for_sim=True) as robot:
57
+ for info in robot.describe():
58
+ print(f"[{info.index}] {info.name} id={info.id} dof={info.dof}")
59
+ ```
60
+
61
+ `wait_for_sim=True` blocks until a simulator announces at least one robot; pass
62
+ `wait_for_sim_timeout=30` for a finite wait.
63
+
64
+ ## What you can do
65
+
66
+ ```python
67
+ from sim2bot import Robot
68
+
69
+ with Robot() as robot: # ws://localhost:8765/ws
70
+ info = robot.describe() # dof, home, limits, gripper, cameras, ...
71
+ print(info[0].index, info[0].id, info[0].name, info[0].dof)
72
+
73
+ robot.move_to(info[0].home) # joint position target
74
+ robot.set_velocity([0.1] * info[0].dof) # joint velocity target
75
+ robot.move_to_pose([0.45, 0.0, 0.35]) # Cartesian target, solved by browser IK
76
+ robot.move_trajectory([(0.0, q0), (1.5, q1)]) # timed joint trajectory
77
+ robot.stop()
78
+
79
+ state = robot.state()
80
+ print(state.q, state.qd, state.qdd, state.qddd) # position ... jerk
81
+ print(state.tcp, state.tcp_orientation) # TCP position + quaternion
82
+ print(state.tcp_linear_velocity, state.tcp_angular_velocity)
83
+
84
+ if info[0].has_gripper:
85
+ robot.gripper(1.0) # 0.0 closed .. 1.0 open
86
+
87
+ robot.base_velocity(vx=0.4, omega=0.35) # mobile / aerial bases
88
+
89
+ robot.marker("goal", "sphere", position=[0.45, 0, 0.35], scale=0.06)
90
+
91
+ for device in robot.room_devices(): # doors and windows in the scene
92
+ if device.motion == "actuated":
93
+ robot.set_room_opening(device.id, 1.0)
94
+
95
+ for cam in robot.cameras():
96
+ print(cam["id"], cam["label"])
97
+
98
+ with robot.camera("model:0", fps=30) as feed: # codec="raw" for lowest latency
99
+ frame = feed.read(timeout=2.0)
100
+ image = frame.image() # numpy BGR — needs the [cv2] extra
101
+ ```
102
+
103
+ Telemetry and camera reads are **latest-value, drop-don't-queue**: they return
104
+ the present, never a backlog.
105
+
106
+ Robot discovery gives you both `index` and `id`. Address commands by `index`
107
+ (`robot.move_to(q, robot=info.index)`); use `id` to recognise the same scene
108
+ robot across the app and your script.
109
+
110
+ Camera parameters you leave unset (`fps`, `width`, `height`, `quality`, `codec`)
111
+ inherit that camera's setting in the app, so your script overrides the GUI only
112
+ where it says so.
113
+
114
+ Runnable versions of all of this are in [`examples/`](examples/).
115
+
116
+ ## Command line
117
+
118
+ ```sh
119
+ sim2bot bridge # run the local bridge explicitly
120
+ sim2bot doctor # check bridge, browser, TCP/UDP, video, OpenCV
121
+ sim2bot list-robots # wait for the simulator and print index / id / name
122
+ sim2bot open # open the app (override with SIM2BOT_APP_URL)
123
+ ```
124
+
125
+ ## Transport
126
+
127
+ WebSocket by default. For a lower-latency control path with no TCP
128
+ head-of-line blocking:
129
+
130
+ ```python
131
+ Robot(transport="udp") # control + telemetry over UDP (8771)
132
+ ```
133
+
134
+ Camera frames always use the binary video WebSocket, because one frame is far
135
+ larger than a datagram. On localhost the two transports perform about the same;
136
+ UDP's advantage shows over a real network.
137
+
138
+ ## More than one simulator, and other machines
139
+
140
+ Use a room to pair one script with one browser tab:
141
+
142
+ ```python
143
+ Robot(room="bench-a") # or SIM2BOT_BRIDGE_ROOM=bench-a
144
+ ```
145
+
146
+ Without a room, commands go to the most recently connected tab.
147
+
148
+ Scripts on the same machine need no credentials. To drive the bridge from
149
+ another machine on the LAN, bind it to a LAN interface **with a token** — the
150
+ bridge refuses non-loopback clients otherwise:
151
+
152
+ ```sh
153
+ SIM2BOT_BRIDGE_TOKEN=choose-a-secret sim2bot bridge --host 0.0.0.0
154
+ ```
155
+
156
+ ```python
157
+ Robot(url="ws://192.168.1.42:8765/ws", api_key="choose-a-secret")
158
+ ```
159
+
160
+ ## Protocol
161
+
162
+ The wire format is documented in [`docs/protocol.md`](docs/protocol.md), and
163
+ [`fixtures/v1/`](fixtures/v1/) holds one example message per type. Those
164
+ fixtures are the contract: the tests here check this SDK against them, and the
165
+ Sim2Bot app checks its own implementation against the same files. If you are
166
+ writing a client in another language, implement against the fixtures.
167
+
168
+ ## Versions
169
+
170
+ The package version is the version to quote in a bug report. Each release says
171
+ which Sim2Bot app versions it is verified against in
172
+ [`CHANGELOG.md`](CHANGELOG.md).
173
+
174
+ ## Contributing
175
+
176
+ Issues and pull requests are welcome — see [`CONTRIBUTING.md`](CONTRIBUTING.md).
177
+ This repository holds the Python client, the relay and the protocol fixtures.
178
+ The Sim2Bot application itself is closed source, so bugs in the simulator, the
179
+ GUI or rendering are reported here but fixed there.
180
+
181
+ ## Licence
182
+
183
+ MIT — see [`LICENSE`](LICENSE).
@@ -0,0 +1,8 @@
1
+ {
2
+ "type": "base_velocity",
3
+ "vx": 0.4,
4
+ "vy": 0.0,
5
+ "vz": 0.0,
6
+ "omega": 0.35,
7
+ "robot": 0
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "type": "camera_subscribe",
3
+ "camera": "model:0",
4
+ "fps": 30,
5
+ "width": 256,
6
+ "height": 256,
7
+ "quality": 80,
8
+ "codec": 0
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "camera_unsubscribe",
3
+ "camera": "model:0"
4
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "gripper",
3
+ "fraction": 0.25,
4
+ "robot": 0
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "hello",
3
+ "role": "controller",
4
+ "room": "bench-a"
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "joint_position",
3
+ "robot": 0,
4
+ "q": [0, -0.45, 0, -2.2, 0, 1.75, 0.8]
5
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "type": "joint_trajectory",
3
+ "robot": 0,
4
+ "loop": false,
5
+ "points": [
6
+ { "t": 0, "q": [0, -0.45, 0, -2.2, 0, 1.75, 0.8] },
7
+ { "t": 1.25, "q": [0.2, -0.35, 0.15, -2, 0.1, 1.5, 0.6] }
8
+ ]
9
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "joint_trajectory_stop",
3
+ "robot": 0
4
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "type": "joint_velocity",
3
+ "qd": [
4
+ 0.1,
5
+ 0.0,
6
+ -0.25,
7
+ 0.0,
8
+ 0.3,
9
+ 0.0,
10
+ 0.0
11
+ ],
12
+ "robot": 0
13
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "type": "marker",
3
+ "marker": {
4
+ "id": "grasp_target",
5
+ "shape": "arrow",
6
+ "from": [
7
+ 0.3,
8
+ 0.0,
9
+ 0.4
10
+ ],
11
+ "to": [
12
+ 0.3,
13
+ 0.0,
14
+ 0.1
15
+ ],
16
+ "color": [
17
+ 1.0,
18
+ 0.35,
19
+ 0.0,
20
+ 1.0
21
+ ],
22
+ "scale": 0.02
23
+ }
24
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "marker_clear"
3
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "marker_delete",
3
+ "id": "grasp_target"
4
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "type": "marker",
3
+ "marker": {
4
+ "id": "depth_cloud",
5
+ "shape": "points",
6
+ "points": [
7
+ [
8
+ 0.1,
9
+ 0.0,
10
+ 0.05
11
+ ],
12
+ [
13
+ 0.12,
14
+ 0.01,
15
+ 0.06
16
+ ],
17
+ [
18
+ 0.14,
19
+ -0.01,
20
+ 0.05
21
+ ]
22
+ ],
23
+ "color": [
24
+ 0.2,
25
+ 0.8,
26
+ 1.0,
27
+ 1.0
28
+ ],
29
+ "scale": 0.004
30
+ }
31
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "type": "reset",
3
+ "robot": 0
4
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "type": "room_opening",
3
+ "opening": "room_door_ab12cd34",
4
+ "fraction": 0.75
5
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "stop"
3
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "type": "tcp_pose",
3
+ "position": [
4
+ 0.45,
5
+ 0.0,
6
+ 0.35
7
+ ]
8
+ }