✨ feat(planning): 添加离线飞拍规划能力

* 固化离线飞拍轨迹加载、保存和规划结果。

* 真机初始化失败时保留模型加载后的离线规划能力。

* 更新状态接口、调试页和回归测试覆盖。
This commit is contained in:
2026-06-24 11:40:07 +08:00
parent 070d2ba5c0
commit 5193f537b0
24 changed files with 1398 additions and 738 deletions

View File

@@ -28,6 +28,58 @@
<dd id="meta-status">初始化中...</dd>
</dl>
</section>
<section class="offline-panel" id="offline-planning-panel">
<h2>离线飞拍规划</h2>
<p class="offline-warning">生成轨迹不会向机器人发送命令;只有 RealReady 状态才能执行真实运动。</p>
<div class="offline-grid">
<label>
机器人模型
<input id="offline-robot-name" value="FANUC_LR_Mate_200iD">
</label>
<button id="offline-load-model" type="button">加载模型</button>
<label>
已上传轨迹
<select id="offline-trajectory-select"></select>
</label>
<button id="offline-refresh-trajectories" type="button" class="secondary">刷新列表</button>
<label>
规划方法
<select id="offline-planning-method">
<option value="icsp">icsp</option>
<option value="self-adapt-icsp">self-adapt-icsp</option>
</select>
</label>
<button id="offline-generate" type="button">生成最终发送轨迹</button>
</div>
<details>
<summary>上传飞拍轨迹 JSON</summary>
<textarea id="offline-upload-json" class="body-editor">{
"name": "demo-flyshot",
"waypoints": [[0,0,0,0,0,0],[0.001,0,0,0,0,0],[0.002,0,0,0,0,0],[0.003,0,0,0,0,0]],
"shot_flags": [false,true,false,false],
"offset_values": [0,1,0,0],
"addrs": [[],[7,8],[],[]]
}</textarea>
<button id="offline-upload" type="button">上传并刷新列表</button>
</details>
<div id="offline-planning-status" class="empty-hint">等待离线规划操作。</div>
<div id="offline-planning-summary"></div>
<div class="offline-table-wrap">
<table id="offline-send-table">
<thead>
<tr><th>序号</th><th>发送时间</th><th>轨迹时间</th><th>关节角(deg)</th><th>IO Mask</th><th>IO Value</th></tr>
</thead>
<tbody></tbody>
</table>
</div>
<div class="button-row">
<button id="offline-prev-page" type="button" class="secondary">上一页</button>
<span id="offline-page-info">0 / 0</span>
<button id="offline-next-page" type="button" class="secondary">下一页</button>
</div>
<pre id="offline-shot-events" class="response-body"></pre>
<pre id="offline-artifact-paths" class="response-body"></pre>
</section>
<div id="debug-console-app">
<div class="empty-hint">正在加载接口列表...</div>
</div>
@@ -41,11 +93,6 @@
</aside>
<script id="debug-static-docs" type="application/json">
{
"GET /": {
"summary": "根路径探活",
"description": "返回旧 HTTP 服务约定的 Hello World 响应,用来确认兼容层宿主已启动。",
"requestBodyFields": []
},
"GET /healthz": {
"summary": "宿主健康检查",
"description": "返回 replacement 宿主的基础健康状态,适合探活和部署验收。",
@@ -66,39 +113,9 @@
"description": "返回当前 ControllerClient 兼容层和 FANUC 运行时的聚合状态快照,供状态页和外部诊断读取。",
"requestBodyFields": []
},
"POST /connect_server/": {
"summary": "记录旧客户端目标服务",
"description": "兼容旧 `connect_server` 调用形状;在 replacement 宿主中只记录调用方期望连接的服务端地址,不会再启动旧 TCP+JSON 网关。",
"requestBodyFields": []
},
"GET /get_server_version/": {
"summary": "读取服务端版本",
"description": "返回当前 replacement 宿主暴露给旧客户端语义的服务端版本号。",
"requestBodyFields": []
},
"GET /get_client_version/": {
"summary": "读取客户端版本",
"description": "返回兼容层对外声明的客户端版本号,便于旧链路做版本诊断。",
"requestBodyFields": []
},
"POST /setup_robot/": {
"summary": "按名称加载机器人",
"description": "根据机器人名称加载对应模型和运行配置,为后续连接、使能和执行做准备。",
"requestBodyFields": []
},
"POST /setup_robot_from_env/": {
"summary": "按环境文件加载机器人",
"description": "兼容旧 `env_file` 入口,根据环境文件路径完成机器人初始化配置加载。",
"requestBodyFields": []
},
"POST /set_show_tcp/": {
"summary": "设置 TCP 显示开关",
"description": "兼容旧可视化参数接口,记录是否显示 TCP 坐标轴及其尺寸参数。",
"requestBodyFields": []
},
"GET /is_setup/": {
"summary": "查询是否已初始化",
"description": "返回当前兼容层是否已经完成 `SetUpRobot` 初始化。",
"description": "只加载机器人模型和 RobotConfig.json,不连接、不使能;成功后可进行离线规划。",
"requestBodyFields": []
},
"GET /enable_robot/": {
@@ -116,11 +133,6 @@
"description": "触发兼容层的 `StopMove` 语义,用于终止当前点动或轨迹执行。",
"requestBodyFields": []
},
"POST /set_active_controller/": {
"summary": "切换控制器模式",
"description": "通过查询参数 `sim` 指定当前使用仿真控制器还是真机控制器。",
"requestBodyFields": []
},
"POST /connect_robot/": {
"summary": "连接机器人控制器",
"description": "根据查询参数 `ip` 连接机器人控制器,建立后续命令与状态链路。",
@@ -232,8 +244,8 @@
]
},
"POST /save_traj_info/": {
"summary": "导出轨迹文件",
"description": "为指定飞拍轨迹生成并导出 `SaveTrajInfo` 兼容文件集合;底层未实现时会返回 501。",
"summary": "离线生成最终发送轨迹",
"description": "仅要求机器人模型已加载;完成规划、触发绑定、最终 8ms 序列生成和文件导出,并返回完整规划结果。",
"requestBodyFields": [
{ "name": "name", "type": "string", "required": true, "description": "目标飞拍轨迹名称。" },
{ "name": "method", "type": "string", "required": false, "description": "轨迹规划方法,默认 `icsp`。" }
@@ -262,15 +274,12 @@
{ "name": "name", "type": "string", "required": true, "description": "要删除的飞拍轨迹名称。" }
]
},
"POST /init_mpc_robt": {
"summary": "一键初始化旧链路",
"description": "兼容旧 `init_mpc_robt` 入口,按历史拼写保留。会串联执行 `SetUpRobot -> SetActiveController -> Connect -> EnableRobot`。",
"POST /init_mpc_robot": {
"summary": "真机优先初始化",
"description": "执行 `加载模型 -> 连接真机 -> EnableRobot(8)`;连接失败时模型仍保持 OfflineReady。",
"requestBodyFields": [
{ "name": "server_ip", "type": "string", "required": true, "description": "旧客户端记录的目标服务端 IP,仅保留兼容语义。" },
{ "name": "port", "type": "integer", "required": true, "description": "旧客户端记录的目标服务端端口。" },
{ "name": "robot_name", "type": "string", "required": true, "description": "机器人名称,用于加载模型与配置。" },
{ "name": "robot_ip", "type": "string", "required": true, "description": "机器人控制器 IP。" },
{ "name": "sim", "type": "boolean", "required": false, "description": "是否连接仿真控制器;默认 `false` 表示真机。" }
{ "name": "robot_ip", "type": "string", "required": true, "description": "机器人控制器 IP。" }
]
},
"GET /get_pose": {