Skip to content

Integrate Manus glove calibration into CaptureServer - #1408

Open
gareth-morgan-nv wants to merge 2 commits into
gmorgan/manus-calibration-workerfrom
gmorgan/capture-server-manus-calibration
Open

gareth-morgan-nv wants to merge 2 commits into
gmorgan/manus-calibration-workerfrom
gmorgan/capture-server-manus-calibration

Conversation

@gareth-morgan-nv

@gareth-morgan-nv gareth-morgan-nv commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Stage 2 of Manus glove calibration, stacked on #1406 (base gmorgan/manus-calibration-worker): CaptureServer runs the standalone calibration worker on its host over its existing connection, supervises it, stores the resulting MCAL files in a managed directory, and lets a later capture select them by name. This PR is only the integration delta; the worker, supervisor and storage are #1406.

  • Shared library. The worker supervisor (worker.py), its line protocol parser (protocol.py) and McalStore move with git mv from the standalone example into a zero-dependency distribution, isaaccapture-manus-calibration, at src/plugins/manus/calibration/python/, beside the native worker. The standalone example and egocap both depend on it as a path dependency (egocap keeps its single pyproject.toml; uv.lock gains the one package). No second copy and no sys.path tricks; a deployed CaptureServer does not need the example's source tree.
  • One admission gate. A calibration session implements the same small surface as a capture session (session_id, owner_ws, done, cleanup_ok, request_stop) behind CaptureServer._active_session, so capture and calibration are mutually exclusive from acceptance through cleanup (BUSY for either order, nothing is interrupted), owner disconnect and server shutdown cancel it, and a worker that could not be reaped keeps the station unavailable for both. Capture Stop and StopCalibration each address only their own kind. Calibration emits control and status messages only and creates no acquisition or OpenXR session.
  • Wire (numeric, additive). MessageType 11 to 17 for StartCalibration, ConfirmCalibrationStep, StopCalibration, CalibrationStarted, CalibrationStatus, CalibrationStepAccepted, CalibrationStopped; no existing value, decoder or the protocol version changes. The Manus entry of Begin.plugins gains optional left_calibration / right_calibration basenames (omitted keeps the exact earlier bytes). Step messages carry mode, duration_seconds, continuous and estimated_seconds so a continuous SDK step is never presented as an instantaneous or guaranteed-timed capture.
  • Client API. CaptureClient.start_calibration / confirm_calibration_step / stop_calibration with immutable snapshots, one terminal callback per accepted attempt (including after transport loss, then with reason=None and no files), confirm that returns only after the worker accepted the step, and ManusPluginConfig(left_calibration, right_calibration) for capture (bare PluginType callers are unchanged).
  • Files and selection. Basenames are validated against the managed directory before any hardware starts (bare .mcal name, real path inside the directory, readable regular file, no duplicates), resolved host paths go to the plugin's own --left-calibration / --right-calibration arguments, and only basenames are echoed.
  • Config and docs. --manus-calibration-dir and --manus-calibrator (default: the Manus install under $ISAAC_ROOT/install/plugins/manus); a missing worker leaves capture and saved-file selection unaffected and only rejects generating a calibration, with a clear message. capture_server/CALIBRATION.md is the contract; capture_server/scripts/calibrate_and_capture.py is a minimal operator-driven example.

Known issue

Unchanged from #1406: with the real SDK and no working Manus license on the test machine, the SDK call that starts a step did not return within the supervisor's bound, the cause is not established, and a full calibration, MCAL export and loading an exported file through the tracking plugin have not been demonstrated. A passing mock integration does not change that.

Validation

Nothing in this PR was executed. At the author's request no test suite and no hardware test was run for this change; the tests below were written but are unrun.

  • Source review, ruff format/ruff check and byte-compilation of the touched Python; uv lock regenerated (with a newer uv than the 0.10.2 installed here, which cannot read the repo root pyproject.toml when it follows the new path dependency); only the new package was added to the lock.
  • New tests under examples/egocap/tests/capture_server/ (test_calibration_protocol.py, test_calibration_module.py, test_calibration_server.py, test_calibration_client.py, test_calibration_selection.py, test_calibration_cli.py): the protocol additions, resolve_calibration_file and the calibration session, admission exclusivity in both directions, failed and unreleased cleanup keeping the station busy for both kinds, duplicate and stale confirms, owner disconnect and shutdown, a missing worker, continuous metadata, the client API, capture-time selection (plugin arguments, basenames echoed, begin-time refusals before any source is built, enum-only callers unchanged), saved-file selection without a worker, and the CLI flags: written, not run.
  • examples/egocap suites (tests/capture_server, tests/recording, tests/recording_service) and the standalone example's tests after the module move: not run.
  • End to end with the real worker and gloves: not done.
  • pre-commit: SKIP=check-copyright-year pre-commit run --all-files passed (exit 0, nothing modified) on the final tree.

🤖 Generated with Claude Code

Stage 2 of Manus glove calibration, on top of the standalone worker.

- Shared library: the worker supervisor, its line protocol parser and the
  MCAL store move from the standalone example into a standard-library-only
  distribution, isaaccapture-manus-calibration, beside the native worker.
  The example and egocap depend on it as a path dependency; egocap keeps its
  single pyproject and lock.
- One admission gate: a calibration session implements the capture session's
  admission surface behind CaptureServer._active_session, so the two are
  mutually exclusive from acceptance through cleanup. Owner disconnect and
  shutdown cancel it, an unreaped worker keeps the station busy for both,
  and Stop and StopCalibration each address only their own kind.
- Wire: numeric MessageType 11 to 17 for StartCalibration,
  ConfirmCalibrationStep, StopCalibration and the four server events. The
  Manus plugin entry gains optional left/right calibration basenames; capture
  values and the protocol version are unchanged. Steps carry mode, duration,
  continuous and estimated_seconds.
- CaptureClient: start_calibration, confirm_calibration_step,
  stop_calibration and ManusPluginConfig, with one terminal callback per
  accepted attempt and an honest unconfirmed outcome after transport loss.
- Capture selection: basenames are validated against the managed directory
  before any hardware starts and passed as the plugin's own calibration
  arguments; only basenames are echoed.
- Config and docs: --manus-calibration-dir and --manus-calibrator,
  CALIBRATION.md, and a minimal calibrate-then-capture script.

Nothing in this change was executed: the tests written for it, and the
existing suites, were not run. The step-start stall seen with the real SDK in
the standalone worker is unchanged and undiagnosed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

The managed calibration directory is now configured independently of the
worker executable: without a worker only generating a new calibration is
unavailable, and capture can still select saved files from the directory
after the usual basename, containment and readability checks. Documents the
cleanup invariant next to the session's cleanup state, and adds the
capture-time selection, decoupling and CLI tests (written, not run).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Signed-off-by: Gareth Morgan <gmorgan@nvidia.com>

This branch was successfully deployed

1 active deployment
dev — bc0c90ae Deployed Nov 2, 2026 by gareth-morgan-nv via publish-wheel #6392
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants