-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhumanoid_open_starter.py
More file actions
201 lines (163 loc) · 7.16 KB
/
Copy pathhumanoid_open_starter.py
File metadata and controls
201 lines (163 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#!/usr/bin/env python3
"""
humanoid_open_starter.py
========================
A single-file starter that combines open-source patterns for the three core
areas of humanoid robotics development:
1. Movement & Control – Gymnasium / MuJoCo Humanoid-v4 style loop
2. AI / Policy – simple random + optional Stable-Baselines3 PPO stub
3. Sensor / Observation – observation processing & basic vision-ready hooks
This file is intentionally self-contained and educational.
It is NOT a full production stack. For real work use the projects surveyed:
• LeRobot + GR00T N1.7 (end-to-end VLA + hardware abstraction)
• humanoid-gym (Isaac Gym RL + zero-shot sim2real)
• HoloMotion / ProtoMotions / PHC (whole-body foundation control)
• Pinocchio + Pink (kinematics / IK)
• Berkeley Humanoid Lite / ToddlerBot (low-cost full stacks)
Install minimal dependencies:
pip install gymnasium[mujoco] numpy
Optional (for the PPO path):
pip install stable-baselines3
Run:
python humanoid_open_starter.py
"""
from __future__ import annotations
import time
from typing import Optional, Tuple
import numpy as np
# ---------------------------------------------------------------------------
# 1. Movement & Control (Gymnasium Humanoid-v4 pattern)
# ---------------------------------------------------------------------------
try:
import gymnasium as gym
except ImportError:
raise ImportError(
"Please install gymnasium with MuJoCo support:\n"
" pip install gymnasium[mujoco]"
)
def make_humanoid_env(render: bool = True) -> gym.Env:
"""Create a standard Humanoid-v4 environment (open Gymnasium / MuJoCo)."""
render_mode = "human" if render else None
env = gym.make("Humanoid-v4", render_mode=render_mode)
return env
# ---------------------------------------------------------------------------
# 2. Sensor / Observation handling
# ---------------------------------------------------------------------------
def process_observation(obs: np.ndarray) -> dict:
"""
Minimal observation processing that mirrors the structure used by
LeRobot, humanoid-gym and most modern humanoid stacks.
In a real system this would also include:
- camera images (OpenCV / ZMQ streams)
- proprioception (joint positions / velocities)
- IMU / force-torque
- language instruction embedding (for VLAs like GR00T)
"""
# Humanoid-v4 observation is a flat vector (~376–378 dims).
# We keep it simple and just return a dict that future code can extend.
return {
"proprio": obs.astype(np.float32),
"timestamp": time.time(),
# Placeholder for future vision / language
"image": None,
"language": None,
}
def mock_camera_frame(width: int = 64, height: int = 64) -> np.ndarray:
"""Tiny placeholder that shows where an OpenCV / ZMQ camera would plug in."""
# In real code replace with:
# import cv2
# ret, frame = cap.read()
return np.zeros((height, width, 3), dtype=np.uint8)
# ---------------------------------------------------------------------------
# 3. AI / Policy
# ---------------------------------------------------------------------------
class RandomPolicy:
"""Baseline open-loop random policy (useful for debugging the control loop)."""
def __init__(self, action_space: gym.spaces.Box):
self.action_space = action_space
def select_action(self, obs_dict: dict) -> np.ndarray:
return self.action_space.sample()
def try_load_ppo(env: gym.Env):
"""
Optional: load a Stable-Baselines3 PPO agent if the package is present.
This mirrors the training style used in many humanoid-gym examples.
"""
try:
from stable_baselines3 import PPO
from stable_baselines3.common.vec_env import DummyVecEnv
# For a real run you would train first:
# model = PPO("MlpPolicy", env, verbose=1)
# model.learn(total_timesteps=100_000)
# model.save("humanoid_ppo")
#
# Here we just create an untrained agent so the API is visible.
vec_env = DummyVecEnv([lambda: env])
model = PPO("MlpPolicy", vec_env, verbose=0)
print("[AI] Stable-Baselines3 PPO available – using untrained agent for demo.")
return model
except ImportError:
print("[AI] stable-baselines3 not installed – falling back to RandomPolicy.")
return None
# ---------------------------------------------------------------------------
# Main control loop that ties the three areas together
# ---------------------------------------------------------------------------
def run_humanoid_loop(
max_steps: int = 500,
render: bool = True,
use_ppo_if_available: bool = True,
):
env = make_humanoid_env(render=render)
obs, info = env.reset()
# Policy selection
ppo_model = try_load_ppo(env) if use_ppo_if_available else None
random_policy = RandomPolicy(env.action_space)
print("\n=== Humanoid Open Starter ===")
print("Combining: Movement/Control + AI/Policy + Sensor/Observation")
print("Press Ctrl+C to stop early.\n")
total_reward = 0.0
try:
for step in range(max_steps):
# ---- Sensor / Observation side ----
obs_dict = process_observation(obs)
# (Optional) attach a mock camera frame
# obs_dict["image"] = mock_camera_frame()
# ---- AI / Policy side ----
if ppo_model is not None:
# Stable-Baselines3 style
action, _ = ppo_model.predict(obs, deterministic=False)
else:
action = random_policy.select_action(obs_dict)
# ---- Movement & Control side ----
obs, reward, terminated, truncated, info = env.step(action)
total_reward += reward
if step % 50 == 0:
print(f"Step {step:4d} | reward={reward:7.2f} | total={total_reward:8.1f}")
if terminated or truncated:
print(f"Episode ended at step {step} (terminated={terminated}, truncated={truncated})")
obs, info = env.reset()
total_reward = 0.0
if render:
# Small sleep so the viewer is watchable
time.sleep(0.01)
except KeyboardInterrupt:
print("\nInterrupted by user.")
finally:
env.close()
print("Environment closed. Done.")
# ---------------------------------------------------------------------------
# Entry point
# ---------------------------------------------------------------------------
if __name__ == "__main__":
# Quick start – change these flags as needed
run_humanoid_loop(
max_steps=1000,
render=True, # set False for headless / faster runs
use_ppo_if_available=True, # tries Stable-Baselines3 if installed
)
print(
"\nNext steps (from the open-source survey):\n"
" 1. Replace the policy with a LeRobot / GR00T N1.7 checkpoint\n"
" 2. Move the loop into Isaac Lab or humanoid-gym for parallel training\n"
" 3. Add real camera streams (OpenCV / ZMQ) and proprioception\n"
" 4. Deploy on Unitree G1 / Berkeley Humanoid Lite / ToddlerBot\n"
)