antioch-py 2.2.3__py3-none-any.whl → 3.0.0__py3-none-any.whl
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.
Potentially problematic release.
This version of antioch-py might be problematic. Click here for more details.
- antioch/__init__.py +101 -0
- antioch/{module/execution.py → execution.py} +1 -1
- antioch/{module/input.py → input.py} +2 -4
- antioch/{module/module.py → module.py} +17 -34
- antioch/{module/node.py → node.py} +17 -16
- {antioch_py-2.2.3.dist-info → antioch_py-3.0.0.dist-info}/METADATA +8 -11
- antioch_py-3.0.0.dist-info/RECORD +61 -0
- {antioch_py-2.2.3.dist-info → antioch_py-3.0.0.dist-info}/WHEEL +1 -1
- antioch_py-3.0.0.dist-info/licenses/LICENSE +21 -0
- common/ark/__init__.py +6 -16
- common/ark/ark.py +23 -62
- common/ark/hardware.py +1 -1
- common/ark/kinematics.py +1 -1
- common/ark/module.py +22 -0
- common/ark/node.py +46 -3
- common/ark/scheduler.py +2 -29
- common/ark/sim.py +1 -1
- {antioch/module → common/ark}/token.py +17 -0
- common/assets/rigging.usd +0 -0
- common/constants.py +63 -5
- common/core/__init__.py +37 -24
- common/core/auth.py +87 -112
- common/core/container.py +261 -0
- common/core/registry.py +131 -152
- common/core/rome.py +251 -0
- common/core/telemetry.py +176 -0
- common/core/types.py +219 -0
- common/message/__init__.py +19 -5
- common/message/annotation.py +174 -23
- common/message/array.py +25 -1
- common/message/camera.py +23 -1
- common/message/color.py +32 -6
- common/message/detection.py +40 -0
- common/message/foxglove.py +20 -0
- common/message/frame.py +71 -7
- common/message/image.py +58 -9
- common/message/imu.py +24 -4
- common/message/joint.py +69 -10
- common/message/log.py +52 -7
- common/message/pir.py +23 -8
- common/message/plot.py +57 -0
- common/message/point.py +55 -6
- common/message/point_cloud.py +55 -19
- common/message/pose.py +59 -19
- common/message/quaternion.py +105 -92
- common/message/radar.py +195 -29
- common/message/twist.py +34 -0
- common/message/types.py +40 -5
- common/message/vector.py +180 -245
- common/sim/__init__.py +49 -0
- common/{session/config.py → sim/objects.py} +97 -27
- common/sim/state.py +11 -0
- common/utils/comms.py +30 -12
- common/utils/logger.py +26 -7
- antioch/message.py +0 -87
- antioch/module/__init__.py +0 -53
- antioch/session/__init__.py +0 -152
- antioch/session/ark.py +0 -500
- antioch/session/asset.py +0 -65
- antioch/session/error.py +0 -80
- antioch/session/objects/__init__.py +0 -40
- antioch/session/objects/animation.py +0 -162
- antioch/session/objects/articulation.py +0 -180
- antioch/session/objects/basis_curve.py +0 -180
- antioch/session/objects/camera.py +0 -65
- antioch/session/objects/collision.py +0 -46
- antioch/session/objects/geometry.py +0 -58
- antioch/session/objects/ground_plane.py +0 -48
- antioch/session/objects/imu.py +0 -53
- antioch/session/objects/joint.py +0 -49
- antioch/session/objects/light.py +0 -123
- antioch/session/objects/pir_sensor.py +0 -98
- antioch/session/objects/radar.py +0 -62
- antioch/session/objects/rigid_body.py +0 -197
- antioch/session/objects/xform.py +0 -119
- antioch/session/record.py +0 -158
- antioch/session/scene.py +0 -1544
- antioch/session/session.py +0 -211
- antioch/session/task.py +0 -309
- antioch_py-2.2.3.dist-info/RECORD +0 -85
- antioch_py-2.2.3.dist-info/entry_points.txt +0 -2
- common/core/agent.py +0 -324
- common/core/task.py +0 -36
- common/message/velocity.py +0 -11
- common/rome/__init__.py +0 -9
- common/rome/client.py +0 -430
- common/rome/error.py +0 -16
- common/session/__init__.py +0 -31
- common/session/environment.py +0 -31
- common/session/sim.py +0 -129
- common/utils/usd.py +0 -12
- /antioch/{module/clock.py → clock.py} +0 -0
- {antioch_py-2.2.3.dist-info → antioch_py-3.0.0.dist-info}/top_level.txt +0 -0
- /common/message/{base.py → message.py} +0 -0
antioch/session/scene.py
DELETED
|
@@ -1,1544 +0,0 @@
|
|
|
1
|
-
from typing import Literal, overload
|
|
2
|
-
|
|
3
|
-
from antioch.session.ark import Ark
|
|
4
|
-
from antioch.session.objects import (
|
|
5
|
-
Animation,
|
|
6
|
-
Articulation,
|
|
7
|
-
BasisCurve,
|
|
8
|
-
Camera,
|
|
9
|
-
Geometry,
|
|
10
|
-
GroundPlane,
|
|
11
|
-
Imu,
|
|
12
|
-
Joint,
|
|
13
|
-
Light,
|
|
14
|
-
PirSensor,
|
|
15
|
-
Radar,
|
|
16
|
-
RigidBody,
|
|
17
|
-
XForm,
|
|
18
|
-
get_mesh_approximation,
|
|
19
|
-
has_collision,
|
|
20
|
-
remove_collision,
|
|
21
|
-
set_collision,
|
|
22
|
-
set_pir_material,
|
|
23
|
-
)
|
|
24
|
-
from antioch.session.session import SessionContainer
|
|
25
|
-
from common.core import ContainerSource, get_asset_path
|
|
26
|
-
from common.core.agent import Agent
|
|
27
|
-
from common.message import Pose, Vector3
|
|
28
|
-
from common.session.config import (
|
|
29
|
-
ArticulationConfig,
|
|
30
|
-
ArticulationJointConfig,
|
|
31
|
-
BodyType,
|
|
32
|
-
CameraConfig,
|
|
33
|
-
CameraMode,
|
|
34
|
-
DistortionModel,
|
|
35
|
-
GeometryConfig,
|
|
36
|
-
GeometryType,
|
|
37
|
-
GroundPlaneConfig,
|
|
38
|
-
ImuConfig,
|
|
39
|
-
JointAxis,
|
|
40
|
-
JointConfig,
|
|
41
|
-
JointType,
|
|
42
|
-
LightConfig,
|
|
43
|
-
LightType,
|
|
44
|
-
MeshApproximation,
|
|
45
|
-
PirSensorConfig,
|
|
46
|
-
RadarConfig,
|
|
47
|
-
RigidBodyConfig,
|
|
48
|
-
)
|
|
49
|
-
from common.session.environment import SessionEnvironment
|
|
50
|
-
from common.session.sim import PrimAttributeValue, SceneQueryResponse, SceneTarget, SimulationInfo, SimulationTime
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class Scene(SessionContainer):
|
|
54
|
-
"""
|
|
55
|
-
Singleton wrapper for scene-level operations.
|
|
56
|
-
|
|
57
|
-
Uses a lazy singleton pattern - the first instantiation or call to get_current()
|
|
58
|
-
creates the instance, and all subsequent calls return the same instance.
|
|
59
|
-
|
|
60
|
-
Provides low-level scene operations (clear, step, status) and factory methods
|
|
61
|
-
for creating and retrieving views (add_*/get_* pattern).
|
|
62
|
-
|
|
63
|
-
Example:
|
|
64
|
-
scene = Scene() # or Scene.get_current()
|
|
65
|
-
scene.clear()
|
|
66
|
-
scene.toggle_ui(show_ui=False)
|
|
67
|
-
scene.play()
|
|
68
|
-
scene.step(dt_us=1_000_000)
|
|
69
|
-
|
|
70
|
-
# Add views
|
|
71
|
-
geometry = scene.add_geometry(path="/World/box", ...)
|
|
72
|
-
|
|
73
|
-
# Get existing views
|
|
74
|
-
existing_geometry = scene.get_geometry(path="/World/box")
|
|
75
|
-
|
|
76
|
-
# Query scene hierarchy
|
|
77
|
-
from common.session.sim import SceneTarget
|
|
78
|
-
all_prims = scene.query_scene(root_path="/World")
|
|
79
|
-
cameras = scene.query_scene(target=SceneTarget.CAMERA)
|
|
80
|
-
|
|
81
|
-
# Add Ark from registry
|
|
82
|
-
ark = scene.add_ark(name="my_robot", version="1.0.0")
|
|
83
|
-
|
|
84
|
-
# Add asset from registry
|
|
85
|
-
scene.add_asset(path="/World/my_asset", name="asset_name", version="1.0.0")
|
|
86
|
-
|
|
87
|
-
# Or add asset from file path
|
|
88
|
-
scene.add_asset(path="/World/my_model", asset_file_path="/path/to/model.usdz")
|
|
89
|
-
"""
|
|
90
|
-
|
|
91
|
-
_current: "Scene | None" = None
|
|
92
|
-
_ark: "Ark | None" = None
|
|
93
|
-
|
|
94
|
-
def __new__(cls) -> "Scene":
|
|
95
|
-
if cls._current is None:
|
|
96
|
-
cls._current = super().__new__(cls)
|
|
97
|
-
return cls._current
|
|
98
|
-
|
|
99
|
-
def __init__(self):
|
|
100
|
-
"""
|
|
101
|
-
Initialize scene wrapper.
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
if not hasattr(self, "_initialized"):
|
|
105
|
-
super().__init__()
|
|
106
|
-
self._initialized = True
|
|
107
|
-
self._agent = Agent()
|
|
108
|
-
Scene._current = self
|
|
109
|
-
|
|
110
|
-
@classmethod
|
|
111
|
-
def get_current(cls) -> "Scene":
|
|
112
|
-
"""
|
|
113
|
-
Get the current scene, creating it if it doesn't exist (lazy singleton).
|
|
114
|
-
|
|
115
|
-
:return: The current scene.
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
if cls._current is None:
|
|
119
|
-
cls._current = Scene()
|
|
120
|
-
return cls._current
|
|
121
|
-
|
|
122
|
-
@property
|
|
123
|
-
def info(self) -> SimulationInfo:
|
|
124
|
-
"""
|
|
125
|
-
Get comprehensive simulation info.
|
|
126
|
-
|
|
127
|
-
:return: Info response with detailed simulation information.
|
|
128
|
-
"""
|
|
129
|
-
|
|
130
|
-
return self._session.query_sim_rpc(
|
|
131
|
-
endpoint="get_info",
|
|
132
|
-
response_type=SimulationInfo,
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
@property
|
|
136
|
-
def time_us(self) -> int:
|
|
137
|
-
"""
|
|
138
|
-
Get the current simulation time in microseconds.
|
|
139
|
-
|
|
140
|
-
:return: Current simulation time in microseconds.
|
|
141
|
-
"""
|
|
142
|
-
|
|
143
|
-
return self._session.query_sim_rpc(
|
|
144
|
-
endpoint="get_time",
|
|
145
|
-
response_type=SimulationTime,
|
|
146
|
-
).time_us
|
|
147
|
-
|
|
148
|
-
@property
|
|
149
|
-
def ark(self):
|
|
150
|
-
"""
|
|
151
|
-
Get the current Ark if one exists.
|
|
152
|
-
|
|
153
|
-
:return: The current Ark or None.
|
|
154
|
-
"""
|
|
155
|
-
|
|
156
|
-
return self._ark
|
|
157
|
-
|
|
158
|
-
def add_ark(
|
|
159
|
-
self,
|
|
160
|
-
name: str,
|
|
161
|
-
version: str,
|
|
162
|
-
path: str = "/World",
|
|
163
|
-
world_pose: Pose | dict | None = None,
|
|
164
|
-
local_pose: Pose | dict | None = None,
|
|
165
|
-
source: ContainerSource | None = None,
|
|
166
|
-
debug: bool = False,
|
|
167
|
-
timeout: float = 30.0,
|
|
168
|
-
) -> "Ark":
|
|
169
|
-
"""
|
|
170
|
-
Add an Ark container at the specified path.
|
|
171
|
-
|
|
172
|
-
This builds the entire Ark: loads definition, builds kinematics and hardware,
|
|
173
|
-
starts containers via agent, and initializes scheduling. Everything is ready to run.
|
|
174
|
-
|
|
175
|
-
:param name: Name of the Ark.
|
|
176
|
-
:param version: Version of the Ark.
|
|
177
|
-
:param path: USD path where the Ark will be built (default: "/World").
|
|
178
|
-
:param world_pose: Optional world pose.
|
|
179
|
-
:param local_pose: Optional local pose.
|
|
180
|
-
:param source: Container image source.
|
|
181
|
-
:param debug: Enable debug mode.
|
|
182
|
-
:param timeout: Timeout in seconds for the Ark to start.
|
|
183
|
-
:return: The fully initialized Ark container.
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
# Auto-select the container source based on session environment
|
|
187
|
-
if source is None:
|
|
188
|
-
source = ContainerSource.LOCAL if SessionEnvironment.check() == SessionEnvironment.LOCAL else ContainerSource.REMOTE
|
|
189
|
-
|
|
190
|
-
self._ark = Ark(
|
|
191
|
-
path=path,
|
|
192
|
-
scene=self,
|
|
193
|
-
name=name,
|
|
194
|
-
version=version,
|
|
195
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
196
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
197
|
-
source=source,
|
|
198
|
-
debug=debug,
|
|
199
|
-
timeout=timeout,
|
|
200
|
-
)
|
|
201
|
-
|
|
202
|
-
return self._ark
|
|
203
|
-
|
|
204
|
-
def play(self) -> None:
|
|
205
|
-
"""
|
|
206
|
-
Start or resume playing the simulation.
|
|
207
|
-
|
|
208
|
-
Automatically starts the simulation if stopped, or resumes if paused.
|
|
209
|
-
After playing, background rendering is disabled and the viewport is only
|
|
210
|
-
updated with calls to step() or render().
|
|
211
|
-
"""
|
|
212
|
-
|
|
213
|
-
self._session.query_sim_rpc(endpoint="play")
|
|
214
|
-
|
|
215
|
-
def pause(self) -> None:
|
|
216
|
-
"""
|
|
217
|
-
Pause the simulation.
|
|
218
|
-
|
|
219
|
-
Freezes time but keeps physics initialized, enabling background rendering.
|
|
220
|
-
"""
|
|
221
|
-
|
|
222
|
-
self._session.query_sim_rpc(endpoint="pause")
|
|
223
|
-
|
|
224
|
-
def render(self) -> None:
|
|
225
|
-
"""
|
|
226
|
-
Force render the simulation.
|
|
227
|
-
"""
|
|
228
|
-
|
|
229
|
-
self._session.query_sim_rpc(endpoint="render")
|
|
230
|
-
|
|
231
|
-
def step(self, dt_us: int = 1_000_000) -> None:
|
|
232
|
-
"""
|
|
233
|
-
Step the simulation forward.
|
|
234
|
-
|
|
235
|
-
The simulation must be playing before calling this method. Call play() first.
|
|
236
|
-
If an Ark exists, delegates to Ark.step() which handles both node execution
|
|
237
|
-
and physics stepping. Otherwise steps physics directly.
|
|
238
|
-
|
|
239
|
-
:param dt_us: Amount of time to step in microseconds (default 1 second).
|
|
240
|
-
:raises SessionSimRpcClientError: If simulation is not playing.
|
|
241
|
-
"""
|
|
242
|
-
|
|
243
|
-
# Delegate to Ark if present
|
|
244
|
-
if self._ark is not None:
|
|
245
|
-
self._ark.step(dt_us)
|
|
246
|
-
return
|
|
247
|
-
|
|
248
|
-
# No Ark, step physics directly
|
|
249
|
-
self._step_physics(dt_us)
|
|
250
|
-
|
|
251
|
-
def set_simulation_controls(
|
|
252
|
-
self,
|
|
253
|
-
max_physics_dt_us: int | None = None,
|
|
254
|
-
render_interval_us: int | None = None,
|
|
255
|
-
) -> None:
|
|
256
|
-
"""
|
|
257
|
-
Set simulation control parameters.
|
|
258
|
-
|
|
259
|
-
The max_physics_dt_us is the maximum physics step size in microseconds
|
|
260
|
-
that will be used by the simulation backend. Setting a larger value will
|
|
261
|
-
speed up the simulation, but may cause instability and lower the physics
|
|
262
|
-
fidelity. You should generally stick to values between 1ms and 20ms.
|
|
263
|
-
|
|
264
|
-
The render_interval_us is the interval in microseconds at which the viewport
|
|
265
|
-
will be rendered **in simulation time**. Setting a larger value will reduce the
|
|
266
|
-
number of renders and speed up the simulation, but may increase lag and jitter
|
|
267
|
-
in the viewport. You should generally stick to values between 10ms and 100ms.
|
|
268
|
-
|
|
269
|
-
:param max_physics_dt_us: Maximum physics timestep in microseconds.
|
|
270
|
-
:param render_interval_us: Render interval in microseconds.
|
|
271
|
-
:raises SessionSimRpcClientError: If parameters are invalid.
|
|
272
|
-
"""
|
|
273
|
-
|
|
274
|
-
self._session.query_sim_rpc(
|
|
275
|
-
endpoint="set_simulation_controls",
|
|
276
|
-
payload={
|
|
277
|
-
"max_physics_dt_us": max_physics_dt_us,
|
|
278
|
-
"render_interval_us": render_interval_us,
|
|
279
|
-
},
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
def clear(self, timeout: float = 30.0) -> None:
|
|
283
|
-
"""
|
|
284
|
-
Clear and completely reset the scene.
|
|
285
|
-
|
|
286
|
-
Stops any running Ark before clearing the scene.
|
|
287
|
-
|
|
288
|
-
:param timeout: Timeout in seconds for stopping the Ark.
|
|
289
|
-
"""
|
|
290
|
-
|
|
291
|
-
# Always try to stop the Ark via the agent (idempotent)
|
|
292
|
-
self._agent.stop_ark(timeout=timeout)
|
|
293
|
-
self._ark = None
|
|
294
|
-
|
|
295
|
-
# Clear the simulation scene completely
|
|
296
|
-
self._session.query_sim_rpc(endpoint="clear")
|
|
297
|
-
|
|
298
|
-
def restart(self) -> None:
|
|
299
|
-
"""
|
|
300
|
-
Restart the simulation container.
|
|
301
|
-
|
|
302
|
-
This endpoint only works in Kubernetes environments. It sends SIGKILL to PID 1
|
|
303
|
-
(the container entrypoint process), which will forcefully terminate the entire
|
|
304
|
-
container and trigger a restart.
|
|
305
|
-
|
|
306
|
-
Note: This function will not return as the process will be killed immediately.
|
|
307
|
-
"""
|
|
308
|
-
|
|
309
|
-
# Always try to stop the Ark via the agent (idempotent)
|
|
310
|
-
self._agent.stop_ark()
|
|
311
|
-
self._ark = None
|
|
312
|
-
|
|
313
|
-
# Restart the RPC container
|
|
314
|
-
self._session.query_sim_rpc(endpoint="restart")
|
|
315
|
-
|
|
316
|
-
def toggle_ui(self, show_ui: bool) -> None:
|
|
317
|
-
"""
|
|
318
|
-
Toggle the Isaac Sim UI visibility.
|
|
319
|
-
|
|
320
|
-
:param show_ui: Whether to show or hide the UI.
|
|
321
|
-
"""
|
|
322
|
-
|
|
323
|
-
self._session.query_sim_rpc(
|
|
324
|
-
endpoint="toggle_ui",
|
|
325
|
-
payload={"show_ui": show_ui},
|
|
326
|
-
)
|
|
327
|
-
|
|
328
|
-
def set_camera_view(
|
|
329
|
-
self,
|
|
330
|
-
eye: Vector3 | list[float] | tuple[float, float, float],
|
|
331
|
-
target: Vector3 | list[float] | tuple[float, float, float],
|
|
332
|
-
camera_prim_path: str | None = None,
|
|
333
|
-
) -> None:
|
|
334
|
-
"""
|
|
335
|
-
Set the viewport camera view position and target.
|
|
336
|
-
|
|
337
|
-
:param eye: Eye position (camera location) in world coordinates.
|
|
338
|
-
:param target: Target position (look-at point) in world coordinates.
|
|
339
|
-
:param camera_prim_path: Optional USD path to the camera prim to configure.
|
|
340
|
-
"""
|
|
341
|
-
|
|
342
|
-
self._session.query_sim_rpc(
|
|
343
|
-
endpoint="set_camera_view",
|
|
344
|
-
payload={
|
|
345
|
-
"eye": Vector3.from_any(eye),
|
|
346
|
-
"target": Vector3.from_any(target),
|
|
347
|
-
"camera_prim_path": camera_prim_path,
|
|
348
|
-
},
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
def set_active_viewport_camera(self, camera_prim_path: str) -> None:
|
|
352
|
-
"""
|
|
353
|
-
Set which camera is active in the viewport.
|
|
354
|
-
|
|
355
|
-
:param camera_prim_path: USD path to the camera prim to make active.
|
|
356
|
-
"""
|
|
357
|
-
|
|
358
|
-
self._session.query_sim_rpc(
|
|
359
|
-
endpoint="set_active_viewport_camera",
|
|
360
|
-
payload={"camera_prim_path": camera_prim_path},
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
def get_prim_attribute(self, path: str, attribute_name: str) -> float | int | str | bool | list[float]:
|
|
364
|
-
"""
|
|
365
|
-
Get an attribute value from any prim.
|
|
366
|
-
|
|
367
|
-
Supports primitive and vector types: float, int, bool, string, Vec2/3/4, Quat.
|
|
368
|
-
|
|
369
|
-
:param path: USD path to the prim.
|
|
370
|
-
:param attribute_name: Name of the attribute to get.
|
|
371
|
-
:return: The attribute value (scalar or list for vectors/quaternions).
|
|
372
|
-
:raises ValueError: If prim or attribute doesn't exist, or type is unsupported.
|
|
373
|
-
"""
|
|
374
|
-
|
|
375
|
-
return self._session.query_sim_rpc(
|
|
376
|
-
endpoint="scene/get_prim_attribute_value",
|
|
377
|
-
response_type=PrimAttributeValue,
|
|
378
|
-
payload={"path": path, "attribute_name": attribute_name},
|
|
379
|
-
).value
|
|
380
|
-
|
|
381
|
-
def set_prim_attribute(self, path: str, attribute_name: str, value: float | int | str | bool | list[float]) -> None:
|
|
382
|
-
"""
|
|
383
|
-
Set an attribute value on any prim.
|
|
384
|
-
|
|
385
|
-
Supports primitive and vector types: float, int, bool, string, Vec2/3/4, Quat.
|
|
386
|
-
The attribute must already exist.
|
|
387
|
-
|
|
388
|
-
:param path: USD path to the prim.
|
|
389
|
-
:param attribute_name: Name of the attribute to set.
|
|
390
|
-
:param value: The value to set (scalar or list for vectors/quaternions).
|
|
391
|
-
:raises ValueError: If prim or attribute doesn't exist, or value is incompatible.
|
|
392
|
-
"""
|
|
393
|
-
|
|
394
|
-
self._session.query_sim_rpc(
|
|
395
|
-
endpoint="scene/set_prim_attribute_value",
|
|
396
|
-
payload={"path": path, "attribute_name": attribute_name, "value": value},
|
|
397
|
-
)
|
|
398
|
-
|
|
399
|
-
def query_scene(self, root_path: str = "/World", target: SceneTarget | None = None) -> SceneQueryResponse:
|
|
400
|
-
"""
|
|
401
|
-
Query the USD scene hierarchy for prims matching specific criteria.
|
|
402
|
-
|
|
403
|
-
Traverses the scene starting from root_path and finds all prims that match
|
|
404
|
-
the target type (or all applicable targets if target is None). This works
|
|
405
|
-
regardless of simulation state.
|
|
406
|
-
|
|
407
|
-
:param root_path: Root path to start the query from (default: "/World").
|
|
408
|
-
:param target: Specific target type to filter for (None returns all).
|
|
409
|
-
:return: Scene query response with matching prims and their applicable targets.
|
|
410
|
-
"""
|
|
411
|
-
|
|
412
|
-
return self._session.query_sim_rpc(
|
|
413
|
-
endpoint="scene/query_hierarchy",
|
|
414
|
-
response_type=SceneQueryResponse,
|
|
415
|
-
payload={"root_path": root_path, "target": target},
|
|
416
|
-
)
|
|
417
|
-
|
|
418
|
-
def delete_prim(self, path: str) -> None:
|
|
419
|
-
"""
|
|
420
|
-
Delete a prim from the scene.
|
|
421
|
-
|
|
422
|
-
:param path: USD path for the prim to delete.
|
|
423
|
-
"""
|
|
424
|
-
|
|
425
|
-
self._session.query_sim_rpc(endpoint="scene/delete_prim", payload={"path": path})
|
|
426
|
-
|
|
427
|
-
def add_asset(
|
|
428
|
-
self,
|
|
429
|
-
path: str,
|
|
430
|
-
name: str | None = None,
|
|
431
|
-
version: str | None = None,
|
|
432
|
-
asset_file_path: str | None = None,
|
|
433
|
-
asset_prim_path: str | None = None,
|
|
434
|
-
remove_articulation: bool = True,
|
|
435
|
-
remove_rigid_body: bool = False,
|
|
436
|
-
remove_sensors: bool = False,
|
|
437
|
-
world_pose: Pose | dict | None = None,
|
|
438
|
-
local_pose: Pose | dict | None = None,
|
|
439
|
-
scale: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
440
|
-
) -> str:
|
|
441
|
-
"""
|
|
442
|
-
Add and convert an asset file (FBX, OBJ, glTF, USD, etc) to USD.
|
|
443
|
-
|
|
444
|
-
Either provide asset_file_path directly OR provide both name and version to load from
|
|
445
|
-
the asset registry. Exactly one option must be used.
|
|
446
|
-
|
|
447
|
-
:param path: USD path where the asset will be added (e.g., "/World/my_model").
|
|
448
|
-
:param name: Name of the asset in the registry (requires version).
|
|
449
|
-
:param version: Version of the asset in the registry (requires name).
|
|
450
|
-
:param asset_file_path: Path to the asset file (FBX, OBJ, glTF, STL, USD, etc).
|
|
451
|
-
:param asset_prim_path: Full path to prim in the USD file to reference.
|
|
452
|
-
:param remove_articulation: Whether to remove articulation APIs.
|
|
453
|
-
:param remove_rigid_body: Whether to remove rigid body APIs.
|
|
454
|
-
:param remove_sensors: Whether to remove sensor and graph prims.
|
|
455
|
-
:param world_pose: Optional world pose as Pose (or dict with position/orientation lists).
|
|
456
|
-
:param local_pose: Optional local pose as Pose (or dict with position/orientation lists).
|
|
457
|
-
:param scale: Optional scale as Vector3 (or list/tuple of 3 floats).
|
|
458
|
-
:raises ValueError: If neither option or both options are provided.
|
|
459
|
-
"""
|
|
460
|
-
|
|
461
|
-
# Validate that exactly one option is provided
|
|
462
|
-
has_file_path = asset_file_path is not None
|
|
463
|
-
has_name_version = name is not None and version is not None
|
|
464
|
-
has_partial_name_version = (name is not None) != (version is not None)
|
|
465
|
-
if has_partial_name_version:
|
|
466
|
-
raise ValueError("Both name and version must be provided together")
|
|
467
|
-
if not has_file_path and not has_name_version:
|
|
468
|
-
raise ValueError("Either asset_file_path or both name and version must be provided")
|
|
469
|
-
if has_file_path and has_name_version:
|
|
470
|
-
raise ValueError("Cannot provide both asset_file_path and name/version")
|
|
471
|
-
|
|
472
|
-
# Resolve asset file path from registry if name/version provided
|
|
473
|
-
if has_name_version:
|
|
474
|
-
if name is None or version is None:
|
|
475
|
-
raise ValueError("Name and version must be provided together")
|
|
476
|
-
asset_file_path = str(get_asset_path(name=name, version=version, assert_exists=True))
|
|
477
|
-
|
|
478
|
-
if not asset_file_path:
|
|
479
|
-
raise ValueError("Asset file path is required")
|
|
480
|
-
self._session.query_sim_rpc(
|
|
481
|
-
endpoint="scene/add_asset",
|
|
482
|
-
payload={
|
|
483
|
-
"path": path,
|
|
484
|
-
"asset_file_path": asset_file_path,
|
|
485
|
-
"asset_prim_path": asset_prim_path,
|
|
486
|
-
"remove_articulation": remove_articulation,
|
|
487
|
-
"remove_rigid_body": remove_rigid_body,
|
|
488
|
-
"remove_sensors": remove_sensors,
|
|
489
|
-
"world_pose": Pose.from_any(world_pose) if world_pose is not None else None,
|
|
490
|
-
"local_pose": Pose.from_any(local_pose) if local_pose is not None else None,
|
|
491
|
-
"scale": Vector3.from_any(scale) if scale is not None else None,
|
|
492
|
-
},
|
|
493
|
-
)
|
|
494
|
-
return path
|
|
495
|
-
|
|
496
|
-
def add_geometry(
|
|
497
|
-
self,
|
|
498
|
-
path: str,
|
|
499
|
-
geometry_type: GeometryType,
|
|
500
|
-
radius: float | None = None,
|
|
501
|
-
height: float | None = None,
|
|
502
|
-
size: float | None = None,
|
|
503
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
504
|
-
opacity: float = 1.0,
|
|
505
|
-
world_pose: Pose | dict | None = None,
|
|
506
|
-
local_pose: Pose | dict | None = None,
|
|
507
|
-
enable_collision: bool = True,
|
|
508
|
-
static_friction: float = 0.5,
|
|
509
|
-
dynamic_friction: float = 0.5,
|
|
510
|
-
restitution: float = 0.2,
|
|
511
|
-
mesh_file_path: str | None = None,
|
|
512
|
-
mesh_approximation: MeshApproximation = MeshApproximation.CONVEX_DECOMPOSITION,
|
|
513
|
-
contact_offset: float | None = None,
|
|
514
|
-
rest_offset: float | None = None,
|
|
515
|
-
torsional_patch_radius: float | None = None,
|
|
516
|
-
min_torsional_patch_radius: float | None = None,
|
|
517
|
-
) -> Geometry:
|
|
518
|
-
"""
|
|
519
|
-
Add geometry to the scene.
|
|
520
|
-
|
|
521
|
-
:param path: USD path for the geometry.
|
|
522
|
-
:param geometry_type: Type of geometry (sphere, cube, cylinder, cone, capsule, mesh).
|
|
523
|
-
:param radius: Radius for sphere/cylinder/cone/capsule.
|
|
524
|
-
:param height: Height for cylinder/cone/capsule.
|
|
525
|
-
:param size: Size for cube (uniform).
|
|
526
|
-
:param color: RGB color as Vector3 (or list/tuple of 3 floats) with values 0-1.
|
|
527
|
-
:param opacity: Opacity from 0 (transparent) to 1 (opaque).
|
|
528
|
-
:param world_pose: Optional world pose as Pose (or dict with position/orientation lists).
|
|
529
|
-
:param local_pose: Optional local pose as Pose (or dict with position/orientation lists).
|
|
530
|
-
:param enable_collision: Whether to enable collision.
|
|
531
|
-
:param static_friction: Static friction coefficient.
|
|
532
|
-
:param dynamic_friction: Dynamic friction coefficient.
|
|
533
|
-
:param restitution: Restitution (bounciness).
|
|
534
|
-
:param mesh_file_path: Path to mesh file (FBX, OBJ, glTF, STL, etc.) - required for MESH type.
|
|
535
|
-
:param mesh_approximation: Collision mesh approximation method (for meshes).
|
|
536
|
-
:param contact_offset: Distance at which collision detection begins.
|
|
537
|
-
:param rest_offset: Minimum separation distance between objects.
|
|
538
|
-
:param torsional_patch_radius: Radius for torsional friction calculations.
|
|
539
|
-
:param min_torsional_patch_radius: Minimum radius for torsional friction.
|
|
540
|
-
:return: The geometry instance.
|
|
541
|
-
"""
|
|
542
|
-
|
|
543
|
-
return Geometry.add(
|
|
544
|
-
path=path,
|
|
545
|
-
config=GeometryConfig(
|
|
546
|
-
geometry_type=geometry_type,
|
|
547
|
-
radius=radius,
|
|
548
|
-
height=height,
|
|
549
|
-
size=size,
|
|
550
|
-
color=Vector3.from_any(color) if color is not None else None,
|
|
551
|
-
opacity=opacity,
|
|
552
|
-
enable_collision=enable_collision,
|
|
553
|
-
static_friction=static_friction,
|
|
554
|
-
dynamic_friction=dynamic_friction,
|
|
555
|
-
restitution=restitution,
|
|
556
|
-
mesh_file_path=mesh_file_path,
|
|
557
|
-
mesh_approximation=mesh_approximation,
|
|
558
|
-
contact_offset=contact_offset,
|
|
559
|
-
rest_offset=rest_offset,
|
|
560
|
-
torsional_patch_radius=torsional_patch_radius,
|
|
561
|
-
min_torsional_patch_radius=min_torsional_patch_radius,
|
|
562
|
-
),
|
|
563
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
564
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
565
|
-
)
|
|
566
|
-
|
|
567
|
-
def get_geometry(self, path: str) -> Geometry:
|
|
568
|
-
"""
|
|
569
|
-
Get existing geometry from the scene.
|
|
570
|
-
|
|
571
|
-
:param path: USD path for the geometry.
|
|
572
|
-
:return: The geometry instance.
|
|
573
|
-
"""
|
|
574
|
-
|
|
575
|
-
return Geometry(path)
|
|
576
|
-
|
|
577
|
-
def add_articulation(
|
|
578
|
-
self,
|
|
579
|
-
path: str,
|
|
580
|
-
joint_configs: list[ArticulationJointConfig] | None = None,
|
|
581
|
-
solver_position_iterations: int = 32,
|
|
582
|
-
solver_velocity_iterations: int = 1,
|
|
583
|
-
sleep_threshold: float = 0.005,
|
|
584
|
-
stabilization_threshold: float = 0.001,
|
|
585
|
-
enable_self_collisions: bool = False,
|
|
586
|
-
world_pose: Pose | dict | None = None,
|
|
587
|
-
local_pose: Pose | dict | None = None,
|
|
588
|
-
scale: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
589
|
-
) -> Articulation:
|
|
590
|
-
"""
|
|
591
|
-
Add an articulation to the scene.
|
|
592
|
-
|
|
593
|
-
:param path: USD path for the articulation.
|
|
594
|
-
:param joint_configs: Per-joint configurations (stiffness, damping, limits, etc).
|
|
595
|
-
:param solver_position_iterations: Number of position iterations for the solver.
|
|
596
|
-
:param solver_velocity_iterations: Number of velocity iterations for the solver.
|
|
597
|
-
:param sleep_threshold: Sleep threshold for the articulation.
|
|
598
|
-
:param stabilization_threshold: Stabilization threshold for the articulation.
|
|
599
|
-
:param enable_self_collisions: Whether to enable self-collisions.
|
|
600
|
-
:param world_pose: Optional world pose as Pose (or dict with position/orientation lists).
|
|
601
|
-
:param local_pose: Optional local pose as Pose (or dict with position/orientation lists).
|
|
602
|
-
:param scale: Optional scale as Vector3 (or list/tuple of 3 floats).
|
|
603
|
-
:return: The articulation instance.
|
|
604
|
-
"""
|
|
605
|
-
|
|
606
|
-
return Articulation.add(
|
|
607
|
-
path=path,
|
|
608
|
-
config=ArticulationConfig(
|
|
609
|
-
solver_position_iterations=solver_position_iterations,
|
|
610
|
-
solver_velocity_iterations=solver_velocity_iterations,
|
|
611
|
-
sleep_threshold=sleep_threshold,
|
|
612
|
-
stabilization_threshold=stabilization_threshold,
|
|
613
|
-
enable_self_collisions=enable_self_collisions,
|
|
614
|
-
joint_configs=joint_configs or [],
|
|
615
|
-
),
|
|
616
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
617
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
618
|
-
scale=Vector3.from_any(scale) if scale is not None else None,
|
|
619
|
-
)
|
|
620
|
-
|
|
621
|
-
def get_articulation(self, path: str) -> Articulation:
|
|
622
|
-
"""
|
|
623
|
-
Get an existing articulation from the scene.
|
|
624
|
-
|
|
625
|
-
:param path: USD path for the articulation.
|
|
626
|
-
:return: The articulation instance.
|
|
627
|
-
"""
|
|
628
|
-
|
|
629
|
-
return Articulation(path)
|
|
630
|
-
|
|
631
|
-
def add_joint(
|
|
632
|
-
self,
|
|
633
|
-
path: str,
|
|
634
|
-
parent_path: str,
|
|
635
|
-
child_path: str,
|
|
636
|
-
pose: Pose | dict | None = None,
|
|
637
|
-
joint_type: JointType = JointType.FIXED,
|
|
638
|
-
axis: JointAxis = JointAxis.X,
|
|
639
|
-
lower_limit: float | None = None,
|
|
640
|
-
upper_limit: float | None = None,
|
|
641
|
-
friction: float = 0.01,
|
|
642
|
-
armature: float = 0.1,
|
|
643
|
-
exclude_from_articulation: bool = False,
|
|
644
|
-
) -> Joint:
|
|
645
|
-
"""
|
|
646
|
-
Add a joint to the scene.
|
|
647
|
-
|
|
648
|
-
:param path: USD path for the joint.
|
|
649
|
-
:param parent_path: USD path to parent body.
|
|
650
|
-
:param child_path: USD path to child body.
|
|
651
|
-
:param pose: Joint pose relative to parent (defaults to identity).
|
|
652
|
-
:param joint_type: Type of joint motion (FIXED, REVOLUTE, PRISMATIC).
|
|
653
|
-
:param axis: Axis of motion for non-fixed joints.
|
|
654
|
-
:param lower_limit: Lower motion limit (degrees for revolute, meters for prismatic).
|
|
655
|
-
:param upper_limit: Upper motion limit (degrees for revolute, meters for prismatic).
|
|
656
|
-
:param friction: Joint friction coefficient (unitless).
|
|
657
|
-
:param armature: Joint armature (kg for prismatic, kg-m^2 for revolute).
|
|
658
|
-
:param exclude_from_articulation: Whether to exclude this joint from articulation.
|
|
659
|
-
:return: The joint instance.
|
|
660
|
-
"""
|
|
661
|
-
|
|
662
|
-
return Joint.add(
|
|
663
|
-
path=path,
|
|
664
|
-
config=JointConfig(
|
|
665
|
-
parent_path=parent_path,
|
|
666
|
-
child_path=child_path,
|
|
667
|
-
pose=Pose.from_any(pose) if pose is not None else Pose.identity(),
|
|
668
|
-
joint_type=joint_type,
|
|
669
|
-
axis=axis,
|
|
670
|
-
lower_limit=lower_limit,
|
|
671
|
-
upper_limit=upper_limit,
|
|
672
|
-
friction=friction,
|
|
673
|
-
armature=armature,
|
|
674
|
-
exclude_from_articulation=exclude_from_articulation,
|
|
675
|
-
),
|
|
676
|
-
)
|
|
677
|
-
|
|
678
|
-
def get_joint(self, path: str) -> Joint:
|
|
679
|
-
"""
|
|
680
|
-
Get an existing joint from the scene.
|
|
681
|
-
|
|
682
|
-
:param path: USD path for the joint.
|
|
683
|
-
:return: The joint instance.
|
|
684
|
-
"""
|
|
685
|
-
|
|
686
|
-
return Joint(path)
|
|
687
|
-
|
|
688
|
-
def add_rigid_body(
|
|
689
|
-
self,
|
|
690
|
-
path: str,
|
|
691
|
-
body_type: BodyType = BodyType.DYNAMIC,
|
|
692
|
-
mass: float = 1.0,
|
|
693
|
-
density: float | None = None,
|
|
694
|
-
center_of_mass: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
695
|
-
diagonal_inertia: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
696
|
-
principal_axes: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
697
|
-
sleep_threshold: float | None = None,
|
|
698
|
-
linear_velocity: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
699
|
-
angular_velocity: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
700
|
-
world_pose: Pose | dict | None = None,
|
|
701
|
-
local_pose: Pose | dict | None = None,
|
|
702
|
-
scale: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
703
|
-
) -> RigidBody:
|
|
704
|
-
"""
|
|
705
|
-
Add rigid body physics to the scene.
|
|
706
|
-
|
|
707
|
-
:param path: USD path for the rigid body.
|
|
708
|
-
:param body_type: Body type (dynamic or kinematic).
|
|
709
|
-
:param mass: Mass in kg.
|
|
710
|
-
:param density: Density in kg/m³ (alternative to mass).
|
|
711
|
-
:param center_of_mass: Center of mass offset as Vector3 (or list/tuple) in body frame.
|
|
712
|
-
:param diagonal_inertia: Diagonal inertia values as Vector3 (or list/tuple).
|
|
713
|
-
:param principal_axes: Principal axes orientation as RPY Vector3 (or list/tuple).
|
|
714
|
-
:param sleep_threshold: Mass-normalized kinetic energy threshold for sleeping.
|
|
715
|
-
:param linear_velocity: Initial linear velocity as Vector3 (or list/tuple).
|
|
716
|
-
:param angular_velocity: Initial angular velocity as Vector3 (or list/tuple).
|
|
717
|
-
:param world_pose: Optional world pose as Pose (or dict with position/orientation lists).
|
|
718
|
-
:param local_pose: Optional local pose as Pose (or dict with position/orientation lists).
|
|
719
|
-
:param scale: Optional scale as Vector3 (or list/tuple of 3 floats).
|
|
720
|
-
:return: The rigid body instance.
|
|
721
|
-
"""
|
|
722
|
-
|
|
723
|
-
return RigidBody.add(
|
|
724
|
-
path=path,
|
|
725
|
-
config=RigidBodyConfig(
|
|
726
|
-
body_type=body_type,
|
|
727
|
-
mass=mass,
|
|
728
|
-
density=density,
|
|
729
|
-
center_of_mass=Vector3.from_any(center_of_mass) if center_of_mass is not None else None,
|
|
730
|
-
diagonal_inertia=Vector3.from_any(diagonal_inertia) if diagonal_inertia is not None else None,
|
|
731
|
-
principal_axes=Vector3.from_any(principal_axes) if principal_axes is not None else None,
|
|
732
|
-
sleep_threshold=sleep_threshold,
|
|
733
|
-
linear_velocity=Vector3.from_any(linear_velocity) if linear_velocity is not None else None,
|
|
734
|
-
angular_velocity=Vector3.from_any(angular_velocity) if angular_velocity is not None else None,
|
|
735
|
-
),
|
|
736
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
737
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
738
|
-
scale=Vector3.from_any(scale) if scale is not None else None,
|
|
739
|
-
)
|
|
740
|
-
|
|
741
|
-
def get_rigid_body(self, path: str) -> RigidBody:
|
|
742
|
-
"""
|
|
743
|
-
Get an existing rigid body from the scene.
|
|
744
|
-
|
|
745
|
-
:param path: USD path for the rigid body.
|
|
746
|
-
:return: The rigid body instance.
|
|
747
|
-
"""
|
|
748
|
-
|
|
749
|
-
return RigidBody(path)
|
|
750
|
-
|
|
751
|
-
def add_light(
|
|
752
|
-
self,
|
|
753
|
-
path: str,
|
|
754
|
-
light_type: LightType = LightType.SPHERE,
|
|
755
|
-
intensity: float = 30000.0,
|
|
756
|
-
exposure: float = 10.0,
|
|
757
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
758
|
-
radius: float = 0.1,
|
|
759
|
-
width: float | None = None,
|
|
760
|
-
height: float | None = None,
|
|
761
|
-
length: float | None = None,
|
|
762
|
-
angle: float | None = None,
|
|
763
|
-
texture_file: str | None = None,
|
|
764
|
-
world_pose: Pose | dict | None = None,
|
|
765
|
-
local_pose: Pose | dict | None = None,
|
|
766
|
-
) -> Light:
|
|
767
|
-
"""
|
|
768
|
-
Add a light to the scene.
|
|
769
|
-
|
|
770
|
-
:param path: USD path for the light.
|
|
771
|
-
:param light_type: Type of light (sphere, rect, disk, cylinder, distant, dome).
|
|
772
|
-
:param intensity: Light intensity.
|
|
773
|
-
:param exposure: Light exposure value.
|
|
774
|
-
:param color: RGB color as Vector3 (or list/tuple of 3 floats) with values 0-1 (defaults to white).
|
|
775
|
-
:param radius: Light radius in meters (for sphere lights).
|
|
776
|
-
:param width: Width in meters (for rect lights).
|
|
777
|
-
:param height: Height in meters (for rect/cylinder lights).
|
|
778
|
-
:param length: Length in meters (for cylinder lights).
|
|
779
|
-
:param angle: Angle in degrees (for distant lights).
|
|
780
|
-
:param texture_file: Path to texture file (for dome lights).
|
|
781
|
-
:param world_pose: Optional world pose as Pose (or dict with position/orientation lists).
|
|
782
|
-
:param local_pose: Optional local pose as Pose (or dict with position/orientation lists).
|
|
783
|
-
:return: The light instance.
|
|
784
|
-
"""
|
|
785
|
-
|
|
786
|
-
return Light.add(
|
|
787
|
-
path=path,
|
|
788
|
-
config=LightConfig(
|
|
789
|
-
light_type=light_type,
|
|
790
|
-
intensity=intensity,
|
|
791
|
-
exposure=exposure,
|
|
792
|
-
color=Vector3.from_any(color) if color is not None else Vector3(data=(1.0, 1.0, 1.0)),
|
|
793
|
-
radius=radius,
|
|
794
|
-
width=width,
|
|
795
|
-
height=height,
|
|
796
|
-
length=length,
|
|
797
|
-
angle=angle,
|
|
798
|
-
texture_file=texture_file,
|
|
799
|
-
),
|
|
800
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
801
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
802
|
-
)
|
|
803
|
-
|
|
804
|
-
def get_light(self, path: str) -> Light:
|
|
805
|
-
"""
|
|
806
|
-
Get an existing light from the scene.
|
|
807
|
-
|
|
808
|
-
:param path: USD path for the light.
|
|
809
|
-
:return: The light instance.
|
|
810
|
-
"""
|
|
811
|
-
|
|
812
|
-
return Light(path)
|
|
813
|
-
|
|
814
|
-
def add_xform(
|
|
815
|
-
self,
|
|
816
|
-
path: str,
|
|
817
|
-
world_pose: Pose | dict | None = None,
|
|
818
|
-
local_pose: Pose | dict | None = None,
|
|
819
|
-
scale: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
820
|
-
) -> XForm:
|
|
821
|
-
"""
|
|
822
|
-
Add an xform to the scene.
|
|
823
|
-
|
|
824
|
-
:param path: USD path for the xform.
|
|
825
|
-
:param world_pose: Optional world pose as Pose (or dict with position/orientation lists).
|
|
826
|
-
:param local_pose: Optional local pose as Pose (or dict with position/orientation lists).
|
|
827
|
-
:param scale: Optional scale as Vector3 (or list/tuple of 3 floats).
|
|
828
|
-
:return: The xform instance.
|
|
829
|
-
"""
|
|
830
|
-
|
|
831
|
-
return XForm.add(
|
|
832
|
-
path=path,
|
|
833
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
834
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
835
|
-
scale=Vector3.from_any(scale) if scale is not None else None,
|
|
836
|
-
)
|
|
837
|
-
|
|
838
|
-
def get_xform(self, path: str) -> XForm:
|
|
839
|
-
"""
|
|
840
|
-
Get an existing xform from the scene.
|
|
841
|
-
|
|
842
|
-
:param path: USD path for the xform.
|
|
843
|
-
:return: The xform instance.
|
|
844
|
-
"""
|
|
845
|
-
|
|
846
|
-
return XForm(path)
|
|
847
|
-
|
|
848
|
-
@overload
|
|
849
|
-
def add_animation(
|
|
850
|
-
self,
|
|
851
|
-
path: str,
|
|
852
|
-
*,
|
|
853
|
-
waypoints: list[Vector3],
|
|
854
|
-
loop: bool = True,
|
|
855
|
-
) -> Animation: ...
|
|
856
|
-
|
|
857
|
-
@overload
|
|
858
|
-
def add_animation(
|
|
859
|
-
self,
|
|
860
|
-
path: str,
|
|
861
|
-
*,
|
|
862
|
-
basis_curve: str,
|
|
863
|
-
samples_per_segment: int = 10,
|
|
864
|
-
sort_by: Literal["X", "Y", "Z"] | None = None,
|
|
865
|
-
ascending: bool = True,
|
|
866
|
-
) -> Animation: ...
|
|
867
|
-
|
|
868
|
-
def add_animation(
|
|
869
|
-
self,
|
|
870
|
-
path: str,
|
|
871
|
-
*,
|
|
872
|
-
waypoints: list[Vector3] | None = None,
|
|
873
|
-
basis_curve: str | None = None,
|
|
874
|
-
samples_per_segment: int = 10,
|
|
875
|
-
sort_by: Literal["X", "Y", "Z"] | None = None,
|
|
876
|
-
ascending: bool = True,
|
|
877
|
-
loop: bool = True,
|
|
878
|
-
) -> Animation:
|
|
879
|
-
"""
|
|
880
|
-
Add an animation to the scene.
|
|
881
|
-
|
|
882
|
-
:param path: USD path for the animation (must contain a skeleton root).
|
|
883
|
-
:param waypoints: List of waypoints for the animation path.
|
|
884
|
-
:param basis_curve: Path to the basis curve to use for the animation.
|
|
885
|
-
:param samples_per_segment: The number of samples per segment to use from the basis curve.
|
|
886
|
-
:param sort_by: The axis to sort the points by.
|
|
887
|
-
:param ascending: Whether to sort the points in ascending order.
|
|
888
|
-
:param loop: Whether to loop the animation.
|
|
889
|
-
:return: The animation instance.
|
|
890
|
-
:raises ValueError: If both waypoints and basis curve are provided.
|
|
891
|
-
:raises ValueError: If neither waypoints nor basis curve are provided.
|
|
892
|
-
"""
|
|
893
|
-
if waypoints is not None and basis_curve is not None:
|
|
894
|
-
raise ValueError("Must specify either waypoints or basis curve")
|
|
895
|
-
if waypoints is not None:
|
|
896
|
-
return Animation.add(
|
|
897
|
-
path=path,
|
|
898
|
-
waypoints=waypoints,
|
|
899
|
-
loop=loop,
|
|
900
|
-
)
|
|
901
|
-
elif basis_curve is not None:
|
|
902
|
-
return Animation.add(
|
|
903
|
-
path=path,
|
|
904
|
-
basis_curve=basis_curve,
|
|
905
|
-
samples_per_segment=samples_per_segment,
|
|
906
|
-
sort_by=sort_by,
|
|
907
|
-
ascending=ascending,
|
|
908
|
-
)
|
|
909
|
-
else:
|
|
910
|
-
raise ValueError("Must specify either waypoints or basis curve")
|
|
911
|
-
|
|
912
|
-
def get_animation(self, path: str) -> Animation:
|
|
913
|
-
"""
|
|
914
|
-
Get an existing animation from the scene.
|
|
915
|
-
|
|
916
|
-
:param path: USD path for the animation.
|
|
917
|
-
:return: The animation instance.
|
|
918
|
-
"""
|
|
919
|
-
|
|
920
|
-
return Animation(path)
|
|
921
|
-
|
|
922
|
-
def add_ground_plane(
|
|
923
|
-
self,
|
|
924
|
-
path: str,
|
|
925
|
-
size: float = 5000.0,
|
|
926
|
-
z_position: float = 0.0,
|
|
927
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
928
|
-
static_friction: float = 0.5,
|
|
929
|
-
dynamic_friction: float = 0.5,
|
|
930
|
-
restitution: float = 0.0,
|
|
931
|
-
) -> GroundPlane:
|
|
932
|
-
"""
|
|
933
|
-
Add a ground plane to the scene.
|
|
934
|
-
|
|
935
|
-
:param path: USD path for the ground plane.
|
|
936
|
-
:param size: Size of the ground plane in meters.
|
|
937
|
-
:param z_position: Z position of the ground plane.
|
|
938
|
-
:param color: RGB color as Vector3 (or list/tuple of 3 floats) with values 0-1 (defaults to gray).
|
|
939
|
-
:param static_friction: Friction when objects are not moving.
|
|
940
|
-
:param dynamic_friction: Friction when objects are sliding.
|
|
941
|
-
:param restitution: Bounciness of collisions (0=no bounce, 1=perfect bounce).
|
|
942
|
-
:return: The ground plane instance.
|
|
943
|
-
"""
|
|
944
|
-
|
|
945
|
-
return GroundPlane.add(
|
|
946
|
-
path=path,
|
|
947
|
-
config=GroundPlaneConfig(
|
|
948
|
-
size=size,
|
|
949
|
-
z_position=z_position,
|
|
950
|
-
color=Vector3.from_any(color) if color is not None else Vector3(data=(0.5, 0.5, 0.5)),
|
|
951
|
-
static_friction=static_friction,
|
|
952
|
-
dynamic_friction=dynamic_friction,
|
|
953
|
-
restitution=restitution,
|
|
954
|
-
),
|
|
955
|
-
)
|
|
956
|
-
|
|
957
|
-
def get_ground_plane(self, path: str) -> GroundPlane:
|
|
958
|
-
"""
|
|
959
|
-
Get an existing ground plane from the scene.
|
|
960
|
-
|
|
961
|
-
:param path: USD path for the ground plane.
|
|
962
|
-
:return: The ground plane instance.
|
|
963
|
-
"""
|
|
964
|
-
|
|
965
|
-
return GroundPlane(path)
|
|
966
|
-
|
|
967
|
-
def add_camera(
|
|
968
|
-
self,
|
|
969
|
-
path: str,
|
|
970
|
-
config: CameraConfig | None = None,
|
|
971
|
-
mode: CameraMode = CameraMode.RGB,
|
|
972
|
-
frequency: int = 30,
|
|
973
|
-
width: int = 640,
|
|
974
|
-
height: int = 480,
|
|
975
|
-
focal_length: float = 50.0,
|
|
976
|
-
sensor_width: float = 20.4,
|
|
977
|
-
sensor_height: float = 15.3,
|
|
978
|
-
near_clip: float = 0.1,
|
|
979
|
-
far_clip: float = 1000.0,
|
|
980
|
-
f_stop: float = 0.0,
|
|
981
|
-
focus_distance: float = 10.0,
|
|
982
|
-
principal_point_x: float = 0.0,
|
|
983
|
-
principal_point_y: float = 0.0,
|
|
984
|
-
distortion_model: DistortionModel = DistortionModel.PINHOLE,
|
|
985
|
-
distortion_coefficients: list[float] | None = None,
|
|
986
|
-
world_pose: Pose | dict | None = None,
|
|
987
|
-
local_pose: Pose | dict | None = None,
|
|
988
|
-
) -> Camera:
|
|
989
|
-
"""
|
|
990
|
-
Add a camera to the scene.
|
|
991
|
-
|
|
992
|
-
:param path: USD path for the camera.
|
|
993
|
-
:param config: Optional camera configuration (alternative to individual parameters).
|
|
994
|
-
:param mode: Camera capture mode (RGB or depth).
|
|
995
|
-
:param frequency: Camera update frequency in Hz.
|
|
996
|
-
:param width: Image width in pixels.
|
|
997
|
-
:param height: Image height in pixels.
|
|
998
|
-
:param focal_length: Focal length in mm.
|
|
999
|
-
:param sensor_width: Physical sensor width in mm.
|
|
1000
|
-
:param sensor_height: Physical sensor height in mm.
|
|
1001
|
-
:param near_clip: Near clipping plane in meters.
|
|
1002
|
-
:param far_clip: Far clipping plane in meters.
|
|
1003
|
-
:param f_stop: F-stop for depth of field.
|
|
1004
|
-
:param focus_distance: Focus distance in meters.
|
|
1005
|
-
:param principal_point_x: Principal point X offset in pixels.
|
|
1006
|
-
:param principal_point_y: Principal point Y offset in pixels.
|
|
1007
|
-
:param distortion_model: Lens distortion model.
|
|
1008
|
-
:param distortion_coefficients: Distortion coefficients.
|
|
1009
|
-
:param world_pose: Optional world pose.
|
|
1010
|
-
:param local_pose: Optional local pose.
|
|
1011
|
-
:return: The camera instance.
|
|
1012
|
-
"""
|
|
1013
|
-
|
|
1014
|
-
if config is None:
|
|
1015
|
-
config = CameraConfig(
|
|
1016
|
-
mode=mode,
|
|
1017
|
-
frequency=frequency,
|
|
1018
|
-
width=width,
|
|
1019
|
-
height=height,
|
|
1020
|
-
focal_length=focal_length,
|
|
1021
|
-
sensor_width=sensor_width,
|
|
1022
|
-
sensor_height=sensor_height,
|
|
1023
|
-
near_clip=near_clip,
|
|
1024
|
-
far_clip=far_clip,
|
|
1025
|
-
f_stop=f_stop,
|
|
1026
|
-
focus_distance=focus_distance,
|
|
1027
|
-
principal_point_x=principal_point_x,
|
|
1028
|
-
principal_point_y=principal_point_y,
|
|
1029
|
-
distortion_model=distortion_model,
|
|
1030
|
-
distortion_coefficients=distortion_coefficients,
|
|
1031
|
-
)
|
|
1032
|
-
|
|
1033
|
-
return Camera.add(
|
|
1034
|
-
path=path,
|
|
1035
|
-
config=config,
|
|
1036
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
1037
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
1038
|
-
)
|
|
1039
|
-
|
|
1040
|
-
def get_camera(self, path: str) -> Camera:
|
|
1041
|
-
"""
|
|
1042
|
-
Get existing camera from the scene.
|
|
1043
|
-
|
|
1044
|
-
:param path: USD path for the camera.
|
|
1045
|
-
:return: The camera instance.
|
|
1046
|
-
"""
|
|
1047
|
-
|
|
1048
|
-
return Camera(path)
|
|
1049
|
-
|
|
1050
|
-
def add_imu(
|
|
1051
|
-
self,
|
|
1052
|
-
path: str,
|
|
1053
|
-
config: ImuConfig | None = None,
|
|
1054
|
-
frequency: int | None = None,
|
|
1055
|
-
linear_acceleration_filter_size: int = 10,
|
|
1056
|
-
angular_velocity_filter_size: int = 10,
|
|
1057
|
-
orientation_filter_size: int = 10,
|
|
1058
|
-
world_pose: Pose | dict | None = None,
|
|
1059
|
-
local_pose: Pose | dict | None = None,
|
|
1060
|
-
) -> Imu:
|
|
1061
|
-
"""
|
|
1062
|
-
Add an IMU to the scene.
|
|
1063
|
-
|
|
1064
|
-
:param path: USD path for the IMU.
|
|
1065
|
-
:param config: Optional IMU configuration (alternative to individual parameters).
|
|
1066
|
-
:param frequency: Sensor update frequency in Hz (optional, defaults to physics rate).
|
|
1067
|
-
:param linear_acceleration_filter_size: Filter window size for linear acceleration.
|
|
1068
|
-
:param angular_velocity_filter_size: Filter window size for angular velocity.
|
|
1069
|
-
:param orientation_filter_size: Filter window size for orientation.
|
|
1070
|
-
:param world_pose: Optional world pose.
|
|
1071
|
-
:param local_pose: Optional local pose.
|
|
1072
|
-
:return: The IMU instance.
|
|
1073
|
-
"""
|
|
1074
|
-
|
|
1075
|
-
if config is None:
|
|
1076
|
-
config = ImuConfig(
|
|
1077
|
-
frequency=frequency,
|
|
1078
|
-
linear_acceleration_filter_size=linear_acceleration_filter_size,
|
|
1079
|
-
angular_velocity_filter_size=angular_velocity_filter_size,
|
|
1080
|
-
orientation_filter_size=orientation_filter_size,
|
|
1081
|
-
)
|
|
1082
|
-
|
|
1083
|
-
return Imu.add(
|
|
1084
|
-
path=path,
|
|
1085
|
-
config=config,
|
|
1086
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
1087
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
1088
|
-
)
|
|
1089
|
-
|
|
1090
|
-
def get_imu(self, path: str) -> Imu:
|
|
1091
|
-
"""
|
|
1092
|
-
Get existing IMU from the scene.
|
|
1093
|
-
|
|
1094
|
-
:param path: USD path for the IMU.
|
|
1095
|
-
:return: The IMU instance.
|
|
1096
|
-
"""
|
|
1097
|
-
|
|
1098
|
-
return Imu(path)
|
|
1099
|
-
|
|
1100
|
-
def add_radar(
|
|
1101
|
-
self,
|
|
1102
|
-
path: str,
|
|
1103
|
-
config: RadarConfig | None = None,
|
|
1104
|
-
frequency: int = 10,
|
|
1105
|
-
max_azimuth: float = 66.0,
|
|
1106
|
-
max_elevation: float = 20.0,
|
|
1107
|
-
max_range: float = 200.0,
|
|
1108
|
-
range_resolution: float = 0.4,
|
|
1109
|
-
azimuth_resolution: float = 1.3,
|
|
1110
|
-
elevation_resolution: float = 5.0,
|
|
1111
|
-
azimuth_noise: float = 0.0,
|
|
1112
|
-
range_noise: float = 0.0,
|
|
1113
|
-
world_pose: Pose | dict | None = None,
|
|
1114
|
-
local_pose: Pose | dict | None = None,
|
|
1115
|
-
) -> Radar:
|
|
1116
|
-
"""
|
|
1117
|
-
Add a radar to the scene.
|
|
1118
|
-
|
|
1119
|
-
:param path: USD path for the radar.
|
|
1120
|
-
:param config: Optional radar configuration (alternative to individual parameters).
|
|
1121
|
-
:param frequency: Sensor update frequency in Hz.
|
|
1122
|
-
:param max_azimuth: Maximum azimuth angle in degrees (±FOV from center).
|
|
1123
|
-
:param max_elevation: Maximum elevation angle in degrees (±FOV from center).
|
|
1124
|
-
:param max_range: Maximum detection range in meters.
|
|
1125
|
-
:param range_resolution: Range resolution in meters.
|
|
1126
|
-
:param azimuth_resolution: Azimuth resolution at boresight in degrees.
|
|
1127
|
-
:param elevation_resolution: Elevation resolution at boresight in degrees.
|
|
1128
|
-
:param azimuth_noise: Azimuth measurement noise standard deviation in radians.
|
|
1129
|
-
:param range_noise: Range measurement noise standard deviation in meters.
|
|
1130
|
-
:param world_pose: Optional world pose.
|
|
1131
|
-
:param local_pose: Optional local pose.
|
|
1132
|
-
:return: The radar instance.
|
|
1133
|
-
"""
|
|
1134
|
-
|
|
1135
|
-
if config is None:
|
|
1136
|
-
config = RadarConfig(
|
|
1137
|
-
frequency=frequency,
|
|
1138
|
-
max_azimuth=max_azimuth,
|
|
1139
|
-
max_elevation=max_elevation,
|
|
1140
|
-
max_range=max_range,
|
|
1141
|
-
range_resolution=range_resolution,
|
|
1142
|
-
azimuth_resolution=azimuth_resolution,
|
|
1143
|
-
elevation_resolution=elevation_resolution,
|
|
1144
|
-
azimuth_noise=azimuth_noise,
|
|
1145
|
-
range_noise=range_noise,
|
|
1146
|
-
)
|
|
1147
|
-
|
|
1148
|
-
return Radar.add(
|
|
1149
|
-
path=path,
|
|
1150
|
-
config=config,
|
|
1151
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
1152
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
1153
|
-
)
|
|
1154
|
-
|
|
1155
|
-
def add_basis_curve_semi_circle(
|
|
1156
|
-
self,
|
|
1157
|
-
path: str,
|
|
1158
|
-
center: Vector3 | list[float] | tuple[float, float, float] = Vector3.zeros(),
|
|
1159
|
-
radius: float = 1.0,
|
|
1160
|
-
min_angle_deg: float = 0.0,
|
|
1161
|
-
max_angle_deg: float = 180.0,
|
|
1162
|
-
guide: bool = False,
|
|
1163
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
1164
|
-
width: float = 0.005,
|
|
1165
|
-
) -> BasisCurve:
|
|
1166
|
-
"""
|
|
1167
|
-
Add a basis curve semi-circle to the scene.
|
|
1168
|
-
|
|
1169
|
-
:param path: USD path for the basis curve.
|
|
1170
|
-
:param center: Center of the basis curve.
|
|
1171
|
-
:param radius: Radius of the basis curve.
|
|
1172
|
-
:param min_angle_deg: Minimum angle of the basis curve in degrees.
|
|
1173
|
-
:param max_angle_deg: Maximum angle of the basis curve in degrees.
|
|
1174
|
-
:param guide: If True, mark as guide purpose (invisible to cameras). If False, default purpose.
|
|
1175
|
-
:param color: Optional RGB color [0-1].
|
|
1176
|
-
:param width: Width of the curve.
|
|
1177
|
-
:return: The basis curve instance.
|
|
1178
|
-
"""
|
|
1179
|
-
|
|
1180
|
-
return BasisCurve.add(
|
|
1181
|
-
path=path,
|
|
1182
|
-
center=Vector3.from_any(center),
|
|
1183
|
-
radius=radius,
|
|
1184
|
-
min_angle_deg=min_angle_deg,
|
|
1185
|
-
max_angle_deg=max_angle_deg,
|
|
1186
|
-
guide=guide,
|
|
1187
|
-
color=Vector3.from_any(color) if color is not None else None,
|
|
1188
|
-
width=width,
|
|
1189
|
-
)
|
|
1190
|
-
|
|
1191
|
-
@overload
|
|
1192
|
-
def add_basis_curve_line(
|
|
1193
|
-
self,
|
|
1194
|
-
path: str,
|
|
1195
|
-
*,
|
|
1196
|
-
start: Vector3 | list[float] | tuple[float, float, float],
|
|
1197
|
-
end: Vector3 | list[float] | tuple[float, float, float],
|
|
1198
|
-
guide: bool = False,
|
|
1199
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
1200
|
-
width: float = 0.005,
|
|
1201
|
-
) -> BasisCurve: ...
|
|
1202
|
-
|
|
1203
|
-
@overload
|
|
1204
|
-
def add_basis_curve_line(
|
|
1205
|
-
self,
|
|
1206
|
-
path: str,
|
|
1207
|
-
*,
|
|
1208
|
-
start: Vector3 | list[float] | tuple[float, float, float],
|
|
1209
|
-
angle_deg: float,
|
|
1210
|
-
length: float,
|
|
1211
|
-
guide: bool = False,
|
|
1212
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
1213
|
-
width: float = 0.005,
|
|
1214
|
-
) -> BasisCurve: ...
|
|
1215
|
-
|
|
1216
|
-
def add_basis_curve_line(
|
|
1217
|
-
self,
|
|
1218
|
-
path: str,
|
|
1219
|
-
*,
|
|
1220
|
-
start: Vector3 | list[float] | tuple[float, float, float],
|
|
1221
|
-
end: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
1222
|
-
angle_deg: float | None = None,
|
|
1223
|
-
length: float | None = None,
|
|
1224
|
-
guide: bool = False,
|
|
1225
|
-
color: Vector3 | list[float] | tuple[float, float, float] | None = None,
|
|
1226
|
-
width: float = 0.005,
|
|
1227
|
-
) -> BasisCurve:
|
|
1228
|
-
"""
|
|
1229
|
-
Add a basis curve line to the scene.
|
|
1230
|
-
|
|
1231
|
-
Supports two modes:
|
|
1232
|
-
- Cartesian: Provide start and end points directly
|
|
1233
|
-
- Polar: Provide start point, angle (degrees from +X axis in XY plane), and length
|
|
1234
|
-
|
|
1235
|
-
Examples:
|
|
1236
|
-
# Cartesian mode
|
|
1237
|
-
line = scene.add_basis_curve_line(
|
|
1238
|
-
"/World/line1",
|
|
1239
|
-
start=[0, 0, 0],
|
|
1240
|
-
end=[1, 1, 0],
|
|
1241
|
-
)
|
|
1242
|
-
|
|
1243
|
-
# Polar mode
|
|
1244
|
-
line = scene.add_basis_curve_line(
|
|
1245
|
-
"/World/line2",
|
|
1246
|
-
start=[0, 0, 0],
|
|
1247
|
-
angle_deg=45.0,
|
|
1248
|
-
length=2.0,
|
|
1249
|
-
)
|
|
1250
|
-
|
|
1251
|
-
:param path: USD path for the basis curve.
|
|
1252
|
-
:param start: Start point of the line.
|
|
1253
|
-
:param end: End point of the line (Cartesian mode).
|
|
1254
|
-
:param angle_deg: Angle in degrees from +X axis in XY plane (polar mode).
|
|
1255
|
-
:param length: Length of the line (polar mode).
|
|
1256
|
-
:param guide: If True, mark as guide purpose (invisible to cameras). If False, default purpose.
|
|
1257
|
-
:param color: Optional RGB color [0-1].
|
|
1258
|
-
:param width: Width of the curve.
|
|
1259
|
-
:return: The basis curve instance.
|
|
1260
|
-
:raises ValueError: If both modes are specified or neither mode is complete.
|
|
1261
|
-
"""
|
|
1262
|
-
if end is not None and (angle_deg is not None or length is not None):
|
|
1263
|
-
raise ValueError("Cannot specify both end point and angle/length in Cartesian mode")
|
|
1264
|
-
if end is None and angle_deg is None and length is None:
|
|
1265
|
-
raise ValueError("Must specify either end point or angle/length")
|
|
1266
|
-
if length is not None and angle_deg is None:
|
|
1267
|
-
raise ValueError("Must specify angle when length is provided")
|
|
1268
|
-
if angle_deg is not None and length is None:
|
|
1269
|
-
raise ValueError("Must specify length when angle is provided")
|
|
1270
|
-
|
|
1271
|
-
return BasisCurve.add_line(
|
|
1272
|
-
path=path,
|
|
1273
|
-
start=Vector3.from_any(start),
|
|
1274
|
-
end=Vector3.from_any(end) if end is not None else None,
|
|
1275
|
-
angle_deg=angle_deg,
|
|
1276
|
-
length=length,
|
|
1277
|
-
guide=guide,
|
|
1278
|
-
color=Vector3.from_any(color) if color is not None else None,
|
|
1279
|
-
width=width,
|
|
1280
|
-
)
|
|
1281
|
-
|
|
1282
|
-
def get_basis_curve(self, path: str) -> BasisCurve:
|
|
1283
|
-
"""
|
|
1284
|
-
Get existing basis curve from the scene.
|
|
1285
|
-
|
|
1286
|
-
:param path: USD path for the basis curve.
|
|
1287
|
-
:return: The basis curve instance.
|
|
1288
|
-
"""
|
|
1289
|
-
|
|
1290
|
-
return BasisCurve(path)
|
|
1291
|
-
|
|
1292
|
-
def get_radar(self, path: str) -> Radar:
|
|
1293
|
-
"""
|
|
1294
|
-
Get existing radar from the scene.
|
|
1295
|
-
|
|
1296
|
-
:param path: USD path for the radar.
|
|
1297
|
-
:return: The radar instance.
|
|
1298
|
-
"""
|
|
1299
|
-
|
|
1300
|
-
return Radar(path)
|
|
1301
|
-
|
|
1302
|
-
def add_pir_sensor(
|
|
1303
|
-
self,
|
|
1304
|
-
path: str,
|
|
1305
|
-
config: PirSensorConfig | None = None,
|
|
1306
|
-
update_rate_hz: float = 60.0,
|
|
1307
|
-
max_range: float = 20.0,
|
|
1308
|
-
total_horiz_fov_deg: float = 150.0,
|
|
1309
|
-
sensor_side_fov_deg: float = 45.0,
|
|
1310
|
-
sensor_center_fov_deg: float = 45.0,
|
|
1311
|
-
sensor_rays_horiz: int = 128,
|
|
1312
|
-
sensor_rays_vert: int = 16,
|
|
1313
|
-
min_vertical_angle_center: float = -30.0,
|
|
1314
|
-
max_vertical_angle_center: float = 30.0,
|
|
1315
|
-
min_vertical_angle_side: float = -30.0,
|
|
1316
|
-
max_vertical_angle_side: float = 30.0,
|
|
1317
|
-
gain_center: float = 0.015,
|
|
1318
|
-
gain_sides: float = 0.01,
|
|
1319
|
-
hp_corner_hz: float = 0.4,
|
|
1320
|
-
lp_corner_hz: float = 10.0,
|
|
1321
|
-
threshold: float | None = None,
|
|
1322
|
-
threshold_scale: float = 1.0,
|
|
1323
|
-
blind_time_s: float = 0.5,
|
|
1324
|
-
pulse_counter: int = 2,
|
|
1325
|
-
window_time_s: float = 2.0,
|
|
1326
|
-
count_mode: int = 0,
|
|
1327
|
-
lens_transmission: float = 0.9,
|
|
1328
|
-
lens_segments_h: int = 6,
|
|
1329
|
-
ambient_temp_c: float = 20.0,
|
|
1330
|
-
thermal_time_constant_s: float = 0.2,
|
|
1331
|
-
pyro_responsivity: float = 4000.0,
|
|
1332
|
-
noise_amplitude: float = 20e-6,
|
|
1333
|
-
target_delta_t: float = 10.0,
|
|
1334
|
-
target_distance: float = 5.0,
|
|
1335
|
-
target_emissivity: float = 0.98,
|
|
1336
|
-
target_velocity_mps: float = 1.0,
|
|
1337
|
-
world_pose: Pose | dict | None = None,
|
|
1338
|
-
local_pose: Pose | dict | None = None,
|
|
1339
|
-
) -> PirSensor:
|
|
1340
|
-
"""
|
|
1341
|
-
Add a PIR (Passive Infrared) sensor to the scene.
|
|
1342
|
-
|
|
1343
|
-
PIR sensors detect infrared radiation changes caused by moving warm objects.
|
|
1344
|
-
The sensor uses a dual-element design with interleaved zones for motion detection.
|
|
1345
|
-
|
|
1346
|
-
:param path: USD path for the PIR sensor.
|
|
1347
|
-
:param config: Optional PIR sensor configuration (alternative to individual parameters).
|
|
1348
|
-
:param update_rate_hz: Sensor update frequency in Hz.
|
|
1349
|
-
:param max_range: Maximum detection range in meters.
|
|
1350
|
-
:param total_horiz_fov_deg: Total horizontal coverage in degrees. Enables automatic fanning.
|
|
1351
|
-
:param sensor_side_fov_deg: Horizontal FOV for side sensors in degrees.
|
|
1352
|
-
:param sensor_center_fov_deg: Horizontal FOV for center sensor in degrees.
|
|
1353
|
-
:param sensor_rays_horiz: Number of rays per sensor in horizontal direction.
|
|
1354
|
-
:param sensor_rays_vert: Number of rays per sensor in vertical direction.
|
|
1355
|
-
:param min_vertical_angle_center: Minimum vertical angle for center sensor in degrees.
|
|
1356
|
-
:param max_vertical_angle_center: Maximum vertical angle for center sensor in degrees.
|
|
1357
|
-
:param min_vertical_angle_side: Minimum vertical angle for side sensors in degrees.
|
|
1358
|
-
:param max_vertical_angle_side: Maximum vertical angle for side sensors in degrees.
|
|
1359
|
-
:param gain_center: Amplifier gain for center sensor.
|
|
1360
|
-
:param gain_sides: Amplifier gain for side sensors.
|
|
1361
|
-
:param hp_corner_hz: High-pass filter corner frequency in Hz.
|
|
1362
|
-
:param lp_corner_hz: Low-pass filter corner frequency in Hz.
|
|
1363
|
-
:param threshold: Detection threshold (auto-calibrated if None).
|
|
1364
|
-
:param threshold_scale: Scale factor applied to auto-calibrated threshold.
|
|
1365
|
-
:param blind_time_s: Blind time after detection in seconds.
|
|
1366
|
-
:param pulse_counter: Number of pulses required to trigger detection (1-4).
|
|
1367
|
-
:param window_time_s: Window time for pulse counting in seconds.
|
|
1368
|
-
:param count_mode: Pulse counting mode (0 = sign change required, 1 = any crossing).
|
|
1369
|
-
:param lens_transmission: Lens transmission coefficient (0-1).
|
|
1370
|
-
:param lens_segments_h: Number of horizontal lens segments (facets).
|
|
1371
|
-
:param ambient_temp_c: Ambient temperature in Celsius.
|
|
1372
|
-
:param thermal_time_constant_s: Pyroelectric element thermal time constant in seconds.
|
|
1373
|
-
:param pyro_responsivity: Pyroelectric responsivity scaling factor.
|
|
1374
|
-
:param noise_amplitude: Thermal/electronic noise amplitude.
|
|
1375
|
-
:param target_delta_t: Target temperature difference for threshold calibration in Celsius.
|
|
1376
|
-
:param target_distance: Target distance for threshold calibration in meters.
|
|
1377
|
-
:param target_emissivity: Target emissivity for threshold calibration.
|
|
1378
|
-
:param target_velocity_mps: Target velocity for threshold calibration in m/s.
|
|
1379
|
-
:param world_pose: Optional world pose.
|
|
1380
|
-
:param local_pose: Optional local pose.
|
|
1381
|
-
:return: The PIR sensor instance.
|
|
1382
|
-
"""
|
|
1383
|
-
|
|
1384
|
-
if config is None:
|
|
1385
|
-
config = PirSensorConfig(
|
|
1386
|
-
update_rate_hz=update_rate_hz,
|
|
1387
|
-
max_range=max_range,
|
|
1388
|
-
total_horiz_fov_deg=total_horiz_fov_deg,
|
|
1389
|
-
sensor_side_fov_deg=sensor_side_fov_deg,
|
|
1390
|
-
sensor_center_fov_deg=sensor_center_fov_deg,
|
|
1391
|
-
sensor_rays_horiz=sensor_rays_horiz,
|
|
1392
|
-
sensor_rays_vert=sensor_rays_vert,
|
|
1393
|
-
min_vertical_angle_center=min_vertical_angle_center,
|
|
1394
|
-
max_vertical_angle_center=max_vertical_angle_center,
|
|
1395
|
-
min_vertical_angle_side=min_vertical_angle_side,
|
|
1396
|
-
max_vertical_angle_side=max_vertical_angle_side,
|
|
1397
|
-
gain_center=gain_center,
|
|
1398
|
-
gain_sides=gain_sides,
|
|
1399
|
-
hp_corner_hz=hp_corner_hz,
|
|
1400
|
-
lp_corner_hz=lp_corner_hz,
|
|
1401
|
-
threshold=threshold,
|
|
1402
|
-
threshold_scale=threshold_scale,
|
|
1403
|
-
blind_time_s=blind_time_s,
|
|
1404
|
-
pulse_counter=pulse_counter,
|
|
1405
|
-
window_time_s=window_time_s,
|
|
1406
|
-
count_mode=count_mode,
|
|
1407
|
-
lens_transmission=lens_transmission,
|
|
1408
|
-
lens_segments_h=lens_segments_h,
|
|
1409
|
-
ambient_temp_c=ambient_temp_c,
|
|
1410
|
-
thermal_time_constant_s=thermal_time_constant_s,
|
|
1411
|
-
pyro_responsivity=pyro_responsivity,
|
|
1412
|
-
noise_amplitude=noise_amplitude,
|
|
1413
|
-
target_delta_t=target_delta_t,
|
|
1414
|
-
target_distance=target_distance,
|
|
1415
|
-
target_emissivity=target_emissivity,
|
|
1416
|
-
target_velocity_mps=target_velocity_mps,
|
|
1417
|
-
)
|
|
1418
|
-
|
|
1419
|
-
return PirSensor.add(
|
|
1420
|
-
path=path,
|
|
1421
|
-
config=config,
|
|
1422
|
-
world_pose=Pose.from_any(world_pose) if world_pose is not None else None,
|
|
1423
|
-
local_pose=Pose.from_any(local_pose) if local_pose is not None else None,
|
|
1424
|
-
)
|
|
1425
|
-
|
|
1426
|
-
def get_pir_sensor(self, path: str) -> PirSensor:
|
|
1427
|
-
"""
|
|
1428
|
-
Get existing PIR sensor from the scene.
|
|
1429
|
-
|
|
1430
|
-
:param path: USD path for the PIR sensor.
|
|
1431
|
-
:return: The PIR sensor instance.
|
|
1432
|
-
"""
|
|
1433
|
-
|
|
1434
|
-
return PirSensor(path)
|
|
1435
|
-
|
|
1436
|
-
def set_collision(self, path: str, mesh_approximation: MeshApproximation | None = None) -> None:
|
|
1437
|
-
"""
|
|
1438
|
-
Apply collision API to a prim.
|
|
1439
|
-
|
|
1440
|
-
:param path: USD path to the prim.
|
|
1441
|
-
:param mesh_approximation: Optional mesh approximation method for collision geometry.
|
|
1442
|
-
"""
|
|
1443
|
-
|
|
1444
|
-
set_collision(path, mesh_approximation)
|
|
1445
|
-
|
|
1446
|
-
def remove_collision(self, path: str) -> None:
|
|
1447
|
-
"""
|
|
1448
|
-
Remove collision API from a prim.
|
|
1449
|
-
|
|
1450
|
-
:param path: USD path to the prim.
|
|
1451
|
-
"""
|
|
1452
|
-
|
|
1453
|
-
remove_collision(path)
|
|
1454
|
-
|
|
1455
|
-
def has_collision(self, path: str) -> bool:
|
|
1456
|
-
"""
|
|
1457
|
-
Check if a prim has collision API applied.
|
|
1458
|
-
|
|
1459
|
-
:param path: USD path to the prim.
|
|
1460
|
-
:return: True if collision API is applied.
|
|
1461
|
-
"""
|
|
1462
|
-
|
|
1463
|
-
return has_collision(path)
|
|
1464
|
-
|
|
1465
|
-
def get_mesh_approximation(self, path: str) -> MeshApproximation | None:
|
|
1466
|
-
"""
|
|
1467
|
-
Get mesh collision approximation from a prim.
|
|
1468
|
-
|
|
1469
|
-
:param path: USD path to the prim.
|
|
1470
|
-
:return: Mesh approximation method, or None if not set.
|
|
1471
|
-
"""
|
|
1472
|
-
|
|
1473
|
-
return get_mesh_approximation(path)
|
|
1474
|
-
|
|
1475
|
-
def set_pir_material(self, path: str, emissivity: float = 0.9, temperature_c: float | None = None) -> None:
|
|
1476
|
-
"""
|
|
1477
|
-
Set PIR-specific thermal properties on a prim.
|
|
1478
|
-
|
|
1479
|
-
These properties define how the prim appears to PIR sensors:
|
|
1480
|
-
- emissivity: How well the surface emits infrared radiation (0-1)
|
|
1481
|
-
- temperature_c: Surface temperature in Celsius
|
|
1482
|
-
|
|
1483
|
-
Example:
|
|
1484
|
-
scene.set_pir_material("/World/person", emissivity=0.98, temperature_c=37.0)
|
|
1485
|
-
|
|
1486
|
-
:param path: USD path of the prim to configure.
|
|
1487
|
-
:param emissivity: Material emissivity (0-1, default 0.9).
|
|
1488
|
-
:param temperature_c: Surface temperature in Celsius (optional).
|
|
1489
|
-
"""
|
|
1490
|
-
|
|
1491
|
-
set_pir_material(path, emissivity, temperature_c)
|
|
1492
|
-
|
|
1493
|
-
def set_nonvisual_material(self, path: str, base: str, coating: str = "none", attribute: str = "none") -> int:
|
|
1494
|
-
"""
|
|
1495
|
-
Set non-visual material properties on all Material prims in a subtree.
|
|
1496
|
-
|
|
1497
|
-
These properties define how objects appear to RTX sensors (LiDAR and Radar).
|
|
1498
|
-
|
|
1499
|
-
Valid base materials:
|
|
1500
|
-
Metals: aluminum, steel, oxidized_steel, iron, oxidized_iron, silver, brass,
|
|
1501
|
-
bronze, oxidized_bronze_patina, tin
|
|
1502
|
-
Polymers: plastic, fiberglass, carbon_fiber, vinyl, plexiglass, pvc, nylon, polyester
|
|
1503
|
-
Glass: clear_glass, frosted_glass, one_way_mirror, mirror, ceramic_glass
|
|
1504
|
-
Other: asphalt, concrete, leaf_grass, dead_leaf_grass, rubber, wood, bark,
|
|
1505
|
-
cardboard, paper, fabric, skin, fur_hair, leather, marble, brick,
|
|
1506
|
-
stone, gravel, dirt, mud, water, salt_water, snow, ice, calibration_lambertion
|
|
1507
|
-
Default: none
|
|
1508
|
-
|
|
1509
|
-
Valid coatings: none, paint, clearcoat, paint_clearcoat
|
|
1510
|
-
|
|
1511
|
-
Valid attributes: none, emissive, retroreflective, single_sided, visually_transparent
|
|
1512
|
-
|
|
1513
|
-
Example:
|
|
1514
|
-
# Make a person visible to radar/lidar with skin material
|
|
1515
|
-
scene.set_nonvisual_material("/World/person", base="skin")
|
|
1516
|
-
|
|
1517
|
-
# Make a car with aluminum body and paint coating
|
|
1518
|
-
scene.set_nonvisual_material("/World/car", base="aluminum", coating="paint")
|
|
1519
|
-
|
|
1520
|
-
:param path: USD path of the root prim to configure.
|
|
1521
|
-
:param base: Base material type.
|
|
1522
|
-
:param coating: Coating type.
|
|
1523
|
-
:param attribute: Material attribute.
|
|
1524
|
-
:return: Number of Material prims modified.
|
|
1525
|
-
"""
|
|
1526
|
-
|
|
1527
|
-
return self._session.query_sim_rpc(
|
|
1528
|
-
endpoint="material/set_nonvisual",
|
|
1529
|
-
payload={"path": path, "base": base, "coating": coating, "attribute": attribute},
|
|
1530
|
-
response_type=int,
|
|
1531
|
-
)
|
|
1532
|
-
|
|
1533
|
-
def _step_physics(self, dt_us: int) -> None:
|
|
1534
|
-
"""
|
|
1535
|
-
Step physics by dt_us.
|
|
1536
|
-
|
|
1537
|
-
:param dt_us: Amount of time to step in microseconds.
|
|
1538
|
-
"""
|
|
1539
|
-
|
|
1540
|
-
if dt_us > 0:
|
|
1541
|
-
self._session.query_sim_rpc(
|
|
1542
|
-
endpoint="step",
|
|
1543
|
-
payload={"dt_us": dt_us},
|
|
1544
|
-
)
|