Files
Mujoco_WASM/training_server/mobile_manipulator/bootstrap.py
T
chenlin f3a8a38acd
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
feat: release v1.0.1 CADWorld 网站与 LeKiwi 智能抓放
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
2026-09-24 09:57:41 +08:00

85 lines
3.1 KiB
Python

"""Optional navigation-only behavior-cloning initialization, followed by PPO.
The teacher is used ONLY to collect training data. Export contains the trained MLP,
not a hidden scripted navigation fallback. Later stages never use this initializer.
"""
import math
import mujoco
import numpy as np
import torch
from .env import MobileManipulatorEnv
from .kernel import TASK, navigation_error
def navigation_teacher(state):
_, yaw = navigation_error(state)
x = state[37] - TASK["navigationOffset"][0] - state[0]
y = state[38] - TASK["navigationOffset"][1] - state[1]
action = np.zeros(TASK["actionSize"], dtype=np.float32)
action[0] = 8 * (math.cos(yaw) * x + math.sin(yaw) * y)
action[1] = 8 * (-math.sin(yaw) * x + math.cos(yaw) * y)
action[2] = -4 * yaw
return np.clip(action, -1, 1)
def bootstrap_navigation(agent, package, params, reset_options, seed):
steps = params["navigationBootstrapSteps"]
if not steps:
return
print(f"Navigation BC initialization: {steps} simulated teacher steps, then PPO", flush=True)
env = MobileManipulatorEnv(
package,
stage="navigate",
reset_options=reset_options,
position_jitter=params["positionJitter"],
)
rng = np.random.default_rng(seed)
observations, actions = [], []
def reset():
env.reset()
# Cover heading errors rather than cloning only a straight, zero-yaw path.
yaw = rng.uniform(-0.6, 0.6)
env.data.qpos[env.base_q + 3 : env.base_q + 7] = [
math.cos(yaw / 2),
0,
0,
math.sin(yaw / 2),
]
mujoco.mj_forward(env.model, env.data)
env.hold()
return env.observe().copy()
try:
env.reset(seed=seed)
observation = reset()
for _ in range(steps):
action = navigation_teacher(env.state)
observations.append(observation.copy())
actions.append(action)
# Cover nearby off-teacher states without teleportation or privileged deployment inputs.
noisy = action.copy()
noisy[:3] += rng.normal(0, 0.2, 3)
observation, _, terminated, truncated, _ = env.step(noisy)
if terminated or truncated:
observation = reset()
finally:
env.close()
x = torch.as_tensor(np.asarray(observations), device=agent.device)
y = torch.as_tensor(np.asarray(actions), device=agent.device)
policy = agent.policy
optimizer = torch.optim.Adam(policy.parameters(), lr=1e-3)
for _ in range(30):
for batch in torch.randperm(steps, device=agent.device).split(256):
features = policy.extract_features(x[batch])
predicted = policy.action_net(policy.mlp_extractor.forward_actor(features))
loss = torch.nn.functional.mse_loss(predicted, y[batch])
optimizer.zero_grad()
loss.backward()
torch.nn.utils.clip_grad_norm_(policy.parameters(), 1)
optimizer.step()
print(f"Navigation BC initialization finished; final batch MSE={loss.item():.6g}", flush=True)