# Aprendizado por Imitação em Robôs do Mundo Real

Este tutorial explicará como treinar uma rede neural para controlar um robô real de forma autônoma.

**Você vai aprender:**

1. Como gravar e visualizar seu conjunto de dados.
2. Como treinar uma política usando seus dados e prepará-la para avaliação.
3. Como avaliar sua política e visualizar os resultados.

Ao seguir essas etapas, você será capaz de replicar tarefas, como pegar um bloco de Lego e colocá-lo em uma caixa, com uma alta taxa de sucesso, conforme mostrado no vídeo abaixo.

Vídeo: tarefa de pegar um bloco de lego

  
    <source
      src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/lerobot_task.mp4"
      type="video/mp4"
    />
  

Este tutorial não está vinculado a um robô específico: mostramos os comandos e trechos de API que você pode adaptar para qualquer plataforma suportada.

Durante a coleta de dados, você usará um dispositivo de “teleoperação”, como um braço líder ou um teclado, para teleoperar o robô e registrar suas trajetórias de movimento.

Depois de reunir trajetórias suficientes, você treina uma rede neural para imitar essas trajetórias e implanta o modelo treinado para que seu robô possa executar a tarefa de forma autônoma.

Se você encontrar algum problema em qualquer momento, entre na nossa [comunidade do Discord](https://discord.com/invite/s3KuuzsPFb) para obter suporte.

Quer obter rapidamente os comandos corretos para a sua configuração? O [notebook de introdução](https://github.com/huggingface/lerobot/blob/main/examples/notebooks/quickstart.ipynb) [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/huggingface/lerobot/blob/main/examples/notebooks/quickstart.ipynb) permite configurar o seu robô uma única vez e gera todos os comandos abaixo prontos para colar.

## Configurar e Calibrar

Se você ainda não configurou e calibrou seu robô e dispositivo de teleop, faça isso seguindo o tutorial para o seu robô, por exemplo [SO-101](./so101), [OpenArm](./openarm), [Koch](./koch) ou [LeKiwi](./lekiwi). Todos os robôs suportados estão listados em **Robots** na barra lateral.

## Teleoperação

Neste exemplo, demonstraremos como teleoperar o robô SO101. Para cada comando, também fornecemos um exemplo de API correspondente.

Observe que o `id` associado a um robô é usado para armazenar o arquivo de calibração. É importante usar o mesmo `id` ao teleoperar, gravar e avaliar ao usar a mesma configuração.

```bash
lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem58760431541 \
    --robot.id=my_awesome_follower_arm \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem58760431551 \
    --teleop.id=my_awesome_leader_arm
```

```python
from lerobot.teleoperators.so_leader import SO101Leader, SO101LeaderConfig
from lerobot.robots.so_follower import SO101Follower, SO101FollowerConfig

robot_config = SO101FollowerConfig(
    port="/dev/tty.usbmodem5AB90687491",
    id="my_follower_arm",
)

teleop_config = SO101LeaderConfig(
    port="/dev/tty.usbmodem5AB90689011",
    id="my_leader_arm",
)

robot = SO101Follower(robot_config)
teleop_device = SO101Leader(teleop_config)
robot.connect()
teleop_device.connect()

while True:
    action = teleop_device.get_action()
    robot.send_action(action)
```

O comando teleoperate executará automaticamente:

1. Identifique calibrações ausentes e inicie o procedimento de calibração.
2. Conecte o robô e o dispositivo de teleoperação e inicie a teleoperação.

## Câmeras

Para adicionar câmeras à sua configuração, siga este [Guia](./cameras).

## Teleopere com câmeras

Com o `rerun`, você pode teleoperar novamente enquanto visualiza simultaneamente os feeds das câmeras e as posições das juntas. Este exemplo usa duas câmeras, `wrist` e `top`; mantemos a mesma configuração de câmeras para o restante do tutorial.

```bash
lerobot-teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem5AB90687491 \
    --robot.id=my_follower_arm \
    --robot.cameras="{ wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, top: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem5AB90689011 \
    --teleop.id=my_leader_arm \
    --display_data=true
```

```python
import time
from lerobot.teleoperators.so_leader import SO101Leader, SO101LeaderConfig
from lerobot.robots.so_follower import SO101Follower, SO101FollowerConfig
from lerobot.cameras.opencv import OpenCVCameraConfig
from lerobot.utils.visualization_utils import init_visualization, log_visualization_data, shutdown_visualization

robot_config = SO101FollowerConfig(
    port="/dev/tty.usbmodem5AB90687491",
    id="my_follower_arm",
    cameras={
        "wrist": OpenCVCameraConfig(index_or_path=0, width=640, height=480, fps=30),
        "top": OpenCVCameraConfig(index_or_path=1, width=640, height=480, fps=30)
    }
)

teleop_config = SO101LeaderConfig(
    port="/dev/tty.usbmodem5AB90689011",
    id="my_leader_arm",
)

init_visualization("rerun", session_name="teleoperation")  # pass "foxglove" to stream to Foxglove instead

robot = SO101Follower(robot_config)
teleop_device = SO101Leader(teleop_config)
robot.connect()
teleop_device.connect()

TARGET_HZ = 30
TIME_PER_FRAME = 1.0 / TARGET_HZ

while True:
    start_time = time.perf_counter()

    observation = robot.get_observation()
    action = teleop_device.get_action()
    robot.send_action(action)
    log_visualization_data("rerun", observation=observation, action=action)

    elapsed_time = time.perf_counter() - start_time
    sleep_time = TIME_PER_FRAME - elapsed_time
    if sleep_time > 0:
        time.sleep(sleep_time)
```

## Registrar um conjunto de dados

Depois que você estiver familiarizado com a teleoperação, poderá gravar seu primeiro conjunto de dados.

Usamos os recursos do hub do Hugging Face para enviar seu dataset. Se você ainda não usou o Hub, verifique se consegue fazer login via cli usando um token de acesso de escrita; esse token pode ser gerado nas [configurações do Hugging Face](https://huggingface.co/settings/tokens).

Adicione seu token ao CLI executando este comando:

```bash
hf auth login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential
```

Em seguida, armazene o nome do seu repositório do Hugging Face em uma variável:

```bash
HF_USER=$(NO_COLOR=1 hf auth whoami | awk -F': *' 'NR==1 {print $2}')
echo $HF_USER
```

Agora você pode gravar um conjunto de dados. Para gravar 5 episódios e enviar seu conjunto de dados para o hub, adapte o código abaixo para o seu robô e execute o comando ou o exemplo de API.

```bash
lerobot-record \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem585A0076841 \
    --robot.id=my_awesome_follower_arm \
    --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \
    --robot.cameras="{ wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, top: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
    --teleop.type=so101_leader \
    --teleop.port=/dev/tty.usbmodem58760431551 \
    --teleop.id=my_awesome_leader_arm \
    --display_data=true \
    --dataset.repo_id=${HF_USER}/record-test \
    --dataset.num_episodes=5 \
    --dataset.single_task="Grab the black cube" \
    --dataset.streaming_encoding=true \
    --dataset.encoder_threads=2
# Optional: --dataset.rgb_encoder.vcodec=auto
```

```python
from lerobot.cameras.opencv import OpenCVCameraConfig
from lerobot.datasets.lerobot_dataset import LeRobotDataset
from lerobot.utils.feature_utils import hw_to_dataset_features
from lerobot.robots.so_follower import SO101Follower, SO101FollowerConfig
from lerobot.teleoperators.so_leader.config_so_leader import SO101LeaderConfig
from lerobot.teleoperators.so_leader.so_leader import SO101Leader
from lerobot.common.control_utils import init_keyboard_listener
from lerobot.utils.utils import log_say
from lerobot.utils.visualization_utils import init_visualization
from lerobot.scripts.lerobot_record import record_loop
from lerobot.processor import make_default_processors

NUM_EPISODES = 5
FPS = 30
EPISODE_TIME_SEC = 60
RESET_TIME_SEC = 10
TASK_DESCRIPTION = "My task description"

def main():
    # Create robot configuration
    robot_config = SO101FollowerConfig(
        port="/dev/tty.usbmodem5AB90687491",
        id="my_follower_arm",
        cameras={
            "wrist": OpenCVCameraConfig(index_or_path=0, width=640, height=480, fps=30),
            "top": OpenCVCameraConfig(index_or_path=1, width=640, height=480, fps=30)
        }
    )

    teleop_config = SO101LeaderConfig(
        port="/dev/tty.usbmodem5AB90689011",
        id="my_leader_arm",
    )

    # Initialize the robot and teleoperator
    robot = SO101Follower(robot_config)
    teleop = SO101Leader(teleop_config)

    # Configure the dataset features
    action_features = hw_to_dataset_features(robot.action_features, "action")
    obs_features = hw_to_dataset_features(robot.observation_features, "observation")
    dataset_features = {**action_features, **obs_features}

    # Create the dataset
    dataset = LeRobotDataset.create(
        repo_id="<hf_username>/<dataset_repo_id>",
        fps=FPS,
        features=dataset_features,
        robot_type=robot.name,
        use_videos=True,
        image_writer_threads=4,
    )

    # Initialize the keyboard listener and rerun visualization
    _, events = init_keyboard_listener()
    init_visualization("rerun", session_name="recording")

    # Connect the robot and teleoperator
    robot.connect()
    teleop.connect()

    # Create the required processors
    teleop_action_processor, robot_action_processor, robot_observation_processor = make_default_processors()

    episode_idx = 0
    while episode_idx < NUM_EPISODES and not events["stop_recording"]:
        log_say(f"Recording episode {episode_idx + 1} of {NUM_EPISODES}")

        record_loop(
            robot=robot,
            events=events,
            fps=FPS,
            teleop_action_processor=teleop_action_processor,
            robot_action_processor=robot_action_processor,
            robot_observation_processor=robot_observation_processor,
            teleop=teleop,
            dataset=dataset,
            control_time_s=EPISODE_TIME_SEC,
            single_task=TASK_DESCRIPTION,
            display_data=True,
        )

        # Reset the environment if not stopping or re-recording
        if not events["stop_recording"] and (episode_idx < NUM_EPISODES - 1 or events["rerecord_episode"]):
            log_say("Reset the environment")
            record_loop(
                robot=robot,
                events=events,
                fps=FPS,
                teleop_action_processor=teleop_action_processor,
                robot_action_processor=robot_action_processor,
                robot_observation_processor=robot_observation_processor,
                teleop=teleop,
                control_time_s=RESET_TIME_SEC,
                single_task=TASK_DESCRIPTION,
                display_data=True,
            )

        if events["rerecord_episode"]:
            log_say("Re-recording episode")
            events["rerecord_episode"] = False
            events["exit_early"] = False
            dataset.clear_episode_buffer()
            continue

        dataset.save_episode()
        episode_idx += 1

    # finalize dataset
    log_say("Finalizing dataset...")
    dataset.finalize()
    # Clean up
    log_say("Stop recording")
    robot.disconnect()
    teleop.disconnect()
    dataset.push_to_hub()

if __name__ == "__main__":
    main()
```

Os nomes das câmeras que você escolher (aqui `wrist` e `top`) se tornam as chaves do dataset `observation.images.wrist` e `observation.images.top`. Uma política treinada neste dataset espera os mesmos nomes de câmeras e resolução quando você a implantar, então reutilize o mesmo valor de `--robot.cameras` em cada etapa deste tutorial. Se os nomes tiverem que ser diferentes, consulte [Rename Map](./rename_map).

`lerobot-record` adiciona a data e a hora da sessão ao final de `--dataset.repo_id`, de modo que cada gravação receba um nome único: `${HF_USER}/record-test` é salvo como `${HF_USER}/record-test_YYYYMMDD_HHMMSS` (por exemplo, `record-test_20260929_143012`). Encontre o nome completo no seu perfil do Hugging Face ou com `ls ~/.cache/huggingface/lerobot/${HF_USER}`, e use-o em todos os lugares em que os comandos abaixo indicam `record-test_YYYYMMDD_HHMMSS`. Para manter exatamente o nome que você passou, adicione `--dataset.no_stamp=true`.

#### Upload de dataset

Localmente, seu conjunto de dados é armazenado nesta pasta: `~/.cache/huggingface/lerobot/{repo-id}`. Ao final da gravação dos dados, seu conjunto de dados será enviado para a sua página do Hugging Face (por exemplo, `https://huggingface.co/datasets/${HF_USER}/record-test_YYYYMMDD_HHMMSS`), que você pode obter executando:

```bash
echo https://huggingface.co/datasets/${HF_USER}/record-test_YYYYMMDD_HHMMSS
```

Seu conjunto de dados será automaticamente marcado com `LeRobot` para que a comunidade o encontre facilmente, e você também pode adicionar tags personalizadas, por exemplo `--dataset.tags='["tutorial"]'`.

Você pode procurar por outros conjuntos de dados do LeRobot no hub pesquisando pelas [tags](https://huggingface.co/datasets?other=LeRobot) `LeRobot`.

Você também pode enviar seu dataset local para o Hub manualmente, executando:

```bash
hf upload ${HF_USER}/record-test_YYYYMMDD_HHMMSS ~/.cache/huggingface/lerobot/${HF_USER}/record-test_YYYYMMDD_HHMMSS --repo-type dataset
```

#### Função de registro

`lerobot-record` fornece um conjunto de ferramentas para capturar e gerenciar dados durante a operação do robô:

##### 1. Armazenamento de dados

- Os dados são armazenados no formato `LeRobotDataset` e são gravados em disco durante a gravação.
- Por padrão, o conjunto de dados é enviado para a sua página do Hugging Face após a gravação.
  - Para desativar o upload, use `--dataset.push_to_hub=False`.

##### 2. Checkpointing e Retomada

- Os checkpoints são criados automaticamente durante a gravação.
- Se um problema ocorrer ou você quiser gravar episódios adicionais no mesmo dataset, é possível retomar reexecutando o mesmo comando com `--resume=true`. Passe o nome completo do dataset, incluindo seu timestamp (`--dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS`). Ao retomar uma gravação, `--dataset.num_episodes` deve ser definido para o **número de episódios adicionais a serem gravados**, e não para o número total de episódios alvo no dataset! Certifique-se de que você também defina `--dataset.root="local_path"`, pois é um caminho local para salvar a nova parte do dataset e é obrigatório para retomar.
- Executar o comando novamente sem `--resume=true` inicia um novo conjunto de dados com um novo timestamp. Se você usar `--dataset.no_stamp=true`, exclua primeiro o diretório do conjunto de dados existente.

##### 3. Parâmetros de gravação

Defina o fluxo de gravação de dados usando argumentos de linha de comando:

- `--dataset.episode_time_s=60` Duração de cada episódio de gravação de dados (padrão: **60 segundos**).
- `--dataset.reset_time_s=60` Duração para redefinir o ambiente após cada episódio (padrão: **60 segundos**).
- `--dataset.num_episodes=50` Número total de episódios a serem registrados (padrão: **50**).

##### 4. Controles de teclado durante a gravação

Controle o fluxo de gravação de dados usando atalhos de teclado:

- Pressione **Seta para a direita (`→`)** ou **`n`**: interrompe precocemente o episódio atual ou redefine o tempo e avança para o próximo.
- Pressione **Seta para a esquerda (`←`)** ou **`r`**: cancela o episódio atual e o grava novamente.
- Pressione **Escape (`ESC`)** ou **`q`**: interrompe imediatamente a sessão, codifica os vídeos e faz o upload do conjunto de dados.

Esses atalhos de fluxo de controle funcionam em sessões **X11, Wayland e headless/SSH**. Quando um backend global de teclado não está disponível (Wayland, uma máquina headless ou macOS sem permissão de Acessibilidade), o `lerobot-record` lê automaticamente as mesmas teclas do terminal — inicie-o a partir de um terminal interativo e mantenha-o em foco. Você também pode usar os equivalentes em letras **`n`** (próximo, igual a `→`), **`r`** (regravar, igual a `←`) e **`q`** (sair, igual a `ESC`). Não é necessário configurar o `$DISPLAY`.

Isso se aplica apenas ao fluxo de controle de gravação. A **teleoperação** por teclado (dirigir o robô com o teclado) ainda requer um backend global de teclas, portanto, funciona apenas em uma sessão X11, em um desktop Windows ou no macOS com permissões de Acessibilidade/Monitoramento de Entrada concedidas — não em sessões Wayland ou headless.

#### Dicas para coletar dados

Quando você estiver confortável com a gravação de dados, pode criar um conjunto de dados maior para o treinamento. Uma boa tarefa inicial é pegar um objeto em diferentes localizações e colocá-lo em uma caixa. Sugerimos gravar pelo menos 50 episódios, com 10 episódios por localização. Mantenha as câmeras fixas e mantenha um comportamento de pegada consistente ao longo das gravações. Certifique-se também de que o objeto que você está manipulando esteja visível nas câmeras. Uma boa regra geral é que você deve ser capaz de executar a tarefa sozinho olhando apenas para as imagens das câmeras.

Nas seções a seguir, você treinará sua rede neural. Após alcançar um desempenho confiável de preensão, você pode começar a introduzir mais variações durante a coleta de dados, como locais adicionais de preensão, diferentes técnicas de preensão e alterações nas posições da câmera.

Evite adicionar muita variação muito rapidamente, pois isso pode prejudicar seus resultados.

Se você deseja se aprofundar neste tópico importante, pode conferir o [post no blog](https://huggingface.co/blog/lerobot-datasets#what-makes-a-good-dataset) que escrevemos sobre o que torna um bom dataset.

#### Relatórios de cadência

`lerobot-record` controla o ritmo do loop em `--dataset.fps` e relata o que foi realmente alcançado: um resumo em uma linha para cada episódio que você mantém e um bloco para toda a sessão quando a gravação termina — inclusive em caso de `Ctrl-C`.

```
Cadence (episode 0): 29.88 Hz vs 30 Hz target · 600 ticks, 20.0 s measured · 8/599 ticks over the 33.3 ms budget (work mean 18.4 ms, worst 45.1 ms)
Cadence (episode 1): 29.88 Hz vs 30 Hz target · 600 ticks, 20.0 s measured · 8/599 ticks over the 33.3 ms budget (work mean 18.4 ms, worst 45.1 ms)
Cadence summary — whole run, 2 episodes · target 30 Hz (33.3 ms budget per tick): 1200 ticks, 1198 judged
  effective cadence: 29.88 Hz over 40.1 s measured
  ticks over the 33.3 ms work budget: 16/1198 (1.3%) — work mean 18.4 ms, worst 45.1 ms
  loop-body steps (share of measured work):
    observe      mean  13.65 ms · worst  40.20 ms ·  74.4% of work · 1200 calls
    process_obs  mean   0.30 ms · worst   0.30 ms ·   1.6% of work · 1200 calls
    teleop       mean   1.80 ms · worst   1.80 ms ·   9.8% of work · 1200 calls
    send         mean   0.90 ms · worst   0.90 ms ·   4.9% of work · 1200 calls
    record       mean   1.70 ms · worst   1.90 ms ·   9.3% of work · 1200 calls
  pacing headroom: 15.1 ms slept per tick on average (max 16.7 ms) — near zero means the loop is saturated
```

Vale a pena ler isso antes de treinar no dataset. O timestamp de um frame é derivado do seu índice, então uma sessão que rodou a 25 Hz ainda produz um dataset que _afirma_ 30 — o movimento registrado é simplesmente mais rápido que a realidade. Acima, `observe` é 74% do trabalho do loop e seu `worst` é 40 ms em um orçamento de 33,3 ms: foram as câmeras que empurraram aqueles 16 ticks para além do limite. **Margem de ritmo** próxima de zero significa que não há mais nada para absorver um tick lento.

As fases de reset entre episódios são ritmadas da mesma forma, mas são deliberadamente excluídas desses números, pois não registram nada. `lerobot-teleoperate` e `lerobot-replay` relatam da mesma forma, e `lerobot-rollout` adiciona as linhas específicas de interpolação descritas em [Relatório de Cadência](./inference#cadence-reporting).

#### Solução de problemas:

- No Linux, as teclas de controle de fluxo de gravação (teclas de seta, Escape) funcionam em X11, Wayland e sessões headless/SSH, desde que o `lerobot-record` seja executado em um terminal interativo — não é necessário configurar o `$DISPLAY`. Se as teclas não tiverem efeito, verifique se você está em um terminal interativo (TTY), e não em uma sessão piped/não-TTY, e se ele está em foco; os equivalentes em letras `n` / `r` / `q` também funcionam. A _teleoperação_ por teclado (em oposição ao fluxo de controle de gravação) ainda requer um backend global de teclas — uma sessão X11, um desktop Windows ou macOS com permissões de Acessibilidade/Monitoramento de Entrada concedidas — e não está disponível em Wayland ou em máquinas headless. Consulte [limitações do pynput](https://pynput.readthedocs.io/en/latest/limitations.html#linux).

## Visualizar um conjunto de dados

Seu conjunto de dados é enviado ao Hub por padrão (a menos que você tenha passado `--dataset.push_to_hub=False`), então você pode abri-lo no [LeRobot Dataset Visualizer](https://huggingface.co/spaces/lerobot/visualize_dataset) imediatamente: insira o id do seu repositório na página inicial ou vá direto para o primeiro episódio com o link que isso imprime:

```bash
echo "https://huggingface.co/spaces/lerobot/visualize_dataset?path=/${HF_USER}/record-test_YYYYMMDD_HHMMSS/episode_0"
```

Faça login no visualizador para abrir um conjunto de dados privado. Consulte [Explore a Dataset in the Browser](./using_dataset_tools#explore-a-dataset-in-the-browser) para um passo a passo.

## Reproduzir um episódio

Um recurso útil é a função `replay`, que permite reproduzir qualquer episódio que você tenha gravado ou episódios de qualquer dataset disponível. Essa função ajuda a testar a repetibilidade das ações do seu robô e a avaliar a transferibilidade entre robôs do mesmo modelo.

Você pode reproduzir o primeiro episódio no seu robô com o comando abaixo ou com o exemplo de API:

```bash
lerobot-replay \
    --robot.type=so101_follower \
    --robot.port=/dev/tty.usbmodem58760431541 \
    --robot.id=my_awesome_follower_arm \
    --dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS \
    --dataset.episode=0 # choose the episode you want to replay
```

```python
import time

from lerobot.datasets import LeRobotDataset
from lerobot.robots.so_follower import SO101Follower, SO101FollowerConfig
from lerobot.utils.robot_utils import precise_sleep
from lerobot.utils.utils import log_say

episode_idx = 0

robot_config = SO101FollowerConfig(port="/dev/tty.usbmodem5AB90687491", id="my_follower_arm")

robot = SO101Follower(robot_config)
robot.connect()

dataset = LeRobotDataset("<hf_username>/<dataset_repo_id>", episodes=[episode_idx])
actions = dataset.select_columns("action")

log_say(f"Replaying episode {episode_idx}")
for idx in range(dataset.num_frames):
    t0 = time.perf_counter()

    action = {
        name: float(actions[idx]["action"][i]) for i, name in enumerate(dataset.features["action"]["names"])
    }
    robot.send_action(action)

    precise_sleep(max(1.0 / dataset.fps - (time.perf_counter() - t0), 0.0))

robot.disconnect()
```

Seu robô deve replicar movimentos semelhantes aos que você gravou. Por exemplo, confira [este vídeo](https://x.com/RemiCadene/status/1793654950905680090) em que usamos `replay` em um robô ALOHA da [Trossen Robotics](https://www.trossenrobotics.com).

## Treinar uma política

Para treinar uma política para controlar seu robô, use o script [`lerobot-train`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/scripts/lerobot_train.py). Alguns argumentos são obrigatórios. Aqui está um exemplo de comando:

```bash
lerobot-train \
  --dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS \
  --policy.type=act \
  --output_dir=outputs/train/act_so101_test \
  --job_name=act_so101_test \
  --policy.device=cuda \
  --trackio.enable=true \
  --policy.repo_id=${HF_USER}/my_policy
```

Vamos explicar o comando:

1. Fornecemos o dataset gravado anteriormente como argumento com `--dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS` (use o nome completo do seu dataset, incluindo o timestamp).
2. Fornecemos a política com `policy.type=act`. Isso carrega as configurações de [`configuration_act.py`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/act/configuration_act.py). É importante destacar que esta política se adaptará automaticamente ao número de estados dos motores, ações dos motores e câmeras do seu robô (por exemplo, `wrist` e `top`) que foram salvos no seu conjunto de dados.
3. Fornecemos `policy.device=cuda` porque estamos treinando em uma GPU Nvidia, mas você pode usar `policy.device=mps` para treinar em Apple silicon.
4. Fornecemos `trackio.enable=true` para usar o [Trackio](https://huggingface.co/docs/trackio) na visualização dos gráficos de treinamento. Isso é opcional. Execute `trackio show --project lerobot` para abrir o painel de controle ou passe `--trackio.space_id=<user>/<space>` para sincronizar a execução com um Hugging Face Space.
5. Não definimos `--steps`, portanto o treinamento é executado para o padrão de 100.000 passos. Isso geralmente é mais do que um pequeno conjunto de dados precisa: o aprendizado por imitação normalmente converge dentro de 5 a 10 épocas sobre os dados. Consulte o [Guia de Computação e Hardware](./hardware_guide#training-time) para converter épocas em um valor de `--steps` para o tamanho do seu conjunto de dados e tamanho do lote.

O treinamento deve levar algumas horas. Você encontrará os checkpoints em `outputs/train/act_so101_test/checkpoints`.

Para retomar o treinamento a partir de um checkpoint, abaixo está um exemplo de comando para retomar do checkpoint `last` da política `act_so101_test`:

```bash
lerobot-train \
  --config_path=outputs/train/act_so101_test/checkpoints/last/pretrained_model/train_config.json \
  --resume=true
```

`--config_path` também aceita um **Hub repo id**: se uma execução enviou seus checkpoints para o Hub (com `--save_checkpoint_to_hub=true`), você pode retomar diretamente do repositório — o checkpoint mais recente é baixado e o treinamento continua, restaurando o otimizador, o agendador, o contador de etapas e a ordem dos dados:

```bash
lerobot-train --config_path=${HF_USER}/my_policy --resume=true
```

Se você não deseja enviar seu modelo para o hub após o treinamento, use `--policy.push_to_hub=false`.

Além disso, você pode fornecer `tags` extras ou especificar uma `license` para seu modelo ou tornar o repositório do modelo `private` adicionando o seguinte: `--policy.private=true --policy.tags=\[so101,tutorial\] --policy.license=mit`

#### Treinar usando o Google Colab

Se o seu computador local não possui uma GPU potente, você pode utilizar o Google Colab para treinar seu modelo seguindo o [notebook de treinamento ACT](./notebooks#training-act).

#### Treinar usando Hugging Face Jobs

Hugging Face Jobs permite que você selecione facilmente o hardware e execute o treinamento na nuvem. Portanto, se você não possui uma GPU potente, precisa de mais VRAM ou simplesmente deseja treinar um modelo muito mais rápido, use o HF Jobs! O modelo é de pagamento por uso e você paga apenas por cada segundo de utilização. Você pode ver a tabela de preços e informações adicionais [aqui](https://huggingface.co/docs/hub/jobs).

`lerobot-train` é executado localmente por padrão. Para executar em uma GPU da HuggingFace, passe `--job.target` com o nome de um sabor de hardware:

```bash
lerobot-train \
  --dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS \
  --policy.type=act \
  --policy.repo_id=${HF_USER}/my_policy \
  --job.target=a10g-small
```

Liste os sabores e preços disponíveis com `hf jobs hardware`. A execução transmite os logs para o seu terminal; pressione Ctrl-C para se desconectar (o job continua rodando na nuvem). Reconecte ou cancele com:

```bash
hf jobs logs <job-id>
hf jobs cancel <job-id>
```

Se o seu conjunto de dados existir apenas localmente (ainda não no Hub), ele é enviado automaticamente para um repositório **privado** do Hub para que o job possa baixá-lo por `repo_id` (nada é tornado público). O modelo treinado é enviado para o repositório do modelo ao final da execução. Para também enviar cada checkpoint intermediário para o Hub conforme é salvo (para que você possa monitorar o progresso durante a execução), adicione `--save_checkpoint_to_hub=true` — isso requer uma imagem de runtime que inclua esse recurso.

Cada job (e qualquer dataset enviado pela execução) é marcado com `lerobot`, o que facilita encontrá-lo no Hub. Adicione os seus com `--job.tags '["my-tag"]'`.

Por padrão, o job é limitado a `2d` (48h) de tempo real. Substitua esse valor com uma string de duração de HF Jobs, por exemplo, `--job.timeout=4h` para falhar mais rápido ou `--job.timeout=7d` para uma execução mais longa.

> **Observação:** o repositório do modelo é criado previamente (ele contém a configuração de treinamento preparada que a tarefa executa). Se uma execução falhar antes de o modelo ser enviado, esse repositório permanece no Hub para que você possa inspecioná-lo — ele não é excluído automaticamente, portanto, falhas repetidas podem deixar repositórios vazios. Remova um com `hf repos delete <repo-id>`.

**Pré-requisitos:** execute `hf auth login` antes de enviar. Para o Trackio, passe `--trackio.space_id=<user>/<space>` — o Space é criado se não existir e o HF_TOKEN do job é encaminhado automaticamente.

**Retomando em um job.** Adicionar `--job.target` a um comando de retomada executa a retomada na nuvem — o mesmo comando funciona localmente ou remotamente. O repositório de checkpoint é a fonte da verdade, e novos checkpoints continuam a linhagem no mesmo repositório:

```bash
# resume a Hub run on a job (its checkpoints are already on the Hub)
lerobot-train --config_path=${HF_USER}/my_policy --resume=true --job.target=a10g-small

# resume a LOCAL run on a job — the checkpoint is uploaded to a private Hub repo first,
# then the job resumes from it (a local-only dataset is uploaded the same way)
lerobot-train \
  --config_path=outputs/train/act_so101_test/checkpoints/last/pretrained_model/train_config.json \
  --resume=true \
  --job.target=a10g-small
```

As configurações do job vêm do comando atual, portanto, substitua `--job.target`, `--job.timeout` etc. conforme necessário; para que a execução retomada possa ser retomada novamente no futuro, mantenha `--save_checkpoint_to_hub=true`.

#### Upload de pontos de verificação de políticas

Quando o treinamento estiver concluído, envie o checkpoint mais recente com:

```bash
hf upload ${HF_USER}/act_so101_test \
  outputs/train/act_so101_test/checkpoints/last/pretrained_model
```

Você também pode enviar checkpoints intermediários com:

```bash
CKPT=010000
hf upload ${HF_USER}/act_so101_test${CKPT} \
  outputs/train/act_so101_test/checkpoints/${CKPT}/pretrained_model
```

## Execute inferência e avalie sua política

Use o `lerobot-rollout` para implantar uma política treinada no seu robô. Você pode escolher diferentes estratégias de acordo com suas necessidades.

Use o mesmo `--robot.id` (para que a calibração seja encontrada), o mesmo `--robot.cameras` e a mesma descrição da tarefa do seu conjunto de dados gravado. Conjuntos de dados gravados por `lerobot-rollout` devem ter um nome que comece com `rollout_`, e, assim como o `lerobot-record`, ele adiciona um timestamp a esse nome.

Os exemplos abaixo carregam o modelo a partir de `--policy.path`. Para fixar uma versão específica enviada — útil depois que `--save_checkpoint_to_hub=true` tiver commitado vários checkpoints — adicione `--policy.pretrained_revision` com um hash de commit, branch ou tag. Cada checkpoint enviado é marcado com seu passo (por exemplo, `--policy.pretrained_revision=010000`), permitindo recuperar um checkpoint pelo passo sem precisar buscar seu sha de commit.

```bash
lerobot-rollout \
  --strategy.type=base \
  --policy.path=${HF_USER}/my_policy \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5AB90687491 \
  --robot.id=my_follower_arm \
  --robot.cameras="{ wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, top: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
  --task="Grab the black cube" \
  --duration=60
```

```bash
lerobot-rollout \
  --strategy.type=sentry \
  --strategy.upload_every_n_episodes=5 \
  --policy.path=${HF_USER}/my_policy \
  --robot.type=so101_follower \
  --robot.port=/dev/tty.usbmodem5AB90687491 \
  --robot.id=my_follower_arm \
  --robot.cameras="{ wrist: {type: opencv, index_or_path: 0, width: 640, height: 480, fps: 30}, top: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30}}" \
  --dataset.repo_id=${HF_USER}/rollout_so101_test \
  --dataset.single_task="Grab the black cube" \
  --duration=600
```

A flag `--strategy.type` seleciona o modo de execução:

- `base`: Rollout autônomo sem gravação de dados (útil para avaliação rápida)
- `sentry`: Gravação contínua com upload automático (útil para avaliação em larga escala)
- `highlight`: Gravação em buffer circular com salvamento por tecla (útil para capturar eventos interessantes)
- `dagger`: Coleta de dados com intervenção humana (veja [HIL Data Collection](./hil_data_collection))
- `episodic`: Gravação de política orientada a episódios com fases de reinício entre episódios

Todas as estratégias suportam `--inference.type=rtc` para uma execução suave com modelos VLA lentos (Pi0, Pi0.5, SmolVLA). Consulte [Policy Deployment](./inference) para todas as estratégias e suas flags.

