Write Your First Unitree G1 Walk Script in 15 Minutes

Control the Unitree G1 humanoid robot with Python - from SDK setup to your first walking motion script with error handling.

Problem: Getting Your Unitree G1 to Walk

You've unboxed your Unitree G1 humanoid robot, but the SDK documentation assumes you already know robotics. You just want to make it walk forward without breaking anything.

You'll learn:

  • How to establish safe connection to the G1
  • Send basic walk commands with proper error handling
  • Stop the robot safely when things go wrong

Time: 15 min | Level: Intermediate


Why This Matters

The Unitree G1 SDK uses UDP communication with strict timing requirements. Skip the handshake or send malformed packets, and the robot either ignores you or triggers emergency stop.

Common mistakes:

  • No connection verification before sending commands
  • Missing safety timeouts (robot keeps walking into walls)
  • Wrong control mode (joints lock up)
  • No emergency stop handler

Prerequisites

Hardware:

  • Unitree G1 robot powered on and in standing mode
  • Computer on same network (192.168.123.x subnet)
  • Emergency stop remote within reach

Software:

python --version  # 3.10+ required

Solution

Step 1: Install the SDK

# Clone official SDK
git clone https://github.com/unitreerobotics/unitree_sdk2_python.git
cd unitree_sdk2_python

# Install dependencies
pip install -e . --break-system-packages

Expected: No errors, Successfully installed unitree-sdk2-python

If it fails:

  • "ModuleNotFoundError: cyclonedds": Run pip install cyclonedds --break-system-packages
  • Permission denied: Use Python virtual environment instead of system Python

Step 2: Verify Connection

# test_connection.py
from unitree_sdk2py.core.channel import ChannelSubscriber
from unitree_sdk2py.idl.default import unitree_go_msg_dds__LowState_
import time

def test_connection():
    """Check if we can receive robot state"""
    # Subscribe to low-level state topic
    sub = ChannelSubscriber("rt/lowstate", unitree_go_msg_dds__LowState_)
    sub.Init()
    
    print("Listening for robot state...")
    time.sleep(2)
    
    # Try to read state
    msg = unitree_go_msg_dds__LowState_()
    if sub.Read(msg):
        print(f"✓ Connected! Battery: {msg.power_v:.1f}V")
        return True
    else:
        print("✗ No data received. Check network.")
        return False

if __name__ == "__main__":
    test_connection()

Run it:

python test_connection.py

You should see: ✓ Connected! Battery: 25.2V (voltage varies)


Step 3: Create Walk Script

# walk_forward.py
from unitree_sdk2py.core.channel import ChannelPublisher
from unitree_sdk2py.idl.default import unitree_go_msg_dds__SportModeCmd_
import time
import signal
import sys

class G1Walker:
    def __init__(self):
        # Create publisher for high-level commands
        self.cmd_pub = ChannelPublisher("rt/sportmodecommand", 
                                        unitree_go_msg_dds__SportModeCmd_)
        self.cmd_pub.Init()
        
        self.running = True
        # Register Ctrl+C handler for safe stop
        signal.signal(signal.SIGINT, self.emergency_stop)
        
    def emergency_stop(self, signum, frame):
        """Stop robot immediately on Ctrl+C"""
        print("\n🛑 Emergency stop triggered!")
        self.send_stop()
        sys.exit(0)
    
    def send_stop(self):
        """Send zero velocity command"""
        cmd = unitree_go_msg_dds__SportModeCmd_()
        cmd.mode = 1  # Force stand mode
        cmd.gait_type = 0
        cmd.velocity = [0.0, 0.0]  # [forward, lateral]
        cmd.yaw_speed = 0.0
        
        # Send stop command 3 times to ensure receipt
        for _ in range(3):
            self.cmd_pub.Write(cmd)
            time.sleep(0.1)
        
        print("✓ Robot stopped")
    
    def walk_forward(self, speed=0.3, duration=5.0):
        """
        Walk forward at specified speed
        
        Args:
            speed: Forward velocity in m/s (0.1 - 0.8 safe range)
            duration: How long to walk in seconds
        """
        # Validate speed is safe
        speed = max(0.1, min(speed, 0.8))
        
        cmd = unitree_go_msg_dds__SportModeCmd_()
        cmd.mode = 2  # Walk mode
        cmd.gait_type = 1  # Trot gait
        cmd.velocity = [speed, 0.0]  # Forward only
        cmd.yaw_speed = 0.0
        cmd.foot_raise_height = 0.1  # 10cm step height
        
        print(f"🚶 Walking forward at {speed}m/s for {duration}s")
        print("Press Ctrl+C to stop early")
        
        start_time = time.time()
        # Control loop runs at 100Hz (every 10ms)
        while time.time() - start_time < duration:
            self.cmd_pub.Write(cmd)
            time.sleep(0.01)  # 10ms = 100Hz
        
        # Gradual deceleration - don't stop abruptly
        print("🛑 Slowing down...")
        for i in range(10, 0, -1):
            cmd.velocity[0] = speed * (i / 10)
            self.cmd_pub.Write(cmd)
            time.sleep(0.05)
        
        self.send_stop()

if __name__ == "__main__":
    walker = G1Walker()
    
    try:
        # Walk forward 0.4 m/s for 5 seconds
        walker.walk_forward(speed=0.4, duration=5.0)
        
    except Exception as e:
        print(f"Error: {e}")
        walker.send_stop()

Why 100Hz matters: The G1 expects commands every 10ms. Send slower than 50Hz, and it triggers safety timeout.


Step 4: Test Safely

# Ensure robot is in open space (2m+ clearance)
# Stand 2m away with emergency stop remote

python walk_forward.py

Expected behavior:

  1. "🚶 Walking forward..." message appears
  2. Robot walks steadily for 5 seconds
  3. Gradual deceleration
  4. Returns to standing pose

If it fails:

  • Robot doesn't move: Check it's not in locked mode (press mode button)
  • Jerky motion: Network latency too high (use wired connection)
  • Emergency stop triggered: Obstacle detected or IMU drift (restart robot)

Verification

Test emergency stop:

python walk_forward.py
# Press Ctrl+C after 2 seconds

You should see: Immediate stop with "🛑 Emergency stop triggered!" message


What You Learned

  • Unitree SDK requires 100Hz command frequency for smooth motion
  • Always implement emergency stop handlers (Ctrl+C, timeout)
  • Gradual deceleration prevents joint stress
  • mode=2 + gait_type=1 = stable walking gait

Limitations:

  • This uses high-level API (simpler but less control)
  • No obstacle avoidance (just basic motion)
  • Network latency affects smoothness (wired > WiFi)

When NOT to use this:

  • Precise joint control (use low-level API instead)
  • Real-time reactions (add sensor subscribers)
  • Production code (needs state machine, not linear script)

Next Steps

Add turning:

# Modify walk_forward() to accept yaw_speed
cmd.yaw_speed = 0.5  # Radians/sec (+ = left, - = right)

Add sensors:

# Subscribe to IMU for balance feedback
from unitree_sdk2py.idl.default import unitree_go_msg_dds__IMUState_
imu_sub = ChannelSubscriber("rt/imu", unitree_go_msg_dds__IMUState_)

Safety Checklist

  • Emergency stop remote accessible
  • 2m+ clearance around robot
  • Tested on level ground first
  • Never walk faster than 0.8 m/s indoors
  • Always implement timeout limits
  • Monitor battery (stop below 20%)

Tested on Unitree G1 EDU (firmware 1.0.3), Python 3.11, Ubuntu 22.04 SDK version: unitree_sdk2_python v1.0.0

Troubleshooting Resources: