LeRobot documentation

Representaciones de acciones

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.6.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Representaciones de acciones

Esta guía explica las diferentes formas en que las acciones de los robots pueden representarse en LeRobot, cómo se relacionan entre sí y cuándo utilizar cada una.

Espacio conjunto vs espacio del efector final

Antes de discutir las representaciones de acciones, resulta útil comprender los dos espacios de coordenadas en los que pueden existir las acciones.

Espacio Conjunto

Las acciones en el espacio de articulaciones especifican directamente las posiciones objetivo para cada motor. Para un brazo de 6-DOF con un actuador, una acción en el espacio de articulaciones podría verse así:

action = [shoulder_pan: 45.0, shoulder_lift: -20.0, elbow: -30.0, wrist_pitch: 10.0, wrist_roll: 0.0, wrist_yaw: 5.0, gripper: 0.8]

El espacio de articulaciones es el predeterminado en LeRobot. Es simple, no requiere un modelo cinemático y se mapea directamente a las comandos de los motores. La mayoría de las configuraciones para principiantes (SO-100, Koch) usan acciones en el espacio de articulaciones.

Espacio del efector final (EE)

Las acciones en el espacio del efector final especifican la posición y orientación deseadas de la punta de la herramienta del robot (agarrador) en coordenadas cartesianas:

action = [x: 0.25, y: -0.10, z: 0.15, wx: 0.0, wy: 0.0, wz: 0.1, gripper: 0.8]

El espacio EE es más intuitivo para tareas como pick-and-place porque describe directamente dónde debe ir el efector final, pero requiere un modelo cinemático (URDF) para convertir entre las poses del EE y los ángulos de las articulaciones.

Conversión entre espacios

LeRobot proporciona pasos de procesador para convertir entre espacios de articulaciones y EE mediante cinemática directa e inversa. Estos se construyen sobre RobotKinematics, que carga un modelo URDF de su robot.

from lerobot.model.kinematics import RobotKinematics
from lerobot.robots.so_follower.robot_kinematic_processor import (
    ForwardKinematicsJointsToEE,
    InverseKinematicsEEToJoints,
)

kinematics = RobotKinematics(
    urdf_path="./SO101/so101_new_calib.urdf",
    target_frame_name="gripper_frame_link",
    joint_names=["shoulder", "elbow", "wrist_pitch", "wrist_roll", "wrist_yaw"],
)

# Joints → EE (for observations: "where is my gripper?")
fk_step = ForwardKinematicsJointsToEE(kinematics=kinematics, motor_names=[...])

# EE → Joints (for actions: "move my gripper here")
ik_step = InverseKinematicsEEToJoints(kinematics=kinematics, motor_names=[...])

Vea examples/so100_to_so100_EE/ para un ejemplo completo y funcional de grabación, reproducción y evaluación con acciones en el espacio EE en un brazo SO-100.

Acciones absolutas, relativas y delta

Independientemente de si trabaja en el espacio conjunto o en el espacio de la extremidad efectora, los valores de acción pueden expresarse de tres maneras diferentes. La terminología sigue a UMI (Chi et al., 2024).

Acciones absolutas (predeterminado de LeRobot)

Cada acción especifica directamente la posición objetivo.

Ejemplo (espacio conjunto, bloque de 4):

current_state = [45.0, -30.0, 10.0]

action_chunk = [
    [46.0, -29.0, 11.0],   # go to 46, -29, 11
    [47.5, -27.0, 12.0],   # go to 47.5, -27, 12
    [49.0, -25.0, 13.5],   # go to 49, -25, 13.5
    [50.0, -24.0, 15.0],   # go to 50, -24, 15
]

Cada valor es una posición objetivo en el sistema de coordenadas del robot. Es simple y directo, pero requiere un sistema de coordenadas global consistente. Este es el valor predeterminado en LeRobot.

Acciones relativas (usadas por OpenPI / pi0)

Cada acción en el fragmento es un desplazamiento desde el estado actual en el momento de la predicción. Todas las acciones del fragmento comparten el mismo punto de referencia:

current_state = [45.0, -30.0, 10.0]

relative_chunk = [
    [1.0,  1.0, 1.0],   # +1 from current → target 46, -29, 11
    [2.5,  3.0, 2.0],   # +2.5 from current → target 47.5, -27, 12
    [4.0,  5.0, 3.5],   # +4 from current → target 49, -25, 13.5
    [5.0,  6.0, 5.0],   # +5 from current → target 50, -24, 15
]

La conversión es directa: relative = absolute - current_state. Para recuperar el valor absoluto: absolute = relative + current_state.

¿Por qué usar acciones relativas? El modelo aprende a predecir desplazamientos centrados en cero, lo cual es más fácil de normalizar y conduce a un entrenamiento más estable. Dado que cada fragmento referencia el mismo estado actual, no hay acumulación de errores entre fragmentos.

Acciones Delta (diferencias secuenciales)

Cada acción es un desplazamiento respecto a la acción anterior (o respecto al estado actual en el primer paso):

current_state = [45.0, -30.0, 10.0]

delta_chunk = [
    [1.0,  1.0, 1.0],   # current → 46, -29, 11
    [1.5,  2.0, 1.0],   # previous action → 47.5, -27, 12
    [1.5,  2.0, 1.5],   # previous action → 49, -25, 13.5
    [1.0,  1.0, 1.5],   # previous action → 50, -24, 15
]

Aquí, cada paso es relativo al anterior. Para recuperar las posiciones absolutas, es necesario sumar todos los deltas previos, lo que significa que los errores se acumulan con el tiempo. UMI argumenta explícitamente en contra de esta representación por esta razón.

Comparación visual

La figura siguiente (basada en una figura de UMI, Chi et al., 2024) ilustra la diferencia clave. Con trayectoria relativa, cada acción del bloque apunta de vuelta al mismo origen (estado actual), por lo que un nuevo paso de inferencia restablece la referencia de forma limpia. Con delta, cada acción depende de la anterior, por lo que los errores se acumulan. Las acciones absolutas requieren un sistema de coordenadas global coherente.

Relative Trajectory as Action Representation (UMI, Chi et al., 2024)

Uso de acciones relativas en LeRobot

LeRobot proporciona RelativeActionsProcessorStep para convertir entre acciones absolutas y relativas dentro de la línea de procesamiento. Así es como pi0, pi0.5 y pi0_fast admiten acciones relativas.

Nota: Todos los modelos pi (pi0, pi0.5, pi0fast) aplican la conversión relativa _antes de la normalización (relative → normalize), por lo que el normalizador siempre ve valores delta (relativos). Esto significa que se requieren estadísticas de acciones relativas para todos ellos al entrenar con use_relative_actions=true. En pi0_fast, RelativeActionsProcessorStep solo modifica la acción; la observación del estado no cambia, por lo que NormalizerProcessorStep sigue ejecutándose antes del tokenizador de estado y el tokenizador continúa recibiendo el estado normalizado como se espera.

Cómo funciona

Durante el entrenamiento (preprocesamiento), las acciones se convierten de absolutas a relativas antes de que el modelo las vea:

raw absolute action → RelativeActionsProcessorStep → normalize → model

Durante la inferencia (postprocesamiento), las predicciones del modelo se convierten de nuevo a valores absolutos antes de enviarse al robot:

model output → unnormalize → AbsoluteActionsProcessorStep → robot

El AbsoluteActionsProcessorStep lee el estado actual en caché de su RelativeActionsProcessorStep emparejado, por lo que ambos deben estar conectados (lo gestiona automáticamente la fábrica de políticas).

Habilitar acciones relativas para la familia pi (pi0, pi0.5, pi0_fast)

Paso 1: Precompute las estadísticas de acción relativas para tu conjunto de datos:

lerobot-edit-dataset \
    --repo_id your_dataset \
    --new_repo_id your_dataset \
    --operation.type recompute_stats \
    --operation.overwrite true \
    --operation.relative_action true \
    --operation.chunk_size 50 \
    --operation.relative_exclude_joints "['gripper']"

Paso 2: Entrenar con acciones relativas habilitadas:

lerobot-train \
    --dataset.repo_id=your_dataset \
    --policy.type=pi0 \
    --policy.use_relative_actions=true \
    --policy.relative_exclude_joints='["gripper"]'

El parámetro relative_exclude_joints especifica las articulaciones que deben permanecer en el espacio absoluto. Por ejemplo, los comandos de las pinzas suelen ser binarios (abrir/cerrar) y no se benefician de la codificación relativa.

Para las configuraciones de política que definen action_feature_names, make_policy rellena esta lista a partir de los metadatos names de la característica de acción del conjunto de datos. Los nombres pueden ser una secuencia plana o un diccionario cuyos valores son todas listas o tuplas. Por ejemplo, {"arm": ["shoulder", "elbow"], "hand": ["gripper"]} se convierte en ["shoulder", "elbow", "gripper"], no en las claves de los grupos. Se conserva el orden de inserción de los grupos y el orden dentro de cada grupo, por lo que se deben declarar los nombres en el mismo orden que el vector de acción. Los mapeos de nombre a índice heredados conservan su comportamiento de orden de claves.

Combinar acciones relativas con RTC

RTC ejecuta la inferencia de la política a alta frecuencia y envía las acciones al robot a medida que se predicen, en lugar de esperar a un bloque completo. Las acciones relativas y RTC son totalmente compatibles: como cada bloque en modo relativo hace referencia al mismo estado actual (capturado al inicio de la inferencia), cada acción predicha dentro del bloque sigue siendo un desplazamiento válido incluso si el robot ya se ha movido. No se requiere un manejo especial: RelativeActionsProcessorStep almacena en caché el estado una vez por llamada de inferencia y AbsoluteActionsProcessorStep lo aplica a cada acción de la salida transmitida.

Combinar acciones relativas con el espacio EE

Las acciones relativas funcionan tanto en el espacio articulado como en el espacio de la efectora final. Por ejemplo, si su conjunto de datos almacena acciones de la efectora final, la codificación relativa las convierte en desplazamientos desde la pose actual de la efectora final:

current_ee_state = [x: 0.25, y: -0.10, z: 0.15, gripper: 0.8]

absolute_ee_chunk = [
    [0.26, -0.09, 0.16, 0.8],
    [0.28, -0.07, 0.18, 0.8],
]

relative_ee_chunk = [
    [0.01,  0.01, 0.01, 0.0],   # offset from current EE pose
    [0.03,  0.03, 0.03, 0.0],   # offset from current EE pose
]

Resumen del pipeline de procesamiento

A continuación se muestra cómo se componen los distintos procesadores. Cada flecha es un paso de procesador y pueden encadenarse en un RobotProcessorPipeline o un PolicyProcessorPipeline:

                    ┌─────────────────────────────────────────┐
   Action Space     │   Joint Space  ←──IK──→  EE Space      │
                    │   ForwardKinematicsJointsToEE           │
                    │   InverseKinematicsEEToJoints           │
                    └─────────────────────────────────────────┘

                    ┌─────────────────────────────────────────┐
   Representation   │   Absolute  ←────→  Relative            │
                    │   RelativeActionsProcessorStep (pre)    │
                    │   AbsoluteActionsProcessorStep (post)   │
                    └─────────────────────────────────────────┘

                    ┌─────────────────────────────────────────┐
   Normalization    │   Raw  ←────→  Normalized               │
                    │   NormalizerProcessorStep (pre)         │
                    │   UnnormalizerProcessorStep (post)      │
                    └─────────────────────────────────────────┘

A typical training preprocessor might chain: raw absolute joint actions → relative → normalize. A typical inference postprocessor: unnormalize → absolute → (optionally IK to joints).

Referencias

Update on GitHub