simulo-interfaces 0.7.0__tar.gz → 0.11.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.
- {simulo_interfaces-0.7.0/src/simulo_interfaces.egg-info → simulo_interfaces-0.11.0}/PKG-INFO +6 -5
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/pyproject.toml +11 -2
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/__init__.py +1 -1
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/__init__.py +190 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/actuator.py +53 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/asset.py +99 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/entity.py +180 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/light.py +87 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/materials.py +80 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/physics.py +154 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/pose.py +100 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/primitives.py +132 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/record.py +400 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/robot.py +378 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/scene.py +154 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/sensor.py +133 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/terrain.py +306 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/visual.py +302 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/authoring/world.py +111 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/exceptions.py +1 -1
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/ids.py +1 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/__init__.py +70 -1
- simulo_interfaces-0.11.0/src/simulo/interfaces/platform/artifacts.py +721 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/asset.py +2 -1
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/asset_catalog.py +77 -81
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/debug.py +4 -4
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/domain.py +5 -5
- simulo_interfaces-0.11.0/src/simulo/interfaces/platform/enums.py +177 -0
- simulo_interfaces-0.11.0/src/simulo/interfaces/platform/manifest.py +290 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/runs.py +75 -3
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/submit.py +28 -10
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/anomaly.py +74 -8
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/components.py +26 -6
- simulo_interfaces-0.11.0/src/simulo/interfaces/runtime/env.py +101 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/player.py +16 -1
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/scenario.py +9 -2
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/task.py +8 -1
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/trainer.py +10 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0/src/simulo_interfaces.egg-info}/PKG-INFO +6 -5
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/SOURCES.txt +18 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/requires.txt +5 -4
- simulo_interfaces-0.7.0/src/simulo/interfaces/platform/enums.py +0 -106
- simulo_interfaces-0.7.0/src/simulo/interfaces/runtime/env.py +0 -56
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/MANIFEST.in +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/PYPI.md +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/setup.cfg +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/app.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/callbacks.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/runtime.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/platform/volume.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/py.typed +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/__init__.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/policy.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo/interfaces/runtime/tensors.py +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/dependency_links.txt +0 -0
- {simulo_interfaces-0.7.0 → simulo_interfaces-0.11.0}/src/simulo_interfaces.egg-info/top_level.txt +0 -0
{simulo_interfaces-0.7.0/src/simulo_interfaces.egg-info → simulo_interfaces-0.11.0}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: simulo-interfaces
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0
|
|
4
4
|
Summary: Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package.
|
|
5
5
|
Author-email: Simulo Team <team@simulo.ai>
|
|
6
6
|
License: BSD-3-Clause
|
|
@@ -16,13 +16,14 @@ Classifier: Typing :: Typed
|
|
|
16
16
|
Requires-Python: >=3.11
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
Provides-Extra: dev
|
|
19
|
-
Requires-Dist: black
|
|
20
|
-
Requires-Dist: isort
|
|
21
|
-
Requires-Dist: ruff
|
|
22
|
-
Requires-Dist: mypy
|
|
19
|
+
Requires-Dist: black==26.5.1; extra == "dev"
|
|
20
|
+
Requires-Dist: isort==8.0.1; extra == "dev"
|
|
21
|
+
Requires-Dist: ruff==0.15.21; extra == "dev"
|
|
22
|
+
Requires-Dist: mypy==2.3.0; extra == "dev"
|
|
23
23
|
Requires-Dist: pytest>=8.2; extra == "dev"
|
|
24
24
|
Requires-Dist: build>=1.2; extra == "dev"
|
|
25
25
|
Requires-Dist: twine>=5.1; extra == "dev"
|
|
26
|
+
Requires-Dist: packaging>=23; extra == "dev"
|
|
26
27
|
Provides-Extra: release
|
|
27
28
|
Requires-Dist: commitizen>=3.27; extra == "release"
|
|
28
29
|
Requires-Dist: build>=1.2; extra == "release"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simulo-interfaces"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.11.0"
|
|
8
8
|
description = "Type contracts for the Simulo SDK. Installed automatically as a dependency of the simulo package."
|
|
9
9
|
readme = "PYPI.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -26,7 +26,16 @@ classifiers = [
|
|
|
26
26
|
dependencies = []
|
|
27
27
|
|
|
28
28
|
[project.optional-dependencies]
|
|
29
|
-
|
|
29
|
+
# black/isort/ruff/mypy pinned EXACT, not >=: see simulo-backend/pyproject.toml's
|
|
30
|
+
# `dev` extra for the full rationale (2026-08-01 ruff 0.15.21->0.16.1 CI incident).
|
|
31
|
+
# Keep in lockstep with `.github/workflows/simulo-interfaces-ci.yml`'s
|
|
32
|
+
# `ruff`/`black`/`isort`/`mypy` steps, which resolve their versions from THIS extra
|
|
33
|
+
# (`pip install -e ".[dev]"`).
|
|
34
|
+
dev = ["black==26.5.1", "isort==8.0.1", "ruff==0.15.21", "mypy==2.3.0", "pytest>=8.2", "build>=1.2",
|
|
35
|
+
"twine>=5.1", "packaging>=23"]
|
|
36
|
+
# `packaging` is a direct test dependency, not incidental: the consumer-pin guard parses
|
|
37
|
+
# PEP 508 requirements with it. It arrives transitively via pytest today, which is exactly
|
|
38
|
+
# why it is declared here — a transitive dep that disappears takes the guard with it.
|
|
30
39
|
# `dev` carries build/twine but deliberately not commitizen; `release` below
|
|
31
40
|
# adds commitizen for cutting version bumps without a second build/twine copy.
|
|
32
41
|
release = ["commitizen>=3.27", "build>=1.2", "twine>=5.1"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Simulo Interfaces — implementation-free contract layer for the Simulo platform.
|
|
2
2
|
|
|
3
|
-
Torch-free, zero-runtime-dependency
|
|
3
|
+
Torch-free, zero-runtime-dependency. Importable on a laptop with no
|
|
4
4
|
torch / numpy / gymnasium / Isaac / AWS / HTTP / DB installed. Two parts:
|
|
5
5
|
|
|
6
6
|
* **Part A — ``simulo.interfaces.runtime``**: tensor-library-agnostic structural
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""Part C — the typed authoring surface.
|
|
2
|
+
|
|
3
|
+
The **relocation and mirror destination** for the Simulo authoring value types.
|
|
4
|
+
Each type here has exactly ONE definition — this one — shared by both
|
|
5
|
+
distributions: the thin client authors these values at submit (torch-free,
|
|
6
|
+
e.g. ``simulo.Pose(xyz=(1, 2, 3))``) and the backend executes them on the
|
|
7
|
+
worker. There is no other copy and no re-export shim anywhere ("nuke as you
|
|
8
|
+
go", per the owner's 2026-07-26 directive recorded in the plan): the former
|
|
9
|
+
backend ``core`` modules for these types are deleted, so ``isinstance`` keeps
|
|
10
|
+
working because only this definition exists.
|
|
11
|
+
|
|
12
|
+
Relocated so far — Wave C1: ``pose`` (``Pose``), ``materials`` (``Material``,
|
|
13
|
+
``SurfaceMaterial``), ``physics`` (``Physics``, ``Collision``, ``RigidPhysics``,
|
|
14
|
+
``DeformableMaterial``, ``DeformablePhysics``), ``asset`` (``AssetSource``,
|
|
15
|
+
``USDAsset``, ``URDFAsset`` — the model-source specs, distinct from the thin
|
|
16
|
+
client's registry-handle ``simulo.Asset``; renamed from ``Asset`` — owner
|
|
17
|
+
decision — to resolve that exact name collision), and ``light`` (``Light``,
|
|
18
|
+
``LightConfig``, ``DistantLight``, ``DomeLight``). Wave C2: ``terrain``
|
|
19
|
+
(``Terrain``, ``TerrainConfig``, ``GroundPlane``, ``SubTerrainConfig``,
|
|
20
|
+
``RoughTerrain``), ``primitives`` (``PrimitiveShape``, ``Cone``,
|
|
21
|
+
``Cuboid``, ``Sphere``, ``Cylinder``, ``Transform``), ``entity`` (``Entity``,
|
|
22
|
+
``AssetEntity``), and ``visual`` (``Visual``, ``VisualMarkerBase``,
|
|
23
|
+
``AxesMarker``, ``SphereMarker``, ``ArrowMarker``, ``PointMarker``).
|
|
24
|
+
Wave C4: ``record`` (``RecordConfig`` — the MCAP recording configuration;
|
|
25
|
+
stdlib-only, so it classifies RELOCATE, and the backend recorder imports it
|
|
26
|
+
from here), and ``world`` (``World``, ``USDWorld``): ``Terrain`` is the
|
|
27
|
+
ground you *generate* (``plane``, ``rough``); ``World.usd(...)`` returns
|
|
28
|
+
``USDWorld``, a prebuilt place you *bring*.
|
|
29
|
+
|
|
30
|
+
Mirrored so far — Wave C2: ``scene`` (``SceneProtocol``, ``SceneGroupProtocol``
|
|
31
|
+
— the first MIRROR; the concrete ``Scene``/``SceneGroup`` stay in the backend
|
|
32
|
+
package and explicitly inherit these Protocols). Wave C3: ``robot``
|
|
33
|
+
(``RobotProtocol``, plus ``RobotStateProtocol`` — the grouped live-state
|
|
34
|
+
contract behind ``robot.state``), ``sensor`` (``SensorProtocol``,
|
|
35
|
+
``CameraProtocol``), and ``actuator`` (``ActuatorProtocol``) — same
|
|
36
|
+
mechanism; the concrete classes
|
|
37
|
+
stay in the backend package and explicitly inherit their Protocols, and the
|
|
38
|
+
other concrete sensor/actuator subclasses conform through their bases. Later
|
|
39
|
+
waves add the remaining RELOCATE-classified types and MIRROR Protocols.
|
|
40
|
+
|
|
41
|
+
**R-C3 is the hard constraint on everything that lands here:** no module in
|
|
42
|
+
this package — or anywhere else in ``simulo-interfaces`` — may import
|
|
43
|
+
``simulo.core``, ``simulo.backend``, or the thin client's private internal
|
|
44
|
+
package, at import time or at call time (the ``Scene`` trap: zero torch
|
|
45
|
+
imports, but call-time imports of torch-coupled ``core`` modules deep inside a
|
|
46
|
+
method body). Guarded by ``tests/test_no_core_dependency.py`` in this package —
|
|
47
|
+
both a static import-statement guard and a runtime ``sys.modules`` check that
|
|
48
|
+
imports every submodule AND instantiates/calls the relocated API, because the
|
|
49
|
+
static guard alone cannot see ``from simulo import core``, dynamic access, or a
|
|
50
|
+
call-time-only import buried in a method body.
|
|
51
|
+
|
|
52
|
+
Two relocation mechanisms select which types land here and how (see the derived
|
|
53
|
+
plan for the full worked example and rejected alternatives):
|
|
54
|
+
|
|
55
|
+
* **RELOCATE** — the class definition MOVES here; the old ``core/<module>.py``
|
|
56
|
+
is deleted and every call site rewritten in the same PR (no re-export shims).
|
|
57
|
+
Reserved for types with zero import-time *or* call-time dependency on
|
|
58
|
+
anything that cannot live in a zero-dependency package.
|
|
59
|
+
* **MIRROR** — a ``typing.Protocol`` (named ``*Protocol``, matching the
|
|
60
|
+
``runtime`` contracts) with real signatures and ``...`` bodies lands here,
|
|
61
|
+
describing the class's PUBLIC surface only; the backend's ``core/`` class
|
|
62
|
+
explicitly INHERITS it (nominal conformance, the same pattern
|
|
63
|
+
``simulo-protocol`` already blesses for the ``runtime`` Protocols). Reserved
|
|
64
|
+
for everything else — anything with a real or call-time dependency on torch,
|
|
65
|
+
numpy, gymnasium, skrl, isaaclab, or another MIRROR-classified ``core``
|
|
66
|
+
module. Divergence is gated in three measured layers, because no single one
|
|
67
|
+
suffices: mypy fails signature-*shape* drift (arity, kinds,
|
|
68
|
+
default-presence, types) at the ``core/`` definition site but is SILENT on
|
|
69
|
+
parameter renames and on a property degrading to a plain attribute — those
|
|
70
|
+
need the backend suite's signature-conformance test (per-member bidirectional
|
|
71
|
+
— it compares the live contract against the live implementation — plus a
|
|
72
|
+
member-SET equality check over the implementation's statically-derivable
|
|
73
|
+
public surface: class-body names across its MRO and ``__init__``-bound
|
|
74
|
+
instance attributes, with a pinned documented-omissions allowlist; an extra
|
|
75
|
+
public member is legal subtyping no per-member loop can see, and attributes
|
|
76
|
+
bound outside ``__init__`` stay statically invisible even to the set check)
|
|
77
|
+
— and
|
|
78
|
+
constructor signatures need a separate ``__call__``-Protocol pin in the
|
|
79
|
+
backend's static conformance checks (type checkers exempt ``__init__`` from
|
|
80
|
+
override checks).
|
|
81
|
+
|
|
82
|
+
The checked-in authoring-surface inventory table classifies every name
|
|
83
|
+
currently referenced by the example trees (RELOCATE or MIRROR, source module,
|
|
84
|
+
and cross-references for cryptic engine-style names) — that table, not this
|
|
85
|
+
docstring, is the source of truth for what lands here and when.
|
|
86
|
+
"""
|
|
87
|
+
|
|
88
|
+
from simulo.interfaces.authoring.actuator import ActuatorProtocol
|
|
89
|
+
from simulo.interfaces.authoring.asset import AssetSource, URDFAsset, USDAsset
|
|
90
|
+
from simulo.interfaces.authoring.entity import AssetEntity, Entity
|
|
91
|
+
from simulo.interfaces.authoring.light import DistantLight, DomeLight, Light, LightConfig
|
|
92
|
+
from simulo.interfaces.authoring.materials import Material, SurfaceMaterial
|
|
93
|
+
from simulo.interfaces.authoring.physics import (
|
|
94
|
+
Collision,
|
|
95
|
+
DeformableMaterial,
|
|
96
|
+
DeformablePhysics,
|
|
97
|
+
Physics,
|
|
98
|
+
RigidPhysics,
|
|
99
|
+
)
|
|
100
|
+
from simulo.interfaces.authoring.pose import Pose
|
|
101
|
+
from simulo.interfaces.authoring.primitives import (
|
|
102
|
+
Cone,
|
|
103
|
+
Cuboid,
|
|
104
|
+
Cylinder,
|
|
105
|
+
PrimitiveShape,
|
|
106
|
+
Sphere,
|
|
107
|
+
Transform,
|
|
108
|
+
)
|
|
109
|
+
from simulo.interfaces.authoring.record import RecordConfig
|
|
110
|
+
from simulo.interfaces.authoring.robot import RobotProtocol, RobotStateProtocol
|
|
111
|
+
from simulo.interfaces.authoring.scene import SceneGroupProtocol, SceneProtocol
|
|
112
|
+
from simulo.interfaces.authoring.sensor import CameraProtocol, SensorProtocol
|
|
113
|
+
from simulo.interfaces.authoring.terrain import (
|
|
114
|
+
GroundPlane,
|
|
115
|
+
RoughTerrain,
|
|
116
|
+
SubTerrainConfig,
|
|
117
|
+
Terrain,
|
|
118
|
+
TerrainConfig,
|
|
119
|
+
)
|
|
120
|
+
from simulo.interfaces.authoring.visual import (
|
|
121
|
+
ArrowMarker,
|
|
122
|
+
AxesMarker,
|
|
123
|
+
PointMarker,
|
|
124
|
+
SphereMarker,
|
|
125
|
+
Visual,
|
|
126
|
+
VisualMarkerBase,
|
|
127
|
+
)
|
|
128
|
+
from simulo.interfaces.authoring.world import USDWorld, World
|
|
129
|
+
|
|
130
|
+
__all__ = [
|
|
131
|
+
# pose
|
|
132
|
+
"Pose",
|
|
133
|
+
# materials
|
|
134
|
+
"Material",
|
|
135
|
+
"SurfaceMaterial",
|
|
136
|
+
# physics
|
|
137
|
+
"Collision",
|
|
138
|
+
"RigidPhysics",
|
|
139
|
+
"DeformableMaterial",
|
|
140
|
+
"DeformablePhysics",
|
|
141
|
+
"Physics",
|
|
142
|
+
# asset (model-source specs)
|
|
143
|
+
"AssetSource",
|
|
144
|
+
"USDAsset",
|
|
145
|
+
"URDFAsset",
|
|
146
|
+
# light
|
|
147
|
+
"LightConfig",
|
|
148
|
+
"DistantLight",
|
|
149
|
+
"DomeLight",
|
|
150
|
+
"Light",
|
|
151
|
+
# terrain (ground you generate)
|
|
152
|
+
"TerrainConfig",
|
|
153
|
+
"GroundPlane",
|
|
154
|
+
"SubTerrainConfig",
|
|
155
|
+
"RoughTerrain",
|
|
156
|
+
"Terrain",
|
|
157
|
+
# world (a prebuilt place you bring — split from terrain in Wave C4)
|
|
158
|
+
"USDWorld",
|
|
159
|
+
"World",
|
|
160
|
+
# primitives
|
|
161
|
+
"PrimitiveShape",
|
|
162
|
+
"Cone",
|
|
163
|
+
"Cuboid",
|
|
164
|
+
"Sphere",
|
|
165
|
+
"Cylinder",
|
|
166
|
+
"Transform",
|
|
167
|
+
# entity
|
|
168
|
+
"Entity",
|
|
169
|
+
"AssetEntity",
|
|
170
|
+
# record (RELOCATED Wave C4 — the MCAP recording config; its helper
|
|
171
|
+
# functions stay importable from ``simulo.interfaces.authoring.record``)
|
|
172
|
+
"RecordConfig",
|
|
173
|
+
# visual
|
|
174
|
+
"VisualMarkerBase",
|
|
175
|
+
"AxesMarker",
|
|
176
|
+
"SphereMarker",
|
|
177
|
+
"ArrowMarker",
|
|
178
|
+
"PointMarker",
|
|
179
|
+
"Visual",
|
|
180
|
+
# scene (MIRROR — the concrete classes live in the backend package)
|
|
181
|
+
"SceneProtocol",
|
|
182
|
+
"SceneGroupProtocol",
|
|
183
|
+
# robot / sensor / actuator (MIRROR — the concrete classes live in the
|
|
184
|
+
# backend package and explicitly inherit these Protocols)
|
|
185
|
+
"RobotProtocol",
|
|
186
|
+
"RobotStateProtocol",
|
|
187
|
+
"SensorProtocol",
|
|
188
|
+
"CameraProtocol",
|
|
189
|
+
"ActuatorProtocol",
|
|
190
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""``ActuatorProtocol`` — the declared actuator authoring contract.
|
|
2
|
+
|
|
3
|
+
A MIRROR, not a relocation (same mechanism as the Scene, Robot, and Sensor
|
|
4
|
+
contracts in this package): the concrete ``Actuator`` implementation stays in
|
|
5
|
+
the backend package — its command path writes into a live simulation engine
|
|
6
|
+
handle — so what lives here is the declared public surface only.
|
|
7
|
+
|
|
8
|
+
The backend's concrete ``Actuator`` base class explicitly inherits this
|
|
9
|
+
Protocol (nominal conformance); concrete actuator types (e.g. the surface
|
|
10
|
+
gripper) inherit it through the base and keep their richer surfaces as
|
|
11
|
+
implementation-defined extensions.
|
|
12
|
+
|
|
13
|
+
Enforcement is the standard four layers for a mirror (see the Robot contract
|
|
14
|
+
module's docstring). ``get_state`` faithfully mirrors today's untyped return:
|
|
15
|
+
a named supported subset for actuator state is a later, separate contract
|
|
16
|
+
decision, deliberately not designed here.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from typing import Any, Optional, Protocol, runtime_checkable
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@runtime_checkable
|
|
23
|
+
class ActuatorProtocol(Protocol):
|
|
24
|
+
"""The actuator authoring contract — an action interface for robots.
|
|
25
|
+
|
|
26
|
+
An actuator is configured at authoring time, attached to a scene path,
|
|
27
|
+
and driven with commands during simulation. Concrete actuator types
|
|
28
|
+
define their own command and state shapes.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
path: Optional[str]
|
|
32
|
+
"""Scene path where the actuator is attached (may be set via the scene)."""
|
|
33
|
+
|
|
34
|
+
enabled: bool
|
|
35
|
+
"""Whether the actuator is active."""
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def name(self) -> Optional[str]:
|
|
39
|
+
"""Actuator name — set by the scene when the actuator is added."""
|
|
40
|
+
...
|
|
41
|
+
|
|
42
|
+
def set_command(self, command: Any) -> None:
|
|
43
|
+
"""Set an actuator-specific command. Commands are buffered and
|
|
44
|
+
flushed automatically before the next physics step."""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
def get_state(self) -> Any:
|
|
48
|
+
"""Current actuator-specific state."""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
def reset(self) -> None:
|
|
52
|
+
"""Reset the actuator to its default state."""
|
|
53
|
+
...
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Model-source asset specs — USD/URDF sources a scene loads.
|
|
2
|
+
|
|
3
|
+
Owns the canonical ``AssetSource`` / ``USDAsset`` / ``URDFAsset`` model-source
|
|
4
|
+
dataclasses. Distinct from the thin client's user-facing ``simulo.Asset``
|
|
5
|
+
registry handle (a catalog ref like ``robot/so-arm-100:v3``): these classes
|
|
6
|
+
name a USD/URDF *file source* to load into a scene, and the backend consumes
|
|
7
|
+
them when it builds the simulation.
|
|
8
|
+
|
|
9
|
+
Renamed from ``Asset`` (owner decision): the old name collided with the
|
|
10
|
+
thin client's registry-handle ``simulo.Asset`` — same name, different
|
|
11
|
+
constructor, different members, both user-facing. Nothing failed on the
|
|
12
|
+
collision (both expose ``.usd()``/``.urdf()``, the handle's just returns
|
|
13
|
+
``Any``), which is exactly why it was worth a rename rather than a shim.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from typing import TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class AssetSource:
|
|
22
|
+
"""Base model-source asset class."""
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
# ``AssetSource.usd`` / ``AssetSource.urdf`` are attached dynamically
|
|
26
|
+
# below (they return the ``USDAsset`` / ``URDFAsset`` subclasses,
|
|
27
|
+
# which are defined after this class). These declarations never
|
|
28
|
+
# execute; they exist so a type checker sees the convenience aliases
|
|
29
|
+
# with their precise signatures instead of rejecting
|
|
30
|
+
# ``AssetSource.usd(...)`` as an unknown attribute.
|
|
31
|
+
@classmethod
|
|
32
|
+
def usd(cls, path: str) -> "USDAsset": ...
|
|
33
|
+
|
|
34
|
+
@classmethod
|
|
35
|
+
def urdf(cls, path: str) -> "URDFAsset": ...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@dataclass
|
|
39
|
+
class USDAsset(AssetSource):
|
|
40
|
+
"""USD file asset.
|
|
41
|
+
|
|
42
|
+
Attributes:
|
|
43
|
+
path: Path to USD file (supports file://, nucleus:// schemes). The
|
|
44
|
+
legacy simulo:// path alias is REMOVED — 'simulo/...' is a catalog
|
|
45
|
+
ref ([publisher/]kind/name[:vN], 'simulo' = the global-catalog
|
|
46
|
+
publisher), resolved through
|
|
47
|
+
simulo.Asset.from_registry("robot/<name>:v1"), never a runtime
|
|
48
|
+
path scheme. A simulo:// path raises a clear migration error at
|
|
49
|
+
resolution time.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
path: str
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def usd(cls, path: str) -> "USDAsset":
|
|
56
|
+
"""Create a USD asset.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
path: Path to USD file
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
USDAsset instance
|
|
63
|
+
"""
|
|
64
|
+
return cls(path=path)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@dataclass
|
|
68
|
+
class URDFAsset(AssetSource):
|
|
69
|
+
"""URDF file asset.
|
|
70
|
+
|
|
71
|
+
Attributes:
|
|
72
|
+
path: Path to URDF file
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
path: str
|
|
76
|
+
|
|
77
|
+
@classmethod
|
|
78
|
+
def urdf(cls, path: str) -> "URDFAsset":
|
|
79
|
+
"""Create a URDF asset.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
path: Path to URDF file
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
URDFAsset instance
|
|
86
|
+
"""
|
|
87
|
+
return cls(path=path)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Alias for convenience — callers reach for `AssetSource.usd(...)` /
|
|
91
|
+
# `AssetSource.urdf(...)`.
|
|
92
|
+
# Attached dynamically; the TYPE_CHECKING declarations on AssetSource above
|
|
93
|
+
# are what let a type checker see them.
|
|
94
|
+
AssetSource.usd = USDAsset.usd # type: ignore[method-assign]
|
|
95
|
+
AssetSource.urdf = URDFAsset.urdf # type: ignore[method-assign]
|
|
96
|
+
|
|
97
|
+
# Explicit public surface — keeps the TYPE_CHECKING import (needed for the
|
|
98
|
+
# static-only `usd`/`urdf` declarations above) off the star-import namespace.
|
|
99
|
+
__all__ = ["AssetSource", "USDAsset", "URDFAsset"]
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"""Entity abstraction for objects in the scene."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Optional, Tuple
|
|
5
|
+
|
|
6
|
+
from simulo.interfaces.authoring.asset import AssetSource
|
|
7
|
+
from simulo.interfaces.authoring.materials import Material
|
|
8
|
+
from simulo.interfaces.authoring.physics import DeformablePhysics, RigidPhysics
|
|
9
|
+
from simulo.interfaces.authoring.pose import Pose
|
|
10
|
+
from simulo.interfaces.authoring.primitives import Cone, Cuboid, Cylinder, Sphere
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class Entity:
|
|
15
|
+
"""An Entity is any object that can exist within a Scene.
|
|
16
|
+
|
|
17
|
+
Entities represent presence. They exist in space, have identity,
|
|
18
|
+
and may have physical state.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
name: str
|
|
22
|
+
pose: Pose = field(default_factory=Pose.identity)
|
|
23
|
+
material: Optional[Material] = None
|
|
24
|
+
physics: Optional[RigidPhysics | DeformablePhysics] = None
|
|
25
|
+
|
|
26
|
+
class primitive:
|
|
27
|
+
"""Factory for primitive entities."""
|
|
28
|
+
|
|
29
|
+
@staticmethod
|
|
30
|
+
def cone(
|
|
31
|
+
name: str,
|
|
32
|
+
radius: float = 0.5,
|
|
33
|
+
height: float = 1.0,
|
|
34
|
+
pose: Optional[Pose] = None,
|
|
35
|
+
material: Optional[Material] = None,
|
|
36
|
+
physics: Optional[RigidPhysics | DeformablePhysics] = None,
|
|
37
|
+
) -> Cone:
|
|
38
|
+
"""Create a cone entity.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
name: Entity name
|
|
42
|
+
radius: Cone base radius
|
|
43
|
+
height: Cone height
|
|
44
|
+
pose: Pose in space
|
|
45
|
+
material: Visual material
|
|
46
|
+
physics: Physics properties
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Cone entity
|
|
50
|
+
"""
|
|
51
|
+
return Cone(
|
|
52
|
+
name=name,
|
|
53
|
+
radius=radius,
|
|
54
|
+
height=height,
|
|
55
|
+
pose=pose or Pose.identity(),
|
|
56
|
+
material=material,
|
|
57
|
+
physics=physics,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def cuboid(
|
|
62
|
+
name: str,
|
|
63
|
+
size: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
|
64
|
+
pose: Optional[Pose] = None,
|
|
65
|
+
material: Optional[Material] = None,
|
|
66
|
+
physics: Optional[RigidPhysics | DeformablePhysics] = None,
|
|
67
|
+
) -> Cuboid:
|
|
68
|
+
"""Create a cuboid entity.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
name: Entity name
|
|
72
|
+
size: Box size as (width, depth, height)
|
|
73
|
+
pose: Pose in space
|
|
74
|
+
material: Visual material
|
|
75
|
+
physics: Physics properties
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
Cuboid entity
|
|
79
|
+
"""
|
|
80
|
+
return Cuboid(
|
|
81
|
+
name=name,
|
|
82
|
+
size=size,
|
|
83
|
+
pose=pose or Pose.identity(),
|
|
84
|
+
material=material,
|
|
85
|
+
physics=physics,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def sphere(
|
|
90
|
+
name: str,
|
|
91
|
+
radius: float = 0.5,
|
|
92
|
+
pose: Optional[Pose] = None,
|
|
93
|
+
material: Optional[Material] = None,
|
|
94
|
+
physics: Optional[RigidPhysics | DeformablePhysics] = None,
|
|
95
|
+
) -> Sphere:
|
|
96
|
+
"""Create a sphere entity.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
name: Entity name
|
|
100
|
+
radius: Sphere radius
|
|
101
|
+
pose: Pose in space
|
|
102
|
+
material: Visual material
|
|
103
|
+
physics: Physics properties
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Sphere entity
|
|
107
|
+
"""
|
|
108
|
+
return Sphere(
|
|
109
|
+
name=name,
|
|
110
|
+
radius=radius,
|
|
111
|
+
pose=pose or Pose.identity(),
|
|
112
|
+
material=material,
|
|
113
|
+
physics=physics,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
@staticmethod
|
|
117
|
+
def cylinder(
|
|
118
|
+
name: str,
|
|
119
|
+
radius: float = 0.5,
|
|
120
|
+
height: float = 1.0,
|
|
121
|
+
pose: Optional[Pose] = None,
|
|
122
|
+
material: Optional[Material] = None,
|
|
123
|
+
physics: Optional[RigidPhysics | DeformablePhysics] = None,
|
|
124
|
+
) -> Cylinder:
|
|
125
|
+
"""Create a cylinder entity.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
name: Entity name
|
|
129
|
+
radius: Cylinder radius
|
|
130
|
+
height: Cylinder height
|
|
131
|
+
pose: Pose in space
|
|
132
|
+
material: Visual material
|
|
133
|
+
physics: Physics properties
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
Cylinder entity
|
|
137
|
+
"""
|
|
138
|
+
return Cylinder(
|
|
139
|
+
name=name,
|
|
140
|
+
radius=radius,
|
|
141
|
+
height=height,
|
|
142
|
+
pose=pose or Pose.identity(),
|
|
143
|
+
material=material,
|
|
144
|
+
physics=physics,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def from_asset(
|
|
149
|
+
name: str,
|
|
150
|
+
asset: AssetSource,
|
|
151
|
+
pose: Optional[Pose] = None,
|
|
152
|
+
) -> "AssetEntity":
|
|
153
|
+
"""Create an entity from a USD or URDF asset.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
name: Entity name
|
|
157
|
+
asset: Asset specification
|
|
158
|
+
pose: Pose in space
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
AssetEntity instance
|
|
162
|
+
"""
|
|
163
|
+
return AssetEntity(
|
|
164
|
+
name=name,
|
|
165
|
+
asset=asset,
|
|
166
|
+
pose=pose or Pose.identity(),
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@dataclass
|
|
171
|
+
class AssetEntity(Entity):
|
|
172
|
+
"""Entity loaded from an external asset file.
|
|
173
|
+
|
|
174
|
+
Attributes:
|
|
175
|
+
asset: Asset specification (USD, URDF, etc.). Required at construction;
|
|
176
|
+
``None`` is not a valid default but is kept here to preserve the
|
|
177
|
+
existing dataclass field ordering. Callers always supply this.
|
|
178
|
+
"""
|
|
179
|
+
|
|
180
|
+
asset: Optional[AssetSource] = None
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Light source definitions."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Optional, Tuple
|
|
5
|
+
|
|
6
|
+
from simulo.interfaces.authoring.pose import Pose
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class LightConfig:
|
|
11
|
+
"""Base light configuration."""
|
|
12
|
+
|
|
13
|
+
name: str
|
|
14
|
+
intensity: float = 1000.0
|
|
15
|
+
color: Tuple[float, float, float] = (1.0, 1.0, 1.0)
|
|
16
|
+
pose: Pose = field(default_factory=Pose.identity)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class DistantLight(LightConfig):
|
|
21
|
+
"""Distant (directional) light source.
|
|
22
|
+
|
|
23
|
+
Similar to sunlight - parallel rays from infinity.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class DomeLight(LightConfig):
|
|
31
|
+
"""Dome light for ambient illumination."""
|
|
32
|
+
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class Light:
|
|
37
|
+
"""Light factory."""
|
|
38
|
+
|
|
39
|
+
@staticmethod
|
|
40
|
+
def distant(
|
|
41
|
+
name: str = "distantLight",
|
|
42
|
+
intensity: float = 1000.0,
|
|
43
|
+
color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
|
44
|
+
pose: Optional[Pose] = None,
|
|
45
|
+
) -> DistantLight:
|
|
46
|
+
"""Create a distant light.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
name: Light name
|
|
50
|
+
intensity: Light intensity
|
|
51
|
+
color: RGB color
|
|
52
|
+
pose: Pose in space
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
DistantLight instance
|
|
56
|
+
"""
|
|
57
|
+
return DistantLight(
|
|
58
|
+
name=name,
|
|
59
|
+
intensity=intensity,
|
|
60
|
+
color=color,
|
|
61
|
+
pose=pose or Pose.identity(),
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def dome(
|
|
66
|
+
name: str = "domeLight",
|
|
67
|
+
intensity: float = 1000.0,
|
|
68
|
+
color: Tuple[float, float, float] = (1.0, 1.0, 1.0),
|
|
69
|
+
) -> DomeLight:
|
|
70
|
+
"""Create a dome light.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
name: Light name
|
|
74
|
+
intensity: Light intensity
|
|
75
|
+
color: RGB color
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
DomeLight instance
|
|
79
|
+
"""
|
|
80
|
+
return DomeLight(
|
|
81
|
+
name=name,
|
|
82
|
+
intensity=intensity,
|
|
83
|
+
color=color,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
__all__ = ["LightConfig", "DistantLight", "DomeLight", "Light"]
|