Record Episodes

Once you’re familiar with teleoperation, you can record your first dataset.

Logging into Hugging Face

If you want to use Hugging Face Hub features for uploading your dataset and you haven’t done so before, make sure you’ve logged in using a write-access token which can be generated from the Hugging Face settings.

huggingface-cli login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential

Store your Hugging Face repository name in a variable:

HF_USER=$(huggingface-cli whoami | head -n 1)
echo $HF_USER

Recording and Uploading a Dataset

Record two episodes and upload your dataset to the Hugging Face Hub:

uv run lerobot-record \
    --robot.type=bi_widowxai_follower_robot \
    --robot.left_arm_ip_address=192.168.1.5 \
    --robot.right_arm_ip_address=192.168.1.4 \
    --robot.id=bimanual_follower \
    --robot.cameras='{
    cam_low: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    cam_high: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    cam_left_wrist: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    cam_right_wrist: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    }' \
    --teleop.type=bi_widowxai_leader_teleop \
    --teleop.left_arm_ip_address=192.168.1.3 \
    --teleop.right_arm_ip_address=192.168.1.2 \
    --teleop.id=bimanual_leader \
    --display_data=true \
    --dataset.repo_id=${HF_USER}/bimanual-widowxai-handover-cube \
    --dataset.episode_time_s=60 \
    --dataset.reset_time_s=15 \
    --dataset.num_episodes=2 \
    --dataset.push_to_hub=true \
    --dataset.single_task="Grab and handover the red cube to the other arm"

Note

The units for each joint are as follows:

  • Joints 0-5: Radians

  • Joint 6 (Gripper): Meters

Handling Camera FPS Issues

Note

If the camera FPS is unstable, consider increasing the number of image writers per thread or disable camera display.

uv run lerobot-record \
    --robot.type=bi_widowxai_follower_robot \
    --robot.left_arm_ip_address=192.168.1.5 \
    --robot.right_arm_ip_address=192.168.1.4 \
    --robot.id=bimanual_follower \
    --robot.cameras= '{
    cam_low: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    cam_high: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    cam_left_wrist: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    cam_right_wrist: {"type": "intelrealsense", "serial_number_or_name": "0123456789", "width": 640, "height": 480, "fps": 30},
    }' \
    --teleop.type=bi_widowxai_leader_teleop \
    --teleop.left_arm_ip_address=192.168.1.3 \
    --teleop.right_arm_ip_address=192.168.1.2 \
    --teleop.id=bimanual_leader \
    --display_data=true \
    --dataset.repo_id=${HF_USER}/bimanual-widowxai-handover-cube \
    --dataset.episode_time_s=60 \
    --dataset.reset_time_s=15 \
    --dataset.num_episodes=2 \
    --dataset.push_to_hub=true \
    --dataset.single_task="Grab and handover the red cube to the other arm" \
    --dataset.num_image_writer_threads_per_camera=8 \
    --display_data=false

If using RealSense camera interface is causing fps issues, you can try using the OpenCV interface instead. Make sure that you have configured the cameras correctly as described in Camera Serial Number.

Recording Configuration

When recording a dataset, you can specify command line arguments to customize the behavior:

  • --dataset.repo_id (str): The dataset identifier. By convention, it should match the format {hf_username}/{dataset_name} (e.g. lerobot/test). (default: None)

  • --dataset.single_task (str): A short but accurate description of the task performed during the recording (e.g. “Pick the Lego block and drop it in the box on the right.”). (default: None)

  • --dataset.root (str | Path | None): The root directory where the dataset will be stored (e.g. ‘dataset/path’). (default: None)

  • --dataset.fps (int): The number of frames per second to record. (default: 30)

  • --dataset.episode_time_s (int | float): The duration of data recording for each episode in seconds. (default: 60)

  • --dataset.reset_time_s (int | float): The duration of the reset phase after each episode in seconds. (default: 60)

  • --dataset.num_episodes (int): The number of episodes to record. (default: 50)

  • --dataset.video (bool): Flag to encode frames in the dataset into video. (default: True)

  • --dataset.push_to_hub (bool): Flag to upload the dataset to the Hugging Face Hub. (default: True)

  • --dataset.private (bool): Flag to upload the dataset to a private repository on the Hugging Face Hub. (default: False)

  • --dataset.tags (list[str]): A list of tags to add to the dataset on the Hub. (default: None)

  • --dataset.num_image_writer_processes (int): The number of subprocesses handling the saving of frames as PNGs. Set to 0 to use threads only; set to ≥1 to use subprocesses, each using threads to write images. (default: 0)

  • --dataset.num_image_writer_threads_per_camera (int): The number of threads writing frames as PNG images on disk, per camera. Too many threads might cause unstable teleoperation FPS due to main thread blocking; too few might cause low camera FPS. (default: 4)

  • --dataset.video_encoding_batch_size (int): The number of episodes to record before batch encoding videos. Set to 1 for immediate encoding (default behavior), or higher for batched encoding. (default: 1)

  • --dataset.rename_map (dict): A rename map for observations to override image and state keys. (default: {})