Cómo calibrar las cámaras en Unitree G1
Calibración de cámara intrínseca y extrínseca basada en ChArUco para las cámaras de cabeza Unitree G1. Guarde en YAML, valida y integra con su pila de políticas.
Cada manipulación seria o la locomoción del humanoide Unitree G1 comienza con una buena calibración de la cámara. Este tutorial recorre la calibración intrínseca y extrínseca de la matriz de la cámara de la cabeza G1 utilizando una tabla ChArUco y OpenCV, guardando los resultados a YAML y validando con una verificación de la cordura de error de reproyección.
Humanoid Tiempo total: aproximadamente 90 minutos Dificultad: Intermedio Actualizado abril 2026
Lo que lograrás
Al final de este tutorial tendrá intrínsecas por cámara (matriz de cámara y coeficientes de distorsión) para cada una de las cámaras de cabeza G1, extrínsecas entre cámaras en el equipo de cabeza, y opcionalmente la extrínseca desde el marco de la cámara de cabeza hasta el enlace de base G1. Todo guardado en YAML en un formato que su pila de ROS 2 / LeRobot / OpenVLA puede consumir directamente.
La mala calibración es una de las causas raíces más comunes de "la política funcionó en sim pero falla en el robot real"
Pre-requisitos
- Unitree G1 con la matriz de cámara de la cabeza alimentada y en streaming (las variantes EDU / Desarrollador exponen las cámaras sobre el SDK).
- Tabla de ChArUco. Imprimir una tabla A2 8x11 con cuadros de 40 mm y marcadores de 30 mm ArUco en papel mate y montarla en una superficie rígida, plana y no deformable (tabla de espuma o acrílico).
- Estación de trabajo con Ubuntu 22.04, Python 3.10, OpenCV 4.8+, y el SDK Unitree G1 instalado.
- Evite el sol directo o los reflejos especulares en la tabla.
Los pasos
- Imprimir y montar la tabla de ChArUco
Generar la tabla PDF:
```
python -c "
import cv2
aruco = cv2.aruco
d = aruco.getPredefinedDictionary(aruco.DICT_5X5_100)
board = aruco.CharucoBoard((8, 11), 0.040, 0.030, d)
img = board.generateImage((1500, 2100), marginSize=40)
cv2.imwrite('charuco_a2.png', img)
"
```
Imprimir en tamaño real (sin escalar) en papel mate A2, verificar que los cuadros impresos miden exactamente 40,0 mm, y montar en un respaldo rígido y plano.
Configure el G1 y transmita las cámaras
Inicie el proceso de conexión de la cámara de cabeza a través del SDK Unitree. La unión exacta de Python está en el [unitreerobotics]
- Captura 40 a 60 cuadros de tablero
Mover la cabeza (o la placa) de G1 a través de una amplia gama de poses: inclinada a la izquierda, inclinada a la derecha, cercana, lejos, fuera del eje. La calibración de OpenCV es tan buena como la diversidad de puntos de vista que le da. Para la estereo extrínseca, captura marcos sincronizados en ambas cámaras para cada pose.
```
import cv2
for i in range(60):
frame_left, frame_right = camera.grab_sync()
cv2.imwrite(f'calib/left_{i:03d}.png', frame_left)
cv2.imwrite(f'calib/right_{i:03d}.png', frame_right)
input("move board, press enter")
```
Punta: la tabla debe llenar al menos el 30% del marco, y los marcadores más detectados en las esquinas deben abarcar toda la región de la imagen.
Computa las intrínsecas por cámara
Ejecutar la calibración intrínseca de ChArUco por cámara:
```
import cv2, glob, numpy as np
aruco = cv2.aruco
d = aruco.getPredefinedDictionary(aruco.DICT_5X5_100)
board = aruco.CharucoBoard((8, 11), 0.040, 0.030, d)
detector = aruco.CharucoDetector(board)
all_corners, all_ids, img_size = [], [], None
for fn in sorted(glob.glob('calib/left_*.png')):
img = cv2.imread(fn, cv2.IMREAD_GRAYSCALE)
img_size = img.shape[::-1]
corners, ids, _, _ = detector.detectBoard(img)
if ids is not None and len(ids) > 6:
all_corners.append(corners)
all_ids.append(ids)
ret, K, dist, rvecs, tvecs = aruco.calibrateCameraCharuco(
all_corners, all_ids, board, img_size, None, None)
print('RMS reprojection error:', ret)
```
RMS objetivo por debajo de 0,5 píxeles. Por encima de 1 px indica mala planitud de la tabla, insuficiente diversidad de posturas o marcos fuera de enfoque.
- Computa las estereotipos extrínsecas
Para pares de cámaras (por ejemplo, cámaras de cabeza izquierda + derecha en una plataforma G1 binocular), ejecuta
```
ret, K1, D1, K2, D2, R, T, E, F = cv2.stereoCalibrate(
object_points, left_img_points, right_img_points,
K_left, D_left, K_right, D_right, img_size,
flags=cv2.CALIB_FIX_INTRINSIC)
```
Computa extrínsecas de cabeza a base (opcional)
Si su política de aguas abajo necesita posiciones de cámara en el enlace base o marco mundial G1, recorra a través de la kinemática de la cabeza conocida: lea el estado de la cabeza en el SDK, compón con el extrínseco de la cámara a la cabeza (desde la URDF o una calibración de ojo de mano única) y publique un ROS 2
Ahorrar para YAML
Guarde en un formato YAML compatible con ROS para que funcionen los cargadores estándar
```
import yaml
out = {
'image_width': 1280,
'image_height': 720,
'camera_name': 'g1_head_left',
'camera_matrix': {'rows': 3, 'cols': 3, 'data': K.flatten().tolist()},
'distortion_model': 'plumb_bob',
'distortion_coefficients': {'rows': 1, 'cols': 5, 'data': dist.flatten().tolist()},
}
with open('g1_head_left.yaml', 'w') as f:
yaml.safe_dump(out, f)
```
- Valida en una escena de prueba
Captura un nuevo marco ChArUco que no estaba en el conjunto de calibración. Detecta esquinas, reproyecta usando tus intrínsecas guardadas, y superpone la imagen. El error medio de reproyección debe permanecer por debajo de 0,5 píxeles. También pasear el robot a través de algunas poses diferentes de la cabeza y ver la disparidad estéreo en un objeto de distancia conocida si está de acuerdo con la distancia medida en cinta a dentro de 1 a 2 cm a un rango de 1 m, sus extrínsecas son buenas.
¿Qué hacer ahora?
Incluye sus intrínsecas calibradas en cualquier pila de políticas de aguas abajo: OpenVLA fine-tuning utiliza imágenes rectificadas, LeRobot recording almacena las
Modo de falla común
Esto es un error de re-proyección: tablero deformado, diversidad de postura insuficiente o marcos fuera de enfoque.
Extrínsecas equivocadas en unos pocos cm: generalmente un insecto unidad
Runs inconsistentes: comprobar que el estado de la articulación de la cabeza está bloqueado mientras se captura cada marco; movimiento durante la captura de interrupciones de calibración.
** Política sigue fallido después de la calibración:** verifique el orden de imagen (BGR vs RGB) y el orden de tamaño (recorte luego recorte vs recorte luego recorte) coincide con el procesamiento preliminar de la política.
Inmersión profunda: por qué ChArUco sobre tablero de ajedrez simple
Un tablero de ajedrez simple es el objetivo de calibración del libro de texto, pero tiene un modo de falla bien conocido: si alguna parte del tablero está oculta, toda la detección falla. ChArUco (un tablero de ajedrez con fiduciarios ArUco incrustados en los cuadros blancos) resuelve esto dando a cada rincón una identidad única. El calibrador puede usar observaciones parciales, por lo que puede mover la tabla de manera agresiva a través de diversas poses sin perder tiempo de captura en marcos inutilizables. Evite las funciones obsoletas en los tutoriales antiguos; el refinamiento de la esquina de subpixel es mucho mejor en la nueva API.
En particular, para las cámaras de cabeza humanoides, ChArUco también ayuda con una sutileza: la cabeza se inclina durante la captura, por lo que sus marcos alternan entre "la tabla toma toda la imagen" y "la tabla se desvía a un lado".
¿Qué tan bueno es lo suficientemente bueno?
El error de reproyección es el número de título, pero no toda la historia.
- ** Formación en políticas de RGB:** 0,5 a 1,0 px está bien. Las políticas son algo tolerantes a los pequeños errores intrínsecos, especialmente si se entrenan y se despliegan con la misma calibración.
- ** Profundidad de estereo o SLAM:** inferior a 0,3 px. Compuestos de error externo a través de la triangulación.
- Manipulamiento de ojos de mano: menos de 0,5 px en el interior y menos de 2 mm en el exterior del factor de cámara a la extremidad.
Inmersión profunda: desencadenantes de recalibración
Un G1 no necesita una recalibración semanal, pero algunos eventos lo justifican: (1) cualquier impacto físico en la cabeza o montaje de la cámara, (2) el intercambio de una cámara, (3) la deriva térmica en un nuevo sitio de despliegue (laboratorio frío al suelo de producción caliente), y (4) si se ven errores de re-proyección creciendo durante semanas de uso. Automatice una rápida verificación de la cordura de ChArUco como parte de su mantenimiento semanal
Profundidad: integración con la formación política
Una vez que se guarde la calibración YAML, cablearla en su pila aguas abajo en tres lugares: (1) la tubería de grabación guarda la calibración junto a cada episodio para que pueda rectificarlo más tarde si es necesario, (2) la preprocesamiento de políticas opcionalmente no desvía o cultiva según lo intrínseco, y (3) la preprocesamiento de tiempo de inferencia utiliza los mismos parámetros como la formación. Las discrepancias entre la formación y el preprocesamiento de la inferencia son la causa raíz más común de los fallos de "trabajo en portátil, fracaso en robot".
Preguntas frecuentes
** ¿Puedo omitir la calibración si estoy haciendo solo teleop? ** Sí, teleop no requiere calibración. Pero pierdes la capacidad de entrenar una política de pixel-to-action más tarde en los datos grabados.
¿Cuánto tiempo es válida una calibración? Meses, sin impacto físico en la cabeza.
¿La calibración de G1 URDF es lo suficientemente precisa como para salir de la caja? Por lo general, dentro de unos pocos milímetros
¿Qué hay de las cámaras de ojo de pez? Utilice los módulos







