Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: Test and build
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.head_ref || github.ref_name }}
cancel-in-progress: true
jobs:
tests:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python: ['3.10', '3.11', '3.12', '3.13', '3.14', '3.15']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python }}
- run: python -m pip install .[dev]
- run: python -m pytest -q
- run: python -m ruff check src tests examples tools/build_runtime_release.py tools/configure_release.py tools/check_release.py tools/probe_private_runtime.py
- run: python -m ruff format --check src tests examples tools/build_runtime_release.py tools/configure_release.py tools/check_release.py tools/probe_private_runtime.py
- run: source-leap --demo --frames 3 --json
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.15'
- run: python -m pip install build twine
- run: python -m build
- run: python -m twine check dist/*
- uses: actions/upload-artifact@v4
with:
name: python-distributions
path: dist/*
34 changes: 34 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Publish Python package
on:
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: '3.15'
- run: python -m pip install .[dev] twine
- run: python -m pytest -q
- run: python -m build
- run: python -m twine check dist/*
- run: python tools/check_release.py
- uses: actions/upload-artifact@v4
with:
name: publish-distributions
path: dist/*
publish:
needs: build
runs-on: ubuntu-latest
environment: pypi
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
name: publish-distributions
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.venv/
.tools/
.pytest_cache/
.ruff_cache/
__pycache__/
*.py[cod]
dist/
build/
*.egg-info/
recordings/
motion_data.txt

1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
MIT License

Copyright (c) 2021 ano0002
Copyright (c) 2026 Source Robotics

Permission is hereby granted, free of charge, to any person obtaining a copy
Expand Down
154 changes: 154 additions & 0 deletions PACKAGE_DESIGN.md

Large diffs are not rendered by default.

217 changes: 214 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,215 @@
# Source-Robotics-Leap-Motion
Leap motion source robotics demo
**Source Robotics Leap Motion - 0.1.0b1 release candidate**

<img src="LEAP_PAR6.png" alt="drawing" width="5000"/>
A Python package for the **Original Leap Motion Controller**, with owned hand data,
recording/replay, and configurable coordinate mapping for custom robot integrations.
It runs on current Python without `LeapPython.pyd` or a Python 3.8 process.

The beta is distributed through this repository's `v0.1.0b1` GitHub release. PyPI
publication is being configured. Install the wheel directly, then start tracking:

```powershell
python -m pip install https://github.com/Source-Robotics/Source-Robotics-Leap-Motion/releases/download/v0.1.0b1/source_robotics_leap_motion-0.1.0b1-py3-none-any.whl
source-leap
```

The Windows engine downloads automatically when needed. First-use driver setup may
require Windows approval. See [release status and validation](docs/BETA_VALIDATION.md)
and [publication steps](docs/RELEASING.md). Linux/macOS currently use an installed
vendor tracking service and remain experimental for hardware use.

**Try it in this project's virtual environment.** Python 3.15.2 and the package are
already installed in `.venv`. No activation is necessary:

```powershell
.\.venv\Scripts\source-leap.exe --demo
.\.venv\Scripts\source-leap.exe setup
.\.venv\Scripts\source-leap.exe doctor --probe
.\.venv\Scripts\source-leap.exe
```

The first command shows synthetic hand motion. The last uses a connected controller.
Stop with Ctrl+C. Add `--frames 60` or `--duration 5` for a bounded run.
`source-leap.cmd --demo` is a convenience wrapper for this checkout.

To install the source in another existing environment:

```powershell
python -m pip install .
source-leap --demo
```

Python **3.10 or newer** is required. The wheel has been installed and tested on
**CPython 3.10.11, 3.11.9, 3.12.10, 3.13.17, 3.14.10, and 3.15.2, Windows x64**.
Each version passed all 86 tests, received live camera frames, and replayed a recorded
real hand. Python 3.10 additionally uses small `tomli` and `typing-extensions`
backports, installed automatically by pip. All versions use `websocket-client`.
Python 3.9 and earlier are not supported by the new package.

The [compatibility and performance report](docs/COMPATIBILITY_PERFORMANCE.md) explains
the test matrix, measured stream rate, comparison with the original Python 3.8 SDK,
and remaining limits. The tracking engine and driver are unchanged; no improvement
in tracking accuracy or camera frame rate is claimed.

**Automatic runtime selection.** `Tracker()` and `source-leap` reuse an installed
compatible service or find the cached private runtime automatically. If neither is
available, the release catalog supplies a pinned Windows download. Its SHA-256 and
file sizes are checked, interrupted transfers resume, and installation is atomic.
The compressed download is removed after installation to keep one extracted copy.
Imports perform no downloads, device access, or background startup.

The service path supports LeapC and the local protocol-v6 WebSocket endpoint.
On this PC, the fallback was verified with service `3.2.1+45911` on
`127.0.0.1:6437` and the actual Original Leap Motion Controller. A 30-second check
captured 3,399 frames, including 53 frames containing a left hand with all five
fingers and four bones per finger. Recording and replay also passed. See
[the hardware validation notes](docs/HARDWARE_VALIDATION.md).

An existing working legacy service can therefore be used without upgrading it.
The native LeapC loader supports Windows x64, Linux x64, and macOS Intel/Apple
Silicon. Linux/macOS hardware integration remains experimental and needs a compatible
vendor service. Windows private-engine operation has been hardware-tested. No vendor
DLLs or model data are included in the Python wheel; the Windows runtime is a separate
GitHub release asset. Clean-PC driver setup still needs a real hardware test.

**First-use setup.** `source-leap setup` reports device status and probes actual frames.
An unplugged device is distinguished from Windows problem code 28 (missing driver).
Only an explicit `--install-driver` action or an accepted interactive prompt requests
Windows approval. A working driver is not replaced. `--open-downloads` opens the
official platform setup page. Linux instructions point to the vendor's core service
package; macOS instructions select the appropriate vendor installation.

An offline Windows installation is also available:

```powershell
.\.venv\Scripts\source-leap.exe setup --archive dist\runtime\source-leap-runtime-windows-x86_64-3.2.1.zip
```

`SOURCE_LEAP_CACHE` selects a development/test cache. Normal users need no environment
variables. `--catalog PATH` is a setup/deployment override for a release catalog.

**Private Windows runtime.** Developers can prepare a local engine copy without the
control panel or visualizer:

```powershell
.\.venv\Scripts\source-leap.exe runtime prepare "C:\Program Files (x86)\Leap Motion\Core Services" --destination .tools\private-runtime-321 --dependencies .
.\.venv\Scripts\source-leap.exe runtime inspect .tools\private-runtime-321
.\.venv\Scripts\source-leap.exe monitor --runtime-dir .tools\private-runtime-321
```

Preparation copies local files and records checksums. Applications acquire leases on
a hidden coordinator that starts the engine and waits for an actual camera frame.
Closing one application keeps the engine alive for other clients. The engine exits
after the last client leaves, including crashed clients. Configuration and logs live
outside the engine directory. The package never stops or installs system services.
`Tracker(runtime_dir="...")` selects a developer bundle explicitly.

The base engine contains seven files, about **248 MB** before compression. The release
archive adds driver files and notices: **251 MB extracted, 244 MB compressed**.
The private engine delivered 1,047 frames in ten
seconds, about 105 FPS, including 50 full hand skeletons. It ran as the normal user
while the installed service was stopped. First-frame startup took about 2.6 seconds.
The project owner confirmed redistribution permission on 5 November 2026. The
installed beta wheel also passed two-client sharing, repeated startup, crash cleanup,
and a live-frame check of the restored installed service. Clean-PC USB setup and
other-platform hardware tests remain pending.
See [the prototype, evidence, and bounded test command](docs/MINIMAL_RUNTIME.md).
The proposed first-use flow and Windows/Linux/macOS targets are documented in
[installation and platforms](docs/INSTALLATION_PLATFORMS.md).

**Read hand data.** The same API accepts live, synthetic, and replay sources:

```python
from source_robotics_leap_motion import Tracker

with Tracker() as tracker: # use Tracker.demo() to try without a camera
print("Backend:", tracker.backend_name)
for frame in tracker:
if hand := frame.right_hand:
print(hand.palm.position, hand.grab_strength)
```

Positions, widths, and distances use **metres**; palm velocity uses metres/second.
Camera axes remain Leap's axes: +x right, +y up, +z toward the user. Quaternions have
named `x`, `y`, `z`, `w` components. Frame timestamps are microseconds in the named
`clock_domain`, not Unix time. An empty-hand frame is valid; absence of frames produces
`TrackingTimeoutError`. Service/camera disconnections produce `ConnectionError`.

Frames are immutable Python snapshots and retain no SDK pointers. LeapC includes
finger/arm rotations. The legacy backend exposes finger joint positions when supplied
by protocol v6, derives palm orientation from normal/direction, and reports unavailable
bone rotations and pinch distance as `None`. It never substitutes a made-up rotation.

**Record and replay.** Existing recordings are protected by default:

```powershell
.\.venv\Scripts\source-leap.exe record recordings\session.jsonl --frames 300
.\.venv\Scripts\source-leap.exe replay recordings\session.jsonl --realtime
.\.venv\Scripts\source-leap.exe record recordings\demo.jsonl --demo --frames 60
.\.venv\Scripts\source-leap.exe replay recordings\demo.jsonl --json
```

The destination folder is created automatically. JSON output contains only frames on stdout;
status and errors go to stderr. Each recording has a schema version, timestamp and
coordinate conventions, and one frame per line. Reading streams the file without
loading the whole session. Headerless historical `motion_data.txt` files use a different
format and are not accepted as recordings.

```python
from source_robotics_leap_motion import Recorder, Tracker, read_recording

with Tracker.demo(realtime=False) as tracker, Recorder("demo.jsonl") as recording:
for _ in range(60):
recording.write(tracker.read())

for frame in read_recording("demo.jsonl"):
print(frame.timestamp_us, frame.right_hand.palm.position)
```

**Customize coordinate mapping.** The package provides a pure mapping function, with
no hard-coded robot origin or workspace:

```python
from source_robotics_leap_motion import Mapping, Vector3

mapping = Mapping(axes=("-z", "-x", "y"), gain=Vector3(0.5, 0.5, 0.5))
target = mapping.map_position(
hand.palm.position,
hand_origin=calibrated_hand_position,
robot_origin=current_robot_position,
)
```

Gains apply in output coordinates. Zero locks an axis. Signed axis permutations must
preserve handedness. `Mapping.from_toml("examples/my_arm.toml")` loads the same settings.
Run `python examples/custom_mapping.py` for a complete synthetic example that only
prints targets.

This alpha supplies tracking and mapping primitives. Robot adapters, activation/clutch
states, motion limits, adaptive filtering, and continuous robot control are the next
milestone; a production `Teleoperator` is **not implemented**. There is no automatic
connection to an arm, no motor-driver dependency, and no implicit movement command.

**Diagnostics.** `doctor` inspects fixed runtime locations without loading native
code. `doctor --probe` also opens tracking and waits for a frame. Exit code 0 indicates
the requested check passed, 2 indicates a configuration/tracking error, and Ctrl+C
returns 130. A WebSocket connection can succeed while the camera is unplugged, paused,
or otherwise not streaming; a successful greeting alone is not a live-frame test.

Developers can explicitly select a LeapC library with `--library PATH` or the
`SOURCE_LEAP_LIBRARY` environment variable. An explicit selection never silently
falls back to another backend. Normal users should not need either option.

**Development and validation.**

```powershell
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe -m ruff check src tests examples
.\.venv\Scripts\python.exe -m ruff format --check src tests examples
.\.venv\Scripts\python.exe -m build --wheel
```

The original scripts and binaries remain historical references. The original README
is preserved in [docs/LEGACY_README.md](docs/LEGACY_README.md). Current scope and design
are in [PACKAGE_DESIGN.md](PACKAGE_DESIGN.md); native-interface verification is described
in [docs/NATIVE_ABI.md](docs/NATIVE_ABI.md).
53 changes: 53 additions & 0 deletions docs/BETA_VALIDATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
**Beta 0.1.0b1 validation - 5 November 2026**

This release candidate implements automatic runtime delivery and cache selection,
shared engine ownership, first-use setup, and experimental POSIX LeapC loading.
The repository was made public with the owner's explicit approval. The GitHub beta
release is prepared with a public runtime URL; PyPI publication depends on authorizing
its Trusted Publisher. The direct GitHub wheel installation is the initial beta path.

**Windows checks.** All checks used project-local Python virtual environments.

- The 244,070,193-byte release archive was served by a local HTTP server, downloaded,
verified against its pinned SHA-256, and installed atomically. A fresh process reused
the cache with the server unavailable. The compressed cache copy was removed.
- Windows device inspection reported the Original controller present, with problem
code zero. No driver installation or replacement was performed on this working PC.
- The beta wheel was installed into an isolated venv. With the installed service
temporarily stopped, plain `Tracker()` selected the cached engine automatically.
- Two simultaneous clients acquired leases. Closing the first left the second
receiving 30 more camera frames. Closing the last client stopped the engine.
- Two complete engine restart cycles received real camera frames and cleaned up.
- A separate client received a frame and exited abruptly without closing its tracker.
Its lease closed automatically, and the coordinator stopped the unused engine.
- The installed service was restored, and a real-frame probe passed afterward.
Results: `.tools/private-probes/f8562a2404a64767bc4f6202a4e9f828/summary.json`.
- The 86-test suite covers transport resume/restart, checksum failures, extraction
validation, atomic caching, device-status distinctions, shared leases, connection
recovery, native loading, data models, mapping, CLI behavior, and recording/replay.

The earlier hand capture remains the live skeleton evidence: 1,047 frames over ten
seconds, including 50 complete left-hand samples with arm data, about 105 FPS.
No new CPU/latency improvement is claimed by this installer/lifecycle work.

**Other platforms.** Native loading uses the vendor header's Windows calling
convention on Windows and C calling convention on Linux/macOS. The SDK structures
remain packed as specified by the vendor header. Background-frame policy is requested
explicitly. Loader selection is unit-tested. Installed library discovery includes
the documented Ubuntu paths and the macOS application SDK path.

GitHub CI is configured for Python 3.10-3.15 on Windows, Linux, and macOS. CI results
were checked on source commit `7c2f782`: every Windows and Linux Python job passed,
along with the package build and metadata checks. macOS 3.11 and 3.13 jobs passed;
other macOS jobs were still waiting for hosted runners at the time of this report.
The Windows installed-wheel matrix separately passed all 86 tests on each Python
minor version from 3.10 through 3.15, with live camera frames and private-recording replay.
No Linux or Mac hardware test has been performed on this Windows PC. Windows-managed
runtime archives are deliberately rejected on other platforms, which use an installed
native vendor service and platform-specific setup instructions.

**Remaining release checks.** A clean Windows hardware installation is still needed
to validate driver-only setup without any previous vendor installation. A working
developer PC does not provide that evidence. Linux/macOS real-device tests and long
sessions also remain. Public runtime availability and PyPI publisher configuration
are required before new users can use the short PyPI package-name installation flow.
Loading
Loading