openphysicalai 0.2.1__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.
- openphysicalai-0.2.1/PKG-INFO +203 -0
- openphysicalai-0.2.1/README.md +185 -0
- openphysicalai-0.2.1/openphysicalai/__init__.py +9 -0
- openphysicalai-0.2.1/openphysicalai/budget.py +59 -0
- openphysicalai-0.2.1/openphysicalai/cli.py +115 -0
- openphysicalai-0.2.1/openphysicalai/injection.py +64 -0
- openphysicalai-0.2.1/openphysicalai/interfaces.py +47 -0
- openphysicalai-0.2.1/openphysicalai/perception.py +237 -0
- openphysicalai-0.2.1/openphysicalai/planners.py +159 -0
- openphysicalai-0.2.1/openphysicalai/profiler.py +226 -0
- openphysicalai-0.2.1/openphysicalai/render.py +124 -0
- openphysicalai-0.2.1/openphysicalai/report.py +39 -0
- openphysicalai-0.2.1/openphysicalai/runner.py +401 -0
- openphysicalai-0.2.1/openphysicalai/server.py +113 -0
- openphysicalai-0.2.1/openphysicalai/sim.py +312 -0
- openphysicalai-0.2.1/openphysicalai/skills.py +50 -0
- openphysicalai-0.2.1/openphysicalai/stats.py +15 -0
- openphysicalai-0.2.1/openphysicalai/store.py +36 -0
- openphysicalai-0.2.1/openphysicalai/tasks.py +124 -0
- openphysicalai-0.2.1/openphysicalai.egg-info/PKG-INFO +203 -0
- openphysicalai-0.2.1/openphysicalai.egg-info/SOURCES.txt +27 -0
- openphysicalai-0.2.1/openphysicalai.egg-info/dependency_links.txt +1 -0
- openphysicalai-0.2.1/openphysicalai.egg-info/entry_points.txt +2 -0
- openphysicalai-0.2.1/openphysicalai.egg-info/requires.txt +13 -0
- openphysicalai-0.2.1/openphysicalai.egg-info/top_level.txt +1 -0
- openphysicalai-0.2.1/pyproject.toml +23 -0
- openphysicalai-0.2.1/setup.cfg +4 -0
- openphysicalai-0.2.1/tests/test_core.py +25 -0
- openphysicalai-0.2.1/tests/test_sim.py +32 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openphysicalai
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: OpenPhysicalAI Lab core: budget-aware, latency-coupled evaluation for Physical AI
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: mujoco>=3.1
|
|
9
|
+
Requires-Dist: numpy>=1.24
|
|
10
|
+
Requires-Dist: psutil>=5.9
|
|
11
|
+
Provides-Extra: sim
|
|
12
|
+
Requires-Dist: mujoco>=3.1; extra == "sim"
|
|
13
|
+
Provides-Extra: gpu
|
|
14
|
+
Requires-Dist: psutil; extra == "gpu"
|
|
15
|
+
Requires-Dist: nvidia-ml-py; extra == "gpu"
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Requires-Dist: pytest; extra == "dev"
|
|
18
|
+
|
|
19
|
+
<div align="center">
|
|
20
|
+
|
|
21
|
+
# 🤖 OpenPhysicalAI Lab (`v0.2.1`)
|
|
22
|
+
|
|
23
|
+
**Real-Time Embodied AI Simulation, Closed-Loop Failure Recovery & Hardware Budget Benchmarking — Engineered to Run Inside 4 GB VRAM.**
|
|
24
|
+
|
|
25
|
+
[](LICENSE)
|
|
26
|
+
[-brightgreen.svg)](#verified-benchmarks--scientific-results)
|
|
27
|
+
[](#system-architecture)
|
|
28
|
+
[-76b900.svg)](#community-hardware-leaderboard)
|
|
29
|
+
[](#quick-start)
|
|
30
|
+
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ⚡ Why OpenPhysicalAI Lab?
|
|
36
|
+
|
|
37
|
+
Most embodied AI frameworks assume you have a 24 GB RTX 4090 or an 80 GB datacenter GPU. **OpenPhysicalAI Lab** proves that deterministic 3D physics, vision perception, local LLM task planning, and closed-loop failure recovery can run **entirely locally on a 4 GB VRAM laptop (`OPAI-4G`)**.
|
|
38
|
+
|
|
39
|
+
Unlike static benchmarks that pause the physics engine while the LLM thinks, OpenPhysicalAI Lab enforces **Real-Time Mode**: the physical world keeps moving while the planner reasons, exposing the true **Latency Tax** of slow models and measuring capability under strict **VRAM, System RAM, Latency, and Energy (Joule) Budget Cards**.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🏗️ System Architecture
|
|
44
|
+
|
|
45
|
+
```mermaid
|
|
46
|
+
flowchart LR
|
|
47
|
+
subgraph Sim["MuJoCo 3.16 Real-Time Engine (432 FPS)"]
|
|
48
|
+
World["5-DOF Arm + Parallel Gripper\nTable, Cubes, Conveyor"]
|
|
49
|
+
Inject["Seeded Failure Injector\n(Slip, Displacement, Noise)"]
|
|
50
|
+
Render["3D OpenGL GPU Renderer\n(Shadows + Orthographic Vision)"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
subgraph Percep["Perception & Kinematics"]
|
|
54
|
+
Vision["Vision / Oracle Detector\n(~1 mm Accuracy)"]
|
|
55
|
+
Kalman["Alpha-Beta Velocity Tracker\n(Latency Lead Compensation)"]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
subgraph Agent["Closed-Loop Recovery Agent"]
|
|
59
|
+
Verifier["Tiered Verifiers\n(V0 Oracle | V1 Proprio | V2 Camera)"]
|
|
60
|
+
Planner["Local Ollama LLM Planner\n(Gemma 2 2B / Qwen3 4B JSON)"]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
subgraph Telemetry["NVML & Budget Auditor"]
|
|
64
|
+
Profiler["NVML + Ollama /api/ps\n(VRAM, RAM, Watts, Temp)"]
|
|
65
|
+
Card["SQLite + Signed\nBudget Card (.md / .csv)"]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
World --> Inject --> Render --> Vision --> Kalman
|
|
69
|
+
Kalman --> Verifier --> Planner
|
|
70
|
+
Planner -- "Hold Policy Advances World by Δt_plan" --> World
|
|
71
|
+
Sim -.-> Profiler --> Card
|
|
72
|
+
Agent -.-> Profiler
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## ✅ What Is Real & Verified
|
|
78
|
+
|
|
79
|
+
| Subsystem | Implementation Status |
|
|
80
|
+
|---|---|
|
|
81
|
+
| **Physics Engine** | Real MuJoCo 3.16.0: 5-DOF robotic arm, parallel friction gripper, table, multi-size cubes, open-top container, and kinematic moving conveyor. Analytic IK + Cartesian skill primitives. |
|
|
82
|
+
| **3D GPU Rendering** | Native `mujoco.Renderer` 3D perspective camera (distance 0.92 m, elevation -26°, azimuth 135°) with directional shadow mapping (~432 FPS / 2.3 ms/frame on RTX 3050 Laptop GPU) + 1 mm accurate orthographic vision pipeline. |
|
|
83
|
+
| **Phase-1 Gate** | Deterministic scripted pick-and-place passes **200/200 random scenes (100.0%)** (`python python/gate1.py`). |
|
|
84
|
+
| **Benchmark Tasks** | 5 seeded, cross-process deterministic tasks: `pick_place`, `smallest`, spatial (`left_of`), `multi_object`, and `dynamic` (moving conveyor cube). |
|
|
85
|
+
| **Local LLM Planners** | Rule-based baseline + Ollama local LLMs (`gemma2:2b`, `qwen3:4b-instruct-2507-q4_K_M`) with strict JSON-schema output and kinematic action validation. |
|
|
86
|
+
| **Agent Architectures** | Open-Loop (blind execution), Closed-Loop (abort on anomaly), and Recovery Agent (active failure detection, diagnosis, re-observation, and replanning). |
|
|
87
|
+
| **Hardware Profiler** | Tracks process-tree RSS, system RAM, NVML Compute/Graphics VRAM, Ollama `/api/ps` VRAM, GPU power (W), energy per episode (J), core temperature (°C), and thermal throttling. |
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 📊 Verified Benchmarks & Scientific Results
|
|
92
|
+
|
|
93
|
+
All benchmarks below were executed on an HP Victus 15 (**OPAI-4G Reference Tier**: NVIDIA GeForce RTX 3050 Laptop GPU 4.0 GB VRAM, 16 GB System RAM, Windows 11, MuJoCo 3.16.0).
|
|
94
|
+
|
|
95
|
+
### 1. Local LLM Planner Speed & Footprint (OPAI-4G Tier)
|
|
96
|
+
|
|
97
|
+
| Local Model (Ollama) | Weights Size | Peak Device VRAM | Warm Planning Latency | Throughput | Schema Compliance |
|
|
98
|
+
### 1. Local LLM Planner Speed & Footprint (OPAI-4G Tier, N=20 per Model, Real-Time Mode)
|
|
99
|
+
|
|
100
|
+
All models evaluated under identical real-time closed-loop pick-and-place tasks on an NVIDIA GeForce RTX 3050 Laptop GPU (4.0 GB VRAM):
|
|
101
|
+
|
|
102
|
+
| Local Model (Ollama) | Weights Size | Peak Device VRAM | Warm Planning Latency (p50 / p95) | Throughput | TSR (95% CI, N=20) | Notes |
|
|
103
|
+
|---|---|---|---|---|---|---|
|
|
104
|
+
| **`qwen2.5:3b`** | 1.9 GB | 2.57 GB | **469 ms / 493 ms** | 70.6 tok/s | **100.0%** (83.9%–100.0%) | Fastest response, reliable spatial parsing |
|
|
105
|
+
| **`gemma2:2b`** | 1.6 GB | 2.36 GB | **715 ms / 751 ms** | 69.5 tok/s | **100.0%** (83.9%–100.0%) | Consistent schema compliance & low footprint |
|
|
106
|
+
| **`llama3.2:1b`** | 1.3 GB | 1.97 GB | **577 ms / 608 ms** | 99.9 tok/s | **0.0%** (0.0%–16.1%) | Fast generation, but frequent JSON/action schema violations |
|
|
107
|
+
|
|
108
|
+
### 2. Verifier Honesty Benchmark (Moderate Perturbation, Real-Time Mode, N=100 per Cell)
|
|
109
|
+
|
|
110
|
+
Evaluated with Rule-Based Recovery Agent under moderate failure injection (slip probability $p=0.25$, displacement, and wrong placement). Raw JSON exported in `verifier_benchmark_summary_N100.json`:
|
|
111
|
+
|
|
112
|
+
| Agent | Verifier Level | Mode | TSR (95% CI, N=100) | Injections | Detect Rate | Recover Rate | Missed Failures | False Alarms | Planning p95 |
|
|
113
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
114
|
+
| **Recovery** | **V0 (Simulator Oracle)** | realtime | **74.0%** (64.6%–81.6%) | 138 | 97.1% | 52.2% | **0.0%** | 0.0% | 0.03 ms |
|
|
115
|
+
| **Recovery** | **V1 (Proprioception Only)** | realtime | **68.0%** (58.3%–76.3%) | 124 | 87.9% | 51.4% | **3.7%** | 0.0% | 0.03 ms |
|
|
116
|
+
| **Recovery** | **V2 (Proprio + Camera Vision)**| realtime | **73.0%** (63.6%–80.7%) | 137 | 96.4% | 51.5% | **0.3%** | 0.0% | 0.03 ms |
|
|
117
|
+
|
|
118
|
+
> [!IMPORTANT]
|
|
119
|
+
> **Key Verifier Finding**: Proprioceptive verification alone (`V1`) suffers a **3.7% missed-failure rate** because joint sensors cannot detect when a placed object lands outside the container boundary (`wrong_placement`). Vision verification (`V2`) closes this gap, reducing missed failures to **0.3%**, approaching oracle upper bound (`V0`).
|
|
120
|
+
|
|
121
|
+
### 3. The Latency Tax on Dynamic Conveyor Tasks
|
|
122
|
+
|
|
123
|
+
Measured on the `dynamic` task with moving cube at $0.02\text{ m/s}$, single-frame perception, without velocity lead compensation:
|
|
124
|
+
|
|
125
|
+
| Agent Architecture | Verifier | Execution Mode | Planner Delay ($\Delta t$) | TSR (95% CI, N=50) | Physical Mechanism |
|
|
126
|
+
|---|---|---|---|---|---|
|
|
127
|
+
| **Closed-Loop (Rule)** | V1 | sync | 0 ms | **38.0%** (25.9%–51.8%) | Physics paused while planning |
|
|
128
|
+
| **Closed-Loop (Rule)** | V1 | realtime | 0 ms | **38.0%** (25.9%–51.8%) | Real-time baseline |
|
|
129
|
+
| **Closed-Loop (Rule)** | V1 | realtime | 1,000 ms (1.0 s) | **0.0%** (0.0%–7.1%) | Cube shifts ~20 mm past gripper capture zone |
|
|
130
|
+
| **Closed-Loop (Rule)** | V1 | realtime | 2,000 ms (2.0 s) | **0.0%** (0.0%–7.1%) | Stale observation causes complete grasp miss |
|
|
131
|
+
| **Recovery (Velocity-Lead)**| V1 | realtime | 1,000 ms (1.0 s) | **100.0%** (72.2%–100.0%) | Forward-projected intercept overcomes latency tax |
|
|
132
|
+
|
|
133
|
+
> [!NOTE]
|
|
134
|
+
> Physical AI agents relying purely on reactive perception fail when planner latency exceeds the physical dynamic timescale. Latency compensation (velocity projection $\hat{v} \cdot (\tau_{\text{plan}} + \tau_{\text{travel}})$) restores 100% reliability even at multi-second planning delays.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 🚀 Quick Start
|
|
139
|
+
|
|
140
|
+
### 1. One-Click Windows Launch (Desktop App)
|
|
141
|
+
Clone the repository and double-click `start-app.bat`, or run from terminal:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
git clone https://github.com/VedantJadhav701/OpenphysicalAI-lab.git
|
|
145
|
+
cd OpenphysicalAI-lab
|
|
146
|
+
|
|
147
|
+
# Optional: activate your existing Conda environment (auto-detected by main.js)
|
|
148
|
+
conda activate thermo_agent
|
|
149
|
+
|
|
150
|
+
npm install
|
|
151
|
+
npm start
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 2. Pull the Recommended 4GB-Tier Local LLM Planner
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
ollama pull gemma2:2b
|
|
158
|
+
|
|
159
|
+
# Or for the 4B Qwen3 planner:
|
|
160
|
+
ollama pull qwen3:4b-instruct-2507-q4_K_M
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### 3. Headless CLI & Phase-1 Gate Verification
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
python python/gate1.py
|
|
167
|
+
pytest python/tests
|
|
168
|
+
python -m openphysicalai.cli run --task pick_place --perception vision --perturb moderate --verifier V2 --episodes 50
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 🏆 Community Hardware Leaderboard
|
|
174
|
+
|
|
175
|
+
Run the benchmark suite on your machine, generate a signed Budget Card (`budget_card_run_*.md`), and submit a Pull Request to add your hardware configuration below!
|
|
176
|
+
|
|
177
|
+
| Contributor | Device / GPU | Tier Class | Planner Model | Peak Device VRAM | Planning p95 | Recovery TSR | Energy / Ep | Budget Status |
|
|
178
|
+
|---|---|---|---|---|---|---|---|---|
|
|
179
|
+
| **@VedantJadhav701** | HP Victus 15 (RTX 3050 4GB, 16GB RAM) | `OPAI-4G` | `gemma2:2b` | 2.10 GB | 698 ms | 100.0% | ~92 J | ✅ PASS |
|
|
180
|
+
| **@VedantJadhav701** | HP Victus 15 (RTX 3050 4GB, 16GB RAM) | `OPAI-4G` | `qwen3:4b-q4_K_M` | 2.53 GB | 1344 ms | 100.0% | 133.6 J | ✅ PASS |
|
|
181
|
+
| *Your GitHub Handle* | *Add your GPU / Apple Silicon / CPU* | *OPAI-4G/8G/16G* | *Any Ollama Model* | *Measured GB* | *Measured ms* | *Measured %* | *Measured J* | *Submit PR!* |
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 🗂️ Repository Layout
|
|
186
|
+
|
|
187
|
+
```text
|
|
188
|
+
├── main.js / preload.js # Electron main process, Conda auto-discovery, single-instance lock
|
|
189
|
+
├── start-app.bat # One-click Windows launcher
|
|
190
|
+
├── src/ # iOS-style Electron frontend UI
|
|
191
|
+
├── python/
|
|
192
|
+
│ ├── gate1.py # 200-scene deterministic Phase-1 physics gate
|
|
193
|
+
│ ├── tests/ # Pytest unit & integration test suite
|
|
194
|
+
│ └── openphysicalai/ # Core engine: sim, tasks, skills, perception, render (3D GPU),
|
|
195
|
+
│ # planners, injection, runner, profiler, budget, store, cli
|
|
196
|
+
└── docs/ # Architectural roadmap & experimental specifications
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## 📄 License
|
|
202
|
+
|
|
203
|
+
Licensed under the Apache License 2.0 — see [LICENSE](LICENSE) for full details.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# 🤖 OpenPhysicalAI Lab (`v0.2.1`)
|
|
4
|
+
|
|
5
|
+
**Real-Time Embodied AI Simulation, Closed-Loop Failure Recovery & Hardware Budget Benchmarking — Engineered to Run Inside 4 GB VRAM.**
|
|
6
|
+
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[-brightgreen.svg)](#verified-benchmarks--scientific-results)
|
|
9
|
+
[](#system-architecture)
|
|
10
|
+
[-76b900.svg)](#community-hardware-leaderboard)
|
|
11
|
+
[](#quick-start)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## ⚡ Why OpenPhysicalAI Lab?
|
|
18
|
+
|
|
19
|
+
Most embodied AI frameworks assume you have a 24 GB RTX 4090 or an 80 GB datacenter GPU. **OpenPhysicalAI Lab** proves that deterministic 3D physics, vision perception, local LLM task planning, and closed-loop failure recovery can run **entirely locally on a 4 GB VRAM laptop (`OPAI-4G`)**.
|
|
20
|
+
|
|
21
|
+
Unlike static benchmarks that pause the physics engine while the LLM thinks, OpenPhysicalAI Lab enforces **Real-Time Mode**: the physical world keeps moving while the planner reasons, exposing the true **Latency Tax** of slow models and measuring capability under strict **VRAM, System RAM, Latency, and Energy (Joule) Budget Cards**.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## 🏗️ System Architecture
|
|
26
|
+
|
|
27
|
+
```mermaid
|
|
28
|
+
flowchart LR
|
|
29
|
+
subgraph Sim["MuJoCo 3.16 Real-Time Engine (432 FPS)"]
|
|
30
|
+
World["5-DOF Arm + Parallel Gripper\nTable, Cubes, Conveyor"]
|
|
31
|
+
Inject["Seeded Failure Injector\n(Slip, Displacement, Noise)"]
|
|
32
|
+
Render["3D OpenGL GPU Renderer\n(Shadows + Orthographic Vision)"]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
subgraph Percep["Perception & Kinematics"]
|
|
36
|
+
Vision["Vision / Oracle Detector\n(~1 mm Accuracy)"]
|
|
37
|
+
Kalman["Alpha-Beta Velocity Tracker\n(Latency Lead Compensation)"]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
subgraph Agent["Closed-Loop Recovery Agent"]
|
|
41
|
+
Verifier["Tiered Verifiers\n(V0 Oracle | V1 Proprio | V2 Camera)"]
|
|
42
|
+
Planner["Local Ollama LLM Planner\n(Gemma 2 2B / Qwen3 4B JSON)"]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
subgraph Telemetry["NVML & Budget Auditor"]
|
|
46
|
+
Profiler["NVML + Ollama /api/ps\n(VRAM, RAM, Watts, Temp)"]
|
|
47
|
+
Card["SQLite + Signed\nBudget Card (.md / .csv)"]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
World --> Inject --> Render --> Vision --> Kalman
|
|
51
|
+
Kalman --> Verifier --> Planner
|
|
52
|
+
Planner -- "Hold Policy Advances World by Δt_plan" --> World
|
|
53
|
+
Sim -.-> Profiler --> Card
|
|
54
|
+
Agent -.-> Profiler
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## ✅ What Is Real & Verified
|
|
60
|
+
|
|
61
|
+
| Subsystem | Implementation Status |
|
|
62
|
+
|---|---|
|
|
63
|
+
| **Physics Engine** | Real MuJoCo 3.16.0: 5-DOF robotic arm, parallel friction gripper, table, multi-size cubes, open-top container, and kinematic moving conveyor. Analytic IK + Cartesian skill primitives. |
|
|
64
|
+
| **3D GPU Rendering** | Native `mujoco.Renderer` 3D perspective camera (distance 0.92 m, elevation -26°, azimuth 135°) with directional shadow mapping (~432 FPS / 2.3 ms/frame on RTX 3050 Laptop GPU) + 1 mm accurate orthographic vision pipeline. |
|
|
65
|
+
| **Phase-1 Gate** | Deterministic scripted pick-and-place passes **200/200 random scenes (100.0%)** (`python python/gate1.py`). |
|
|
66
|
+
| **Benchmark Tasks** | 5 seeded, cross-process deterministic tasks: `pick_place`, `smallest`, spatial (`left_of`), `multi_object`, and `dynamic` (moving conveyor cube). |
|
|
67
|
+
| **Local LLM Planners** | Rule-based baseline + Ollama local LLMs (`gemma2:2b`, `qwen3:4b-instruct-2507-q4_K_M`) with strict JSON-schema output and kinematic action validation. |
|
|
68
|
+
| **Agent Architectures** | Open-Loop (blind execution), Closed-Loop (abort on anomaly), and Recovery Agent (active failure detection, diagnosis, re-observation, and replanning). |
|
|
69
|
+
| **Hardware Profiler** | Tracks process-tree RSS, system RAM, NVML Compute/Graphics VRAM, Ollama `/api/ps` VRAM, GPU power (W), energy per episode (J), core temperature (°C), and thermal throttling. |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 📊 Verified Benchmarks & Scientific Results
|
|
74
|
+
|
|
75
|
+
All benchmarks below were executed on an HP Victus 15 (**OPAI-4G Reference Tier**: NVIDIA GeForce RTX 3050 Laptop GPU 4.0 GB VRAM, 16 GB System RAM, Windows 11, MuJoCo 3.16.0).
|
|
76
|
+
|
|
77
|
+
### 1. Local LLM Planner Speed & Footprint (OPAI-4G Tier)
|
|
78
|
+
|
|
79
|
+
| Local Model (Ollama) | Weights Size | Peak Device VRAM | Warm Planning Latency | Throughput | Schema Compliance |
|
|
80
|
+
### 1. Local LLM Planner Speed & Footprint (OPAI-4G Tier, N=20 per Model, Real-Time Mode)
|
|
81
|
+
|
|
82
|
+
All models evaluated under identical real-time closed-loop pick-and-place tasks on an NVIDIA GeForce RTX 3050 Laptop GPU (4.0 GB VRAM):
|
|
83
|
+
|
|
84
|
+
| Local Model (Ollama) | Weights Size | Peak Device VRAM | Warm Planning Latency (p50 / p95) | Throughput | TSR (95% CI, N=20) | Notes |
|
|
85
|
+
|---|---|---|---|---|---|---|
|
|
86
|
+
| **`qwen2.5:3b`** | 1.9 GB | 2.57 GB | **469 ms / 493 ms** | 70.6 tok/s | **100.0%** (83.9%–100.0%) | Fastest response, reliable spatial parsing |
|
|
87
|
+
| **`gemma2:2b`** | 1.6 GB | 2.36 GB | **715 ms / 751 ms** | 69.5 tok/s | **100.0%** (83.9%–100.0%) | Consistent schema compliance & low footprint |
|
|
88
|
+
| **`llama3.2:1b`** | 1.3 GB | 1.97 GB | **577 ms / 608 ms** | 99.9 tok/s | **0.0%** (0.0%–16.1%) | Fast generation, but frequent JSON/action schema violations |
|
|
89
|
+
|
|
90
|
+
### 2. Verifier Honesty Benchmark (Moderate Perturbation, Real-Time Mode, N=100 per Cell)
|
|
91
|
+
|
|
92
|
+
Evaluated with Rule-Based Recovery Agent under moderate failure injection (slip probability $p=0.25$, displacement, and wrong placement). Raw JSON exported in `verifier_benchmark_summary_N100.json`:
|
|
93
|
+
|
|
94
|
+
| Agent | Verifier Level | Mode | TSR (95% CI, N=100) | Injections | Detect Rate | Recover Rate | Missed Failures | False Alarms | Planning p95 |
|
|
95
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
96
|
+
| **Recovery** | **V0 (Simulator Oracle)** | realtime | **74.0%** (64.6%–81.6%) | 138 | 97.1% | 52.2% | **0.0%** | 0.0% | 0.03 ms |
|
|
97
|
+
| **Recovery** | **V1 (Proprioception Only)** | realtime | **68.0%** (58.3%–76.3%) | 124 | 87.9% | 51.4% | **3.7%** | 0.0% | 0.03 ms |
|
|
98
|
+
| **Recovery** | **V2 (Proprio + Camera Vision)**| realtime | **73.0%** (63.6%–80.7%) | 137 | 96.4% | 51.5% | **0.3%** | 0.0% | 0.03 ms |
|
|
99
|
+
|
|
100
|
+
> [!IMPORTANT]
|
|
101
|
+
> **Key Verifier Finding**: Proprioceptive verification alone (`V1`) suffers a **3.7% missed-failure rate** because joint sensors cannot detect when a placed object lands outside the container boundary (`wrong_placement`). Vision verification (`V2`) closes this gap, reducing missed failures to **0.3%**, approaching oracle upper bound (`V0`).
|
|
102
|
+
|
|
103
|
+
### 3. The Latency Tax on Dynamic Conveyor Tasks
|
|
104
|
+
|
|
105
|
+
Measured on the `dynamic` task with moving cube at $0.02\text{ m/s}$, single-frame perception, without velocity lead compensation:
|
|
106
|
+
|
|
107
|
+
| Agent Architecture | Verifier | Execution Mode | Planner Delay ($\Delta t$) | TSR (95% CI, N=50) | Physical Mechanism |
|
|
108
|
+
|---|---|---|---|---|---|
|
|
109
|
+
| **Closed-Loop (Rule)** | V1 | sync | 0 ms | **38.0%** (25.9%–51.8%) | Physics paused while planning |
|
|
110
|
+
| **Closed-Loop (Rule)** | V1 | realtime | 0 ms | **38.0%** (25.9%–51.8%) | Real-time baseline |
|
|
111
|
+
| **Closed-Loop (Rule)** | V1 | realtime | 1,000 ms (1.0 s) | **0.0%** (0.0%–7.1%) | Cube shifts ~20 mm past gripper capture zone |
|
|
112
|
+
| **Closed-Loop (Rule)** | V1 | realtime | 2,000 ms (2.0 s) | **0.0%** (0.0%–7.1%) | Stale observation causes complete grasp miss |
|
|
113
|
+
| **Recovery (Velocity-Lead)**| V1 | realtime | 1,000 ms (1.0 s) | **100.0%** (72.2%–100.0%) | Forward-projected intercept overcomes latency tax |
|
|
114
|
+
|
|
115
|
+
> [!NOTE]
|
|
116
|
+
> Physical AI agents relying purely on reactive perception fail when planner latency exceeds the physical dynamic timescale. Latency compensation (velocity projection $\hat{v} \cdot (\tau_{\text{plan}} + \tau_{\text{travel}})$) restores 100% reliability even at multi-second planning delays.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 🚀 Quick Start
|
|
121
|
+
|
|
122
|
+
### 1. One-Click Windows Launch (Desktop App)
|
|
123
|
+
Clone the repository and double-click `start-app.bat`, or run from terminal:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
git clone https://github.com/VedantJadhav701/OpenphysicalAI-lab.git
|
|
127
|
+
cd OpenphysicalAI-lab
|
|
128
|
+
|
|
129
|
+
# Optional: activate your existing Conda environment (auto-detected by main.js)
|
|
130
|
+
conda activate thermo_agent
|
|
131
|
+
|
|
132
|
+
npm install
|
|
133
|
+
npm start
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 2. Pull the Recommended 4GB-Tier Local LLM Planner
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
ollama pull gemma2:2b
|
|
140
|
+
|
|
141
|
+
# Or for the 4B Qwen3 planner:
|
|
142
|
+
ollama pull qwen3:4b-instruct-2507-q4_K_M
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 3. Headless CLI & Phase-1 Gate Verification
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
python python/gate1.py
|
|
149
|
+
pytest python/tests
|
|
150
|
+
python -m openphysicalai.cli run --task pick_place --perception vision --perturb moderate --verifier V2 --episodes 50
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 🏆 Community Hardware Leaderboard
|
|
156
|
+
|
|
157
|
+
Run the benchmark suite on your machine, generate a signed Budget Card (`budget_card_run_*.md`), and submit a Pull Request to add your hardware configuration below!
|
|
158
|
+
|
|
159
|
+
| Contributor | Device / GPU | Tier Class | Planner Model | Peak Device VRAM | Planning p95 | Recovery TSR | Energy / Ep | Budget Status |
|
|
160
|
+
|---|---|---|---|---|---|---|---|---|
|
|
161
|
+
| **@VedantJadhav701** | HP Victus 15 (RTX 3050 4GB, 16GB RAM) | `OPAI-4G` | `gemma2:2b` | 2.10 GB | 698 ms | 100.0% | ~92 J | ✅ PASS |
|
|
162
|
+
| **@VedantJadhav701** | HP Victus 15 (RTX 3050 4GB, 16GB RAM) | `OPAI-4G` | `qwen3:4b-q4_K_M` | 2.53 GB | 1344 ms | 100.0% | 133.6 J | ✅ PASS |
|
|
163
|
+
| *Your GitHub Handle* | *Add your GPU / Apple Silicon / CPU* | *OPAI-4G/8G/16G* | *Any Ollama Model* | *Measured GB* | *Measured ms* | *Measured %* | *Measured J* | *Submit PR!* |
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## 🗂️ Repository Layout
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
├── main.js / preload.js # Electron main process, Conda auto-discovery, single-instance lock
|
|
171
|
+
├── start-app.bat # One-click Windows launcher
|
|
172
|
+
├── src/ # iOS-style Electron frontend UI
|
|
173
|
+
├── python/
|
|
174
|
+
│ ├── gate1.py # 200-scene deterministic Phase-1 physics gate
|
|
175
|
+
│ ├── tests/ # Pytest unit & integration test suite
|
|
176
|
+
│ └── openphysicalai/ # Core engine: sim, tasks, skills, perception, render (3D GPU),
|
|
177
|
+
│ # planners, injection, runner, profiler, budget, store, cli
|
|
178
|
+
└── docs/ # Architectural roadmap & experimental specifications
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 📄 License
|
|
184
|
+
|
|
185
|
+
Licensed under the Apache License 2.0 — see [LICENSE](LICENSE) for full details.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""OpenPhysicalAI Lab core (early scaffold).
|
|
2
|
+
|
|
3
|
+
Interfaces and budget logic only. MuJoCo backend, scheduler and real policies
|
|
4
|
+
arrive in Phase 1+ (see docs/OpenPhysicalAI_Lab_Plan_v3.md).
|
|
5
|
+
"""
|
|
6
|
+
__version__ = "0.2.1"
|
|
7
|
+
|
|
8
|
+
from .budget import Budget, BudgetCheck, evaluate_budget # noqa: F401
|
|
9
|
+
from .stats import wilson_interval # noqa: F401
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Budget contract: separate caps for process-attributed and device-wide usage."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class Budget:
|
|
10
|
+
vram_process_peak_gb: float = 3.2
|
|
11
|
+
vram_device_peak_gb: float = 3.8
|
|
12
|
+
ram_process_peak_gb: float = 8.0
|
|
13
|
+
ram_system_peak_gb: float = 14.0
|
|
14
|
+
planning_ms_p95: float = 2500.0
|
|
15
|
+
profile: str = "standard"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class BudgetCheck:
|
|
20
|
+
name: str
|
|
21
|
+
value: Optional[float]
|
|
22
|
+
cap: float
|
|
23
|
+
ok: bool
|
|
24
|
+
note: str = ""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class BudgetResult:
|
|
29
|
+
passed: bool
|
|
30
|
+
checks: List[BudgetCheck] = field(default_factory=list)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def evaluate_budget(budget: Budget, observed: Dict[str, Optional[float]], not_applicable: tuple = ()) -> BudgetResult:
|
|
34
|
+
"""Compare observed peaks to caps. A missing observation is a failure of measurement, not a pass.
|
|
35
|
+
`not_applicable` lists keys that do not apply on this machine (e.g. VRAM caps on a CPU-only machine)."""
|
|
36
|
+
spec = [
|
|
37
|
+
("vram_process_peak_gb", budget.vram_process_peak_gb),
|
|
38
|
+
("vram_device_peak_gb", budget.vram_device_peak_gb),
|
|
39
|
+
("ram_process_peak_gb", budget.ram_process_peak_gb),
|
|
40
|
+
("ram_system_peak_gb", budget.ram_system_peak_gb),
|
|
41
|
+
("planning_ms_p95", budget.planning_ms_p95),
|
|
42
|
+
]
|
|
43
|
+
checks: List[BudgetCheck] = []
|
|
44
|
+
for name, cap in spec:
|
|
45
|
+
v = observed.get(name)
|
|
46
|
+
if name in not_applicable:
|
|
47
|
+
checks.append(BudgetCheck(name, None, cap, True, "not applicable"))
|
|
48
|
+
elif v is None:
|
|
49
|
+
checks.append(BudgetCheck(name, None, cap, False, "not measured"))
|
|
50
|
+
else:
|
|
51
|
+
checks.append(BudgetCheck(name, float(v), cap, float(v) <= cap))
|
|
52
|
+
return BudgetResult(all(c.ok for c in checks), checks)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
PROFILES = {
|
|
56
|
+
"relaxed": Budget(3.2, 3.8, 8.0, 14.0, 4000.0, "relaxed"),
|
|
57
|
+
"standard": Budget(3.2, 3.8, 8.0, 14.0, 2500.0, "standard"),
|
|
58
|
+
"strict": Budget(3.2, 3.8, 8.0, 14.0, 500.0, "strict"),
|
|
59
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""opai CLI (scaffold): `opai profile`, `opai check-budget`."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import json
|
|
6
|
+
import platform
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from . import __version__
|
|
12
|
+
from .budget import Budget, evaluate_budget
|
|
13
|
+
from .profiler import gpu_snapshot
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def cmd_profile(_args) -> int:
|
|
17
|
+
info = {
|
|
18
|
+
"version": __version__,
|
|
19
|
+
"os": platform.platform(),
|
|
20
|
+
"python": sys.version.split()[0],
|
|
21
|
+
"gpu": gpu_snapshot(),
|
|
22
|
+
}
|
|
23
|
+
print(json.dumps(info, indent=2))
|
|
24
|
+
return 0
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def cmd_doctor(_args) -> int:
|
|
28
|
+
import psutil
|
|
29
|
+
g = gpu_snapshot()
|
|
30
|
+
mem = psutil.virtual_memory()
|
|
31
|
+
cls = "CPU-only"
|
|
32
|
+
if g:
|
|
33
|
+
t = g["total_gb"]
|
|
34
|
+
cls = "OPAI-2G" if t <= 3 else "OPAI-4G" if t <= 6 else "OPAI-8G" if t <= 12 else "OPAI-16G"
|
|
35
|
+
doc = {
|
|
36
|
+
"version": __version__,
|
|
37
|
+
"platform": platform.platform(),
|
|
38
|
+
"python": sys.version.split()[0],
|
|
39
|
+
"processor": platform.processor(),
|
|
40
|
+
"cpu_count_physical": psutil.cpu_count(logical=False),
|
|
41
|
+
"cpu_count_logical": psutil.cpu_count(logical=True),
|
|
42
|
+
"ram_total_gb": round(mem.total / (1024**3), 2),
|
|
43
|
+
"ram_available_gb": round(mem.available / (1024**3), 2),
|
|
44
|
+
"hardware_class": cls,
|
|
45
|
+
"gpu": g,
|
|
46
|
+
}
|
|
47
|
+
print(json.dumps(doc, indent=2))
|
|
48
|
+
return 0
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def cmd_check_budget(args) -> int:
|
|
52
|
+
observed = json.loads(args.observed)
|
|
53
|
+
res = evaluate_budget(Budget(), observed)
|
|
54
|
+
print("PASS" if res.passed else "FAIL")
|
|
55
|
+
for c in res.checks:
|
|
56
|
+
print(f" {'ok ' if c.ok else 'BAD'} {c.name}: {c.value} / {c.cap} {c.note}")
|
|
57
|
+
return 0 if res.passed else 1
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def cmd_run(args) -> int:
|
|
61
|
+
from .report import budget_card
|
|
62
|
+
from .runner import RunConfig, run
|
|
63
|
+
cfg_dict = {k: v for k, v in vars(args).items() if k not in ("cmd", "fn", "export_json") and v is not None}
|
|
64
|
+
cfg = RunConfig.from_dict(cfg_dict)
|
|
65
|
+
cfg.frames = False
|
|
66
|
+
|
|
67
|
+
reproduce_cmd = (
|
|
68
|
+
f"opai run --task {cfg.task} --policy {cfg.policy} --agent {cfg.agent} "
|
|
69
|
+
f"--perception {cfg.perception} --verifier {cfg.verifier} --perturb {cfg.perturb} "
|
|
70
|
+
f"--mode {cfg.mode} --budget {cfg.budget} --episodes {cfg.episodes} --seed {cfg.seed}"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
def emit(e):
|
|
74
|
+
if e.get("event") == "progress" and e["done"] % 10 == 0:
|
|
75
|
+
print(f" episode {e['done']}/{e['total']} successes {e['successes']}", file=sys.stderr)
|
|
76
|
+
|
|
77
|
+
res = run(cfg, emit=emit)
|
|
78
|
+
res["reproduce_command"] = reproduce_cmd
|
|
79
|
+
card_text = budget_card(res)
|
|
80
|
+
print(card_text)
|
|
81
|
+
print(f"\nReproduce command:\n {reproduce_cmd}\n")
|
|
82
|
+
|
|
83
|
+
if getattr(args, "export_json", None):
|
|
84
|
+
out_path = args.export_json
|
|
85
|
+
with open(out_path, "w") as f:
|
|
86
|
+
json.dump(res, f, indent=2)
|
|
87
|
+
print(f"Exported raw run data to {out_path}")
|
|
88
|
+
|
|
89
|
+
return 0
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def main(argv=None) -> int:
|
|
93
|
+
p = argparse.ArgumentParser(prog="opai")
|
|
94
|
+
sub = p.add_subparsers(dest="cmd", required=True)
|
|
95
|
+
sub.add_parser("profile").set_defaults(fn=cmd_profile)
|
|
96
|
+
sub.add_parser("doctor", help="inspect host hardware, NVML, and budget class").set_defaults(fn=cmd_doctor)
|
|
97
|
+
cb = sub.add_parser("check-budget")
|
|
98
|
+
cb.add_argument("observed", help='JSON, e.g. \'{"vram_process_peak_gb": 2.1}\'')
|
|
99
|
+
cb.set_defaults(fn=cmd_check_budget)
|
|
100
|
+
r = sub.add_parser("run", help="headless benchmark run, prints a Budget Card")
|
|
101
|
+
for name, default in (("task", "pick_place"), ("policy", "rule"), ("agent", "recovery"), ("perception", "oracle"), ("verifier", "V1"),
|
|
102
|
+
("perturb", "clean"), ("mode", "sync"), ("budget", "standard")):
|
|
103
|
+
r.add_argument("--" + name, default=default)
|
|
104
|
+
r.add_argument("--episodes", type=int, default=50)
|
|
105
|
+
r.add_argument("--seed", type=int, default=0)
|
|
106
|
+
r.add_argument("--extra-latency-ms", dest="extra_latency_ms", type=float, default=0.0)
|
|
107
|
+
r.add_argument("--velocity-lead", dest="velocity_lead", action=argparse.BooleanOptionalAction, default=True)
|
|
108
|
+
r.add_argument("--export-json", dest="export_json", type=str, default=None, help="path to export raw run.json")
|
|
109
|
+
r.set_defaults(fn=cmd_run)
|
|
110
|
+
args = p.parse_args(argv)
|
|
111
|
+
return args.fn(args)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
if __name__ == "__main__":
|
|
115
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Seeded failure / perturbation injection. Ground truth of what was injected is logged for scoring
|
|
2
|
+
only and is never exposed to the agent."""
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import Dict, List
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
LEVELS = {
|
|
12
|
+
"clean": {"p": 0.00, "pos_noise": 0.000, "pix_noise": 0.0},
|
|
13
|
+
"mild": {"p": 0.10, "pos_noise": 0.010, "pix_noise": 8.0},
|
|
14
|
+
"moderate": {"p": 0.25, "pos_noise": 0.020, "pix_noise": 16.0},
|
|
15
|
+
"severe": {"p": 0.40, "pos_noise": 0.035, "pix_noise": 28.0},
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
EXPECTED_DIAGNOSIS = {"grasp_slip": "object_dropped", "object_displaced": "grasp_miss", "wrong_placement": "wrong_placement"}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@dataclass
|
|
22
|
+
class Injector:
|
|
23
|
+
level: str
|
|
24
|
+
rng: np.random.Generator
|
|
25
|
+
log: List[Dict] = field(default_factory=list)
|
|
26
|
+
|
|
27
|
+
def __post_init__(self):
|
|
28
|
+
self.cfg = LEVELS[self.level]
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def pos_noise(self) -> float:
|
|
32
|
+
return self.cfg["pos_noise"]
|
|
33
|
+
|
|
34
|
+
@property
|
|
35
|
+
def pix_noise(self) -> float:
|
|
36
|
+
return self.cfg["pix_noise"]
|
|
37
|
+
|
|
38
|
+
def _roll(self) -> bool:
|
|
39
|
+
return self.cfg["p"] > 0 and self.rng.random() < self.cfg["p"]
|
|
40
|
+
|
|
41
|
+
def displace(self, world, oid: str, step: int) -> bool:
|
|
42
|
+
if self._roll():
|
|
43
|
+
ang = self.rng.uniform(0, 2 * math.pi)
|
|
44
|
+
d = self.rng.uniform(0.06, 0.09)
|
|
45
|
+
x0, y0 = world.obj_pos(oid)[:2]
|
|
46
|
+
nx, ny = x0 + d * math.cos(ang), y0 + d * math.sin(ang)
|
|
47
|
+
nx, ny = min(max(nx, 0.10), 0.36), min(max(ny, -0.25), 0.25)
|
|
48
|
+
world.teleport(oid, nx - x0, ny - y0)
|
|
49
|
+
self.log.append({"type": "object_displaced", "step": step, "object": oid})
|
|
50
|
+
return True
|
|
51
|
+
return False
|
|
52
|
+
|
|
53
|
+
def slip(self, step: int) -> bool:
|
|
54
|
+
if self._roll():
|
|
55
|
+
self.log.append({"type": "grasp_slip", "step": step})
|
|
56
|
+
return True
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
def placement_offset(self, step: int):
|
|
60
|
+
if self._roll():
|
|
61
|
+
ang = self.rng.uniform(0, 2 * math.pi)
|
|
62
|
+
self.log.append({"type": "wrong_placement", "step": step})
|
|
63
|
+
return 0.12 * math.cos(ang), 0.12 * math.sin(ang)
|
|
64
|
+
return 0.0, 0.0
|