feat(simulation): add Worker AI polygon runtime and terrain navigation
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
"""Replay retained sensor evidence against the shipped CMU adapter on Worker.
|
||||
|
||||
Owns exactly one bounded CPU container. Never starts rendering or model GPU jobs.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import http.client
|
||||
import json
|
||||
import subprocess
|
||||
import time
|
||||
from collections import Counter
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from uuid import uuid4
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def main():
|
||||
p = argparse.ArgumentParser()
|
||||
p.add_argument("--adapter", type=Path, required=True)
|
||||
p.add_argument("--run", type=Path, required=True)
|
||||
p.add_argument("--output", type=Path, required=True)
|
||||
p.add_argument("--limit", type=int, default=180)
|
||||
p.add_argument("--terrain", action="store_true")
|
||||
args = p.parse_args()
|
||||
profile = json.loads((args.adapter / "models.worker-006.json").read_text())
|
||||
identity = subprocess.check_output(
|
||||
[
|
||||
"docker",
|
||||
"run",
|
||||
"-d",
|
||||
"--name",
|
||||
"ndc-ai-polygon-navigation-replay-" + uuid4().hex[:8],
|
||||
"--cpus",
|
||||
"3",
|
||||
"--memory",
|
||||
"2g",
|
||||
"--label",
|
||||
"com.nodedc.product=mission-core",
|
||||
"--label",
|
||||
"com.nodedc.stack=ai-polygon-qualification",
|
||||
"--label",
|
||||
"com.nodedc.role=qualification",
|
||||
"--label",
|
||||
"com.nodedc.managed-by=ai-polygon-qualification",
|
||||
"-p",
|
||||
"127.0.0.1:18193:8010",
|
||||
"--mount",
|
||||
f"type=bind,source={args.adapter},target=/adapter,readonly",
|
||||
profile["navigation"]["image"],
|
||||
],
|
||||
text=True,
|
||||
).strip()
|
||||
connection = http.client.HTTPConnection("127.0.0.1", 18193, timeout=3)
|
||||
source = args.run / "camera/decisions.jsonl"
|
||||
rows = [json.loads(line) for line in source.read_text().splitlines()]
|
||||
report = dict(
|
||||
utc=datetime.now(UTC).isoformat(),
|
||||
monotonic=time.monotonic(),
|
||||
input_sha256=hashlib.sha256(source.read_bytes()).hexdigest(),
|
||||
samples=[],
|
||||
)
|
||||
try:
|
||||
deadline = time.monotonic() + 20
|
||||
while True:
|
||||
try:
|
||||
connection.request("GET", "/ready")
|
||||
response = connection.getresponse()
|
||||
response.read()
|
||||
if response.status == 200:
|
||||
break
|
||||
except (OSError, http.client.HTTPException):
|
||||
connection.close()
|
||||
if time.monotonic() > deadline:
|
||||
raise TimeoutError("Replay navigation unavailable")
|
||||
time.sleep(0.2)
|
||||
for row in rows[: args.limit]:
|
||||
if row["goal"] is None:
|
||||
continue
|
||||
observation = np.load(args.run / "camera" / f"{row['frame_id']:08d}.range.npz")
|
||||
payload = dict(
|
||||
points=observation["points"].tolist(),
|
||||
pose=observation["pose"].tolist(),
|
||||
goal=row["goal"],
|
||||
max_speed_mps=0.15,
|
||||
allow_reverse=row.get("mission", {}).get("state") == "reversing",
|
||||
include_terrain=args.terrain,
|
||||
)
|
||||
connection.request("POST", "/plan", body=json.dumps(payload))
|
||||
response = connection.getresponse()
|
||||
result = json.loads(response.read())
|
||||
if response.status != 200:
|
||||
raise RuntimeError(result)
|
||||
report["samples"].append(
|
||||
dict(
|
||||
frame=row["frame_id"],
|
||||
pose=payload["pose"],
|
||||
original=row["decision"],
|
||||
result=result,
|
||||
)
|
||||
)
|
||||
time.sleep(0.18)
|
||||
finally:
|
||||
connection.close()
|
||||
subprocess.run(["docker", "rm", "-f", identity], check=True, capture_output=True)
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(json.dumps(report, indent=2), encoding="utf-8")
|
||||
failures = Counter(
|
||||
v["result"].get("diagnostic", {}).get("failure", v["result"]["status"])
|
||||
for v in report["samples"]
|
||||
)
|
||||
blocked = [v for v in report["samples"] if v["result"]["status"] == "blocked"]
|
||||
print(
|
||||
json.dumps(dict(failures=failures, first_blocked=blocked[:1], last=report["samples"][-1:]))
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user