simulo-interfaces 0.23.0__tar.gz → 0.24.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.23.0/src/simulo_interfaces.egg-info → simulo_interfaces-0.24.0}/PKG-INFO +1 -1
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/pyproject.toml +1 -1
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/__init__.py +16 -10
- simulo_interfaces-0.24.0/src/simulo/interfaces/authoring/policy_inputs.py +207 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/prop.py +12 -6
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/record.py +5 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/robot.py +21 -9
- simulo_interfaces-0.24.0/src/simulo/interfaces/authoring/robot_config.py +82 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/scene.py +6 -1
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/sensor.py +9 -1
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/asset_catalog.py +2 -2
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/evaluation.py +9 -3
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/onnx_bundle.py +192 -45
- simulo_interfaces-0.24.0/src/simulo/interfaces/platform/policy_checkpoint.py +89 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/runs.py +9 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/submit.py +3 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/systems.py +6 -7
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/__init__.py +2 -0
- simulo_interfaces-0.24.0/src/simulo/interfaces/runtime/policy_frames.py +42 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/task.py +30 -1
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0/src/simulo_interfaces.egg-info}/PKG-INFO +1 -1
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo_interfaces.egg-info/SOURCES.txt +4 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/MANIFEST.in +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/PYPI.md +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/setup.cfg +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/__init__.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/actuator.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/asset.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/checkpoint.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/entity.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/light.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/materials.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/physics.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/pose.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/primitives.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/terrain.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/visual.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/world.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/exceptions.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/ids.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/__init__.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/_payload.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/app.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/asset.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/callbacks.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/debug.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/domain.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/enums.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/job_events.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/manifest.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/outputs.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/preview.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/runtime.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/volume.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/py.typed +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/anomaly.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/components.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/env.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/player.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/policy.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/tensors.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/runtime/trainer.py +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo_interfaces.egg-info/dependency_links.txt +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo_interfaces.egg-info/requires.txt +0 -0
- {simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo_interfaces.egg-info/top_level.txt +0 -0
|
@@ -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.24.0"
|
|
8
8
|
description = "Typed Python contracts for the Simulo cloud robotics SDK and managed simulation runtime."
|
|
9
9
|
readme = "PYPI.md"
|
|
10
10
|
requires-python = ">=3.11"
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/__init__.py
RENAMED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
"""Part C — the typed authoring surface.
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
Each type
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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.
|
|
3
|
+
The relocation and mirror destination for shared authoring value types.
|
|
4
|
+
Each value type has one definition here, used by the torch-free client when
|
|
5
|
+
submitting a job and by the backend when executing it. Robot configuration
|
|
6
|
+
records retain their existing backend import paths as re-exports of these
|
|
7
|
+
same objects.
|
|
11
8
|
|
|
12
9
|
Relocated so far — Wave C1: ``pose`` (``Pose``), ``materials`` (``Material``,
|
|
13
10
|
``SurfaceMaterial``), ``physics`` (``Physics``, ``Collision``, ``RigidPhysics``,
|
|
@@ -53,8 +50,9 @@ clearly in a submit-only installation.
|
|
|
53
50
|
Two relocation mechanisms select which types land here and how (see the derived
|
|
54
51
|
plan for the full worked example and rejected alternatives):
|
|
55
52
|
|
|
56
|
-
* **RELOCATE** — the class definition MOVES here
|
|
57
|
-
|
|
53
|
+
* **RELOCATE** — the class definition MOVES here. Dependency-bearing modules
|
|
54
|
+
that also exposed a shared value type can re-export its one definition for
|
|
55
|
+
existing callers; dependency-free modules move with their call sites.
|
|
58
56
|
Reserved for types with zero import-time *or* call-time dependency on
|
|
59
57
|
anything that cannot live in a zero-dependency package.
|
|
60
58
|
* **MIRROR** — a ``typing.Protocol`` (named ``*Protocol``, matching the
|
|
@@ -99,6 +97,7 @@ from simulo.interfaces.authoring.physics import (
|
|
|
99
97
|
Physics,
|
|
100
98
|
RigidPhysics,
|
|
101
99
|
)
|
|
100
|
+
from simulo.interfaces.authoring.policy_inputs import PolicyInput, PolicyInputSchema
|
|
102
101
|
from simulo.interfaces.authoring.pose import Pose
|
|
103
102
|
from simulo.interfaces.authoring.primitives import (
|
|
104
103
|
Cone,
|
|
@@ -111,6 +110,7 @@ from simulo.interfaces.authoring.primitives import (
|
|
|
111
110
|
from simulo.interfaces.authoring.prop import PropProtocol, PropStateProtocol
|
|
112
111
|
from simulo.interfaces.authoring.record import RecordConfig
|
|
113
112
|
from simulo.interfaces.authoring.robot import RobotProtocol, RobotStateProtocol
|
|
113
|
+
from simulo.interfaces.authoring.robot_config import ActuatorGainsConfig, ArticulationConfig, JointConfig
|
|
114
114
|
from simulo.interfaces.authoring.scene import SceneGroupProtocol, SceneProtocol
|
|
115
115
|
from simulo.interfaces.authoring.sensor import CameraProtocol
|
|
116
116
|
from simulo.interfaces.authoring.terrain import (
|
|
@@ -175,6 +175,8 @@ __all__ = [
|
|
|
175
175
|
"RecordConfig",
|
|
176
176
|
# injected policy input (dependency-free; loading is deferred to execution)
|
|
177
177
|
"PolicyCheckpoint",
|
|
178
|
+
"PolicyInput",
|
|
179
|
+
"PolicyInputSchema",
|
|
178
180
|
# visual
|
|
179
181
|
"VisualMarkerBase",
|
|
180
182
|
"AxesMarker",
|
|
@@ -185,6 +187,10 @@ __all__ = [
|
|
|
185
187
|
# scene (MIRROR — the concrete classes live in the backend package)
|
|
186
188
|
"SceneProtocol",
|
|
187
189
|
"SceneGroupProtocol",
|
|
190
|
+
# robot configuration (dependency-free owning definitions)
|
|
191
|
+
"ActuatorGainsConfig",
|
|
192
|
+
"ArticulationConfig",
|
|
193
|
+
"JointConfig",
|
|
188
194
|
# robot / prop / sensor / actuator (MIRROR — the concrete classes live in
|
|
189
195
|
# the backend package and explicitly inherit these Protocols)
|
|
190
196
|
"RobotProtocol",
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Dependency-free declarations for raw actor and critic inputs.
|
|
2
|
+
|
|
3
|
+
Images must be batched RGB uint8 NHWC. The contract requires future trainer
|
|
4
|
+
and export consumers to convert the current minibatch to NCHW float and divide
|
|
5
|
+
by 255; ``center`` also subtracts 0.5. These transforms belong in the actor's
|
|
6
|
+
graph. This module checks declarations and raw values, not graph behavior.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
from collections.abc import Mapping
|
|
15
|
+
from dataclasses import asdict, dataclass
|
|
16
|
+
from typing import Any, Literal
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
20
|
+
class PolicyInput:
|
|
21
|
+
"""One named input, with ``shape`` excluding the environment batch.
|
|
22
|
+
|
|
23
|
+
Names match ``[A-Za-z][A-Za-z0-9_]*``; shape dimensions are positive.
|
|
24
|
+
Tuple and list shapes are accepted and stored as tuples. Defaults are
|
|
25
|
+
``dtype="float32"``, ``kind="numeric"`` and ``preprocessing="none"``.
|
|
26
|
+
Numeric inputs require float32, no camera and no preprocessing. Image
|
|
27
|
+
inputs require uint8, shape ``(H, W, 3)`` and a nonblank camera scene name:
|
|
28
|
+
the last segment of ``scene.add(camera, at="/World/<name>")``. Full paths
|
|
29
|
+
are rejected. LearningEnv setup requires that camera's purpose to be
|
|
30
|
+
``"policy"``. Two policy cameras cannot share a scene name.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
name: str
|
|
34
|
+
shape: tuple[int, ...]
|
|
35
|
+
dtype: str = "float32"
|
|
36
|
+
kind: Literal["numeric", "image"] = "numeric"
|
|
37
|
+
camera: str | None = None
|
|
38
|
+
preprocessing: Literal["none", "center"] = "none"
|
|
39
|
+
|
|
40
|
+
def __post_init__(self) -> None:
|
|
41
|
+
label = f"Input {self.name!r}"
|
|
42
|
+
if isinstance(self.shape, list):
|
|
43
|
+
object.__setattr__(self, "shape", tuple(self.shape))
|
|
44
|
+
if not isinstance(self.name, str) or not re.fullmatch(r"[A-Za-z][A-Za-z0-9_]*", self.name):
|
|
45
|
+
raise ValueError(f"{label}: name must start with a letter and contain only letters, digits or underscores.")
|
|
46
|
+
if (
|
|
47
|
+
not isinstance(self.shape, tuple)
|
|
48
|
+
or not self.shape
|
|
49
|
+
or any(type(dim) is not int or dim <= 0 for dim in self.shape)
|
|
50
|
+
):
|
|
51
|
+
raise ValueError(f"{label}: shape must be a nonempty tuple of positive dimensions, excluding batch.")
|
|
52
|
+
if self.kind not in ("numeric", "image"):
|
|
53
|
+
raise ValueError(f"{label}: kind must be 'numeric' or 'image'.")
|
|
54
|
+
if self.preprocessing not in ("none", "center"):
|
|
55
|
+
raise ValueError(f"{label}: preprocessing must be 'none' or 'center'.")
|
|
56
|
+
if self.kind == "image":
|
|
57
|
+
if self.dtype != "uint8":
|
|
58
|
+
raise ValueError(f"{label}: image dtype must be uint8 RGB NHWC, got {self.dtype!r}.")
|
|
59
|
+
if len(self.shape) != 3 or self.shape[-1] != 3:
|
|
60
|
+
raise ValueError(f"{label}: image shape must be (H, W, 3) RGB NHWC, excluding batch, got {self.shape}.")
|
|
61
|
+
if not isinstance(self.camera, str) or not self.camera.strip():
|
|
62
|
+
raise ValueError(f"{label}: image inputs require a camera identity.")
|
|
63
|
+
if "/" in self.camera or self.camera != self.camera.strip():
|
|
64
|
+
raise ValueError(f"{label}: camera must be a scene name, the last segment of scene.add(..., at=...).")
|
|
65
|
+
elif self.dtype != "float32" or self.camera is not None or self.preprocessing != "none":
|
|
66
|
+
raise ValueError(f"{label}: numeric inputs require float32, no camera, and preprocessing='none'.")
|
|
67
|
+
|
|
68
|
+
def to_dict(self) -> dict[str, Any]:
|
|
69
|
+
"""Return JSON metadata, converting the stored tuple shape to a list."""
|
|
70
|
+
return {**asdict(self), "shape": list(self.shape)}
|
|
71
|
+
|
|
72
|
+
@classmethod
|
|
73
|
+
def from_dict(cls, value: Mapping[str, Any]) -> PolicyInput:
|
|
74
|
+
"""Parse JSON, converting list shapes to tuples; reject unknown fields."""
|
|
75
|
+
if not isinstance(value, Mapping):
|
|
76
|
+
raise ValueError("Input declaration must be an object.")
|
|
77
|
+
allowed = {"name", "shape", "dtype", "kind", "camera", "preprocessing"}
|
|
78
|
+
if set(value) - allowed or not {"name", "shape"} <= set(value):
|
|
79
|
+
raise ValueError(f"Input {value.get('name')!r}: declaration has missing or unknown fields.")
|
|
80
|
+
shape = value["shape"]
|
|
81
|
+
if not isinstance(shape, (list, tuple)):
|
|
82
|
+
raise ValueError(f"Input {value['name']!r}: shape must be an array of positive dimensions.")
|
|
83
|
+
return cls(**{**value, "shape": tuple(shape)})
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass(frozen=True, slots=True, kw_only=True)
|
|
87
|
+
class PolicyInputSchema:
|
|
88
|
+
"""Ordered actor inputs and optional separate training-only critic inputs.
|
|
89
|
+
|
|
90
|
+
``critic=None`` means the critic uses exactly the actor declarations.
|
|
91
|
+
Future export and playback consumers must use only ``actor``. A critic
|
|
92
|
+
declaration sharing an actor name must be identical. Actor inputs omitted
|
|
93
|
+
from an explicit critic are not supplied to that critic. Order is part of
|
|
94
|
+
checkpoint compatibility, including numeric concatenation order.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
actor: tuple[PolicyInput, ...]
|
|
98
|
+
critic: tuple[PolicyInput, ...] | None = None
|
|
99
|
+
|
|
100
|
+
def __post_init__(self) -> None:
|
|
101
|
+
for role, inputs in (("actor", self.actor), ("critic", self.critic_inputs)):
|
|
102
|
+
if not isinstance(inputs, tuple) or not inputs:
|
|
103
|
+
raise ValueError(f"{role} inputs must be a nonempty tuple of PolicyInput declarations.")
|
|
104
|
+
seen: set[str] = set()
|
|
105
|
+
for spec in inputs:
|
|
106
|
+
if not isinstance(spec, PolicyInput):
|
|
107
|
+
raise ValueError(f"{role} inputs must contain PolicyInput declarations.")
|
|
108
|
+
if spec.name in seen:
|
|
109
|
+
raise ValueError(f"{role} input {spec.name!r}: duplicate input name.")
|
|
110
|
+
seen.add(spec.name)
|
|
111
|
+
actor = {spec.name: spec for spec in self.actor}
|
|
112
|
+
for spec in self.critic_inputs:
|
|
113
|
+
if spec.name in actor and spec != actor[spec.name]:
|
|
114
|
+
raise ValueError(
|
|
115
|
+
f"critic input {spec.name!r}: declaration contradicts the actor input of the same name."
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def critic_inputs(self) -> tuple[PolicyInput, ...]:
|
|
120
|
+
"""Effective critic declarations, defaulting to actor inputs."""
|
|
121
|
+
return self.actor if self.critic is None else self.critic
|
|
122
|
+
|
|
123
|
+
def to_dict(self) -> dict[str, Any]:
|
|
124
|
+
"""Return the actor/critic schema for a checkpoint sidecar."""
|
|
125
|
+
return {
|
|
126
|
+
"actor": [spec.to_dict() for spec in self.actor],
|
|
127
|
+
"critic": None if self.critic is None else [spec.to_dict() for spec in self.critic],
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@classmethod
|
|
131
|
+
def from_dict(cls, value: Mapping[str, Any]) -> PolicyInputSchema:
|
|
132
|
+
"""Parse a schema without permitting undeclared metadata."""
|
|
133
|
+
if not isinstance(value, Mapping) or set(value) != {"actor", "critic"}:
|
|
134
|
+
raise ValueError("Policy input schema requires exactly actor and critic fields.")
|
|
135
|
+
actor, critic = value["actor"], value["critic"]
|
|
136
|
+
if not isinstance(actor, (list, tuple)) or (critic is not None and not isinstance(critic, (list, tuple))):
|
|
137
|
+
raise ValueError("Policy input schema actor and critic must be arrays (critic may be null).")
|
|
138
|
+
return cls(
|
|
139
|
+
actor=tuple(PolicyInput.from_dict(spec) for spec in actor),
|
|
140
|
+
critic=None if critic is None else tuple(PolicyInput.from_dict(spec) for spec in critic),
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
@property
|
|
144
|
+
def fingerprint(self) -> str:
|
|
145
|
+
"""SHA-256 of ordered inputs, including camera and preprocessing.
|
|
146
|
+
|
|
147
|
+
An omitted critic and an explicitly identical critic are equivalent.
|
|
148
|
+
Batch size is absent, so a checkpoint can change parallelism.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
def canonical(spec: PolicyInput) -> dict[str, Any]:
|
|
152
|
+
# Pin v1's subset: future defaulted fields do not invalidate hashes.
|
|
153
|
+
return {name: getattr(spec, name) for name in ("name", "shape", "dtype", "kind", "camera", "preprocessing")}
|
|
154
|
+
|
|
155
|
+
metadata = {
|
|
156
|
+
"version": "simulo.policy-input-fingerprint.v1",
|
|
157
|
+
"actor": [canonical(spec) for spec in self.actor],
|
|
158
|
+
"critic": [canonical(spec) for spec in self.critic_inputs],
|
|
159
|
+
}
|
|
160
|
+
return hashlib.sha256(json.dumps(metadata, sort_keys=True, separators=(",", ":")).encode()).hexdigest()
|
|
161
|
+
|
|
162
|
+
def validate_values(
|
|
163
|
+
self,
|
|
164
|
+
actor: Any,
|
|
165
|
+
critic: Any,
|
|
166
|
+
*,
|
|
167
|
+
batch_size: int | None = None,
|
|
168
|
+
) -> None:
|
|
169
|
+
"""Check raw names, shapes, dtypes and batch size at LearningEnv._init_spaces.
|
|
170
|
+
|
|
171
|
+
Values need only ``shape`` and ``dtype`` attributes. No engine or tensor
|
|
172
|
+
package is imported. One declared numeric input may use the legacy
|
|
173
|
+
tensor return; multiple or image inputs require a named mapping. Values
|
|
174
|
+
must have a leading num_envs batch. Failures raise ValueError naming the
|
|
175
|
+
role and input. Legacy tasks with no schema are not checked by setup.
|
|
176
|
+
"""
|
|
177
|
+
expected_batch = batch_size
|
|
178
|
+
for role, specs, values in (("actor", self.actor, actor), ("critic", self.critic_inputs, critic)):
|
|
179
|
+
if not isinstance(values, Mapping):
|
|
180
|
+
if len(specs) != 1 or specs[0].kind != "numeric":
|
|
181
|
+
raise ValueError(f"{role} input {specs[0].name!r}: named inputs require a mapping.")
|
|
182
|
+
values = {specs[0].name: values}
|
|
183
|
+
declared = {spec.name for spec in specs}
|
|
184
|
+
for name in values:
|
|
185
|
+
if name not in declared:
|
|
186
|
+
raise ValueError(f"{role} input {name!r}: unknown input name.")
|
|
187
|
+
for spec in specs:
|
|
188
|
+
if spec.name not in values:
|
|
189
|
+
raise ValueError(f"{role} input {spec.name!r}: missing input.")
|
|
190
|
+
value = values[spec.name]
|
|
191
|
+
shape = tuple(getattr(value, "shape", ()))
|
|
192
|
+
if (
|
|
193
|
+
len(shape) != len(spec.shape) + 1
|
|
194
|
+
or shape[1:] != spec.shape
|
|
195
|
+
or type(shape[0]) is not int
|
|
196
|
+
or shape[0] <= 0
|
|
197
|
+
):
|
|
198
|
+
raise ValueError(
|
|
199
|
+
f"{role} input {spec.name!r}: expected batched shape (N, {spec.shape}), got {shape}."
|
|
200
|
+
)
|
|
201
|
+
if expected_batch is None:
|
|
202
|
+
expected_batch = shape[0]
|
|
203
|
+
if shape[0] != expected_batch:
|
|
204
|
+
raise ValueError(f"{role} input {spec.name!r}: expected batch {expected_batch}, got {shape[0]}.")
|
|
205
|
+
dtype = str(getattr(value, "dtype", "")).removeprefix("torch.")
|
|
206
|
+
if dtype != spec.dtype:
|
|
207
|
+
raise ValueError(f"{role} input {spec.name!r}: expected dtype {spec.dtype}, got {dtype!r}.")
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/prop.py
RENAMED
|
@@ -154,15 +154,21 @@ class PropProtocol(Protocol):
|
|
|
154
154
|
|
|
155
155
|
@property
|
|
156
156
|
def default_pose(self) -> TensorLike:
|
|
157
|
-
"""The prop's spawn pose in the **world** frame
|
|
157
|
+
"""The prop's spawn pose in the **world** frame.
|
|
158
158
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
``state.pose`` and directly usable as
|
|
162
|
-
reset. Index it with the environments being
|
|
163
|
-
(``prop.default_pose[env_ids]``), perturb, and write it back with
|
|
159
|
+
For a prop added with ``per_environment=True`` (the default), the pose
|
|
160
|
+
has shape ``(num_envs, 7)`` and includes each environment's origin, so
|
|
161
|
+
it is directly comparable with ``state.pose`` and directly usable as
|
|
162
|
+
the base for a randomised reset. Index it with the environments being
|
|
163
|
+
reset (``prop.default_pose[env_ids]``), perturb, and write it back with
|
|
164
164
|
:meth:`set_pose`.
|
|
165
165
|
|
|
166
|
+
For a prop added with ``per_environment=False``, this is one row
|
|
167
|
+
containing its authored world pose with no environment origin. A
|
|
168
|
+
shared prop is supported only when the scene has one environment;
|
|
169
|
+
scene building refuses ``per_environment=False`` for a prop when
|
|
170
|
+
``num_envs > 1``.
|
|
171
|
+
|
|
166
172
|
Raises ``RuntimeError`` until the simulation runtime has attached the
|
|
167
173
|
prop.
|
|
168
174
|
"""
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/record.py
RENAMED
|
@@ -195,6 +195,11 @@ class RecordConfig:
|
|
|
195
195
|
profile precedence can distinguish "user passed False" from "default
|
|
196
196
|
None". Do not edit defaults to plain ``bool`` — the silent-default
|
|
197
197
|
mitigation depends on the tri-state.
|
|
198
|
+
|
|
199
|
+
``record_all_envs`` expands numeric recording data only. Policy camera
|
|
200
|
+
video always uses ``env_indices`` (default: environment 0), so host frame
|
|
201
|
+
buffers and encoder count are bounded by the selected environments and
|
|
202
|
+
declared cameras, independently of the total environment count.
|
|
198
203
|
"""
|
|
199
204
|
|
|
200
205
|
output_path: Optional[Union[str, "os.PathLike[str]", Path]] = None
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/robot.py
RENAMED
|
@@ -64,6 +64,7 @@ from typing import Any, Dict, List, Optional, Protocol, Tuple, runtime_checkable
|
|
|
64
64
|
|
|
65
65
|
from simulo.interfaces.authoring.asset import AssetSource
|
|
66
66
|
from simulo.interfaces.authoring.pose import Pose
|
|
67
|
+
from simulo.interfaces.authoring.robot_config import ArticulationConfig, JointConfig
|
|
67
68
|
from simulo.interfaces.runtime.tensors import TensorLike
|
|
68
69
|
|
|
69
70
|
|
|
@@ -183,17 +184,21 @@ class RobotProtocol(Protocol):
|
|
|
183
184
|
scale: Tuple[float, float, float]
|
|
184
185
|
"""Per-axis spawn scale factor."""
|
|
185
186
|
|
|
186
|
-
articulation:
|
|
187
|
+
articulation: ArticulationConfig
|
|
187
188
|
"""Articulation physics and control configuration."""
|
|
188
189
|
|
|
189
|
-
joint_config: Optional[List[
|
|
190
|
+
joint_config: Optional[List[JointConfig]]
|
|
190
191
|
"""Optional per-joint configurations."""
|
|
191
192
|
|
|
192
193
|
disable_gravity: bool
|
|
193
194
|
"""If ``True``, gravity is disabled for this robot."""
|
|
194
195
|
|
|
195
196
|
actuator_gains: Optional[Dict[str, Any]]
|
|
196
|
-
"""Optional mapping of actuator-group names to gain configurations.
|
|
197
|
+
"""Optional mapping of actuator-group names to gain configurations.
|
|
198
|
+
|
|
199
|
+
Catalog robots support only the ``"all_joints"`` key; other keys are ignored
|
|
200
|
+
with a warning.
|
|
201
|
+
"""
|
|
197
202
|
|
|
198
203
|
# -- Identity and attachment ------------------------------------------
|
|
199
204
|
|
|
@@ -257,12 +262,19 @@ class RobotProtocol(Protocol):
|
|
|
257
262
|
|
|
258
263
|
@property
|
|
259
264
|
def default_pose(self) -> TensorLike:
|
|
260
|
-
"""Base pose that :meth:`reset` writes in the world frame
|
|
261
|
-
|
|
262
|
-
position in m followed by a
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
265
|
+
"""Base pose that :meth:`reset` writes in the world frame.
|
|
266
|
+
|
|
267
|
+
Columns are ``[x, y, z, qw, qx, qy, qz]``: position in m followed by a
|
|
268
|
+
w-first unit quaternion. For a robot added with
|
|
269
|
+
``per_environment=True`` (the default), the shape is ``(num_envs, 7)``
|
|
270
|
+
and each environment's origin is included. For a robot added with
|
|
271
|
+
``per_environment=False``, this is one row containing its authored
|
|
272
|
+
world pose with no environment origin. A shared robot is supported
|
|
273
|
+
only when the scene has one environment; scene building refuses
|
|
274
|
+
``per_environment=False`` for a robot when ``num_envs > 1``. Available
|
|
275
|
+
from ``on_start`` onward. Each read returns a new tensor, so writing
|
|
276
|
+
into it cannot change a later reset.
|
|
277
|
+
"""
|
|
266
278
|
...
|
|
267
279
|
|
|
268
280
|
@property
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""Dependency-free robot physics and joint-control configuration."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import List, Optional, Tuple
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ActuatorGainsConfig:
|
|
9
|
+
"""Configuration for an actuator group.
|
|
10
|
+
|
|
11
|
+
Actuators control named groups of joints.
|
|
12
|
+
Use this to configure control properties per actuator group.
|
|
13
|
+
|
|
14
|
+
Attributes:
|
|
15
|
+
stiffness: Position gain (P in PD control). Set to 0 for effort control.
|
|
16
|
+
damping: Velocity gain (D in PD control). Set to 0 for effort control.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
stiffness: float = 0.0
|
|
20
|
+
damping: float = 0.0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class JointConfig:
|
|
25
|
+
"""Configuration for a single joint.
|
|
26
|
+
|
|
27
|
+
Stored-USD robots receive force drives on drive-less joints. Only non-None
|
|
28
|
+
gains and limits override existing values; zero is an explicit override.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
name: Joint name
|
|
32
|
+
type: Joint type (revolute, prismatic, fixed, etc.)
|
|
33
|
+
limits: (lower, upper) position limits in radians or meters
|
|
34
|
+
effort_limit: Maximum torque/force in N·m or N. Stored USD joints use
|
|
35
|
+
this value when non-None; otherwise they keep the USD/PhysX limit.
|
|
36
|
+
Only newly created drives get a finite fallback of 1000.
|
|
37
|
+
velocity_limit: Maximum velocity in rad/s or m/s. Stored USD joints use
|
|
38
|
+
this value when non-None; otherwise they keep the USD/PhysX limit.
|
|
39
|
+
Only newly created drives get a finite fallback of 100.
|
|
40
|
+
damping: Velocity gain; None keeps task actuator_gains or USD gains.
|
|
41
|
+
stiffness: Position gain; None keeps task actuator_gains or USD gains.
|
|
42
|
+
armature: Armature inertia; not applied by the stored-USD builder.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
name: str = ""
|
|
46
|
+
type: str = "revolute"
|
|
47
|
+
limits: Optional[Tuple[float, float]] = None
|
|
48
|
+
effort_limit: Optional[float] = None
|
|
49
|
+
velocity_limit: Optional[float] = None
|
|
50
|
+
damping: Optional[float] = None
|
|
51
|
+
stiffness: Optional[float] = None
|
|
52
|
+
armature: float = 0.0
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class ArticulationConfig:
|
|
57
|
+
"""Configuration for robot articulation physics and control.
|
|
58
|
+
|
|
59
|
+
For stored USDs, only non-None solver, self-collision and root-fixing
|
|
60
|
+
settings override USD-authored values or PhysX defaults. Declaring joint
|
|
61
|
+
defaults alone leaves those physics settings intact. Sleep and stabilization
|
|
62
|
+
thresholds are not applied by the stored-USD builder.
|
|
63
|
+
|
|
64
|
+
Attributes:
|
|
65
|
+
solver_position_iterations: Position solver iteration count
|
|
66
|
+
solver_velocity_iterations: Velocity solver iteration count
|
|
67
|
+
sleep_threshold: Velocity threshold for sleep
|
|
68
|
+
stabilization_threshold: Stabilization threshold
|
|
69
|
+
enable_self_collision: Whether to enable self-collision
|
|
70
|
+
default_joint_positions: Default joint positions (rad or m)
|
|
71
|
+
default_joint_velocities: Default joint velocities (rad/s or m/s)
|
|
72
|
+
fix_root_link: Whether to create a fixed joint from the root link to the world
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
solver_position_iterations: Optional[int] = None
|
|
76
|
+
solver_velocity_iterations: Optional[int] = None
|
|
77
|
+
sleep_threshold: float = 0.005
|
|
78
|
+
stabilization_threshold: float = 0.001
|
|
79
|
+
enable_self_collision: Optional[bool] = None
|
|
80
|
+
default_joint_positions: Optional[List[float]] = None
|
|
81
|
+
default_joint_velocities: Optional[List[float]] = None
|
|
82
|
+
fix_root_link: Optional[bool] = None
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/scene.py
RENAMED
|
@@ -77,6 +77,9 @@ class SceneGroupProtocol(Protocol):
|
|
|
77
77
|
|
|
78
78
|
``per_environment=True`` (the default) clones the item per environment
|
|
79
79
|
when the scene has more than one environment.
|
|
80
|
+
Shared robots and props are supported only when the scene has one
|
|
81
|
+
environment. Transform children are not replicated; add robots and
|
|
82
|
+
props directly to a multi-environment scene.
|
|
80
83
|
"""
|
|
81
84
|
...
|
|
82
85
|
|
|
@@ -116,7 +119,9 @@ class SceneProtocol(Protocol):
|
|
|
116
119
|
|
|
117
120
|
``per_environment=True`` (the default) clones the item per environment
|
|
118
121
|
when ``num_envs > 1``; pass ``per_environment=False`` for shared items
|
|
119
|
-
like ground planes and global lights.
|
|
122
|
+
like ground planes and global lights. Shared robots and props are
|
|
123
|
+
supported only when ``num_envs == 1``. Transform children are not
|
|
124
|
+
replicated; add robots and props directly to a multi-environment scene.
|
|
120
125
|
"""
|
|
121
126
|
...
|
|
122
127
|
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/authoring/sensor.py
RENAMED
|
@@ -32,7 +32,7 @@ documented-omissions allowlist):
|
|
|
32
32
|
implementation; giving them contract homes is a later, separate decision.
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
|
-
from typing import Any, List, Optional, Protocol, runtime_checkable
|
|
35
|
+
from typing import Any, List, Literal, Optional, Protocol, runtime_checkable
|
|
36
36
|
|
|
37
37
|
from simulo.interfaces.runtime.tensors import TensorLike
|
|
38
38
|
|
|
@@ -88,6 +88,14 @@ class CameraProtocol(SensorProtocol, Protocol):
|
|
|
88
88
|
height: int
|
|
89
89
|
"""Image height in pixels."""
|
|
90
90
|
|
|
91
|
+
purpose: Literal["observer", "policy"]
|
|
92
|
+
"""Camera label, default "observer"; only "observer" and "policy" are valid.
|
|
93
|
+
|
|
94
|
+
Construction rejects other values with ValueError. LearningEnv setup
|
|
95
|
+
requires "policy" for declared image cameras. Rendering and recording
|
|
96
|
+
consumers are implemented in later milestones.
|
|
97
|
+
"""
|
|
98
|
+
|
|
91
99
|
data_types: List[str]
|
|
92
100
|
"""Data types to capture (e.g. ``"rgb"``, ``"depth"``, ``"normals"``,
|
|
93
101
|
``"semantic"``)."""
|
|
@@ -695,7 +695,7 @@ ASSET_NOT_FOUND_CODE = "asset_not_found"
|
|
|
695
695
|
# plane); this docstring is the drift anchor for a future reconciliation
|
|
696
696
|
# where the control plane imports these directly instead of re-declaring
|
|
697
697
|
# them. The thin client's `simulo asset publish`/`validate` error
|
|
698
|
-
# rendering (`_client/
|
|
698
|
+
# rendering (`_client/commands/assets.py::_friendly_asset_error`) matches these exact
|
|
699
699
|
# strings, never a hand-typed literal.
|
|
700
700
|
# --------------------------------------------------------------------------
|
|
701
701
|
|
|
@@ -727,7 +727,7 @@ ASSET_UPLOAD_INCOMPLETE_CODE = "asset_upload_incomplete"
|
|
|
727
727
|
# "mirrored, not imported" precedent above), so this is a value-only
|
|
728
728
|
# duplication, drift-anchored by this docstring. The thin client's
|
|
729
729
|
# `simulo asset get`/`deprecate`/`delete` error rendering
|
|
730
|
-
# (`_client/
|
|
730
|
+
# (`_client/commands/assets.py::_friendly_asset_error`) matches these exact strings so
|
|
731
731
|
# the server's already user-language message renders verbatim, never a
|
|
732
732
|
# code-prefixed wire dump.
|
|
733
733
|
# --------------------------------------------------------------------------
|
{simulo_interfaces-0.23.0 → simulo_interfaces-0.24.0}/src/simulo/interfaces/platform/evaluation.py
RENAMED
|
@@ -4,9 +4,10 @@ An eval job runs a trained checkpoint on numbered episodes and judges each
|
|
|
4
4
|
one with the eval file's ``@app.success`` function. The runtime returns the
|
|
5
5
|
report as a plain ``dict`` of :class:`EvaluationReport` shape and registers it
|
|
6
6
|
as a ``report`` output; the client renders it, the Console reads it from the
|
|
7
|
-
job result, and the control plane
|
|
8
|
-
detail goes in ``episodes.csv``
|
|
9
|
-
stays small whatever the episode
|
|
7
|
+
job result, and the control plane validates it before accepting completion.
|
|
8
|
+
Every episode's detail goes in ``episodes.csv``
|
|
9
|
+
(:func:`episodes_csv_columns`), so the report stays small whatever the episode
|
|
10
|
+
count.
|
|
10
11
|
|
|
11
12
|
The comparison block (``--compare``) is part of v1 from the start, so comparing
|
|
12
13
|
two checkpoints never needs a new schema version. Additive-only: a breaking
|
|
@@ -300,6 +301,11 @@ class EvaluationComparison(TypedDict):
|
|
|
300
301
|
"""The ``--compare`` checkpoint."""
|
|
301
302
|
compared_result: EvaluationResult
|
|
302
303
|
"""The ``--compare`` checkpoint's own RESULT."""
|
|
304
|
+
task_changed: NotRequired[bool]
|
|
305
|
+
"""Whether the evaluation task differs from the ``--compare`` checkpoint's training task.
|
|
306
|
+
|
|
307
|
+
Omitted by reports written before this additive v1 field existed.
|
|
308
|
+
"""
|
|
303
309
|
improved: int
|
|
304
310
|
"""Episodes that failed with ``compared_with`` and succeeded with the ``--policy`` checkpoint."""
|
|
305
311
|
regressed: int
|