Por dentro del software: DDS, SDK, alto y bajo nivel
Tu programa no llama a una función del robot: publica y se suscribe a mensajes en un bus DDS. En esta clase armas la bancada del fabricante (simulador, SDK y CycloneDDS 0.10.2), levantas el G1 simulado y lees el primer mensaje de estado, por el mismo camino que usarías con el robot real.
1El camino: tu programa → SDK → DDS → robot o simulador
2La bancada en ~/fth con versiones fijadas, incluido el CycloneDDS compilado
3Alto nivel (locomoción lista) × bajo nivel (motor por motor)
4Dominio e interfaz: el error que hace que el robot parezca muerto
Objetivo: armar la bancada del fabricante (simulador, SDK, CycloneDDS 0.10.2) y leer el primer mensaje de estado del G1 por DDS.
01 · De tu programa al motor
Haz clic en cada bloque.
Haz clic en cada bloque del diagrama para ver qué hace.
Cambiar el simulador por el robot cambia el dominio y la interfaz, no tu código.
02 · Tres cosas que debes saber antes de instalar
Haz clic en cada una.
1. Alto × bajo
Nivel alto: el control de locomoción del fabricante camina y tú pides velocidad (LocoClient en el servicio "sport": SetVelocity, Move, Damp, ZeroTorque).
Nivel bajo: tú mandas en cada motor por rt/lowcmd. Antes, el ejemplo oficial libera el control interno (MotionSwitcherClient, CheckMode y ReleaseMode); si no, los dos se disputan los motores.
2. Dominio e interfaz
El simulador usa el dominio 1 en la interfaz lo (config.py de unitree_mujoco). Los ejemplos del SDK usan el dominio 0 y el nombre de la placa de red conectada al robot.
Un programa y un robot en dominios distintos no se ven: el script espera y el robot parece muerto. La pestaña "Error común" muestra el mensaje.
Red del robot realEl README de unitree_ros2 pone el PC con IP fija en la subred 192.168.123.x (ejemplo: 192.168.123.99) y la interfaz se indica por el nombre (enp3s0).
3. Cuál G1
El G1 base cuesta US$ 13,5 mil en la página oficial (consultada el 19/10/2026), pero no tiene desarrollo secundario: sin SDK. Para programar como en este curso necesitas la versión EDU, que se vende bajo consulta.
Distribuidores citados por la investigación de la formación (oct/2026): US$ 43,5 mil a 73,9 mil (reportado; varía según la versión y el distribuidor). El simulador no cuesta nada y habla el mismo DDS.
03 · Armar el banco de trabajo (una vez)
Venv en ~/fth (el mismo del curso 0, si lo hiciste), simulador y SDK fijados en commits, y el CycloneDDS 0.10.2 compilado: pip solo falla en aarch64 sin la biblioteca C. Necesitas python3.12 (con venv), git, cmake y un compilador C.
cyclonedds C 0.10.2 instalado em ~/fth/cyclonedds/install
cyclonedds 0.10.2 · unitree_sdk2py 1.0.1 · mujoco 3.16.0
Los dos commits y las tres versiones. La compilación tarda unos minutos; el aviso del compilador queda oculto en /dev/null.
04 · Levantar el G1 simulado y leer el estado
kit/sim.py ejecuta el puente de unitree_mujoco sin ventana, en segundo plano, durante 8 s; ler_estado.py es otro proceso que solo se suscribe a rt/lowstate. El G1 está colgado del elástico (el pórtico del simulador).
class Estado:
"""Assina rt/lowstate e guarda a última mensagem e quantas chegaram."""
def __init__(self):
from unitree_sdk2py.core.channel import ChannelSubscriber
from unitree_sdk2py.idl.unitree_hg.msg.dds_ import LowState_
self.ultima, self.n, self.t_ultima = None, 0, 0.0
self.sub = ChannelSubscriber("rt/lowstate", LowState_)
self.sub.Init(self._chegou, 10)
Mostrado · solo con el robot real, después del checklist
# Trecho de example/g1/low_level/g1_low_level_example.py (unitree_sdk2_python 814556d)
ChannelFactoryInitialize(0, sys.argv[1]) # domínio 0 + nome da placa ligada ao robô
self.msc = MotionSwitcherClient()
self.msc.SetTimeout(5.0)
self.msc.Init()
status, result = self.msc.CheckMode()
while result['name']: # libera o controle interno antes do baixo nível
self.msc.ReleaseMode()
status, result = self.msc.CheckMode()
time.sleep(1)
Ejemplo del repositorio
simulador: G1 29 motores · DDS domínio 1 em lo · 8 s · suspenso: sim
tópico: rt/lowstate · tipo: unitree_hg LowState_
IMU quatérnio (w, x, y, z): [1.0, 0.0, 0.1, 0.0] · tronco em pé (inclinação < 20°): sim
junta 0 (left_hip_pitch): q = 0.0 rad · torque estimado = 0 N·m
motores no pacote: 35 (o G1 de 29 GDL usa os índices 0 a 28)
saída: 0
simulador: fim em t = 8.0 s · robô suspenso (pés fora do chão)
El paquete tiene 35 posiciones de motor; el G1 de 29 GDL usa las 29 primeras. Motores sueltos: torque cero.
ERRO: nenhuma mensagem em rt/lowstate em 10 s. O simulador está rodando? (kit/sim.py)
saída: 1
Ningún mensaje en 10 s: el simulador no está corriendo, o tu programa está en otro dominio u otra interfaz.
05 · Práctica
Banco de pruebas listo y primer mensaje leído.
E1 · Montar el banco de pruebas
15 min
Corre los dos bloques de preparación. Si cmake se queja, instala cmake y un compilador C desde el gestor de paquetes de tu sistema y corre el segundo bloque de nuevo.
Corre el bloque del simulador con la lectura y explica por qué el paquete tiene 35 motores si el G1 tiene 29.
Listo cuando:python3 kit/ler_estado.py; echo "saída: $?" (con el sim.py corriendo) → motores no pacote: 35 (o G1 de 29 GDL usa os índices 0 a 28) y saída: 0.
E3 · Ver el error del dominio
3 min
Corre solo el ler_estado.py, sin el simulador, y espera los 10 s.
Listo cuando:ERRO: nenhuma mensagem em rt/lowstate em 10 s y saída: 1.
06 · Prueba de la clase
La explicación aparece después de tu respuesta.
Pregunta 1 de 4
El ler_estado.py se quedó 10 s esperando y dio error. ¿Cuál es la causa más probable?competencia
Correcto
Publicador y suscriptor solo se encuentran en el mismo dominio y en la misma interfaz. El simulador usa el dominio 1 en lo; el ejemplo del SDK, el dominio 0.
¿Qué tópico trae el estado (IMU y motores) del G1?
Correcto
El estado viene en rt/lowstate y el comando va en rt/lowcmd, ambos del IDL unitree_hg. /robot_state y RobotState_ eran de un curso antiguo y no existen en el SDK.
No es esa
El estado viene en rt/lowstate y el comando va en rt/lowcmd, ambos del IDL unitree_hg. /robot_state y RobotState_ eran de un curso antiguo y no existen en el SDK.Repasar: De tu programa al motor
Pregunta 3 de 4
Antes de mandar un comando de bajo nivel al robot real, ¿qué hace el ejemplo oficial?
Correcto
CheckMode y ReleaseMode hasta que el control interno salga; si no, tu rt/lowcmd y el controlador del fabricante se disputan los motores. En el simulador ese servicio no existe.
No es esa
CheckMode y ReleaseMode hasta que el control interno salga; si no, tu rt/lowcmd y el controlador del fabricante se disputan los motores. En el simulador ese servicio no existe.Repasar: Armar el banco de trabajo (una vez)
Pregunta 4 de 4
¿Por qué el curso compila CycloneDDS en vez de usar solo pip?
Correcto
El paquete Python cyclonedds 0.10.2 necesita la biblioteca C; en aarch64 no había binario listo. Se compila la tag 0.10.2 y se apunta CYCLONEDDS_HOME.
No es esa
El paquete Python cyclonedds 0.10.2 necesita la biblioteca C; en aarch64 no había binario listo. Se compila la tag 0.10.2 y se apunta CYCLONEDDS_HOME.Repasar: Armar el banco de trabajo (una vez)
Prueba completada
Acertaste {a} de {n}. Si aciertas todas, la clase se marca como completada.
Elige una alternativa. La explicación aparece después de tu intento.
07 · En tres frases
BusPrograma y robot conversan por DDS: rt/lowstate y rt/lowcmd.
DominioSimulador en el dominio 1 en lo; robot en el 0 en la placa de red.
Banco de pruebasunitree_mujoco 1eb6642, SDK 814556d y CycloneDDS 0.10.2.