Skip to content

fix(devices): force-release camera/serial in recording and calibration teardown#65

Merged
nicolas-rabault merged 1 commit into
huggingface:mainfrom
cn0303:fix/force-release-device-on-record-calibrate
Jul 16, 2026
Merged

fix(devices): force-release camera/serial in recording and calibration teardown#65
nicolas-rabault merged 1 commit into
huggingface:mainfrom
cn0303:fix/force-release-device-on-record-calibrate

Conversation

@cn0303

@cn0303 cn0303 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Problem

When a device disconnect() fails during recording or calibration teardown
(a flaky USB camera or serial port; an issue common on Windows), the underlying
handle can stay open. That keeps the camera/COM port busy and blocks the next
session from acquiring it. This is the failure mode behind issue #50 :
recording hangs on "PREPARING SESSION" with the backend logging
"Waiting for camera resources to be released."

Context

safe_disconnect_device() (lelab/utils/devices.py) was added to force-close the serial port + cameras
when a normal disconnect throws but it was wired only into teleoperation's teardown. Its own commit
noted "other call sites (calibration, recording) can adopt the same helper in follow-ups,"
and in #50 Nicolas noted the recording path still needs this treatment. This PR completes that rollout.

Change

  • record.py : the recording-session finally now calls safe_disconnect_device(robot, …) (and the
    teleop device) instead of a bare disconnect(), so a flaky teardown force-releases the device.
  • calibrate.py : _cleanup_device() now force-releases and always clears self.device. The old
    code set self.device = None inside the try after disconnect(), so a failed disconnect left both
    the port open and the handle set : blocking the next calibration. Now both are always handled.

Testing

  • Hardware-confirmed on Windows 11 (SO-101 + USB wrist_cam, lerobot 0.6.0). Before (on main): a
    recording that ends without a clean disconnect leaks the camera; the teardown logs no
    OpenCVCamera(0) disconnected, and the next recording dies with
    OpenCVCamera(0) read failed (status=False) / "camera resource conflict". After (this branch): the
    teardown force-releases the camera and the next recording acquires it normally.
  • New test_cleanup_device_force_releases_and_clears_when_disconnect_fails; asserts that when the
    device's disconnect() raises, calibration cleanup still force-closes the port and clears the handle.
  • Full suite: 186 passed, 2 failed; the 2 failures (test_pid_alive_returns_false_for_unlikely_pid,
    test_list_imported_local_checkpoints_tree, both in test_jobs.py) are pre-existing on main
    (confirmed by re-running them with this change stashed) and unrelated to this PR.
  • pre-commit green (ruff, ruff-format, mypy, bandit, typos, pyupgrade).

Notes / scope

  • This applies the force-release the maintainer identified as missing on the recording path; whether it
    fully resolves Recording session stuck on "PREPARING SESSION" — Advance/Space button not working on Windows #50 for the reporter (their report also mentions a COM-port conflict after visiting
    Teleoperation first) is worth confirming; hence "Addresses" not "Fixes."
  • Deliberately tight: this only wires in the existing helper. The deeper calibration stop/restart threading
    race (worker still alive during cleanup; start_calibration not checking thread.is_alive()) is a
    separate, more opinionated change and is left out of this PR.
  • Source-only; no frontend changes

…n teardown

When a device.disconnect() fails during recording or calibration teardown
(a flaky USB camera or serial port), the underlying handle can stay open,
keeping the device busy and blocking the next session from acquiring it —
the failure mode behind issue huggingface#50 (recording stuck on "PREPARING SESSION"
on Windows: "Waiting for camera resources to be released").

safe_disconnect_device() was added to force-close the serial port/cameras
when a normal disconnect throws, but wired only into teleoperation's
teardown. Adopt it in the two remaining call sites the helper was meant for:

- record.py: the recording-session finally now force-releases the robot (and
  teleop) instead of a bare disconnect().
- calibrate.py: _cleanup_device now force-releases and always clears the
  device handle, so a failed disconnect can't leave the arm half-owned and
  block the next calibration (the old code only cleared the handle when the
  disconnect succeeded).

Adds a calibrate-cleanup test covering the disconnect-fails path.
@nicolas-rabault
nicolas-rabault self-requested a review July 16, 2026 13:48

@nicolas-rabault nicolas-rabault left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice one.
Thank you @cn0303

@nicolas-rabault
nicolas-rabault merged commit 69a1022 into huggingface:main Jul 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recording session stuck on "PREPARING SESSION" — Advance/Space button not working on Windows

2 participants