sstsr 2.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.
@@ -0,0 +1,318 @@
1
+ Metadata-Version: 2.5
2
+ Name: sstsr
3
+ Version: 2.0.0
4
+ Summary: Task Space Regions for grasp and placement planning (import as `tsr`)
5
+ Project-URL: Homepage, https://github.com/personalrobotics/tsr
6
+ Project-URL: Repository, https://github.com/personalrobotics/tsr
7
+ Project-URL: Issues, https://github.com/personalrobotics/tsr/issues
8
+ Author-email: Siddhartha Srinivasa <siddhartha.srinivasa@gmail.com>
9
+ Maintainer-email: Siddhartha Srinivasa <siddhartha.srinivasa@gmail.com>
10
+ License-Expression: BSD-2-Clause
11
+ License-File: LICENSE
12
+ Keywords: motion-planning,robotics,task-space-regions,tsr
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: License :: OSI Approved :: BSD License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: 3.14
24
+ Classifier: Topic :: Scientific/Engineering
25
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
26
+ Requires-Python: >=3.10
27
+ Requires-Dist: numpy>=1.24.0
28
+ Requires-Dist: pyyaml>=6.0.1
29
+ Requires-Dist: scipy>=1.10.0
30
+ Provides-Extra: test
31
+ Requires-Dist: build>=1.0.0; extra == 'test'
32
+ Requires-Dist: hypothesis>=6.112; extra == 'test'
33
+ Requires-Dist: pytest-cov>=4.0.0; extra == 'test'
34
+ Requires-Dist: pytest>=7.0.0; extra == 'test'
35
+ Provides-Extra: viz
36
+ Requires-Dist: matplotlib>=3.8.0; extra == 'viz'
37
+ Requires-Dist: pillow>=10.3.0; extra == 'viz'
38
+ Requires-Dist: pyvista>=0.43.0; extra == 'viz'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # Task Space Regions (TSR)
42
+
43
+ A Python library for pose-constrained manipulation planning using Task Space Regions.
44
+
45
+ TSRs encode *any* manipulation constraint as a bounded region in SE(3): grasping,
46
+ placing, transporting, pouring, tool use, and more. A planner samples from a TSR
47
+ to get valid end-effector poses satisfying the constraint.
48
+
49
+ Based on the IJRR paper ["Task Space Regions: A Framework for Pose-Constrained Manipulation Planning"](https://www.ri.cmu.edu/pub_files/2011/10/dmitry_ijrr10-1.pdf) by Berenson, Srinivasa, and Kuffner.
50
+
51
+ ## Gallery
52
+
53
+ ### Grasps
54
+
55
+ ![TSR Grasp Templates](assets/tsr_grasps.png)
56
+
57
+ ### Stable placements
58
+
59
+ ![Stable Placements — primitives](assets/stable_placements.png)
60
+
61
+ *Cylinder, box, sphere, and torus in every stable pose on a table surface.*
62
+
63
+ ![Stable Placements — non-convex meshes](assets/mesh_placements.png)
64
+
65
+ *L-shape, T-shape, and a mug (cylinder + handle) — `place_mesh` applied to arbitrary vertex clouds. Each object is shown in all stable orientations above the 5° margin threshold.*
66
+
67
+ ## Installation
68
+
69
+ The distribution is named **`sstsr`** on PyPI; the import name is `tsr`.
70
+
71
+ ```bash
72
+ pip install sstsr # or: uv add sstsr
73
+ ```
74
+ ```python
75
+ import tsr # the import name is unchanged
76
+ ```
77
+
78
+ For visualization support:
79
+ ```bash
80
+ pip install "sstsr[viz]" # or: uv add "sstsr[viz]"
81
+ ```
82
+
83
+ For development:
84
+ ```bash
85
+ git clone https://github.com/personalrobotics/tsr.git
86
+ cd tsr
87
+ uv sync --extra test
88
+ ```
89
+
90
+ ## Quick Start
91
+
92
+ ### Load templates for a full manipulation task
93
+
94
+ Templates are YAML files that encode pose constraints for each step of a task.
95
+ The library ships with two narratives:
96
+
97
+ ```python
98
+ from tsr import load_package_template
99
+ import numpy as np
100
+
101
+ # --- Tool use: screwdriver ---
102
+ grasp = load_package_template("grasps", "screwdriver_grasp.yaml")
103
+ drive = load_package_template("tasks", "drive_screw.yaml")
104
+ drop = load_package_template("places", "toolchest_drop.yaml")
105
+
106
+ screwdriver_pose = np.eye(4)
107
+ screwdriver_pose[:3, 3] = [0.4, 0.1, 0.02]
108
+
109
+ gripper_poses = grasp.sample(screwdriver_pose)
110
+
111
+ # --- Everyday manipulation: mug of water ---
112
+ pick = load_package_template("grasps", "mug_handle_grasp.yaml")
113
+ carry = load_package_template("tasks", "mug_transport_upright.yaml")
114
+ pour = load_package_template("tasks", "mug_pour_into_sink.yaml")
115
+ place = load_package_template("places", "mug_on_table.yaml")
116
+ ```
117
+
118
+ ### Generate templates from object geometry
119
+
120
+ #### Grasping
121
+
122
+ `ParallelJawGripper` generates TSR templates directly from shape parameters.
123
+ Pre-configured subclasses are provided for common grippers:
124
+
125
+ | Class | `finger_length` | `max_aperture` | Notes |
126
+ |---|---|---|---|
127
+ | `Robotiq2F140` | 55 mm | 140 mm | Robotiq 2F-140 parallel gripper |
128
+ | `FrankaHand` | 44.5 mm | 80 mm | Franka Emika Panda hand |
129
+
130
+ ```python
131
+ import numpy as np
132
+ from tsr.hands import ParallelJawGripper, Robotiq2F140, FrankaHand
133
+
134
+ # Use a pre-configured gripper for a known hardware platform
135
+ gripper = Robotiq2F140()
136
+ gripper = FrankaHand()
137
+
138
+ # Or configure manually for custom hardware
139
+ gripper = ParallelJawGripper(finger_length=0.055, max_aperture=0.140)
140
+
141
+ # Cylinder — side + top + bottom: 4*k templates (default k=3: 12 total)
142
+ templates = gripper.grasp_cylinder(
143
+ cylinder_radius=0.040, # 4 cm radius
144
+ cylinder_height=0.120, # 12 cm tall
145
+ reference="mug",
146
+ )
147
+
148
+ # Box — all six faces, two finger orientations per face: up to 2*6*k templates
149
+ templates = gripper.grasp_box(box_x=0.08, box_y=0.06, box_z=0.18, reference="box")
150
+
151
+ # Sphere — full SO(3) approach: k templates
152
+ templates = gripper.grasp_sphere(object_radius=0.040, reference="ball")
153
+
154
+ # Torus — side (all minor angles) + span (if aperture allows)
155
+ templates = gripper.grasp_torus(
156
+ torus_radius=0.035, # major radius R: center to tube center
157
+ tube_radius=0.015, # minor radius r: tube cross-section
158
+ reference="handle",
159
+ )
160
+
161
+ # Instantiate at a specific object pose and sample
162
+ mug_pose = np.eye(4)
163
+ mug_pose[:3, 3] = [0.5, 0.0, 0.0] # mug at x=0.5m
164
+
165
+ grasp_poses = [t.sample(mug_pose) for t in templates]
166
+ ```
167
+
168
+ #### Placing
169
+
170
+ `StablePlacer` generates one TSR template per stable resting pose on a flat surface:
171
+
172
+ ```python
173
+ import numpy as np
174
+ from tsr.placement import StablePlacer
175
+
176
+ placer = StablePlacer(table_x=0.60, table_y=0.40)
177
+
178
+ # Analytic primitives
179
+ templates = placer.place_cylinder(cylinder_radius=0.040, cylinder_height=0.120, subject="mug")
180
+ templates = placer.place_box(lx=0.08, ly=0.06, lz=0.18, subject="box") # up to 3 poses
181
+ templates = placer.place_sphere(radius=0.040, subject="ball")
182
+ templates = placer.place_torus(major_radius=0.035, minor_radius=0.015, subject="ring")
183
+
184
+ # Arbitrary mesh — pass any (N, 3) vertex cloud + centre of mass
185
+ vertices = np.array([...]) # (N, 3) points
186
+ com = np.array([cx, cy, cz])
187
+ templates = placer.place_mesh(vertices, com, subject="widget",
188
+ min_margin_deg=5.0) # discard marginal poses
189
+
190
+ # Each template encodes one stable orientation; sample a table pose for it
191
+ table_pose = np.eye(4)
192
+ table_pose[2, 3] = 0.75 # table surface at z = 0.75 m
193
+
194
+ for t in templates:
195
+ pose = t.sample(table_pose)
196
+ print(t, "→ COM z =", pose[2, 3])
197
+ ```
198
+
199
+ Stability is determined by the COM-projection criterion: a face is stable if the
200
+ centre of mass projects inside the support polygon formed by that face's contact
201
+ region. The stability margin is `arctan(d_min / h_com)` where `d_min` is the
202
+ minimum distance from the COM projection to any edge of the polygon.
203
+
204
+ ### Work directly with TSRs
205
+
206
+ ```python
207
+ from tsr import TSR
208
+ import numpy as np
209
+
210
+ # A TSR is defined by three components:
211
+ # T0_w : 4×4 transform — world frame to TSR frame
212
+ # Tw_e : 4×4 transform — TSR frame to end-effector at Bw=0
213
+ # Bw : 6×2 bounds — [x, y, z, roll, pitch, yaw]
214
+
215
+ # Example: keep a mug upright — free xy/yaw, small pitch/roll
216
+ T0_w = np.eye(4)
217
+ Tw_e = np.eye(4)
218
+ Bw = np.zeros((6, 2))
219
+ Bw[0, :] = [-2.0, 2.0] # x: anywhere in workspace
220
+ Bw[1, :] = [-2.0, 2.0] # y: anywhere in workspace
221
+ Bw[2, :] = [ 0.5, 1.5] # z: transport height
222
+ Bw[3, :] = [-0.26, 0.26] # roll: ±15°
223
+ Bw[4, :] = [-0.26, 0.26] # pitch: ±15°
224
+ Bw[5, :] = [-np.pi, np.pi] # yaw: free
225
+
226
+ tsr = TSR(T0_w=T0_w, Tw_e=Tw_e, Bw=Bw)
227
+
228
+ pose = tsr.sample() # random SE(3) pose in the region
229
+ distance, _ = tsr.distance(pose) # distance to nearest valid pose
230
+ is_valid = tsr.contains(pose) # containment check
231
+ ```
232
+
233
+ ### Save and load templates
234
+
235
+ ```python
236
+ from tsr import TSRTemplate, save_template, load_template
237
+ import numpy as np
238
+
239
+ template = TSRTemplate(
240
+ T_ref_tsr=np.eye(4),
241
+ Tw_e=Tw_e,
242
+ Bw=Bw,
243
+ task="transport",
244
+ subject="mug",
245
+ reference="world",
246
+ name="Mug Transport Upright",
247
+ description="Keep mug upright during transport, ±15° tilt tolerance",
248
+ )
249
+
250
+ save_template(template, "my_template.yaml")
251
+ template = load_template("my_template.yaml")
252
+
253
+ # Bind to an object pose at runtime
254
+ tsr = template.instantiate(np.eye(4))
255
+ ```
256
+
257
+ ## End-effector frame convention
258
+
259
+ All templates in this library use a canonical end-effector frame:
260
+
261
+ ```
262
+ z = approach direction (toward contact surface)
263
+ y = opening / spread direction (finger opening for grippers, tool axis for others)
264
+ x = right-hand normal (x = y × z)
265
+ ```
266
+
267
+ AnyGrasp / GraspNet uses `x = approach` — convert with:
268
+ ```python
269
+ R_convert = np.array([[0, 0, -1], [0, 1, 0], [1, 0, 0]])
270
+ ```
271
+
272
+ ## TSR Chains
273
+
274
+ For coupled multi-body constraints (e.g., door opening, bimanual transport):
275
+
276
+ ```python
277
+ from tsr import TSRChain
278
+
279
+ chain = TSRChain(TSRs=[hinge_tsr, handle_tsr])
280
+ pose = chain.sample()
281
+ ```
282
+
283
+ ## Visualization
284
+
285
+ ```python
286
+ from tsr.viz import TSRVisualizer, cylinder_renderer, parallel_jaw_renderer, plasma_colors
287
+
288
+ poses = [t.sample(mug_pose) for t in templates]
289
+ colors = plasma_colors(len(templates))
290
+
291
+ TSRVisualizer(
292
+ title="Cylinder Grasp Templates",
293
+ focus=(0., 0., 0.06),
294
+ ).render(
295
+ reference_renderer=cylinder_renderer(radius=0.04, height=0.12),
296
+ subject_renderer=parallel_jaw_renderer(finger_length=0.055, half_aperture=0.07),
297
+ poses=poses,
298
+ colors=colors,
299
+ out="grasp_viz.png",
300
+ )
301
+ ```
302
+
303
+ Requires the `viz` extra: `uv sync --extra viz`.
304
+
305
+ ## Documentation
306
+
307
+ - **[Tutorial](docs/tutorial.md)** — TSR theory, math, and worked examples
308
+ - **[Examples](examples/)** — Runnable scripts (`uv run python examples/<script>.py`)
309
+
310
+ ## Testing
311
+
312
+ ```bash
313
+ uv run pytest tests/ -v
314
+ ```
315
+
316
+ ## License
317
+
318
+ BSD-2-Clause — see LICENSE file.
@@ -0,0 +1,31 @@
1
+ tsr/__init__.py,sha256=DyDsghINgL32BvUXfpL4ha5REqDv2m65d6Vot5q4tao,3123
2
+ tsr/io.py,sha256=Idz-WTx9S6vHgDhDtKfxPQ-zKX1aS32zaXIgOpxbYlE,3641
3
+ tsr/sampling.py,sha256=OAd4HuHXB2K0oBCfPlgWAefVtSBNmR_BLVYluFattI4,9330
4
+ tsr/template.py,sha256=6AGX4_VTq_Kx3dtSPoSgQV5DAiLSUCyGdFIb3JeEx5c,5491
5
+ tsr/tsr.py,sha256=shVgAeoVZOjhYSG0ni8BvHTMl1fwW7ZjbfP6nUeeYCc,370
6
+ tsr/tsr_chain.py,sha256=a8XR1-MB7uQHTo1NFj5X6C-fGxxZq4nJAPdOzrKVDuY,392
7
+ tsr/utils.py,sha256=jYBOmGBG8SJlM9DNDz8H5tVhrCOdSgJ_pAXMKAaGnyA,546
8
+ tsr/viz.py,sha256=fnQ71qFDE8DSXPhoMOzAagyQzxWDMxhMRmHQDrIqoMs,23026
9
+ tsr/core/__init__.py,sha256=diN8q5DK-IXMaHd-ujTZ-g6NluvCNikR6QuVJ0-WHu0,952
10
+ tsr/core/tsr.py,sha256=b_aXQlhmdEVvN9ZJF2g6soCDWE2G1gf2FdBcrksDNdk,21775
11
+ tsr/core/tsr_chain.py,sha256=aZYAIZWyFr9Q2hVtBzqldDj_mZJS6vcfodwwdrOKBDA,8655
12
+ tsr/core/utils.py,sha256=eTePgeaCP31A_gN1G54xhFfluv7K8jLhORHb5NkB1x0,3467
13
+ tsr/hands/__init__.py,sha256=4Tu3eae6Y8pGyVQ_Jcgqq55UDJNAA4L2dnNqCWY8JFY,891
14
+ tsr/hands/base.py,sha256=pYJBruv2NB1lq4blfO07BvLygwKP046ILErkhG-2WWM,25992
15
+ tsr/hands/parallel_jaw.py,sha256=mvwewuVHHucqCh5uoI_s5m-xsWWO6FBU_JXHjm2BXzE,48753
16
+ tsr/hands/registry.py,sha256=W_NW5oH3lIEZ--uB8OrFH6-e08qsTxUVmbwqTVTumec,3881
17
+ tsr/placement/__init__.py,sha256=Hyg0YXIACgIAp9oXKunKpJodNt_97WEi8HMXhKGjjjo,579
18
+ tsr/placement/_stable_poses.py,sha256=nchSC2FygISBKyCd2T7066DLi6vr1Cd9-ykT9vgJIi0,6471
19
+ tsr/placement/stable_placer.py,sha256=Xpg_9jVehcj7gXiF6ddaldB99m6YxurRHq0m4Yo02zI,11682
20
+ tsr/templates/README.md,sha256=6g96Okg29hed0tZBsYx3C0gnsQhVG3lutelmvKFLLp0,2059
21
+ tsr/templates/grasps/mug_handle_grasp.yaml,sha256=5cTgOjvHJe0__ktKZSyQZ0VoNq8An6klws9Jr8Y5vuU,546
22
+ tsr/templates/grasps/screwdriver_grasp.yaml,sha256=H75b_HUETx0LXmVnR--YvtW0qu7AOUdMMWA97mFEEIQ,572
23
+ tsr/templates/places/mug_on_table.yaml,sha256=1VoKshxoZT7yiG9L1PMqJLWXdGD1ikGzjDbwLkv1ies,519
24
+ tsr/templates/places/toolchest_drop.yaml,sha256=gu81vy5OcxtWoe40xSd_u7sIQT5ZwM53JJecDhMQNG8,761
25
+ tsr/templates/tasks/drive_screw.yaml,sha256=rh6U3GkXJ-Ng_ZtX4xXq3XNfYA_enstrY9Tm7dgIqo4,697
26
+ tsr/templates/tasks/mug_pour_into_sink.yaml,sha256=BOwNwpnUkcMMk9c8QibMC5q86Vx4kqGc4IMH7iwvig8,714
27
+ tsr/templates/tasks/mug_transport_upright.yaml,sha256=wM2Ns3L84Qyn_f6vLeKhOLK3cLpJH_-dgdRJWvMi_F0,751
28
+ sstsr-2.0.0.dist-info/METADATA,sha256=dok81wfFTioCoWWbHnfE4NPUbB5VHRJ8GR8X08VI8UM,10181
29
+ sstsr-2.0.0.dist-info/WHEEL,sha256=THafob7ofN-NsuMN7Mg4qZyHaQI7KkD-QlcQatYhXPo,87
30
+ sstsr-2.0.0.dist-info/licenses/LICENSE,sha256=IJQAUlQgzVn5wagmuyH6I6-iEjAMVWMNqN1sNJmh0LY,1333
31
+ sstsr-2.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.32.3
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2025, Siddhartha Srinivasa and contributors to TSR
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
tsr/__init__.py ADDED
@@ -0,0 +1,104 @@
1
+ # SPDX-License-Identifier: BSD-2-Clause
2
+ # Authors: Siddhartha Srinivasa and contributors to TSR
3
+
4
+ """TSR — Task Space Regions for robotics.
5
+
6
+ Robot-agnostic Task Space Region (TSR) functionality for pose-constrained
7
+ manipulation planning. The package is layered:
8
+
9
+ * **core** — the pure-math heart: :class:`TSR`, :class:`TSRChain`, and SE(3)
10
+ helpers. Robot-agnostic, NumPy/SciPy only.
11
+ * **template** — :class:`TSRTemplate`: a reusable, serialisable, scene-agnostic
12
+ recipe that instantiates to a concrete TSR at a reference pose.
13
+ * **factories** — domain knowledge that *produces* templates:
14
+ :class:`ParallelJawGripper` (and ready-made hands) for grasps, and
15
+ :class:`StablePlacer` for placements.
16
+ * **services** — :mod:`tsr.io` (persistence), sampling helpers, and the
17
+ optional :mod:`tsr.viz` renderer (install with the ``viz`` extra).
18
+
19
+ The spine: a factory produces recipes; a recipe instantiates to math::
20
+
21
+ from tsr import ParallelJawGripper
22
+ gripper = ParallelJawGripper(finger_length=0.055, max_aperture=0.140)
23
+ templates = gripper.grasp_cylinder(cylinder_radius=0.04, cylinder_height=0.12)
24
+ tsr = templates[0].instantiate(object_pose_in_world)
25
+ pose = tsr.sample() # a valid grasp pose
26
+ assert tsr.contains(pose)
27
+ """
28
+
29
+ # --- Layer 0: core math -------------------------------------------------------
30
+ from .core import (
31
+ EPSILON,
32
+ TSR,
33
+ TSRChain,
34
+ geodesic_distance,
35
+ geodesic_error,
36
+ rotation_angle,
37
+ wrap_to_interval,
38
+ )
39
+
40
+ # --- Layer 1: the reusable recipe ---------------------------------------------
41
+ from .template import TSRTemplate
42
+
43
+ # --- Layer 2: factories (domain knowledge -> recipes) -------------------------
44
+ from .hands import FrankaHand, GripperBase, ParallelJawGripper, Robotiq2F85, Robotiq2F140
45
+ from .placement import StablePlacer
46
+
47
+ # --- Layer 3: services --------------------------------------------------------
48
+ from .io import (
49
+ get_package_templates,
50
+ list_available_templates,
51
+ load_package_template,
52
+ load_package_templates_by_category,
53
+ load_template,
54
+ load_template_collection,
55
+ save_template,
56
+ save_template_collection,
57
+ )
58
+ from .sampling import (
59
+ choose_tsr,
60
+ choose_tsr_index,
61
+ instantiate_templates,
62
+ sample_from_templates,
63
+ sample_from_tsrs,
64
+ weights_from_tsrs,
65
+ )
66
+
67
+ __version__ = "2.0.0"
68
+
69
+ __all__ = [
70
+ # core
71
+ "TSR",
72
+ "TSRChain",
73
+ "wrap_to_interval",
74
+ "rotation_angle",
75
+ "geodesic_error",
76
+ "geodesic_distance",
77
+ "EPSILON",
78
+ # template
79
+ "TSRTemplate",
80
+ # factories
81
+ "GripperBase",
82
+ "ParallelJawGripper",
83
+ "Robotiq2F85",
84
+ "Robotiq2F140",
85
+ "FrankaHand",
86
+ "StablePlacer",
87
+ # sampling helpers
88
+ "choose_tsr",
89
+ "choose_tsr_index",
90
+ "instantiate_templates",
91
+ "sample_from_tsrs",
92
+ "sample_from_templates",
93
+ "weights_from_tsrs",
94
+ # template I/O
95
+ "save_template",
96
+ "save_template_collection",
97
+ "load_template",
98
+ "load_template_collection",
99
+ "load_package_template",
100
+ "load_package_templates_by_category",
101
+ "list_available_templates",
102
+ "get_package_templates",
103
+ "__version__",
104
+ ]
tsr/core/__init__.py ADDED
@@ -0,0 +1,35 @@
1
+ # SPDX-License-Identifier: BSD-2-Clause
2
+ # Authors: Siddhartha Srinivasa and contributors to TSR
3
+
4
+ """tsr.core — the pure-math heart of the package.
5
+
6
+ Layer 0 of the architecture: robot-agnostic SE(3) geometry with no dependencies
7
+ beyond NumPy (and SciPy for the optional optimiser paths). Nothing in this
8
+ subpackage imports from the convenience layers above it (templates, factories,
9
+ io, sampling, viz); that invariant is enforced by
10
+ ``tests/tsr/test_architecture.py``.
11
+
12
+ The public symbols are re-exported at the top level (``from tsr import TSR``);
13
+ import them from here when you want only the kernel.
14
+ """
15
+
16
+ from .tsr import NANBW, TSR
17
+ from .tsr_chain import TSRChain
18
+ from .utils import (
19
+ EPSILON,
20
+ geodesic_distance,
21
+ geodesic_error,
22
+ rotation_angle,
23
+ wrap_to_interval,
24
+ )
25
+
26
+ __all__ = [
27
+ "TSR",
28
+ "TSRChain",
29
+ "NANBW",
30
+ "EPSILON",
31
+ "wrap_to_interval",
32
+ "rotation_angle",
33
+ "geodesic_error",
34
+ "geodesic_distance",
35
+ ]