# Aprendizaje por imitación en robots del mundo real

En este tutorial se explica cómo entrenar una red neuronal para controlar un robot real de forma autónoma.

**Aprenderás:**

1. Cómo registrar y visualizar tu conjunto de datos.
2. Cómo entrenar una política con tus datos y prepararla para la evaluación.
3. Cómo evaluar su política y visualizar los resultados.

Siguiendo estos pasos, podrás replicar tareas, como recoger un bloque de Lego y colocarlo en una caja con una alta tasa de éxito, como se muestra en el video a continuación.

Video: tarea de recoger un bloque de LEGO

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

Este tutorial no está vinculado a un robot específico: te guiamos a través de los comandos y fragmentos de API que puedes adaptar para cualquier plataforma compatible.

Durante la recopilación de datos, utilizará un dispositivo de “teleoperación”, como un brazo líder o un teclado, para teleoperar el robot y registrar sus trayectorias de movimiento.

Una vez que hayas recopilado suficientes trayectorias, entrenarás una red neuronal para imitar estas trayectorias y desplegarás el modelo entrenado para que tu robot pueda realizar la tarea de forma autónoma.

Si tienes algún problema en cualquier momento, entra en nuestra [comunidad de Discord](https://discord.com/invite/s3KuuzsPFb) para obtener soporte.

¿Quieres obtener rápidamente los comandos correctos para tu configuración? El [cuaderno de inicio rápido](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) te permite configurar tu robot una sola vez y genera todos los comandos siguientes listos para pegar.

## Configurar y calibrar

Si aún no has configurado y calibrado tu robot y tu dispositivo de teleoperación, hazlo siguiendo el tutorial de tu robot, por ejemplo [SO-101](./so101), [OpenArm](./openarm), [Koch](./koch) o [LeKiwi](./lekiwi). Todos los robots compatibles están listados en **Robots** en la barra lateral.

## Teleoperar

En este ejemplo, demostraremos cómo teleoperar el robot SO101. Para cada comando, también proporcionamos un ejemplo de API correspondiente.

Tenga en cuenta que el `id` asociado con un robot se utiliza para almacenar el archivo de calibración. Es importante usar el mismo `id` al teleoperar, grabar y evaluar cuando se utiliza la misma configuración.

```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)
```

El comando teleoperate hará lo siguiente automáticamente:

1. Identifique las calibraciones que falten e inicie el procedimiento de calibración.
2. Conecte el robot y el dispositivo de teleoperación y comience la teleoperación.

## Cámaras

Para añadir cámaras a tu configuración, sigue esta [Guía](./cameras).

## Teleopere con cámaras

Con `rerun`, puedes teleoperar de nuevo mientras visualizas simultáneamente las transmisiones de las cámaras y las posiciones de las articulaciones. Este ejemplo utiliza dos cámaras, `wrist` y `top`; mantendremos la misma configuración de cámaras para el resto del 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 un conjunto de datos

Una vez que esté familiarizado con la teleoperación, puede grabar su primer conjunto de datos.

Utilizamos las funciones del hub de Hugging Face para subir tu conjunto de datos. Si no has utilizado el Hub anteriormente, asegúrate de poder iniciar sesión mediante la cli usando un token de acceso de escritura; este token se puede generar desde [los ajustes de Hugging Face](https://huggingface.co/settings/tokens).

Agrega tu token a la CLI ejecutando este comando:

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

Luego, guarda el nombre de tu repositorio de Hugging Face en una variable:

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

Ahora puedes grabar un conjunto de datos. Para grabar 5 episodios y subir tu conjunto de datos al hub, adapta el siguiente código a tu robot y ejecuta el comando o el ejemplo 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()
```

Los nombres de cámara que elijas (aquí `wrist` y `top`) se convierten en las claves del conjunto de datos `observation.images.wrist` y `observation.images.top`. Una política entrenada con este conjunto de datos espera los mismos nombres de cámara y la misma resolución al desplegarla, por lo que reutiliza el mismo valor de `--robot.cameras` en cada paso de este tutorial. Si los nombres deben ser diferentes, consulta [Rename Map](./rename_map).

`lerobot-record` añade la fecha y la hora de la sesión al final de `--dataset.repo_id`, de modo que cada grabación recibe un nombre único: `${HF_USER}/record-test` se guarda como `${HF_USER}/record-test_YYYYMMDD_HHMMSS` (por ejemplo, `record-test_20260929_143012`). Puedes encontrar el nombre completo en tu perfil de Hugging Face o con `ls ~/.cache/huggingface/lerobot/${HF_USER}`, y úsalo en todos los lugares donde los comandos siguientes indican `record-test_YYYYMMDD_HHMMSS`. Para mantener el nombre exacto que pasaste, añade `--dataset.no_stamp=true`.

#### Carga de datos

Localmente, tu conjunto de datos se almacena en esta carpeta: `~/.cache/huggingface/lerobot/{repo-id}`. Al finalizar la grabación de datos, tu conjunto de datos se subirá a tu página de Hugging Face (p. ej. `https://huggingface.co/datasets/${HF_USER}/record-test_YYYYMMDD_HHMMSS`) que puedes obtener ejecutando:

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

Tu conjunto de datos se etiquetará automáticamente con `LeRobot` para que la comunidad lo encuentre fácilmente, y también puedes añadir etiquetas personalizadas, por ejemplo `--dataset.tags='["tutorial"]'`.

Puedes buscar otros conjuntos de datos de LeRobot en el hub buscando las [etiquetas](https://huggingface.co/datasets?other=LeRobot) `LeRobot`.

También puedes subir tu conjunto de datos local al Hub manualmente, ejecutando:

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

#### Función Record

`lerobot-record` ofrece un conjunto de herramientas para capturar y gestionar datos durante la operación del robot:

##### 1. Almacenamiento de datos

- Los datos se almacenan en el formato `LeRobotDataset` y se guardan en el disco durante la grabación.
- Por defecto, el conjunto de datos se publica en tu página de Hugging Face después de la grabación.
  - Para deshabilitar la carga, use `--dataset.push_to_hub=False`.

##### 2. Puntos de control y reanudación

- Los puntos de control se crean automáticamente durante la grabación.
- Si se produce un problema o deseas grabar episodios adicionales en el mismo conjunto de datos, puedes reanudar la grabación ejecutando de nuevo el mismo comando con `--resume=true`. Pasa el nombre completo del conjunto de datos, incluido su marca de tiempo (`--dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS`). Al reanudar una grabación, `--dataset.num_episodes` debe establecerse en el **número de episodios adicionales que se van a grabar**, y no en el número total de episodios objetivo del conjunto de datos. Asegúrate de que también establezcas `--dataset.root="local_path"`, ya que es una ruta local para guardar la nueva parte del conjunto de datos y es obligatoria para reanudar.
- Volver a ejecutar el comando sin `--resume=true` inicia un nuevo conjunto de datos con una nueva marca de tiempo. Si usa `--dataset.no_stamp=true`, elimine primero el directorio del conjunto de datos existente.

##### 3. Parámetros de grabación

Establezca el flujo de grabación de datos mediante argumentos de línea de comandos:

- `--dataset.episode_time_s=60` Duración de cada episodio de grabación de datos (predeterminado: **60 segundos**).
- `--dataset.reset_time_s=60` Duración para restablecer el entorno después de cada episodio (predeterminado: **60 segundos**).
- `--dataset.num_episodes=50` Número total de episodios a registrar (predeterminado: **50**).

##### 4. Controles de teclado durante la grabación

Controla el flujo de grabación de datos mediante atajos de teclado:

- Pulse **flecha derecha (`→`)** o **`n`**: detenga prematuramente el episodio actual o restablezca el tiempo y pase al siguiente.
- Pulsa **flecha izquierda (`←`)** o **`r`**: cancela el episodio actual y vuelve a grabarlo.
- Pulsa **Escape (`ESC`)** o **`q`**: detiene la sesión de inmediato, codifica los vídeos y sube el conjunto de datos.

Estos atajos de flujo de control funcionan en sesiones de **X11, Wayland y headless/SSH**. Cuando no está disponible un backend global de teclado (Wayland, una máquina headless o macOS sin permiso de Accesibilidad), `lerobot-record` lee automáticamente las mismas teclas desde la terminal: inícialo desde una terminal interactiva y mantenla enfocada. También puedes usar los equivalentes en letras **`n`** (siguiente, igual que `→`), **`r`** (regrabar, igual que `←`) y **`q`** (salir, igual que `ESC`). No se requiere configurar `$DISPLAY`.

Esto se aplica únicamente al flujo de control de la grabación. La **teleoperación** por teclado (controlar el robot con el teclado) sigue requiriendo un backend global de teclas, por lo que solo funciona en una sesión X11, un escritorio de Windows o macOS con permisos de Accesibilidad/Monitoreo de entrada concedidos, y no en Wayland ni en sesiones sin interfaz gráfica.

#### Consejos para recopilar datos

Una vez que se sienta cómodo con la grabación de datos, puede crear un conjunto de datos más grande para el entrenamiento. Una buena tarea inicial es agarrar un objeto en diferentes ubicaciones y colocarlo en un contenedor. Sugerimos grabar al menos 50 episodios, con 10 episodios por ubicación. Mantenga las cámaras fijas y mantenga un comportamiento de agarre constante durante toda la grabación. Asegúrese también de que el objeto que está manipulando sea visible en las cámaras. Una buena regla general es que usted mismo debería poder realizar la tarea mirando únicamente las imágenes de las cámaras.

En las siguientes secciones, entrenará su red neuronal. Una vez que logre un rendimiento de agarre confiable, podrá comenzar a introducir más variaciones durante la recopilación de datos, como ubicaciones de agarre adicionales, técnicas de agarre diferentes y cambios en las posiciones de las cámaras.

Evite añadir demasiada variación demasiado rápido, ya que puede obstaculizar sus resultados.

Si deseas profundizar en este tema importante, puedes consultar el [post del blog](https://huggingface.co/blog/lerobot-datasets#what-makes-a-good-dataset) que escribimos sobre qué hace que un conjunto de datos sea bueno.

#### Informe de cadencia

`lerobot-record` regula el bucle a `--dataset.fps` e informa de lo que se logró realmente: un resumen de una línea para cada episodio que se conserve y un bloque para toda la sesión al finalizar la grabación, incluso con `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
```

Conviene leer esto antes de entrenar con el conjunto de datos. La marca de tiempo de un fotograma se deriva de su índice, por lo que una sesión que se ejecutó a 25 Hz sigue generando un conjunto de datos que _afirma_ 30: el movimiento grabado es simplemente más rápido que la realidad. En la parte superior, `observe` representa el 74% del trabajo del bucle y su `worst` es de 40 ms con un presupuesto de 33,3 ms: las cámaras son lo que empujó esos 16 ticks por encima. Un **margen de ritmo** cercano a cero significa que no queda nada para absorber un tick lento.

Las fases de reinicio entre episodios se regulan de la misma manera, pero no forman parte de estas cifras de forma deliberada, ya que no registran nada. `lerobot-teleoperate` y `lerobot-replay` informan de la misma manera, y `lerobot-rollout` añade las líneas específicas de interpolación descritas en [Informe de cadencia](./inference#cadence-reporting).

#### Solución de problemas:

- En Linux, las teclas de control de flujo de grabación (teclas de flecha, Escape) funcionan en X11, Wayland y sesiones headless/SSH siempre que `lerobot-record` se ejecute en una terminal interactiva: no es necesario configurar `$DISPLAY`. Si las teclas no tienen efecto, asegúrate de estar en una terminal interactiva (TTY) y no en una sesión con tubería/no-TTY, y de que la terminal tenga el foco; los equivalentes de letras `n` / `r` / `q` también funcionan. La _teleoperación_ por teclado (a diferencia del flujo de control de grabación) sigue requiriendo un backend global de teclas: una sesión X11, un escritorio de Windows o macOS con permisos de Accesibilidad/Monitoreo de entrada, y no está disponible en Wayland ni en máquinas headless. Consulta [limitaciones de pynput](https://pynput.readthedocs.io/en/latest/limitations.html#linux).

## Visualizar un conjunto de datos

Tu conjunto de datos se sube al Hub de forma predeterminada (a menos que hayas pasado `--dataset.push_to_hub=False`), por lo que puedes abrirlo en el [LeRobot Dataset Visualizer](https://huggingface.co/spaces/lerobot/visualize_dataset) de inmediato: introduce tu id de repositorio en su página de inicio o ve directamente al primer episodio con el enlace que imprime:

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

Inicia sesión en el visualizador para abrir un conjunto de datos privado. Consulta [Explorar un conjunto de datos en el navegador](./using_dataset_tools#explore-a-dataset-in-the-browser) para obtener una guía paso a paso.

## Reproducir un episodio

Una función útil es `replay`, que permite reproducir cualquier episodio que hayas grabado o episodios de cualquier conjunto de datos disponible. Esta función te ayuda a probar la repetibilidad de las acciones de tu robot y a evaluar la transferibilidad entre robots del mismo modelo.

Puedes reproducir el primer episodio en tu robot con el siguiente comando o con el ejemplo de la 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()
```

Tu robot debe replicar movimientos similares a los que grabaste. Por ejemplo, mira [este video](https://x.com/RemiCadene/status/1793654950905680090) donde usamos `replay` en un robot ALOHA de [Trossen Robotics](https://www.trossenrobotics.com).

## Entrenar una política

Para entrenar una política que controle tu robot, usa el script [`lerobot-train`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/scripts/lerobot_train.py). Se requieren algunos argumentos. Aquí hay un ejemplo 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
```

Explicamos el comando:

1. Proporcionamos el conjunto de datos grabado anteriormente como argumento con `--dataset.repo_id=${HF_USER}/record-test_YYYYMMDD_HHMMSS` (usa el nombre completo de tu conjunto de datos, incluyendo la marca de tiempo).
2. Proporcionamos la política con `policy.type=act`. Esto carga las configuraciones desde [`configuration_act.py`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/act/configuration_act.py). Es importante destacar que esta política se adaptará automáticamente al número de estados de los motores, acciones de los motores y cámaras de tu robot (por ejemplo, `wrist` y `top`) que se hayan guardado en tu conjunto de datos.
3. Proporcionamos `policy.device=cuda` porque estamos entrenando en una GPU de Nvidia, pero podrías usar `policy.device=mps` para entrenar en silicio de Apple.
4. Proporcionamos `trackio.enable=true` para usar [Trackio](https://huggingface.co/docs/trackio) para visualizar los gráficos de entrenamiento. Esto es opcional. Ejecuta `trackio show --project lerobot` para abrir el panel de control, o pasa `--trackio.space_id=<user>/<space>` para sincronizar la ejecución con un Hugging Face Space.
5. No configuramos `--steps`, por lo que el entrenamiento se ejecuta durante los 100.000 pasos predeterminados. Eso suele ser más de lo que necesita un conjunto de datos pequeño: el aprendizaje por imitación generalmente converge en 5-10 épocas sobre los datos. Consulta la [Guía de cómputo y hardware](./hardware_guide#training-time) para convertir las épocas en un valor de `--steps` para el tamaño de tu conjunto de datos y el tamaño del lote.

El entrenamiento debería tardar varias horas. Encontrará los puntos de control en `outputs/train/act_so101_test/checkpoints`.

Para reanudar el entrenamiento desde un punto de control, a continuación se muestra un ejemplo de comando para reanudar desde el punto de control `last` de la 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` también acepta un **id de repositorio del Hub**: si una ejecución subió sus puntos de control al Hub (con `--save_checkpoint_to_hub=true`), puedes reanudar directamente desde el repositorio: se descarga su punto de control más reciente y el entrenamiento continúa, restaurando el optimizador, el programador, el contador de pasos y el orden de los datos:

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

Si no deseas subir tu modelo al hub después del entrenamiento, usa `--policy.push_to_hub=false`.

Además, puede proporcionar `tags` adicionales o especificar una `license` para su modelo o hacer que el repositorio del modelo sea `private` agregando esto: `--policy.private=true --policy.tags=\[so101,tutorial\] --policy.license=mit`

#### Entrenar usando Google Colab

Si tu computadora local no cuenta con una GPU potente, puedes utilizar Google Colab para entrenar tu modelo siguiendo el [cuaderno de entrenamiento ACT](./notebooks#training-act).

#### Entrenar usando Hugging Face Jobs

Hugging Face Jobs te permite seleccionar el hardware fácilmente y ejecutar el entrenamiento en la nube. Por lo tanto, si no tienes una GPU potente, si necesitas más VRAM o simplemente quieres entrenar un modelo mucho más rápido, ¡usa HF Jobs! El pago es por uso y simplemente pagas por cada segundo de uso; puedes ver los precios y la información adicional [aquí](https://huggingface.co/docs/hub/jobs).

`lerobot-train` se ejecuta localmente de forma predeterminada. Para ejecutarlo en una GPU de HuggingFace, pasa `--job.target` con el nombre de un 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
```

Obtén la lista de sabores disponibles y precios con `hf jobs hardware`. La ejecución transmite sus registros a tu terminal; presiona Ctrl-C para desconectarte (el trabajo sigue ejecutándose en la nube). Vuelve a conectarte o cancela con:

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

Si tu conjunto de datos existe solo localmente (aún no está en el Hub), se sube automáticamente a un repositorio de Hub **privado** para que el trabajo pueda descargarlo por `repo_id` (nada se hace público). El modelo entrenado se sube al repositorio del modelo al final de la ejecución. Para subir también cada punto de control intermedio al Hub a medida que se guarda (para que puedas monitorear el progreso a mitad de la ejecución), agrega `--save_checkpoint_to_hub=true`; esto requiere una imagen de tiempo de ejecución que incluya esta función.

Cada trabajo (y cualquier conjunto de datos enviado por la ejecución) se etiqueta con `lerobot` para que sea fácil de encontrar en el Hub. Añade los tuyos con `--job.tags '["my-tag"]'`.

Por defecto, el trabajo tiene un límite de `2d` (48 h) de tiempo real. Puedes superarlo con una cadena de duración de HF Jobs, por ejemplo, `--job.timeout=4h` para fallar antes o `--job.timeout=7d` para una ejecución más larga.

> **Nota:** el repositorio del modelo se crea de antemano (contiene la configuración de entrenamiento preparada desde la que se ejecuta el trabajo). Si una ejecución falla antes de que el modelo se suba, ese repositorio se deja en el Hub para que puedas inspeccionarlo: no se elimina automáticamente, por lo que las fallas repetidas pueden dejar repositorios vacíos. Elimínalo con `hf repos delete <repo-id>`.

**Prerrequisitos:** ejecute `hf auth login` antes de enviar. Para Trackio, pase `--trackio.space_id=<user>/<space>` — el Space se crea si no existe y el HF_TOKEN del trabajo se reenvía automáticamente.

**Reanudación en un trabajo.** Agregar `--job.target` a un comando de reanudación ejecuta la reanudación en la nube: el mismo comando funciona de forma local o remota. El repositorio de puntos de control es la fuente de verdad y los nuevos puntos de control continúan la línea de sucesión en el mismo repositorio:

```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
```

La configuración del trabajo proviene del comando actual, por lo que sobrescribe `--job.target`, `--job.timeout`, etc. según sea necesario; para que la ejecución reanudada pueda reanudarse más adelante, mantén `--save_checkpoint_to_hub=true`.

#### Cargar puntos de control de la política

Una vez finalizado el entrenamiento, sube el punto de control más reciente con:

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

También puedes subir puntos de control intermedios con:

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

## Ejecuta la inferencia y evalúa tu política

Use `lerobot-rollout` para desplegar una política entrenada en su robot. Puede elegir diferentes estrategias según sus necesidades.

Utilice el mismo `--robot.id` (para que se encuentre la calibración), el mismo `--robot.cameras` y la misma descripción de la tarea que en su conjunto de datos grabado. Los conjuntos de datos grabados por `lerobot-rollout` deben tener un nombre que comience con `rollout_`, y, al igual que `lerobot-record`, añade una marca de tiempo a ese nombre.

Los ejemplos siguientes cargan el modelo desde `--policy.path`. Para fijar una versión específica publicada, útil una vez que `--save_checkpoint_to_hub=true` ha comprometido varios puntos de control, añada `--policy.pretrained_revision` con un hash de commit, una rama o una etiqueta. Cada punto de control publicado se etiqueta con su paso (p. ej. `--policy.pretrained_revision=010000`), por lo que puede recuperar un punto de control por paso sin buscar su 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
```

La bandera `--strategy.type` selecciona el modo de ejecución:

- `base`: Despliegue autónomo sin registro de datos (útil para una evaluación rápida)
- `sentry`: Grabación continua con carga automática (útil para evaluaciones a gran escala)
- `highlight`: Grabación con búfer circular y guardado mediante pulsación de tecla (útil para capturar eventos interesantes)
- `dagger`: Recopilación de datos con intervención humana (ver [Recopilación de datos HIL](./hil_data_collection))
- `episodic`: Registro de políticas orientado a episodios con fases de reinicio entre episodios

Todas las estrategias admiten `--inference.type=rtc` para una ejecución fluida con modelos VLA lentos (Pi0, Pi0.5, SmolVLA). Consulte [Policy Deployment](./inference) para conocer todas las estrategias y sus banderas.

