Download runtime/reference.py from BAAI/PingPongRealWorldRL: direct link, hf CLI and curl.
- Browser
- Download file 7.69 kB
-
https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/runtime/reference.py
- Command line
-
hf download hf://BAAI/PingPongRealWorldRL/runtime/reference.py
-
curl -L -o reference.py https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/runtime/reference.py
7.69 kB
| """Online CLoSD reference generation and the frozen ready pose. | |
| ``ReferenceGenerator`` wraps the *training* runtime | |
| (``MotionBricksCLoSDRuntime`` with a native ``*.closd-runtime.pt`` bundle), so | |
| conditioning, clamping, sampling, decoding and FK are byte-for-byte the code | |
| used during RL. ``FrozenPose`` loads the per-robot ready pose that the | |
| training environment blends into whenever a generated clip is exhausted. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass | |
| import numpy as np | |
| import torch | |
| from .embodiments import EmbodimentSpec | |
| from .paths import load_closd_runtime_module | |
| class ReferenceClip: | |
| joint_pos: np.ndarray # (T, N) policy joint order, absolute angles | |
| joint_vel: np.ndarray # (T, N) | |
| pelvis_pos: np.ndarray # (T, 3) env-local (= world for a single env) | |
| pelvis_quat: np.ndarray # (T, 4) wxyz | |
| clamped: bool # condition was clamped to the generator's domain | |
| clamp_delta: float # norm of the clamped position part [m] | |
| raw_condition: np.ndarray # (9,) | |
| used_condition: np.ndarray # (9,) | |
| def length(self) -> int: | |
| return int(self.joint_pos.shape[0]) | |
| class FrozenPose: | |
| joint_pos: np.ndarray # (N,) policy joint order | |
| pelvis_pos: np.ndarray # (3,) env-local | |
| pelvis_quat: np.ndarray # (4,) wxyz | |
| def load_frozen_pose(spec: EmbodimentSpec, policy_joint_names: list[str], frame: int = 0) -> FrozenPose: | |
| """Load ``data/<ROBOT>/frozen_closd_ready_pose_toeout_lowload.npz`` (frame 0, like training).""" | |
| data = np.load(spec.ready_pose_path(), allow_pickle=True) | |
| joint_pos = np.asarray(data["joint_pos"], dtype=np.float64)[frame] | |
| body_pos = np.asarray(data["body_pos_w"], dtype=np.float64)[frame] | |
| body_quat = np.asarray(data["body_quat_w"], dtype=np.float64)[frame] | |
| if "joint_names" in data.files: | |
| file_joints = [str(x) for x in np.asarray(data["joint_names"]).ravel()] | |
| index = [file_joints.index(name) for name in policy_joint_names if name in file_joints] | |
| if len(index) != len(policy_joint_names): | |
| missing = [n for n in policy_joint_names if n not in file_joints] | |
| if missing and len(index) + len(missing) == len(policy_joint_names): | |
| # joints absent from the file (none expected) keep 0.0 | |
| full = np.zeros(len(policy_joint_names)) | |
| for i, name in enumerate(policy_joint_names): | |
| if name in file_joints: | |
| full[i] = joint_pos[file_joints.index(name)] | |
| joint_pos = full | |
| else: | |
| raise ValueError(f"ready pose is missing joints {missing}") | |
| else: | |
| joint_pos = joint_pos[index] | |
| elif joint_pos.shape[0] != len(policy_joint_names): | |
| raise ValueError( | |
| f"ready pose has {joint_pos.shape[0]} joints without names; policy expects {len(policy_joint_names)}" | |
| ) | |
| if "body_names" in data.files: | |
| body_names = [str(x) for x in np.asarray(data["body_names"]).ravel()] | |
| pelvis = body_names.index("pelvis") if "pelvis" in body_names else 0 | |
| else: | |
| pelvis = 0 # legacy G1 file: MuJoCo body order, pelvis first | |
| return FrozenPose(joint_pos=joint_pos, pelvis_pos=body_pos[pelvis].copy(), pelvis_quat=body_quat[pelvis].copy()) | |
| class ReferenceGenerator: | |
| """Generate reference clips with the training runtime and the native bundle.""" | |
| def __init__( | |
| self, | |
| spec: EmbodimentSpec, | |
| policy_joint_names: list[str], | |
| default_joint_pos: np.ndarray, | |
| device: str | None = None, | |
| sampling_steps: int | None = None, | |
| ): | |
| self.spec = spec | |
| self.device = device or ("cuda" if torch.cuda.is_available() else "cpu") | |
| runtime_module = load_closd_runtime_module() | |
| self.runtime = runtime_module.MotionBricksCLoSDRuntime( | |
| str(spec.bundle_path()), | |
| humanoid_xml=str(spec.mjcf_path()), | |
| device=self.device, | |
| sampling_steps=sampling_steps, | |
| fps=spec.closd_fps, | |
| condition_clamp_enabled=True, | |
| condition_time_range=spec.condition_time_range, | |
| condition_lateral_range=spec.condition_lateral_range, | |
| condition_forward_range=spec.condition_forward_range, | |
| condition_height_range=spec.condition_height_range, | |
| robot_joint_names=list(policy_joint_names), | |
| robot_default_joint_pos=np.asarray(default_joint_pos, dtype=np.float32), | |
| reference_body_names=list(spec.reference_body_names), | |
| ) | |
| self.policy_joint_names = list(policy_joint_names) | |
| self.num_joints = len(policy_joint_names) | |
| # indices (into the policy joint vector) of the joints the model generates, in model order | |
| self.model_joint_index = np.asarray(self.runtime.isaaclab_to_mujoco, dtype=np.int64) | |
| self.context_len = int(getattr(self.runtime, "context_len", 0)) | |
| self.history_len = max(1, self.context_len) | |
| self.pred_len = int(self.runtime.pred_len) | |
| self.fps = float(self.runtime.fps) | |
| self.pelvis_index = list(spec.reference_body_names).index("pelvis") | |
| self.qpos_dim = 7 + len(self.model_joint_index) | |
| def prefix_frame(self, pelvis_pos_local: np.ndarray, pelvis_quat: np.ndarray, joint_pos_policy: np.ndarray) -> np.ndarray: | |
| """One prefix qpos frame: ``[root xyz, root wxyz, model joints]`` (training ``_current_robot_qpos_local``).""" | |
| return np.concatenate( | |
| [np.asarray(pelvis_pos_local, dtype=np.float32), np.asarray(pelvis_quat, dtype=np.float32), | |
| np.asarray(joint_pos_policy, dtype=np.float32)[self.model_joint_index]] | |
| ) | |
| def generate(self, command_local: np.ndarray, prefix_history: np.ndarray, played_frames: int) -> ReferenceClip: | |
| """Generate one clip. | |
| ``command_local``: 9-vector ``[1, hit_time, hit_x, hit_y, hit_z, 0, 0, 0, 0]`` (env-local). | |
| ``prefix_history``: ``(history_len, 7 + n_model_joints)`` robot qpos frames. | |
| ``played_frames``: frames that will actually be played (``round(next_resample_time * fps)``). | |
| """ | |
| played = int(np.clip(played_frames, 1, self.pred_len)) | |
| cmd = torch.as_tensor(np.asarray(command_local, dtype=np.float32).reshape(1, 9), device=self.device) | |
| prefix = torch.as_tensor(np.asarray(prefix_history, dtype=np.float32).reshape(1, self.history_len, -1), device=self.device) | |
| played_t = torch.tensor([played], dtype=torch.long, device=self.device) | |
| payload = self.runtime.generate_batch_tensors(cmd, prefix_qpos=prefix, played_frames=played_t) | |
| joint_pos = payload["joint_pos"][0, :played].detach().cpu().numpy().astype(np.float64) | |
| joint_vel = payload["joint_vel"][0, :played].detach().cpu().numpy().astype(np.float64) | |
| body_pos = payload["body_pos_w"][0, :played].detach().cpu().numpy().astype(np.float64) | |
| body_quat = payload["body_quat_w"][0, :played].detach().cpu().numpy().astype(np.float64) | |
| raw = payload["_raw_condition"][0].detach().cpu().numpy().astype(np.float64) | |
| used = payload["_condition"][0].detach().cpu().numpy().astype(np.float64) | |
| delta = used[1:5] - raw[1:5] | |
| return ReferenceClip( | |
| joint_pos=joint_pos, | |
| joint_vel=joint_vel, | |
| pelvis_pos=body_pos[:, self.pelvis_index], | |
| pelvis_quat=body_quat[:, self.pelvis_index], | |
| clamped=bool(np.any(np.abs(delta) > 1e-6)), | |
| clamp_delta=float(np.linalg.norm(delta[1:4])), | |
| raw_condition=raw, | |
| used_condition=used, | |
| ) | |