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.
- sim2bot-0.1.0/CHANGELOG.md +58 -0
- sim2bot-0.1.0/LICENSE +21 -0
- sim2bot-0.1.0/MANIFEST.in +11 -0
- sim2bot-0.1.0/PKG-INFO +226 -0
- sim2bot-0.1.0/README.md +183 -0
- sim2bot-0.1.0/fixtures/v1/base_velocity.json +8 -0
- sim2bot-0.1.0/fixtures/v1/camera_subscribe.json +9 -0
- sim2bot-0.1.0/fixtures/v1/camera_unsubscribe.json +4 -0
- sim2bot-0.1.0/fixtures/v1/gripper.json +5 -0
- sim2bot-0.1.0/fixtures/v1/hello_room.json +5 -0
- sim2bot-0.1.0/fixtures/v1/joint_position.json +5 -0
- sim2bot-0.1.0/fixtures/v1/joint_trajectory.json +9 -0
- sim2bot-0.1.0/fixtures/v1/joint_trajectory_stop.json +4 -0
- sim2bot-0.1.0/fixtures/v1/joint_velocity.json +13 -0
- sim2bot-0.1.0/fixtures/v1/marker.json +24 -0
- sim2bot-0.1.0/fixtures/v1/marker_clear.json +3 -0
- sim2bot-0.1.0/fixtures/v1/marker_delete.json +4 -0
- sim2bot-0.1.0/fixtures/v1/marker_points.json +31 -0
- sim2bot-0.1.0/fixtures/v1/reset.json +4 -0
- sim2bot-0.1.0/fixtures/v1/room_opening.json +5 -0
- sim2bot-0.1.0/fixtures/v1/stop.json +3 -0
- sim2bot-0.1.0/fixtures/v1/tcp_pose.json +8 -0
- sim2bot-0.1.0/fixtures/v1/tcp_pose_oriented.json +15 -0
- sim2bot-0.1.0/fixtures/v1/telemetry.json +24 -0
- sim2bot-0.1.0/pyproject.toml +59 -0
- sim2bot-0.1.0/setup.cfg +4 -0
- sim2bot-0.1.0/sim2bot/__init__.py +38 -0
- sim2bot-0.1.0/sim2bot/bridge.py +232 -0
- sim2bot-0.1.0/sim2bot/bridge_server.py +488 -0
- sim2bot-0.1.0/sim2bot/cli.py +292 -0
- sim2bot-0.1.0/sim2bot/client.py +1543 -0
- sim2bot-0.1.0/sim2bot.egg-info/SOURCES.txt +32 -0
- sim2bot-0.1.0/tests/test_bridge.py +278 -0
- sim2bot-0.1.0/tests/test_fixtures.py +255 -0
- 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
|
+
[](https://github.com/Source-Robotics/sim2bot-python/actions/workflows/ci.yml)
|
|
47
|
+
[](https://pypi.org/project/sim2bot/)
|
|
48
|
+
[](https://pypi.org/project/sim2bot/)
|
|
49
|
+
[](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).
|
sim2bot-0.1.0/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# sim2bot — Python client for the Sim2Bot simulator
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Source-Robotics/sim2bot-python/actions/workflows/ci.yml)
|
|
4
|
+
[](https://pypi.org/project/sim2bot/)
|
|
5
|
+
[](https://pypi.org/project/sim2bot/)
|
|
6
|
+
[](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,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,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
|
+
}
|