examples/notebooks/quickstart.ipynb
Calibration → teleoperation → data collection → training → evaluation.
Install the required dependencies: pip install -e .[notebook,dataset,training,viz,hardware].
How to use:
Run All).Each setup is different, please refer to the LeRobot documentation for more details on each step and available options.
Feel free to make this notebook your own and adapt it to your needs!
def _cameras_arg(cameras: dict) -> str:
if not cameras:
return ""
entries = [f"{n}: {{{', '.join(f'{k}: {v}' for k, v in cfg.items())}}}" for n, cfg in cameras.items()]
return "{ " + ", ".join(entries) + " }"
def print_cmd(*parts: str) -> None:
"""Print a shell command with line continuations, skipping empty parts."""
non_empty = [p for p in parts if p]
print(" \\\n ".join(non_empty))
Edit this cell, then Run All to generate all commands below.
# Robot (follower) - run `lerobot-find-port` to discover the port
ROBOT_TYPE = "so101_follower"
ROBOT_PORT = "/dev/ttyACM0"
ROBOT_ID = "my_follower_arm"
# Teleop (leader) - run `lerobot-find-port` to discover the port
TELEOP_TYPE = "so101_leader"
TELEOP_PORT = "/dev/ttyACM1"
TELEOP_ID = "my_leader_arm"
# Cameras - set to {} to disable
# Run `lerobot-find-cameras opencv` to list available cameras and their indices
CAMERAS = {
"top": {"type": "opencv", "index_or_path": 2, "width": 640, "height": 480, "fps": 30},
"wrist": {"type": "opencv", "index_or_path": 4, "width": 640, "height": 480, "fps": 30},
}
# Dataset
HF_USER = "your_hf_username" # `hf auth whoami` to find your username
DATASET_NAME = "my_so101_dataset"
TASK_DESCRIPTION = "pick and place the block"
NUM_EPISODES = 10
# Training
POLICY_TYPE = "act" # act, diffusion, smolvla, ...
POLICY_DEVICE = "cuda" # cuda / cpu / mps
TRAIN_STEPS = 10_000
SAVE_FREQ = 2_000
OUTPUT_DIR = f"outputs/train/{DATASET_NAME}"
# Inference - Hub repo ID or local checkpoint path
# e.g. set to f"{OUTPUT_DIR}/checkpoints/last" to use a local checkpoint
POLICY_PATH = f"{HF_USER}/{DATASET_NAME}_{POLICY_TYPE}"
LAST_CHECKPOINT_PATH = f"{OUTPUT_DIR}/checkpoints/last"
# Derived
DATASET_REPO_ID = f"{HF_USER}/{DATASET_NAME}"
DATASET_ROOT = f"data/{DATASET_NAME}"
POLICY_REPO_ID = f"{HF_USER}/{DATASET_NAME}_{POLICY_TYPE}"
EVAL_REPO_ID = f"{HF_USER}/eval_{DATASET_NAME}"
CAMERAS_ARG = _cameras_arg(CAMERAS)
CAMERAS_FLAG = f'--robot.cameras="{CAMERAS_ARG}"' if CAMERAS_ARG else ""
print(f"Robot : {ROBOT_TYPE} @ {ROBOT_PORT}")
print(f"Teleop : {TELEOP_TYPE} @ {TELEOP_PORT}")
print(f"Cameras: {list(CAMERAS) or 'none'}")
print(f"Dataset: {DATASET_REPO_ID} ({NUM_EPISODES} episodes) saved to {DATASET_ROOT}")
print(f"Policy : {POLICY_TYPE} -> {POLICY_REPO_ID}")
Run once per arm before first use.
# Follower
print_cmd(
"lerobot-calibrate",
f"--robot.type={ROBOT_TYPE}",
f"--robot.port={ROBOT_PORT}",
f"--robot.id={ROBOT_ID}",
)
# Leader
print_cmd(
"lerobot-calibrate",
f"--teleop.type={TELEOP_TYPE}",
f"--teleop.port={TELEOP_PORT}",
f"--teleop.id={TELEOP_ID}",
)
See the teleoperation docs and the cameras guide for more options.
print_cmd(
"lerobot-teleoperate",
f"--robot.type={ROBOT_TYPE}",
f"--robot.port={ROBOT_PORT}",
f"--robot.id={ROBOT_ID}",
CAMERAS_FLAG,
f"--teleop.type={TELEOP_TYPE}",
f"--teleop.port={TELEOP_PORT}",
f"--teleop.id={TELEOP_ID}",
"--display_data=true",
)
See the recording docs for tips on gathering good data.
print_cmd(
"lerobot-record",
f"--robot.type={ROBOT_TYPE}",
f"--robot.port={ROBOT_PORT}",
f"--robot.id={ROBOT_ID}",
CAMERAS_FLAG,
f"--teleop.type={TELEOP_TYPE}",
f"--teleop.port={TELEOP_PORT}",
f"--teleop.id={TELEOP_ID}",
f"--dataset.repo_id={DATASET_REPO_ID}",
f"--dataset.num_episodes={NUM_EPISODES}",
f'--dataset.single_task="{TASK_DESCRIPTION}"',
"--dataset.streaming_encoding=true",
"--display_data=true",
)
# Resume a previously interrupted recording session
print_cmd(
"lerobot-record",
f"--robot.type={ROBOT_TYPE}",
f"--robot.port={ROBOT_PORT}",
f"--robot.id={ROBOT_ID}",
CAMERAS_FLAG,
f"--teleop.type={TELEOP_TYPE}",
f"--teleop.port={TELEOP_PORT}",
f"--teleop.id={TELEOP_ID}",
f"--dataset.repo_id={DATASET_REPO_ID}",
f"--dataset.root={DATASET_ROOT}",
f"--dataset.num_episodes={NUM_EPISODES}",
f'--dataset.single_task="{TASK_DESCRIPTION}"',
"--dataset.streaming_encoding=true",
"--display_data=true",
"--resume=true",
)
See the training docs for configuration options and tips.
print_cmd(
"lerobot-train",
f"--dataset.repo_id={DATASET_REPO_ID}",
f"--policy.type={POLICY_TYPE}",
f"--policy.device={POLICY_DEVICE}",
f"--policy.repo_id={POLICY_REPO_ID}",
f"--output_dir={OUTPUT_DIR}",
f"--steps={TRAIN_STEPS}",
f"--save_freq={SAVE_FREQ}",
)
# Resume a previously interrupted training session
print_cmd(
"lerobot-train",
f"--config_path={LAST_CHECKPOINT_PATH}/pretrained_model/train_config.json",
"--resume=true",
)
Uses POLICY_PATH from the Configuration cell (defaults to the Hub repo ID). You can also put there the LAST_CHECKPOINT_PATH.
See the inference docs for details.
Recently lerobot-rollout was introduced, you can read more about it here.
print_cmd(
"lerobot-rollout",
"--strategy.type=base",
f"--policy.path={POLICY_PATH}",
f"--robot.type={ROBOT_TYPE}",
f"--robot.port={ROBOT_PORT}",
CAMERAS_FLAG,
f'--task="{TASK_DESCRIPTION}"',
"--duration=60",
)
if you are using the V0.5.1 release you should use lerobot-record instead of rollout
print_cmd(
"lerobot-record",
f"--policy.path={POLICY_PATH}",
f"--robot.type={ROBOT_TYPE}",
f"--robot.port={ROBOT_PORT}",
f"--robot.id={ROBOT_ID}",
CAMERAS_FLAG,
f"--teleop.type={TELEOP_TYPE}",
f"--teleop.port={TELEOP_PORT}",
f"--teleop.id={TELEOP_ID}",
f"--dataset.repo_id={EVAL_REPO_ID}",
f"--dataset.num_episodes={NUM_EPISODES}",
f'--dataset.single_task="{TASK_DESCRIPTION}"',
"--dataset.streaming_encoding=true",
)