sstsr 2.0.0__tar.gz

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.
Files changed (91) hide show
  1. sstsr-2.0.0/.github/CODEOWNERS +1 -0
  2. sstsr-2.0.0/.github/ISSUE_TEMPLATE/bug_report.md +22 -0
  3. sstsr-2.0.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. sstsr-2.0.0/.github/ISSUE_TEMPLATE/improvement.md +13 -0
  5. sstsr-2.0.0/.github/ISSUE_TEMPLATE/task.md +12 -0
  6. sstsr-2.0.0/.github/pull_request_template.md +24 -0
  7. sstsr-2.0.0/.github/workflows/ci.yml +53 -0
  8. sstsr-2.0.0/.github/workflows/release.yml +110 -0
  9. sstsr-2.0.0/.gitignore +217 -0
  10. sstsr-2.0.0/CHANGELOG.md +66 -0
  11. sstsr-2.0.0/CODE_OF_CONDUCT.md +13 -0
  12. sstsr-2.0.0/CONTRIBUTING.md +50 -0
  13. sstsr-2.0.0/CONTRIBUTORS.md +11 -0
  14. sstsr-2.0.0/LICENSE +24 -0
  15. sstsr-2.0.0/PKG-INFO +318 -0
  16. sstsr-2.0.0/README.md +278 -0
  17. sstsr-2.0.0/SECURITY.md +7 -0
  18. sstsr-2.0.0/assets/mesh_placements.png +0 -0
  19. sstsr-2.0.0/assets/stable_placements.png +0 -0
  20. sstsr-2.0.0/assets/tsr_grasps.png +0 -0
  21. sstsr-2.0.0/docs/ARCHITECTURE.md +61 -0
  22. sstsr-2.0.0/docs/REVIEW.md +96 -0
  23. sstsr-2.0.0/docs/figures/fig1_tsr_concept.png +0 -0
  24. sstsr-2.0.0/docs/figures/fig2_coordinate_frames.png +0 -0
  25. sstsr-2.0.0/docs/figures/fig3_bounds_matrix.png +0 -0
  26. sstsr-2.0.0/docs/figures/fig4_primitives.png +0 -0
  27. sstsr-2.0.0/docs/figures/fig5_tsr_chain.png +0 -0
  28. sstsr-2.0.0/docs/figures/fig6_placement_example.png +0 -0
  29. sstsr-2.0.0/docs/figures/generate_figures.py +743 -0
  30. sstsr-2.0.0/docs/tutorial.md +657 -0
  31. sstsr-2.0.0/examples/basic_tsr.py +81 -0
  32. sstsr-2.0.0/examples/mesh_placements.py +324 -0
  33. sstsr-2.0.0/examples/parallel_jaw_grasp.py +143 -0
  34. sstsr-2.0.0/examples/stable_placements.py +165 -0
  35. sstsr-2.0.0/examples/task_templates.py +85 -0
  36. sstsr-2.0.0/examples/tsr_chains.py +109 -0
  37. sstsr-2.0.0/pyproject.toml +110 -0
  38. sstsr-2.0.0/src/tsr/__init__.py +104 -0
  39. sstsr-2.0.0/src/tsr/core/__init__.py +35 -0
  40. sstsr-2.0.0/src/tsr/core/tsr.py +550 -0
  41. sstsr-2.0.0/src/tsr/core/tsr_chain.py +249 -0
  42. sstsr-2.0.0/src/tsr/core/utils.py +108 -0
  43. sstsr-2.0.0/src/tsr/hands/__init__.py +30 -0
  44. sstsr-2.0.0/src/tsr/hands/base.py +652 -0
  45. sstsr-2.0.0/src/tsr/hands/parallel_jaw.py +1302 -0
  46. sstsr-2.0.0/src/tsr/hands/registry.py +92 -0
  47. sstsr-2.0.0/src/tsr/io.py +99 -0
  48. sstsr-2.0.0/src/tsr/placement/__init__.py +20 -0
  49. sstsr-2.0.0/src/tsr/placement/_stable_poses.py +166 -0
  50. sstsr-2.0.0/src/tsr/placement/stable_placer.py +309 -0
  51. sstsr-2.0.0/src/tsr/sampling.py +251 -0
  52. sstsr-2.0.0/src/tsr/template.py +157 -0
  53. sstsr-2.0.0/src/tsr/templates/README.md +60 -0
  54. sstsr-2.0.0/src/tsr/templates/grasps/mug_handle_grasp.yaml +54 -0
  55. sstsr-2.0.0/src/tsr/templates/grasps/screwdriver_grasp.yaml +54 -0
  56. sstsr-2.0.0/src/tsr/templates/places/mug_on_table.yaml +52 -0
  57. sstsr-2.0.0/src/tsr/templates/places/toolchest_drop.yaml +55 -0
  58. sstsr-2.0.0/src/tsr/templates/tasks/drive_screw.yaml +55 -0
  59. sstsr-2.0.0/src/tsr/templates/tasks/mug_pour_into_sink.yaml +55 -0
  60. sstsr-2.0.0/src/tsr/templates/tasks/mug_transport_upright.yaml +55 -0
  61. sstsr-2.0.0/src/tsr/tsr.py +12 -0
  62. sstsr-2.0.0/src/tsr/tsr_chain.py +12 -0
  63. sstsr-2.0.0/src/tsr/utils.py +24 -0
  64. sstsr-2.0.0/src/tsr/viz.py +685 -0
  65. sstsr-2.0.0/tests/README.md +143 -0
  66. sstsr-2.0.0/tests/__init__.py +0 -0
  67. sstsr-2.0.0/tests/benchmarks/__init__.py +4 -0
  68. sstsr-2.0.0/tests/benchmarks/test_performance.py +179 -0
  69. sstsr-2.0.0/tests/tsr/__init__.py +0 -0
  70. sstsr-2.0.0/tests/tsr/_hypothesis_strategies.py +91 -0
  71. sstsr-2.0.0/tests/tsr/hands/__init__.py +0 -0
  72. sstsr-2.0.0/tests/tsr/hands/test_box_grasp.py +326 -0
  73. sstsr-2.0.0/tests/tsr/hands/test_parallel_jaw.py +257 -0
  74. sstsr-2.0.0/tests/tsr/hands/test_registry.py +63 -0
  75. sstsr-2.0.0/tests/tsr/hands/test_robotiq.py +48 -0
  76. sstsr-2.0.0/tests/tsr/hands/test_robotiq_2f85.py +58 -0
  77. sstsr-2.0.0/tests/tsr/hands/test_sphere_grasp.py +140 -0
  78. sstsr-2.0.0/tests/tsr/hands/test_torus_grasp.py +260 -0
  79. sstsr-2.0.0/tests/tsr/placement/__init__.py +0 -0
  80. sstsr-2.0.0/tests/tsr/placement/test_stable_placer.py +426 -0
  81. sstsr-2.0.0/tests/tsr/test_architecture.py +54 -0
  82. sstsr-2.0.0/tests/tsr/test_property_core.py +155 -0
  83. sstsr-2.0.0/tests/tsr/test_property_factories.py +155 -0
  84. sstsr-2.0.0/tests/tsr/test_regressions.py +109 -0
  85. sstsr-2.0.0/tests/tsr/test_sampling.py +338 -0
  86. sstsr-2.0.0/tests/tsr/test_serialization.py +356 -0
  87. sstsr-2.0.0/tests/tsr/test_tsr.py +426 -0
  88. sstsr-2.0.0/tests/tsr/test_tsr_chain.py +439 -0
  89. sstsr-2.0.0/tests/tsr/test_tsr_template.py +379 -0
  90. sstsr-2.0.0/tests/tsr/test_utils.py +194 -0
  91. sstsr-2.0.0/uv.lock +1617 -0
@@ -0,0 +1 @@
1
+ * @siddhss5
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report a reproducible bug
4
+ labels: bug
5
+ ---
6
+
7
+ ## Environment
8
+ - OS:
9
+ - Python version:
10
+ - uv version:
11
+ - Package version or commit:
12
+
13
+ ## Reproduction
14
+ <!-- Minimal steps to reproduce the problem. -->
15
+
16
+ ## Expected behavior
17
+
18
+ ## Actual behavior
19
+
20
+ ## Logs / traceback
21
+ ```
22
+ ```
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Questions and discussion
4
+ url: https://github.com/personalrobotics/robot-code/discussions
5
+ about: Ask questions or discuss design in the umbrella repo.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: Improvement
3
+ about: Propose an enhancement to existing functionality
4
+ labels: enhancement
5
+ ---
6
+
7
+ ## Motivation
8
+ <!-- What problem or limitation prompts this improvement? -->
9
+
10
+ ## Proposal
11
+ <!-- What should change, concretely? -->
12
+
13
+ ## Alternatives considered
@@ -0,0 +1,12 @@
1
+ ---
2
+ name: Task
3
+ about: A planned unit of work
4
+ labels: task
5
+ ---
6
+
7
+ ## Goal
8
+
9
+ ## Acceptance criteria
10
+ - [ ]
11
+
12
+ ## Notes
@@ -0,0 +1,24 @@
1
+ ## Summary
2
+
3
+ <!-- One or two sentences describing what this PR does and why. -->
4
+
5
+ ## Changes
6
+
7
+ <!-- Bulleted list of the concrete changes made. -->
8
+ -
9
+
10
+ ## Testing
11
+
12
+ - [ ] `uv run pytest tests/ -v` passes
13
+ - [ ] `uv run ruff check .` passes
14
+ - [ ] `uv run ruff format --check .` passes
15
+ - [ ] Integration tested locally against the robot-code workspace (if cross-repo)
16
+
17
+ ## Breaking changes
18
+
19
+ - [ ] None
20
+ - [ ] Yes (describe migration below):
21
+
22
+ ## Related issues
23
+
24
+ <!-- e.g. Fixes #123, Part of personalrobotics/robot-code#3 -->
@@ -0,0 +1,53 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: ci-${{ github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ test:
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+
24
+ - name: Set up uv
25
+ uses: astral-sh/setup-uv@v5
26
+ with:
27
+ enable-cache: true
28
+ python-version: ${{ matrix.python-version }}
29
+
30
+ - name: Install dependencies
31
+ run: uv sync --all-extras --dev
32
+
33
+ - name: Ruff lint
34
+ run: uv run ruff check .
35
+
36
+ - name: Ruff format check
37
+ run: uv run ruff format --check .
38
+
39
+ - name: Pytest
40
+ run: uv run pytest tests/ -v
41
+
42
+ notify-robot-code:
43
+ needs: test
44
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
45
+ runs-on: ubuntu-latest
46
+ steps:
47
+ - name: Dispatch integration run
48
+ uses: peter-evans/repository-dispatch@v3
49
+ with:
50
+ token: ${{ secrets.ROBOT_CODE_DISPATCH_TOKEN }}
51
+ repository: personalrobotics/robot-code
52
+ event-type: sibling-updated
53
+ client-payload: '{"repo":"${{ github.event.repository.name }}","sha":"${{ github.sha }}"}'
@@ -0,0 +1,110 @@
1
+ name: Release
2
+
3
+ # Tag-driven release pipeline.
4
+ #
5
+ # Tag patterns:
6
+ # v*rc* -> build sdist + wheel, publish to TestPyPI (dry run)
7
+ # v* -> build sdist + wheel, publish to real PyPI + GitHub Release
8
+ # (manual workflow_dispatch also builds + publishes to TestPyPI)
9
+ #
10
+ # Auth: Trusted Publishing (PyPI / TestPyPI OIDC). No API tokens in CI.
11
+ # The publish jobs run inside named GitHub environments (`release` /
12
+ # `testpypi-release`) so the org's environment-protection rules apply.
13
+ #
14
+ # sstsr is pure Python, so a single `uv build` produces both artifacts.
15
+
16
+ on:
17
+ push:
18
+ tags: ["v*"]
19
+ workflow_dispatch:
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ jobs:
25
+ build:
26
+ name: Build sdist + wheel
27
+ runs-on: ubuntu-latest
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with:
31
+ fetch-depth: 0
32
+
33
+ - name: Set up uv
34
+ uses: astral-sh/setup-uv@v5
35
+
36
+ - name: Build
37
+ run: uv build
38
+
39
+ - name: Check metadata
40
+ run: uvx twine check dist/*
41
+
42
+ - name: Upload artifacts
43
+ uses: actions/upload-artifact@v4
44
+ with:
45
+ name: dist
46
+ path: dist/*
47
+
48
+ publish_testpypi:
49
+ name: Publish → TestPyPI
50
+ needs: build
51
+ runs-on: ubuntu-latest
52
+ # RC tags (e.g. v2.0.0rc1) and manual triggers. The real PyPI job runs on
53
+ # non-RC v* tags only.
54
+ if: contains(github.ref, 'rc') || github.event_name == 'workflow_dispatch'
55
+ environment:
56
+ name: testpypi-release
57
+ url: https://test.pypi.org/p/sstsr
58
+ permissions:
59
+ id-token: write # Trusted Publishing OIDC
60
+ steps:
61
+ - uses: actions/download-artifact@v4
62
+ with:
63
+ name: dist
64
+ path: dist
65
+
66
+ - name: Publish to TestPyPI
67
+ uses: pypa/gh-action-pypi-publish@release/v1
68
+ with:
69
+ repository-url: https://test.pypi.org/legacy/
70
+
71
+ publish_pypi:
72
+ name: Publish → PyPI
73
+ needs: build
74
+ runs-on: ubuntu-latest
75
+ # Real PyPI: only on v* tags that DON'T contain 'rc' (e.g. v2.0.0).
76
+ if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'rc')
77
+ environment:
78
+ name: release
79
+ url: https://pypi.org/p/sstsr
80
+ permissions:
81
+ id-token: write
82
+ steps:
83
+ - uses: actions/download-artifact@v4
84
+ with:
85
+ name: dist
86
+ path: dist
87
+
88
+ - name: Publish to PyPI
89
+ uses: pypa/gh-action-pypi-publish@release/v1
90
+
91
+ github_release:
92
+ name: Create GitHub Release
93
+ needs: publish_pypi
94
+ runs-on: ubuntu-latest
95
+ if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'rc')
96
+ permissions:
97
+ contents: write
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ with:
101
+ fetch-depth: 0
102
+
103
+ - name: Create Release
104
+ uses: softprops/action-gh-release@v2
105
+ with:
106
+ tag_name: ${{ github.ref_name }}
107
+ name: sstsr ${{ github.ref_name }}
108
+ generate_release_notes: true
109
+ draft: false
110
+ prerelease: false
sstsr-2.0.0/.gitignore ADDED
@@ -0,0 +1,217 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be added to the global gitignore or merged into this project gitignore. For a PyCharm
158
+ # project, it is recommended to include the following files in version control:
159
+ # - .idea/modules.xml
160
+ # - .idea/*.iml
161
+ # - .idea/misc.xml
162
+ # - .idea/vcs.xml
163
+ # - .idea/workspace.xml
164
+ # - .idea/tasks.xml
165
+ # - .idea/usage.statistics.xml
166
+ # - .idea/shelf
167
+ # - .idea/dictionaries
168
+ # - .idea/inspectionProfiles
169
+ # - .idea/libraries
170
+ # - .idea/runConfigurations
171
+ # - .idea/scopes
172
+ # - .idea/tools
173
+ # - .idea/uiDesigner.xml
174
+ # - .idea/artifacts
175
+ # - .idea/compiler.xml
176
+ # - .idea/libraries with .xml
177
+ # - .idea/jarRepositories.xml
178
+ # - .idea/encodings.xml
179
+ # - .idea/misc.xml
180
+ # - .idea/modules.xml
181
+ # - .idea/*.iml
182
+ # - .idea/modules
183
+ # - *.iml
184
+ # - *.ipr
185
+ .idea/
186
+
187
+ # VS Code
188
+ .vscode/
189
+
190
+ # macOS
191
+ .DS_Store
192
+ .AppleDouble
193
+ .LSOverride
194
+
195
+ # Windows
196
+ Thumbs.db
197
+ ehthumbs.db
198
+ Desktop.ini
199
+
200
+ # Linux
201
+ *~
202
+
203
+ # ROS specific (if any remnants)
204
+ *.launch
205
+ *.urdf
206
+ *.sdf
207
+ *.world
208
+
209
+ # Temporary files
210
+ *.tmp
211
+ *.temp
212
+ *.swp
213
+ *.swo
214
+ *~
215
+
216
+ # uv specific
217
+ .uv/
@@ -0,0 +1,66 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
+ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [2.0.0] — 2026-09
8
+
9
+ First PyPI release. The distribution is named **`sstsr`** (the name `tsr` was
10
+ already taken); the import name is unchanged — `import tsr`.
11
+
12
+ ### Packaging & licensing
13
+ - **Distribution renamed to `sstsr`.** `pip install sstsr`, then `import tsr`.
14
+ - **Relicensed to BSD-2-Clause**, matching the original PrPy/OpenRAVE-derived TSR
15
+ core (resolves the prior README-vs-LICENSE mismatch).
16
+ - Grasp/hand classes (`ParallelJawGripper`, `Robotiq2F85`, `Robotiq2F140`,
17
+ `FrankaHand`) are now exported at the top level alongside `StablePlacer`.
18
+ - `tsr.__version__` is now available.
19
+ - Tested on Python 3.10–3.14 (classifiers and CI matrix extended to 3.13 and 3.14).
20
+
21
+ ### Breaking changes
22
+ - **`TablePlacer` removed** — use `tsr.placement.StablePlacer`.
23
+ - **`TSRChain.contains()` uses AND semantics** — a transform must satisfy all
24
+ TSRs in the chain simultaneously (was OR).
25
+ - **Grasp factories return `[]` for infeasible geometry instead of raising.**
26
+ `grasp_cylinder_*` and `grasp_sphere` previously raised `ValueError` when the
27
+ object exceeded the aperture; they now return `[]`, consistent with the box and
28
+ torus factories. Exceptions are reserved for invalid *arguments* (non-positive
29
+ sizes, `k < 1`, reversed `angle_range`). See `docs/ARCHITECTURE.md`.
30
+ - **Gripper geometry corrections** (change sampled poses for existing callers):
31
+ `Robotiq2F140` frame correction and `finger_length`; `FrankaHand.finger_length`
32
+ corrected to 54 mm; clearance is now scaled by graspable depth, not
33
+ `finger_length`.
34
+
35
+ ### Fixed
36
+ - **RPY near gimbal lock** (`rot_to_rpy`, `rot_within_rpy_bounds`): the
37
+ singularity threshold was far too wide (`1e-3`), snapping pitch to ±90° up to
38
+ ~2.5° early and discarding up to 0.04 rad of rotation. This made `contains()`
39
+ reject poses that `sample()` produced. Tightened to a true-singularity
40
+ threshold; round-trip error dropped from ~0.04 to ~1e-13.
41
+ - **`StablePlacer.place_mesh` seating**: objects whose center of mass is not at
42
+ the object-frame origin floated above or sank through the table. The resting
43
+ face now sits at `z = 0` for any COM.
44
+ - **`wrap_to_interval`** now guarantees a result in `[lower, lower + 2π)` (a
45
+ floating-point modulo artifact could return exactly `lower + 2π`).
46
+ - **`TSRChain.distance`** no longer crashes on outer (wrapping) rotation
47
+ intervals, and a single-TSR chain's `contains()` uses the exact closed-form
48
+ check instead of the optimiser.
49
+ - Degenerate meshes (fewer than 4 points, coplanar) raise a clear `ValueError`
50
+ instead of a raw SciPy `QhullError`.
51
+ - `grasp_*(k=0)` raises `ValueError` instead of `IndexError`; reversed
52
+ `angle_range` raises instead of silently collapsing yaw freedom.
53
+
54
+ ### Internal
55
+ - The pure-math core (`TSR`, `TSRChain`, SE(3) helpers) moved to a `tsr.core`
56
+ subpackage; deep imports such as `from tsr.tsr import TSR` still work via
57
+ back-compat shims.
58
+ - Added property-based tests (`hypothesis`) covering the core consistency
59
+ contract, serialization round-trips, and the factory invariants; added an
60
+ architecture-enforcement test (`tsr.core` has no upward imports; `import tsr`
61
+ pulls no heavy viz dependencies).
62
+ - Added `docs/REVIEW.md` (pre-release review) and `docs/ARCHITECTURE.md`.
63
+ - Removed the dead top-level `templates/` duplicate and the vestigial
64
+ `MANIFEST.in` (hatchling bundles the packaged `tsr/templates/` automatically).
65
+
66
+ [2.0.0]: https://github.com/personalrobotics/tsr/releases/tag/v2.0.0
@@ -0,0 +1,13 @@
1
+ # Code of Conduct
2
+
3
+ This project adopts the [Contributor Covenant, version 2.1][cc].
4
+
5
+ The full text is available at <https://www.contributor-covenant.org/version/2/1/code_of_conduct/>.
6
+
7
+ ## Reporting
8
+
9
+ Instances of unacceptable behavior may be reported privately to the project
10
+ maintainer at **siddhartha.srinivasa@gmail.com**. All reports will be
11
+ reviewed and investigated promptly and fairly.
12
+
13
+ [cc]: https://www.contributor-covenant.org/version/2/1/code_of_conduct/
@@ -0,0 +1,50 @@
1
+ # Contributing
2
+
3
+ This repository is part of the [robot-code workspace](https://github.com/personalrobotics/robot-code).
4
+ All projects in the workspace share a common layout (`src/` + `tests/`), a single
5
+ package manager (`uv`), and a common CI setup.
6
+
7
+ ## Development setup
8
+
9
+ ```bash
10
+ git clone https://github.com/personalrobotics/robot-code
11
+ cd robot-code
12
+ ./setup.sh
13
+ ```
14
+
15
+ This clones every sibling repo (including this one) into a single uv workspace
16
+ and runs `uv sync`. You can then work in any sibling's directory.
17
+
18
+ ## Running tests and linters
19
+
20
+ From inside this repo:
21
+
22
+ ```bash
23
+ uv run pytest tests/ -v
24
+ uv run ruff check .
25
+ uv run ruff format --check .
26
+ ```
27
+
28
+ From the workspace root, you can also run the cross-repo integration suite:
29
+
30
+ ```bash
31
+ uv run pytest tests/integration -v
32
+ ```
33
+
34
+ ## Pull requests
35
+
36
+ - Branch from `main`. Open a PR with a clear summary and test plan.
37
+ - Per-repo CI (ruff + pytest) must pass.
38
+ - Cross-repo integration CI in robot-code runs automatically when this repo's
39
+ `main` advances, and on scheduled nightly runs.
40
+ - Review is by [@siddhss5](https://github.com/siddhss5) (enforced via CODEOWNERS).
41
+
42
+ ## Package manager: uv only
43
+
44
+ We use [uv](https://docs.astral.sh/uv/) exclusively. **Do not use pip.**
45
+ The workspace layout in robot-code relies on uv's workspace resolution.
46
+
47
+ ## License
48
+
49
+ By contributing, you agree that your contributions will be licensed under the
50
+ MIT License (see [LICENSE](LICENSE)).
@@ -0,0 +1,11 @@
1
+ # Contributors
2
+
3
+ This project builds on earlier work by the robotics community. We acknowledge
4
+ the following original authors and contributors:
5
+
6
+ - **Dmitry Berenson**, **Siddhartha Srinivasa**, **James Kuffner** — original
7
+ TSR formulation, [IJRR 2011](https://www.ri.cmu.edu/pub_files/2011/10/dmitry_ijrr10-1.pdf).
8
+ - **Michael Koval** (Carnegie Mellon University, 2013) — early Python TSR
9
+ implementation that seeded this package.
10
+
11
+ Please submit pull requests to be added to this list.
sstsr-2.0.0/LICENSE ADDED
@@ -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.