LeRobot documentation
相机
相机
LeRobot 提供了多种视频采集选项:
| 类 | 支持的相机 |
|---|---|
OpenCVCamera | 手机、内置笔记本电脑摄像头、USB 摄像头 |
ZMQCamera | 网络摄像头 |
RealSenseCamera | Intel RealSense(带深度) |
Reachy2Camera | Reachy 2 机器人摄像头 |
有关
OpenCVCamera的兼容性详情,请参阅 OpenCV 视频 I/O 概述。
找到您的摄像头
每个摄像头都需要一个唯一的标识符才能被实例化,以便区分多个已连接的设备。
OpenCVCamera 和 RealSenseCamera 支持自动发现。运行以下命令以列出可用设备及其标识符。请注意,根据操作系统的不同,这些标识符可能会在重启计算机或重新插拔摄像头后发生变化。
lerobot-find-cameras opencv # or realsense for Intel Realsense cameras如果连接了两个摄像头,输出将类似于以下内容:
--- Detected Cameras ---
Camera #0:
Name: OpenCV Camera @ 0
Type: OpenCV
Id: 0
Backend api: AVFOUNDATION
Default stream profile:
Format: 16.0
Width: 1920
Height: 1080
Fps: 15.0
--------------------
(more cameras ...)在
macOS上使用 Intel RealSense 相机时,可能会遇到此 错误:Error finding RealSense cameras: failed to set power state。可以通过使用sudo权限运行相同命令来解决此问题。请注意,在macOS上使用 RealSense 相机并不稳定。
ZMQCamera 和 Reachy2Camera 不支持自动发现。必须通过提供其网络地址和端口或机器人 SDK 设置来手动配置它们。
相机放置与照明
相机图像是策略学习的依据,因此良好的相机设置比高分辨率更为重要:
- 均匀照亮场景。 使用漫射且一致的光线,避免直射阳光、强烈反光和移动阴影。录制与部署之间的光照差异可能导致策略失效。
- 固定相机位置。 请将其牢固安装,并在录制会话之间,或录制与部署之间保持不动。
- 明确任务。 物体、夹爪和目标应在至少一个摄像头中可见。一个好的测试方法:仅通过查看摄像头图像,您能否自己完成该任务?
- 保持分辨率适中。 640×480 分辨率、30 fps 帧率对于大多数任务已经足够,同时也能确保录制和训练的速度。
使用摄像头
帧访问模式
所有相机类都实现了三种用于捕获帧的访问模式:
| 方法 | 行为 | Blocks? | 最适用于 |
|---|---|---|---|
read() | 等待相机硬件返回一帧图像。根据相机和 SDK 的不同,可能会长时间阻塞。 | 是的 | 简单脚本,顺序捕获 |
async_read(timeout_ms) | 返回后台线程中最新的未消费帧。仅当缓冲区为空时阻塞,最长等待 timeout_ms。如果未收到帧,则引发 TimeoutError。 | 带超时 | 与相机帧率同步的控制循环 |
read_latest(max_age_ms) | 查看缓冲区中最新的帧(可能已过期)。如果帧的年龄超过 max_age_ms,则引发 TimeoutError。 | No | UI 可视化、日志记录、监控 |
使用示例
以下示例展示了如何使用相机 API 来配置不同类型的相机并捕获帧。
- 使用基于 OpenCV 的相机进行阻塞和非阻塞帧捕获
- 使用 Intel RealSense 相机进行颜色和深度捕获
未能干净地断开相机连接可能会导致资源泄漏。请使用上下文管理器协议以确保自动清理:
with OpenCVCamera(config) as camera: ...您也可以手动调用
connect()和disconnect(),但请务必在后者中使用finally块。
from lerobot.cameras.opencv import OpenCVCamera, OpenCVCameraConfig
from lerobot.cameras import ColorMode, Cv2Rotation
# Construct an `OpenCVCameraConfig` with your desired FPS, resolution, color mode, and rotation.
config = OpenCVCameraConfig(
index_or_path=0,
fps=15,
width=1920,
height=1080,
color_mode=ColorMode.RGB,
rotation=Cv2Rotation.NO_ROTATION
)
# Instantiate and connect an `OpenCVCamera`, performing a warm-up read (default).
with OpenCVCamera(config) as camera:
# Read a frame synchronously — blocks until hardware delivers a new frame
frame = camera.read()
print(f"read() call returned frame with shape:", frame.shape)
# Read a frame asynchronously with a timeout — returns the latest unconsumed frame or waits up to timeout_ms for a new one
try:
for i in range(10):
frame = camera.async_read(timeout_ms=200)
print(f"async_read call returned frame {i} with shape:", frame.shape)
except TimeoutError as e:
print(f"No frame received within timeout: {e}")
# Instantly return a frame - returns the most recent frame captured by the camera
try:
initial_frame = camera.read_latest(max_age_ms=1000)
for i in range(10):
frame = camera.read_latest(max_age_ms=1000)
print(f"read_latest call returned frame {i} with shape:", frame.shape)
print(f"Was a new frame received by the camera? {not (initial_frame == frame).any()}")
except TimeoutError as e:
print(f"Frame too old: {e}")
from lerobot.cameras.realsense import RealSenseCamera, RealSenseCameraConfig
from lerobot.cameras import ColorMode, Cv2Rotation
# Create a `RealSenseCameraConfig` specifying your camera’s serial number and enabling depth.
config = RealSenseCameraConfig(
serial_number_or_name="233522074606",
fps=15,
width=640,
height=480,
color_mode=ColorMode.RGB,
use_depth=True,
# Optional fixed color controls. Omit them to leave the current sensor settings unchanged.
exposure=120,
gain=64,
white_balance=4600,
rotation=Cv2Rotation.NO_ROTATION
)
# Instantiate and connect a `RealSenseCamera` with warm-up read (default).
camera = RealSenseCamera(config)
camera.connect()
# Capture a color frame via `read()` and a depth map via `read_depth()`.
try:
color_frame = camera.read()
depth_map = camera.read_depth()
print("Color frame shape:", color_frame.shape)
print("Depth map shape:", depth_map.shape)
finally:
camera.disconnect()手动颜色控制会禁用相应的自动曝光或白平衡模式。其支持的取值范围因相机型号而异;如果传入无效值,将在连接时引发错误,错误信息中会包含传感器报告的取值范围。请求不支持的控制项同样会引发错误。省略的控制项将保持传感器现有的自动或手动设置不变。这些选项需要 use_rgb=True。
手动颜色控制需要专用的 RGB 模块。没有该模块的相机(例如 RealSense D405)不支持这些控制,并会在连接时引发错误。
处理深度
Intel RealSense 和 Reachy 2 摄像头可以同步捕获彩色和深度数据。调用 read() 会以 (H, W, 3) uint8 格式返回 彩色 帧。调用 read_depth() 会以 (H, W, 1) uint16 格式返回 深度图,其中每个像素值表示以毫米为单位的传感器距离。像素值为 0 通常表示“无可用测量值”(超出范围、被遮挡或置信度低)。
在录制过程中,控制循环通过 read_latest()(颜色)和 read_latest_depth()(深度)非阻塞地读取最新的缓冲帧,并将深度图作为同级特征添加(例如,在 front 旁边添加 front_depth)。
有关在录制数据集时深度流的存储和编码方式,请参阅视频编码指南中的深度流部分。
使用手机摄像头
要在 macOS 上将 iPhone 用作摄像头,请启用连续互通相机功能:
- 请确保您的 Mac 运行的是 macOS 13 或更高版本,并且您的 iPhone 使用的是 iOS 16 或更高版本。
- 使用相同的 Apple ID 登录两台设备。
- 使用 USB 数据线连接您的设备,或开启 Wi-Fi 和蓝牙以建立无线连接。
有关更多详细信息,请访问 Apple 支持。
如果想在 OBS 中将手机用作摄像头,请按照以下步骤设置虚拟摄像头。
- (仅限 Linux)安装
v4l2loopback-dkms和v4l-utils。这些包用于创建虚拟摄像头设备并验证其设置。使用以下命令安装:
sudo apt install v4l2loopback-dkms v4l-utils在手机上安装 DroidCam 应用。该应用支持 iOS 和 Android 系统。
下载并安装 OBS Studio。
下载并安装 DroidCam OBS 插件。
启动 OBS Studio。
将您的手机添加为源。请按照此处的说明操作。请务必将分辨率设置为
640x480,以避免出现水印。调整分辨率设置。在 OBS Studio 中,前往
File > Settings > Video或OBS > Preferences... > Video。手动输入将Base(Canvas) Resolution和Output(Scaled) Resolution更改为640x480。启动虚拟摄像头。在 OBS Studio 中,请按照此处的说明操作。
验证虚拟摄像头的设置和分辨率。
- Linux: 使用
v4l2-ctl列出设备并检查分辨率:您应该能看到v4l2-ctl --list-devices # find VirtualCam and note its /dev/videoX path v4l2-ctl -d /dev/videoX --get-fmt-video # replace with your VirtualCam pathVirtualCam已列出,分辨率为640x480. - macOS:打开 Photo Booth 或 FaceTime,并选择“OBS Virtual Camera”作为输入。
- Windows:原生相机应用不支持虚拟相机。请使用视频会议应用(Zoom、Teams),或直接运行
lerobot-find-cameras opencv进行验证。
- Linux: 使用
Troubleshooting
虚拟相机分辨率不正确。
删除虚拟相机源并重新创建它。创建后无法更改分辨率。
在后台线程中读取 OpenCVCamera(X) 帧时出错:OpenCVCamera(X) 的帧宽度=640 或高度=480 与配置的宽度=1920 或高度=1080 不匹配。
此错误是由 OBS 虚拟摄像头在重新缩放后仍报告 1920x1080 分辨率引起的。目前唯一的解决方法是注释掉 _postprocess_image() 中的宽度和高度检查。
如果一切设置正确,您的手机将显示为标准 OpenCV 摄像头,并可与 OpenCVCamera 一起使用。