fix(devices): force-release camera/serial in recording and calibration teardown#65
Merged
nicolas-rabault merged 1 commit intoJul 16, 2026
Conversation
…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
self-requested a review
July 16, 2026 13:48
nicolas-rabault
approved these changes
Jul 16, 2026
nicolas-rabault
left a comment
Member
There was a problem hiding this comment.
Very nice one.
Thank you @cn0303
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 + cameraswhen 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-sessionfinallynow callssafe_disconnect_device(robot, …)(and theteleop device) instead of a bare
disconnect(), so a flaky teardown force-releases the device.calibrate.py:_cleanup_device()now force-releases and always clearsself.device. The oldcode set
self.device = Noneinside thetryafterdisconnect(), so a failed disconnect left boththe port open and the handle set : blocking the next calibration. Now both are always handled.
Testing
wrist_cam, lerobot 0.6.0). Before (onmain): arecording that ends without a clean disconnect leaks the camera; the teardown logs no
OpenCVCamera(0) disconnected, and the next recording dies withOpenCVCamera(0) read failed (status=False)/ "camera resource conflict". After (this branch): theteardown force-releases the camera and the next recording acquires it normally.
test_cleanup_device_force_releases_and_clears_when_disconnect_fails; asserts that when thedevice's
disconnect()raises, calibration cleanup still force-closes the port and clears the handle.test_pid_alive_returns_false_for_unlikely_pid,test_list_imported_local_checkpoints_tree, both intest_jobs.py) are pre-existing onmain(confirmed by re-running them with this change stashed) and unrelated to this PR.
Notes / scope
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."
race (worker still alive during cleanup;
start_calibrationnot checkingthread.is_alive()) is aseparate, more opinionated change and is left out of this PR.