{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "e1be666f",
   "metadata": {},
   "source": [
    "# MicroDuck 直播 Notebook：梯面攀爬 / 接触课程\n",
    "\n",
    "把任务、策略、ONNX、MuJoCo 和 RDK X5/BPU 验收串成一条可复用流程。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63833942",
   "metadata": {},
   "source": [
    "## 0. 运行说明\n",
    "\n",
    "建议在 `02-可运行代码/microduck-playground-stilts` 的 Python 环境中启动 Jupyter。训练模型和板端 HBM 不随 Git 提交；通过 `MICRODUCK_ONNX`、`RDK_BPU_HBM` 和 `RDK_HOST` 注入。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "9a045a2e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.804089Z",
     "iopub.status.busy": "2026-09-19T08:21:51.803970Z",
     "iopub.status.idle": "2026-09-19T08:21:51.807637Z",
     "shell.execute_reply": "2026-09-19T08:21:51.807400Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "专题目录: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题\n",
      "可运行代码: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/02-可运行代码/microduck-playground-stilts\n",
      "输出目录: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/03-Notebook/outputs\n",
      "Jupyter 工作站: ubuntu Linux x86_64\n",
      "RDK 地址: 192.168.8.128 用户: sunrise\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "import json\n",
    "import os\n",
    "import platform\n",
    "import shlex\n",
    "import socket\n",
    "import subprocess\n",
    "\n",
    "\n",
    "def locate_topic_root():\n",
    "    cwd = Path.cwd().resolve()\n",
    "    for base in (cwd, *cwd.parents):\n",
    "        if (base / \"02-可运行代码\").is_dir() and (base / \"01-任务资料\").is_dir():\n",
    "            return base\n",
    "        group = base / \"16-专题组队学习\"\n",
    "        if group.is_dir():\n",
    "            matches = list(group.glob(\"*/02-可运行代码\"))\n",
    "            if matches:\n",
    "                return matches[0].parent\n",
    "    configured = os.getenv(\"MICRODUCK_TOPIC_ROOT\")\n",
    "    if configured and Path(configured).is_dir():\n",
    "        return Path(configured).resolve()\n",
    "    raise RuntimeError(\"找不到专题目录，请从 03-Notebook 启动 Jupyter，或设置 MICRODUCK_TOPIC_ROOT。\")\n",
    "\n",
    "\n",
    "TOPIC_ROOT = locate_topic_root()\n",
    "PLAYGROUND_ROOT = TOPIC_ROOT / \"02-可运行代码\" / \"microduck-playground-stilts\"\n",
    "OUTPUT_ROOT = TOPIC_ROOT / \"03-Notebook\" / \"outputs\"\n",
    "OUTPUT_ROOT.mkdir(parents=True, exist_ok=True)\n",
    "print(\"专题目录:\", TOPIC_ROOT)\n",
    "print(\"可运行代码:\", PLAYGROUND_ROOT)\n",
    "print(\"输出目录:\", OUTPUT_ROOT)\n",
    "print(\"Jupyter 工作站:\", socket.gethostname(), platform.system(), platform.machine())\n",
    "print(\"RDK 地址:\", os.getenv(\"RDK_HOST\", \"192.168.8.128\"), \"用户: sunrise\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebe7a052",
   "metadata": {},
   "source": [
    "## 1. 模型契约与本地检查\n",
    "\n",
    "目标契约是 actor `obs[1, 61] -> action[1, 14]`。如果本任务没有随专题提交 checkpoint/ONNX，Notebook 会明确显示“模型未提供”，不会用别的任务模型冒充当前任务结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "99aa60b8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.808286Z",
     "iopub.status.busy": "2026-09-19T08:21:51.808225Z",
     "iopub.status.idle": "2026-09-19T08:21:51.810323Z",
     "shell.execute_reply": "2026-09-19T08:21:51.810073Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "任务: Mjlab-Video-Ladder-Footstep-MicroDuck\n",
      "ONNX: 未提供\n",
      "该任务尚未随专题提交任务专属 ONNX；请设置 MICRODUCK_ONNX 后再运行模型检查。\n"
     ]
    }
   ],
   "source": [
    "TASK_ID = 'Mjlab-Video-Ladder-Footstep-MicroDuck'\n",
    "MODEL_HINT = None\n",
    "MODEL_PATH = Path(os.getenv(\"MICRODUCK_ONNX\", \"\")) if os.getenv(\"MICRODUCK_ONNX\") else None\n",
    "if MODEL_PATH is None and MODEL_HINT:\n",
    "    candidate = TOPIC_ROOT / MODEL_HINT\n",
    "    if candidate.exists():\n",
    "        MODEL_PATH = candidate\n",
    "if MODEL_PATH is None and not MODEL_HINT and not TASK_ID:\n",
    "    candidates = sorted(TOPIC_ROOT.glob(\"01-任务资料/**/*.onnx\"))\n",
    "    MODEL_PATH = candidates[0] if candidates else None\n",
    "print(\"任务:\", TASK_ID or \"接口/网页演示\")\n",
    "print(\"ONNX:\", MODEL_PATH if MODEL_PATH else \"未提供\")\n",
    "if TASK_ID and MODEL_PATH is None:\n",
    "    print(\"该任务尚未随专题提交任务专属 ONNX；请设置 MICRODUCK_ONNX 后再运行模型检查。\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "1af4bfea",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.810816Z",
     "iopub.status.busy": "2026-09-19T08:21:51.810767Z",
     "iopub.status.idle": "2026-09-19T08:21:51.813173Z",
     "shell.execute_reply": "2026-09-19T08:21:51.812918Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PASS-model-contract-cell: 模型未提供，已记录目标契约\n"
     ]
    }
   ],
   "source": [
    "def inspect_onnx(path):\n",
    "    try:\n",
    "        import onnx\n",
    "    except ImportError:\n",
    "        print(\"缺少 onnx：请在 microduck-playground 环境中启动 Jupyter。\")\n",
    "        return None\n",
    "    model = onnx.load(str(path))\n",
    "    onnx.checker.check_model(model)\n",
    "    def shape(value):\n",
    "        return [d.dim_value if d.dim_value else (d.dim_param or \"?\") for d in value.type.tensor_type.shape.dim]\n",
    "    result = {\n",
    "        \"inputs\": [(item.name, shape(item)) for item in model.graph.input],\n",
    "        \"outputs\": [(item.name, shape(item)) for item in model.graph.output],\n",
    "        \"nodes\": len(model.graph.node),\n",
    "        \"metadata\": {item.key: item.value for item in model.metadata_props},\n",
    "    }\n",
    "    print(json.dumps(result, ensure_ascii=False, indent=2))\n",
    "    return result\n",
    "\n",
    "contract = inspect_onnx(MODEL_PATH) if MODEL_PATH else None\n",
    "print(\"PASS-model-contract-cell:\", \"已完成检查\" if contract is not None else \"模型未提供，已记录目标契约\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0222a6b8",
   "metadata": {},
   "source": [
    "## 2. ONNX 导出入口\n",
    "\n",
    "训练得到的是策略 checkpoint；导出时要把 actor 和观测归一化一起固化到 ONNX。下面是本任务命令模板。`--video` 会在本机录制仿真回放，完整视频写入 `outputs/`，不提交到 Git。\n",
    "\n",
    "```bash\n",
    "社区已发布 models/climber.onnx 与 models/getup.onnx；本 Notebook 只做契约检查，不从本地 14 级任务导出替代模型\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4af06280",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.813681Z",
     "iopub.status.busy": "2026-09-19T08:21:51.813632Z",
     "iopub.status.idle": "2026-09-19T08:21:51.815186Z",
     "shell.execute_reply": "2026-09-19T08:21:51.814954Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "uv run python scripts/export.py Mjlab-Video-Ladder-Footstep-MicroDuck --checkpoint-file <CHECKPOINT.pt> --onnx-file outputs/policy.onnx --num-envs 1 --video --video-length 250\n",
      "导出前后检查：观测维度、动作顺序、归一化和 action clip。\n"
     ]
    }
   ],
   "source": [
    "EXPORT_COMMAND = \"python scripts/export_onnx.py run_dir=<FASTSAC_RUN_DIR> output=outputs/motrix_ball_balance_latest.onnx opset=11\" if TASK_ID == \"microduck-ball-balance\" else (\"uv run python scripts/export.py \" + (TASK_ID or \"<TASK_ID>\") + \" --checkpoint-file <CHECKPOINT.pt> --onnx-file outputs/policy.onnx --num-envs 1 --video --video-length 250\")\n",
    "print(EXPORT_COMMAND)\n",
    "print(\"导出前后检查：观测维度、动作顺序、归一化和 action clip。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb89890d",
   "metadata": {},
   "source": [
    "## 3. 训练路径说明：从零或从预训练 checkpoint 开始\n",
    "\n",
    "每个 Notebook 都把训练入口和回放入口分开：可以把 `resume=False` 作为从零初始化，也可以把 `resume=True`、任务专属 checkpoint 和对应的 actor/critic/优化器状态作为预训练续训。默认演示视频使用已经验证过的任务模型，不能把它描述成当前单元刚训练出来的模型。\n",
    "\n",
    "这里的“10 个 iteration”是 10 轮采样加策略优化，不是每个动作只训练 10 步；例如 `64 个并行环境 × 24 个控制步 × 10` 才是约 `15360` 条 transition。导航 Notebook 明确不训练，直接接入已有模型；扰动和爬梯等 Notebook 也会标明它们使用的任务专属模型或官方双模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "781c4e9e",
   "metadata": {},
   "source": [
    "## 3. 爬梯模型检查：climber / get-up\n",
    "\n",
    "`climber.onnx` 负责逐级爬梯，`getup.onnx` 负责登桌后的起身。两个模型都使用\n",
    "61 维观测、14 维动作，13 个命令槽保持零值；监督器根据脚部与桌面的接触和根部位置切换策略。\n",
    "\n",
    "本页的 GPU 视频已完成爬梯、登桌与站稳，记录 `handoff_success=true`、`stable_seconds=11.54`。\n",
    "BPU 视频单独记录板端动作推理，当前存档结果为梯面接触。\n",
    "模型来源、环境准备和继续训练步骤见[梯面攀爬教程](../01-任务资料/06-MicroDuck梯面攀爬强化学习导读/README.md#6-爬梯与登桌复现步骤)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "c43d8cbf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.815689Z",
     "iopub.status.busy": "2026-09-19T08:21:51.815643Z",
     "iopub.status.idle": "2026-09-19T08:21:51.912482Z",
     "shell.execute_reply": "2026-09-19T08:21:51.912147Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "社区爬梯 artifact: /home/ubuntu/microduck-climb-artifacts\n",
      "climber: /home/ubuntu/microduck-climb-artifacts/models/climber.onnx\n",
      "get-up: /home/ubuntu/microduck-climb-artifacts/models/getup.onnx\n",
      "检查社区模型: climber.onnx\n",
      "{\n",
      "  \"inputs\": [\n",
      "    [\n",
      "      \"obs\",\n",
      "      [\n",
      "        1,\n",
      "        61\n",
      "      ]\n",
      "    ]\n",
      "  ],\n",
      "  \"outputs\": [\n",
      "    [\n",
      "      \"actions\",\n",
      "      [\n",
      "        1,\n",
      "        14\n",
      "      ]\n",
      "    ]\n",
      "  ],\n",
      "  \"nodes\": 9,\n",
      "  \"metadata\": {\n",
      "    \"run_path\": \"/scratch/floor-desk/desk-height-gate/baseline/train/final.pt\",\n",
      "    \"joint_names\": \"left_hip_yaw,left_hip_roll,left_hip_pitch,left_knee,left_ankle,neck_pitch,head_pitch,head_yaw,head_roll,right_hip_yaw,right_hip_roll,right_hip_pitch,right_knee,right_ankle\",\n",
      "    \"joint_stiffness\": \"1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000\",\n",
      "    \"joint_damping\": \"0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000\",\n",
      "    \"default_joint_pos\": \"0.000,-0.087,-0.458,-0.005,0.453,0.349,0.349,0.000,0.000,0.000,0.087,0.458,0.005,-0.453\",\n",
      "    \"command_names\": \"twist\",\n",
      "    \"observation_names\": \"base_ang_vel,projected_gravity,joint_pos,joint_vel,actions,command,head_command,body_command\",\n",
      "    \"action_scale\": \"1.0\"\n",
      "  }\n",
      "}\n",
      "检查社区模型: getup.onnx\n",
      "{\n",
      "  \"inputs\": [\n",
      "    [\n",
      "      \"obs\",\n",
      "      [\n",
      "        1,\n",
      "        61\n",
      "      ]\n",
      "    ]\n",
      "  ],\n",
      "  \"outputs\": [\n",
      "    [\n",
      "      \"actions\",\n",
      "      [\n",
      "        1,\n",
      "        14\n",
      "      ]\n",
      "    ]\n",
      "  ],\n",
      "  \"nodes\": 9,\n",
      "  \"metadata\": {\n",
      "    \"run_path\": \"/scratch/floor-desk/desk-local-getup/pilot2/control-train/final.pt\",\n",
      "    \"joint_names\": \"left_hip_yaw,left_hip_roll,left_hip_pitch,left_knee,left_ankle,neck_pitch,head_pitch,head_yaw,head_roll,right_hip_yaw,right_hip_roll,right_hip_pitch,right_knee,right_ankle\",\n",
      "    \"joint_stiffness\": \"1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000,1.000\",\n",
      "    \"joint_damping\": \"0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000,0.000\",\n",
      "    \"default_joint_pos\": \"0.000,-0.087,-0.458,-0.005,0.453,0.349,0.349,0.000,0.000,0.000,0.087,0.458,0.005,-0.453\",\n",
      "    \"command_names\": \"twist\",\n",
      "    \"observation_names\": \"base_ang_vel,projected_gravity,joint_pos,joint_vel,actions,command,head_command,body_command\",\n",
      "    \"action_scale\": \"1.0\"\n",
      "  }\n",
      "}\n",
      "PASS-community-ladder-models: climber + get-up；板端视频使用专用双模型闭环单元。\n"
     ]
    }
   ],
   "source": [
    "LADDER_ARTIFACT_ROOT = Path(os.getenv(\n",
    "    \"MICRODUCK_LADDER_ARTIFACT_ROOT\",\n",
    "    \"/home/ubuntu/microduck-climb-artifacts\",\n",
    ")).expanduser()\n",
    "CLIMBER_ONNX = LADDER_ARTIFACT_ROOT / \"models\" / \"climber.onnx\"\n",
    "GETUP_ONNX = LADDER_ARTIFACT_ROOT / \"models\" / \"getup.onnx\"\n",
    "print(\"社区爬梯 artifact:\", LADDER_ARTIFACT_ROOT)\n",
    "print(\"climber:\", CLIMBER_ONNX if CLIMBER_ONNX.is_file() else \"未找到\")\n",
    "print(\"get-up:\", GETUP_ONNX if GETUP_ONNX.is_file() else \"未找到\")\n",
    "\n",
    "ladder_models = [p for p in (CLIMBER_ONNX, GETUP_ONNX) if p.is_file()]\n",
    "for ladder_model in ladder_models:\n",
    "    print(\"检查社区模型:\", ladder_model.name)\n",
    "    inspect_onnx(ladder_model)\n",
    "\n",
    "if CLIMBER_ONNX.is_file() and GETUP_ONNX.is_file():\n",
    "    MODEL_PATH = CLIMBER_ONNX\n",
    "    print(\"PASS-community-ladder-models: climber + get-up；板端视频使用专用双模型闭环单元。\")\n",
    "else:\n",
    "    print(\"未找到完整的社区 climber/get-up 模型；未使用 walking checkpoint 替代。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec221463",
   "metadata": {},
   "source": [
    "## 4. 本地 ONNX 基准推理\n",
    "\n",
    "这一步只验证 ONNX 图能在本机运行，以及输出形状和数值是否有限；它不是训练效果评测，也不是 BPU 验收。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "fef4cacf",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.913301Z",
     "iopub.status.busy": "2026-09-19T08:21:51.913195Z",
     "iopub.status.idle": "2026-09-19T08:21:51.952928Z",
     "shell.execute_reply": "2026-09-19T08:21:51.952596Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{\n",
      "  \"providers\": [\n",
      "    \"CPUExecutionProvider\"\n",
      "  ],\n",
      "  \"inputs\": [\n",
      "    [\n",
      "      \"obs\",\n",
      "      [\n",
      "        1,\n",
      "        61\n",
      "      ]\n",
      "    ]\n",
      "  ],\n",
      "  \"outputs\": [\n",
      "    [\n",
      "      \"actions\",\n",
      "      [\n",
      "        1,\n",
      "        14\n",
      "      ]\n",
      "    ]\n",
      "  ],\n",
      "  \"finite\": true\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "def onnx_local_smoke(path):\n",
    "    try:\n",
    "        import numpy as np\n",
    "        import onnxruntime as ort\n",
    "    except ImportError as exc:\n",
    "        print(\"缺少本地推理依赖:\", exc)\n",
    "        return None\n",
    "    session = ort.InferenceSession(str(path), providers=[\"CPUExecutionProvider\"])\n",
    "    feeds = {}\n",
    "    for item in session.get_inputs():\n",
    "        shape = [dim if isinstance(dim, int) and dim > 0 else 1 for dim in item.shape]\n",
    "        feeds[item.name] = np.zeros(shape, dtype=np.float32)\n",
    "    outputs = session.run(None, feeds)\n",
    "    info = {\"providers\": session.get_providers(), \"inputs\": [(x.name, x.shape) for x in session.get_inputs()], \"outputs\": [(x.name, x.shape) for x in session.get_outputs()], \"finite\": all(np.isfinite(x).all() for x in outputs)}\n",
    "    print(json.dumps(info, ensure_ascii=False, indent=2, default=str))\n",
    "    return outputs\n",
    "\n",
    "if MODEL_PATH:\n",
    "    local_outputs = onnx_local_smoke(MODEL_PATH)\n",
    "else:\n",
    "    print(\"跳过：尚未提供该任务 ONNX。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "928e8406",
   "metadata": {},
   "source": [
    "## 5. GPU 推理视频\n",
    "\n",
    "GPU 运行 climber/get-up 两个 actor，Ubuntu 负责 MuJoCo 物理和渲染。\n",
    "设置 `MICRODUCK_LADDER_ROOT` 为 desk-climb 目录，`MICRODUCK_GPU_LADDER_CLIMBER` 和\n",
    "`MICRODUCK_GPU_LADDER_GETUP` 为对应 ONNX 路径。视频与报告保存到 `outputs/gpu_videos/`。\n",
    "\n",
    "先检查脚本、环境与模型路径，再运行 24 秒的爬梯、登桌和起身序列。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "63647ae2",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:21:51.953757Z",
     "iopub.status.busy": "2026-09-19T08:21:51.953681Z",
     "iopub.status.idle": "2026-09-19T08:23:52.708342Z",
     "shell.execute_reply": "2026-09-19T08:23:52.708057Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "GPU 推理任务: ladder\n",
      "GPU 模型: (PosixPath('/home/ubuntu/workspaces/microduck_bpu_models/converted/official_ladder_climber.opset11.onnx'), PosixPath('/home/ubuntu/workspaces/microduck_bpu_models/converted/official_ladder_getup.opset11.onnx'))\n",
      "开始生成 GPU 推理视频。\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "PASS-OFFICIAL-LADDER-PAIR-VIDEO: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/03-Notebook/outputs/gpu_videos/ladder_gpu_latest.mp4\n",
      "PASS-OFFICIAL-LADDER-PAIR-REPORT: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/03-Notebook/outputs/gpu_videos/ladder_gpu_latest.json\n",
      "PASS-GPU-VIDEO: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/03-Notebook/outputs/gpu_videos/ladder_gpu_latest.mp4\n",
      "{'task': 'ladder-official-policy-pair', 'task_id': 'Mjlab-FloorDeskBlind-MicroDuck', 'backend': 'GPU ONNX via Torch CUDA', 'policy_device': 'GPU', 'bpu_host': '192.168.8.128', 'climber_port': 8875, 'getup_port': 8876, 'climber_hbm': None, 'getup_hbm': None, 'climber_hbm_sha256': None, 'getup_hbm_sha256': None, 'climber_onnx': '/home/ubuntu/workspaces/microduck_bpu_models/converted/official_ladder_climber.opset11.onnx', 'getup_onnx': '/home/ubuntu/workspaces/microduck_bpu_models/converted/official_ladder_getup.opset11.onnx', 'trace_output': None, 'official_onnx_contract': {'observation_dim': 61, 'action_dim': 14, 'command_slots_zero': True}, 'runtime_contract': {'climber_filter': 'none', 'getup_filter_alpha_head': 0.5, 'getup_filter_alpha_legs': 0.7, 'getup_kp_ratio': 0.8}, 'steps': 1200, 'num_envs': 64, 'record_env': 17, 'nominal_video_seconds': 24.0, 'switch_events': [{'step': 575, 'seconds': 11.5, 'feet_on_desktop': [False, True], 'root_ladder_relative': [0.5072607398033142, 0.009490810334682465, 0.7280181050300598], 'inside_desktop': True}], 'termination_steps': [569, 570, 571, 572, 573, 574, 575, 576], 'termination_terms': [{'step': 569, 'terms': ['fallen']}, {'step': 570, 'terms': ['fallen']}, {'step': 571, 'terms': ['bad_orientation', 'fallen']}, {'step': 572, 'terms': ['bad_orientation', 'fallen']}, {'step': 573, 'terms': ['bad_orientation', 'fallen']}, {'step': 574, 'terms': ['bad_orientation', 'fallen']}, {'step': 575, 'terms': ['bad_orientation', 'fallen']}, {'step': 576, 'terms': ['bad_orientation', 'fallen']}], 'stable_start_step': 624, 'max_stable_frames': 577, 'stable_seconds': 11.540000000000001, 'handoff_success': True, 'stable_trace': [{'step': 576, 'standing': False, 'eligible': False, 'consecutive_frames': 0, 'gravity_z': -0.15493124723434448, 'linear_speed': 0.41272738575935364, 'angular_speed': 5.6028008460998535, 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5110964179039001, 0.008893810212612152, 0.7363682985305786], 'inside_desktop': True}, {'step': 601, 'standing': False, 'eligible': True, 'consecutive_frames': 0, 'gravity_z': -0.8048996329307556, 'linear_speed': 0.3694978952407837, 'angular_speed': 2.6242947578430176, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5503403544425964, 0.0776108130812645, 0.7624103426933289], 'inside_desktop': True}, {'step': 626, 'standing': True, 'eligible': True, 'consecutive_frames': 3, 'gravity_z': -0.9995108246803284, 'linear_speed': 0.03993793949484825, 'angular_speed': 1.0219252109527588, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.574328601360321, 0.06477006524801254, 0.7749777436256409], 'inside_desktop': True}, {'step': 651, 'standing': True, 'eligible': True, 'consecutive_frames': 28, 'gravity_z': -0.9998524785041809, 'linear_speed': 0.013266641646623611, 'angular_speed': 0.15525540709495544, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5775482058525085, 0.0651291236281395, 0.7756972312927246], 'inside_desktop': True}, {'step': 676, 'standing': True, 'eligible': True, 'consecutive_frames': 53, 'gravity_z': -0.9998827576637268, 'linear_speed': 0.002338631311431527, 'angular_speed': 0.014392845332622528, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5785228610038757, 0.06527551263570786, 0.7760127186775208], 'inside_desktop': True}, {'step': 701, 'standing': True, 'eligible': True, 'consecutive_frames': 78, 'gravity_z': -0.9998686909675598, 'linear_speed': 0.003975661937147379, 'angular_speed': 0.028599198907613754, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5786170363426208, 0.0651305541396141, 0.7760841250419617], 'inside_desktop': True}, {'step': 726, 'standing': True, 'eligible': True, 'consecutive_frames': 103, 'gravity_z': -0.9998804926872253, 'linear_speed': 0.0013547317357733846, 'angular_speed': 0.007832815870642662, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5788628458976746, 0.06504186242818832, 0.7761501669883728], 'inside_desktop': True}, {'step': 751, 'standing': True, 'eligible': True, 'consecutive_frames': 128, 'gravity_z': -0.9998806118965149, 'linear_speed': 0.0008876420906744897, 'angular_speed': 0.01919175311923027, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5790347456932068, 0.06494554132223129, 0.7762283086776733], 'inside_desktop': True}, {'step': 776, 'standing': True, 'eligible': True, 'consecutive_frames': 153, 'gravity_z': -0.9998880624771118, 'linear_speed': 0.002918081358075142, 'angular_speed': 0.02802935615181923, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5791937708854675, 0.06477387994527817, 0.7763177156448364], 'inside_desktop': True}, {'step': 801, 'standing': True, 'eligible': True, 'consecutive_frames': 178, 'gravity_z': -0.999868631362915, 'linear_speed': 0.004036320839077234, 'angular_speed': 0.03300287947058678, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5792335867881775, 0.06458695977926254, 0.7763510942459106], 'inside_desktop': True}, {'step': 826, 'standing': True, 'eligible': True, 'consecutive_frames': 203, 'gravity_z': -0.9997828006744385, 'linear_speed': 6.187070539453998e-05, 'angular_speed': 0.05681483447551727, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5792190432548523, 0.06462939828634262, 0.77638179063797], 'inside_desktop': True}, {'step': 851, 'standing': True, 'eligible': True, 'consecutive_frames': 228, 'gravity_z': -0.9997751712799072, 'linear_speed': 0.0002871440665330738, 'angular_speed': 0.0650053545832634, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5795785784721375, 0.06462987512350082, 0.7764571309089661], 'inside_desktop': True}, {'step': 876, 'standing': True, 'eligible': True, 'consecutive_frames': 253, 'gravity_z': -0.9997461438179016, 'linear_speed': 0.001824887003749609, 'angular_speed': 0.05413341522216797, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5797020792961121, 0.06465848535299301, 0.7765130996704102], 'inside_desktop': True}, {'step': 901, 'standing': True, 'eligible': True, 'consecutive_frames': 278, 'gravity_z': -0.9997640252113342, 'linear_speed': 0.0036788443103432655, 'angular_speed': 0.002877963939681649, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5800277590751648, 0.06469186395406723, 0.776578962802887], 'inside_desktop': True}, {'step': 926, 'standing': True, 'eligible': True, 'consecutive_frames': 303, 'gravity_z': -0.9997559189796448, 'linear_speed': 0.0016460574697703123, 'angular_speed': 0.01984294131398201, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5800065398216248, 0.06471332162618637, 0.7766239047050476], 'inside_desktop': True}, {'step': 951, 'standing': True, 'eligible': True, 'consecutive_frames': 328, 'gravity_z': -0.999798059463501, 'linear_speed': 0.0009834786178544164, 'angular_speed': 0.06695786118507385, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5803155303001404, 0.06481107324361801, 0.7766703367233276], 'inside_desktop': True}, {'step': 976, 'standing': True, 'eligible': True, 'consecutive_frames': 353, 'gravity_z': -0.9997984170913696, 'linear_speed': 0.0004615448706317693, 'angular_speed': 0.012429248541593552, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5803598761558533, 0.06484874337911606, 0.7767193913459778], 'inside_desktop': True}, {'step': 1001, 'standing': True, 'eligible': True, 'consecutive_frames': 378, 'gravity_z': -0.9998342394828796, 'linear_speed': 0.001705230912193656, 'angular_speed': 0.0324225053191185, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5806438326835632, 0.06483825296163559, 0.7767575979232788], 'inside_desktop': True}, {'step': 1026, 'standing': True, 'eligible': True, 'consecutive_frames': 403, 'gravity_z': -0.99983149766922, 'linear_speed': 0.000669811968691647, 'angular_speed': 0.013362021185457706, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807086825370789, 0.06479533761739731, 0.7767845988273621], 'inside_desktop': True}, {'step': 1051, 'standing': True, 'eligible': True, 'consecutive_frames': 428, 'gravity_z': -0.9998422265052795, 'linear_speed': 0.0014027525903657079, 'angular_speed': 0.052303824573755264, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.580819308757782, 0.06465800851583481, 0.7768238186836243], 'inside_desktop': True}, {'step': 1076, 'standing': True, 'eligible': True, 'consecutive_frames': 453, 'gravity_z': -0.9998496770858765, 'linear_speed': 0.0032579004764556885, 'angular_speed': 0.03221122547984123, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807525515556335, 0.06461461633443832, 0.776845395565033], 'inside_desktop': True}, {'step': 1101, 'standing': True, 'eligible': True, 'consecutive_frames': 478, 'gravity_z': -0.999853253364563, 'linear_speed': 0.001933555817231536, 'angular_speed': 0.01712367683649063, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5808951258659363, 0.06457646936178207, 0.7768455743789673], 'inside_desktop': True}, {'step': 1126, 'standing': True, 'eligible': True, 'consecutive_frames': 503, 'gravity_z': -0.9998330473899841, 'linear_speed': 0.0018369018798694015, 'angular_speed': 0.019642548635601997, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807759165763855, 0.06438811868429184, 0.7768673896789551], 'inside_desktop': True}, {'step': 1151, 'standing': True, 'eligible': True, 'consecutive_frames': 528, 'gravity_z': -0.9998359680175781, 'linear_speed': 0.0021581966429948807, 'angular_speed': 0.017641572281718254, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807713866233826, 0.0643218383193016, 0.7768728733062744], 'inside_desktop': True}, {'step': 1176, 'standing': True, 'eligible': True, 'consecutive_frames': 553, 'gravity_z': -0.999843180179596, 'linear_speed': 0.002122962847352028, 'angular_speed': 0.01911747455596924, 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5808832049369812, 0.06427129358053207, 0.7768670916557312], 'inside_desktop': True}], 'contact_trace': [{'step': 0, 'recovering': False, 'root': [3.0577876567840576, -4.997474670410156, 0.11938111484050751], 'feet_on_desktop': [False, False], 'root_ladder_relative': [-0.034239090979099274, 0.0027650222182273865, 0.12199999392032623], 'inside_desktop': False}, {'step': 25, 'recovering': False, 'root': [3.145066499710083, -4.996091842651367, 0.14653100073337555], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.052189551293849945, 0.00684579461812973, 0.14679723978042603], 'inside_desktop': False}, {'step': 50, 'recovering': False, 'root': [3.158827781677246, -4.9914326667785645, 0.16427861154079437], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.06546469777822495, 0.008241020143032074, 0.16401083767414093], 'inside_desktop': False}, {'step': 75, 'recovering': False, 'root': [3.1809892654418945, -4.9960832595825195, 0.19608646631240845], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.08890148252248764, 0.004409633576869965, 0.19563552737236023], 'inside_desktop': False}, {'step': 100, 'recovering': False, 'root': [3.175248622894287, -4.98992919921875, 0.21639513969421387], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.0810682401061058, 0.011242710053920746, 0.21418531239032745], 'inside_desktop': False}, {'step': 125, 'recovering': False, 'root': [3.2063510417938232, -4.993631839752197, 0.24727095663547516], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.1144237145781517, 0.0071023330092430115, 0.24728037416934967], 'inside_desktop': False}, {'step': 150, 'recovering': False, 'root': [3.198471784591675, -4.989050388336182, 0.27454081177711487], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.10784312337636948, 0.010897956788539886, 0.27151426672935486], 'inside_desktop': False}, {'step': 175, 'recovering': False, 'root': [3.229909896850586, -4.985351085662842, 0.3041808605194092], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.1408044993877411, 0.012595497071743011, 0.30224135518074036], 'inside_desktop': False}, {'step': 200, 'recovering': False, 'root': [3.2263643741607666, -4.9877800941467285, 0.33123579621315], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.13318607211112976, 0.01203521341085434, 0.3300606608390808], 'inside_desktop': False}, {'step': 225, 'recovering': False, 'root': [3.248246192932129, -4.979587078094482, 0.3597211241722107], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.15806743502616882, 0.020722709596157074, 0.3596862256526947], 'inside_desktop': False}, {'step': 250, 'recovering': False, 'root': [3.2740979194641113, -4.988430500030518, 0.39389359951019287], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.1766192615032196, 0.012835346162319183, 0.39147648215293884], 'inside_desktop': False}, {'step': 275, 'recovering': False, 'root': [3.274188756942749, -4.980527877807617, 0.411914199590683], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.18221184611320496, 0.020164333283901215, 0.4117431044578552], 'inside_desktop': False}, {'step': 300, 'recovering': False, 'root': [3.316723585128784, -4.988149642944336, 0.45088285207748413], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.22473689913749695, 0.01201852411031723, 0.4502352178096771], 'inside_desktop': False}, {'step': 325, 'recovering': False, 'root': [3.305427074432373, -4.9806742668151855, 0.4694596827030182], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.2115153968334198, 0.020024143159389496, 0.4669016897678375], 'inside_desktop': False}, {'step': 350, 'recovering': False, 'root': [3.3420233726501465, -4.987231254577637, 0.5041190385818481], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.25025007128715515, 0.013261161744594574, 0.5038790106773376], 'inside_desktop': False}, {'step': 375, 'recovering': False, 'root': [3.3348052501678467, -4.980576992034912, 0.5256460905075073], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.2436332404613495, 0.01883920282125473, 0.5252379179000854], 'inside_desktop': False}, {'step': 400, 'recovering': False, 'root': [3.369558095932007, -4.984242916107178, 0.5598766207695007], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.27892062067985535, 0.01357349008321762, 0.5576003193855286], 'inside_desktop': False}, {'step': 425, 'recovering': False, 'root': [3.363133668899536, -4.981700897216797, 0.5900340676307678], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.27056023478507996, 0.01825030893087387, 0.5891014337539673], 'inside_desktop': False}, {'step': 450, 'recovering': False, 'root': [3.3883869647979736, -4.976043224334717, 0.6188172698020935], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.29846903681755066, 0.02430614084005356, 0.6181809306144714], 'inside_desktop': False}, {'step': 475, 'recovering': False, 'root': [3.4117469787597656, -4.982131004333496, 0.6523953080177307], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.31451675295829773, 0.018825851380825043, 0.6500871181488037], 'inside_desktop': False}, {'step': 500, 'recovering': False, 'root': [3.4142580032348633, -4.974502086639404, 0.669813334941864], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.32239553332328796, 0.026108108460903168, 0.669678270816803], 'inside_desktop': False}, {'step': 525, 'recovering': False, 'root': [3.465203285217285, -4.984477519989014, 0.7087022066116333], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.3651878535747528, 0.01732095330953598, 0.7085472941398621], 'inside_desktop': False}, {'step': 550, 'recovering': False, 'root': [3.4788529872894287, -4.976877689361572, 0.7351073622703552], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.38356491923332214, 0.023870788514614105, 0.7332829236984253], 'inside_desktop': False}, {'step': 575, 'recovering': True, 'root': [3.6030330657958984, -4.991332054138184, 0.7363682985305786], 'feet_on_desktop': [False, True], 'root_ladder_relative': [0.5072607398033142, 0.009490810334682465, 0.7280181050300598], 'inside_desktop': True}, {'step': 600, 'recovering': True, 'root': [3.6422770023345947, -4.922615051269531, 0.7624103426933289], 'feet_on_desktop': [True, False], 'root_ladder_relative': [0.5480379462242126, 0.07096751779317856, 0.7599475979804993], 'inside_desktop': True}, {'step': 625, 'recovering': True, 'root': [3.6662652492523193, -4.935455799102783, 0.7749777436256409], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5736176371574402, 0.06518968194723129, 0.774938702583313], 'inside_desktop': True}, {'step': 650, 'recovering': True, 'root': [3.669484853744507, -4.935096740722656, 0.7756972312927246], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5777716040611267, 0.06505616754293442, 0.7756959199905396], 'inside_desktop': True}, {'step': 675, 'recovering': True, 'root': [3.670459508895874, -4.934950351715088, 0.7760127186775208], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5785271525382996, 0.06525500863790512, 0.7760140895843506], 'inside_desktop': True}, {'step': 700, 'recovering': True, 'root': [3.670553684234619, -4.935095310211182, 0.7760841250419617], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5786239504814148, 0.06517060846090317, 0.7760463953018188], 'inside_desktop': True}, {'step': 725, 'recovering': True, 'root': [3.670799493789673, -4.935184001922607, 0.7761501669883728], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5788339972496033, 0.06505712121725082, 0.776136577129364], 'inside_desktop': True}, {'step': 750, 'recovering': True, 'root': [3.670971393585205, -4.9352803230285645, 0.7762283086776733], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5790061354637146, 0.06493791192770004, 0.7762272357940674], 'inside_desktop': True}, {'step': 775, 'recovering': True, 'root': [3.671130418777466, -4.935451984405518, 0.7763177156448364], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5792085528373718, 0.06473954766988754, 0.7763305306434631], 'inside_desktop': True}, {'step': 800, 'recovering': True, 'root': [3.671170234680176, -4.935638904571533, 0.7763510942459106], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5791582465171814, 0.06462892144918442, 0.7763196229934692], 'inside_desktop': True}, {'step': 825, 'recovering': True, 'root': [3.6711556911468506, -4.935596466064453, 0.77638179063797], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5792335867881775, 0.06463893502950668, 0.7763791680335999], 'inside_desktop': True}, {'step': 850, 'recovering': True, 'root': [3.6715152263641357, -4.935595989227295, 0.7764571309089661], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5796117186546326, 0.06463559716939926, 0.7764540314674377], 'inside_desktop': True}, {'step': 875, 'recovering': True, 'root': [3.6716387271881104, -4.935567378997803, 0.7765130996704102], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5796942114830017, 0.0646570548415184, 0.7765095233917236], 'inside_desktop': True}, {'step': 900, 'recovering': True, 'root': [3.671964406967163, -4.9355340003967285, 0.776578962802887], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5800556540489197, 0.06469710916280746, 0.7765821218490601], 'inside_desktop': True}, {'step': 925, 'recovering': True, 'root': [3.671943187713623, -4.935512542724609, 0.7766239047050476], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5800003409385681, 0.06470759958028793, 0.7766197919845581], 'inside_desktop': True}, {'step': 950, 'recovering': True, 'root': [3.6722521781921387, -4.935414791107178, 0.7766703367233276], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.580324113368988, 0.0648239478468895, 0.7766770124435425], 'inside_desktop': True}, {'step': 975, 'recovering': True, 'root': [3.6722965240478516, -4.93537712097168, 0.7767193913459778], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5803541541099548, 0.0648401603102684, 0.7767194509506226], 'inside_desktop': True}, {'step': 1000, 'recovering': True, 'root': [3.6725804805755615, -4.93538761138916, 0.7767575979232788], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.580647885799408, 0.06484778970479965, 0.7767611742019653], 'inside_desktop': True}, {'step': 1025, 'recovering': True, 'root': [3.672645330429077, -4.935430526733398, 0.7767845988273621], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807027220726013, 0.0648096427321434, 0.7767846584320068], 'inside_desktop': True}, {'step': 1050, 'recovering': True, 'root': [3.6727559566497803, -4.935567855834961, 0.7768238186836243], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5808319449424744, 0.06466563791036606, 0.7768223881721497], 'inside_desktop': True}, {'step': 1075, 'recovering': True, 'root': [3.672689199447632, -4.935611248016357, 0.776845395565033], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.580746591091156, 0.06460412591695786, 0.7768406867980957], 'inside_desktop': True}, {'step': 1100, 'recovering': True, 'root': [3.6728317737579346, -4.935649394989014, 0.7768455743789673], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5809161067008972, 0.06457456201314926, 0.7768526673316956], 'inside_desktop': True}, {'step': 1125, 'recovering': True, 'root': [3.672712564468384, -4.935837745666504, 0.7768673896789551], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807399153709412, 0.06439956277608871, 0.7768751382827759], 'inside_desktop': True}, {'step': 1150, 'recovering': True, 'root': [3.672708034515381, -4.935904026031494, 0.7768728733062744], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5807420611381531, 0.0643514022231102, 0.7768785953521729], 'inside_desktop': True}, {'step': 1175, 'recovering': True, 'root': [3.6728198528289795, -4.935954570770264, 0.7768670916557312], 'feet_on_desktop': [True, True], 'root_ladder_relative': [0.5809165835380554, 0.0642760619521141, 0.7768716216087341], 'inside_desktop': True}], 'mean_climber_round_trip_ms': 0.40168594789144624, 'p95_climber_round_trip_ms': 0.5242721012109535, 'mean_getup_round_trip_ms': 0.4271529551682761, 'p95_getup_round_trip_ms': 0.8007058000657689, 'note': 'Ubuntu runs MuJoCo and the privileged simulator-only foot-desktop handoff detector; the selected environment is controlled by either the RDK X5 HBM pair, the GPU ONNX actor, or the CPU ONNX reference, while inert background environments preserve the official vectorized scene shape.'}\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<a href=\"../01-任务资料/精选视频/assets/notebook-replays/ladder_gpu.gif\"><img src=\"../01-任务资料/精选视频/assets/notebook-replays/ladder_gpu.gif\" alt=\"GPU 推理回放：梯面攀爬\" width=\"640\"></a>"
      ],
      "text/plain": [
       "GIF 预览：../01-任务资料/精选视频/assets/notebook-replays/ladder_gpu.gif；原始 MP4 未嵌入 Notebook，以控制仓库体积。"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import sys\n",
    "\n",
    "GPU_TASK = 'ladder'\n",
    "GPU_VIDEO_STEPS = int(os.getenv(\"MICRODUCK_GPU_VIDEO_STEPS\", \"250\"))\n",
    "GPU_VIDEO_OUTPUT = OUTPUT_ROOT / \"gpu_videos\" / f\"{GPU_TASK}_gpu_latest.mp4\" if GPU_TASK else None\n",
    "GPU_ONNX_DEFAULTS = {\n",
    "    \"basketball\": \"/home/ubuntu/workspaces/microduck_bpu_models/converted/basketball.opset11.onnx\",\n",
    "    \"walking\": \"/home/ubuntu/workspaces/microduck_bpu_models/converted/walking.opset11.onnx\",\n",
    "    \"perturbation\": \"/home/ubuntu/workspaces/microduck_bpu_models/converted/walking.opset11.onnx\",\n",
    "    \"stilt\": \"/home/ubuntu/workspaces/microduck_bpu_models/converted/stilts25.opset11.onnx\",\n",
    "    \"swing\": \"/home/ubuntu/workspaces/microduck_bpu_models/converted/swing.opset11.onnx\",\n",
    "    \"ball_balance\": \"/home/ubuntu/workspaces/microduck_bpu_models/converted/motrix_ball_balance.opset11.onnx\",\n",
    "}\n",
    "GPU_ONNX = Path(os.getenv(\"MICRODUCK_GPU_ONNX\", GPU_ONNX_DEFAULTS.get(GPU_TASK, \"\"))).expanduser() if GPU_TASK else None\n",
    "GPU_LADDER_CLIMBER = Path(os.getenv(\"MICRODUCK_GPU_LADDER_CLIMBER\", \"/home/ubuntu/workspaces/microduck_bpu_models/converted/official_ladder_climber.opset11.onnx\")).expanduser()\n",
    "GPU_LADDER_GETUP = Path(os.getenv(\"MICRODUCK_GPU_LADDER_GETUP\", \"/home/ubuntu/workspaces/microduck_bpu_models/converted/official_ladder_getup.opset11.onnx\")).expanduser()\n",
    "MOTRIX_ROOT = Path(os.getenv(\"MOTRIX_ROOT\", \"/home/ubuntu/workspaces/MotrixLab\")).expanduser() if GPU_TASK == \"ball_balance\" else None\n",
    "MOTRIX_PYTHON = Path(os.getenv(\"MOTRIX_PYTHON\", str(MOTRIX_ROOT / \".venv/bin/python\"))).expanduser() if MOTRIX_ROOT else None\n",
    "MOTRIX_RUNNER = PLAYGROUND_ROOT / \"scripts\" / \"motrix_runner.py\" if GPU_TASK == \"ball_balance\" else None\n",
    "GPU_SCRIPT = PLAYGROUND_ROOT / \"scripts\" / (\"motrix_gpu_inloop_video.py\" if GPU_TASK == \"ball_balance\" else \"gpu_inloop_video.py\")\n",
    "GPU_LADDER_SCRIPT = PLAYGROUND_ROOT / \"scripts\" / \"bpu_official_ladder_pair_video.py\"\n",
    "GPU_LADDER_ROOT = Path(os.getenv(\"MICRODUCK_LADDER_ROOT\", \"/home/ubuntu/workspaces/microduck-playground-official/experiments/desk-climb\")).expanduser()\n",
    "\n",
    "if GPU_TASK == \"ladder\":\n",
    "    gpu_ready = all(path.is_file() for path in (GPU_LADDER_SCRIPT, GPU_LADDER_CLIMBER, GPU_LADDER_GETUP)) and all((GPU_LADDER_ROOT / part).is_dir() for part in (\"source\", \"training\"))\n",
    "    gpu_cmd = [\n",
    "        sys.executable, str(GPU_LADDER_SCRIPT), \"--backend\", \"gpu\",\n",
    "        \"--official-root\", str(GPU_LADDER_ROOT),\n",
    "        \"--climber-onnx\", str(GPU_LADDER_CLIMBER), \"--getup-onnx\", str(GPU_LADDER_GETUP),\n",
    "        \"--output\", str(GPU_VIDEO_OUTPUT), \"--seconds\", \"24\", \"--num-envs\", \"64\", \"--record-env\", \"17\",\n",
    "    ]\n",
    "else:\n",
    "    gpu_ready = GPU_SCRIPT.is_file() and GPU_ONNX is not None and GPU_ONNX.is_file()\n",
    "    gpu_cmd = [sys.executable, str(GPU_SCRIPT)] if GPU_TASK != \"ball_balance\" else [str(MOTRIX_PYTHON), str(MOTRIX_RUNNER), \"video\", str(GPU_SCRIPT)]\n",
    "    if GPU_TASK != \"ball_balance\":\n",
    "        gpu_cmd += [\"--task\", GPU_TASK]\n",
    "    gpu_cmd += [\"--onnx\", str(GPU_ONNX), \"--output\", str(GPU_VIDEO_OUTPUT), \"--steps\", str(GPU_VIDEO_STEPS)]\n",
    "\n",
    "print(\"GPU 推理任务:\", GPU_TASK)\n",
    "print(\"GPU 模型:\", GPU_ONNX if GPU_TASK != \"ladder\" else (GPU_LADDER_CLIMBER, GPU_LADDER_GETUP))\n",
    "if not gpu_ready:\n",
    "    print(\"GPU 回放暂不可运行：请检查任务专属 ONNX、脚本和 Motrix 环境。\")\n",
    "elif GPU_TASK == \"ball_balance\" and (MOTRIX_PYTHON is None or not MOTRIX_PYTHON.is_file()):\n",
    "    print(\"找不到 MotrixLab Python 环境:\", MOTRIX_PYTHON)\n",
    "else:\n",
    "    GPU_VIDEO_OUTPUT.parent.mkdir(parents=True, exist_ok=True)\n",
    "    print(\"开始生成 GPU 推理视频。\")\n",
    "    gpu_result = subprocess.run(gpu_cmd, cwd=PLAYGROUND_ROOT, env=os.environ.copy(), capture_output=True, text=True)\n",
    "    safe_lines = [line for line in (gpu_result.stdout + \"\\n\" + gpu_result.stderr).splitlines() if \"GPU\" in line or \"PASS-\" in line or \"Video\" in line]\n",
    "    print(\"\\n\".join(safe_lines[-20:]))\n",
    "    if gpu_result.returncode != 0 or not GPU_VIDEO_OUTPUT.is_file():\n",
    "        raise RuntimeError(\"GPU 推理视频生成失败，请查看脚本日志。\")\n",
    "    GPU_REPORT = GPU_VIDEO_OUTPUT.with_suffix(\".json\")\n",
    "    print(\"PASS-GPU-VIDEO:\", GPU_VIDEO_OUTPUT)\n",
    "    if GPU_REPORT.is_file():\n",
    "        print(json.loads(GPU_REPORT.read_text(encoding=\"utf-8\")))\n",
    "    from IPython.display import Video, display\n",
    "    display(Video(str(GPU_VIDEO_OUTPUT), embed=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73726750",
   "metadata": {},
   "source": [
    "## 6. RDK X5 BPU 推理视频\n",
    "\n",
    "Ubuntu 运行 MuJoCo 仿真，RDK X5 通过两份任务 HBM 计算动作。板端在线时运行生成新的 MP4 和 JSON；\n",
    "允许缓存时可查看先前保存的结果。检查报告中的 `switch_events`、`handoff_success` 和 `stable_seconds`，\n",
    "分别确认策略交接、完整序列成功和持续站立时间。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "4aa64127",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:23:52.713431Z",
     "iopub.status.busy": "2026-09-19T08:23:52.713368Z",
     "iopub.status.idle": "2026-09-19T08:24:05.107329Z",
     "shell.execute_reply": "2026-09-19T08:24:05.107033Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "BPU 官方双模型: /home/ubuntu/workspaces/microduck_bpu_models/compiled/official_ladder_climber/model_output/official_ladder_climber.bin /home/ubuntu/workspaces/microduck_bpu_models/compiled/official_ladder_getup/model_output/official_ladder_getup.bin\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "|   16  | desk_leg_pose_cost    |    0.0 |\n",
      "|   17  | desk_leg_action_cost  |    0.0 |\n",
      "+-------+-----------------------+--------+\n",
      "\n",
      "[INFO] <NullCurriculumManager> (inactive)\n",
      "[INFO] <MetricsManager> contains 1 active terms.\n",
      "+-------------------------+\n",
      "|   Active Metrics Terms  |\n",
      "+-------+-----------------+\n",
      "| Index | Name            |\n",
      "+-------+-----------------+\n",
      "|   0   | mean_action_acc |\n",
      "+-------+-----------------+\n",
      "\n",
      "[INFO] <NullRecorderManager> (inactive)\n",
      "Module mujoco_warp._src.io 4b387a0 load on device 'cuda:0' took 1.41 ms  (cached)\n",
      "Module _tile_cholesky_factorize__locals__cholesky_factorize_0587d9b8 99b4248 load on device 'cuda:0' took 16.79 ms  (cached)\n",
      "Module _tile_cholesky_solve__locals__cholesky_solve_11830e2e 7d510a5 load on device 'cuda:0' took 16.42 ms  (cached)\n",
      "\n",
      "/home/ubuntu/workspaces/microduck_rl/.venv/lib/python3.12/site-packages/mjlab/entity/entity.py:149: UserWarning: Actuator config matched 14 joint(s) but the same expressions also match 7 site(s): imu, left_foot, head_camera, tof, head_imu, mouth_tip, right_foot. Add a separate config with transmission_type=TransmissionType.SITE if those should be actuated too.\n",
      "  self._add_actuators()\n",
      "Traceback (most recent call last):\n",
      "  File \"/home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/02-可运行代码/microduck-playground-stilts/scripts/bpu_official_ladder_pair_video.py\", line 577, in <module>\n",
      "    main()\n",
      "  File \"/home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/02-可运行代码/microduck-playground-stilts/scripts/bpu_official_ladder_pair_video.py\", line 406, in main\n",
      "    climber = BpuClient(args.bpu_host, args.climber_port)\n",
      "              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/02-可运行代码/microduck-playground-stilts/scripts/bpu_official_ladder_pair_video.py\", line 49, in __init__\n",
      "    self.sock = socket.create_connection((host, port), timeout=15.0)\n",
      "                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
      "  File \"/home/ubuntu/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/socket.py\", line 865, in create_connection\n",
      "    raise exceptions[0]\n",
      "  File \"/home/ubuntu/.local/share/uv/python/cpython-3.12.14-linux-x86_64-gnu/lib/python3.12/socket.py\", line 850, in create_connection\n",
      "    sock.connect(sa)\n",
      "OSError: [Errno 113] No route to host\n",
      "BPU-CACHED-VIDEO: /home/ubuntu/workspaces/microduck-teaching/microduck-topic/16-专题组队学习/05-MicroDuck运动策略与任务开发专题/03-Notebook/outputs/bpu_videos/ladder_official_pair_bpu_latest.mp4\n",
      "说明: 本轮板端不可达，保留此前真实 RDK X5 BPU 双模型视频。\n",
      "{'task': 'ladder-official-policy-pair', 'task_id': 'Mjlab-FloorDeskBlind-MicroDuck', 'backend': 'RDK X5 BPU via hbm_runtime', 'policy_device': 'RDK BPU', 'bpu_host': '192.168.8.128', 'climber_port': 8875, 'getup_port': 8876, 'climber_hbm': '/home/ubuntu/workspaces/microduck_bpu_models/compiled/official_ladder_climber/model_output/official_ladder_climber.bin', 'getup_hbm': '/home/ubuntu/workspaces/microduck_bpu_models/compiled/official_ladder_getup/model_output/official_ladder_getup.bin', 'climber_hbm_sha256': '9e234d73300000e23a1bc299d44a4c40980204268bb5871a2d6d87034d11bcdd', 'getup_hbm_sha256': '225635a174555ed6d1e2bf196de8ccc812d92c41cdaadf1de36fecef40649651', 'climber_onnx': None, 'getup_onnx': None, 'trace_output': None, 'official_onnx_contract': {'observation_dim': 61, 'action_dim': 14, 'command_slots_zero': True}, 'runtime_contract': {'climber_filter': 'none', 'getup_filter_alpha_head': 0.5, 'getup_filter_alpha_legs': 0.7, 'getup_kp_ratio': 0.8}, 'steps': 1200, 'num_envs': 64, 'record_env': 17, 'nominal_video_seconds': 24.0, 'switch_events': [], 'termination_steps': [579, 580, 581, 582, 583, 584, 585, 586, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, 855, 856, 857, 858, 859, 860, 861, 862, 863, 864, 865, 866, 867, 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 887, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908, 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, 927, 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199, 1200], 'termination_terms': [{'step': 579, 'terms': ['fallen']}, {'step': 580, 'terms': ['bad_orientation', 'fallen']}, {'step': 581, 'terms': ['bad_orientation', 'fallen']}, {'step': 582, 'terms': ['bad_orientation', 'fallen']}, {'step': 583, 'terms': ['bad_orientation', 'fallen']}, {'step': 584, 'terms': ['bad_orientation', 'fallen']}, {'step': 585, 'terms': ['bad_orientation', 'fallen']}, {'step': 586, 'terms': ['bad_orientation', 'fallen']}, {'step': 593, 'terms': ['bad_orientation', 'fallen']}, {'step': 594, 'terms': ['bad_orientation', 'fallen']}, {'step': 595, 'terms': ['bad_orientation', 'fallen']}, {'step': 596, 'terms': ['bad_orientation', 'fallen']}, {'step': 597, 'terms': ['bad_orientation', 'fallen']}, {'step': 598, 'terms': ['bad_orientation', 'fallen']}, {'step': 599, 'terms': ['bad_orientation', 'fallen']}, {'step': 600, 'terms': ['bad_orientation', 'fallen']}, {'step': 601, 'terms': ['bad_orientation', 'fallen']}, {'step': 602, 'terms': ['bad_orientation', 'fallen']}, {'step': 603, 'terms': ['bad_orientation', 'fallen']}, {'step': 604, 'terms': ['bad_orientation', 'fallen']}, {'step': 605, 'terms': ['bad_orientation', 'fallen']}, {'step': 606, 'terms': ['bad_orientation', 'fallen']}, {'step': 607, 'terms': ['bad_orientation', 'fallen']}, {'step': 608, 'terms': ['bad_orientation', 'fallen']}, {'step': 609, 'terms': ['bad_orientation', 'fallen']}, {'step': 610, 'terms': ['bad_orientation', 'fallen']}, {'step': 611, 'terms': ['bad_orientation', 'fallen']}, {'step': 612, 'terms': ['bad_orientation', 'fallen']}, {'step': 613, 'terms': ['bad_orientation', 'fallen']}, {'step': 614, 'terms': ['bad_orientation', 'fallen']}, {'step': 615, 'terms': ['bad_orientation', 'fallen']}, {'step': 616, 'terms': ['bad_orientation', 'fallen']}, {'step': 617, 'terms': ['bad_orientation', 'fallen']}, {'step': 618, 'terms': ['bad_orientation', 'fallen']}, {'step': 619, 'terms': ['bad_orientation', 'fallen']}, {'step': 620, 'terms': ['bad_orientation', 'fallen']}, {'step': 621, 'terms': ['bad_orientation', 'fallen']}, {'step': 622, 'terms': ['bad_orientation', 'fallen']}, {'step': 623, 'terms': ['bad_orientation', 'fallen']}, {'step': 624, 'terms': ['bad_orientation', 'fallen']}, {'step': 625, 'terms': ['bad_orientation', 'fallen']}, {'step': 626, 'terms': ['bad_orientation', 'fallen']}, {'step': 627, 'terms': ['bad_orientation', 'fallen']}, {'step': 628, 'terms': ['bad_orientation', 'fallen']}, {'step': 629, 'terms': ['bad_orientation', 'fallen']}, {'step': 630, 'terms': ['bad_orientation', 'fallen']}, {'step': 631, 'terms': ['bad_orientation', 'fallen']}, {'step': 632, 'terms': ['bad_orientation', 'fallen']}, {'step': 633, 'terms': ['bad_orientation', 'fallen']}, {'step': 634, 'terms': ['bad_orientation', 'fallen']}, {'step': 635, 'terms': ['bad_orientation', 'fallen']}, {'step': 636, 'terms': ['bad_orientation', 'fallen']}, {'step': 637, 'terms': ['bad_orientation', 'fallen']}, {'step': 638, 'terms': ['bad_orientation', 'fallen']}, {'step': 639, 'terms': ['bad_orientation', 'fallen']}, {'step': 640, 'terms': ['bad_orientation', 'fallen']}, {'step': 641, 'terms': ['bad_orientation', 'fallen']}, {'step': 642, 'terms': ['bad_orientation', 'fallen']}, {'step': 643, 'terms': ['bad_orientation', 'fallen']}, {'step': 644, 'terms': ['bad_orientation', 'fallen']}, {'step': 645, 'terms': ['bad_orientation', 'fallen']}, {'step': 646, 'terms': ['bad_orientation', 'fallen']}, {'step': 647, 'terms': ['bad_orientation', 'fallen']}, {'step': 648, 'terms': ['bad_orientation', 'fallen']}, {'step': 649, 'terms': ['bad_orientation', 'fallen']}, {'step': 650, 'terms': ['bad_orientation', 'fallen']}, {'step': 651, 'terms': ['bad_orientation', 'fallen']}, {'step': 652, 'terms': ['bad_orientation', 'fallen']}, {'step': 653, 'terms': ['bad_orientation', 'fallen']}, {'step': 654, 'terms': ['bad_orientation', 'fallen']}, {'step': 655, 'terms': ['bad_orientation', 'fallen']}, {'step': 656, 'terms': ['bad_orientation', 'fallen']}, {'step': 657, 'terms': ['bad_orientation', 'fallen']}, {'step': 658, 'terms': ['bad_orientation', 'fallen']}, {'step': 659, 'terms': ['bad_orientation', 'fallen']}, {'step': 660, 'terms': ['bad_orientation', 'fallen']}, {'step': 661, 'terms': ['bad_orientation', 'fallen']}, {'step': 662, 'terms': ['bad_orientation', 'fallen']}, {'step': 663, 'terms': ['bad_orientation', 'fallen']}, {'step': 664, 'terms': ['bad_orientation', 'fallen']}, {'step': 665, 'terms': ['bad_orientation', 'fallen']}, {'step': 666, 'terms': ['bad_orientation', 'fallen']}, {'step': 667, 'terms': ['bad_orientation', 'fallen']}, {'step': 668, 'terms': ['bad_orientation', 'fallen']}, {'step': 669, 'terms': ['bad_orientation', 'fallen']}, {'step': 670, 'terms': ['bad_orientation', 'fallen']}, {'step': 671, 'terms': ['bad_orientation', 'fallen']}, {'step': 672, 'terms': ['bad_orientation', 'fallen']}, {'step': 673, 'terms': ['bad_orientation', 'fallen']}, {'step': 674, 'terms': ['bad_orientation', 'fallen']}, {'step': 675, 'terms': ['bad_orientation', 'fallen']}, {'step': 676, 'terms': ['bad_orientation', 'fallen']}, {'step': 677, 'terms': ['bad_orientation', 'fallen']}, {'step': 678, 'terms': ['bad_orientation', 'fallen']}, {'step': 679, 'terms': ['bad_orientation', 'fallen']}, {'step': 680, 'terms': ['bad_orientation', 'fallen']}, {'step': 681, 'terms': ['bad_orientation', 'fallen']}, {'step': 682, 'terms': ['bad_orientation', 'fallen']}, {'step': 683, 'terms': ['bad_orientation', 'fallen']}, {'step': 684, 'terms': ['bad_orientation', 'fallen']}, {'step': 685, 'terms': ['bad_orientation', 'fallen']}, {'step': 686, 'terms': ['bad_orientation', 'fallen']}, {'step': 687, 'terms': ['bad_orientation', 'fallen']}, {'step': 688, 'terms': ['bad_orientation', 'fallen']}, {'step': 689, 'terms': ['bad_orientation', 'fallen']}, {'step': 690, 'terms': ['bad_orientation', 'fallen']}, {'step': 691, 'terms': ['bad_orientation', 'fallen']}, {'step': 692, 'terms': ['bad_orientation', 'fallen']}, {'step': 693, 'terms': ['bad_orientation', 'fallen']}, {'step': 694, 'terms': ['bad_orientation', 'fallen']}, {'step': 695, 'terms': ['bad_orientation', 'fallen']}, {'step': 696, 'terms': ['bad_orientation', 'fallen']}, {'step': 697, 'terms': ['bad_orientation', 'fallen']}, {'step': 698, 'terms': ['bad_orientation', 'fallen']}, {'step': 699, 'terms': ['bad_orientation', 'fallen']}, {'step': 700, 'terms': ['bad_orientation', 'fallen']}, {'step': 701, 'terms': ['bad_orientation', 'fallen']}, {'step': 702, 'terms': ['bad_orientation', 'fallen']}, {'step': 703, 'terms': ['bad_orientation', 'fallen']}, {'step': 704, 'terms': ['bad_orientation', 'fallen']}, {'step': 705, 'terms': ['bad_orientation', 'fallen']}, {'step': 706, 'terms': ['bad_orientation', 'fallen']}, {'step': 707, 'terms': ['bad_orientation', 'fallen']}, {'step': 708, 'terms': ['bad_orientation', 'fallen']}, {'step': 709, 'terms': ['bad_orientation', 'fallen']}, {'step': 710, 'terms': ['bad_orientation', 'fallen']}, {'step': 711, 'terms': ['bad_orientation', 'fallen']}, {'step': 712, 'terms': ['bad_orientation', 'fallen']}, {'step': 713, 'terms': ['bad_orientation', 'fallen']}, {'step': 714, 'terms': ['bad_orientation', 'fallen']}, {'step': 715, 'terms': ['bad_orientation', 'fallen']}, {'step': 716, 'terms': ['bad_orientation', 'fallen']}, {'step': 717, 'terms': ['bad_orientation', 'fallen']}, {'step': 718, 'terms': ['bad_orientation', 'fallen']}, {'step': 719, 'terms': ['bad_orientation', 'fallen']}, {'step': 720, 'terms': ['bad_orientation', 'fallen']}, {'step': 721, 'terms': ['bad_orientation', 'fallen']}, {'step': 722, 'terms': ['bad_orientation', 'fallen']}, {'step': 723, 'terms': ['bad_orientation', 'fallen']}, {'step': 724, 'terms': ['bad_orientation', 'fallen']}, {'step': 725, 'terms': ['bad_orientation', 'fallen']}, {'step': 726, 'terms': ['bad_orientation', 'fallen']}, {'step': 727, 'terms': ['bad_orientation', 'fallen']}, {'step': 728, 'terms': ['bad_orientation', 'fallen']}, {'step': 729, 'terms': ['bad_orientation', 'fallen']}, {'step': 730, 'terms': ['bad_orientation', 'fallen']}, {'step': 731, 'terms': ['bad_orientation', 'fallen']}, {'step': 732, 'terms': ['bad_orientation', 'fallen']}, {'step': 733, 'terms': ['bad_orientation', 'fallen']}, {'step': 734, 'terms': ['bad_orientation', 'fallen']}, {'step': 735, 'terms': ['bad_orientation', 'fallen']}, {'step': 736, 'terms': ['bad_orientation', 'fallen']}, {'step': 737, 'terms': ['bad_orientation', 'fallen']}, {'step': 738, 'terms': ['bad_orientation', 'fallen']}, {'step': 739, 'terms': ['bad_orientation', 'fallen']}, {'step': 740, 'terms': ['bad_orientation', 'fallen']}, {'step': 741, 'terms': ['bad_orientation', 'fallen']}, {'step': 742, 'terms': ['bad_orientation', 'fallen']}, {'step': 743, 'terms': ['bad_orientation', 'fallen']}, {'step': 744, 'terms': ['bad_orientation', 'fallen']}, {'step': 745, 'terms': ['bad_orientation', 'fallen']}, {'step': 746, 'terms': ['bad_orientation', 'fallen']}, {'step': 747, 'terms': ['bad_orientation', 'fallen']}, {'step': 748, 'terms': ['bad_orientation', 'fallen']}, {'step': 749, 'terms': ['bad_orientation', 'fallen']}, {'step': 750, 'terms': ['bad_orientation', 'fallen']}, {'step': 751, 'terms': ['bad_orientation', 'fallen']}, {'step': 752, 'terms': ['bad_orientation', 'fallen']}, {'step': 753, 'terms': ['bad_orientation', 'fallen']}, {'step': 754, 'terms': ['bad_orientation', 'fallen']}, {'step': 755, 'terms': ['bad_orientation', 'fallen']}, {'step': 756, 'terms': ['bad_orientation', 'fallen']}, {'step': 757, 'terms': ['bad_orientation', 'fallen']}, {'step': 758, 'terms': ['bad_orientation', 'fallen']}, {'step': 759, 'terms': ['bad_orientation', 'fallen']}, {'step': 760, 'terms': ['bad_orientation', 'fallen']}, {'step': 761, 'terms': ['bad_orientation', 'fallen']}, {'step': 762, 'terms': ['bad_orientation', 'fallen']}, {'step': 763, 'terms': ['bad_orientation', 'fallen']}, {'step': 764, 'terms': ['bad_orientation', 'fallen']}, {'step': 765, 'terms': ['bad_orientation', 'fallen']}, {'step': 766, 'terms': ['bad_orientation', 'fallen']}, {'step': 767, 'terms': ['bad_orientation', 'fallen']}, {'step': 768, 'terms': ['bad_orientation', 'fallen']}, {'step': 769, 'terms': ['bad_orientation', 'fallen']}, {'step': 770, 'terms': ['bad_orientation', 'fallen']}, {'step': 771, 'terms': ['bad_orientation', 'fallen']}, {'step': 772, 'terms': ['bad_orientation', 'fallen']}, {'step': 773, 'terms': ['bad_orientation', 'fallen']}, {'step': 774, 'terms': ['bad_orientation', 'fallen']}, {'step': 775, 'terms': ['bad_orientation', 'fallen']}, {'step': 776, 'terms': ['bad_orientation', 'fallen']}, {'step': 777, 'terms': ['bad_orientation', 'fallen']}, {'step': 778, 'terms': ['bad_orientation', 'fallen']}, {'step': 779, 'terms': ['bad_orientation', 'fallen']}, {'step': 780, 'terms': ['bad_orientation', 'fallen']}, {'step': 781, 'terms': ['bad_orientation', 'fallen']}, {'step': 782, 'terms': ['bad_orientation', 'fallen']}, {'step': 783, 'terms': ['bad_orientation', 'fallen']}, {'step': 784, 'terms': ['bad_orientation', 'fallen']}, {'step': 785, 'terms': ['bad_orientation', 'fallen']}, {'step': 786, 'terms': ['bad_orientation', 'fallen']}, {'step': 787, 'terms': ['bad_orientation', 'fallen']}, {'step': 788, 'terms': ['bad_orientation', 'fallen']}, {'step': 789, 'terms': ['bad_orientation', 'fallen']}, {'step': 790, 'terms': ['bad_orientation', 'fallen']}, {'step': 791, 'terms': ['bad_orientation', 'fallen']}, {'step': 792, 'terms': ['bad_orientation', 'fallen']}, {'step': 793, 'terms': ['bad_orientation', 'fallen']}, {'step': 794, 'terms': ['bad_orientation', 'fallen']}, {'step': 795, 'terms': ['bad_orientation', 'fallen']}, {'step': 796, 'terms': ['bad_orientation', 'fallen']}, {'step': 797, 'terms': ['bad_orientation', 'fallen']}, {'step': 798, 'terms': ['bad_orientation', 'fallen']}, {'step': 799, 'terms': ['bad_orientation', 'fallen']}, {'step': 800, 'terms': ['bad_orientation', 'fallen']}, {'step': 801, 'terms': ['bad_orientation', 'fallen']}, {'step': 802, 'terms': ['bad_orientation', 'fallen']}, {'step': 803, 'terms': ['bad_orientation', 'fallen']}, {'step': 804, 'terms': ['bad_orientation', 'fallen']}, {'step': 805, 'terms': ['bad_orientation', 'fallen']}, {'step': 806, 'terms': ['bad_orientation', 'fallen']}, {'step': 807, 'terms': ['bad_orientation', 'fallen']}, {'step': 808, 'terms': ['bad_orientation', 'fallen']}, {'step': 809, 'terms': ['bad_orientation', 'fallen']}, {'step': 810, 'terms': ['bad_orientation', 'fallen']}, {'step': 811, 'terms': ['bad_orientation', 'fallen']}, {'step': 812, 'terms': ['bad_orientation', 'fallen']}, {'step': 813, 'terms': ['bad_orientation', 'fallen']}, {'step': 814, 'terms': ['bad_orientation', 'fallen']}, {'step': 815, 'terms': ['bad_orientation', 'fallen']}, {'step': 816, 'terms': ['bad_orientation', 'fallen']}, {'step': 817, 'terms': ['bad_orientation', 'fallen']}, {'step': 818, 'terms': ['bad_orientation', 'fallen']}, {'step': 819, 'terms': ['bad_orientation', 'fallen']}, {'step': 820, 'terms': ['bad_orientation', 'fallen']}, {'step': 821, 'terms': ['bad_orientation', 'fallen']}, {'step': 822, 'terms': ['bad_orientation', 'fallen']}, {'step': 823, 'terms': ['bad_orientation', 'fallen']}, {'step': 824, 'terms': ['bad_orientation', 'fallen']}, {'step': 825, 'terms': ['bad_orientation', 'fallen']}, {'step': 826, 'terms': ['bad_orientation', 'fallen']}, {'step': 827, 'terms': ['bad_orientation', 'fallen']}, {'step': 828, 'terms': ['bad_orientation', 'fallen']}, {'step': 829, 'terms': ['bad_orientation', 'fallen']}, {'step': 830, 'terms': ['bad_orientation', 'fallen']}, {'step': 831, 'terms': ['bad_orientation', 'fallen']}, {'step': 832, 'terms': ['bad_orientation', 'fallen']}, {'step': 833, 'terms': ['bad_orientation', 'fallen']}, {'step': 834, 'terms': ['bad_orientation', 'fallen']}, {'step': 835, 'terms': ['bad_orientation', 'fallen']}, {'step': 836, 'terms': ['bad_orientation', 'fallen']}, {'step': 837, 'terms': ['bad_orientation', 'fallen']}, {'step': 838, 'terms': ['bad_orientation', 'fallen']}, {'step': 839, 'terms': ['bad_orientation', 'fallen']}, {'step': 840, 'terms': ['bad_orientation', 'fallen']}, {'step': 841, 'terms': ['bad_orientation', 'fallen']}, {'step': 842, 'terms': ['bad_orientation', 'fallen']}, {'step': 843, 'terms': ['bad_orientation', 'fallen']}, {'step': 844, 'terms': ['bad_orientation', 'fallen']}, {'step': 845, 'terms': ['bad_orientation', 'fallen']}, {'step': 846, 'terms': ['bad_orientation', 'fallen']}, {'step': 847, 'terms': ['bad_orientation', 'fallen']}, {'step': 848, 'terms': ['bad_orientation', 'fallen']}, {'step': 849, 'terms': ['bad_orientation', 'fallen']}, {'step': 850, 'terms': ['bad_orientation', 'fallen']}, {'step': 851, 'terms': ['bad_orientation', 'fallen']}, {'step': 852, 'terms': ['bad_orientation', 'fallen']}, {'step': 853, 'terms': ['bad_orientation', 'fallen']}, {'step': 854, 'terms': ['bad_orientation', 'fallen']}, {'step': 855, 'terms': ['bad_orientation', 'fallen']}, {'step': 856, 'terms': ['bad_orientation', 'fallen']}, {'step': 857, 'terms': ['bad_orientation', 'fallen']}, {'step': 858, 'terms': ['bad_orientation', 'fallen']}, {'step': 859, 'terms': ['bad_orientation', 'fallen']}, {'step': 860, 'terms': ['bad_orientation', 'fallen']}, {'step': 861, 'terms': ['bad_orientation', 'fallen']}, {'step': 862, 'terms': ['bad_orientation', 'fallen']}, {'step': 863, 'terms': ['bad_orientation', 'fallen']}, {'step': 864, 'terms': ['bad_orientation', 'fallen']}, {'step': 865, 'terms': ['bad_orientation', 'fallen']}, {'step': 866, 'terms': ['bad_orientation', 'fallen']}, {'step': 867, 'terms': ['bad_orientation', 'fallen']}, {'step': 868, 'terms': ['bad_orientation', 'fallen']}, {'step': 869, 'terms': ['bad_orientation', 'fallen']}, {'step': 870, 'terms': ['bad_orientation', 'fallen']}, {'step': 871, 'terms': ['bad_orientation', 'fallen']}, {'step': 872, 'terms': ['bad_orientation', 'fallen']}, {'step': 873, 'terms': ['bad_orientation', 'fallen']}, {'step': 874, 'terms': ['bad_orientation', 'fallen']}, {'step': 875, 'terms': ['bad_orientation', 'fallen']}, {'step': 876, 'terms': ['bad_orientation', 'fallen']}, {'step': 877, 'terms': ['bad_orientation', 'fallen']}, {'step': 878, 'terms': ['bad_orientation', 'fallen']}, {'step': 879, 'terms': ['bad_orientation', 'fallen']}, {'step': 880, 'terms': ['bad_orientation', 'fallen']}, {'step': 881, 'terms': ['bad_orientation', 'fallen']}, {'step': 882, 'terms': ['bad_orientation', 'fallen']}, {'step': 883, 'terms': ['bad_orientation', 'fallen']}, {'step': 884, 'terms': ['bad_orientation', 'fallen']}, {'step': 885, 'terms': ['bad_orientation', 'fallen']}, {'step': 886, 'terms': ['bad_orientation', 'fallen']}, {'step': 887, 'terms': ['bad_orientation', 'fallen']}, {'step': 888, 'terms': ['bad_orientation', 'fallen']}, {'step': 889, 'terms': ['bad_orientation', 'fallen']}, {'step': 890, 'terms': ['bad_orientation', 'fallen']}, {'step': 891, 'terms': ['bad_orientation', 'fallen']}, {'step': 892, 'terms': ['bad_orientation', 'fallen']}, {'step': 893, 'terms': ['bad_orientation', 'fallen']}, {'step': 894, 'terms': ['bad_orientation', 'fallen']}, {'step': 895, 'terms': ['bad_orientation', 'fallen']}, {'step': 896, 'terms': ['bad_orientation', 'fallen']}, {'step': 897, 'terms': ['bad_orientation', 'fallen']}, {'step': 898, 'terms': ['bad_orientation', 'fallen']}, {'step': 899, 'terms': ['bad_orientation', 'fallen']}, {'step': 900, 'terms': ['bad_orientation', 'fallen']}, {'step': 901, 'terms': ['bad_orientation', 'fallen']}, {'step': 902, 'terms': ['bad_orientation', 'fallen']}, {'step': 903, 'terms': ['bad_orientation', 'fallen']}, {'step': 904, 'terms': ['bad_orientation', 'fallen']}, {'step': 905, 'terms': ['bad_orientation', 'fallen']}, {'step': 906, 'terms': ['bad_orientation', 'fallen']}, {'step': 907, 'terms': ['bad_orientation', 'fallen']}, {'step': 908, 'terms': ['bad_orientation', 'fallen']}, {'step': 909, 'terms': ['bad_orientation', 'fallen']}, {'step': 910, 'terms': ['bad_orientation', 'fallen']}, {'step': 911, 'terms': ['bad_orientation', 'fallen']}, {'step': 912, 'terms': ['bad_orientation', 'fallen']}, {'step': 913, 'terms': ['bad_orientation', 'fallen']}, {'step': 914, 'terms': ['bad_orientation', 'fallen']}, {'step': 915, 'terms': ['bad_orientation', 'fallen']}, {'step': 916, 'terms': ['bad_orientation', 'fallen']}, {'step': 917, 'terms': ['bad_orientation', 'fallen']}, {'step': 918, 'terms': ['bad_orientation', 'fallen']}, {'step': 919, 'terms': ['bad_orientation', 'fallen']}, {'step': 920, 'terms': ['bad_orientation', 'fallen']}, {'step': 921, 'terms': ['bad_orientation', 'fallen']}, {'step': 922, 'terms': ['bad_orientation', 'fallen']}, {'step': 923, 'terms': ['bad_orientation', 'fallen']}, {'step': 924, 'terms': ['bad_orientation', 'fallen']}, {'step': 925, 'terms': ['bad_orientation', 'fallen']}, {'step': 926, 'terms': ['bad_orientation', 'fallen']}, {'step': 927, 'terms': ['bad_orientation', 'fallen']}, {'step': 928, 'terms': ['bad_orientation', 'fallen']}, {'step': 929, 'terms': ['bad_orientation', 'fallen']}, {'step': 930, 'terms': ['bad_orientation', 'fallen']}, {'step': 931, 'terms': ['bad_orientation', 'fallen']}, {'step': 932, 'terms': ['bad_orientation', 'fallen']}, {'step': 933, 'terms': ['bad_orientation', 'fallen']}, {'step': 934, 'terms': ['bad_orientation', 'fallen']}, {'step': 935, 'terms': ['bad_orientation', 'fallen']}, {'step': 936, 'terms': ['bad_orientation', 'fallen']}, {'step': 937, 'terms': ['bad_orientation', 'fallen']}, {'step': 938, 'terms': ['bad_orientation', 'fallen']}, {'step': 939, 'terms': ['bad_orientation', 'fallen']}, {'step': 940, 'terms': ['bad_orientation', 'fallen']}, {'step': 941, 'terms': ['bad_orientation', 'fallen']}, {'step': 942, 'terms': ['bad_orientation', 'fallen']}, {'step': 943, 'terms': ['bad_orientation', 'fallen']}, {'step': 944, 'terms': ['bad_orientation', 'fallen']}, {'step': 945, 'terms': ['bad_orientation', 'fallen']}, {'step': 946, 'terms': ['bad_orientation', 'fallen']}, {'step': 947, 'terms': ['bad_orientation', 'fallen']}, {'step': 948, 'terms': ['bad_orientation', 'fallen']}, {'step': 949, 'terms': ['bad_orientation', 'fallen']}, {'step': 950, 'terms': ['bad_orientation', 'fallen']}, {'step': 951, 'terms': ['bad_orientation', 'fallen']}, {'step': 952, 'terms': ['bad_orientation', 'fallen']}, {'step': 953, 'terms': ['bad_orientation', 'fallen']}, {'step': 954, 'terms': ['bad_orientation', 'fallen']}, {'step': 955, 'terms': ['bad_orientation', 'fallen']}, {'step': 956, 'terms': ['bad_orientation', 'fallen']}, {'step': 957, 'terms': ['bad_orientation', 'fallen']}, {'step': 958, 'terms': ['bad_orientation', 'fallen']}, {'step': 959, 'terms': ['bad_orientation', 'fallen']}, {'step': 960, 'terms': ['bad_orientation', 'fallen']}, {'step': 961, 'terms': ['bad_orientation', 'fallen']}, {'step': 962, 'terms': ['bad_orientation', 'fallen']}, {'step': 963, 'terms': ['bad_orientation', 'fallen']}, {'step': 964, 'terms': ['bad_orientation', 'fallen']}, {'step': 965, 'terms': ['bad_orientation', 'fallen']}, {'step': 966, 'terms': ['bad_orientation', 'fallen']}, {'step': 967, 'terms': ['bad_orientation', 'fallen']}, {'step': 968, 'terms': ['bad_orientation', 'fallen']}, {'step': 969, 'terms': ['bad_orientation', 'fallen']}, {'step': 970, 'terms': ['bad_orientation', 'fallen']}, {'step': 971, 'terms': ['bad_orientation', 'fallen']}, {'step': 972, 'terms': ['bad_orientation', 'fallen']}, {'step': 973, 'terms': ['bad_orientation', 'fallen']}, {'step': 974, 'terms': ['bad_orientation', 'fallen']}, {'step': 975, 'terms': ['bad_orientation', 'fallen']}, {'step': 976, 'terms': ['bad_orientation', 'fallen']}, {'step': 977, 'terms': ['bad_orientation', 'fallen']}, {'step': 978, 'terms': ['bad_orientation', 'fallen']}, {'step': 979, 'terms': ['bad_orientation', 'fallen']}, {'step': 980, 'terms': ['bad_orientation', 'fallen']}, {'step': 981, 'terms': ['bad_orientation', 'fallen']}, {'step': 982, 'terms': ['bad_orientation', 'fallen']}, {'step': 983, 'terms': ['bad_orientation', 'fallen']}, {'step': 984, 'terms': ['bad_orientation', 'fallen']}, {'step': 985, 'terms': ['bad_orientation', 'fallen']}, {'step': 986, 'terms': ['bad_orientation', 'fallen']}, {'step': 987, 'terms': ['bad_orientation', 'fallen']}, {'step': 988, 'terms': ['bad_orientation', 'fallen']}, {'step': 989, 'terms': ['bad_orientation', 'fallen']}, {'step': 990, 'terms': ['bad_orientation', 'fallen']}, {'step': 991, 'terms': ['bad_orientation', 'fallen']}, {'step': 992, 'terms': ['bad_orientation', 'fallen']}, {'step': 993, 'terms': ['bad_orientation', 'fallen']}, {'step': 994, 'terms': ['bad_orientation', 'fallen']}, {'step': 995, 'terms': ['bad_orientation', 'fallen']}, {'step': 996, 'terms': ['bad_orientation', 'fallen']}, {'step': 997, 'terms': ['bad_orientation', 'fallen']}, {'step': 998, 'terms': ['bad_orientation', 'fallen']}, {'step': 999, 'terms': ['bad_orientation', 'fallen']}, {'step': 1000, 'terms': ['bad_orientation', 'fallen']}, {'step': 1001, 'terms': ['bad_orientation', 'fallen']}, {'step': 1002, 'terms': ['bad_orientation', 'fallen']}, {'step': 1003, 'terms': ['bad_orientation', 'fallen']}, {'step': 1004, 'terms': ['bad_orientation', 'fallen']}, {'step': 1005, 'terms': ['bad_orientation', 'fallen']}, {'step': 1006, 'terms': ['bad_orientation', 'fallen']}, {'step': 1007, 'terms': ['bad_orientation', 'fallen']}, {'step': 1008, 'terms': ['bad_orientation', 'fallen']}, {'step': 1009, 'terms': ['bad_orientation', 'fallen']}, {'step': 1010, 'terms': ['bad_orientation', 'fallen']}, {'step': 1011, 'terms': ['bad_orientation', 'fallen']}, {'step': 1012, 'terms': ['bad_orientation', 'fallen']}, {'step': 1013, 'terms': ['bad_orientation', 'fallen']}, {'step': 1014, 'terms': ['bad_orientation', 'fallen']}, {'step': 1015, 'terms': ['bad_orientation', 'fallen']}, {'step': 1016, 'terms': ['bad_orientation', 'fallen']}, {'step': 1017, 'terms': ['bad_orientation', 'fallen']}, {'step': 1018, 'terms': ['bad_orientation', 'fallen']}, {'step': 1019, 'terms': ['bad_orientation', 'fallen']}, {'step': 1020, 'terms': ['bad_orientation', 'fallen']}, {'step': 1021, 'terms': ['bad_orientation', 'fallen']}, {'step': 1022, 'terms': ['bad_orientation', 'fallen']}, {'step': 1023, 'terms': ['bad_orientation', 'fallen']}, {'step': 1024, 'terms': ['bad_orientation', 'fallen']}, {'step': 1025, 'terms': ['bad_orientation', 'fallen']}, {'step': 1026, 'terms': ['bad_orientation', 'fallen']}, {'step': 1027, 'terms': ['bad_orientation', 'fallen']}, {'step': 1028, 'terms': ['bad_orientation', 'fallen']}, {'step': 1029, 'terms': ['bad_orientation', 'fallen']}, {'step': 1030, 'terms': ['bad_orientation', 'fallen']}, {'step': 1031, 'terms': ['bad_orientation', 'fallen']}, {'step': 1032, 'terms': ['bad_orientation', 'fallen']}, {'step': 1033, 'terms': ['bad_orientation', 'fallen']}, {'step': 1034, 'terms': ['bad_orientation', 'fallen']}, {'step': 1035, 'terms': ['bad_orientation', 'fallen']}, {'step': 1036, 'terms': ['bad_orientation', 'fallen']}, {'step': 1037, 'terms': ['bad_orientation', 'fallen']}, {'step': 1038, 'terms': ['bad_orientation', 'fallen']}, {'step': 1039, 'terms': ['bad_orientation', 'fallen']}, {'step': 1040, 'terms': ['bad_orientation', 'fallen']}, {'step': 1041, 'terms': ['bad_orientation', 'fallen']}, {'step': 1042, 'terms': ['bad_orientation', 'fallen']}, {'step': 1043, 'terms': ['bad_orientation', 'fallen']}, {'step': 1044, 'terms': ['bad_orientation', 'fallen']}, {'step': 1045, 'terms': ['bad_orientation', 'fallen']}, {'step': 1046, 'terms': ['bad_orientation', 'fallen']}, {'step': 1047, 'terms': ['bad_orientation', 'fallen']}, {'step': 1048, 'terms': ['bad_orientation', 'fallen']}, {'step': 1049, 'terms': ['bad_orientation', 'fallen']}, {'step': 1050, 'terms': ['bad_orientation', 'fallen']}, {'step': 1051, 'terms': ['bad_orientation', 'fallen']}, {'step': 1052, 'terms': ['bad_orientation', 'fallen']}, {'step': 1053, 'terms': ['bad_orientation', 'fallen']}, {'step': 1054, 'terms': ['bad_orientation', 'fallen']}, {'step': 1055, 'terms': ['bad_orientation', 'fallen']}, {'step': 1056, 'terms': ['bad_orientation', 'fallen']}, {'step': 1057, 'terms': ['bad_orientation', 'fallen']}, {'step': 1058, 'terms': ['bad_orientation', 'fallen']}, {'step': 1059, 'terms': ['bad_orientation', 'fallen']}, {'step': 1060, 'terms': ['bad_orientation', 'fallen']}, {'step': 1061, 'terms': ['bad_orientation', 'fallen']}, {'step': 1062, 'terms': ['bad_orientation', 'fallen']}, {'step': 1063, 'terms': ['bad_orientation', 'fallen']}, {'step': 1064, 'terms': ['bad_orientation', 'fallen']}, {'step': 1065, 'terms': ['bad_orientation', 'fallen']}, {'step': 1066, 'terms': ['bad_orientation', 'fallen']}, {'step': 1067, 'terms': ['bad_orientation', 'fallen']}, {'step': 1068, 'terms': ['bad_orientation', 'fallen']}, {'step': 1069, 'terms': ['bad_orientation', 'fallen']}, {'step': 1070, 'terms': ['bad_orientation', 'fallen']}, {'step': 1071, 'terms': ['bad_orientation', 'fallen']}, {'step': 1072, 'terms': ['bad_orientation', 'fallen']}, {'step': 1073, 'terms': ['bad_orientation', 'fallen']}, {'step': 1074, 'terms': ['bad_orientation', 'fallen']}, {'step': 1075, 'terms': ['bad_orientation', 'fallen']}, {'step': 1076, 'terms': ['bad_orientation', 'fallen']}, {'step': 1077, 'terms': ['bad_orientation', 'fallen']}, {'step': 1078, 'terms': ['bad_orientation', 'fallen']}, {'step': 1079, 'terms': ['bad_orientation', 'fallen']}, {'step': 1080, 'terms': ['bad_orientation', 'fallen']}, {'step': 1081, 'terms': ['bad_orientation', 'fallen']}, {'step': 1082, 'terms': ['bad_orientation', 'fallen']}, {'step': 1083, 'terms': ['bad_orientation', 'fallen']}, {'step': 1084, 'terms': ['bad_orientation', 'fallen']}, {'step': 1085, 'terms': ['bad_orientation', 'fallen']}, {'step': 1086, 'terms': ['bad_orientation', 'fallen']}, {'step': 1087, 'terms': ['bad_orientation', 'fallen']}, {'step': 1088, 'terms': ['bad_orientation', 'fallen']}, {'step': 1089, 'terms': ['bad_orientation', 'fallen']}, {'step': 1090, 'terms': ['bad_orientation', 'fallen']}, {'step': 1091, 'terms': ['bad_orientation', 'fallen']}, {'step': 1092, 'terms': ['bad_orientation', 'fallen']}, {'step': 1093, 'terms': ['bad_orientation', 'fallen']}, {'step': 1094, 'terms': ['bad_orientation', 'fallen']}, {'step': 1095, 'terms': ['bad_orientation', 'fallen']}, {'step': 1096, 'terms': ['bad_orientation', 'fallen']}, {'step': 1097, 'terms': ['bad_orientation', 'fallen']}, {'step': 1098, 'terms': ['bad_orientation', 'fallen']}, {'step': 1099, 'terms': ['bad_orientation', 'fallen']}, {'step': 1100, 'terms': ['bad_orientation', 'fallen']}, {'step': 1101, 'terms': ['bad_orientation', 'fallen']}, {'step': 1102, 'terms': ['bad_orientation', 'fallen']}, {'step': 1103, 'terms': ['bad_orientation', 'fallen']}, {'step': 1104, 'terms': ['bad_orientation', 'fallen']}, {'step': 1105, 'terms': ['bad_orientation', 'fallen']}, {'step': 1106, 'terms': ['bad_orientation', 'fallen']}, {'step': 1107, 'terms': ['bad_orientation', 'fallen']}, {'step': 1108, 'terms': ['bad_orientation', 'fallen']}, {'step': 1109, 'terms': ['bad_orientation', 'fallen']}, {'step': 1110, 'terms': ['bad_orientation', 'fallen']}, {'step': 1111, 'terms': ['bad_orientation', 'fallen']}, {'step': 1112, 'terms': ['bad_orientation', 'fallen']}, {'step': 1113, 'terms': ['bad_orientation', 'fallen']}, {'step': 1114, 'terms': ['bad_orientation', 'fallen']}, {'step': 1115, 'terms': ['bad_orientation', 'fallen']}, {'step': 1116, 'terms': ['bad_orientation', 'fallen']}, {'step': 1117, 'terms': ['bad_orientation', 'fallen']}, {'step': 1118, 'terms': ['bad_orientation', 'fallen']}, {'step': 1119, 'terms': ['bad_orientation', 'fallen']}, {'step': 1120, 'terms': ['bad_orientation', 'fallen']}, {'step': 1121, 'terms': ['bad_orientation', 'fallen']}, {'step': 1122, 'terms': ['bad_orientation', 'fallen']}, {'step': 1123, 'terms': ['bad_orientation', 'fallen']}, {'step': 1124, 'terms': ['bad_orientation', 'fallen']}, {'step': 1125, 'terms': ['bad_orientation', 'fallen']}, {'step': 1126, 'terms': ['bad_orientation', 'fallen']}, {'step': 1127, 'terms': ['bad_orientation', 'fallen']}, {'step': 1128, 'terms': ['bad_orientation', 'fallen']}, {'step': 1129, 'terms': ['bad_orientation', 'fallen']}, {'step': 1130, 'terms': ['bad_orientation', 'fallen']}, {'step': 1131, 'terms': ['bad_orientation', 'fallen']}, {'step': 1132, 'terms': ['bad_orientation', 'fallen']}, {'step': 1133, 'terms': ['bad_orientation', 'fallen']}, {'step': 1134, 'terms': ['bad_orientation', 'fallen']}, {'step': 1135, 'terms': ['bad_orientation', 'fallen']}, {'step': 1136, 'terms': ['bad_orientation', 'fallen']}, {'step': 1137, 'terms': ['bad_orientation', 'fallen']}, {'step': 1138, 'terms': ['bad_orientation', 'fallen']}, {'step': 1139, 'terms': ['bad_orientation', 'fallen']}, {'step': 1140, 'terms': ['bad_orientation', 'fallen']}, {'step': 1141, 'terms': ['bad_orientation', 'fallen']}, {'step': 1142, 'terms': ['bad_orientation', 'fallen']}, {'step': 1143, 'terms': ['bad_orientation', 'fallen']}, {'step': 1144, 'terms': ['bad_orientation', 'fallen']}, {'step': 1145, 'terms': ['bad_orientation', 'fallen']}, {'step': 1146, 'terms': ['bad_orientation', 'fallen']}, {'step': 1147, 'terms': ['bad_orientation', 'fallen']}, {'step': 1148, 'terms': ['bad_orientation', 'fallen']}, {'step': 1149, 'terms': ['bad_orientation', 'fallen']}, {'step': 1150, 'terms': ['bad_orientation', 'fallen']}, {'step': 1151, 'terms': ['bad_orientation', 'fallen']}, {'step': 1152, 'terms': ['bad_orientation', 'fallen']}, {'step': 1153, 'terms': ['bad_orientation', 'fallen']}, {'step': 1154, 'terms': ['bad_orientation', 'fallen']}, {'step': 1155, 'terms': ['bad_orientation', 'fallen']}, {'step': 1156, 'terms': ['bad_orientation', 'fallen']}, {'step': 1157, 'terms': ['bad_orientation', 'fallen']}, {'step': 1158, 'terms': ['bad_orientation', 'fallen']}, {'step': 1159, 'terms': ['bad_orientation', 'fallen']}, {'step': 1160, 'terms': ['bad_orientation', 'fallen']}, {'step': 1161, 'terms': ['bad_orientation', 'fallen']}, {'step': 1162, 'terms': ['bad_orientation', 'fallen']}, {'step': 1163, 'terms': ['bad_orientation', 'fallen']}, {'step': 1164, 'terms': ['bad_orientation', 'fallen']}, {'step': 1165, 'terms': ['bad_orientation', 'fallen']}, {'step': 1166, 'terms': ['bad_orientation', 'fallen']}, {'step': 1167, 'terms': ['bad_orientation', 'fallen']}, {'step': 1168, 'terms': ['bad_orientation', 'fallen']}, {'step': 1169, 'terms': ['bad_orientation', 'fallen']}, {'step': 1170, 'terms': ['bad_orientation', 'fallen']}, {'step': 1171, 'terms': ['bad_orientation', 'fallen']}, {'step': 1172, 'terms': ['bad_orientation', 'fallen']}, {'step': 1173, 'terms': ['bad_orientation', 'fallen']}, {'step': 1174, 'terms': ['bad_orientation', 'fallen']}, {'step': 1175, 'terms': ['bad_orientation', 'fallen']}, {'step': 1176, 'terms': ['bad_orientation', 'fallen']}, {'step': 1177, 'terms': ['bad_orientation', 'fallen']}, {'step': 1178, 'terms': ['bad_orientation', 'fallen']}, {'step': 1179, 'terms': ['bad_orientation', 'fallen']}, {'step': 1180, 'terms': ['bad_orientation', 'fallen']}, {'step': 1181, 'terms': ['bad_orientation', 'fallen']}, {'step': 1182, 'terms': ['bad_orientation', 'fallen']}, {'step': 1183, 'terms': ['bad_orientation', 'fallen']}, {'step': 1184, 'terms': ['bad_orientation', 'fallen']}, {'step': 1185, 'terms': ['bad_orientation', 'fallen']}, {'step': 1186, 'terms': ['bad_orientation', 'fallen']}, {'step': 1187, 'terms': ['bad_orientation', 'fallen']}, {'step': 1188, 'terms': ['bad_orientation', 'fallen']}, {'step': 1189, 'terms': ['bad_orientation', 'fallen']}, {'step': 1190, 'terms': ['bad_orientation', 'fallen']}, {'step': 1191, 'terms': ['bad_orientation', 'fallen']}, {'step': 1192, 'terms': ['bad_orientation', 'fallen']}, {'step': 1193, 'terms': ['bad_orientation', 'fallen']}, {'step': 1194, 'terms': ['bad_orientation', 'fallen']}, {'step': 1195, 'terms': ['bad_orientation', 'fallen']}, {'step': 1196, 'terms': ['bad_orientation', 'fallen']}, {'step': 1197, 'terms': ['bad_orientation', 'fallen']}, {'step': 1198, 'terms': ['bad_orientation', 'fallen']}, {'step': 1199, 'terms': ['bad_orientation', 'fallen']}, {'step': 1200, 'terms': ['bad_orientation', 'fallen']}], 'stable_start_step': None, 'max_stable_frames': 0, 'stable_seconds': 0.0, 'handoff_success': False, 'stable_trace': [], 'contact_trace': [{'step': 0, 'recovering': False, 'root': [3.0577876567840576, -4.997474670410156, 0.11938111484050751], 'feet_on_desktop': [False, False], 'root_ladder_relative': [-0.034239090979099274, 0.0027650222182273865, 0.12199999392032623], 'inside_desktop': False}, {'step': 25, 'recovering': False, 'root': [3.1450321674346924, -4.9901909828186035, 0.14503581821918488], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.04975052922964096, 0.010757766664028168, 0.14552591741085052], 'inside_desktop': False}, {'step': 50, 'recovering': False, 'root': [3.1460776329040527, -4.982883930206299, 0.15677985548973083], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.05424448102712631, 0.016920410096645355, 0.15668827295303345], 'inside_desktop': False}, {'step': 75, 'recovering': False, 'root': [3.177398443222046, -4.98989200592041, 0.1903156340122223], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.07953711599111557, 0.011022411286830902, 0.1885318011045456], 'inside_desktop': False}, {'step': 100, 'recovering': False, 'root': [3.1641292572021484, -4.980403900146484, 0.2039075791835785], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.07205601781606674, 0.02022441476583481, 0.20363152027130127], 'inside_desktop': False}, {'step': 125, 'recovering': False, 'root': [3.206439256668091, -4.9875569343566895, 0.24450154602527618], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.11439128965139389, 0.012783370912075043, 0.24397413432598114], 'inside_desktop': False}, {'step': 150, 'recovering': False, 'root': [3.1964030265808105, -4.981236457824707, 0.26321062445640564], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.10293551534414291, 0.01991208642721176, 0.2609764635562897], 'inside_desktop': False}, {'step': 175, 'recovering': False, 'root': [3.233297824859619, -4.987325668334961, 0.29817190766334534], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.1412162482738495, 0.013151966035366058, 0.2979878783226013], 'inside_desktop': False}, {'step': 200, 'recovering': False, 'root': [3.2260923385620117, -4.982788562774658, 0.32474932074546814], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.13587424159049988, 0.01865752786397934, 0.3214675486087799], 'inside_desktop': False}, {'step': 225, 'recovering': False, 'root': [3.2598605155944824, -4.980321407318115, 0.35430842638015747], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.16917750239372253, 0.016895614564418793, 0.35241472721099854], 'inside_desktop': False}, {'step': 250, 'recovering': False, 'root': [3.25394606590271, -4.981133937835693, 0.38031142950057983], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.16074082255363464, 0.018960796296596527, 0.3794574737548828], 'inside_desktop': False}, {'step': 275, 'recovering': False, 'root': [3.279066324234009, -4.973018169403076, 0.41031554341316223], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.18918892741203308, 0.025670848786830902, 0.4099203646183014], 'inside_desktop': False}, {'step': 300, 'recovering': False, 'root': [3.2915546894073486, -4.9785475730896, 0.4399409890174866], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.19613930583000183, 0.02205546945333481, 0.437380313873291], 'inside_desktop': False}, {'step': 325, 'recovering': False, 'root': [3.300673484802246, -4.973627090454102, 0.4620696008205414], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.20886632800102234, 0.02687009423971176, 0.4620586037635803], 'inside_desktop': False}, {'step': 350, 'recovering': False, 'root': [3.3293545246124268, -4.980380535125732, 0.4979453980922699], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.23262330889701843, 0.020283065736293793, 0.495714396238327], 'inside_desktop': False}, {'step': 375, 'recovering': False, 'root': [3.3290584087371826, -4.975251197814941, 0.5149056911468506], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.23697683215141296, 0.025483928620815277, 0.5145350694656372], 'inside_desktop': False}, {'step': 400, 'recovering': False, 'root': [3.3722972869873047, -4.9830474853515625, 0.555117130279541], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.2807409465312958, 0.017217479646205902, 0.5549328327178955], 'inside_desktop': False}, {'step': 425, 'recovering': False, 'root': [3.3650314807891846, -4.978694438934326, 0.576586902141571], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.2710544764995575, 0.02261241525411606, 0.5741820931434631], 'inside_desktop': False}, {'step': 450, 'recovering': False, 'root': [3.399016857147217, -4.983526229858398, 0.6076566576957703], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.30692145228385925, 0.01708587259054184, 0.6077840924263], 'inside_desktop': False}, {'step': 475, 'recovering': False, 'root': [3.3903141021728516, -4.9808244705200195, 0.6376470327377319], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.2992992103099823, 0.01980050653219223, 0.6344285011291504], 'inside_desktop': False}, {'step': 500, 'recovering': False, 'root': [3.4274723529815674, -4.978277683258057, 0.6651345491409302], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.33672234416007996, 0.01939614862203598, 0.6636655926704407], 'inside_desktop': False}, {'step': 525, 'recovering': False, 'root': [3.4250574111938477, -4.9787702560424805, 0.6947082281112671], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.33174368739128113, 0.021120868623256683, 0.6931589841842651], 'inside_desktop': False}, {'step': 550, 'recovering': False, 'root': [3.4658796787261963, -4.976681709289551, 0.7231909036636353], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.3743414580821991, 0.022128425538539886, 0.7214447259902954], 'inside_desktop': False}, {'step': 575, 'recovering': False, 'root': [3.5505852699279785, -4.981891632080078, 0.7359279990196228], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.45032045245170593, 0.01818927377462387, 0.743180513381958], 'inside_desktop': False}, {'step': 600, 'recovering': False, 'root': [3.6053519248962402, -4.962912559509277, 0.7361092567443848], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5127086043357849, 0.03829368203878403, 0.7368682026863098], 'inside_desktop': True}, {'step': 625, 'recovering': False, 'root': [3.610753297805786, -4.96338415145874, 0.7367659211158752], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.518821656703949, 0.03683885186910629, 0.7367683053016663], 'inside_desktop': True}, {'step': 650, 'recovering': False, 'root': [3.6110050678253174, -4.963460445404053, 0.736728847026825], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5190531611442566, 0.03678306192159653, 0.736727237701416], 'inside_desktop': True}, {'step': 675, 'recovering': False, 'root': [3.6111702919006348, -4.963545322418213, 0.7367097735404968], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5192322134971619, 0.03666289895772934, 0.736711859703064], 'inside_desktop': True}, {'step': 700, 'recovering': False, 'root': [3.611341714859009, -4.9636664390563965, 0.7366949319839478], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.519401490688324, 0.03656085580587387, 0.7366976737976074], 'inside_desktop': True}, {'step': 725, 'recovering': False, 'root': [3.611502170562744, -4.963796138763428, 0.7366816401481628], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5195650458335876, 0.03643067926168442, 0.7366785407066345], 'inside_desktop': True}, {'step': 750, 'recovering': False, 'root': [3.611682653427124, -4.963926792144775, 0.7366548180580139], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5197324156761169, 0.03631051629781723, 0.7366582155227661], 'inside_desktop': True}, {'step': 775, 'recovering': False, 'root': [3.6118850708007812, -4.964094161987305, 0.7366540431976318], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5199460387229919, 0.03613504022359848, 0.7366520166397095], 'inside_desktop': True}, {'step': 800, 'recovering': False, 'root': [3.612063407897949, -4.9642791748046875, 0.7366718053817749], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5201236605644226, 0.03594716638326645, 0.7366691827774048], 'inside_desktop': True}, {'step': 825, 'recovering': False, 'root': [3.6122660636901855, -4.964442253112793, 0.736650288105011], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5203258395195007, 0.0357874259352684, 0.736644446849823], 'inside_desktop': True}, {'step': 850, 'recovering': False, 'root': [3.6124439239501953, -4.964605331420898, 0.7366249561309814], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5204958319664001, 0.035633884370326996, 0.7366237640380859], 'inside_desktop': True}, {'step': 875, 'recovering': False, 'root': [3.6126065254211426, -4.964734077453613, 0.736600935459137], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5206686854362488, 0.03548940271139145, 0.7365999221801758], 'inside_desktop': True}, {'step': 900, 'recovering': False, 'root': [3.6128008365631104, -4.9648871421813965, 0.7365731596946716], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.520857036113739, 0.035345397889614105, 0.7365754842758179], 'inside_desktop': True}, {'step': 925, 'recovering': False, 'root': [3.6130213737487793, -4.965056419372559, 0.7365483641624451], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5210735201835632, 0.035176120698451996, 0.7365514039993286], 'inside_desktop': True}, {'step': 950, 'recovering': False, 'root': [3.6134557723999023, -4.965215682983398, 0.736488938331604], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5214959979057312, 0.035017333924770355, 0.7364875078201294], 'inside_desktop': True}, {'step': 975, 'recovering': False, 'root': [3.6138060092926025, -4.965240478515625, 0.7364546656608582], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5218622088432312, 0.03496583551168442, 0.736474335193634], 'inside_desktop': True}, {'step': 1000, 'recovering': False, 'root': [3.614440679550171, -4.9654717445373535, 0.7364104390144348], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5225023627281189, 0.034788452088832855, 0.7364527583122253], 'inside_desktop': True}, {'step': 1025, 'recovering': False, 'root': [3.614962100982666, -4.965713977813721, 0.7362114787101746], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.523023784160614, 0.034515224397182465, 0.7362061142921448], 'inside_desktop': True}, {'step': 1050, 'recovering': False, 'root': [3.614989757537842, -4.965705394744873, 0.7362091541290283], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5230421423912048, 0.03454049676656723, 0.7362111210823059], 'inside_desktop': True}, {'step': 1075, 'recovering': False, 'root': [3.61495041847229, -4.965643882751465, 0.7362216711044312], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5230211615562439, 0.03456052392721176, 0.73622065782547], 'inside_desktop': True}, {'step': 1100, 'recovering': False, 'root': [3.6149492263793945, -4.965649604797363, 0.7362431287765503], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5229906439781189, 0.03459867089986801, 0.7362391948699951], 'inside_desktop': True}, {'step': 1125, 'recovering': False, 'root': [3.6149089336395264, -4.965622901916504, 0.7362618446350098], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5229777693748474, 0.0345967635512352, 0.7362715005874634], 'inside_desktop': True}, {'step': 1150, 'recovering': False, 'root': [3.6149067878723145, -4.965603351593018, 0.736303985118866], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.5229596495628357, 0.03463014215230942, 0.7362850904464722], 'inside_desktop': True}, {'step': 1175, 'recovering': False, 'root': [3.6148681640625, -4.965608596801758, 0.7363107800483704], 'feet_on_desktop': [False, False], 'root_ladder_relative': [0.522904098033905, 0.03465159982442856, 0.7363020181655884], 'inside_desktop': True}], 'mean_climber_round_trip_ms': 13.52387006705006, 'p95_climber_round_trip_ms': 40.46261054463682, 'mean_getup_round_trip_ms': None, 'p95_getup_round_trip_ms': None, 'note': 'Ubuntu runs MuJoCo and the privileged simulator-only foot-desktop handoff detector; the selected environment is controlled by either the RDK X5 HBM pair, the GPU ONNX actor, or the CPU ONNX reference, while inert background environments preserve the official vectorized scene shape.'}\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<a href=\"../01-任务资料/精选视频/assets/notebook-replays/ladder_bpu_cached.gif\"><img src=\"../01-任务资料/精选视频/assets/notebook-replays/ladder_bpu_cached.gif\" alt=\"历史缓存 BPU 推理回放：梯面攀爬\" width=\"640\"></a>"
      ],
      "text/plain": [
       "GIF 预览：../01-任务资料/精选视频/assets/notebook-replays/ladder_bpu_cached.gif；原始 MP4 未嵌入 Notebook，以控制仓库体积。"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MuJoCo 回放命令模板: uv run python scripts/infer_policy.py --walking <LADDER.onnx> --new-cmd-obs\n"
     ]
    }
   ],
   "source": [
    "import hashlib\n",
    "import sys\n",
    "\n",
    "BPU_TASK = 'ladder'\n",
    "BPU_LADDER_LOCAL_OPT_IN = os.getenv(\"MICRODUCK_RUN_LOCAL_LADDER_BPU\", \"0\") == \"1\"\n",
    "BPU_VIDEO_STEPS = int(os.getenv(\"MICRODUCK_BPU_VIDEO_STEPS\", \"250\"))\n",
    "BPU_VIDEO_WIDTH = int(os.getenv(\"MICRODUCK_BPU_VIDEO_WIDTH\", \"640\"))\n",
    "BPU_VIDEO_HEIGHT = int(os.getenv(\"MICRODUCK_BPU_VIDEO_HEIGHT\", \"480\"))\n",
    "BPU_CAMERA_DISTANCE = os.getenv(\"MICRODUCK_BPU_CAMERA_DISTANCE\", \"1.2\")\n",
    "BPU_CAMERA_ELEVATION = os.getenv(\"MICRODUCK_BPU_CAMERA_ELEVATION\", \"-8\")\n",
    "BPU_CAMERA_AZIMUTH = os.getenv(\"MICRODUCK_BPU_CAMERA_AZIMUTH\", \"90\")\n",
    "BPU_PORT = int(os.getenv(\"MICRODUCK_BPU_PORT\", \"8765\"))\n",
    "RDK_CONTROL_PORT = int(os.getenv(\"MICRODUCK_BPU_CONTROL_PORT\", \"8766\"))\n",
    "RDK_HOST = os.getenv(\"RDK_HOST\", \"192.168.8.128\")\n",
    "BPU_HBM_DEFAULTS = {\n",
    "    \"ball_balance\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/ball_balance/model_output/ball_balance.opset11.bin\",\n",
    "    \"basketball\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/basketball/model_output/basketball.opset11.bin\",\n",
    "    \"walking\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/walking/model_output/walking.opset11.bin\",\n",
    "    \"perturbation\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/walking/model_output/walking.opset11.bin\",\n",
    "    \"stilt\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/stilts25/model_output/stilts25.opset11.bin\",\n",
    "    \"swing\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/swing/model_output/swing.opset11.bin\",\n",
    "    \"ladder\": \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/ladder/model_output/ladder.opset11.bin\",\n",
    "}\n",
    "RDK_HBM_DEFAULTS = {\n",
    "    \"ball_balance\": \"/home/sunrise/microduck_policy/hbm/ball_balance.bin\",\n",
    "    \"basketball\": \"/home/sunrise/microduck_policy/hbm/basketball.bin\",\n",
    "    \"walking\": \"/home/sunrise/microduck_policy/hbm/walking.bin\",\n",
    "    \"perturbation\": \"/home/sunrise/microduck_policy/hbm/walking.bin\",\n",
    "    \"stilt\": \"/home/sunrise/microduck_policy/hbm/stilts25.bin\",\n",
    "    \"swing\": \"/home/sunrise/microduck_policy/hbm/swing.bin\",\n",
    "    \"ladder\": \"/home/sunrise/microduck_policy/hbm/ladder.bin\",\n",
    "}\n",
    "BPU_HBM = Path(os.getenv(\"MICRODUCK_BPU_HBM\", BPU_HBM_DEFAULTS.get(BPU_TASK, \"\"))) if BPU_TASK else None\n",
    "RDK_HBM = RDK_HBM_DEFAULTS.get(BPU_TASK, \"\") if BPU_TASK else \"\"\n",
    "RDK_SERVER_SCRIPT = os.getenv(\"RDK_BPU_SERVER_SCRIPT\", \"/home/sunrise/microduck_policy/rdk_bpu_policy_server.py\")\n",
    "MOTRIX_ROOT = Path(os.getenv(\"MOTRIX_ROOT\", \"/home/ubuntu/workspaces/MotrixLab\")).expanduser() if BPU_TASK == \"ball_balance\" else None\n",
    "MOTRIX_PYTHON = Path(os.getenv(\"MOTRIX_PYTHON\", str(MOTRIX_ROOT / \".venv/bin/python\"))).expanduser() if MOTRIX_ROOT else None\n",
    "MOTRIX_RUNNER = PLAYGROUND_ROOT / \"scripts\" / \"motrix_runner.py\" if BPU_TASK == \"ball_balance\" else None\n",
    "BPU_VIDEO_SCRIPT = PLAYGROUND_ROOT / \"scripts\" / (\"motrix_bpu_inloop_video.py\" if BPU_TASK == \"ball_balance\" else \"bpu_inloop_video.py\")\n",
    "BPU_VIDEO_OUTPUT = OUTPUT_ROOT / \"bpu_videos\" / f\"{BPU_TASK}_bpu_latest.mp4\" if BPU_TASK else None\n",
    "ALLOW_CACHED_BPU = os.getenv(\"MICRODUCK_ALLOW_CACHED_BPU\", \"0\") == \"1\"\n",
    "BPU_LADDER_PAIR_SCRIPT = PLAYGROUND_ROOT / \"scripts\" / \"bpu_official_ladder_pair_video.py\"\n",
    "BPU_LADDER_CLIMBER_HBM = Path(os.getenv(\"MICRODUCK_BPU_LADDER_CLIMBER_HBM\", \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/official_ladder_climber/model_output/official_ladder_climber.bin\")).expanduser()\n",
    "BPU_LADDER_GETUP_HBM = Path(os.getenv(\"MICRODUCK_BPU_LADDER_GETUP_HBM\", \"/home/ubuntu/workspaces/microduck_bpu_models/compiled/official_ladder_getup/model_output/official_ladder_getup.bin\")).expanduser()\n",
    "BPU_LADDER_PAIR_OUTPUT = OUTPUT_ROOT / \"bpu_videos\" / \"ladder_official_pair_bpu_latest.mp4\"\n",
    "\n",
    "def show_cached_bpu_video(path, reason):\n",
    "    if not ALLOW_CACHED_BPU or path is None or not path.is_file():\n",
    "        return False\n",
    "    print(\"BPU-CACHED-VIDEO:\", path)\n",
    "    print(\"说明:\", reason)\n",
    "    report = path.with_suffix(\".json\")\n",
    "    if report.is_file():\n",
    "        print(json.loads(report.read_text(encoding=\"utf-8\")))\n",
    "    from IPython.display import Video, display\n",
    "    display(Video(str(path), embed=True))\n",
    "    return True\n",
    "\n",
    "def restart_rdk_policy_server():\n",
    "    if not BPU_TASK or not RDK_HBM:\n",
    "        return False\n",
    "    try:\n",
    "        if BPU_HBM is not None and BPU_HBM.is_file():\n",
    "            payload = BPU_HBM.read_bytes()\n",
    "            request = {\n",
    "                \"op\": \"upload_and_switch\",\n",
    "                \"task\": BPU_TASK,\n",
    "                \"size\": len(payload),\n",
    "                \"sha256\": hashlib.sha256(payload).hexdigest(),\n",
    "            }\n",
    "        else:\n",
    "            payload = b\"\"\n",
    "            request = {\"op\": \"switch\", \"task\": BPU_TASK}\n",
    "        with socket.create_connection((RDK_HOST, RDK_CONTROL_PORT), timeout=8) as control:\n",
    "            control.sendall((json.dumps(request) + \"\\n\").encode(\"utf-8\"))\n",
    "            if payload:\n",
    "                for offset in range(0, len(payload), 1024 * 1024):\n",
    "                    control.sendall(payload[offset:offset + 1024 * 1024])\n",
    "            response = json.loads(control.makefile(\"rb\").readline().decode(\"utf-8\"))\n",
    "        if response.get(\"ok\"):\n",
    "            action = \"已上传并切换\" if payload else \"已切换\"\n",
    "            print(\"RDK 任务策略服务\" + action + \":\", BPU_TASK, \"->\", response.get(\"model\"), \"pid=\", response.get(\"pid\"))\n",
    "            return True\n",
    "        print(\"RDK BPU 控制服务拒绝切换:\", response)\n",
    "    except (OSError, ValueError, json.JSONDecodeError) as exc:\n",
    "        print(\"RDK BPU 控制服务不可用，尝试 SSH:\", exc)\n",
    "    remote = \"sunrise@\" + RDK_HOST\n",
    "    command = (\n",
    "        \"pkill -f '^python3 .*rdk_bpu_policy_server.py' >/dev/null 2>&1 || true; \"\n",
    "        \"sleep 1; \"\n",
    "        \"nohup python3 \" + shlex.quote(RDK_SERVER_SCRIPT) +\n",
    "        \" --model \" + shlex.quote(RDK_HBM) +\n",
    "        \" --port \" + str(BPU_PORT) +\n",
    "        \" >/tmp/microduck_bpu_server.log 2>&1 </dev/null &\"\n",
    "    )\n",
    "    result = subprocess.run(\n",
    "        [\"ssh\", \"-o\", \"BatchMode=yes\", \"-o\", \"ConnectTimeout=8\", remote, \"bash -lc \" + shlex.quote(command)],\n",
    "        capture_output=True, text=True,\n",
    "    )\n",
    "    if result.returncode:\n",
    "        print(\"RDK 策略服务启动失败:\", result.stderr.strip() or result.stdout.strip())\n",
    "        return False\n",
    "    print(\"RDK 任务策略服务已切换:\", BPU_TASK, \"->\", RDK_HBM)\n",
    "    return True\n",
    "\n",
    "if BPU_TASK == \"ladder\":\n",
    "    pair_ready = BPU_LADDER_PAIR_SCRIPT.is_file() and BPU_LADDER_CLIMBER_HBM.is_file() and BPU_LADDER_GETUP_HBM.is_file()\n",
    "    pair_cmd = [\n",
    "        sys.executable, str(BPU_LADDER_PAIR_SCRIPT), \"--backend\", \"bpu\",\n",
    "        \"--climber-hbm\", str(BPU_LADDER_CLIMBER_HBM), \"--getup-hbm\", str(BPU_LADDER_GETUP_HBM),\n",
    "        \"--output\", str(BPU_LADDER_PAIR_OUTPUT), \"--seconds\", os.getenv(\"MICRODUCK_LADDER_SECONDS\", \"24\"),\n",
    "        \"--num-envs\", \"64\", \"--record-env\", \"17\",\n",
    "    ]\n",
    "    print(\"BPU 官方双模型:\", BPU_LADDER_CLIMBER_HBM, BPU_LADDER_GETUP_HBM)\n",
    "    if not pair_ready:\n",
    "        print(\"官方爬梯 BPU 双模型视频暂不可运行：请检查 climber/get-up HBM 和脚本。\")\n",
    "    else:\n",
    "        BPU_LADDER_PAIR_OUTPUT.parent.mkdir(parents=True, exist_ok=True)\n",
    "        pair_result = subprocess.run(pair_cmd, cwd=PLAYGROUND_ROOT, env=os.environ.copy(), capture_output=True, text=True)\n",
    "        print(\"\\n\".join((pair_result.stdout + \"\\n\" + pair_result.stderr).splitlines()[-35:]))\n",
    "        if pair_result.returncode != 0 or not BPU_LADDER_PAIR_OUTPUT.is_file():\n",
    "            if not show_cached_bpu_video(BPU_LADDER_PAIR_OUTPUT, \"本轮板端不可达，保留此前真实 RDK X5 BPU 双模型视频。\"):\n",
    "                raise RuntimeError(\"官方爬梯 BPU 双模型视频生成失败。\")\n",
    "        else:\n",
    "            print(\"PASS-BPU-VIDEO:\", BPU_LADDER_PAIR_OUTPUT)\n",
    "            pair_report = BPU_LADDER_PAIR_OUTPUT.with_suffix(\".json\")\n",
    "            if pair_report.is_file():\n",
    "                print(json.loads(pair_report.read_text(encoding=\"utf-8\")))\n",
    "            from IPython.display import Video, display\n",
    "            display(Video(str(BPU_LADDER_PAIR_OUTPUT), embed=True))\n",
    "elif not BPU_TASK:\n",
    "    print(\"该任务目前没有可验证的任务专属 HBM；不会用其他任务视频替代。\")\n",
    "elif BPU_TASK == \"ladder\" and not BPU_LADDER_LOCAL_OPT_IN:\n",
    "    print(\"已跳过本地 14 级 ladder HBM 视频：它不是社区 climber/get-up 方案。\")\n",
    "    print(\"只有明确设置 MICRODUCK_RUN_LOCAL_LADDER_BPU=1 才会运行本地实验，不得将结果标为社区复刻。\")\n",
    "elif BPU_HBM is None or not BPU_HBM.is_file():\n",
    "    print(\"Ubuntu 端 HBM 不存在:\", BPU_HBM)\n",
    "elif not BPU_VIDEO_SCRIPT.is_file():\n",
    "    print(\"找不到板端闭环录制器:\", BPU_VIDEO_SCRIPT)\n",
    "elif BPU_TASK == \"ball_balance\" and (MOTRIX_PYTHON is None or not MOTRIX_PYTHON.is_file()):\n",
    "    print(\"找不到 MotrixLab Python 环境:\", MOTRIX_PYTHON)\n",
    "elif BPU_TASK == \"ball_balance\" and (MOTRIX_RUNNER is None or not MOTRIX_RUNNER.is_file()):\n",
    "    print(\"找不到 MotrixLab 启动器:\", MOTRIX_RUNNER)\n",
    "elif restart_rdk_policy_server():\n",
    "    BPU_VIDEO_OUTPUT.parent.mkdir(parents=True, exist_ok=True)\n",
    "    if BPU_TASK == \"ball_balance\":\n",
    "        video_cmd = [str(MOTRIX_PYTHON), str(MOTRIX_RUNNER), \"video\", str(BPU_VIDEO_SCRIPT)]\n",
    "    else:\n",
    "        video_cmd = [sys.executable, str(BPU_VIDEO_SCRIPT)]\n",
    "    if BPU_TASK != \"ball_balance\":\n",
    "        video_cmd += [\"--task\", BPU_TASK]\n",
    "    video_cmd += [\n",
    "        \"--bpu-host\", RDK_HOST, \"--bpu-port\", str(BPU_PORT),\n",
    "        \"--hbm\", str(BPU_HBM), \"--output\", str(BPU_VIDEO_OUTPUT),\n",
    "        \"--steps\", str(BPU_VIDEO_STEPS), \"--width\", str(BPU_VIDEO_WIDTH),\n",
    "        \"--height\", str(BPU_VIDEO_HEIGHT),\n",
    "    ]\n",
    "    video_cmd += [\n",
    "        \"--camera-distance\", BPU_CAMERA_DISTANCE,\n",
    "        \"--camera-elevation\", BPU_CAMERA_ELEVATION,\n",
    "        \"--camera-azimuth\", BPU_CAMERA_AZIMUTH,\n",
    "    ]\n",
    "    print(\"开始生成板端闭环视频:\", \" \".join(shlex.quote(x) for x in video_cmd))\n",
    "    video_result = subprocess.run(\n",
    "        video_cmd, cwd=PLAYGROUND_ROOT, env=os.environ.copy(),\n",
    "        capture_output=True, text=True,\n",
    "    )\n",
    "    print(\"\\n\".join((video_result.stdout + \"\\n\" + video_result.stderr).splitlines()[-35:]))\n",
    "    if video_result.returncode != 0 or not BPU_VIDEO_OUTPUT.is_file():\n",
    "        raise RuntimeError(\"BPU-in-the-loop 视频生成失败，请先查看上面最后 35 行日志。\")\n",
    "    BPU_REPORT = BPU_VIDEO_OUTPUT.with_suffix(\".json\")\n",
    "    print(\"PASS-BPU-VIDEO:\", BPU_VIDEO_OUTPUT)\n",
    "    if BPU_REPORT.is_file():\n",
    "        print(json.loads(BPU_REPORT.read_text(encoding=\"utf-8\")))\n",
    "    from IPython.display import Video, display\n",
    "    display(Video(str(BPU_VIDEO_OUTPUT), embed=True))\n",
    "else:\n",
    "    show_cached_bpu_video(BPU_VIDEO_OUTPUT, \"本轮板端不可达，保留此前真实 RDK X5 BPU 任务视频。\")\n",
    "\n",
    "SIM_COMMAND = 'uv run python scripts/infer_policy.py --walking <LADDER.onnx> --new-cmd-obs'\n",
    "print(\"MuJoCo 回放命令模板:\", SIM_COMMAND)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "90b7f491",
   "metadata": {},
   "source": [
    "## 7. RDK X5 / BPU 检查\n",
    "\n",
    "检查板端连通、HBM 元数据和服务日志。MobileNet 样例验证 BPU 运行时；爬梯任务使用对应的 climber/get-up HBM。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "11b2dd40",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-09-19T08:24:05.111632Z",
     "iopub.status.busy": "2026-09-19T08:24:05.111531Z",
     "iopub.status.idle": "2026-09-19T08:24:08.222688Z",
     "shell.execute_reply": "2026-09-19T08:24:08.222345Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "默认 BPU 样例模型: /opt/tros/humble/lib/dnn_benchmark_example/config/X5/mobilenetv1_224x224_nv12.bin\n",
      "默认 BPU 样例输入: 75264 bytes uint8\n",
      "MicroDuck 策略 HBM: 该任务尚未提供\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "RDK 暂不可达，跳过板端验收: ssh: connect to host 192.168.8.128 port 22: No route to host\n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "\n",
    "RDK_HOST = os.getenv(\"RDK_HOST\", \"192.168.8.128\")\n",
    "BPU_SMOKE_MODEL = os.getenv(\n",
    "    \"RDK_BPU_SMOKE_MODEL\",\n",
    "    \"/opt/tros/humble/lib/dnn_benchmark_example/config/X5/mobilenetv1_224x224_nv12.bin\",\n",
    ")\n",
    "BPU_SMOKE_INPUT_BYTES = int(os.getenv(\"RDK_BPU_SMOKE_INPUT_BYTES\", \"75264\"))\n",
    "BPU_HBM = os.getenv(\"RDK_BPU_HBM\", \"\")\n",
    "print(\"默认 BPU 样例模型:\", BPU_SMOKE_MODEL)\n",
    "print(\"默认 BPU 样例输入:\", BPU_SMOKE_INPUT_BYTES, \"bytes uint8\")\n",
    "print(\"MicroDuck 策略 HBM:\", BPU_HBM or \"该任务尚未提供\")\n",
    "probe_script = \"for x in hrt_model_exec hb_mapper hrt_bin_dump hrt_bin_info python3; do if command -v $x >/dev/null 2>&1; then echo $x=$(command -v $x); else echo $x=MISSING; fi; done\"\n",
    "remote = \"sunrise@\" + RDK_HOST\n",
    "probe = subprocess.run([\"ssh\", \"-o\", \"BatchMode=yes\", \"-o\", \"ConnectTimeout=5\", remote, \"bash -lc \" + shlex.quote(probe_script)], capture_output=True, text=True)\n",
    "if probe.returncode:\n",
    "    print(\"RDK 暂不可达，跳过板端验收:\", probe.stderr.strip() or \"ssh failed\")\n",
    "else:\n",
    "    print(\"RDK 已连通:\", RDK_HOST)\n",
    "    print(probe.stdout)\n",
    "    if not BPU_HBM:\n",
    "        print(\"没有任务 HBM：不执行通用样例冒充任务推理。\")\n",
    "        smoke_model = BPU_SMOKE_MODEL\n",
    "        smoke_bytes = BPU_SMOKE_INPUT_BYTES\n",
    "        smoke_info_cmd = \"hrt_model_exec model_info --model_file \" + shlex.quote(smoke_model)\n",
    "        smoke_info = subprocess.run([\"ssh\", remote, \"bash -lc \" + shlex.quote(smoke_info_cmd)], capture_output=True, text=True)\n",
    "        print(\"BPU 样例 model_info exit:\", smoke_info.returncode)\n",
    "        print(smoke_info.stdout[-4000:])\n",
    "        print(smoke_info.stderr[-1000:])\n",
    "        if smoke_info.returncode == 0:\n",
    "            import numpy as np\n",
    "            local_input = OUTPUT_ROOT / \"rdk_bpu_runtime_smoke.bin\"\n",
    "            np.zeros(smoke_bytes, dtype=np.uint8).tofile(local_input)\n",
    "            remote_dir = \"/tmp/microduck_notebook\"\n",
    "            remote_input = remote_dir + \"/rdk_bpu_runtime_smoke.bin\"\n",
    "            subprocess.run([\"ssh\", remote, \"mkdir\", \"-p\", remote_dir], check=True)\n",
    "            subprocess.run([\"scp\", str(local_input), remote + \":\" + remote_input], check=True)\n",
    "            dump_dir = remote_dir + \"/runtime_dump\"\n",
    "            infer_cmd = \"rm -rf \" + shlex.quote(dump_dir) + \" && mkdir -p \" + shlex.quote(dump_dir) + \" && hrt_model_exec infer --model_file \" + shlex.quote(smoke_model) + \" --input_file \" + shlex.quote(remote_input) + \" --enable_dump true --dump_format txt --dump_path \" + shlex.quote(dump_dir)\n",
    "            started = time.perf_counter()\n",
    "            infer = subprocess.run([\"ssh\", remote, \"bash -lc \" + shlex.quote(infer_cmd)], capture_output=True, text=True)\n",
    "            elapsed_ms = (time.perf_counter() - started) * 1000.0\n",
    "            print(\"BPU runtime sample exit:\", infer.returncode, \"round-trip ms:\", round(elapsed_ms, 2))\n",
    "            print(infer.stdout[-4000:])\n",
    "            print(infer.stderr[-1000:])\n",
    "            if infer.returncode == 0:\n",
    "                print(\"PASS-rdk-bpu-runtime-sample: X5 BPU 样例推理已返回 0。\")\n",
    "    else:\n",
    "        info_cmd = \"hrt_model_exec model_info --model_file \" + shlex.quote(BPU_HBM)\n",
    "        info = subprocess.run([\"ssh\", remote, \"bash -lc \" + shlex.quote(info_cmd)], capture_output=True, text=True)\n",
    "        print(\"HBM model_info exit:\", info.returncode)\n",
    "        print(info.stdout[-6000:])\n",
    "        print(info.stderr[-2000:])\n",
    "        if info.returncode == 0:\n",
    "            # hrt_model_exec consumes binary tensors; this zero observation is\n",
    "            # only a transport/BPU smoke input, not a task-quality evaluation.\n",
    "            import numpy as np\n",
    "            local_input = OUTPUT_ROOT / \"zero_obs_61_f32.bin\"\n",
    "            np.zeros((1, 61), dtype=np.float32).tofile(local_input)\n",
    "            remote_dir = \"/tmp/microduck_notebook\"\n",
    "            remote_input = remote_dir + \"/zero_obs_61_f32.bin\"\n",
    "            subprocess.run([\"ssh\", remote, \"mkdir\", \"-p\", remote_dir], check=True)\n",
    "            subprocess.run([\"scp\", str(local_input), remote + \":\" + remote_input], check=True)\n",
    "            dump_dir = remote_dir + \"/dump\"\n",
    "            infer_cmd = \"rm -rf \" + shlex.quote(dump_dir) + \" && mkdir -p \" + shlex.quote(dump_dir) + \" && hrt_model_exec infer --model_file \" + shlex.quote(BPU_HBM) + \" --input_file \" + shlex.quote(remote_input) + \" --enable_dump true --dump_format txt --dump_path \" + shlex.quote(dump_dir)\n",
    "            started = time.perf_counter()\n",
    "            infer = subprocess.run([\"ssh\", remote, \"bash -lc \" + shlex.quote(infer_cmd)], capture_output=True, text=True)\n",
    "            elapsed_ms = (time.perf_counter() - started) * 1000.0\n",
    "            print(\"BPU infer exit:\", infer.returncode, \"round-trip ms:\", round(elapsed_ms, 2))\n",
    "            print(infer.stdout[-6000:])\n",
    "            print(infer.stderr[-2000:])\n",
    "            if infer.returncode == 0:\n",
    "                print(\"PASS-rdk-bpu: hrt_model_exec infer 已返回 0。\")\n",
    "            else:\n",
    "                print(\"未通过：优先以第 5 节 BPU-in-the-loop 报告为准。\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ab04531",
   "metadata": {},
   "source": [
    "## 8. 结果检查\n",
    "\n",
    "- `PASS-local-onnx`：模型结构与本地推理检查通过。\n",
    "- `PASS-GPU-VIDEO`：生成 GPU 推理视频与 JSON 报告。\n",
    "- `PASS-BPU-VIDEO`：当前在线生成板端推理视频。\n",
    "- `BPU-CACHED-VIDEO`：展示之前保存的板端视频。\n",
    "- `handoff_success`、`stable_seconds`：检查登桌起身与持续站立，本页 GPU 存档分别为 `true` 和 `11.54`。\n",
    "\n",
    "GPU 与 BPU 的任务指标分别记录；代码单元保留此前运行的输出。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
