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
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
from antioch.session.session import Session, SessionContainer
|
|
2
|
-
from common.message import PirStatus, Pose
|
|
3
|
-
from common.session.config import PirSensorConfig
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class PirSensor(SessionContainer):
|
|
7
|
-
"""
|
|
8
|
-
PIR (Passive Infrared) sensor object for motion detection.
|
|
9
|
-
|
|
10
|
-
PIR sensors detect infrared radiation changes caused by moving warm objects.
|
|
11
|
-
The sensor uses a 3-sensor design (center, left, right) with dual elements per sensor.
|
|
12
|
-
|
|
13
|
-
Example:
|
|
14
|
-
scene = Scene()
|
|
15
|
-
pir = scene.add_pir_sensor(path="/World/pir_sensor")
|
|
16
|
-
scene.play()
|
|
17
|
-
scene.step(dt_us=100_000)
|
|
18
|
-
status = pir.get_detection_status()
|
|
19
|
-
print(f"Detected: {status.is_detected}")
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def __init__(self, path: str, config: PirSensorConfig | None = None):
|
|
23
|
-
"""
|
|
24
|
-
Initialize PIR sensor object.
|
|
25
|
-
|
|
26
|
-
:param path: USD path for the PIR sensor.
|
|
27
|
-
:param config: Optional PIR sensor config.
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
super().__init__()
|
|
31
|
-
self._config = config
|
|
32
|
-
self._session.query_sim_rpc(endpoint="pir_sensor/get", payload={"path": path})
|
|
33
|
-
self._path = path
|
|
34
|
-
|
|
35
|
-
@classmethod
|
|
36
|
-
def add(cls, path: str, config: PirSensorConfig, world_pose: Pose | None, local_pose: Pose | None) -> "PirSensor":
|
|
37
|
-
"""
|
|
38
|
-
Add PIR sensor to the scene.
|
|
39
|
-
|
|
40
|
-
:param path: USD path for the PIR sensor.
|
|
41
|
-
:param config: PIR sensor configuration.
|
|
42
|
-
:param world_pose: Optional world pose.
|
|
43
|
-
:param local_pose: Optional local pose.
|
|
44
|
-
:return: The PIR sensor instance.
|
|
45
|
-
"""
|
|
46
|
-
|
|
47
|
-
Session.get_current().query_sim_rpc(
|
|
48
|
-
endpoint="pir_sensor/add",
|
|
49
|
-
payload={"path": path, "config": config, "world_pose": world_pose, "local_pose": local_pose},
|
|
50
|
-
)
|
|
51
|
-
return cls(path, config)
|
|
52
|
-
|
|
53
|
-
def get_detection_status(self) -> PirStatus:
|
|
54
|
-
"""
|
|
55
|
-
Get current detection status.
|
|
56
|
-
|
|
57
|
-
:return: Detection status with is_detected, signal_strength, and per-sensor details.
|
|
58
|
-
"""
|
|
59
|
-
|
|
60
|
-
return PirStatus(**self._session.query_sim_rpc(endpoint="pir_sensor/get_status", payload={"path": self._path}))
|
|
61
|
-
|
|
62
|
-
def set_debug_mode(self, enabled: bool) -> None:
|
|
63
|
-
"""
|
|
64
|
-
Enable or disable debug ray visualization.
|
|
65
|
-
|
|
66
|
-
When enabled, rays are drawn each update:
|
|
67
|
-
- Green: Center sensor
|
|
68
|
-
- Blue: Left sensor
|
|
69
|
-
- Red: Right sensor
|
|
70
|
-
- Cyan points at hit locations
|
|
71
|
-
|
|
72
|
-
:param enabled: Whether to enable debug visualization.
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
self._session.query_sim_rpc(endpoint="pir_sensor/set_debug_mode", payload={"path": self._path, "enabled": enabled})
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def set_pir_material(path: str, emissivity: float = 0.9, temperature_c: float | None = None) -> None:
|
|
79
|
-
"""
|
|
80
|
-
Set PIR-specific thermal properties on a prim.
|
|
81
|
-
|
|
82
|
-
These properties define how the prim appears to PIR sensors:
|
|
83
|
-
- emissivity: How well the surface emits infrared radiation (0-1)
|
|
84
|
-
- temperature_c: Surface temperature in Celsius
|
|
85
|
-
|
|
86
|
-
Example:
|
|
87
|
-
# Make a target detectable by PIR sensors
|
|
88
|
-
set_pir_material("/World/person", emissivity=0.98, temperature_c=37.0)
|
|
89
|
-
|
|
90
|
-
:param path: USD path of the prim to configure.
|
|
91
|
-
:param emissivity: Material emissivity (0-1, default 0.9).
|
|
92
|
-
:param temperature_c: Surface temperature in Celsius (optional).
|
|
93
|
-
"""
|
|
94
|
-
|
|
95
|
-
Session.get_current().query_sim_rpc(
|
|
96
|
-
endpoint="pir_material/set",
|
|
97
|
-
payload={"path": path, "emissivity": emissivity, "temperature_c": temperature_c},
|
|
98
|
-
)
|
antioch/session/objects/radar.py
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
from antioch.session.session import Session, SessionContainer
|
|
2
|
-
from common.message import Pose, RadarScan
|
|
3
|
-
from common.session.config import RadarConfig
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Radar(SessionContainer):
|
|
7
|
-
"""
|
|
8
|
-
Radar object for time-synchronized scan data.
|
|
9
|
-
|
|
10
|
-
Example:
|
|
11
|
-
scene = Scene()
|
|
12
|
-
radar = scene.get_radar(name="my_ark/my_module/my_radar")
|
|
13
|
-
scan = radar.get_scan()
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
def __init__(self, path: str):
|
|
17
|
-
"""
|
|
18
|
-
Initialize Radar object.
|
|
19
|
-
|
|
20
|
-
:param path: USD path for the radar.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
super().__init__()
|
|
24
|
-
self._session.query_sim_rpc(endpoint="radar/get", payload={"path": path})
|
|
25
|
-
self._path = path
|
|
26
|
-
|
|
27
|
-
@classmethod
|
|
28
|
-
def add(cls, path: str, config: RadarConfig, world_pose: Pose | None, local_pose: Pose | None) -> "Radar":
|
|
29
|
-
"""
|
|
30
|
-
Add radar to the scene.
|
|
31
|
-
|
|
32
|
-
:param path: USD path for the radar.
|
|
33
|
-
:param config: Radar configuration.
|
|
34
|
-
:param world_pose: Optional world pose.
|
|
35
|
-
:param local_pose: Optional local pose.
|
|
36
|
-
:return: The radar instance.
|
|
37
|
-
"""
|
|
38
|
-
|
|
39
|
-
Session.get_current().query_sim_rpc(
|
|
40
|
-
endpoint="radar/add",
|
|
41
|
-
payload={"path": path, "config": config, "world_pose": world_pose, "local_pose": local_pose},
|
|
42
|
-
)
|
|
43
|
-
return cls(path)
|
|
44
|
-
|
|
45
|
-
def get_scan(self) -> RadarScan | None:
|
|
46
|
-
"""
|
|
47
|
-
Get radar scan data.
|
|
48
|
-
|
|
49
|
-
:return: Radar scan with detections, or None if scan data is not ready.
|
|
50
|
-
"""
|
|
51
|
-
|
|
52
|
-
scan = self._session.query_sim_rpc(endpoint="radar/get_scan", payload={"path": self._path})
|
|
53
|
-
return RadarScan(**scan) if scan else None
|
|
54
|
-
|
|
55
|
-
def set_debug_mode(self, enabled: bool) -> None:
|
|
56
|
-
"""
|
|
57
|
-
Enable or disable debug visualization.
|
|
58
|
-
|
|
59
|
-
:param enabled: Whether to enable debug visualization.
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
self._session.query_sim_rpc(endpoint="radar/set_debug_mode", payload={"path": self._path, "enabled": enabled})
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
from antioch.session.session import Session, SessionContainer
|
|
2
|
-
from common.message import Pose, Twist, Vector3
|
|
3
|
-
from common.session.config import RigidBodyConfig
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class RigidBody(SessionContainer):
|
|
7
|
-
"""
|
|
8
|
-
Ergonomic wrapper for rigid body operations.
|
|
9
|
-
|
|
10
|
-
Rigid bodies should be added using scene.add_rigid_body() or retrieved using scene.get_rigid_body().
|
|
11
|
-
|
|
12
|
-
Example:
|
|
13
|
-
scene = Scene()
|
|
14
|
-
|
|
15
|
-
# Add rigid body
|
|
16
|
-
body = scene.add_rigid_body(
|
|
17
|
-
path="/World/cube",
|
|
18
|
-
mass=1.0,
|
|
19
|
-
linear_velocity=[1.0, 0.0, 0.0]
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
# Set velocity with tuples/lists
|
|
23
|
-
body.set_velocity(
|
|
24
|
-
linear=(1.0, 0.0, 0.0),
|
|
25
|
-
angular=[0.0, 0.0, 1.0]
|
|
26
|
-
)
|
|
27
|
-
pose = body.get_world_pose()
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
def __init__(self, path: str):
|
|
31
|
-
"""
|
|
32
|
-
Initialize rigid body by resolving path and validating existence.
|
|
33
|
-
|
|
34
|
-
:param path: USD path for the rigid body.
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
super().__init__()
|
|
38
|
-
self._session.query_sim_rpc(endpoint="rigid_body/get", payload={"path": path})
|
|
39
|
-
self._path = path
|
|
40
|
-
|
|
41
|
-
@classmethod
|
|
42
|
-
def add(
|
|
43
|
-
cls,
|
|
44
|
-
path: str,
|
|
45
|
-
config: RigidBodyConfig,
|
|
46
|
-
world_pose: Pose | None,
|
|
47
|
-
local_pose: Pose | None,
|
|
48
|
-
scale: Vector3 | None,
|
|
49
|
-
) -> "RigidBody":
|
|
50
|
-
"""
|
|
51
|
-
Add a rigid body to the scene.
|
|
52
|
-
|
|
53
|
-
:param path: USD path for the rigid body.
|
|
54
|
-
:param config: Rigid body configuration.
|
|
55
|
-
:param world_pose: Optional world pose.
|
|
56
|
-
:param local_pose: Optional local pose.
|
|
57
|
-
:param scale: Optional scale.
|
|
58
|
-
:return: The rigid body instance.
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
Session.get_current().query_sim_rpc(
|
|
62
|
-
endpoint="rigid_body/add",
|
|
63
|
-
payload={"path": path, "config": config, "world_pose": world_pose, "local_pose": local_pose, "scale": scale},
|
|
64
|
-
)
|
|
65
|
-
return cls(path)
|
|
66
|
-
|
|
67
|
-
def get_velocity(self) -> Twist:
|
|
68
|
-
"""
|
|
69
|
-
Get the velocity of the rigid body.
|
|
70
|
-
|
|
71
|
-
:return: Linear and angular velocities.
|
|
72
|
-
"""
|
|
73
|
-
|
|
74
|
-
return self._session.query_sim_rpc(endpoint="rigid_body/get_velocity", payload={"path": self._path}, response_type=Twist)
|
|
75
|
-
|
|
76
|
-
def set_velocity(
|
|
77
|
-
self,
|
|
78
|
-
linear: Vector3 | list[float] | tuple[float, float, float],
|
|
79
|
-
angular: Vector3 | list[float] | tuple[float, float, float],
|
|
80
|
-
) -> None:
|
|
81
|
-
"""
|
|
82
|
-
Set the velocity of the rigid body.
|
|
83
|
-
|
|
84
|
-
:param linear: Linear velocity as Vector3 (or list/tuple of 3 floats).
|
|
85
|
-
:param angular: Angular velocity as Vector3 (or list/tuple of 3 floats).
|
|
86
|
-
"""
|
|
87
|
-
|
|
88
|
-
twist = Twist(linear=Vector3.from_any(linear), angular=Vector3.from_any(angular))
|
|
89
|
-
self._session.query_sim_rpc(endpoint="rigid_body/set_velocity", payload={"path": self._path, "twist": twist})
|
|
90
|
-
|
|
91
|
-
def apply_force(
|
|
92
|
-
self,
|
|
93
|
-
force: Vector3 | list[float] | tuple[float, float, float],
|
|
94
|
-
is_global: bool = True,
|
|
95
|
-
) -> None:
|
|
96
|
-
"""
|
|
97
|
-
Apply force to the rigid body.
|
|
98
|
-
|
|
99
|
-
:param force: Force vector as Vector3 (or list/tuple of 3 floats).
|
|
100
|
-
:param is_global: Whether force is in global frame.
|
|
101
|
-
"""
|
|
102
|
-
|
|
103
|
-
self._session.query_sim_rpc(
|
|
104
|
-
endpoint="rigid_body/apply_force",
|
|
105
|
-
payload={"path": self._path, "force": Vector3.from_any(force), "is_global": is_global},
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
def get_mass(self) -> float:
|
|
109
|
-
"""
|
|
110
|
-
Get the mass of the rigid body.
|
|
111
|
-
|
|
112
|
-
:return: Mass in kg.
|
|
113
|
-
"""
|
|
114
|
-
|
|
115
|
-
return self._session.query_sim_rpc(endpoint="rigid_body/get_mass", payload={"path": self._path}, response_type=float)
|
|
116
|
-
|
|
117
|
-
def get_inertia(self) -> list[float]:
|
|
118
|
-
"""
|
|
119
|
-
Get the inertia tensor of the rigid body.
|
|
120
|
-
|
|
121
|
-
:return: Inertia tensor as 9 values (3x3 matrix flattened).
|
|
122
|
-
"""
|
|
123
|
-
|
|
124
|
-
return self._session.query_sim_rpc(endpoint="rigid_body/get_inertia", payload={"path": self._path}, response_type=list)
|
|
125
|
-
|
|
126
|
-
def get_center_of_mass(self) -> Pose:
|
|
127
|
-
"""
|
|
128
|
-
Get the center of mass position and orientation.
|
|
129
|
-
|
|
130
|
-
:return: Center of mass as Pose.
|
|
131
|
-
"""
|
|
132
|
-
|
|
133
|
-
return self._session.query_sim_rpc(endpoint="rigid_body/get_center_of_mass", payload={"path": self._path}, response_type=Pose)
|
|
134
|
-
|
|
135
|
-
def enable_gravity(self) -> None:
|
|
136
|
-
"""
|
|
137
|
-
Enable gravity on the rigid body.
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
self._session.query_sim_rpc(endpoint="rigid_body/enable_gravity", payload={"path": self._path})
|
|
141
|
-
|
|
142
|
-
def disable_gravity(self) -> None:
|
|
143
|
-
"""
|
|
144
|
-
Disable gravity on the rigid body.
|
|
145
|
-
"""
|
|
146
|
-
|
|
147
|
-
self._session.query_sim_rpc(endpoint="rigid_body/disable_gravity", payload={"path": self._path})
|
|
148
|
-
|
|
149
|
-
def enable_physics(self) -> None:
|
|
150
|
-
"""
|
|
151
|
-
Enable rigid body physics (make body dynamic).
|
|
152
|
-
"""
|
|
153
|
-
|
|
154
|
-
self._session.query_sim_rpc(endpoint="rigid_body/enable_physics", payload={"path": self._path})
|
|
155
|
-
|
|
156
|
-
def disable_physics(self) -> None:
|
|
157
|
-
"""
|
|
158
|
-
Disable rigid body physics (make body kinematic).
|
|
159
|
-
"""
|
|
160
|
-
|
|
161
|
-
self._session.query_sim_rpc(endpoint="rigid_body/disable_physics", payload={"path": self._path})
|
|
162
|
-
|
|
163
|
-
def get_world_pose(self) -> Pose:
|
|
164
|
-
"""
|
|
165
|
-
Get the world pose of the rigid body.
|
|
166
|
-
|
|
167
|
-
:return: World pose.
|
|
168
|
-
"""
|
|
169
|
-
|
|
170
|
-
return self._session.query_sim_rpc(endpoint="rigid_body/get_world_pose", payload={"path": self._path}, response_type=Pose)
|
|
171
|
-
|
|
172
|
-
def get_local_pose(self) -> Pose:
|
|
173
|
-
"""
|
|
174
|
-
Get the local pose of the rigid body.
|
|
175
|
-
|
|
176
|
-
:return: Local pose.
|
|
177
|
-
"""
|
|
178
|
-
|
|
179
|
-
return self._session.query_sim_rpc(endpoint="rigid_body/get_local_pose", payload={"path": self._path}, response_type=Pose)
|
|
180
|
-
|
|
181
|
-
def set_world_pose(self, pose: Pose | dict) -> None:
|
|
182
|
-
"""
|
|
183
|
-
Set the world pose of the rigid body.
|
|
184
|
-
|
|
185
|
-
:param pose: World pose as Pose (or dict with position/orientation lists).
|
|
186
|
-
"""
|
|
187
|
-
|
|
188
|
-
self._session.query_sim_rpc(endpoint="rigid_body/set_world_pose", payload={"path": self._path, "pose": pose})
|
|
189
|
-
|
|
190
|
-
def set_local_pose(self, pose: Pose | dict) -> None:
|
|
191
|
-
"""
|
|
192
|
-
Set the local pose of the rigid body.
|
|
193
|
-
|
|
194
|
-
:param pose: Local pose as Pose (or dict with position/orientation lists).
|
|
195
|
-
"""
|
|
196
|
-
|
|
197
|
-
self._session.query_sim_rpc(endpoint="rigid_body/set_local_pose", payload={"path": self._path, "pose": pose})
|
antioch/session/objects/xform.py
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
from antioch.session.session import Session, SessionContainer
|
|
2
|
-
from common.message import Pose, Vector3
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class XForm(SessionContainer):
|
|
6
|
-
"""
|
|
7
|
-
Ergonomic wrapper for xform operations.
|
|
8
|
-
|
|
9
|
-
XForms should be added using scene.add_xform() or retrieved using scene.get_xform().
|
|
10
|
-
|
|
11
|
-
Example:
|
|
12
|
-
scene = Scene()
|
|
13
|
-
|
|
14
|
-
# Add xform
|
|
15
|
-
xform = scene.add_xform(
|
|
16
|
-
path="/World/container",
|
|
17
|
-
world_pose={"position": [1.0, 2.0, 3.0], "orientation": [1.0, 0.0, 0.0, 0.0]},
|
|
18
|
-
scale=[2.0, 2.0, 2.0]
|
|
19
|
-
)
|
|
20
|
-
|
|
21
|
-
pose = xform.get_world_pose()
|
|
22
|
-
"""
|
|
23
|
-
|
|
24
|
-
def __init__(self, path: str):
|
|
25
|
-
"""
|
|
26
|
-
Initialize xform by resolving path and validating existence.
|
|
27
|
-
|
|
28
|
-
:param path: USD path for the xform.
|
|
29
|
-
"""
|
|
30
|
-
|
|
31
|
-
super().__init__()
|
|
32
|
-
self._session.query_sim_rpc(endpoint="xform/get", payload={"path": path})
|
|
33
|
-
self._path = path
|
|
34
|
-
|
|
35
|
-
@classmethod
|
|
36
|
-
def add(
|
|
37
|
-
cls,
|
|
38
|
-
path: str,
|
|
39
|
-
world_pose: Pose | None,
|
|
40
|
-
local_pose: Pose | None,
|
|
41
|
-
scale: Vector3 | None,
|
|
42
|
-
) -> "XForm":
|
|
43
|
-
"""
|
|
44
|
-
Add an xform to the scene.
|
|
45
|
-
|
|
46
|
-
:param path: USD path for the xform.
|
|
47
|
-
:param world_pose: Optional world pose.
|
|
48
|
-
:param local_pose: Optional local pose.
|
|
49
|
-
:param scale: Optional scale.
|
|
50
|
-
:return: The xform instance.
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
Session.get_current().query_sim_rpc(
|
|
54
|
-
endpoint="xform/add",
|
|
55
|
-
payload={"path": path, "world_pose": world_pose, "local_pose": local_pose, "scale": scale},
|
|
56
|
-
)
|
|
57
|
-
return cls(path)
|
|
58
|
-
|
|
59
|
-
def get_world_pose(self) -> Pose:
|
|
60
|
-
"""
|
|
61
|
-
Get the world pose of the xform.
|
|
62
|
-
|
|
63
|
-
:return: World pose.
|
|
64
|
-
"""
|
|
65
|
-
|
|
66
|
-
return self._session.query_sim_rpc(
|
|
67
|
-
endpoint="xform/get_world_pose",
|
|
68
|
-
payload={"path": self._path},
|
|
69
|
-
response_type=Pose,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
def get_local_pose(self) -> Pose:
|
|
73
|
-
"""
|
|
74
|
-
Get the local pose of the xform.
|
|
75
|
-
|
|
76
|
-
:return: Local pose.
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
return self._session.query_sim_rpc(
|
|
80
|
-
endpoint="xform/get_local_pose",
|
|
81
|
-
payload={"path": self._path},
|
|
82
|
-
response_type=Pose,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
def set_world_pose(self, pose: Pose | dict) -> None:
|
|
86
|
-
"""
|
|
87
|
-
Set the world pose of the xform.
|
|
88
|
-
|
|
89
|
-
:param pose: World pose as Pose (or dict with position/orientation lists).
|
|
90
|
-
"""
|
|
91
|
-
|
|
92
|
-
self._session.query_sim_rpc(
|
|
93
|
-
endpoint="xform/set_world_pose",
|
|
94
|
-
payload={"path": self._path, "pose": pose},
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
def set_local_pose(self, pose: Pose | dict) -> None:
|
|
98
|
-
"""
|
|
99
|
-
Set the local pose of the xform.
|
|
100
|
-
|
|
101
|
-
:param pose: Local pose as Pose (or dict with position/orientation lists).
|
|
102
|
-
"""
|
|
103
|
-
|
|
104
|
-
self._session.query_sim_rpc(
|
|
105
|
-
endpoint="xform/set_local_pose",
|
|
106
|
-
payload={"path": self._path, "pose": pose},
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
def set_visibility(self, visible: bool) -> None:
|
|
110
|
-
"""
|
|
111
|
-
Set the visibility of the xform.
|
|
112
|
-
|
|
113
|
-
:param visible: True to make visible, False to hide.
|
|
114
|
-
"""
|
|
115
|
-
|
|
116
|
-
self._session.query_sim_rpc(
|
|
117
|
-
endpoint="xform/set_visibility",
|
|
118
|
-
payload={"path": self._path, "visible": visible},
|
|
119
|
-
)
|
antioch/session/record.py
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
from collections import deque
|
|
2
|
-
from threading import Lock
|
|
3
|
-
from typing import TypeVar, overload
|
|
4
|
-
|
|
5
|
-
from antioch.module.node import TOKEN_OUTPUT_PATH
|
|
6
|
-
from antioch.module.token import Token, TokenType
|
|
7
|
-
from antioch.session.error import SessionRecordError
|
|
8
|
-
from common.ark.ark import Ark as ArkDefinition
|
|
9
|
-
from common.message import Message
|
|
10
|
-
from common.utils.comms import CommsSession
|
|
11
|
-
|
|
12
|
-
T = TypeVar("T", bound=Message)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class NodeOutputRecorder:
|
|
16
|
-
"""
|
|
17
|
-
Records node outputs by subscribing to token stream with filtering and buffering.
|
|
18
|
-
|
|
19
|
-
Maintains a circular buffer of recent tokens using async callback for efficient updates.
|
|
20
|
-
Validates that module/node/output exists in the Ark definition.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(
|
|
24
|
-
self,
|
|
25
|
-
comms: CommsSession,
|
|
26
|
-
ark_def: ArkDefinition,
|
|
27
|
-
module_name: str,
|
|
28
|
-
node_name: str,
|
|
29
|
-
output_name: str,
|
|
30
|
-
token_type: TokenType | None = TokenType.DATA,
|
|
31
|
-
last_n: int = 10,
|
|
32
|
-
):
|
|
33
|
-
"""
|
|
34
|
-
Initialize node output recorder with validation and subscription.
|
|
35
|
-
|
|
36
|
-
:param comms: Communication session for subscribing to token stream.
|
|
37
|
-
:param ark_def: Ark definition used to validate module/node/output exists.
|
|
38
|
-
:param module_name: Name of module containing the node.
|
|
39
|
-
:param node_name: Name of node containing the output.
|
|
40
|
-
:param output_name: Name of output to record tokens from.
|
|
41
|
-
:param token_type: Token type to filter (None records all types).
|
|
42
|
-
:param last_n: Maximum number of recent tokens to buffer.
|
|
43
|
-
:raises SessionRecordError: If module, node, or output doesn't exist in Ark.
|
|
44
|
-
"""
|
|
45
|
-
|
|
46
|
-
# Validate module exists
|
|
47
|
-
module = next((m for m in ark_def.modules if m.name == module_name), None)
|
|
48
|
-
if module is None:
|
|
49
|
-
raise SessionRecordError(f"Module '{module_name}' not found in Ark")
|
|
50
|
-
|
|
51
|
-
# Validate node exists
|
|
52
|
-
node = module.nodes.get(node_name)
|
|
53
|
-
if node is None:
|
|
54
|
-
raise SessionRecordError(f"Node '{node_name}' not found in module '{module_name}'")
|
|
55
|
-
|
|
56
|
-
# Validate output exists
|
|
57
|
-
output = node.outputs.get(output_name)
|
|
58
|
-
if output is None:
|
|
59
|
-
raise SessionRecordError(f"Output '{output_name}' not found in node '{module_name}/{node_name}'")
|
|
60
|
-
|
|
61
|
-
self._token_type = token_type
|
|
62
|
-
self._buffer: deque[Token] = deque(maxlen=last_n)
|
|
63
|
-
self._buffer_lock = Lock()
|
|
64
|
-
self._subscriber = comms.declare_callback_subscriber(TOKEN_OUTPUT_PATH.format(path=output.path), self._on_token)
|
|
65
|
-
|
|
66
|
-
@overload
|
|
67
|
-
def next(self, message_cls: type[T]) -> T | None: ...
|
|
68
|
-
|
|
69
|
-
@overload
|
|
70
|
-
def next(self, message_cls: None = None) -> dict | None: ...
|
|
71
|
-
|
|
72
|
-
def next(self, message_cls: type[T] | None = None) -> T | dict | None:
|
|
73
|
-
"""
|
|
74
|
-
Return next deserialized payload in order and remove from buffer.
|
|
75
|
-
|
|
76
|
-
:param message_cls: Message class to deserialize payload (None for generic JSON dict).
|
|
77
|
-
:return: Deserialized payload, or None if buffer empty.
|
|
78
|
-
"""
|
|
79
|
-
|
|
80
|
-
token = self.next_token()
|
|
81
|
-
if token is None:
|
|
82
|
-
return None
|
|
83
|
-
return self._deserialize_payload(token, message_cls)
|
|
84
|
-
|
|
85
|
-
@overload
|
|
86
|
-
def latest(self, message_cls: type[T]) -> T | None: ...
|
|
87
|
-
|
|
88
|
-
@overload
|
|
89
|
-
def latest(self, message_cls: None = None) -> dict | None: ...
|
|
90
|
-
|
|
91
|
-
def latest(self, message_cls: type[T] | None = None) -> T | dict | None:
|
|
92
|
-
"""
|
|
93
|
-
Return latest deserialized payload and clear entire buffer.
|
|
94
|
-
|
|
95
|
-
:param message_cls: Message class to deserialize payload (None for generic JSON dict).
|
|
96
|
-
:return: Deserialized payload, or None if buffer empty.
|
|
97
|
-
"""
|
|
98
|
-
|
|
99
|
-
token = self.latest_token()
|
|
100
|
-
if token is None:
|
|
101
|
-
return None
|
|
102
|
-
return self._deserialize_payload(token, message_cls)
|
|
103
|
-
|
|
104
|
-
def next_token(self) -> Token | None:
|
|
105
|
-
"""
|
|
106
|
-
Return next token in order and remove from buffer.
|
|
107
|
-
|
|
108
|
-
:return: Token, or None if buffer empty.
|
|
109
|
-
"""
|
|
110
|
-
|
|
111
|
-
with self._buffer_lock:
|
|
112
|
-
if not self._buffer:
|
|
113
|
-
return None
|
|
114
|
-
return self._buffer.popleft()
|
|
115
|
-
|
|
116
|
-
def latest_token(self) -> Token | None:
|
|
117
|
-
"""
|
|
118
|
-
Return latest buffered token and clear entire buffer.
|
|
119
|
-
|
|
120
|
-
:return: Token, or None if buffer empty.
|
|
121
|
-
"""
|
|
122
|
-
|
|
123
|
-
with self._buffer_lock:
|
|
124
|
-
if not self._buffer:
|
|
125
|
-
return None
|
|
126
|
-
token = self._buffer[-1]
|
|
127
|
-
self._buffer.clear()
|
|
128
|
-
return token
|
|
129
|
-
|
|
130
|
-
def _on_token(self, sample) -> None:
|
|
131
|
-
"""
|
|
132
|
-
Callback invoked when token arrives, filters by type and adds to buffer.
|
|
133
|
-
|
|
134
|
-
:param sample: Zenoh sample containing token payload.
|
|
135
|
-
"""
|
|
136
|
-
|
|
137
|
-
token = Token.unpack(sample.payload.to_bytes())
|
|
138
|
-
if self._token_type is not None and token.status != self._token_type:
|
|
139
|
-
return
|
|
140
|
-
|
|
141
|
-
with self._buffer_lock:
|
|
142
|
-
self._buffer.append(token)
|
|
143
|
-
|
|
144
|
-
def _deserialize_payload(self, token: Token, message_cls: type[T] | None) -> T | dict | None:
|
|
145
|
-
"""
|
|
146
|
-
Deserialize token payload as specific message type or generic JSON dict.
|
|
147
|
-
|
|
148
|
-
:param token: Token containing payload to deserialize.
|
|
149
|
-
:param message_cls: Message class to deserialize as (None for generic JSON).
|
|
150
|
-
:return: Deserialized payload.
|
|
151
|
-
"""
|
|
152
|
-
|
|
153
|
-
if token.payload is None:
|
|
154
|
-
return None
|
|
155
|
-
elif message_cls is None:
|
|
156
|
-
return Message.extract_data_as_json(token.payload)
|
|
157
|
-
else:
|
|
158
|
-
return message_cls.unpack(token.payload)
|