antioch-py 1.9.7__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 +0 -0
- antioch/message.py +87 -0
- antioch/module/__init__.py +53 -0
- antioch/module/clock.py +62 -0
- antioch/module/execution.py +278 -0
- antioch/module/input.py +127 -0
- antioch/module/module.py +218 -0
- antioch/module/node.py +357 -0
- antioch/module/token.py +42 -0
- antioch/session/__init__.py +150 -0
- antioch/session/ark.py +504 -0
- antioch/session/asset.py +65 -0
- antioch/session/error.py +80 -0
- antioch/session/record.py +158 -0
- antioch/session/scene.py +1500 -0
- antioch/session/session.py +220 -0
- antioch/session/task.py +323 -0
- antioch/session/views/__init__.py +40 -0
- antioch/session/views/animation.py +189 -0
- antioch/session/views/articulation.py +245 -0
- antioch/session/views/basis_curve.py +186 -0
- antioch/session/views/camera.py +92 -0
- antioch/session/views/collision.py +75 -0
- antioch/session/views/geometry.py +74 -0
- antioch/session/views/ground_plane.py +63 -0
- antioch/session/views/imu.py +73 -0
- antioch/session/views/joint.py +64 -0
- antioch/session/views/light.py +175 -0
- antioch/session/views/pir_sensor.py +140 -0
- antioch/session/views/radar.py +73 -0
- antioch/session/views/rigid_body.py +282 -0
- antioch/session/views/xform.py +119 -0
- antioch_py-1.9.7.dist-info/METADATA +24 -0
- antioch_py-1.9.7.dist-info/RECORD +99 -0
- antioch_py-1.9.7.dist-info/WHEEL +5 -0
- antioch_py-1.9.7.dist-info/entry_points.txt +2 -0
- antioch_py-1.9.7.dist-info/top_level.txt +2 -0
- common/__init__.py +0 -0
- common/ark/__init__.py +60 -0
- common/ark/ark.py +128 -0
- common/ark/hardware.py +121 -0
- common/ark/kinematics.py +31 -0
- common/ark/module.py +85 -0
- common/ark/node.py +94 -0
- common/ark/scheduler.py +439 -0
- common/ark/sim.py +33 -0
- common/assets/__init__.py +3 -0
- common/constants.py +47 -0
- common/core/__init__.py +52 -0
- common/core/agent.py +296 -0
- common/core/auth.py +305 -0
- common/core/registry.py +331 -0
- common/core/task.py +36 -0
- common/message/__init__.py +59 -0
- common/message/annotation.py +89 -0
- common/message/array.py +500 -0
- common/message/base.py +517 -0
- common/message/camera.py +91 -0
- common/message/color.py +139 -0
- common/message/frame.py +50 -0
- common/message/image.py +171 -0
- common/message/imu.py +14 -0
- common/message/joint.py +47 -0
- common/message/log.py +31 -0
- common/message/pir.py +15 -0
- common/message/point.py +109 -0
- common/message/point_cloud.py +63 -0
- common/message/pose.py +148 -0
- common/message/quaternion.py +273 -0
- common/message/radar.py +58 -0
- common/message/types.py +37 -0
- common/message/vector.py +786 -0
- common/rome/__init__.py +9 -0
- common/rome/client.py +430 -0
- common/rome/error.py +16 -0
- common/session/__init__.py +54 -0
- common/session/environment.py +31 -0
- common/session/sim.py +240 -0
- common/session/views/__init__.py +263 -0
- common/session/views/animation.py +73 -0
- common/session/views/articulation.py +184 -0
- common/session/views/basis_curve.py +102 -0
- common/session/views/camera.py +147 -0
- common/session/views/collision.py +59 -0
- common/session/views/geometry.py +102 -0
- common/session/views/ground_plane.py +41 -0
- common/session/views/imu.py +66 -0
- common/session/views/joint.py +81 -0
- common/session/views/light.py +96 -0
- common/session/views/pir_sensor.py +104 -0
- common/session/views/radar.py +82 -0
- common/session/views/rigid_body.py +236 -0
- common/session/views/viewport.py +21 -0
- common/session/views/xform.py +39 -0
- common/utils/__init__.py +4 -0
- common/utils/comms.py +571 -0
- common/utils/logger.py +123 -0
- common/utils/time.py +42 -0
- common/utils/usd.py +12 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
from typing import Literal, overload
|
|
2
|
+
|
|
3
|
+
from antioch.session.session import Session, SessionContainer
|
|
4
|
+
from common.message import Vector3
|
|
5
|
+
from common.session.views.animation import (
|
|
6
|
+
AddAnimationFromBasisCurve,
|
|
7
|
+
AddAnimationFromWaypoints,
|
|
8
|
+
RemoveAnimation,
|
|
9
|
+
UpdateAnimationBasisCurve,
|
|
10
|
+
UpdateAnimationWaypoints,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Animation(SessionContainer):
|
|
15
|
+
"""
|
|
16
|
+
Ergonomic wrapper for animation operations.
|
|
17
|
+
|
|
18
|
+
Animations should be added using scene.add_animation() or retrieved using scene.get_animation().
|
|
19
|
+
Animations wrap around an existing skeleton UsdSkel.Root and provide a way to play and control the animation.
|
|
20
|
+
|
|
21
|
+
Example:
|
|
22
|
+
scene = Scene()
|
|
23
|
+
|
|
24
|
+
# Add xform
|
|
25
|
+
animation = scene.add_animation(
|
|
26
|
+
path="/World/skeleton",
|
|
27
|
+
waypoints=[Vector3(1.0, 0.0, 0.0), Vector3(0.0, 1.0, 0.0), Vector3(0.0, 0.0, 1.0)],
|
|
28
|
+
loop=True,
|
|
29
|
+
)
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, path: str):
|
|
33
|
+
"""
|
|
34
|
+
Initialize animation by resolving path and validating existence.
|
|
35
|
+
|
|
36
|
+
:param path: USD path for the animation.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
super().__init__()
|
|
40
|
+
self._path = path
|
|
41
|
+
|
|
42
|
+
@overload
|
|
43
|
+
@classmethod
|
|
44
|
+
def add(
|
|
45
|
+
cls,
|
|
46
|
+
path: str,
|
|
47
|
+
*,
|
|
48
|
+
waypoints: list[Vector3],
|
|
49
|
+
loop: bool = True,
|
|
50
|
+
) -> "Animation": ...
|
|
51
|
+
|
|
52
|
+
@overload
|
|
53
|
+
@classmethod
|
|
54
|
+
def add(
|
|
55
|
+
cls,
|
|
56
|
+
path: str,
|
|
57
|
+
*,
|
|
58
|
+
basis_curve: str,
|
|
59
|
+
samples_per_segment: int = 10,
|
|
60
|
+
sort_by: Literal["X", "Y", "Z"] | None = None,
|
|
61
|
+
ascending: bool = True,
|
|
62
|
+
) -> "Animation": ...
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def add(
|
|
66
|
+
cls,
|
|
67
|
+
path: str,
|
|
68
|
+
*,
|
|
69
|
+
waypoints: list[Vector3] | None = None,
|
|
70
|
+
basis_curve: str | None = None,
|
|
71
|
+
samples_per_segment: int = 10,
|
|
72
|
+
sort_by: Literal["X", "Y", "Z"] | None = None,
|
|
73
|
+
ascending: bool = True,
|
|
74
|
+
loop: bool = True,
|
|
75
|
+
) -> "Animation":
|
|
76
|
+
"""
|
|
77
|
+
Add an animation to the scene.
|
|
78
|
+
|
|
79
|
+
:param path: USD path for the animation.
|
|
80
|
+
:param waypoints: List of waypoints.
|
|
81
|
+
:param basis_curve: Path to the basis curve to use for the animation.
|
|
82
|
+
:param samples_per_segment: The number of samples per segment to use from the basis curve.
|
|
83
|
+
:param sort_by: The axis to sort the points by.
|
|
84
|
+
:param ascending: Whether to sort the points in ascending order.
|
|
85
|
+
:param loop: Whether to loop the animation (waypoints only).
|
|
86
|
+
:return: The animation instance.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if waypoints is not None:
|
|
90
|
+
Session.get_current().query_sim_rpc(
|
|
91
|
+
endpoint="add_animation_from_waypoints",
|
|
92
|
+
payload=AddAnimationFromWaypoints(
|
|
93
|
+
path=path,
|
|
94
|
+
waypoints=waypoints,
|
|
95
|
+
loop=loop,
|
|
96
|
+
),
|
|
97
|
+
)
|
|
98
|
+
elif basis_curve is not None:
|
|
99
|
+
Session.get_current().query_sim_rpc(
|
|
100
|
+
endpoint="add_animation_from_basis_curve",
|
|
101
|
+
payload=AddAnimationFromBasisCurve(
|
|
102
|
+
path=path,
|
|
103
|
+
basis_curve=basis_curve,
|
|
104
|
+
samples_per_segment=samples_per_segment,
|
|
105
|
+
sort_by=sort_by,
|
|
106
|
+
ascending=ascending,
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
else:
|
|
110
|
+
raise ValueError("Must provide either waypoints or basis_curve")
|
|
111
|
+
|
|
112
|
+
return cls(path)
|
|
113
|
+
|
|
114
|
+
@overload
|
|
115
|
+
def update(
|
|
116
|
+
self,
|
|
117
|
+
*,
|
|
118
|
+
waypoints: list[Vector3],
|
|
119
|
+
loop: bool = True,
|
|
120
|
+
) -> "Animation": ...
|
|
121
|
+
|
|
122
|
+
@overload
|
|
123
|
+
def update(
|
|
124
|
+
self,
|
|
125
|
+
*,
|
|
126
|
+
basis_curve: str,
|
|
127
|
+
samples_per_segment: int = 10,
|
|
128
|
+
sort_by: Literal["X", "Y", "Z"] | None = None,
|
|
129
|
+
ascending: bool = True,
|
|
130
|
+
) -> "Animation": ...
|
|
131
|
+
|
|
132
|
+
def update(
|
|
133
|
+
self,
|
|
134
|
+
*,
|
|
135
|
+
waypoints: list[Vector3] | None = None,
|
|
136
|
+
basis_curve: str | None = None,
|
|
137
|
+
samples_per_segment: int = 10,
|
|
138
|
+
sort_by: Literal["X", "Y", "Z"] | None = None,
|
|
139
|
+
ascending: bool = True,
|
|
140
|
+
loop: bool = True,
|
|
141
|
+
) -> "Animation":
|
|
142
|
+
"""
|
|
143
|
+
Update the animation.
|
|
144
|
+
|
|
145
|
+
:param waypoints: List of waypoints.
|
|
146
|
+
:param basis_curve: Path to the basis curve to use for the animation.
|
|
147
|
+
:param samples_per_segment: The number of samples per segment to use from the basis curve.
|
|
148
|
+
:param sort_by: The axis to sort the points by.
|
|
149
|
+
:param ascending: Whether to sort the points in ascending order.
|
|
150
|
+
:param loop: Whether to loop the animation (waypoints only).
|
|
151
|
+
:raises ValueError: If both waypoints and basis curve are provided.
|
|
152
|
+
:return: The animation instance.
|
|
153
|
+
"""
|
|
154
|
+
if waypoints is not None and basis_curve is not None:
|
|
155
|
+
raise ValueError("Must provide either waypoints or basis_curve")
|
|
156
|
+
|
|
157
|
+
if waypoints is not None:
|
|
158
|
+
Session.get_current().query_sim_rpc(
|
|
159
|
+
endpoint="update_animation_waypoints",
|
|
160
|
+
payload=UpdateAnimationWaypoints(
|
|
161
|
+
path=self._path,
|
|
162
|
+
waypoints=waypoints,
|
|
163
|
+
loop=loop,
|
|
164
|
+
),
|
|
165
|
+
)
|
|
166
|
+
elif basis_curve is not None:
|
|
167
|
+
Session.get_current().query_sim_rpc(
|
|
168
|
+
endpoint="update_animation_basis_curve",
|
|
169
|
+
payload=UpdateAnimationBasisCurve(
|
|
170
|
+
path=self._path,
|
|
171
|
+
basis_curve=basis_curve,
|
|
172
|
+
samples_per_segment=samples_per_segment,
|
|
173
|
+
sort_by=sort_by,
|
|
174
|
+
ascending=ascending,
|
|
175
|
+
),
|
|
176
|
+
)
|
|
177
|
+
else:
|
|
178
|
+
raise ValueError("Must provide either waypoints or basis_curve")
|
|
179
|
+
return self
|
|
180
|
+
|
|
181
|
+
def remove(self) -> None:
|
|
182
|
+
"""
|
|
183
|
+
Remove the animation from the scene (deletes the character).
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
self._session.query_sim_rpc(
|
|
187
|
+
endpoint="remove_animation",
|
|
188
|
+
payload=RemoveAnimation(path=self._path),
|
|
189
|
+
)
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
from antioch.session.session import Session, SessionContainer
|
|
2
|
+
from common.message import JointState, JointTarget, Pose, Vector3
|
|
3
|
+
from common.session.sim import GetLocalPose, GetWorldPose, SetLocalPose, SetWorldPose
|
|
4
|
+
from common.session.views.articulation import (
|
|
5
|
+
AddArticulation,
|
|
6
|
+
ArticulationConfig,
|
|
7
|
+
ArticulationJointConfig,
|
|
8
|
+
ArticulationJointConfigs,
|
|
9
|
+
ArticulationJointStates,
|
|
10
|
+
ArticulationJointTargets,
|
|
11
|
+
GetArticulation,
|
|
12
|
+
GetArticulationJointConfigs,
|
|
13
|
+
GetArticulationJointStates,
|
|
14
|
+
GetArticulationJointTargets,
|
|
15
|
+
GetArticulationResponse,
|
|
16
|
+
SetArticulationJointConfigs,
|
|
17
|
+
SetArticulationJointStates,
|
|
18
|
+
SetArticulationJointTargets,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Articulation(SessionContainer):
|
|
23
|
+
"""
|
|
24
|
+
Ergonomic wrapper for articulation operations.
|
|
25
|
+
|
|
26
|
+
Articulations should be added using scene.add_articulation() or retrieved using scene.get_articulation().
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
scene = Scene()
|
|
30
|
+
|
|
31
|
+
# Get an existing articulation
|
|
32
|
+
robot = scene.get_articulation(path="/World/robot")
|
|
33
|
+
|
|
34
|
+
# Use articulation
|
|
35
|
+
joint_states = robot.get_joint_states()
|
|
36
|
+
robot.set_joint_targets(
|
|
37
|
+
joint_targets=[
|
|
38
|
+
JointTarget(position=0.1, velocity=0.0, effort=0.0),
|
|
39
|
+
JointTarget(position=0.2, velocity=0.0, effort=0.0),
|
|
40
|
+
]
|
|
41
|
+
)
|
|
42
|
+
pose = robot.get_world_pose()
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, path: str):
|
|
46
|
+
"""
|
|
47
|
+
Initialize articulation by resolving path and validating existence.
|
|
48
|
+
|
|
49
|
+
:param path: USD path for the articulation.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
super().__init__()
|
|
53
|
+
|
|
54
|
+
# Validate path
|
|
55
|
+
self._path = self._session.query_sim_rpc(
|
|
56
|
+
endpoint="get_articulation",
|
|
57
|
+
payload=GetArticulation(path=path),
|
|
58
|
+
response_type=GetArticulationResponse,
|
|
59
|
+
).path
|
|
60
|
+
|
|
61
|
+
@classmethod
|
|
62
|
+
def add(
|
|
63
|
+
cls,
|
|
64
|
+
path: str,
|
|
65
|
+
config: ArticulationConfig,
|
|
66
|
+
world_pose: Pose | None,
|
|
67
|
+
local_pose: Pose | None,
|
|
68
|
+
scale: Vector3 | None,
|
|
69
|
+
) -> "Articulation":
|
|
70
|
+
"""
|
|
71
|
+
Add an articulation to the scene.
|
|
72
|
+
|
|
73
|
+
:param path: USD path for the articulation.
|
|
74
|
+
:param config: Articulation configuration.
|
|
75
|
+
:param world_pose: Optional world pose.
|
|
76
|
+
:param local_pose: Optional local pose.
|
|
77
|
+
:param scale: Optional scale.
|
|
78
|
+
:return: The articulation instance.
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
Session.get_current().query_sim_rpc(
|
|
82
|
+
endpoint="add_articulation",
|
|
83
|
+
payload=AddArticulation(
|
|
84
|
+
path=path,
|
|
85
|
+
config=config,
|
|
86
|
+
world_pose=world_pose,
|
|
87
|
+
local_pose=local_pose,
|
|
88
|
+
scale=scale,
|
|
89
|
+
),
|
|
90
|
+
)
|
|
91
|
+
return cls(path)
|
|
92
|
+
|
|
93
|
+
def get_joint_states(
|
|
94
|
+
self,
|
|
95
|
+
joint_names: list[str] | None = None,
|
|
96
|
+
) -> list[JointState]:
|
|
97
|
+
"""
|
|
98
|
+
Get current joint states.
|
|
99
|
+
|
|
100
|
+
:param joint_names: Optional list of joint names. If None, returns all joints.
|
|
101
|
+
:return: List of joint states.
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
response = self._session.query_sim_rpc(
|
|
105
|
+
endpoint="get_articulation_joint_states",
|
|
106
|
+
payload=GetArticulationJointStates(path=self._path, joint_names=joint_names),
|
|
107
|
+
response_type=ArticulationJointStates,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return response.joint_states if response else []
|
|
111
|
+
|
|
112
|
+
def get_joint_targets(self, joint_names: list[str] | None = None) -> list[JointTarget]:
|
|
113
|
+
"""
|
|
114
|
+
Get current applied control targets.
|
|
115
|
+
|
|
116
|
+
:param joint_names: Optional list of joint names. If None, returns all joints.
|
|
117
|
+
:return: List of joint control targets.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
return self._session.query_sim_rpc(
|
|
121
|
+
endpoint="get_articulation_joint_targets",
|
|
122
|
+
payload=GetArticulationJointTargets(path=self._path, joint_names=joint_names),
|
|
123
|
+
response_type=ArticulationJointTargets,
|
|
124
|
+
).joint_targets
|
|
125
|
+
|
|
126
|
+
def get_joint_configs(self, joint_names: list[str] | None = None) -> list[ArticulationJointConfig]:
|
|
127
|
+
"""
|
|
128
|
+
Get complete joint configurations.
|
|
129
|
+
|
|
130
|
+
Only returns DOF joints. Non-DOF joints are automatically filtered out.
|
|
131
|
+
Use the joint_name field in each config to get joint names.
|
|
132
|
+
|
|
133
|
+
:param joint_names: Optional list of joint names. If None, returns all DOF joints.
|
|
134
|
+
:return: List of joint configurations (DOF joints only).
|
|
135
|
+
"""
|
|
136
|
+
|
|
137
|
+
return self._session.query_sim_rpc(
|
|
138
|
+
endpoint="get_articulation_joint_configs",
|
|
139
|
+
payload=GetArticulationJointConfigs(path=self._path, joint_names=joint_names),
|
|
140
|
+
response_type=ArticulationJointConfigs,
|
|
141
|
+
).joint_configs
|
|
142
|
+
|
|
143
|
+
def set_joint_configs(self, joint_configs: list[ArticulationJointConfig]) -> None:
|
|
144
|
+
"""
|
|
145
|
+
Set complete joint configurations.
|
|
146
|
+
|
|
147
|
+
:param joint_configs: List of joint configurations to apply.
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
self._session.query_sim_rpc(
|
|
151
|
+
endpoint="set_articulation_joint_configs",
|
|
152
|
+
payload=SetArticulationJointConfigs(path=self._path, joint_configs=joint_configs),
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
def set_joint_states(
|
|
156
|
+
self,
|
|
157
|
+
joint_names: list[str] | None = None,
|
|
158
|
+
joint_states: list[JointState] | None = None,
|
|
159
|
+
) -> None:
|
|
160
|
+
"""
|
|
161
|
+
Set the joint states of the articulation (immediate teleport).
|
|
162
|
+
|
|
163
|
+
:param joint_names: Optional list of joint names. If None, sets all joints.
|
|
164
|
+
:param joint_states: List of joint states to set.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
self._session.query_sim_rpc(
|
|
168
|
+
endpoint="set_articulation_joint_states",
|
|
169
|
+
payload=SetArticulationJointStates(
|
|
170
|
+
path=self._path,
|
|
171
|
+
joint_names=joint_names,
|
|
172
|
+
joint_states=joint_states,
|
|
173
|
+
),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def set_joint_targets(
|
|
177
|
+
self,
|
|
178
|
+
joint_names: list[str] | None = None,
|
|
179
|
+
joint_targets: list[JointTarget] | None = None,
|
|
180
|
+
) -> None:
|
|
181
|
+
"""
|
|
182
|
+
Set control targets for the articulation's PD controllers.
|
|
183
|
+
|
|
184
|
+
:param joint_names: Optional list of joint names. If None, targets all joints.
|
|
185
|
+
:param joint_targets: List of joint control targets.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
self._session.query_sim_rpc(
|
|
189
|
+
endpoint="set_articulation_joint_targets",
|
|
190
|
+
payload=SetArticulationJointTargets(
|
|
191
|
+
path=self._path,
|
|
192
|
+
joint_names=joint_names,
|
|
193
|
+
joint_targets=joint_targets,
|
|
194
|
+
),
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
def get_world_pose(self) -> Pose:
|
|
198
|
+
"""
|
|
199
|
+
Get the world pose of the articulation.
|
|
200
|
+
|
|
201
|
+
:return: World pose.
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
return self._session.query_sim_rpc(
|
|
205
|
+
endpoint="get_articulation_world_pose",
|
|
206
|
+
payload=GetWorldPose(path=self._path),
|
|
207
|
+
response_type=Pose,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
def get_local_pose(self) -> Pose:
|
|
211
|
+
"""
|
|
212
|
+
Get the local pose of the articulation.
|
|
213
|
+
|
|
214
|
+
:return: Local pose.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
return self._session.query_sim_rpc(
|
|
218
|
+
endpoint="get_articulation_local_pose",
|
|
219
|
+
payload=GetLocalPose(path=self._path),
|
|
220
|
+
response_type=Pose,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def set_world_pose(self, pose: Pose | dict) -> None:
|
|
224
|
+
"""
|
|
225
|
+
Set the world pose of the articulation.
|
|
226
|
+
|
|
227
|
+
:param pose: World pose as Pose (or dict with position/orientation lists).
|
|
228
|
+
"""
|
|
229
|
+
|
|
230
|
+
self._session.query_sim_rpc(
|
|
231
|
+
endpoint="set_articulation_world_pose",
|
|
232
|
+
payload=SetWorldPose(path=self._path, pose=Pose.from_any(pose)),
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
def set_local_pose(self, pose: Pose | dict) -> None:
|
|
236
|
+
"""
|
|
237
|
+
Set the local pose of the articulation.
|
|
238
|
+
|
|
239
|
+
:param pose: Local pose as Pose (or dict with position/orientation lists).
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
self._session.query_sim_rpc(
|
|
243
|
+
endpoint="set_articulation_local_pose",
|
|
244
|
+
payload=SetLocalPose(path=self._path, pose=Pose.from_any(pose)),
|
|
245
|
+
)
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
from antioch.session.session import Session, SessionContainer
|
|
4
|
+
from common.message import Vector3
|
|
5
|
+
from common.session.views.basis_curve import (
|
|
6
|
+
AddBasisCurveLine,
|
|
7
|
+
AddBasisCurveSemiCircle,
|
|
8
|
+
GetBasisCurve,
|
|
9
|
+
GetBasisCurveExtents,
|
|
10
|
+
GetBasisCurveExtentsResponse,
|
|
11
|
+
GetBasisCurvePoints,
|
|
12
|
+
GetBasisCurvePointsResponse,
|
|
13
|
+
GetBasisCurveResponse,
|
|
14
|
+
RemoveBasisCurve,
|
|
15
|
+
SetBasisCurveVisibility,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BasisCurve(SessionContainer):
|
|
20
|
+
"""
|
|
21
|
+
Ergonomic wrapper for basis curve operations.
|
|
22
|
+
|
|
23
|
+
BasisCurves should be added using scene.add_basis_curve() or retrieved using scene.get_basis_curve().
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
scene = Scene()
|
|
27
|
+
|
|
28
|
+
# Add basis curve
|
|
29
|
+
basis_curve = scene.add_basis_curve(
|
|
30
|
+
path="/World/curve",
|
|
31
|
+
center=[1.0, 2.0, 3.0],
|
|
32
|
+
radius=2.0,
|
|
33
|
+
min_angle_deg=0.0,
|
|
34
|
+
max_angle_deg=180.0,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
extents = basis_curve.get_extents()
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(self, path: str):
|
|
41
|
+
"""
|
|
42
|
+
Initialize basis curve by resolving path and validating existence.
|
|
43
|
+
|
|
44
|
+
:param path: USD path for the basis curve.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
super().__init__()
|
|
48
|
+
|
|
49
|
+
# Validate path
|
|
50
|
+
self._path = self._session.query_sim_rpc(
|
|
51
|
+
endpoint="get_basis_curve",
|
|
52
|
+
payload=GetBasisCurve(path=path),
|
|
53
|
+
response_type=GetBasisCurveResponse,
|
|
54
|
+
).path
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def path(self) -> str:
|
|
58
|
+
"""
|
|
59
|
+
Get the path of the basis curve.
|
|
60
|
+
|
|
61
|
+
:return: The path of the basis curve.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
return self._path
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def add(
|
|
68
|
+
cls,
|
|
69
|
+
path: str,
|
|
70
|
+
center: Vector3 = Vector3.zeros(),
|
|
71
|
+
radius: float = 1.0,
|
|
72
|
+
min_angle_deg: float = 0.0,
|
|
73
|
+
max_angle_deg: float = 180.0,
|
|
74
|
+
) -> "BasisCurve":
|
|
75
|
+
"""
|
|
76
|
+
Add a semi-circle basis curve to the scene.
|
|
77
|
+
|
|
78
|
+
:param path: USD path for the basis curve.
|
|
79
|
+
:param center: Center of the basis curve.
|
|
80
|
+
:param radius: Radius of the basis curve.
|
|
81
|
+
:param min_angle_deg: Minimum angle of the basis curve in degrees.
|
|
82
|
+
:param max_angle_deg: Maximum angle of the basis curve in degrees.
|
|
83
|
+
:return: The basis curve instance.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
Session.get_current().query_sim_rpc(
|
|
87
|
+
endpoint="add_basis_curve_semi_circle",
|
|
88
|
+
payload=AddBasisCurveSemiCircle(
|
|
89
|
+
path=path,
|
|
90
|
+
center=center,
|
|
91
|
+
radius=radius,
|
|
92
|
+
min_angle_deg=min_angle_deg,
|
|
93
|
+
max_angle_deg=max_angle_deg,
|
|
94
|
+
),
|
|
95
|
+
)
|
|
96
|
+
return cls(path)
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
def add_line(
|
|
100
|
+
cls,
|
|
101
|
+
path: str,
|
|
102
|
+
start: Vector3,
|
|
103
|
+
end: Vector3 | None = None,
|
|
104
|
+
angle_deg: float | None = None,
|
|
105
|
+
length: float | None = None,
|
|
106
|
+
) -> "BasisCurve":
|
|
107
|
+
"""
|
|
108
|
+
Add a line basis curve to the scene.
|
|
109
|
+
|
|
110
|
+
Supports two modes:
|
|
111
|
+
- Cartesian: Provide start and end points directly
|
|
112
|
+
- Polar: Provide start point, angle (degrees from +X axis in XY plane), and length
|
|
113
|
+
|
|
114
|
+
:param path: USD path for the basis curve.
|
|
115
|
+
:param start: Start point of the line.
|
|
116
|
+
:param end: End point of the line (Cartesian mode).
|
|
117
|
+
:param angle_deg: Angle in degrees from +X axis in XY plane (polar mode).
|
|
118
|
+
:param length: Length of the line (polar mode).
|
|
119
|
+
:return: The basis curve instance.
|
|
120
|
+
:raises ValueError: If both modes are specified or neither mode is complete.
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
Session.get_current().query_sim_rpc(
|
|
124
|
+
endpoint="add_basis_curve_line",
|
|
125
|
+
payload=AddBasisCurveLine(
|
|
126
|
+
path=path,
|
|
127
|
+
start=start,
|
|
128
|
+
end=end,
|
|
129
|
+
angle_deg=angle_deg,
|
|
130
|
+
length=length,
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
return cls(path)
|
|
134
|
+
|
|
135
|
+
def get_extents(self) -> tuple[Vector3, Vector3]:
|
|
136
|
+
"""
|
|
137
|
+
Get the extents of the basis curve.
|
|
138
|
+
|
|
139
|
+
:return: Extents as tuple of start and end points.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
extents = self._session.query_sim_rpc(
|
|
143
|
+
endpoint="get_basis_curve_extents",
|
|
144
|
+
payload=GetBasisCurveExtents(path=self._path),
|
|
145
|
+
response_type=GetBasisCurveExtentsResponse,
|
|
146
|
+
)
|
|
147
|
+
return extents.start, extents.end
|
|
148
|
+
|
|
149
|
+
def get_points(
|
|
150
|
+
self, samples_per_segment: int = 10, sort_by: Literal["X", "Y", "Z"] | None = None, ascending: bool = True
|
|
151
|
+
) -> list[Vector3]:
|
|
152
|
+
"""
|
|
153
|
+
Get the points of the basis curve.
|
|
154
|
+
|
|
155
|
+
:param samples_per_segment: The number of samples per segment.
|
|
156
|
+
:param sort_by: The axis to sort the points by.
|
|
157
|
+
:param ascending: Whether to sort the points in ascending order.
|
|
158
|
+
:return: The points of the basis curve.
|
|
159
|
+
"""
|
|
160
|
+
return self._session.query_sim_rpc(
|
|
161
|
+
endpoint="get_basis_curve_points",
|
|
162
|
+
payload=GetBasisCurvePoints(path=self._path, samples_per_segment=samples_per_segment, sort_by=sort_by, ascending=ascending),
|
|
163
|
+
response_type=GetBasisCurvePointsResponse,
|
|
164
|
+
).points
|
|
165
|
+
|
|
166
|
+
def set_visibility(self, visible: bool) -> None:
|
|
167
|
+
"""
|
|
168
|
+
Set the visibility of the basis curve.
|
|
169
|
+
|
|
170
|
+
:param visible: True to make visible, False to hide.
|
|
171
|
+
"""
|
|
172
|
+
|
|
173
|
+
self._session.query_sim_rpc(
|
|
174
|
+
endpoint="set_basis_curve_visibility",
|
|
175
|
+
payload=SetBasisCurveVisibility(path=self._path, visible=visible),
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def remove(self) -> None:
|
|
179
|
+
"""
|
|
180
|
+
Remove the basis curve from the scene.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
self._session.query_sim_rpc(
|
|
184
|
+
endpoint="remove_basis_curve",
|
|
185
|
+
payload=RemoveBasisCurve(path=self._path),
|
|
186
|
+
)
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
from antioch.session.session import Session, SessionContainer
|
|
2
|
+
from common.message import CameraInfo, Image, Pose
|
|
3
|
+
from common.session.views.camera import AddCamera, CameraConfig, GetCamera, GetCameraFrame, GetCameraResponse
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Camera(SessionContainer):
|
|
7
|
+
"""
|
|
8
|
+
Camera view for time-synchronized image capture.
|
|
9
|
+
|
|
10
|
+
Example:
|
|
11
|
+
scene = Scene()
|
|
12
|
+
camera = scene.get_camera(name="my_ark/my_module/my_camera")
|
|
13
|
+
frame = camera.get_frame()
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
path: str,
|
|
19
|
+
config: CameraConfig | None = None,
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Initialize camera view.
|
|
23
|
+
|
|
24
|
+
:param path: USD path for the camera.
|
|
25
|
+
:param config: Optional camera config for intrinsics.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
super().__init__()
|
|
29
|
+
|
|
30
|
+
self._config = config
|
|
31
|
+
self._path = self._session.query_sim_rpc(
|
|
32
|
+
endpoint="get_camera",
|
|
33
|
+
payload=GetCamera(path=path),
|
|
34
|
+
response_type=GetCameraResponse,
|
|
35
|
+
).path
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def add(
|
|
39
|
+
cls,
|
|
40
|
+
path: str,
|
|
41
|
+
config: CameraConfig,
|
|
42
|
+
world_pose: Pose | None,
|
|
43
|
+
local_pose: Pose | None,
|
|
44
|
+
) -> "Camera":
|
|
45
|
+
"""
|
|
46
|
+
Add camera to the scene.
|
|
47
|
+
|
|
48
|
+
:param path: USD path for the camera.
|
|
49
|
+
:param config: Camera configuration.
|
|
50
|
+
:param world_pose: Optional world pose.
|
|
51
|
+
:param local_pose: Optional local pose.
|
|
52
|
+
:return: The camera instance.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
Session.get_current().query_sim_rpc(
|
|
56
|
+
endpoint="add_camera",
|
|
57
|
+
payload=AddCamera(
|
|
58
|
+
path=path,
|
|
59
|
+
config=config,
|
|
60
|
+
world_pose=world_pose,
|
|
61
|
+
local_pose=local_pose,
|
|
62
|
+
),
|
|
63
|
+
)
|
|
64
|
+
return cls(path, config)
|
|
65
|
+
|
|
66
|
+
def get_frame(self) -> Image | None:
|
|
67
|
+
"""
|
|
68
|
+
Get camera frame with image data.
|
|
69
|
+
|
|
70
|
+
:return: Image (RGB or depth based on camera mode), or None if image data is not ready.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
image = self._session.query_sim_rpc(
|
|
74
|
+
endpoint="get_camera_frame",
|
|
75
|
+
payload=GetCameraFrame(path=self._path),
|
|
76
|
+
response_type=Image,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
return image
|
|
80
|
+
|
|
81
|
+
def get_camera_info(self, frame_id: str = "camera_optical_frame") -> CameraInfo | None:
|
|
82
|
+
"""
|
|
83
|
+
Get camera info with calculated intrinsics.
|
|
84
|
+
|
|
85
|
+
:param frame_id: The coordinate frame ID for the camera.
|
|
86
|
+
:return: CameraInfo with full intrinsics and distortion parameters, or None if no config.
|
|
87
|
+
"""
|
|
88
|
+
|
|
89
|
+
if self._config is None:
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
return self._config.to_camera_info(frame_id=frame_id)
|