Skip to content

feat(cameras): add Orbbec RGBD camera support via pyorbbecsdk2#3113

Open
orbbecwuxin wants to merge 13 commits intohuggingface:mainfrom
orbbec:feat/orbbec-camera
Open

feat(cameras): add Orbbec RGBD camera support via pyorbbecsdk2#3113
orbbecwuxin wants to merge 13 commits intohuggingface:mainfrom
orbbec:feat/orbbec-camera

Conversation

@orbbecwuxin
Copy link

@orbbecwuxin orbbecwuxin commented Mar 9, 2026

feat(cameras): add Orbbec RGBD camera support via pyorbbecsdk2

Type / Scope

  • Type: Feature
  • Scope: cameras/orbbec, docs, requirements

Summary / Motivation

Adds full support for Orbbec Gemini series cameras (tested on Gemini 336 / 336L) to LeRobot, mirroring the existing RealSense camera interface. The driver is built on pyorbbecsdk2 (SDK 2.0.18) and uses a background thread for async frame capture. Key capabilities include color+depth stream synchronisation, hardware/software depth-to-color (D2C) alignment with automatic fallback, and multi-camera auto-discovery.

Related issues

  • Fixes / Closes: # (if any)
  • Related: # (if any)

What changed

  • Added src/lerobot/cameras/orbbec/camera_orbbec.py: OrbbecCamera implementation with sync/async read, color+depth frame sync, hardware D2C alignment (auto-falls back to software AlignFilter when unsupported), and multi-format color conversion (RGB/BGR/YUYV/MJPG/NV12/NV21/I420).
  • Added src/lerobot/cameras/orbbec/configuration_orbbec.py: OrbbecCameraConfig with D2CMode enum (HARDWARE / SOFTWARE); defaults to SOFTWARE for maximum device compatibility.
  • Added src/lerobot/cameras/orbbec/__init__.py: module exports.
  • Added tests/cameras/test_orbbec.py: 32 unit tests (mock-based), covering 12 sync/async scenarios.
  • Modified src/lerobot/cameras/utils.py, scripts/lerobot_find_cameras.py: register orbbec camera type and lerobot-find-cameras orbbec CLI entry point.
  • Modified src/lerobot/scripts/lerobot_calibrate.py, lerobot_record.py, lerobot_teleoperate.py: add OrbbecCameraConfig import.
  • Modified pyproject.toml, requirements-ubuntu.txt: add pyorbbecsdk2 as an optional dependency.
  • Modified docs/source/cameras.mdx, docs/source/installation.mdx: add Orbbec installation instructions and udev rules.
  • Breaking change: none — existing camera interfaces are unaffected.

How was this tested (or how to run locally)

  • Tests added: tests/cameras/test_orbbec.py (32 tests, all mock-based)

  • Run unit tests:

    pytest -q tests/cameras/test_orbbec.py
  • Install Orbbec SDK:

    pip install pyorbbecsdk2
    # Configure udev rules (see docs/source/installation.mdx)
  • Hardware validation (2 cameras: Gemini 336 + Gemini 336L, USB 3.2):

    lerobot-find-cameras orbbec
    
    lerobot-teleoperate \
      --robot.type=so101_follower \
      --robot.port=/dev/so101_follower \
      --robot.id=so101_follower \
      --robot.cameras='{"handeye":{"type":"orbbec","index_or_serial_number":"<SN1>","width":640,"height":480,"fps":30,"use_depth":true,"align_depth":true,"d2c_mode":"hardware"},"up":{"type":"orbbec","index_or_serial_number":"<SN2>","width":640,"height":480,"fps":30,"use_depth":true,"align_depth":true,"d2c_mode":"hardware"}}' \
      --teleop.type=so101_leader \
      --teleop.port=/dev/so101_leader \
      --teleop.id=so101_leader \
      --display_data=true

Checklist (required before merge)

  • Linting/formatting run (pre-commit run -a)
  • All tests pass locally (pytest)
  • Documentation updated
  • CI is green

Reviewer notes

  • Please focus on the hardware D2C fallback logic in _configure_pipeline (src/lerobot/cameras/orbbec/camera_orbbec.py): when the device does not support hardware D2C, the code automatically switches to a software AlignFilter to prevent runtime crashes.
  • D2CMode default was changed from HARDWARE to SOFTWARE for broader device compatibility; hardware mode offers lower latency and can be explicitly enabled via config.
  • Mock tests cover all public methods; hardware integration tests require manual validation on a real device.
  • Anyone in the community is free to review the PR.

orbbecwuxin and others added 13 commits March 5, 2026 12:46
Implements OrbbecCamera and OrbbecCameraConfig for Orbbec depth cameras
(Gemini 336 / 336L tested), mirroring the RealSense camera interface.

Key features:
- Color and depth streaming with frame-level synchronisation
- Optional depth-to-color alignment via AlignFilter (align_depth=True)
- Separate capture_depth_width/height tracking to handle differing color
  and depth sensor resolutions without validation errors
- Lazy background thread for async_read() / async_read_depth()
- read_latest() peek-buffer for high-frequency consumers
- find_cameras() static method + lerobot-find-cameras orbbec CLI entry
- Multi-format color conversion: RGB, BGR, YUYV, MJPG, NV12, NV21, I420

Bug fixes:
- np.frombuffer(dtype=uint8) for color frames (was np.asanyarray causing
  0-d object array from bytes input)
- Rotation 90/270: swap output self.width/height, not capture dims
- Error message backticks removed to match pytest match= regex

All 32 unit tests pass (mock); hardware validated on 2x Orbbec cameras
(Gemini 336 + Gemini 336L, USB 3.2) across 12 sync/async scenarios.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….18 SDK patterns

- Replace manual format conversion in _frame_to_rgb_image with FormatConvertFilter
  (matching SDK examples/utils.py); use np.frombuffer instead of np.asanyarray
  to avoid OOM when frame.get_data() returns bytes
- Add hardware D2C alignment via config.set_align_mode(OBAlignMode.HW_MODE) +
  get_d2c_depth_profile_list (hw_d2c_align.py pattern); fall back to software
  AlignFilter when hardware mode unavailable
- Enable pipeline.enable_frame_sync() for depth+color synchronisation
- Merge _configure_capture_settings into _configure_pipeline; remove redundant
  state (_depth_profile_size, capture_depth_width/height, _has_color_sensor)
- Split _postprocess_image into _postprocess_color / _postprocess_depth
- Restore find_cameras sensor probing (has_color_sensor, has_depth_sensor,
  default profiles) for multi-camera setup support
- Use device_list[idx] direct indexing (SDK 2.0.18 enumerate.py style)
- Warmup loop uses new_frame_event.wait() instead of try-except-pass
- Fix ruff/mypy/bandit: add FrameSet import, assert guards for _pipeline and
  stop_event, combine nested if, remove try-except-pass

test(cameras/orbbec): update mocks to match refactored implementation

- Add __getitem__ to _make_device_list so device_list[idx] works in tests
- Update error message match patterns to align with new code messages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions github-actions bot added documentation Improvements or fixes to the project’s docs tests Problems with test coverage, failures, or improvements to testing sensors Everything related to sensors labels Mar 9, 2026
@imstevenpmwork imstevenpmwork self-assigned this Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or fixes to the project’s docs sensors Everything related to sensors tests Problems with test coverage, failures, or improvements to testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants