GR00T N1 + Unitree G1: kiến trúc WBC+VLA decoupled từ 6Hz đến 500Hz
Đây là bài 1 trong series GR00T N1 + Unitree G1. Series này hướng dẫn từng bước từ thu data đến deploy working whole-body VLA policy trên G1, với G1 là ví dụ cụ thể nhưng cấu trúc adapt được cho bất kỳ humanoid nào có URDF.
Bài này giải thích tại sao kiến trúc phải decoupled, và các tần số khác nhau có nghĩa gì trong thực tế.
Vấn đề cốt lõi: inference 150ms vs control 5ms
Mọi thiết kế kiến trúc trong stack này đều xuất phát từ một thực tế không thể thay đổi:
GR00T N1 inference: ~150ms → ~6 Hz
GEAR upper body ctrl: 20ms → 50 Hz
SONIC loco ctrl: 5ms → 200 Hz
Robot joint servo: 2ms → 500 Hz
Nếu bạn cố chạy end-to-end — VLA output trực tiếp vào joint servos — robot sẽ bị jerk nặng mỗi 150ms và mất balance. Giải pháp là decoupled layers: mỗi layer chạy tốc độ riêng và interpolate.
Ba layer trong GR00T-WBC stack
┌─────────────────────────────────────────┐
│ GR00T N1 (VLA) 6Hz / 150ms │
│ Input: camera × 3 + language │
│ Output: target wrist pose L/R │
│ + gripper width L/R │
└──────────────┬──────────────────────────┘
│ high-level command
┌──────────────▼──────────────────────────┐
│ GEAR (upper body) 50Hz / 20ms │
│ RL-trained arm controller │
│ Input: wrist target + proprioception │
│ Output: arm joint torques │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ SONIC / HOVER (loco) 200Hz / 5ms │
│ MPC + RL whole-body balance │
│ Input: CoM target + terrain │
│ Output: ALL joint commands (30+ DoF) │
└──────────────┬──────────────────────────┘
│
┌──────────────▼──────────────────────────┐
│ Robot servo drivers 500Hz / 2ms │
│ PD controller per joint │
└─────────────────────────────────────────┘
Tại sao chia như vậy?
- VLA không cần biết cách balance — nó chỉ cần biết "tay phải đến đây"
- Locomotion không cần hiểu ngôn ngữ — nó chỉ cần biết CoM phải đặt đâu
- Mỗi layer có domain riêng, debug độc lập, thay thế độc lập
GR00T N1: model architecture
Repo: NVIDIA/Isaac-GR00T
Input:
- Left wrist camera RGB (224×224)
- Right wrist camera RGB (224×224)
- Head camera RGB (224×224) [optional]
- Language instruction (tokenized)
Backbone:
- Eagle2 vision encoder (NVIDIA, 300M params)
- Llama-3 language model (adapted)
- Fusion: cross-attention layers
Action head:
- Flow-matching diffusion
- Predicts action chunk (T=16 steps ahead)
- Output per step: Δ end-effector pose L/R + gripper binary
Parameters: ~2B total
Inference: ~150ms on RTX 4090
Action chunking: GR00T N1 không predict 1 action — nó predict chunk 16 bước tới. Robot thực thi chunk đó trong khi N1 inference bước tiếp. Đây là cách "smooth" được 6Hz thành cảm giác liên tục.
Unitree G1: joint map
G1 có 29 DoF trong config đầy đủ (với gripper):
Mỗi chân (×2):
hip_yaw, hip_roll, hip_pitch → 3 DoF
knee_pitch → 1 DoF
ankle_pitch, ankle_roll → 2 DoF
= 6 DoF × 2 chân = 12 DoF
Mỗi cánh tay (×2):
shoulder_pitch, shoulder_roll, shoulder_yaw → 3 DoF
elbow_pitch → 1 DoF
wrist_roll, wrist_pitch → 2 DoF
= 6 DoF × 2 tay = 12 DoF
Thân (waist):
waist_yaw → 1 DoF
Gripper (×2):
gripper_left, gripper_right → 2 DoF (nếu có)
Tổng: 12 + 12 + 1 + 2 = 27–29 DoF
GR00T-WBC kiểm soát tất cả 27-29 DoF đồng thời — đó là lý do WBC phức tạp hơn arm-only policy nhiều.
Adapt cho robot khác
Stack này thiết kế modular — bạn có thể thay G1 bằng bất kỳ humanoid nào có full URDF và joint SDK.
Thay robot: 3 bước
Bước 1: Cung cấp URDF
# Cấu trúc thư mục trong GR00T-WBC
groot_wbc/robots/
├── g1/
│ ├── g1.urdf
│ ├── joint_config.yaml ← đây là file cần sửa
│ └── pd_gains.yaml
├── gr1/
└── YOUR_ROBOT/ ← tạo thư mục mới
├── your_robot.urdf
├── joint_config.yaml
└── pd_gains.yaml
Bước 2: Sửa joint_config.yaml
# joint_config.yaml cho robot của bạn
robot_name: "your_robot"
urdf_path: "robots/YOUR_ROBOT/your_robot.urdf"
# Map joint names theo thứ tự URDF của bạn
left_arm_joints:
- "left_shoulder_pitch_joint"
- "left_shoulder_roll_joint"
- "left_shoulder_yaw_joint"
- "left_elbow_pitch_joint"
- "left_wrist_roll_joint"
- "left_wrist_pitch_joint"
right_arm_joints:
- "right_shoulder_pitch_joint"
# ... tương tự
leg_joints:
- "left_hip_yaw_joint"
# ... 12 joint cho 2 chân
# End-effector frames (phải có trong URDF)
left_ee_frame: "left_gripper_link"
right_ee_frame: "right_gripper_link"
Bước 3: Tune PD gains
# pd_gains.yaml — điều chỉnh theo motor specs của robot
joint_gains:
left_shoulder_pitch_joint:
kp: 150.0 # position gain
kd: 10.0 # velocity gain (damping)
left_elbow_pitch_joint:
kp: 80.0
kd: 5.0
# ... mỗi joint có gains riêng
Với G1: gains đã được NVIDIA tune sẵn trong
groot_wbc/robots/g1/pd_gains.yaml. Với robot khác, bắt đầu với gains thấp (kp 50, kd 3) và tăng dần sau khi test trong sim.
Điều kiện cần để chạy được series này
| Thành phần | Minimum | Recommended |
|---|---|---|
| GPU (training) | RTX 4090 (24GB) | A100 40GB |
| GPU (inference) | RTX 3090 (24GB) | RTX 4090 |
| RAM | 32GB | 64GB |
| Storage | 500GB SSD | 2TB NVMe |
| Robot | Unitree G1/H1 (optional cho bài 2-4 nếu dùng sim) | Unitree G1 |
| Sim | Isaac Lab (Isaac Sim 4.x) | Isaac Lab |
Không có G1? Bài 2-4 có thể làm hoàn toàn trong Isaac Sim với G1 URDF. Bài 5 (sim2real) cần robot thật.
Roadmap series
| Bài | Chủ đề |
|---|---|
| Bài 1 (này) | Kiến trúc decoupled, G1 joints, adapt robot |
| Bài 2 | Thu data: Isaac Lab teleop + xr_teleoperate, LeRobot format |
| Bài 3 | Fine-tune GR00T N1: GPU config, training script |
| Bài 4 | Deploy GR00T-WBC: GEAR + SONIC trên G1 |
| Bài 5 | Sim2real + Evaluation: domain rand, humanoid-bench |
Kết
Insight quan trọng nhất từ bài này: decoupled không phải là compromise — đó là engineering đúng. Mixing VLA inference (ML) và joint servo (control) vào một loop duy nhất sẽ cho bạn hệ thống không thể debug và không an toàn. Mỗi layer có responsibility rõ ràng, test độc lập, và fail rõ ràng khi có vấn đề.
Bài tiếp theo: Thu data với Isaac Lab và xr_teleoperate → LeRobot format.
Nguồn tham khảo
- GR00T N1 paper (arxiv:2503.14734)
- GR00T-WBC paper (arxiv:2506.08000)
- NVIDIA/Isaac-GR00T GitHub
- NVlabs/GR00T-WholeBodyControl GitHub
- Unitree G1 URDF