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.

Files changed (99) hide show
  1. antioch/__init__.py +0 -0
  2. antioch/message.py +87 -0
  3. antioch/module/__init__.py +53 -0
  4. antioch/module/clock.py +62 -0
  5. antioch/module/execution.py +278 -0
  6. antioch/module/input.py +127 -0
  7. antioch/module/module.py +218 -0
  8. antioch/module/node.py +357 -0
  9. antioch/module/token.py +42 -0
  10. antioch/session/__init__.py +150 -0
  11. antioch/session/ark.py +504 -0
  12. antioch/session/asset.py +65 -0
  13. antioch/session/error.py +80 -0
  14. antioch/session/record.py +158 -0
  15. antioch/session/scene.py +1500 -0
  16. antioch/session/session.py +220 -0
  17. antioch/session/task.py +323 -0
  18. antioch/session/views/__init__.py +40 -0
  19. antioch/session/views/animation.py +189 -0
  20. antioch/session/views/articulation.py +245 -0
  21. antioch/session/views/basis_curve.py +186 -0
  22. antioch/session/views/camera.py +92 -0
  23. antioch/session/views/collision.py +75 -0
  24. antioch/session/views/geometry.py +74 -0
  25. antioch/session/views/ground_plane.py +63 -0
  26. antioch/session/views/imu.py +73 -0
  27. antioch/session/views/joint.py +64 -0
  28. antioch/session/views/light.py +175 -0
  29. antioch/session/views/pir_sensor.py +140 -0
  30. antioch/session/views/radar.py +73 -0
  31. antioch/session/views/rigid_body.py +282 -0
  32. antioch/session/views/xform.py +119 -0
  33. antioch_py-1.9.7.dist-info/METADATA +24 -0
  34. antioch_py-1.9.7.dist-info/RECORD +99 -0
  35. antioch_py-1.9.7.dist-info/WHEEL +5 -0
  36. antioch_py-1.9.7.dist-info/entry_points.txt +2 -0
  37. antioch_py-1.9.7.dist-info/top_level.txt +2 -0
  38. common/__init__.py +0 -0
  39. common/ark/__init__.py +60 -0
  40. common/ark/ark.py +128 -0
  41. common/ark/hardware.py +121 -0
  42. common/ark/kinematics.py +31 -0
  43. common/ark/module.py +85 -0
  44. common/ark/node.py +94 -0
  45. common/ark/scheduler.py +439 -0
  46. common/ark/sim.py +33 -0
  47. common/assets/__init__.py +3 -0
  48. common/constants.py +47 -0
  49. common/core/__init__.py +52 -0
  50. common/core/agent.py +296 -0
  51. common/core/auth.py +305 -0
  52. common/core/registry.py +331 -0
  53. common/core/task.py +36 -0
  54. common/message/__init__.py +59 -0
  55. common/message/annotation.py +89 -0
  56. common/message/array.py +500 -0
  57. common/message/base.py +517 -0
  58. common/message/camera.py +91 -0
  59. common/message/color.py +139 -0
  60. common/message/frame.py +50 -0
  61. common/message/image.py +171 -0
  62. common/message/imu.py +14 -0
  63. common/message/joint.py +47 -0
  64. common/message/log.py +31 -0
  65. common/message/pir.py +15 -0
  66. common/message/point.py +109 -0
  67. common/message/point_cloud.py +63 -0
  68. common/message/pose.py +148 -0
  69. common/message/quaternion.py +273 -0
  70. common/message/radar.py +58 -0
  71. common/message/types.py +37 -0
  72. common/message/vector.py +786 -0
  73. common/rome/__init__.py +9 -0
  74. common/rome/client.py +430 -0
  75. common/rome/error.py +16 -0
  76. common/session/__init__.py +54 -0
  77. common/session/environment.py +31 -0
  78. common/session/sim.py +240 -0
  79. common/session/views/__init__.py +263 -0
  80. common/session/views/animation.py +73 -0
  81. common/session/views/articulation.py +184 -0
  82. common/session/views/basis_curve.py +102 -0
  83. common/session/views/camera.py +147 -0
  84. common/session/views/collision.py +59 -0
  85. common/session/views/geometry.py +102 -0
  86. common/session/views/ground_plane.py +41 -0
  87. common/session/views/imu.py +66 -0
  88. common/session/views/joint.py +81 -0
  89. common/session/views/light.py +96 -0
  90. common/session/views/pir_sensor.py +104 -0
  91. common/session/views/radar.py +82 -0
  92. common/session/views/rigid_body.py +236 -0
  93. common/session/views/viewport.py +21 -0
  94. common/session/views/xform.py +39 -0
  95. common/utils/__init__.py +4 -0
  96. common/utils/comms.py +571 -0
  97. common/utils/logger.py +123 -0
  98. common/utils/time.py +42 -0
  99. 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)