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:
- "🚶 Walking forward..." message appears
- Robot walks steadily for 5 seconds
- Gradual deceleration
- 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:
- Official SDK Docs
- G1 Developer Forum
- Report issues: support@unitree.com