LeRobot documentation
Unitree G1
Unitree G1
O humanoide Unitree G1 é suportado no LeRobot. Você pode operar por teleoperação, treinar políticas de locomanipulação, testar em simulação e muito mais. As variantes de 29 e 23 graus de liberdade (DoF) são suportadas.
Seleção de Embodiment
A classe UnitreeG1 seleciona suas definições de juntas por meio de UnitreeG1Config.embodiment.
O padrão é g1_29; portanto, as configurações existentes mantêm o comportamento do G1-29. Selecione
o layout de 23 graus de liberdade com --robot.embodiment=g1_23 ou em Python:
from lerobot.robots.unitree_g1 import UnitreeG1Config
config = UnitreeG1Config(embodiment="g1_23", is_simulation=False)| Capacidade | G1-29 | G1-23 |
|---|---|---|
| Configuração conjunta e recursos de ação/observação | 29 articulações do corpo, 14 articulações dos braços | 23 articulações do corpo, 10 articulações dos braços |
| Layout de comandos/feedback do DDS | 29 slots ativos | 29 slots com articulações ausentes mantidos inativos |
| Simulação MuJoCo | Suportado | Ainda não suportado; modelo nativo planejado |
| Controladores de locomoção | GR00T e Holosoma | GR00T e Holosoma |
| Controlador de corpo inteiro SONIC | Suportado | Não suportado; a política requer 29 graus de liberdade |
| Compensação de gravidade | Suportado, desativado por padrão | Ainda não suportado; cinemática nativa planejada |
Ambas as variantes usam o mesmo layout de mensagem DDS de 29 slots. O G1-29 usa todos os 29 slots, enquanto o G1-23 usa 23 e deixa os seis slots de junta inexistente inativos. Os vetores kp, kd e default_positions permanecem, portanto, com 29 elementos e são indexados pelo slot DDS.
Os slots de braço ativos do G1-23 são 15..19 e 22..26. Os slots 13, 14, 20, 21, 27, 28 não possuem
junta ativa; seus valores de configuração devem ser zero. Eles são omitidos dos recursos de ação/observação, sem renumeração.
As entradas de comando inativas e reservadas são limpas antes de publicar uma mensagem G1-23.
Sobrescritas explícitas de ganho devem ser finitas, não negativas e usar o mesmo layout esparsa.
Os ganhos padrão são compartilhados pelo nome da junta entre ambas as variantes, de modo que juntas físicas idênticas
usam ganhos idênticos, enquanto os slots ausentes do G1-23 permanecem zero.
A simulação nativa do MuJoCo para o G1-23 ainda não é suportada. Selecionar a embodiment G1-23 com a simulação habilitada falha antes da inicialização do transporte. Um modelo nativo do MuJoCo para o G1-23 está planejado para uma versão futura.
Parte 1: Primeiros passos
Instale o SDK da Unitree
Siga o guia de instalação do unitree_sdk2_python. Testado com unitree_sdk2py==1.0.1 e 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.
Teste a Instalação (Simulação)
O ambiente de simulação possui suas próprias dependências. Verifique as dependências do ambiente de simulação: 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=GrootLocomotionControllerIsso iniciará uma instância de simulação MuJoCo para o G1. Você pode conectar um controle de jogo à sua máquina antes de iniciar para controlar a locomoção do robô na simulação. Suportamos tanto o HolosomaLocomotionController quanto o GrootLocomotionController via --robot.controller.
- Pressione
9para soltar o robô - Pressione
7/8para aumentar / diminuir a altura da cintura
Escolhendo o efetuor final
--robot.end_effector define o que os braços carregam: dex1 para as pinças paralelas (o padrão), dex3 para as mãos de três dedos, ou dummy para punhos nus. Na simulação, ele seleciona o modelo MuJoCo, que determina os atuadores dos dedos e quais câmeras a cena possui — as câmeras de punho são montadas no efetuor final, portanto dummy possui apenas head_camera.
lerobot-teleoperate \
--robot.type=unitree_g1 \
--robot.is_simulation=true \
--robot.end_effector=dex3 \
--teleop.id=wbc_unitree \
--robot.controller=GrootLocomotionControllerO simulador publica as câmeras do modelo via ZMQ na porta --robot.sim_camera_port (5555 por padrão), que é de onde as câmeras zmq em --robot.cameras as leem. Passe --robot.sim_publish_images=false para abrir a janela interativa do MuJoCo em vez disso: o simulador renderiza ou suas câmeras ou sua janela, nunca ambos, pois os contextos offscreen pertencem à thread que os cria, e não ao visualizador. --robot.sim_onscreen nomeia essa escolha explicitamente, em vez de deixá-la a cargo das câmeras, e solicitar ambos é recusado; defina-o e --robot.sim_publish_images ambos como false para não renderizar nada, o que é o que uma máquina sem display pode fazer.
Conectar ao Robô Físico
O IP Ethernet do G1 é fixo em 192.168.123.164. Sua máquina deve ter um IP estático na mesma sub-rede: 192.168.123.x onde 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 upFaça login via SSH no Robô
ssh unitree@192.168.123.164
# Password: 123Compartilhar a Internet via Ethernet
O G1 precisa de acesso à internet para clonar repositórios e instalar pacotes. Compartilhe a conexão do seu laptop via Ethernet:
No seu laptop:
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 ACCEPTNo 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.8Instale o SDK da Unitree no G1
Siga o guia de instalação do 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 ..Instale o LeRobot no 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) Ative o Wi-Fi no Robô
Para acesso SSH sem fio, você pode habilitar o WiFi no G1 (ele é bloqueado por padrão):
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 NetworkManagerConectar a uma rede 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 wlan0Em seguida, você pode usar SSH via WiFi em vez de Ethernet:
ssh unitree@<ROBOT_WIFI_IP>
# Password: 123Parte 2: Teleoperação & Locomoção
Execute o Servidor de Robô
No robô (a partir de ~/lerobot):
cd ~/lerobot
python src/lerobot/robots/unitree_g1/run_g1_server.py --cameraExecute a Política de Locomoção
Você pode executar o cliente de teleoperação a partir do seu laptop via Ethernet, via WiFi (experimental) ou diretamente no próprio robô. Fique atento à latência potencial introduzida pela sua rede.
A partir do seu laptop:
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=HolosomaLocomotionControllerSuportamos tanto o GrootLocomotionController quanto o HolosomaLocomotionController por meio de --robot.controller.
Parte 3: Loco-Manipulação com o Exoesqueleto Homúnculo
Oferecemos uma solução de locomanipulação por meio do Homunculus Exoskeleton — um exoesqueleto de 7 graus de liberdade de código aberto para controle do corpo inteiro. Confira aqui.
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 a calibração, mova cada junta por todo o seu intervalo. Após o ajuste, mova a junta para uma posição neutra e pressione n para avançar.
Registrar um 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=2Nota: Omita
--teleop.left_arm_config.porte--teleop.right_arm_config.portse você estiver usando apenas o joystick.
Conjunto de dados de exemplo: nepyope/unitree_box_move_blue_full
Parte 4: Treinamento & Inferência
Treinar
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=32Inferência com RTC
Uma política treinada compatível pode usar RTC de inferência 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=rtcOs controladores de locomoção G1 não declaram o contrato de alvo retido usado pela espera recuperável do rollout. Após o início do movimento, esgotar o buffer de ações causa, portanto, uma falha terminal em vez de uma espera de período de tolerância. Prazos de solicitação e limites de idade da observação também se aplicam. Valide que o chunk utilizável da política cobre a latência de inferência antes de usar esta receita; consulte espera e orçamentos locais de RTC. O SONIC possui um contrato de token retido separado, descrito abaixo.
Parte 5: Controle Corporal Completo do SONIC (Políticas de Tokens Latentes)
LeRobot agora portou a metade decoder do stack de deploy whole-body SONIC da NVIDIA como SonicWholeBodyController. Em vez de comandar juntas, a política gera um latent motion token de 64 dimensões (motion_token.{i}.pos) a cada tick; o decoder SONIC mapeia esse token junto com o histórico recente de propriocepção para uma ação residual, que é escalada e somada à pose em pé, produzindo alvos de posição de junta a 50 Hz para todos os 29 DoF.
O controlador carrega seu decodificador ONNX e todas as constantes de implantação (ganhos PD, default_angles, action_scale e o token neutro) de lerobot/sonic_decoder. O repositório também inclui um decodificador destilado de baixa latência, selecionável com o argumento policy_type="low_latency" do controlador (padrão é "default").
Teste em Simulação
Qualquer política de saída de tokens treinada em tokens de movimento SONIC (por exemplo, nepyope/sonic_walk) pode controlá-lo:
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}}'Executar no Robô Físico
Execute o servidor de política de inferência remota na máquina com GPU e mantenha a ponte do robô, o decodificador SONIC e o cliente de rollout no Jetson do G1. Apenas blocos de tokens de 64-D cruzam a rede; o decodificador e o loop de rt/lowcmd de 50 Hz permanecem a bordo.
Instale o extra remoto em ambas as máquinas. Mantenha o extra Unitree no G1:
# GPU machine
python -m pip install -e '.[remote]'
# G1 Jetson
python -m pip install -e '.[unitree_g1,remote]'Na máquina com GPU, inicie o servidor de política a partir da raiz do repositório. O perfil mantido corresponde a nepyope/sonic_walk; para outra política, copie e atualize seu checkpoint e contrato de recursos juntos.
lerobot-policy-server \ --config_path=examples/remote_inference/unitree_g1_sonic.yaml
No G1, mantenha a ponte e a câmera em execução:
python src/lerobot/robots/unitree_g1/run_g1_server.py --camera
Em seguida, inicie o cliente de rollout em um segundo terminal do G1, substituindo <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=trueDigite /start somente depois que o G1 estiver liberado para se mover. O SONIC declara suporte a espera, pois reenviar o último token completo mantém o decodificador embarcado em equilíbrio. Antes do primeiro resultado de política, o rollout envia o token neutro do decodificador. Se o buffer de ações esvaziar, ele repete o último token aplicado por no máximo action_starvation_grace_s (um segundo acima); se nenhuma previsão nova chegar, o rollout falha e segue seu caminho de desligamento/desconexão configurado. Os controladores de locomoção do G1 permanecem sem suporte, pois suas velocidades de joystick não podem ser retidas dessa forma.
A receita desativa o retorno à posição inicial: interpolar pelo espaço de tokens latentes do SONIC não é uma trajetória de retorno físico validada. Evite /reset pela mesma razão, pois ele faria o token retornar ao seu valor de conexão. /stop ainda encerra a sessão remota e desconecta o robô pelo caminho normal de desligamento do controlador.
Com o SonicWholeBodyController, o estado de observação é o eco de token de 64 dimensões, em vez das 29 posições das juntas, portanto, um checkpoint compatível deve ser treinado em relação a esse estado. Na conexão, o robô suaviza as juntas até os default_angles do decodificador antes de o controlador assumir o controle.
Recursos adicionais
- Documentação do SDK da Unitree
- GR00T-WholeBodyControl
- Holosoma
- Documentação do LeRobot
- Unitree IL LeRobot
Última atualização: julho de 2026
Update on GitHub