long-tamp 0.1.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 (99) hide show
  1. long_tamp-0.1.0/LICENSE +21 -0
  2. long_tamp-0.1.0/PKG-INFO +225 -0
  3. long_tamp-0.1.0/README.md +177 -0
  4. long_tamp-0.1.0/pyproject.toml +126 -0
  5. long_tamp-0.1.0/setup.cfg +4 -0
  6. long_tamp-0.1.0/src/long_tamp/__init__.py +124 -0
  7. long_tamp-0.1.0/src/long_tamp/backends/__init__.py +66 -0
  8. long_tamp-0.1.0/src/long_tamp/backends/_hpp_libs.py +96 -0
  9. long_tamp-0.1.0/src/long_tamp/backends/_urdf_paths.py +89 -0
  10. long_tamp-0.1.0/src/long_tamp/backends/base.py +545 -0
  11. long_tamp-0.1.0/src/long_tamp/backends/pyhpp.py +2827 -0
  12. long_tamp-0.1.0/src/long_tamp/cli/__init__.py +265 -0
  13. long_tamp-0.1.0/src/long_tamp/cli/config_loader.py +89 -0
  14. long_tamp-0.1.0/src/long_tamp/cli/interactive_pickers.py +335 -0
  15. long_tamp-0.1.0/src/long_tamp/config/__init__.py +35 -0
  16. long_tamp-0.1.0/src/long_tamp/config/base_config.py +341 -0
  17. long_tamp-0.1.0/src/long_tamp/config/yaml_loader.py +456 -0
  18. long_tamp-0.1.0/src/long_tamp/logging/__init__.py +41 -0
  19. long_tamp-0.1.0/src/long_tamp/logging/log_loader.py +205 -0
  20. long_tamp-0.1.0/src/long_tamp/logging/run_logger.py +336 -0
  21. long_tamp-0.1.0/src/long_tamp/logging/schema.py +143 -0
  22. long_tamp-0.1.0/src/long_tamp/logging/setup.py +100 -0
  23. long_tamp-0.1.0/src/long_tamp/planning/__init__.py +76 -0
  24. long_tamp-0.1.0/src/long_tamp/planning/config.py +619 -0
  25. long_tamp-0.1.0/src/long_tamp/planning/constraints.py +955 -0
  26. long_tamp-0.1.0/src/long_tamp/planning/graph.py +1367 -0
  27. long_tamp-0.1.0/src/long_tamp/planning/grasp_state.py +443 -0
  28. long_tamp-0.1.0/src/long_tamp/planning/path_io.py +232 -0
  29. long_tamp-0.1.0/src/long_tamp/planning/path_recorder.py +668 -0
  30. long_tamp-0.1.0/src/long_tamp/planning/path_replay.py +315 -0
  31. long_tamp-0.1.0/src/long_tamp/planning/planner.py +73 -0
  32. long_tamp-0.1.0/src/long_tamp/planning/scene.py +479 -0
  33. long_tamp-0.1.0/src/long_tamp/planning/sequential_graph_factory.py +353 -0
  34. long_tamp-0.1.0/src/long_tamp/planning/sequential_grasp_filter.py +328 -0
  35. long_tamp-0.1.0/src/long_tamp/tasks/__init__.py +33 -0
  36. long_tamp-0.1.0/src/long_tamp/tasks/base.py +965 -0
  37. long_tamp-0.1.0/src/long_tamp/tasks/block_recovery.py +396 -0
  38. long_tamp-0.1.0/src/long_tamp/tasks/grasp_sequence.py +4827 -0
  39. long_tamp-0.1.0/src/long_tamp/tasks/interactive_grasp_sequence_builder.py +599 -0
  40. long_tamp-0.1.0/src/long_tamp/tasks/mission_checkpoint.py +151 -0
  41. long_tamp-0.1.0/src/long_tamp/tasks/sequence_orchestrator.py +314 -0
  42. long_tamp-0.1.0/src/long_tamp/tasks/task_planning/__init__.py +16 -0
  43. long_tamp-0.1.0/src/long_tamp/tasks/task_planning/capabilities.py +82 -0
  44. long_tamp-0.1.0/src/long_tamp/tasks/task_planning/compiler.py +112 -0
  45. long_tamp-0.1.0/src/long_tamp/tasks/task_planning/host.py +135 -0
  46. long_tamp-0.1.0/src/long_tamp/tasks/task_planning/model.py +192 -0
  47. long_tamp-0.1.0/src/long_tamp/tasks/task_planning/session.py +149 -0
  48. long_tamp-0.1.0/src/long_tamp/utils/__init__.py +49 -0
  49. long_tamp-0.1.0/src/long_tamp/utils/interactive.py +248 -0
  50. long_tamp-0.1.0/src/long_tamp/utils/transforms.py +267 -0
  51. long_tamp-0.1.0/src/long_tamp/version.py +3 -0
  52. long_tamp-0.1.0/src/long_tamp/visualization/__init__.py +64 -0
  53. long_tamp-0.1.0/src/long_tamp/visualization/live_graph_viz.py +581 -0
  54. long_tamp-0.1.0/src/long_tamp/visualization/video_recorder.py +399 -0
  55. long_tamp-0.1.0/src/long_tamp/visualization/viz.py +987 -0
  56. long_tamp-0.1.0/src/long_tamp.egg-info/PKG-INFO +225 -0
  57. long_tamp-0.1.0/src/long_tamp.egg-info/SOURCES.txt +97 -0
  58. long_tamp-0.1.0/src/long_tamp.egg-info/dependency_links.txt +1 -0
  59. long_tamp-0.1.0/src/long_tamp.egg-info/requires.txt +29 -0
  60. long_tamp-0.1.0/src/long_tamp.egg-info/top_level.txt +1 -0
  61. long_tamp-0.1.0/tests/test_backend_optimizer_timeout.py +41 -0
  62. long_tamp-0.1.0/tests/test_block_recovery.py +257 -0
  63. long_tamp-0.1.0/tests/test_config_seed.py +40 -0
  64. long_tamp-0.1.0/tests/test_core.py +114 -0
  65. long_tamp-0.1.0/tests/test_graph_factory_visited_memo.py +289 -0
  66. long_tamp-0.1.0/tests/test_grasp_release_capabilities.py +264 -0
  67. long_tamp-0.1.0/tests/test_grasp_release_use_case_twin.py +200 -0
  68. long_tamp-0.1.0/tests/test_grasp_sequence_helpers.py +158 -0
  69. long_tamp-0.1.0/tests/test_grasp_sequence_logging.py +327 -0
  70. long_tamp-0.1.0/tests/test_grasp_sequence_phase_q_hints.py +372 -0
  71. long_tamp-0.1.0/tests/test_grasp_sequence_resume_state.py +187 -0
  72. long_tamp-0.1.0/tests/test_grasp_state_copy.py +76 -0
  73. long_tamp-0.1.0/tests/test_logging_setup.py +99 -0
  74. long_tamp-0.1.0/tests/test_lookahead_also_reachable.py +219 -0
  75. long_tamp-0.1.0/tests/test_mission_checkpoint.py +79 -0
  76. long_tamp-0.1.0/tests/test_path_recorder.py +789 -0
  77. long_tamp-0.1.0/tests/test_path_replay.py +262 -0
  78. long_tamp-0.1.0/tests/test_plan_phase_edges_generation_retry.py +261 -0
  79. long_tamp-0.1.0/tests/test_planning_helpers.py +270 -0
  80. long_tamp-0.1.0/tests/test_problem_distance_refresh.py +68 -0
  81. long_tamp-0.1.0/tests/test_pruned_recursion.py +306 -0
  82. long_tamp-0.1.0/tests/test_pyhpp.py +646 -0
  83. long_tamp-0.1.0/tests/test_refactored_modules.py +316 -0
  84. long_tamp-0.1.0/tests/test_release_frozen_arms.py +230 -0
  85. long_tamp-0.1.0/tests/test_resume_start_config.py +142 -0
  86. long_tamp-0.1.0/tests/test_run_logger.py +348 -0
  87. long_tamp-0.1.0/tests/test_sequence_orchestrator.py +384 -0
  88. long_tamp-0.1.0/tests/test_sequential_filter.py +306 -0
  89. long_tamp-0.1.0/tests/test_task_base_helpers.py +591 -0
  90. long_tamp-0.1.0/tests/test_task_plan_compiler.py +187 -0
  91. long_tamp-0.1.0/tests/test_task_planning_host.py +17 -0
  92. long_tamp-0.1.0/tests/test_task_planning_ir.py +134 -0
  93. long_tamp-0.1.0/tests/test_task_planning_session.py +92 -0
  94. long_tamp-0.1.0/tests/test_twin_examples.py +100 -0
  95. long_tamp-0.1.0/tests/test_twin_regrasp_bt_session.py +136 -0
  96. long_tamp-0.1.0/tests/test_urdf_mesh_paths.py +59 -0
  97. long_tamp-0.1.0/tests/test_video_output_dir_default.py +110 -0
  98. long_tamp-0.1.0/tests/test_viewers.py +459 -0
  99. long_tamp-0.1.0/tests/test_yaml_loader_paths.py +64 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 CNRS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: long-tamp
3
+ Version: 0.1.0
4
+ Summary: Long-TAMP - Manipulation Planning Framework
5
+ Author-email: Thanh Nguyen <dvtnguyen@laas.fr>
6
+ Maintainer-email: Thanh Nguyen <dvtnguyen@laas.fr>
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/thanhndv212/long-tamp
9
+ Project-URL: Documentation, https://long-tamp.readthedocs.io
10
+ Project-URL: Repository, https://github.com/thanhndv212/long-tamp
11
+ Project-URL: Issues, https://github.com/thanhndv212/long-tamp/issues
12
+ Keywords: robotics,manipulation,motion-planning,hpp,agimus
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: numpy>=1.26
24
+ Requires-Dist: pyyaml>=5.1
25
+ Requires-Dist: pin>=2.6
26
+ Requires-Dist: viser
27
+ Requires-Dist: trimesh
28
+ Requires-Dist: pycollada
29
+ Provides-Extra: hpp
30
+ Requires-Dist: hpp-python>=9.0.2; extra == "hpp"
31
+ Requires-Dist: hpp-gepetto-viewer>=9.0.2; extra == "hpp"
32
+ Provides-Extra: toppra
33
+ Requires-Dist: hpp-toppra>=9.0.2; extra == "toppra"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=6.0; extra == "dev"
36
+ Requires-Dist: pytest-cov; extra == "dev"
37
+ Requires-Dist: black; extra == "dev"
38
+ Requires-Dist: ruff; extra == "dev"
39
+ Requires-Dist: sphinx; extra == "dev"
40
+ Requires-Dist: sphinx-rtd-theme; extra == "dev"
41
+ Provides-Extra: docs
42
+ Requires-Dist: mkdocs>=1.6; extra == "docs"
43
+ Requires-Dist: mkdocs-material>=9.5; extra == "docs"
44
+ Requires-Dist: mkdocs-include-markdown-plugin>=7.0; extra == "docs"
45
+ Provides-Extra: all
46
+ Requires-Dist: long-tamp[dev,docs]; extra == "all"
47
+ Dynamic: license-file
48
+
49
+ # Long-TAMP - Long-Horizon Task-and-Motion Planning
50
+
51
+ Long-horizon, multi-arm task-and-motion planning (TAMP) for manipulation, built on HPP (Humanoid Path Planner).
52
+
53
+ `long_tamp` plans **long, multi-step manipulation sequences** for **several robot arms** on **many movable objects** in a shared scene. **Motion planning** is HPP's constraint-graph planner, driven through a plain-Python task API. **Task planning** is a declarative task plan compiled to **BehaviorTree.CPP**, for standalone, ROS-free mission execution (see *Task Planning* below).
54
+
55
+ ## Capabilities
56
+
57
+ - **Long-horizon sequence planning.** `GraspSequencePlanner` chains an arbitrary number of grasp/place/hand-over phases, each with its own minimal phase-local constraint graph, so planning cost grows **linearly (O(N))** with the number of grasps instead of combinatorially (**O(N!)**).
58
+ - **Multiple robots & objects.** The scene composes several arms into one shared, mutually-collision-aware planning model — able to act independently, cooperate, or hand off objects — alongside any number of free-flying objects/tools, with grasp legality data-driven via `VALID_PAIRS` so adding one is a config change.
59
+ - **Reproducibility, introspection & crash recovery.** Crash-safe JSONL run logging plus a path-capture mechanism (`PathRecorder`) record every phase/edge/path so a run can be replayed, continuity-checked, and checkpointed/resumed rather than replanned from scratch.
60
+ - **Declarative task planning → BehaviorTree.CPP.** A versioned, capability-checked task plan (`tasks/task_planning/`) compiles deterministically to a BehaviorTree.CPP tree, run by a standalone C++ host through an embedded-CPython bridge with no ROS and no network hop (see *Task Planning* below).
61
+ - **Scene visualization.** Interactive 3D viewers: browser-based **viser** (default, no X11) or **gepetto-viewer** (Qt).
62
+
63
+ ## Installation
64
+
65
+ `long_tamp` has two dependency tiers: a pure-Python tier, and the HPP native bindings
66
+ (`hpp-python`, `hpp-toppra`, `hpp-gepetto-viewer`) — C++ extension modules.
67
+
68
+ | Platform | Pure-Python tier (`pip install -e .`) | HPP native bindings |
69
+ |---|---|---|
70
+ | Linux x86_64/aarch64 | ✅ PyPI | ✅ PyPI — `pip install -e ".[hpp,toppra]"` |
71
+ | macOS | ✅ PyPI | ❌ no wheels (PyPI, conda-forge, robotpkg) — needs Docker/Linux |
72
+ | Windows | untested | untested — likely needs Docker/WSL2 |
73
+
74
+ On Linux, everything installs from PyPI in one command, no system packages or Docker
75
+ required. Elsewhere, the pure-Python tier still installs natively via pip, but the planner
76
+ itself needs a Linux environment for the native bindings — see
77
+ [`docs/INSTALL.md`](docs/INSTALL.md) for the robotpkg/source-build/Docker fallback, the
78
+ CMake install path, the NumPy ABI pitfall (robotpkg wants NumPy 1.x, the PyPI wheels want
79
+ NumPy 2.x — don't mix them), and runtime backend detection.
80
+
81
+ ## Usage
82
+
83
+ Writing a task means implementing `ManipulationTask`'s lifecycle contract (`get_objects()`,
84
+ `create_constraints()`, `create_graph()`, `build_initial_config()`,
85
+ `generate_configurations()`, then `setup()` / `run()`) — either by hand, or, for new tasks,
86
+ via a declarative YAML config (recommended). Full, runnable examples live in
87
+ [`docs/usage/standalone-usage.md`](docs/usage/standalone-usage.md) §§4–6 rather than
88
+ duplicated here, alongside multi-phase sequences, resume/replay/checkpoints, and backend
89
+ selection.
90
+
91
+ - **Start from a template**: `script/templates/task_config_template.yaml` +
92
+ `task_my_task.py` — copy, fill in the `<PLACEHOLDER>`s, run.
93
+ - **Read a real, minimal example**: `script/twin/task_lift_ball.py` (bimanual scene).
94
+
95
+ ## Package structure & architecture
96
+
97
+ `tasks/` orchestrates `planning/`, which is backend-agnostic and depends only on `backends/`
98
+ (the one place HPP-specific bindings are imported); `config/`, `logging/`, `visualization/`,
99
+ `utils/`, and `cli/` are horizontal support layers used from `tasks/` and `script/`.
100
+
101
+ ```mermaid
102
+ flowchart TB
103
+ script["script/<br/>end-user task scripts<br/>(one per robot/mission)"]
104
+ tasks["tasks/<br/>ManipulationTask, GraspSequencePlanner,<br/>InteractiveGraspSequenceBuilder"]
105
+ planning["planning/<br/>SceneBuilder, ConstraintBuilder, GraphBuilder,<br/>ConfigGenerator, GraspStateTracker,<br/>SequentialConstraintGraphFactory,<br/>SequentialGraspFilter, path_io,<br/>path_recorder, path_replay"]
106
+ backends["backends/<br/>BackendBase (ABC) → PyHPPBackend<br/>only layer importing pyhpp.*"]
107
+
108
+ config["config/<br/>BaseTaskConfig, YamlTaskLoader"]
109
+ logging_["logging/<br/>RunLogger, JSONL event schema"]
110
+ viz["visualization/<br/>graph diagrams, frame display, video"]
111
+ utils["utils/<br/>transforms, interactive menus"]
112
+ cli["cli/<br/>argparse helpers, interactive pickers"]
113
+
114
+ script --> tasks
115
+ tasks --> planning
116
+ planning --> backends
117
+
118
+ tasks -.uses.-> config
119
+ tasks -.uses.-> logging_
120
+ tasks -.uses.-> viz
121
+ script -.uses.-> cli
122
+ cli -.uses.-> utils
123
+ config -.uses.-> utils
124
+
125
+ style backends fill:#4c566a,stroke:#2e3440,color:#fff
126
+ style planning fill:#5e81ac,stroke:#2e3440,color:#fff
127
+ style tasks fill:#81a1c1,stroke:#2e3440,color:#fff
128
+ style script fill:#88c0d0,stroke:#2e3440,color:#000
129
+ ```
130
+
131
+ Per-phase planning data flow, the loop every mission ultimately runs through:
132
+
133
+ ```mermaid
134
+ flowchart TD
135
+ yaml["YAML config"] -->|YamlTaskLoader| loaded["file_paths, joint_bounds_class, task_config"]
136
+ loaded --> setup["ManipulationTask.setup"]
137
+
138
+ setup --> scene["SceneBuilder<br/>load robots, env, objects"]
139
+ setup --> constraints["ConstraintBuilder /<br/>FactoryConstraintRegistry"]
140
+ setup --> gbuild["GraphBuilder<br/>factory or manual"]
141
+
142
+ scene --> plan["GraspSequencePlanner.plan_sequence"]
143
+ constraints --> plan
144
+ gbuild --> plan
145
+
146
+ plan --> p1["1. build_phase_graph<br/>GraphBuilder plus SequentialConstraintGraphFactory"]
147
+ p1 --> p2["2. GraspStateTracker picks the edge name"]
148
+ p2 --> p3["3. ConfigGenerator.generate_via_edge builds target config"]
149
+ p3 --> p4["4. backend.solve builds the path, then optimize and time-parameterize"]
150
+ p4 --> p5["5. RunLogger.log phase_end, optional auto-save of path"]
151
+ p5 -->|next phase| p1
152
+ p5 --> result["concatenated multi-phase path, O of N planning cost"]
153
+ ```
154
+
155
+ Both diagrams are copied from **[`ARCHITECTURE.md`](ARCHITECTURE.md)**, which is the
156
+ maintained source — it's dated at the top and covers dependency direction and what each
157
+ class does in more depth than fits here. If the two ever disagree, trust `ARCHITECTURE.md`
158
+ and update this copy to match.
159
+
160
+ ## Task Planning (BehaviorTree.CPP)
161
+
162
+ Alongside the plain-Python `ManipulationTask` API, `tasks/task_planning/` is a second,
163
+ declarative entry point: a versioned JSON **TaskPlan IR** (`sequence` / `fallback` / `retry` /
164
+ `condition` / `operation` / `transaction` nodes), validated against a `CapabilityRegistry`,
165
+ compiles deterministically to a **BehaviorTree.CPP** tree. A standalone C++ host
166
+ (`examples/behaviortree/`) runs that tree via an in-process, embedded-CPython bridge — one
167
+ process, no ROS, no network hop. It ships with built-in checkpoint/resume and path-capture
168
+ validation for long, restartable missions, and is the intended integration point for a future
169
+ model-proposed (VLM/LLM) plan.
170
+
171
+ | Stage | File |
172
+ |-------|------|
173
+ | IR validation & fingerprinting | `tasks/task_planning/model.py` (`TaskPlan`) |
174
+ | Capability policy | `tasks/task_planning/capabilities.py` (`CapabilityRegistry`) |
175
+ | IR → BT XML compiler | `tasks/task_planning/compiler.py` |
176
+ | C++ host + CPython bridge | `examples/behaviortree/` |
177
+
178
+ Build with `-DBUILD_BEHAVIORTREE_EXAMPLES=ON`. Full IR schema, the compiler's node mapping,
179
+ build/run steps, checkpointing, and how to add a mission or capability:
180
+ [`docs/usage/behaviortree-integration.md`](docs/usage/behaviortree-integration.md).
181
+
182
+ ## Run Logging
183
+
184
+ `long_tamp` includes a structured run logger that writes a crash-safe JSONL event
185
+ stream for every planning run — one event per phase/edge attempt, plus a JSON snapshot and a
186
+ replay-ready YAML on close. Use it to replay configurations, debug failures, and audit
187
+ results.
188
+
189
+ Logging is **on by default** for every `ManipulationTask` (`log_dir="auto"` creates
190
+ `/tmp/long_tamp/<task_slug>_<timestamp>/`; pass an explicit path to redirect it, or
191
+ `None` to disable). `RunLogger` also works standalone, independent of `ManipulationTask`.
192
+
193
+ | Event | When emitted |
194
+ |-------|-------------|
195
+ | `run_start` | `ManipulationTask.__init__` (with `log_dir`) |
196
+ | `config_snapshot` | `setup()` — full `BaseTaskConfig` + setup params |
197
+ | `sequence_start` | Start of `plan_sequence()` — all call params + `q_init` |
198
+ | `phase_start` | Before each grasp phase — `gripper`, `handle`, `q_start` |
199
+ | `edge_start` | Before each transition edge attempt |
200
+ | `edge_end` | After each edge — `success`, timing, `q_to` or `error` |
201
+ | `phase_end` | After each phase — timing, `state_after`, saved files |
202
+ | `run_end` | On normal return or `KeyboardInterrupt` |
203
+
204
+ For runnable examples — standalone use, inspecting a log afterward
205
+ (`print_run_summary`/`load_run_log`/`get_replay_config`), and configuring the underlying
206
+ Python `logging` hierarchy — see [`docs/usage/standalone-usage.md`](docs/usage/standalone-usage.md) §10.
207
+
208
+ ## Documentation
209
+
210
+ - **Installation**: [`docs/INSTALL.md`](docs/INSTALL.md) — pip (primary), robotpkg/source-build fallback, CMake install path, optional extras, backend detection.
211
+ - **Architecture**: [`ARCHITECTURE.md`](ARCHITECTURE.md) — module layering, dependency direction, data flow. Dated at the top; check it before trusting a claim about what exists.
212
+ - **Usage guide (living reference)**: [`docs/usage/standalone-usage.md`](docs/usage/standalone-usage.md) — writing a task, multi-phase sequences, resume/replay/checkpoints, backends, example scripts.
213
+ - **Development report**: [`docs/legacy/report/development-report.md`](docs/legacy/report/development-report.md) — *why* the framework is built this way: architecture decisions vs. bare HPP, measured before/after numbers, project timeline, and a bugs-found appendix. A point-in-time report, not a living reference.
214
+ - **Design rationale for specific mechanisms**: [`docs/features/`](docs/features/); **upstream HPP defects worked around here**: [`docs/bugs/`](docs/bugs/).
215
+ - **API Reference**: See docstrings in source files.
216
+ - **ROS-free BehaviorTree.CPP integration**: [`docs/usage/behaviortree-integration.md`](docs/usage/behaviortree-integration.md).
217
+
218
+ ## License
219
+
220
+ MIT - See [LICENSE](LICENSE) file
221
+
222
+
223
+ ---
224
+
225
+ **Last Updated**: 2026-09-02
@@ -0,0 +1,177 @@
1
+ # Long-TAMP - Long-Horizon Task-and-Motion Planning
2
+
3
+ Long-horizon, multi-arm task-and-motion planning (TAMP) for manipulation, built on HPP (Humanoid Path Planner).
4
+
5
+ `long_tamp` plans **long, multi-step manipulation sequences** for **several robot arms** on **many movable objects** in a shared scene. **Motion planning** is HPP's constraint-graph planner, driven through a plain-Python task API. **Task planning** is a declarative task plan compiled to **BehaviorTree.CPP**, for standalone, ROS-free mission execution (see *Task Planning* below).
6
+
7
+ ## Capabilities
8
+
9
+ - **Long-horizon sequence planning.** `GraspSequencePlanner` chains an arbitrary number of grasp/place/hand-over phases, each with its own minimal phase-local constraint graph, so planning cost grows **linearly (O(N))** with the number of grasps instead of combinatorially (**O(N!)**).
10
+ - **Multiple robots & objects.** The scene composes several arms into one shared, mutually-collision-aware planning model — able to act independently, cooperate, or hand off objects — alongside any number of free-flying objects/tools, with grasp legality data-driven via `VALID_PAIRS` so adding one is a config change.
11
+ - **Reproducibility, introspection & crash recovery.** Crash-safe JSONL run logging plus a path-capture mechanism (`PathRecorder`) record every phase/edge/path so a run can be replayed, continuity-checked, and checkpointed/resumed rather than replanned from scratch.
12
+ - **Declarative task planning → BehaviorTree.CPP.** A versioned, capability-checked task plan (`tasks/task_planning/`) compiles deterministically to a BehaviorTree.CPP tree, run by a standalone C++ host through an embedded-CPython bridge with no ROS and no network hop (see *Task Planning* below).
13
+ - **Scene visualization.** Interactive 3D viewers: browser-based **viser** (default, no X11) or **gepetto-viewer** (Qt).
14
+
15
+ ## Installation
16
+
17
+ `long_tamp` has two dependency tiers: a pure-Python tier, and the HPP native bindings
18
+ (`hpp-python`, `hpp-toppra`, `hpp-gepetto-viewer`) — C++ extension modules.
19
+
20
+ | Platform | Pure-Python tier (`pip install -e .`) | HPP native bindings |
21
+ |---|---|---|
22
+ | Linux x86_64/aarch64 | ✅ PyPI | ✅ PyPI — `pip install -e ".[hpp,toppra]"` |
23
+ | macOS | ✅ PyPI | ❌ no wheels (PyPI, conda-forge, robotpkg) — needs Docker/Linux |
24
+ | Windows | untested | untested — likely needs Docker/WSL2 |
25
+
26
+ On Linux, everything installs from PyPI in one command, no system packages or Docker
27
+ required. Elsewhere, the pure-Python tier still installs natively via pip, but the planner
28
+ itself needs a Linux environment for the native bindings — see
29
+ [`docs/INSTALL.md`](docs/INSTALL.md) for the robotpkg/source-build/Docker fallback, the
30
+ CMake install path, the NumPy ABI pitfall (robotpkg wants NumPy 1.x, the PyPI wheels want
31
+ NumPy 2.x — don't mix them), and runtime backend detection.
32
+
33
+ ## Usage
34
+
35
+ Writing a task means implementing `ManipulationTask`'s lifecycle contract (`get_objects()`,
36
+ `create_constraints()`, `create_graph()`, `build_initial_config()`,
37
+ `generate_configurations()`, then `setup()` / `run()`) — either by hand, or, for new tasks,
38
+ via a declarative YAML config (recommended). Full, runnable examples live in
39
+ [`docs/usage/standalone-usage.md`](docs/usage/standalone-usage.md) §§4–6 rather than
40
+ duplicated here, alongside multi-phase sequences, resume/replay/checkpoints, and backend
41
+ selection.
42
+
43
+ - **Start from a template**: `script/templates/task_config_template.yaml` +
44
+ `task_my_task.py` — copy, fill in the `<PLACEHOLDER>`s, run.
45
+ - **Read a real, minimal example**: `script/twin/task_lift_ball.py` (bimanual scene).
46
+
47
+ ## Package structure & architecture
48
+
49
+ `tasks/` orchestrates `planning/`, which is backend-agnostic and depends only on `backends/`
50
+ (the one place HPP-specific bindings are imported); `config/`, `logging/`, `visualization/`,
51
+ `utils/`, and `cli/` are horizontal support layers used from `tasks/` and `script/`.
52
+
53
+ ```mermaid
54
+ flowchart TB
55
+ script["script/<br/>end-user task scripts<br/>(one per robot/mission)"]
56
+ tasks["tasks/<br/>ManipulationTask, GraspSequencePlanner,<br/>InteractiveGraspSequenceBuilder"]
57
+ planning["planning/<br/>SceneBuilder, ConstraintBuilder, GraphBuilder,<br/>ConfigGenerator, GraspStateTracker,<br/>SequentialConstraintGraphFactory,<br/>SequentialGraspFilter, path_io,<br/>path_recorder, path_replay"]
58
+ backends["backends/<br/>BackendBase (ABC) → PyHPPBackend<br/>only layer importing pyhpp.*"]
59
+
60
+ config["config/<br/>BaseTaskConfig, YamlTaskLoader"]
61
+ logging_["logging/<br/>RunLogger, JSONL event schema"]
62
+ viz["visualization/<br/>graph diagrams, frame display, video"]
63
+ utils["utils/<br/>transforms, interactive menus"]
64
+ cli["cli/<br/>argparse helpers, interactive pickers"]
65
+
66
+ script --> tasks
67
+ tasks --> planning
68
+ planning --> backends
69
+
70
+ tasks -.uses.-> config
71
+ tasks -.uses.-> logging_
72
+ tasks -.uses.-> viz
73
+ script -.uses.-> cli
74
+ cli -.uses.-> utils
75
+ config -.uses.-> utils
76
+
77
+ style backends fill:#4c566a,stroke:#2e3440,color:#fff
78
+ style planning fill:#5e81ac,stroke:#2e3440,color:#fff
79
+ style tasks fill:#81a1c1,stroke:#2e3440,color:#fff
80
+ style script fill:#88c0d0,stroke:#2e3440,color:#000
81
+ ```
82
+
83
+ Per-phase planning data flow, the loop every mission ultimately runs through:
84
+
85
+ ```mermaid
86
+ flowchart TD
87
+ yaml["YAML config"] -->|YamlTaskLoader| loaded["file_paths, joint_bounds_class, task_config"]
88
+ loaded --> setup["ManipulationTask.setup"]
89
+
90
+ setup --> scene["SceneBuilder<br/>load robots, env, objects"]
91
+ setup --> constraints["ConstraintBuilder /<br/>FactoryConstraintRegistry"]
92
+ setup --> gbuild["GraphBuilder<br/>factory or manual"]
93
+
94
+ scene --> plan["GraspSequencePlanner.plan_sequence"]
95
+ constraints --> plan
96
+ gbuild --> plan
97
+
98
+ plan --> p1["1. build_phase_graph<br/>GraphBuilder plus SequentialConstraintGraphFactory"]
99
+ p1 --> p2["2. GraspStateTracker picks the edge name"]
100
+ p2 --> p3["3. ConfigGenerator.generate_via_edge builds target config"]
101
+ p3 --> p4["4. backend.solve builds the path, then optimize and time-parameterize"]
102
+ p4 --> p5["5. RunLogger.log phase_end, optional auto-save of path"]
103
+ p5 -->|next phase| p1
104
+ p5 --> result["concatenated multi-phase path, O of N planning cost"]
105
+ ```
106
+
107
+ Both diagrams are copied from **[`ARCHITECTURE.md`](ARCHITECTURE.md)**, which is the
108
+ maintained source — it's dated at the top and covers dependency direction and what each
109
+ class does in more depth than fits here. If the two ever disagree, trust `ARCHITECTURE.md`
110
+ and update this copy to match.
111
+
112
+ ## Task Planning (BehaviorTree.CPP)
113
+
114
+ Alongside the plain-Python `ManipulationTask` API, `tasks/task_planning/` is a second,
115
+ declarative entry point: a versioned JSON **TaskPlan IR** (`sequence` / `fallback` / `retry` /
116
+ `condition` / `operation` / `transaction` nodes), validated against a `CapabilityRegistry`,
117
+ compiles deterministically to a **BehaviorTree.CPP** tree. A standalone C++ host
118
+ (`examples/behaviortree/`) runs that tree via an in-process, embedded-CPython bridge — one
119
+ process, no ROS, no network hop. It ships with built-in checkpoint/resume and path-capture
120
+ validation for long, restartable missions, and is the intended integration point for a future
121
+ model-proposed (VLM/LLM) plan.
122
+
123
+ | Stage | File |
124
+ |-------|------|
125
+ | IR validation & fingerprinting | `tasks/task_planning/model.py` (`TaskPlan`) |
126
+ | Capability policy | `tasks/task_planning/capabilities.py` (`CapabilityRegistry`) |
127
+ | IR → BT XML compiler | `tasks/task_planning/compiler.py` |
128
+ | C++ host + CPython bridge | `examples/behaviortree/` |
129
+
130
+ Build with `-DBUILD_BEHAVIORTREE_EXAMPLES=ON`. Full IR schema, the compiler's node mapping,
131
+ build/run steps, checkpointing, and how to add a mission or capability:
132
+ [`docs/usage/behaviortree-integration.md`](docs/usage/behaviortree-integration.md).
133
+
134
+ ## Run Logging
135
+
136
+ `long_tamp` includes a structured run logger that writes a crash-safe JSONL event
137
+ stream for every planning run — one event per phase/edge attempt, plus a JSON snapshot and a
138
+ replay-ready YAML on close. Use it to replay configurations, debug failures, and audit
139
+ results.
140
+
141
+ Logging is **on by default** for every `ManipulationTask` (`log_dir="auto"` creates
142
+ `/tmp/long_tamp/<task_slug>_<timestamp>/`; pass an explicit path to redirect it, or
143
+ `None` to disable). `RunLogger` also works standalone, independent of `ManipulationTask`.
144
+
145
+ | Event | When emitted |
146
+ |-------|-------------|
147
+ | `run_start` | `ManipulationTask.__init__` (with `log_dir`) |
148
+ | `config_snapshot` | `setup()` — full `BaseTaskConfig` + setup params |
149
+ | `sequence_start` | Start of `plan_sequence()` — all call params + `q_init` |
150
+ | `phase_start` | Before each grasp phase — `gripper`, `handle`, `q_start` |
151
+ | `edge_start` | Before each transition edge attempt |
152
+ | `edge_end` | After each edge — `success`, timing, `q_to` or `error` |
153
+ | `phase_end` | After each phase — timing, `state_after`, saved files |
154
+ | `run_end` | On normal return or `KeyboardInterrupt` |
155
+
156
+ For runnable examples — standalone use, inspecting a log afterward
157
+ (`print_run_summary`/`load_run_log`/`get_replay_config`), and configuring the underlying
158
+ Python `logging` hierarchy — see [`docs/usage/standalone-usage.md`](docs/usage/standalone-usage.md) §10.
159
+
160
+ ## Documentation
161
+
162
+ - **Installation**: [`docs/INSTALL.md`](docs/INSTALL.md) — pip (primary), robotpkg/source-build fallback, CMake install path, optional extras, backend detection.
163
+ - **Architecture**: [`ARCHITECTURE.md`](ARCHITECTURE.md) — module layering, dependency direction, data flow. Dated at the top; check it before trusting a claim about what exists.
164
+ - **Usage guide (living reference)**: [`docs/usage/standalone-usage.md`](docs/usage/standalone-usage.md) — writing a task, multi-phase sequences, resume/replay/checkpoints, backends, example scripts.
165
+ - **Development report**: [`docs/legacy/report/development-report.md`](docs/legacy/report/development-report.md) — *why* the framework is built this way: architecture decisions vs. bare HPP, measured before/after numbers, project timeline, and a bugs-found appendix. A point-in-time report, not a living reference.
166
+ - **Design rationale for specific mechanisms**: [`docs/features/`](docs/features/); **upstream HPP defects worked around here**: [`docs/bugs/`](docs/bugs/).
167
+ - **API Reference**: See docstrings in source files.
168
+ - **ROS-free BehaviorTree.CPP integration**: [`docs/usage/behaviortree-integration.md`](docs/usage/behaviortree-integration.md).
169
+
170
+ ## License
171
+
172
+ MIT - See [LICENSE](LICENSE) file
173
+
174
+
175
+ ---
176
+
177
+ **Last Updated**: 2026-09-02
@@ -0,0 +1,126 @@
1
+ [build-system]
2
+ requires = ["setuptools>=45", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "long-tamp"
7
+ version = "0.1.0"
8
+ description = "Long-TAMP - Manipulation Planning Framework"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = {text = "MIT"}
12
+ authors = [
13
+ {name = "Thanh Nguyen", email = "dvtnguyen@laas.fr"}
14
+ ]
15
+ maintainers = [
16
+ {name = "Thanh Nguyen", email = "dvtnguyen@laas.fr"}
17
+ ]
18
+ keywords = ["robotics", "manipulation", "motion-planning", "hpp", "agimus"]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Science/Research",
22
+ "License :: OSI Approved :: MIT License",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.10",
25
+ "Programming Language :: Python :: 3.11",
26
+ "Topic :: Scientific/Engineering",
27
+ ]
28
+
29
+ # Hard runtime deps.
30
+ # numpy / pyyaml — imported unguarded in core modules (numpy, yaml_loader,
31
+ # utils/transforms).
32
+ # pin (pinocchio) — imported unguarded at module scope in utils/transforms.py
33
+ # (SE3, Quaternion, rpyToMatrix are used directly by its
34
+ # functions, not just for type hints), which every task
35
+ # config transitively imports. `import long_tamp` does not
36
+ # work without it — it is not actually optional.
37
+ # viser / trimesh / pycollada — the browser viewer (pyhpp_viser) is the
38
+ # default viewer, so its PyPI-side deps ship by default. The
39
+ # pyhpp_viser bindings themselves come from hpp-gepetto-viewer
40
+ # (see the [hpp] extra below).
41
+ dependencies = [
42
+ # No upper bound: the PyPI-native HPP stack (see [hpp] extra) is a cmeel
43
+ # build — cmeel-boost (a transitive dep of hpp-python) requires numpy>=2.
44
+ # A robotpkg/source-built HPP environment (see docs/INSTALL.md) is instead
45
+ # compiled against NumPy 1.x — install there with `pip install --no-deps
46
+ # -e .` so this constraint (and the `pin` one below) never gets a chance
47
+ # to pull in a PyPI NumPy 2.x / pinocchio that collides with it.
48
+ "numpy>=1.26",
49
+ "pyyaml>=5.1",
50
+ "pin>=2.6",
51
+ "viser",
52
+ "trimesh",
53
+ "pycollada",
54
+ ]
55
+
56
+ [project.optional-dependencies]
57
+ # The full native HPP stack, prebuilt (cmeel) wheels from PyPI — no robotpkg,
58
+ # no source build, no Docker. Linux only today (manylinux_2_28, x86_64/aarch64),
59
+ # Python 3.10-3.14 — see docs/INSTALL.md for the current platform matrix and
60
+ # the robotpkg/source-build fallback for unsupported platforms.
61
+ hpp = [
62
+ "hpp-python>=9.0.2",
63
+ "hpp-gepetto-viewer>=9.0.2",
64
+ ]
65
+
66
+ # TOPPRA time-parameterization (optional optimizer). Also a real PyPI (cmeel)
67
+ # wheel now — see docs/INSTALL.md.
68
+ toppra = [
69
+ "hpp-toppra>=9.0.2",
70
+ ]
71
+
72
+ dev = [
73
+ "pytest>=6.0",
74
+ "pytest-cov",
75
+ "black",
76
+ "ruff",
77
+ "sphinx",
78
+ "sphinx-rtd-theme",
79
+ ]
80
+
81
+ # MkDocs site over docs/ — `mkdocs serve` / `mkdocs build` (see mkdocs.yml).
82
+ docs = [
83
+ "mkdocs>=1.6",
84
+ "mkdocs-material>=9.5",
85
+ "mkdocs-include-markdown-plugin>=7.0",
86
+ ]
87
+
88
+ all = [
89
+ "long-tamp[dev,docs]",
90
+ ]
91
+
92
+ [project.urls]
93
+ Homepage = "https://github.com/thanhndv212/long-tamp"
94
+ Documentation = "https://long-tamp.readthedocs.io"
95
+ Repository = "https://github.com/thanhndv212/long-tamp"
96
+ Issues = "https://github.com/thanhndv212/long-tamp/issues"
97
+
98
+ [tool.setuptools.packages.find]
99
+ where = ["src"]
100
+
101
+ [tool.setuptools.package-data]
102
+ long_tamp = ["py.typed"]
103
+
104
+ [tool.ruff]
105
+ extend-exclude = ["cmake"]
106
+ line-length = 88
107
+
108
+ [tool.ruff.lint]
109
+ extend-select = ["I", "NPY", "RUF", "UP", "W"]
110
+
111
+ [tool.pytest.ini_options]
112
+ testpaths = ["tests"]
113
+ markers = ["slow_planning: real-scene planning checks run nightly in isolated processes"]
114
+ python_files = "test_*.py"
115
+ python_classes = "Test*"
116
+ python_functions = "test_*"
117
+ addopts = "-v --cov=long_tamp --cov-report=html --cov-report=term"
118
+
119
+ [tool.black]
120
+ line-length = 88
121
+ target-version = ['py310']
122
+ extend-exclude = '''
123
+ /(
124
+ | cmake
125
+ )/
126
+ '''
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+