Download scripts/preflight.py from BAAI/PingPongRealWorldRL: direct link, hf CLI and curl.
- Browser
- Download file 11.9 kB
-
https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/scripts/preflight.py
- Command line
-
hf download hf://BAAI/PingPongRealWorldRL/scripts/preflight.py
-
curl -L -o preflight.py https://huggingface.co/BAAI/PingPongRealWorldRL/resolve/main/scripts/preflight.py
11.9 kB
| #!/usr/bin/env python3 | |
| """Offline H2 artifact/mapping/policy/CLoSD preflight; never opens robot topics.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| import sys | |
| import time | |
| import numpy as np | |
| import torch | |
| ROOT = Path(__file__).resolve().parents[1] | |
| if str(ROOT) not in sys.path: | |
| sys.path.insert(0, str(ROOT)) | |
| from runtime.configuration import load_settings # noqa: E402 | |
| from runtime.embodiments import load_embodiment # noqa: E402 | |
| from runtime.h2_contract import ( # noqa: E402 | |
| EXPECTED_HW_TO_POLICY, | |
| EXPECTED_POLICY_TO_HW, | |
| HARDWARE_JOINT_NAMES, | |
| H2_JOINT_MAP_REVISION, | |
| H2Contract, | |
| H2_DOF, | |
| ) | |
| from runtime.h2_shm_bridge import BRIDGE_SIZE, SHM_VERSION # noqa: E402 | |
| from runtime.observation import build_observation, expected_obs_dim # noqa: E402 | |
| from runtime.policy import OnnxPolicy # noqa: E402 | |
| from runtime.provenance import verify_artifacts # noqa: E402 | |
| from runtime.deployment_versions import DEPLOYMENTS # noqa: E402 | |
| from runtime.real_reference import RealReferenceState # noqa: E402 | |
| from runtime.reference import ReferenceGenerator, load_frozen_pose # noqa: E402 | |
| def run(config: Path, *, policy_only: bool, deployment_version: str | None = None) -> dict: | |
| settings = load_settings(config, deployment_version=deployment_version) | |
| verified = verify_artifacts() | |
| spec = load_embodiment("h2") | |
| policy = OnnxPolicy(str(settings.policy_path), device=settings.policy_device) | |
| contract = H2Contract.from_policy(policy, spec.mjcf_path()) | |
| frozen = load_frozen_pose(spec, list(contract.policy_names)) | |
| ready_hw = contract.ready_hw(frozen.joint_pos) | |
| probe_hw = np.arange(H2_DOF, dtype=np.float64) | |
| roundtrip = contract.hw_from_policy(contract.policy_from_hw(probe_hw)) | |
| if not np.array_equal(probe_hw, roundtrip): | |
| raise RuntimeError("H2 mapping round-trip failed") | |
| if tuple(contract.hw_to_policy.tolist()) != EXPECTED_HW_TO_POLICY: | |
| raise RuntimeError("H2 hardware-to-policy mapping tripwire failed") | |
| if tuple(contract.policy_to_hw.tolist()) != EXPECTED_POLICY_TO_HW: | |
| raise RuntimeError("H2 policy-to-hardware mapping tripwire failed") | |
| if settings.hardware_joint_map_revision != H2_JOINT_MAP_REVISION: | |
| raise RuntimeError( | |
| "configured H2 joint-map revision does not match the audited executable: " | |
| f"{settings.hardware_joint_map_revision!r} != {H2_JOINT_MAP_REVISION!r}" | |
| ) | |
| critical_joint_slots = { | |
| 4: ("left_ankle_roll_joint", 14), | |
| 5: ("left_ankle_pitch_joint", 19), | |
| 10: ("right_ankle_roll_joint", 15), | |
| 11: ("right_ankle_pitch_joint", 20), | |
| 12: ("waist_yaw_joint", 2), | |
| 13: ("waist_roll_joint", 5), | |
| 14: ("waist_pitch_joint", 8), | |
| 19: ("left_wrist_roll_joint", 25), | |
| 20: ("left_wrist_pitch_joint", 27), | |
| 21: ("left_wrist_yaw_joint", 29), | |
| 26: ("right_wrist_roll_joint", 26), | |
| 27: ("right_wrist_pitch_joint", 28), | |
| 28: ("right_wrist_yaw_joint", 30), | |
| } | |
| for hardware_id, (joint_name, policy_id) in critical_joint_slots.items(): | |
| if HARDWARE_JOINT_NAMES[hardware_id] != joint_name: | |
| raise RuntimeError( | |
| f"H2 joint-map name tripwire failed at hardware id {hardware_id}: " | |
| f"{HARDWARE_JOINT_NAMES[hardware_id]!r} != {joint_name!r}" | |
| ) | |
| if int(contract.hw_to_policy[hardware_id]) != policy_id: | |
| raise RuntimeError( | |
| f"H2 joint-map policy tripwire failed at hardware id {hardware_id}: " | |
| f"{int(contract.hw_to_policy[hardware_id])} != {policy_id}" | |
| ) | |
| if not np.allclose(ready_hw[29:31], 0.0): | |
| raise RuntimeError("head lock was not applied to official H2 motor ids 29/30") | |
| reference_joint_pos = frozen.joint_pos.copy() | |
| reference_joint_vel = np.zeros(H2_DOF, dtype=np.float64) | |
| reference_pelvis_pos = frozen.pelvis_pos.copy() | |
| reference_pelvis_quat = frozen.pelvis_quat.copy() | |
| generation = None | |
| if not policy_only: | |
| if settings.generator_device == "cuda" and not torch.cuda.is_available(): | |
| raise RuntimeError("full preflight requested CUDA but torch.cuda.is_available() is false") | |
| generator = ReferenceGenerator( | |
| spec, | |
| list(contract.policy_names), | |
| contract.default_policy, | |
| device=settings.generator_device, | |
| sampling_steps=settings.generator_sampling_steps, | |
| ) | |
| reference_state = RealReferenceState( | |
| spec, generator, frozen, landing_xy=settings.landing_xy, | |
| latency_skip_s=settings.active_latency_skip_s, | |
| ) | |
| try: | |
| # Mirror the real runner: warm CUDA kernels, then exercise the | |
| # asynchronous request/result/latency-skip path with no robot I/O. | |
| reference_state.warmup(settings.generator_warmup_steps) | |
| reference_state.update_robot_state( | |
| np.zeros(2), np.array([1.0, 0.0, 0.0, 0.0]), frozen.joint_pos | |
| ) | |
| reference_state.update_external_command( | |
| 1, 0.80, np.array([0.40, 0.0, 1.10]), np.array([-3.0, 0.0, 0.2]), base_y=0.0 | |
| ) | |
| deadline = time.monotonic() + 30.0 | |
| while reference_state.command_id != 1 and time.monotonic() < deadline: | |
| reference_state.step() | |
| time.sleep(0.005) | |
| reference_state.raise_if_failed() | |
| if reference_state.command_id != 1 or reference_state.is_frozen: | |
| raise RuntimeError("asynchronous H2 CLoSD result did not activate before timeout") | |
| arrays = [ | |
| reference_state.ref_joint_pos, | |
| reference_state.ref_joint_vel, | |
| reference_state.ref_pelvis_pos, | |
| reference_state.ref_pelvis_quat, | |
| ] | |
| if not all(np.isfinite(array).all() for array in arrays): | |
| raise RuntimeError("asynchronous H2 CLoSD reference contains NaN/Inf") | |
| phase_values = np.asarray( | |
| [ | |
| reference_state.last_motion_hit_time_s, | |
| reference_state.last_remaining_command_s, | |
| ], | |
| dtype=np.float64, | |
| ) | |
| if not np.isfinite(phase_values).all(): | |
| raise RuntimeError("H2 CLoSD phase alignment diagnostics are non-finite") | |
| phase_frames = int( | |
| round( | |
| ( | |
| reference_state.last_motion_hit_time_s | |
| - reference_state.last_remaining_command_s | |
| ) | |
| * generator.fps | |
| ) | |
| ) | |
| expected_skip = phase_frames if phase_frames >= 1 else 1 | |
| expected_wait = 0 if phase_frames >= 1 else 1 - phase_frames | |
| if reference_state.last_skip_frames != expected_skip: | |
| raise RuntimeError( | |
| "H2 CLoSD phase skip invariant failed: " | |
| f"{reference_state.last_skip_frames} != {expected_skip}" | |
| ) | |
| if reference_state.last_wait_frames != expected_wait: | |
| raise RuntimeError( | |
| "H2 CLoSD phase wait invariant failed: " | |
| f"{reference_state.last_wait_frames} != {expected_wait}" | |
| ) | |
| if reference_state.last_skip_frames < 1: | |
| raise RuntimeError("H2 CLoSD must always discard generated frame zero") | |
| if not np.isclose( | |
| reference_state.last_motion_hit_time_s, | |
| spec.condition_time_range[1], | |
| atol=1.0e-5, | |
| ): | |
| raise RuntimeError( | |
| "the 0.80s preflight command was not clamped to the H2 bundle's " | |
| f"effective hit time {spec.condition_time_range[1]:.3f}s" | |
| ) | |
| reference_joint_pos = reference_state.ref_joint_pos.copy() | |
| reference_joint_vel = reference_state.ref_joint_vel.copy() | |
| reference_pelvis_pos = reference_state.ref_pelvis_pos.copy() | |
| reference_pelvis_quat = reference_state.ref_pelvis_quat.copy() | |
| generation = { | |
| "frames": generator.pred_len, | |
| "clamped": reference_state.last_clamped, | |
| "clamp_delta_m": reference_state.last_clamp_delta_m, | |
| "device": generator.device, | |
| "generation_s": reference_state.last_generation_s, | |
| "latency_skip_frames": reference_state.last_skip_frames, | |
| "skip_frames": reference_state.last_skip_frames, | |
| "wait_frames": reference_state.last_wait_frames, | |
| "motion_hit_s": reference_state.last_motion_hit_time_s, | |
| "remaining_command_s": reference_state.last_remaining_command_s, | |
| "async_path": True, | |
| } | |
| finally: | |
| reference_state.close() | |
| obs = build_observation( | |
| task_command=np.asarray(spec.frozen_command(), dtype=np.float64), | |
| ref_joint_pos=reference_joint_pos, | |
| ref_joint_vel=reference_joint_vel, | |
| root_xy=np.zeros(2), | |
| ref_pelvis_xy=reference_pelvis_pos[:2], | |
| ref_pelvis_quat=reference_pelvis_quat, | |
| pelvis_quat=np.array([1.0, 0.0, 0.0, 0.0]), | |
| heading_quat=np.array([1.0, 0.0, 0.0, 0.0]), | |
| base_ang_vel_body=np.zeros(3), | |
| joint_pos=frozen.joint_pos, | |
| joint_vel=np.zeros(H2_DOF), | |
| default_joint_pos=contract.default_policy, | |
| prev_action=np.zeros(H2_DOF), | |
| noise=False, | |
| ) | |
| if obs.shape != (expected_obs_dim(H2_DOF),) or not np.isfinite(obs).all(): | |
| raise RuntimeError(f"invalid H2 observation: {obs.shape}") | |
| action = np.clip(policy(obs), -10.0, 10.0) | |
| # Exercise the actual learned-policy contract: the clipped action maps to | |
| # a raw virtual PD target. Mechanical position limiting is reserved for | |
| # ready/stop; the bridge performs the latest-state effort projection. | |
| target_hw = contract.learned_raw_hw_targets_from_action(action) | |
| if not np.isfinite(target_hw).all() or not np.allclose(target_hw[29:31], 0.0): | |
| raise RuntimeError("invalid policy-to-H2 target conversion") | |
| return { | |
| "deployment_version": settings.deployment_version, | |
| "policy_path": str(settings.policy_path), | |
| "status": "PASS", | |
| "artifacts_verified": len(verified), | |
| "policy_obs_dim": policy.obs_dim, | |
| "policy_action_dim": policy.act_dim, | |
| "shm_bytes": BRIDGE_SIZE, | |
| "shm_version": SHM_VERSION, | |
| "mode_pr": 0, | |
| "joint_map_revision": H2_JOINT_MAP_REVISION, | |
| "hw_to_policy": contract.hw_to_policy.tolist(), | |
| "policy_to_hw": contract.policy_to_hw.tolist(), | |
| "critical_joint_slots_by_hw_id": { | |
| str(hardware_id): { | |
| "name": joint_name, | |
| "policy_index": policy_id, | |
| } | |
| for hardware_id, (joint_name, policy_id) in critical_joint_slots.items() | |
| }, | |
| "head_target_hw_29_30": target_hw[29:31].tolist(), | |
| "generation": generation, | |
| } | |
| def main() -> None: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--config", type=Path, default=ROOT / "config.yaml") | |
| parser.add_argument("--deployment-version", "--upstream-version", choices=DEPLOYMENTS) | |
| parser.add_argument("--policy-only", action="store_true", help="Skip the native CLoSD generation smoke test.") | |
| parser.add_argument("--json", action="store_true") | |
| args = parser.parse_args() | |
| report = run(args.config, policy_only=args.policy_only, deployment_version=args.deployment_version) | |
| if args.json: | |
| print(json.dumps(report, indent=2, sort_keys=True)) | |
| else: | |
| print("[PREFLIGHT PASS] " + json.dumps(report, sort_keys=True)) | |
| if __name__ == "__main__": | |
| main() | |