LeRobot documentation

Unitree G1

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

Unitree G1

El humanoide Unitree G1 es compatible con LeRobot. Puedes teleoperarlo, entrenar políticas de locomanipulación, probarlo en simulación y mucho más. Se admiten las variantes de 29 y 23 grados de libertad.

Selección de encarnación

La clase UnitreeG1 selecciona sus definiciones de articulaciones a través de UnitreeG1Config.embodiment. El valor predeterminado es g1_29; por lo tanto, las configuraciones existentes conservan el comportamiento de G1-29. Seleccione el diseño de 23-DoF con --robot.embodiment=g1_23 o en Python:

from lerobot.robots.unitree_g1 import UnitreeG1Config

config = UnitreeG1Config(embodiment="g1_23", is_simulation=False)
CapacidadG1-29G1-23
Configuración conjunta y características de acción/observación29 articulaciones del cuerpo, 14 articulaciones de los brazos23 articulaciones del cuerpo, 10 articulaciones de los brazos
Distribución de comandos/retroalimentación de DDS29 slots activos29 ranuras con articulaciones ausentes dejadas inactivas
Simulación de MuJoCoSoportadoAún no compatible; se planea un modelo nativo
Controladores de locomociónGR00T y HolosomaGR00T y Holosoma
Controlador de cuerpo completo SONICSoportadoNo compatible; la política requiere 29 GDL
Compensación de la gravedadSoportado, desactivado por defectoAún no compatible; cinemática nativa planificada

Ambas variantes utilizan el mismo diseño de mensaje DDS de 29 ranuras. G1-29 utiliza las 29 ranuras, mientras que G1-23 utiliza 23 y deja inactivas las seis ranuras de articulaciones inexistentes. Por lo tanto, los vectores kp, kd y default_positions siguen teniendo 29 elementos y se indexan por ranura DDS. Las ranuras de brazo activas de G1-23 son 15..19 y 22..26. Las ranuras 13, 14, 20, 21, 27, 28 no tienen articulación activa; sus valores de configuración deben ser cero. Se omiten de las características de acción/observación, no se renumeran. Las entradas de comando inactivas y reservadas se limpian antes de publicar un mensaje G1-23. Las sobrescripciones explícitas de ganancias deben ser finitas, no negativas y utilizar el mismo diseño disperso. Las ganancias predeterminadas se comparten por nombre de articulación entre ambas variantes, por lo que las articulaciones físicas idénticas utilizan ganancias idénticas, mientras que las ranuras ausentes de G1-23 permanecen en cero.

La simulación nativa de G1-23 en MuJoCo aún no está soportada. Seleccionar la encarnación G1-23 con la simulación habilitada falla antes de la inicialización del transporte. Se planea un modelo nativo de G1-23 en MuJoCo para una versión futura.


Parte 1: Primeros pasos

Instale el SDK de Unitree

Siga la guía de instalación de unitree_sdk2_python. Probado con unitree_sdk2py==1.0.1 y cyclonedds==0.10.2:

conda create -y -n lerobot python=3.12
conda activate lerobot
git clone https://github.com/unitreerobotics/unitree_sdk2_python.git
cd unitree_sdk2_python
pip install -e .
cd ..

Instalar LeRobot

conda install ffmpeg -c conda-forge
conda install -c conda-forge "pinocchio>=3.0.0,<4.0.0"
git clone https://github.com/huggingface/lerobot.git
cd lerobot
pip install -e '.[unitree_g1]'
For now, pinocchio must be installed from conda-forge (not pip) to include the CasADi bindings needed for arm IK.

Probar la instalación (simulación)

El entorno de simulación tiene sus propias dependencias. Consulta las dependencias del entorno de simulación: Unitree G1 Mujoco EnvHub.

pip install mujoco loguru msgpack msgpack-numpy
lerobot-teleoperate \
  --robot.type=unitree_g1 \
  --robot.is_simulation=true \
  --teleop.type=unitree_g1 \
  --teleop.id=wbc_unitree \
  --robot.cameras='{"global_view": {"type": "zmq", "server_address": "localhost", "port": 5555, "camera_name": "head_camera", "width": 640, "height": 480, "fps": 30, "warmup_s": 5}}' \
  --display_data=true \
  --robot.controller=GrootLocomotionController

Esto iniciará una instancia de simulación de MuJoCo para el G1. Puedes conectar un mando de juego a tu máquina antes de iniciar para controlar la locomoción del robot en la simulación. Admitimos tanto HolosomaLocomotionController como GrootLocomotionController mediante --robot.controller.

  • Pulsa 9 para soltar el robot
  • Pulsa 7 / 8 para aumentar / disminuir la altura de la cintura

Elegir el efector final

--robot.end_effector indica qué llevan los brazos: dex1 para las pinzas paralelas (el valor predeterminado), dex3 para las manos de tres dedos, o dummy para muñecas desnudas. En la simulación, selecciona el modelo de MuJoCo, que determina los actuadores de los dedos y las cámaras que incluye la escena: las cámaras de muñeca están montadas en el efector final, por lo que dummy solo tiene head_camera.

lerobot-teleoperate \
  --robot.type=unitree_g1 \
  --robot.is_simulation=true \
  --robot.end_effector=dex3 \
  --teleop.id=wbc_unitree \
  --robot.controller=GrootLocomotionController

El simulador publica las cámaras del modelo a través de ZMQ en --robot.sim_camera_port (5555 por defecto), que es de donde las cámaras zmq en --robot.cameras las leen. Pasa --robot.sim_publish_images=false para abrir la ventana interactiva de MuJoCo en su lugar: el simulador renderiza ya sea sus cámaras o su ventana, nunca ambas, ya que los contextos fuera de pantalla pertenecen al hilo que los crea y no al visor. --robot.sim_onscreen nombra esa elección explícitamente en lugar de dejarla a las cámaras, y pedir ambas se rechaza; establécela y --robot.sim_publish_images ambas en falso para no renderizar ninguna, que es lo que puede hacer una máquina sin pantalla.

Conectar al robot físico

La IP de Ethernet del G1 está fija en 192.168.123.164. Su máquina debe tener una IP estática en la misma subred: 192.168.123.x donde x ≠ 164.

# Replace 'enp131s0' with your ethernet interface name (check with `ip a`)
sudo ip addr flush dev enp131s0
sudo ip addr add 192.168.123.200/24 dev enp131s0
sudo ip link set enp131s0 up

Conectarse al robot mediante SSH

ssh unitree@192.168.123.164
# Password: 123

Compartir Internet a través de Ethernet

El G1 necesita acceso a internet para clonar repositorios e instalar paquetes. Comparta la conexión de su laptop a través de Ethernet:

En tu portátil:

sudo sysctl -w net.ipv4.ip_forward=1

# Replace wlp132s0f0 with your WiFi interface name
sudo iptables -t nat -A POSTROUTING -o wlp132s0f0 -s 192.168.123.0/24 -j MASQUERADE
sudo iptables -A FORWARD -i wlp132s0f0 -o enp131s0 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -A FORWARD -i enp131s0 -o wlp132s0f0 -j ACCEPT

En el G1:

sudo ip route del default 2>/dev/null || true
sudo ip route add default via 192.168.123.200 dev eth0
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

# Verify
ping -c 3 8.8.8.8

Instale el SDK de Unitree en el G1

Siga la guía de instalación de unitree_sdk2_python:

conda create -y -n lerobot python=3.12
conda activate lerobot
git clone https://github.com/unitreerobotics/unitree_sdk2_python.git
cd unitree_sdk2_python
python -m pip install -e .
cd ..

Instalar LeRobot en el G1

git clone https://github.com/huggingface/lerobot.git
cd lerobot
conda install -c conda-forge "pinocchio>=3.0.0,<4.0.0"
python -m pip install -e '.[unitree_g1]'
For now, pinocchio must be installed from conda-forge (not pip) to include the CasADi bindings needed for arm IK.

(Opcional) Activar el WiFi en el robot

Para el acceso SSH inalámbrico, puede habilitar el WiFi en el G1 (está bloqueado de forma predeterminada):

sudo rfkill unblock all
sudo ip link set wlan0 up
sudo nmcli radio wifi on
sudo nmcli device set wlan0 managed yes
sudo systemctl restart NetworkManager

Conectar a una red WiFi:

nmcli device wifi list

sudo nmcli connection add type wifi ifname wlan0 con-name "YourNetwork" ssid "YourNetwork"
sudo nmcli connection modify "YourNetwork" wifi-sec.key-mgmt wpa-psk
sudo nmcli connection modify "YourNetwork" wifi-sec.psk "YourPassword"
sudo nmcli connection modify "YourNetwork" connection.autoconnect yes
sudo nmcli connection up "YourNetwork"

ip a show wlan0

A continuación, puede usar SSH a través de WiFi en lugar de Ethernet:

ssh unitree@<ROBOT_WIFI_IP>
# Password: 123

Parte 2: Teleoperación y locomoción

Ejecutar el servidor de Robot

En el robot (desde ~/lerobot):

cd ~/lerobot
python src/lerobot/robots/unitree_g1/run_g1_server.py --camera

Ejecutar la política de locomoción

Puede ejecutar el cliente de teleoperación desde su portátil a través de Ethernet, a través de WiFi (experimental) o directamente en el propio robot. Tenga en cuenta la latencia potencial introducida por su red.

Desde tu portátil:

lerobot-teleoperate \
  --robot.type=unitree_g1 \
  --robot.is_simulation=false \
  --robot.robot_ip=<ROBOT_IP> \
  --teleop.type=unitree_g1 \
  --teleop.id=wbc_unitree \
  --robot.cameras='{"global_view": {"type": "zmq", "server_address": "<ROBOT_IP>", "port": 5555, "camera_name": "head_camera", "width": 640, "height": 480, "fps": 30}}' \
  --display_data=true \
  --robot.controller=HolosomaLocomotionController

Admitimos tanto GrootLocomotionController como HolosomaLocomotionController mediante --robot.controller.


Parte 3: Manipulación con el exoesqueleto Homunculus

Ofrecemos una solución de loco-manipulación mediante el Exoesqueleto Homunculus, un exoesqueleto de 7 DoF de código abierto para el control de todo el cuerpo. Puedes verlo aquí.

Calibrar

lerobot-calibrate \
  --teleop.type=unitree_g1 \
  --teleop.left_arm_config.port=/dev/ttyACM1 \
  --teleop.right_arm_config.port=/dev/ttyACM0 \
  --teleop.id=exo

Durante la calibración, mueva cada articulación a través de su rango completo. Después de ajustar, coloque la articulación en una posición neutra y presione n para avanzar.

Registrar un Dataset

lerobot-record \
  --robot.type=unitree_g1 \
  --robot.is_simulation=true \
  --robot.cameras='{"global_view": {"type": "zmq", "server_address": "localhost", "port": 5555, "camera_name": "head_camera", "width": 640, "height": 480, "fps": 30}}' \
  --teleop.type=unitree_g1 \
  --teleop.left_arm_config.port=/dev/ttyACM1 \
  --teleop.right_arm_config.port=/dev/ttyACM0 \
  --teleop.id=exo \
  --dataset.repo_id=your-username/dataset-name \
  --dataset.single_task="Test" \
  --dataset.num_episodes=2 \
  --dataset.episode_time_s=5 \
  --dataset.reset_time_s=5 \
  --dataset.push_to_hub=true \
  --dataset.streaming_encoding=true \
  --dataset.encoder_threads=2

Nota: Omita --teleop.left_arm_config.port y --teleop.right_arm_config.port si solo está usando el joystick.

Conjunto de datos de ejemplo: nepyope/unitree_box_move_blue_full


Parte 4: Entrenamiento e inferencia

Entrenar

python src/lerobot/scripts/lerobot_train.py \
  --dataset.repo_id=your-username/dataset-name  \
  --policy.type=pi05 \
  --output_dir=./outputs/pi05_training \
  --job_name=pi05_training \
  --policy.repo_id=your-username/your-repo-id \
  --policy.pretrained_path=lerobot/pi05_base \
  --policy.compile_model=true \
  --policy.gradient_checkpointing=true \
  --trackio.enable=true \
  --policy.dtype=bfloat16 \
  --policy.freeze_vision_encoder=false \
  --policy.train_expert_only=false \
  --steps=3000 \
  --policy.device=cuda \
  --batch_size=32

Inferencia con RTC

Una política entrenada compatible puede usar RTC de inferencia local:

lerobot-rollout \
  --strategy.type=base \
  --policy.path=your-username/your-repo-id \
  --policy.device=cuda \
  --robot.type=unitree_g1 \
  --robot.is_simulation=false \
  --robot.controller=HolosomaLocomotionController \
  --robot.cameras='{"global_view": {"type": "zmq", "server_address": "<ROBOT_IP>", "port": 5555, "camera_name": "head_camera", "width": 640, "height": 480, "fps": 30}}' \
  --task="task_description" \
  --duration=1000 \
  --fps=30 \
  --inference.type=rtc

Los controladores de locomoción G1 no declaran el contrato de objetivo retenido utilizado por la espera recuperable de rollout. Por lo tanto, una vez que comienza el movimiento, agotar su búfer de acciones provoca una falla terminal en lugar de una espera de período de gracia. También se aplican los plazos de solicitud y los límites de antigüedad de la observación. Valide que el chunk utilizable de la política cubra la latencia de inferencia antes de usar esta receta; consulte espera y presupuestos de RTC local. SONIC tiene un contrato de token retenido separado, descrito a continuación.


Parte 5: Control de cuerpo completo de SONIC (Políticas de tokens latentes)

LeRobot ahora incorpora la mitad decoder del stack de despliegue de cuerpo completo SONIC de NVIDIA como SonicWholeBodyController. En lugar de comandar articulaciones, la política emite un token latente de movimiento de 64 dimensiones (motion_token.{i}.pos) en cada tick; el decodificador SONIC mapea ese token junto con el historial reciente de propiocepción a una acción residual que se escala y se suma a la pose de pie, generando objetivos de posición de articulaciones a 50 Hz para los 29 DoF.

El controlador carga su decodificador ONNX y todas las constantes de despliegue (ganancias PD, default_angles, action_scale y el token neutro) desde lerobot/sonic_decoder. El repositorio también incluye un decodificador destilado de baja latencia, seleccionable con el argumento policy_type="low_latency" del controlador (el valor predeterminado es "default").

Prueba en simulación

Cualquier política de salida de tokens entrenada con tokens de movimiento SONIC (p. ej. nepyope/sonic_walk) puede controlarla:

lerobot-rollout \
  --strategy.type=base \
  --policy.path=nepyope/sonic_walk \
  --policy.device=cuda \
  --robot.type=unitree_g1 \
  --robot.is_simulation=true \
  --robot.controller=SonicWholeBodyController \
  --robot.cameras='{"ego_view": {"type": "zmq", "server_address": "localhost", "port": 5555, "camera_name": "head_camera", "width": 640, "height": 480, "fps": 30, "warmup_s": 15}}'

Ejecutar en el robot físico

Ejecute el servidor de políticas de inferencia remota en la máquina con GPU y mantenga el puente del robot, el decodificador SONIC y el cliente de rollout en el Jetson G1. Solo los fragmentos de tokens de 64 dimensiones cruzan la red; el decodificador y el bucle de rt/lowcmd a 50 Hz permanecen a bordo.

Instale el extra remoto en ambas máquinas. Mantenga el extra de Unitree en el G1:

# GPU machine
python -m pip install -e '.[remote]'

# G1 Jetson
python -m pip install -e '.[unitree_g1,remote]'

En la máquina con GPU, inicie el servidor de política desde la raíz del repositorio. El perfil mantenido coincide con nepyope/sonic_walk; para otra política, copie y actualice su checkpoint y su contrato de características juntos.

lerobot-policy-server \
  --config_path=examples/remote_inference/unitree_g1_sonic.yaml

En el G1, mantén el puente y la cámara en funcionamiento:

python src/lerobot/robots/unitree_g1/run_g1_server.py --camera

Luego, inicie el cliente de rollout en un segundo terminal de G1, reemplazando <GPU_MACHINE_IP>:

lerobot-rollout \
  --strategy.type=base \
  --inference.type=remote \
  --inference.endpoint=tcp/<GPU_MACHINE_IP>:7447 \
  --inference.deployment=g1-sonic \
  --inference.semantics=unitree-g1-sonic-motion-token-v1 \
  --inference.encoding=jpeg \
  --inference.action_starvation_grace_s=1.0 \
  --robot.type=unitree_g1 \
  --robot.is_simulation=false \
  --robot.robot_ip=127.0.0.1 \
  --robot.controller=SonicWholeBodyController \
  --robot.cameras='{"ego_view": {"type": "zmq", "server_address": "127.0.0.1", "port": 5555, "camera_name": "head_camera", "width": 640, "height": 480, "fps": 30, "warmup_s": 5}}' \
  --task='walk forward' \
  --fps=30 \
  --return_to_initial_position=false \
  --interactive=true

Escriba /start solo después de que G1 esté listo para moverse. SONIC declara soporte de espera porque reenviar el último token completo mantiene el equilibrio del decodificador a bordo. Antes del primer resultado de la política, rollout envía el token neutro del decodificador. Si el búfer de acciones se agota, repite el último token aplicado durante un máximo de action_starvation_grace_s (un segundo en el ejemplo anterior); si no llega una predicción nueva, rollout falla y sigue su ruta de apagado/desconexión configurada. Los controladores de locomoción de G1 no son compatibles porque sus velocidades de joystick no pueden conservarse de esta manera.

La receta desactiva el retorno a la posición inicial: interpolar a través del espacio de tokens latentes de SONIC no es una trayectoria de retorno físico validada. Evite /reset por la misma razón, ya que devolvería el token a su valor de conexión. /stop sigue cerrando la sesión remota y desconectando el robot a través de la ruta normal de apagado del controlador.

Con SonicWholeBodyController, el estado de observación es el eco de tokens de 64 dimensiones en lugar de las 29 posiciones articulares, por lo que un checkpoint compatible debe entrenarse contra ese estado. Al conectar, el robot lleva las articulaciones suavemente a los default_angles del decodificador antes de que el controlador tome el control.


Recursos adicionales


Última actualización: julio de 2026

Update on GitHub