# 通用机器人离线编程与虚拟控制器技术方案

版本：0.1  
日期：2026-06-26  
目标：为 Web 端离线编程、虚拟调试、通用机器人程序解析、仿真执行和品牌后处理建立技术要求与实现路线。

说明：本文中的 FANUC 指发那科机器人品牌。用户原始描述中的 “FUNAC” 按 FANUC 理解。

## 1. 项目目标

本项目最终目标是实现一套可在 Web 端运行的机器人离线编程与虚拟调试系统：

1. 定义一种通用机器人程序语言，语法和功能对标 ABB RAPID、FANUC TP/KAREL、KUKA KRL。
2. 使用 TypeScript 编写虚拟控制器、程序解析器、运行时、后处理框架和 Web 应用逻辑。
3. 使用 HTML 构建虚拟控制器界面，面向离线编程、运行监控、调试和后处理导出。
4. 将 Orocos KDL 编译为 WebAssembly，在 TypeScript 中调用 KDL WASM 完成机器人正解、逆解、雅可比、轨迹插补等核心计算。
5. Web 端文件系统使用 OPFS，支持项目文件、机器人模型、程序、轨迹、日志、后处理输出的本地持久化。
6. 通过后处理器，将通用机器人程序转换为 ABB、FANUC、KUKA 等品牌机器人程序。

系统定位不是简单代码编辑器，而是“虚拟机器人控制器 + 通用程序编译器 + 运动学内核 + 离线调试环境”。

## 1.1 商业离线编程软件对标定位

主流商业离线编程和虚拟调试软件，例如 ABB RobotStudio、RoboDK、Siemens Process Simulate、Visual Components、DELMIA Robotics 等，通常不是只围绕某一门机器人脚本语言工作，而是围绕“工作站、机器人、工具、坐标系、目标点、路径、工艺操作、仿真执行、后处理输出”建立项目模型。

因此，本项目的通用机器人程序不应设计成单纯模仿 ABB RAPID、FANUC TP 或 KUKA KRL 的文本语言，而应设计为商业 OLP 软件常见的双层模型：

1. 上层是离线编程对象模型
   - Robot：机器人和运动组。
   - Tool：工具、TCP、负载。
   - Frame：工件坐标、夹具坐标、用户坐标。
   - Target：目标点。
   - Path：路径，由目标点序列、工艺参数、速度、过渡、姿态策略组成。
   - Operation：工艺操作，例如搬运、焊接、喷涂、打磨、码垛。
   - Program：程序流程，引用路径和操作。
   - PostProfile：品牌后处理配置。

2. 下层是可执行通用程序
   - 使用 GRL 文本语法表达流程逻辑、运动指令、IO 和异常。
   - 由目标点、路径和操作树自动生成。
   - 可由用户手工编辑。
   - 可编译为统一 IR，由虚拟控制器执行。
   - 可后处理为 ABB、FANUC、KUKA 等品牌程序。

这样设计有 4 个直接收益：

1. 方便从 CAD 曲线、示教点、规划路径、工艺模板自动生成通用机器人程序。
2. 方便把同一个路径用不同品牌后处理器导出，而不丢失路径语义。
3. 方便虚拟控制器在不依赖真实品牌控制器的情况下执行统一 IR。
4. 方便导入 ABB、FANUC、KUKA 程序后，反解析为统一 IR 和 OLP 对象模型，进行跨品牌仿真与迁移。

## 2. 设计原则

1. 通用语言优先，品牌语言兼容

   通用程序语言应抽象出工业机器人共同语义：运动、坐标系、工具、目标点、速度、过渡、IO、变量、流程控制、子程序、异常、任务和中断。ABB、FANUC、KUKA 的差异通过品牌配置和后处理器处理。

   语法风格应贴近商业离线编程软件导出的“中性机器人程序”：清晰的运动语句、稳定的目标点引用、显式速度/过渡/工具/坐标系参数、可读的流程结构。不要把通用语言设计得过度像某一家品牌的控制器语言。

2. 运行语义可解释、可调试

   程序不能只做文本转换，必须先解析为 AST，再生成统一 IR，由虚拟控制器执行。这样才能支持断点、单步、暂停、恢复、变量监控、运动队列检查、报警追踪和路径回放。

3. 运动学内核独立

   TypeScript 负责业务调度、程序解释、仿真状态和 UI；KDL WASM 负责高性能数值计算。二者通过稳定 API 交互，避免把 C++ 对象模型直接泄漏到业务层。

4. Web 本地优先

   项目数据默认存储在 OPFS 中，不依赖服务器。需要提供导入、导出、备份、版本迁移和项目压缩包交换能力。

5. 可扩展到多品牌、多机器人、多工艺

   初期支持 6 轴串联工业机器人。架构上预留外部轴、变位机、导轨、多机器人、多任务、焊接、搬运、码垛、视觉偏移等扩展点。

6. 安全边界明确

   虚拟控制器用于离线编程与虚拟调试，不能直接替代真实控制器的安全功能。导出的品牌程序必须经过真实控制器校验、现场低速试运行和安全确认。

7. 路径对象优先

   商业 OLP 软件的核心不是单条 `MoveL`，而是可管理、可重算、可后处理的 Path 和 Operation。GRL 必须允许程序引用路径对象，也必须允许路径展开为显式运动指令。

8. 导入和导出同等重要

   虚拟控制器不仅要执行 GRL，也要能够解析主流品牌程序的可读文本形态，并转换为统一 IR。这样才能服务已有产线程序的虚拟调试、迁移和改造。

## 2.1 商业 OLP 的典型工作流

系统应支持以下典型工作流：

1. 新建工作站
   - 选择机器人模型。
   - 定义工具 TCP。
   - 定义工件坐标系。
   - 配置 IO 和后处理 profile。

2. 创建目标点
   - 手动输入关节或笛卡尔位姿。
   - 通过虚拟示教器 jog 生成点。
   - 从 CAD 点、曲线、边界、孔位、焊缝导入点。
   - 从已有品牌程序反解析目标点。

3. 创建路径
   - 选择目标点序列。
   - 设置默认运动类型、速度、过渡、工具、坐标系。
   - 设置姿态保持、法向跟随、切向跟随、固定姿态等姿态策略。
   - 自动检查可达性、关节限位、奇异点和路径连续性。

4. 创建操作
   - 搬运操作：接近、抓取、抬起、移动、放置、退出。
   - 焊接操作：引弧、焊接路径、收弧、清枪。
   - 喷涂操作：开喷、路径、关喷、重叠检查。
   - 打磨操作：接触、恒速路径、退出。

5. 生成 GRL 程序
   - 根据路径和操作模板自动生成程序。
   - 用户可查看和编辑 GRL。
   - 程序可重新编译为 IR。

6. 虚拟调试
   - 单步执行。
   - 断点。
   - IO 仿真。
   - 轨迹回放。
   - 检查报警、奇异点、越限、不可达点。

7. 后处理导出
   - 选择 ABB、FANUC、KUKA 等品牌。
   - 生成品牌程序和数据文件。
   - 生成转换报告。

8. 品牌程序导入
   - 导入 ABB RAPID、KUKA KRL、FANUC LS 等可读文本。
   - 解析为 Brand AST。
   - 转换为统一 IR 和 GRL。
   - 尽量恢复目标点、路径和操作结构。

## 2.2 商业级 OLP 能力矩阵

对标成熟离线编程商业软件，本项目应把能力分为“基础可用、商业可交付、产线级虚拟调试”三个层次。

| 能力域 | 基础可用 | 商业可交付 | 产线级虚拟调试 |
| --- | --- | --- | --- |
| 工作站建模 | 单机器人、工具、工件坐标 | 机器人库、工具库、夹具、输送线、工件、工位布局 | 多机器人、多工位、外部轴、PLC/HMI/安全设备 |
| 程序生成 | 手写 GRL、目标点运动 | Path/Operation 自动生成程序 | 从 CAD/工艺数据批量生成并版本化 |
| 机器人运动 | FK/IK、MoveJ/MoveL/MoveC | 可达性、关节限位、奇异点、姿态策略 | 品牌近似轨迹、节拍优化、外部轴协调 |
| 仿真验证 | 轨迹回放 | 碰撞检测、干涉区、工艺事件、IO trace | 真实 PLC/虚拟 PLC 联调、设备顺序验证 |
| 后处理 | ABB/FANUC/KUKA 文本输出 | 可配置 post profile、转换报告、品牌数据文件 | 程序上传/下载、品牌语义回读、现场差异追踪 |
| 调试 | 运行、暂停、单步、报警 | 断点、变量 watch、IO 面板、Wait 诊断 | 多任务、多设备、时间线、产线事件回放 |
| 数据管理 | OPFS 保存 | 项目包、资源库、模板、版本迁移 | 团队协作、权限、审阅、发布基线 |
| Sim-to-Real | 离线轨迹 | TCP/工件坐标标定、基准点偏差补偿 | 现场回传校准、程序差异比对、闭环修正 |

商业级产品的关键不是“能生成几行机器人代码”，而是能形成完整闭环：

```text
导入资源 -> 建站 -> 生成路径 -> 仿真验证 -> 虚拟调试 -> 后处理 -> 现场校准 -> 回读修正
```

## 2.3 商业级对象模型

现有 OLP Object Model 需要进一步扩展为商业软件常见的工作站资源模型：

```text
Station
  Cell
    RobotGroup
      Robot
      ExternalAxis
      Tool
      BaseFrame
    Fixture
    Part
    Conveyor
    SafetyZone
    InterferenceZone
    ProcessResource
  Programs
    GRL Program
    Imported Brand Program
    Generated Brand Program
  Planning
    Targets
    Paths
    Operations
    ProcessTemplates
  Validation
    CollisionSets
    ReachabilityReports
    CycleTimeReports
    IOTrace
    SimulationTrace
```

核心对象说明：

| 对象 | 说明 |
| --- | --- |
| `Station` | 一个完整离线编程项目，对应商业软件中的 station/cell/study |
| `Cell` | 工作站布局，包含机器人、工装、设备、工件 |
| `RobotGroup` | 机器人运动组，未来支持机器人 + 外部轴 |
| `Fixture` | 夹具或工装，带 IO 和运动状态 |
| `Part` | 工件模型、工艺曲线、孔位、焊缝、喷涂区域 |
| `Conveyor` | 输送线或变位输送设备 |
| `SafetyZone` | 安全区域、禁入区域、软限位区域 |
| `InterferenceZone` | 干涉区，用于多机器人互锁或等待 |
| `ProcessTemplate` | 搬运、焊接、喷涂、涂胶、打磨等工艺模板 |
| `ValidationReport` | 碰撞、可达性、节拍、IO、后处理报告 |

## 2.4 商业级功能模块

### 2.4.1 机器人与资源库

需要建立资源库机制，类似商业软件的机器人库、工具库、夹具库：

1. 机器人库
   - 品牌、型号、负载、臂展、轴数。
   - DH/URDF/自定义运动学参数。
   - 关节限位、速度、加速度。
   - 默认 tool/base。
   - 品牌后处理 profile。

2. 工具库
   - TCP。
   - 负载。
   - 3D 模型。
   - 工艺类型，例如夹爪、焊枪、喷枪、主轴。
   - IO 接口，例如夹紧、松开、到位反馈。

3. 工装与设备库
   - 夹具状态。
   - 运动机构。
   - IO 行为脚本。
   - 碰撞几何。

4. 工艺模板库
   - Pick and place。
   - Arc welding。
   - Spot welding。
   - Gluing/dispensing。
   - Painting/spraying。
   - Grinding/polishing。
   - Machining。

### 2.4.2 CAD 与几何导入

商业 OLP 软件通常围绕 CAD/几何创建路径。本项目应预留以下能力：

1. 导入格式
   - MVP：OBJ、STL、glTF。
   - 商业级：STEP、IGES、JT、3DXML 等可通过插件或服务端转换支持。

2. 几何提取
   - 点。
   - 边。
   - 曲线。
   - 面法向。
   - 孔位。
   - 焊缝。
   - 喷涂区域边界。

3. 路径生成
   - 曲线采样。
   - 等距采样。
   - 面法向姿态。
   - 切向姿态。
   - 路径平滑。
   - 接近/离开路径。
   - 自动避让偏移。

4. 数据保留
   - 每个 Path 应保留 CAD source ID。
   - 每个 Target 应保留来源曲线、采样序号、法向、切向。
   - CAD 更新后应能重建路径并保留用户覆盖参数。

### 2.4.3 可达性、碰撞和干涉验证

商业 OLP 的核心价值是提前发现问题。系统应设计以下验证层：

1. 可达性检查
   - IK 是否有解。
   - 是否有多解。
   - 是否符合配置约束。
   - 是否接近关节限位。
   - 是否接近奇异点。

2. 碰撞检测
   - 机器人自身碰撞。
   - 机器人与工件碰撞。
   - 工具与夹具碰撞。
   - 工件搬运过程碰撞。
   - 多机器人碰撞。

3. 干涉区
   - 定义区域。
   - 机器人进入/离开事件。
   - 与 IO/互锁结合。
   - 多机器人共享区域互锁。

4. 节拍分析
   - 单路径时间。
   - 单 Operation 时间。
   - 程序总周期。
   - wait 消耗时间。
   - IO/PLC 响应时间。
   - 瓶颈识别。

MVP 可以先做可达性、限位、奇异点和基础包围盒碰撞；商业级再做网格级碰撞、 swept volume、干涉区和节拍优化。

### 2.4.4 虚拟调试与虚拟调试联调

商业虚拟调试通常不仅运行机器人程序，还验证 PLC、HMI、夹具、输送线和安全逻辑。Web 版本可分阶段实现：

1. 内置逻辑仿真
   - IO 脚本。
   - 设备状态机。
   - 夹具/输送线/传感器仿真。

2. 外部协议联调
   - OPC UA。
   - MQTT。
   - WebSocket bridge。
   - 后续扩展 Modbus TCP、EtherNet/IP、Profinet 网关。

3. PLC 联调
   - 初期通过 WebSocket/OPC UA 接入外部模拟 PLC。
   - 商业级支持真实 PLC 或虚拟 PLC 的信号映射。
   - 所有外部信号进入统一 IO Service。

4. 时间线调试
   - Robot motion timeline。
   - IO timeline。
   - Wait timeline。
   - PLC event timeline。
   - Alarm timeline。

### 2.4.5 校准与 Sim-to-Real

商业离线编程必须考虑仿真到现场的偏差：

1. TCP 校准
   - 记录理论 TCP。
   - 支持现场测量 TCP 回填。
   - 对路径重新计算。

2. 工件坐标校准
   - 三点法/多点法。
   - 基准点拟合。
   - 工件偏移应用到 Path。

3. 机器人基座校准
   - 机器人相对工作站的位置修正。
   - 多机器人之间的基准统一。

4. 程序回读
   - 从现场控制器导回品牌程序。
   - 与离线版本比对。
   - 识别现场修改。

5. 补偿报告
   - TCP 偏差。
   - Frame 偏差。
   - Target 偏差。
   - 程序差异。

### 2.4.6 商业级报告

每次仿真和导出应能生成报告：

| 报告 | 内容 |
| --- | --- |
| Reachability Report | 不可达点、接近限位点、IK 解 |
| Collision Report | 碰撞对象、时间、路径点、严重程度 |
| Cycle Time Report | 总节拍、路径节拍、wait 时间、瓶颈 |
| IO Report | IO 映射、wait、pulse、脚本触发 |
| Post Report | 品牌映射、近似处理、不支持项 |
| Calibration Report | TCP、Frame、Base 偏差 |
| Import Report | 品牌程序导入结果、丢失语义、恢复对象 |

报告应可导出为 JSON 和 HTML。后续可增加 PDF。

## 3. 总体架构

系统分为 8 个核心层：

```text
HTML UI
  |
TypeScript App Shell
  |
Project Service / OPFS Workspace
  |
Program Parser / Semantic Analyzer / IR Compiler
  |
Virtual Controller Runtime
  |
Motion Planner / KDL WASM Adapter
  |
Robot Model / Scene Model / IO Model
  |
Post Processor: ABB RAPID / FANUC / KUKA KRL
```

### 3.1 主要模块

| 模块 | 职责 | 建议实现 |
| --- | --- | --- |
| UI Shell | 页面布局、编辑器、虚拟示教器、监控面板 | HTML + TypeScript |
| Workspace | 项目文件、索引、版本、导入导出 | OPFS + TypeScript |
| Station Model | 工作站、机器人、工具、工装、工件、设备对象 | TypeScript |
| Resource Library | 机器人库、工具库、夹具库、工艺模板库 | JSON + OPFS |
| Geometry Service | 几何导入、路径采样、碰撞几何 | TypeScript + Worker |
| Parser | 通用程序词法、语法解析 | TypeScript grammar-first parser |
| Semantic Analyzer | 类型检查、符号表、坐标系和目标点检查 | TypeScript |
| IR Compiler | AST 转可执行中间表示 | TypeScript |
| Virtual Controller | 程序执行、任务状态、变量、IO、报警、调试 | TypeScript |
| Motion Engine | 运动队列、插补、速度规划、过渡处理 | TypeScript + KDL WASM |
| KDL WASM Adapter | 正解、逆解、雅可比、轨迹基础计算 | C++ KDL 编译 WASM，TS 封装 |
| Validation Engine | 可达性、限位、奇异点、碰撞、节拍验证 | TypeScript + Worker |
| Post Processor | 通用 IR 转品牌程序 | TypeScript |
| Report Engine | 可达性、碰撞、节拍、IO、后处理报告 | TypeScript |
| Test Harness | 语法、语义、运动、后处理一致性测试 | TypeScript test runner |

### 3.2 推荐线程模型

Web 主线程只负责 UI 交互和轻量状态更新。以下模块建议放入 Web Worker：

1. KDL WASM 计算。
2. 程序解析和语义检查。
3. 长程序的虚拟执行和轨迹预计算。
4. OPFS 大文件读写，尤其是使用同步访问句柄时。
5. 碰撞检测和几何采样。
6. 长路径节拍分析和报告生成。

推荐结构：

```text
Main Thread
  - UI
  - editor
  - controller panel

Parser Worker
  - tokenize
  - parse
  - semantic check
  - diagnostics

Controller Worker
  - interpreter
  - execution clock
  - variable state
  - IO simulation
  - motion queue

KDL Worker
  - wasm initialization
  - FK/IK/Jacobian
  - trajectory sampling

Storage Worker
  - OPFS read/write
  - project snapshot
  - import/export
```

## 4. 技术要求

### 4.1 语言与平台

1. 虚拟控制器核心使用 TypeScript。
2. Web 界面使用 HTML，样式可使用 CSS，交互逻辑使用 TypeScript。
3. KDL 使用 C++ 编译为 WebAssembly，通过 TypeScript 调用。
4. 项目文件使用 OPFS 持久化。
5. 系统应能在现代 Chromium 系浏览器中稳定运行，后续再验证 Firefox、Safari 的兼容性。

### 4.2 数值与单位

系统内部统一单位：

| 类型 | 内部单位 |
| --- | --- |
| 长度 | meter |
| 角度 | radian |
| 线速度 | meter/second |
| 角速度 | radian/second |
| 时间 | second |
| 质量 | kilogram |

UI 和程序语言可以支持 `mm`、`deg`、`m/s`、`mm/s` 等显示和输入单位，但进入 IR 和 KDL 前必须规范化。

### 4.3 实时性要求

这是 Web 虚拟控制器，不追求真实伺服周期实时性，但需要可重复、可暂停、可回放：

1. 仿真逻辑周期建议默认 `4 ms` 或 `8 ms`，可配置。
2. UI 刷新周期不应绑定仿真周期，建议 `requestAnimationFrame` 渲染。
3. 运动轨迹采样应支持固定步长采样，例如 `4 ms`、`8 ms`、`12 ms`。
4. 同一输入项目、同一版本算法，应产生可重复的轨迹结果。

### 4.4 浏览器存储要求

1. 项目默认保存在 OPFS。
2. 支持导入导出 zip 项目包。
3. 支持自动保存、手动保存、快照、恢复。
4. 存储结构必须有 schema version，便于后续迁移。
5. 不能只依赖浏览器缓存，必须提供用户可导出的备份文件。

### 4.5 可测试性要求

1. 解析器必须有语法快照测试。
2. 语义分析必须有错误诊断测试。
3. 运动学必须有数值回归测试。
4. 后处理必须有 golden file 测试。
5. 虚拟控制器必须有程序执行状态机测试。

## 5. 通用机器人程序语言设计

通用机器人程序语言暂定名为 GRL，Generic Robot Language。名称可后续调整。

GRL 的目标不是复制某一家品牌语法，而是建立一个稳定的中间语言，能覆盖 ABB、FANUC、KUKA 的共同能力，并保留品牌扩展元数据。

### 5.1 对标对象

| 能力 | ABB RAPID | FANUC TP/KAREL | KUKA KRL | GRL 对应设计 |
| --- | --- | --- | --- | --- |
| 程序组织 | `MODULE`、`PROC`、`FUNC`、`TRAP` | TP 程序、`CALL`、标签；KAREL 程序 | `.src/.dat`、`DEF`、函数、数据文件 | `module`、`proc`、`func`、`trap` |
| 关节运动 | `MoveJ` | `J P[...]` | `PTP` | `movej` |
| 直线运动 | `MoveL` | `L P[...]` | `LIN` | `movel` |
| 圆弧运动 | `MoveC` | `C P[...]` | `CIRC` | `movec` |
| 目标点 | `robtarget`、`jointtarget` | `P[]`、`PR[]` | `E6POS`、`E6AXIS` | `PoseTarget`、`JointTarget` |
| 工具 | `tooldata` | Tool Frame / UTOOL | `$TOOL` | `Tool` |
| 工件/基坐标 | `wobjdata` | User Frame / UFRAME | `$BASE` | `Frame` |
| 速度 | `speeddata` | 百分比、`mm/sec` 等 | `$VEL`、`$ACC` | `Speed` |
| 过渡 | `zonedata`、`fine` | `FINE`、`CNT` | `C_DIS`、`C_PTP`、`APO` | `Zone` |
| IO | `SetDO`、`WaitDI` | `DO[]`、`DI[]`、`WAIT` | `$OUT[]`、`$IN[]`、`WAIT FOR` | `io.write`、`wait` |
| 条件 | `IF`、`TEST` | `IF`、`SELECT`、`LBL/JMP` | `IF`、`SWITCH`、`LOOP` | `if`、`switch`、`while`、`for`、`label` |
| 中断 | `TRAP`、interrupt | 条件监控和后台逻辑 | `INTERRUPT`、`BRAKE`、`RESUME` | `interrupt`、`trap` |
| 错误处理 | `ERROR`、`RAISE`、`UNDO` | Alarm、异常处理依版本而异 | `HALT`、`RESUME`、消息/中断 | `try`、`catch`、`raise`、`alarm` |

### 5.1.1 对标商业 OLP 的中性程序风格

商业 OLP 软件生成程序时，一般具有以下特征：

1. 目标点和运动语句分离

   目标点作为数据保存，程序中通过名称或编号引用。这样便于点位重算、批量修改、路径优化和后处理。

2. 路径和程序流程分离

   路径是可编辑对象，程序流程负责调用路径、控制 IO、处理条件。这样便于从 CAD 曲线、规划点、示教点生成路径，再自动生成程序。

3. 运动参数显式

   每条运动或路径段都能明确给出运动类型、速度、过渡、工具、坐标系。默认值可存在，但展开到 IR 时必须解析为确定值。

4. 工艺语义保留

   焊接、喷涂、打磨、搬运等不应只变成一串 MoveL。通用程序需要保留 operation 类型、工艺参数和路径引用，后处理器才能生成品牌特定工艺指令或注释。

5. 可展开、可回写

   `run_path weld_path` 可以展开为多条 `movel`/`movec`，也可以后处理为品牌程序。反过来，导入品牌程序时也应尽量恢复为 `path` 和 `target`。

因此，GRL 应同时支持两种写法：

1. 面向人类调试的显式运动语句。
2. 面向自动规划和后处理的路径/操作对象语句。

### 5.2 程序工程结构

推荐一个项目包含如下文件：

```text
project.json
robots/
  robot_1.robot.json
  tool_gripper.tool.json
  frame_fixture.frame.json
programs/
  main.grl
  weld.grl
targets/
  main.targets.json
paths/
  weld_path.path.json
operations/
  op_pick_place.operation.json
io/
  io_map.json
post/
  abb.profile.json
  fanuc.profile.json
  kuka.profile.json
generated/
  abb/
  fanuc/
  kuka/
logs/
  controller.log
  simulation.trace.jsonl
```

### 5.3 GRL 文件结构

示例：

```text
module Main

  persistent tool gripper = tool {
    tcp: pose(0 mm, 0 mm, 180 mm, 0 deg, 0 deg, 0 deg),
    mass: 2.5 kg
  }

  persistent frame fixture = frame {
    origin: pose(800 mm, 0 mm, 200 mm, 0 deg, 0 deg, 0 deg)
  }

  target home = joint_target {
    joints: [0 deg, -30 deg, 60 deg, 0 deg, 60 deg, 0 deg]
  }

  target pick = pose_target {
    pose: pose(500 mm, 120 mm, 300 mm, 180 deg, 0 deg, 90 deg),
    config: robot_config(0, 0, 1),
    tool: gripper,
    frame: fixture
  }

  path pick_path {
    defaults {
      tool: gripper,
      frame: fixture,
      speed: linear(300 mm/s),
      zone: z10
    }

    point approach movej target home speed joint(50%) zone fine
    point p1 movel target pick offset z 100 mm
    point p2 movel target pick zone fine
  }

  operation pick_place {
    kind: handling
    path: pick_path
    before p2:
      io.do[1] = true
    after p2:
      wait io.di[1] == true timeout 2 s
  }

  proc main()
    set_tool gripper
    set_frame fixture

    run_path pick_path

    wait io.di[1] == true timeout 2 s
    io.do[2] = true

    call place()
  end

  proc place()
    var pose_target p2 = pick offset z 100 mm
    movel p2 speed linear(200 mm/s) zone fine
  end

end
```

该示例体现两种程序形态：

1. `path pick_path` 适合由规划点、CAD 曲线、工艺模板自动生成。
2. `proc main()` 适合虚拟调试和流程控制。

### 5.4 顶层语法要求

GRL 至少支持以下顶层结构：

1. `module`：程序模块。
2. `import`：导入其他模块。
3. `persistent`：持久变量，类似 ABB `PERS`、KUKA `.dat` 中的持久数据、FANUC 寄存器/位置数据。
4. `const`：常量。
5. `var`：局部变量。
6. `target`：目标点。
7. `proc`：无返回值过程。
8. `func`：有返回值函数。
9. `trap`：中断处理例程。
10. `task`：多任务或后台任务定义，初期可只设计语义，不立即完整实现。
11. `path`：路径对象，由路径点、运动类型、姿态策略和工艺参数组成。
12. `operation`：工艺操作对象，引用 path 并绑定工艺行为。
13. `post_hint`：后处理提示，用于声明品牌输出偏好。

### 5.4.1 Path 语法

路径对象用于承载规划点和规划路径，是连接“自动路径规划”和“机器人程序生成”的核心结构。

```text
path weld_seam_01 {
  defaults {
    tool: weld_gun,
    frame: part_frame,
    speed: linear(120 mm/s),
    zone: z5,
    posture: follow_tangent,
    blend: continuous
  }

  point p_start movej target t_start speed joint(30%) zone fine
  point p001 movel target t001
  point p002 movel target t002
  point p003 movec via t_mid target t003
  event before p001 io.do[10] = true
  event after p003 io.do[10] = false
}
```

Path 语法要求：

1. 每个 `path` 有唯一名称。
2. `defaults` 定义默认工具、坐标系、速度、过渡、姿态策略。
3. `point` 定义路径点，可引用已有 target，也可内联 pose。
4. `event before/after` 用于绑定路径点附近的 IO 或工艺动作。
5. Path 可以在程序中通过 `run_path` 执行。
6. Path 可以在编译阶段展开为运动 IR。
7. Path 可以在后处理阶段展开为品牌运动指令和数据点。

### 5.4.2 Operation 语法

Operation 表达工艺语义，比 path 更高一层：

```text
operation weld_op_01 {
  kind: arc_welding
  path: weld_seam_01
  process {
    weld_id: "WELD_1"
    voltage: 24.0
    current: 180.0
    weave: none
  }
  start_action:
    io.do[20] = true
  end_action:
    io.do[20] = false
}
```

Operation 用途：

1. 保存工艺参数。
2. 驱动仿真时的工艺状态显示。
3. 生成品牌程序时映射到对应品牌的工艺包、IO 或注释。
4. 支持未来工艺库扩展。

首版 Operation 类型：

| 类型 | 用途 |
| --- | --- |
| `handling` | 搬运、上下料、抓取放置 |
| `arc_welding` | 弧焊 |
| `spot_welding` | 点焊 |
| `dispensing` | 涂胶 |
| `spraying` | 喷涂 |
| `grinding` | 打磨 |
| `generic_path` | 通用路径 |

### 5.4.3 自动路径生成到 GRL 的要求

从规划点和规划路径生成 GRL 时，应遵循以下规则：

1. 每个规划点生成稳定 target 名称，例如 `P001`、`P002`，或基于工艺语义命名。
2. 路径整体生成 `path` 对象，而不是直接散落在 `proc main()` 中。
3. 路径默认参数写入 `defaults`，单点差异写在对应 `point` 上。
4. 接近点、离开点、工艺开始点、工艺结束点必须明确标注。
5. IO、焊接开关、夹爪动作等应生成 `event before/after` 或 Operation action。
6. 若路径来自 CAD 曲线，应保留来源引用，例如曲线 ID、采样距离、法向策略。
7. 编译器应能把 path 展开为确定的运动 IR，保证虚拟控制器不依赖 UI 对象也能运行。

示例：

```text
path curve_032_generated {
  source {
    type: cad_curve
    id: "edge_032"
    sample_distance: 5 mm
    normal_strategy: surface_normal
  }
  defaults {
    tool: spray_gun
    frame: part_frame
    speed: linear(500 mm/s)
    zone: z20
    posture: follow_normal
  }
  point p000 movel target T_curve_032_000 zone fine
  point p001 movel target T_curve_032_001
  point p002 movel target T_curve_032_002
}
```

### 5.4.4 `run_path` 和 `run_operation`

程序流程中建议优先调用路径或操作：

```text
proc main()
  run_operation weld_op_01
  run_path retract_path
end
```

编译语义：

1. `run_path path_name` 展开为 path 中的 point 和 event。
2. `run_operation op_name` 展开为 start action、path、end action。
3. 展开后的 IR 保留 source mapping，调试时仍能定位到 path 点和 operation。
4. 后处理器可选择直接展开，也可以按品牌能力生成更紧凑的结构。

### 5.4.5 显式运动和路径调用的关系

GRL 同时允许：

```text
movel pick speed linear(300 mm/s) zone z10
run_path pick_path
```

约束：

1. 手写程序、调试程序、短逻辑程序可直接写 `movej/movel/movec`。
2. 自动规划、CAD-to-path、批量目标点应生成 `path`。
3. 后处理器对两者生成的品牌运动语句应一致。
4. 虚拟控制器执行时二者最终都进入同一 Motion IR。

### 5.5 类型系统

基础类型：

| 类型 | 说明 |
| --- | --- |
| `bool` | 布尔 |
| `int` | 整数 |
| `real` | 浮点数 |
| `string` | 字符串 |
| `time` | 时间 |
| `length` | 长度 |
| `angle` | 角度 |

机器人类型：

| 类型 | 说明 |
| --- | --- |
| `Pose` | 位置和姿态 |
| `JointArray` | 关节角数组 |
| `PoseTarget` | 笛卡尔目标点 |
| `JointTarget` | 关节目标点 |
| `Tool` | 工具数据 |
| `Frame` | 基坐标/工件坐标 |
| `Speed` | 速度数据 |
| `Zone` | 过渡/逼近数据 |
| `Load` | 负载数据 |
| `RobotConfig` | 姿态配置，如肩、肘、腕配置 |
| `ExtAxis` | 外部轴数据 |
| `Path` | 路径对象 |
| `PathPoint` | 路径点 |
| `Operation` | 工艺操作 |
| `ProcessParam` | 工艺参数 |

### 5.6 运动指令

必须支持：

```text
movej target speed Speed zone Zone [tool Tool] [frame Frame]
movel target speed Speed zone Zone [tool Tool] [frame Frame]
movec via target speed Speed zone Zone [tool Tool] [frame Frame]
stop_motion
hold
resume
run_path path_name
run_operation operation_name
```

运动语义要求：

1. `movej` 表示关节空间运动：机器人按各轴关节角度差分运行，关节同起同停，TCP 轨迹不要求是直线。
2. `movel` 表示 TCP 直线运动：TCP 沿起点到终点的空间直线运行，关节角由每个采样点 IK 求解。
3. `movec` 表示 TCP 圆弧运动：TCP 经过 via 点并沿圆弧运行，关节角由每个圆弧采样点 IK 求解。
4. `zone fine` 表示精确到点，不做过渡。
5. `zone z10` 表示允许在目标点附近按半径或品牌等价参数过渡。
6. 每条运动必须绑定当前 `tool`、当前 `frame`、速度、过渡方式。
7. 如果目标点本身指定了 `tool` 或 `frame`，需要定义优先级。建议：指令显式参数最高，其次目标点属性，最后控制器当前状态。

### 5.7 逻辑与流程控制

必须支持：

```text
if condition
  ...
elseif condition
  ...
else
  ...
end

while condition
  ...
end

for i = 0 to 10
  ...
end

switch value
  case 1
    ...
  default
    ...
end

label retry
jump retry
call sub()
return
```

FANUC TP 程序常见标签跳转模型必须能映射到 GRL，但 GRL 新程序建议优先使用结构化控制流。

### 5.8 IO 与等待

示例：

```text
io.do[1] = true
io.go[1] = 16
wait io.di[1] == true
wait io.ai[2] > 3.5 timeout 1.5 s
pulse io.do[3] duration 200 ms
wait rising(io.di[4]) timeout 5 s
wait all(io.di[1] == true, io.di[2] == false)
wait any(io.di[10] == true, timer.done("T_PICK"))
```

要求：

1. 支持 DI、DO、AI、AO、GI、GO。
2. 支持别名，例如 `clamp_closed` 映射到 `di[5]`。
3. 支持等待超时。
4. 支持虚拟 IO 脚本和手动面板输入。
5. 后处理时映射到 ABB、FANUC、KUKA 对应 IO 表达。

### 5.8.1 IO 点类型

通用 IO 类型：

| 类型 | 说明 | 常见品牌映射 |
| --- | --- | --- |
| `DI` | 数字输入 | ABB `DI`、FANUC `DI[]`、KUKA `$IN[]` |
| `DO` | 数字输出 | ABB `DO`、FANUC `DO[]`、KUKA `$OUT[]` |
| `AI` | 模拟输入 | ABB `AI`、FANUC `AI[]`、KUKA analog input |
| `AO` | 模拟输出 | ABB `AO`、FANUC `AO[]`、KUKA analog output |
| `GI` | 组输入，整数 | FANUC `GI[]`、品牌寄存器组合 |
| `GO` | 组输出，整数 | FANUC `GO[]`、品牌寄存器组合 |
| `RI` | 机器人输入，可选 | FANUC `RI[]`，初期可映射为 DI |
| `RO` | 机器人输出，可选 | FANUC `RO[]`，初期可映射为 DO |

推荐 GRL IO 访问形式：

```text
io.di[1]
io.do[2]
io.ai[1]
io.ao[1]
io.gi[1]
io.go[1]
io.alias.clamp_closed
```

其中 `io.alias.xxx` 由 IO map 映射到实际点位，便于后处理和跨品牌迁移。

### 5.8.2 IO 映射文件

项目应包含 `io/io_map.json`：

```json
{
  "schemaVersion": 1,
  "signals": [
    {
      "name": "clamp_close_cmd",
      "type": "DO",
      "index": 1,
      "initial": false,
      "description": "Close clamp command",
      "brand": {
        "abb": "doClampClose",
        "fanuc": "DO[1]",
        "kuka": "$OUT[1]"
      }
    },
    {
      "name": "clamp_closed",
      "type": "DI",
      "index": 1,
      "initial": false,
      "description": "Clamp closed sensor",
      "brand": {
        "abb": "diClampClosed",
        "fanuc": "DI[1]",
        "kuka": "$IN[1]"
      }
    }
  ],
  "groups": [
    {
      "name": "part_id",
      "type": "GI",
      "index": 1,
      "bits": ["DI[10]", "DI[11]", "DI[12]", "DI[13]"],
      "initial": 0
    }
  ]
}
```

要求：

1. `name` 在项目内唯一。
2. `type + index` 组合唯一。
3. `initial` 定义仿真启动默认值。
4. `brand` 定义后处理映射。
5. `groups` 定义组信号与 bit 信号的关系。

### 5.8.3 Wait 语义

`wait` 是虚拟调试的关键指令，必须可暂停、可恢复、可超时、可诊断。

语法：

```text
wait condition [timeout duration] [on_timeout label_or_proc]
```

示例：

```text
wait io.di[1] == true
wait io.alias.clamp_closed == true timeout 2 s
wait io.ai[1] >= 3.5 timeout 500 ms on_timeout clamp_timeout
wait rising(io.di[4]) timeout 5 s
wait falling(io.di[5])
wait changed(io.gi[1])
wait all(io.di[1], !io.di[2], io.gi[1] == 7)
wait any(io.di[10], io.di[11])
```

执行要求：

1. 如果条件当前为真，`wait` 立即完成。
2. 如果条件当前为假，虚拟控制器进入 `Waiting` 子状态，但控制器总状态仍可显示为 `Running/Waiting`。
3. 等待期间程序计数器停留在 wait 指令。
4. 等待期间运动队列默认应已停止在上一条同步点；如果允许后台运动与等待并行，必须显式设计异步语义，首版不建议支持。
5. 超时后产生结构化报警或跳转到 `on_timeout`。
6. 用户在 IO 面板手动改变输入时，wait 应在下一个 controller tick 被重新评估。
7. `hold` 暂停时，wait 的超时计时器也暂停；`resume` 后继续计时。
8. `stop` 停止时，wait 被取消。
9. trace 中必须记录 wait 开始、完成、超时、取消。

### 5.8.4 Wait 条件表达式限制

为了保证可预测性，首版 wait 条件建议只允许：

1. IO 读值。
2. 变量读值。
3. 常量。
4. 比较运算：`==`、`!=`、`>`、`>=`、`<`、`<=`。
5. 逻辑运算：`and`、`or`、`not`。
6. 边沿函数：`rising()`、`falling()`、`changed()`。
7. 组合函数：`all()`、`any()`。
8. 定时器状态，例如 `timer.done("T1")`。

不建议在 wait 条件中允许：

1. 修改变量。
2. 调用可能有副作用的函数。
3. 调用 KDL 运动学计算。
4. 文件读写。
5. 网络请求。

### 5.8.5 IO 脚本

为了虚拟调试，系统需要支持 IO 脚本模拟外部夹具、PLC、传感器。

示例：

```text
io_script clamp_sim {
  when io.do[1] == true delay 300 ms:
    io.di[1] = true

  when io.do[1] == false delay 200 ms:
    io.di[1] = false
}
```

用途：

1. 模拟夹爪闭合反馈。
2. 模拟传感器到位信号。
3. 模拟 PLC 对机器人 DO 的响应。
4. 自动完成测试，不需要人工点 IO。

执行要求：

1. IO 脚本运行在 Controller Worker 或独立 IO Worker。
2. IO 脚本只能修改被标记为 virtual/simulated 的输入信号，避免混淆真实输出。
3. IO 脚本触发和写入必须进入 IO event log。
4. IO 脚本可以启停。
5. IO 脚本必须可重置。

### 5.8.6 Pulse 语义

`pulse` 用于输出一个短脉冲：

```text
pulse io.do[3] duration 200 ms
```

执行语义：

1. 立即将 DO 置为 true。
2. 注册一个定时事件，在 duration 后置回 false。
3. 如果程序被 hold，pulse 定时器是否暂停需要可配置。建议首版随控制器虚拟时间暂停。
4. 如果 stop，未完成 pulse 应恢复为安全默认值，通常为 false。
5. trace 记录 pulse start 和 pulse end。

### 5.8.7 IO 与 Wait 的品牌映射

后处理时必须将 GRL IO 和 wait 语义转换到品牌语法：

| GRL | ABB RAPID | FANUC LS/TP 风格 | KUKA KRL |
| --- | --- | --- | --- |
| `io.do[1] = true` | `SetDO do1, 1;` | `DO[1]=ON ;` | `$OUT[1]=TRUE` |
| `io.do[1] = false` | `SetDO do1, 0;` | `DO[1]=OFF ;` | `$OUT[1]=FALSE` |
| `wait io.di[1] == true` | `WaitDI di1, 1;` 或 `WaitUntil di1=1;` | `WAIT DI[1]=ON ;` | `WAIT FOR $IN[1]` |
| `wait ... timeout 2 s` | 品牌支持时使用超时语义，否则生成计时循环 | 生成 timer/register 逻辑或报警跳转 | 生成计时逻辑或 `WAIT FOR` 近似 |
| `pulse io.do[3] duration 200 ms` | `PulseDO do3, 0.2;` 或展开 | `PULSE DO[3]` 或展开 | `$OUT[3]=TRUE; WAIT SEC 0.2; $OUT[3]=FALSE` |

要求：

1. 简单 IO 写入必须直接映射为品牌原生 IO。
2. 简单 wait 必须直接映射为品牌原生等待。
3. 复杂 wait 表达式如果目标品牌不支持，应展开为条件循环、计时器和报警逻辑。
4. 边沿 wait 如果品牌不支持，应生成前值缓存逻辑或给出不支持诊断。
5. 后处理报告必须说明哪些 wait/pulse 被原生映射，哪些被展开或近似处理。

### 5.9 中断与异常

通用语义：

```text
interrupt clamp_lost when io.di[5] == false do trap_clamp_lost

trap trap_clamp_lost()
  stop_motion
  alarm 1001 "Clamp lost"
end
```

初期实现建议：

1. 支持条件中断注册。
2. 支持中断触发后暂停当前程序。
3. 支持报警产生。
4. 暂不模拟真实品牌控制器全部中断细节，但 IR 中保留中断元数据，便于后处理。

### 5.10 品牌扩展

GRL 需要允许品牌扩展属性，不能为了通用性丢失信息：

```text
@brand.abb {
  conf_l: true
}

@brand.kuka {
  advance: 3
}

@brand.fanuc {
  group: 1
}
```

扩展属性只影响对应品牌后处理，不应破坏通用仿真。

## 6. 解析器与编译流程

### 6.1 编译管线

```text
Source Text
  -> Lexer
  -> Parser
  -> AST
  -> Symbol Table
  -> Semantic Analyzer
  -> IR
  -> Virtual Controller Runtime
  -> Post Processor
```

完整商业 OLP 管线建议扩展为：

```text
OLP Object Model
  - robots
  - tools
  - frames
  - targets
  - paths
  - operations
  |
  v
GRL Source
  |
  v
GRL AST
  |
  v
Executable IR
  |
  +--> Virtual Controller Runtime
  |
  +--> Post Processor
        +--> ABB RAPID
        +--> FANUC LS/TP-compatible text
        +--> KUKA KRL SRC/DAT
```

品牌程序导入管线：

```text
ABB/FANUC/KUKA Source
  -> Brand Lexer
  -> Brand Parser
  -> Brand AST
  -> Brand Semantic Normalizer
  -> Executable IR
  -> Reconstructed GRL / OLP Object Model
  -> Virtual Controller Runtime
```

### 6.2 AST 要求

AST 必须保留：

1. 源文件路径。
2. 起止行列号。
3. 注释位置，便于格式化和后处理保留注释。
4. 原始单位文本和规范化数值。
5. 品牌扩展元数据。

### 6.2.1 三类 AST

系统需要区分三类 AST：

1. GRL AST
   - 表示通用机器人程序。
   - 用于语义检查、格式化、诊断和编译 IR。

2. Brand AST
   - 表示 ABB RAPID、FANUC LS、KUKA KRL 等品牌源程序。
   - 尽量忠实保留品牌语法和源代码位置。
   - 用于品牌程序导入、诊断、转换报告。

3. OLP Model AST
   - 表示工作站对象、路径、操作、工艺参数。
   - 可来自 UI 创建、CAD 生成、GRL 解析或品牌程序反解析。

不要用一个 AST 同时承担三种职责，否则后续导入导出和路径重算会变得难维护。

### 6.3 语义检查

必须检查：

1. 变量是否声明。
2. 目标点类型是否匹配运动指令。
3. 工具、坐标系是否存在。
4. 单位是否正确。
5. IO 地址是否越界。
6. 子程序参数数量和类型是否匹配。
7. 运动指令是否缺失速度或过渡参数。
8. 圆弧运动中起点、过渡点、终点是否退化。
9. 逆解是否有可行解。
10. 关节是否超过软限位。
11. 是否存在不可到达目标点。
12. 是否存在未处理的后处理限制。
13. Path 是否存在空路径、重复点名、非法事件绑定。
14. Operation 是否引用不存在的 path。
15. 自动生成路径是否保留必要的 source metadata。
16. 品牌程序导入后是否存在无法恢复的语义。

### 6.4 IR 设计

IR 不应是品牌文本，而应是可执行指令对象：

```ts
type IrInstruction =
  | MotionInstruction
  | AssignInstruction
  | WaitInstruction
  | CallInstruction
  | BranchInstruction
  | IoInstruction
  | AlarmInstruction
  | ReturnInstruction;
```

运动 IR 示例：

```ts
interface MotionInstruction {
  kind: "motion";
  motionType: "joint" | "linear" | "circular";
  target: TargetRef | ResolvedTarget;
  via?: TargetRef | ResolvedTarget;
  speed: SpeedSpec;
  zone: ZoneSpec;
  tool: ToolRef;
  frame: FrameRef;
  sourceRange: SourceRange;
  brandMeta?: Record<string, unknown>;
}
```

### 6.5 OLP 对象模型

商业离线编程软件通常以对象树组织程序，而不是只以文本文件组织。建议内部定义 OLP Object Model：

```ts
interface OlpProjectModel {
  robots: RobotModel[];
  tools: ToolModel[];
  frames: FrameModel[];
  targets: TargetModel[];
  paths: PathModel[];
  operations: OperationModel[];
  programs: ProgramModel[];
  postProfiles: PostProfile[];
}

interface PathModel {
  id: string;
  name: string;
  robotId: string;
  defaultToolId?: string;
  defaultFrameId?: string;
  defaultSpeed?: SpeedSpec;
  defaultZone?: ZoneSpec;
  postureStrategy?: PostureStrategy;
  source?: PathSource;
  points: PathPointModel[];
  events: PathEventModel[];
}

interface PathPointModel {
  id: string;
  name: string;
  motionType: "joint" | "linear" | "circular";
  targetId?: string;
  target?: ResolvedTarget;
  viaTargetId?: string;
  speed?: SpeedSpec;
  zone?: ZoneSpec;
  toolId?: string;
  frameId?: string;
  process?: Record<string, unknown>;
}
```

该模型的用途：

1. UI 文件树和路径编辑器直接操作它。
2. 从规划点生成程序时先生成它。
3. GRL 编译前可由它生成 GRL。
4. 品牌程序导入后可尽量恢复它。
5. 后处理和虚拟控制器最终仍以 IR 为准。

### 6.6 品牌程序导入解析

虚拟控制器应能解析多品牌机器人的可读程序文本，并统一执行。首版建议支持以下输入：

| 品牌 | 首版导入格式 | 说明 |
| --- | --- | --- |
| ABB | RAPID `.mod/.sys` 文本 | 解析 `MODULE`、`PROC`、`MoveJ`、`MoveL`、`MoveC`、`robtarget`、`tooldata`、`wobjdata` |
| KUKA | KRL `.src/.dat` 文本 | 解析 `DEF`、`PTP`、`LIN`、`CIRC`、`E6POS`、`E6AXIS`、`$TOOL`、`$BASE` |
| FANUC | LS 风格文本或可读 TP 导出 | 解析 `J`、`L`、`C`、`P[]`、`PR[]`、`UTOOL`、`UFRAME`、`CALL`、`LBL/JMP` |

导入目标不是 100% 还原真实控制器所有行为，而是：

1. 能提取目标点。
2. 能提取运动序列。
3. 能提取工具和坐标系引用。
4. 能提取速度和过渡。
5. 能提取主要 IO 和流程控制。
6. 能转换为统一 IR，在虚拟控制器中执行。
7. 能生成转换报告，标明不支持或近似处理的语义。

### 6.6.1 品牌导入转换示例

ABB RAPID：

```text
MoveL pick, v300, z10, gripper\WObj:=fixture;
```

转换为 GRL：

```text
movel pick speed linear(300 mm/s) zone z10 tool gripper frame fixture
```

KUKA KRL：

```text
$VEL.CP = 0.3
LIN XPICK C_DIS
```

转换为 GRL：

```text
movel XPICK speed linear(300 mm/s) zone continuous
```

FANUC LS：

```text
L P[10] 300mm/sec CNT10 ;
```

转换为 GRL：

```text
movel P10 speed linear(300 mm/s) zone cnt(10)
```

### 6.6.2 品牌程序导入限制

必须明确处理以下限制：

1. 品牌控制器内部系统变量不能全部等价映射。
2. 品牌工艺包指令可能需要插件解析。
3. FANUC 二进制 TP 不能直接作为首版目标，优先处理 LS 或文本导出。
4. KUKA `$ADVANCE`、逼近、异步运动等语义需要近似或专项实现。
5. ABB RAPID 的复杂错误处理和多任务需要分阶段支持。
6. 导入后的程序必须附带转换报告，不能假装完全等价。

### 6.7 GRL 生成器

从 OLP Model 生成 GRL 的组件称为 GRL Generator：

```text
OlpProjectModel
  -> GrlGenerator
  -> .grl source files
```

要求：

1. 生成稳定、可读、可 diff 的文本。
2. 保留路径和操作结构，不要默认全部展开成散乱运动语句。
3. 生成的 target 名称稳定。
4. 生成的程序可以再次解析回同等 OLP Model。
5. 支持配置生成风格：
   - compact：多用 `run_path`。
   - expanded：展开为 `movej/movel/movec`。
   - debug：保留更多注释和 source metadata。

## 7. 虚拟控制器设计

虚拟控制器需要支持两类输入：

1. GRL 程序
   - 由用户手写。
   - 由 OLP 对象模型自动生成。
   - 由路径和操作模板生成。

2. 品牌程序
   - ABB RAPID 文本。
   - KUKA KRL 文本。
   - FANUC LS 或可读导出文本。
   - 先解析为 Brand AST，再转换为统一 IR。

虚拟控制器真正执行的是统一 IR，而不是直接解释某个品牌文本。这样才能保证虚拟调试、路径重算、跨品牌后处理和报警诊断使用同一套运行时。

### 7.1 控制器状态机

建议状态：

```text
PowerOff
  -> Booting
  -> MotorsOff
  -> Ready
  -> Manual
  -> Auto
  -> Running
  -> Hold
  -> Fault
  -> EmergencyStop
```

基础命令：

| 命令 | 说明 |
| --- | --- |
| `powerOn` | 上电 |
| `powerOff` | 下电 |
| `motorsOn` | 电机上使能 |
| `motorsOff` | 电机下使能 |
| `loadProgram` | 加载程序 |
| `start` | 启动 |
| `hold` | 暂停 |
| `resume` | 继续 |
| `stop` | 停止 |
| `resetFault` | 复位报警 |
| `stepInto` | 单步进入 |
| `stepOver` | 单步越过 |
| `stepMotion` | 单条运动执行 |

### 7.2 执行模型

虚拟控制器包含：

1. Program Counter：当前执行位置。
2. Call Stack：调用栈。
3. Scope Stack：变量作用域。
4. Motion Queue：运动队列。
5. IO Image：IO 镜像。
6. Timer Table：定时器。
7. Interrupt Table：中断表。
8. Alarm Queue：报警队列。
9. Trace Buffer：执行轨迹。
10. Source Map：IR 到 GRL、Path、Operation 或品牌源程序的映射。
11. Brand Context：当输入来自品牌程序时，保存品牌语义上下文和转换警告。
12. IO Service：IO 点表、别名表、事件队列、边沿检测、等待条件调度。

### 7.3 任务模型

初期支持单主任务：

```text
Task MAIN
  - program: Main.main
  - motion group: robot_1
```

后续扩展：

1. 后台任务，例如 PLC-like 逻辑。
2. 多机器人任务。
3. 独立 IO 任务。
4. 监控任务。
5. 协作运动任务。

### 7.4 运动队列

虚拟控制器不能执行一条运动就结束，而要模拟真实控制器的 look-ahead：

1. 程序解释器将运动指令推入 Motion Queue。
2. Motion Planner 根据速度、过渡、当前姿态生成轨迹。
3. Controller Tick 按仿真时间推进。
4. UI 读取当前关节、TCP、目标点、轨迹和状态。

运动队列字段：

```ts
interface MotionQueueItem {
  id: string;
  instructionId: string;
  pathId?: string;
  pathPointId?: string;
  operationId?: string;
  type: "joint" | "linear" | "circular";
  startJoint: number[];
  endJoint: number[];
  startPose: Pose;
  endPose: Pose;
  viaPose?: Pose;
  speed: SpeedSpec;
  zone: ZoneSpec;
  samples?: TrajectorySample[];
  status: "pending" | "planned" | "running" | "done" | "failed";
}
```

当运动来自 `path` 或 `operation` 时，运动队列必须保留路径点来源。UI 才能在路径表、程序文本、3D 轨迹之间联动定位。

### 7.4.1 Path 执行语义

`run_path` 执行过程：

1. 读取 PathModel。
2. 合并 path defaults 和 point overrides。
3. 解析每个目标点的 tool、frame、speed、zone。
4. 触发 `event before`。
5. 将运动点展开为 MotionQueueItem。
6. 运动完成后触发 `event after`。
7. 记录 trace，包含 pathId 和 pathPointId。

`run_operation` 执行过程：

1. 读取 OperationModel。
2. 执行 start action。
3. 执行引用 path。
4. 执行 end action。
5. 将工艺状态写入 trace。

### 7.4.2 品牌程序执行语义

品牌程序导入后执行过程：

1. Brand AST 转统一 IR。
2. 每条 IR 保留品牌源程序行号。
3. 品牌特有语义被转换为：
   - 等价 IR。
   - 近似 IR。
   - 不支持诊断。
4. 虚拟控制器执行 IR。
5. UI 调试时可以显示品牌源代码当前行，也可以显示转换后的 GRL/IR。

示例：

```text
KUKA LIN XPICK C_DIS
  -> Brand AST
  -> MotionInstruction(linear, target=XPICK, zone=continuous)
  -> MotionQueueItem
```

### 7.5 报警与诊断

报警必须结构化：

```ts
interface ControllerAlarm {
  code: number;
  severity: "info" | "warning" | "error" | "fatal";
  message: string;
  sourceRange?: SourceRange;
  timestamp: number;
  detail?: unknown;
}
```

常见报警：

1. 程序语法错误。
2. 类型错误。
3. 未定义目标点。
4. IK 求解失败。
5. 目标点超限。
6. 奇异点风险。
7. 圆弧退化。
8. IO 等待超时。
9. 后处理不支持某指令。
10. 品牌程序导入语义不完整。
11. Path 展开失败。
12. Operation 工艺参数缺失。

### 7.6 虚拟 IO 实施方案

虚拟 IO 是虚拟调试的核心能力。它用于模拟机器人控制器与夹具、PLC、安全门、传感器、工艺设备之间的信号交互。

#### 7.6.1 IO 架构

```text
Controller Runtime
  |
  +-- IO Service
      |
      +-- IO Image
      +-- IO Alias Table
      +-- IO Event Queue
      +-- Wait Registry
      +-- Edge Detector
      +-- IO Script Engine
      +-- IO Trace Logger
```

IO Service 职责：

1. 保存当前 IO 镜像。
2. 提供读写接口。
3. 管理 IO 别名。
4. 检测边沿和变化。
5. 调度 wait 条件。
6. 执行 pulse 定时恢复。
7. 执行 IO 脚本。
8. 记录 IO 事件日志。
9. 向 UI 推送 IO 变化。

#### 7.6.2 IO Image 数据结构

```ts
type IoSignalType = "DI" | "DO" | "AI" | "AO" | "GI" | "GO" | "RI" | "RO";

interface IoSignalDef {
  id: string;
  name: string;
  type: IoSignalType;
  index: number;
  initial: boolean | number;
  writableByProgram: boolean;
  writableByUser: boolean;
  writableByScript: boolean;
  description?: string;
  brand?: Record<string, string>;
}

interface IoSignalState {
  id: string;
  type: IoSignalType;
  index: number;
  value: boolean | number;
  previousValue: boolean | number;
  updatedAt: number;
  source: "program" | "user" | "script" | "import" | "reset";
}

interface IoImage {
  signals: Map<string, IoSignalState>;
  byAddress: Map<string, string>;
  aliases: Map<string, string>;
}
```

地址规范：

```text
DI[1] -> io.di[1]
DO[1] -> io.do[1]
AI[1] -> io.ai[1]
AO[1] -> io.ao[1]
GI[1] -> io.gi[1]
GO[1] -> io.go[1]
```

#### 7.6.3 IO 读写规则

1. 程序可写 DO、AO、GO、RO。
2. 程序默认不可写 DI、AI、GI、RI，除非该信号配置为 simulated writable。
3. 用户可在 IO 面板手动修改虚拟输入 DI、AI、GI、RI。
4. IO 脚本可修改配置允许的虚拟输入。
5. 所有写入必须经过 IO Service，不能直接改 Map。
6. 每次写入都生成 IoEvent。
7. 重复写入相同值可配置是否记录。建议默认记录程序写入，但 UI 可折叠显示。

```ts
interface IoWriteRequest {
  addressOrAlias: string;
  value: boolean | number;
  source: "program" | "user" | "script" | "import" | "reset";
  timestamp: number;
  instructionId?: string;
}

interface IoEvent {
  id: string;
  signalId: string;
  oldValue: boolean | number;
  newValue: boolean | number;
  source: "program" | "user" | "script" | "import" | "reset";
  timestamp: number;
  instructionId?: string;
}
```

#### 7.6.4 WaitInstruction IR

```ts
interface WaitInstruction {
  kind: "wait";
  condition: ExpressionNode;
  timeoutMs?: number;
  onTimeout?: {
    kind: "alarm" | "jump" | "call" | "continue";
    target?: string;
    alarmCode?: number;
    message?: string;
  };
  sourceRange: SourceRange;
}
```

执行状态：

```ts
interface ActiveWait {
  id: string;
  instructionId: string;
  condition: CompiledExpression;
  startedAtVirtualTime: number;
  timeoutAtVirtualTime?: number;
  status: "waiting" | "completed" | "timeout" | "cancelled";
}
```

#### 7.6.5 Wait 调度流程

控制器执行到 wait：

```text
1. 编译或读取 WaitInstruction 条件表达式。
2. 立即评估一次 condition。
3. 若为 true，PC 前进，记录 wait completed immediate。
4. 若为 false，创建 ActiveWait，控制器进入 Running/Waiting。
5. 每个 controller tick 或 IO 变化事件触发重新评估。
6. 条件为 true 时，ActiveWait completed，PC 前进。
7. 虚拟时间超过 timeout 时，执行 onTimeout 或产生报警。
8. hold 时暂停 timeout 虚拟时间。
9. stop/reset 时取消 ActiveWait。
```

伪代码：

```ts
function executeWait(instruction: WaitInstruction): StepResult {
  if (evalCondition(instruction.condition)) {
    traceWait("completed-immediate", instruction);
    return { pc: "next" };
  }

  waitRegistry.add({
    id: newId(),
    instructionId: instruction.id,
    condition: compileExpression(instruction.condition),
    startedAtVirtualTime: clock.now(),
    timeoutAtVirtualTime: instruction.timeoutMs
      ? clock.now() + instruction.timeoutMs
      : undefined,
    status: "waiting",
  });

  return { pc: "stay", state: "waiting" };
}
```

#### 7.6.6 边沿检测

边沿函数：

```text
rising(io.di[1])
falling(io.di[1])
changed(io.gi[1])
```

实现要求：

1. IO Service 在每次 tick 开始保存 previousValue。
2. IO 写入发生后更新 current value。
3. wait 条件评估时可读取 previous/current。
4. 边沿只在一个 tick 内有效。
5. 如果多个 IO 事件在同一 tick 内发生，按事件顺序处理，并在 trace 中保留顺序。

#### 7.6.7 IO 与虚拟时间

虚拟调试必须使用 controller virtual time，而不是直接使用 wall-clock：

1. `wait timeout` 基于虚拟时间。
2. `pulse duration` 基于虚拟时间。
3. IO 脚本 `delay` 基于虚拟时间。
4. hold 时虚拟时间暂停。
5. 单步模式下虚拟时间按 step 推进。
6. 快进回放时虚拟时间可加速，但事件顺序必须保持。

#### 7.6.8 Wait 与运动同步

首版建议采用同步语义：

1. `movel/movej/movec` 完成后才执行下一条 wait。
2. `wait` 完成后才执行后续运动。
3. 不支持品牌控制器中的复杂并行 advance run 行为。

后续可扩展：

1. 允许提前规划运动队列。
2. 支持路径事件触发 IO。
3. 支持运动中 wait 或 sensor search。
4. 支持品牌特定 advance run 近似。

#### 7.6.9 IO Trace

IO trace 需要记录：

```ts
interface IoTraceRecord {
  time: number;
  kind: "read" | "write" | "wait-start" | "wait-done" | "wait-timeout" | "pulse-start" | "pulse-end";
  signal?: string;
  value?: boolean | number;
  source?: string;
  instructionId?: string;
  programLine?: number;
}
```

用途：

1. 回放虚拟调试过程。
2. 分析 wait 卡住原因。
3. 生成调试报告。
4. 帮助后处理验证 IO 映射。

#### 7.6.10 Wait 卡住诊断

当程序停在 wait 时，UI 和报警系统应显示：

1. 当前等待表达式。
2. 当前表达式求值结果。
3. 每个子表达式的当前值。
4. 已等待时间。
5. 剩余超时时间。
6. 相关 IO 点的最近变化记录。
7. 是否存在 IO 脚本会触发该输入。

示例诊断：

```text
Waiting at line 42:
  wait io.alias.clamp_closed == true timeout 2 s

Current:
  io.alias.clamp_closed -> DI[1] = false
  waited: 1.24 s
  timeout in: 0.76 s
  last write: DO[1] = true by program at 12.380 s
  script: clamp_sim enabled, scheduled DI[1] = true at 12.680 s
```

## 8. KDL WASM 设计

### 8.1 KDL 使用边界

KDL 适合用于：

1. 3D 向量、位姿、旋转、坐标变换。
2. 串联机器人运动链建模。
3. 正向运动学。
4. 逆向运动学。
5. 雅可比计算。
6. 速度级运动学。
7. 基础轨迹与速度曲线能力。

需要注意：KDL 本身不是完整的碰撞检测、工艺仿真或全局路径搜索框架。避障、碰撞检测、节拍优化、工艺参数模拟需要另行设计。

### 8.2 总体落地架构

KDL WASM 不是 UI 组件，而是虚拟控制器和离线编程规划器共用的计算内核。推荐架构如下：

```text
HTML UI / Program Editor / Path Editor
  |
TypeScript Virtual Controller / OLP Planner
  |
KdlWorkerClient
  |
kdl.worker.ts
  |
KDL WASM Module
```

设计要求：

1. UI 主线程不得直接执行大批量 FK、IK、轨迹采样，应通过 Worker 调用 KDL WASM。
2. KDL C++ 类不直接暴露给业务层，业务层只使用稳定 TypeScript API。
3. WASM 内部可以保存 `RobotHandle`、KDL `Chain`、求解器和缓存，主线程只保存 handle。
4. 机器人结构以 URDF 为源数据，OPFS 保存原始 URDF 和转换后的标准模型缓存。
5. 运动函数必须面向商业离线编程工作流，不只提供单点 FK/IK，还要提供批量可达性、轨迹采样、节拍估算和诊断。
6. 对外运动指令只保留 `MOVEJ`、`MOVEL`、`MOVEC` 三类，分别对应关节角度差分、TCP 直线、TCP 圆弧。

### 8.3 URDF 机器人结构定义

机器人结构统一使用 URDF 定义。每个机器人资源建议包含：

```text
robots/
  {robotId}/
    robot.urdf
    robot.meta.json
    limits.override.json
    default_tool.json
    meshes/
```

URDF 使用规则：

1. `robot.urdf` 是机器人运动链的源文件。
2. 支持 `revolute`、`continuous`、`prismatic`、`fixed` joint。
3. 首版不支持 `planar`、`floating` joint；导入时生成明确诊断。
4. 所有长度单位统一为 meter，角度统一为 radian，时间统一为 second。
5. 关节限位优先使用 URDF `limit`；缺少加速度、jerk、厂商速度等级时由 `limits.override.json` 补齐。
6. URDF mesh 只用于显示和碰撞模块，KDL WASM 只消费运动链、关节轴、origin 和 limit。
7. 导入 ABB、FANUC、KUKA 机器人库时，也应转换为 URDF + 元数据，而不是直接把品牌模型写入运动内核。

URDF 到 KDL 的转换分两层实现：

1. TypeScript 层解析 XML，生成标准 `NormalizedRobotModel`，便于浏览器诊断、缓存、版本迁移和 UI 展示。
2. WASM 层接收标准模型，构造 KDL `Tree`/`Chain` 和求解器。

对业务层仍提供 `loadRobotFromUrdf`，避免上层关心解析位置：

```ts
interface UrdfLoadOptions {
  robotId: string;
  baseLink: string;
  tipLink: string;
  tool?: Pose;
  base?: Pose;
  jointOrder?: string[];
  overrideLimits?: JointLimitOverride[];
}

interface NormalizedRobotModel {
  robotId: string;
  name: string;
  baseLink: string;
  tipLink: string;
  links: LinkModel[];
  joints: JointModel[];
  activeJointNames: string[];
  limits: JointLimits[];
  source: {
    type: "urdf";
    urdfHash: string;
  };
}
```

### 8.4 KDL WASM 计算 API 清单

KDL WASM 首版至少应完成以下函数。TypeScript API 使用 camelCase，GRL/品牌指令层使用大写或小写指令名均可映射。

```ts
interface KdlWasmApi {
  init(options?: KdlInitOptions): Promise<void>;

  loadRobotFromUrdf(urdfXml: string, options: UrdfLoadOptions): Promise<RobotHandle>;
  createRobotFromModel(model: NormalizedRobotModel): Promise<RobotHandle>;
  destroyRobot(handle: RobotHandle): Promise<void>;
  getRobotInfo(handle: RobotHandle): Promise<RobotInfo>;
  getJointLimits(handle: RobotHandle): Promise<JointLimits[]>;

  fk(handle: RobotHandle, joints: Float64Array, options?: FkOptions): Promise<FkResult>;
  fkAllLinks(handle: RobotHandle, joints: Float64Array): Promise<LinkPoseResult>;
  jacobian(handle: RobotHandle, joints: Float64Array, options?: JacobianOptions): Promise<JacobianResult>;
  ik(handle: RobotHandle, seed: Float64Array, target: Pose, options?: IkOptions): Promise<IkResult>;
  ikBatch(handle: RobotHandle, seeds: Float64Array[], targets: Pose[], options?: IkOptions): Promise<IkResult[]>;

  checkJointLimits(handle: RobotHandle, joints: Float64Array): Promise<LimitCheckResult>;
  checkSingularity(handle: RobotHandle, joints: Float64Array): Promise<SingularityResult>;
  checkReachability(handle: RobotHandle, target: Pose, options?: IkOptions): Promise<ReachabilityResult>;

  moveJ(handle: RobotHandle, start: Float64Array, target: JointTarget | PoseTarget, options: MoveJOptions): Promise<TrajectoryResult>;
  moveL(handle: RobotHandle, start: Float64Array, target: PoseTarget, options: MoveLOptions): Promise<TrajectoryResult>;
  moveC(handle: RobotHandle, start: Float64Array, via: PoseTarget, target: PoseTarget, options: MoveCOptions): Promise<TrajectoryResult>;

  planPath(handle: RobotHandle, start: Float64Array, segments: MotionSegmentRequest[], options: PathPlanOptions): Promise<PathPlanResult>;
  validatePath(handle: RobotHandle, start: Float64Array, segments: MotionSegmentRequest[], options: PathPlanOptions): Promise<PathValidationResult>;
  estimateCycleTime(trajectory: TrajectoryResult | PathPlanResult): Promise<CycleTimeResult>;

  makeTrapProfile(length: number, options: TrapProfileOptions): Promise<TrapProfileResult>;
  sampleTrapProfile(length: number, options: TrapProfileOptions): Promise<TrapSample[]>;
  resampleTrajectory(trajectory: TrajectoryResult, sampleTime: number): Promise<TrajectoryResult>;
}
```

首版 C++/WASM 内核建议直接使用或封装这些 KDL 能力：

| 功能 | KDL 能力 | 包装层职责 |
| --- | --- | --- |
| 串联链 | `Tree`、`Chain`、`Segment`、`Joint` | 从 URDF 标准模型构造链 |
| 正解 | `ChainFkSolverPos_recursive` | 输出法兰、TCP、各 link 位姿 |
| 雅可比 | `ChainJntToJacSolver` | 输出矩阵和奇异性指标 |
| 逆解 | `ChainIkSolverPos_NR_JL`、`ChainIkSolverPos_LMA` | seed、多解尝试、限位、失败诊断 |
| 直线路径 | `Path_Line` | 生成 MOVEL TCP 采样 |
| 圆弧路径 | `Path_Circle` | 生成 MOVEC TCP 采样 |
| 梯形速度 | `VelocityProfile_Trap` | 生成 `s/sd/sdd` 采样 |
| 轨迹段 | `Trajectory_Segment` | 组合路径与速度曲线 |
| 圆角过渡 | `Path_RoundedComposite` | 第二阶段用于 zone/blend |

### 8.5 通用数据结构

位姿在内部统一使用位置 + 四元数，避免欧拉角奇异；导入导出 ABB/FANUC/KUKA 时再转换为品牌格式。

```ts
type RobotHandle = number;

interface Pose {
  position: [number, number, number];
  quaternion: [number, number, number, number];
}

interface JointLimits {
  name: string;
  lower: number;
  upper: number;
  velocity: number;
  acceleration: number;
  jerk?: number;
}

interface MotionOptionsBase {
  sampleTime: number;
  profile: "trap" | "s_curve";
  speedOverride: number;
  sourceMap?: MotionSourceMap;
  tcp?: Pose;
  base?: Pose;
}

interface MoveJOptions extends MotionOptionsBase {
  jointVelocity?: number[];
  jointAcceleration?: number[];
  blend?: ZoneData;
}

interface MoveLOptions extends MotionOptionsBase {
  tcpVelocity: number;
  tcpAcceleration: number;
  orientationMode: "fixed" | "slerp" | "tool_z_lock";
  ik: IkOptions;
  blend?: ZoneData;
}

interface MoveCOptions extends MoveLOptions {
  arcMode: "via" | "center" | "radius";
  circleDirection?: "short" | "long" | "cw" | "ccw";
}
```

轨迹输出点是虚拟控制器、3D 回放、节拍报告、可达性报告和后处理预览共用的数据结构：

```ts
interface TrajectoryPoint {
  index: number;
  time: number;
  dt: number;
  s: number;
  sd: number;
  sdd: number;
  joints: number[];
  jointVelocity: number[];
  jointAcceleration: number[];
  flange: Pose;
  tcp: Pose;
  tcpVelocity?: [number, number, number, number, number, number];
  tcpAcceleration?: [number, number, number, number, number, number];
  motion: "MOVEJ" | "MOVEL" | "MOVEC";
  segmentId?: string;
  targetId?: string;
  sourceMap?: MotionSourceMap;
  diagnostics: MotionDiagnostic[];
}

interface TrajectoryResult {
  ok: boolean;
  motion: "MOVEJ" | "MOVEL" | "MOVEC";
  duration: number;
  sampleTime: number;
  points: TrajectoryPoint[];
  events: TrajectoryEvent[];
  diagnostics: MotionDiagnostic[];
}
```

区分两类点：

1. 规划点：用户在 OLP 路径编辑器中创建的稀疏目标点，例如 `P10`、`P20`、`P30`。
2. 轨迹采样点：KDL WASM 根据运动方式、速度、加速度和采样周期生成的密集点，用于仿真执行和报告。

### 8.6 正解、逆解、雅可比和可达性

正解输入：

1. 机器人句柄。
2. 关节数组。
3. 工具坐标。
4. 基坐标或工件坐标。

正解输出：

1. 法兰位姿。
2. TCP 位姿。
3. 每个连杆位姿。
4. 是否越限。

IK 要求：

1. 支持 seed joint。
2. 支持关节限位。
3. 支持最大迭代次数。
4. 支持位置和姿态容差。
5. 支持多 seed 尝试。
6. 支持多解候选排序。
7. 支持按配置选择解，例如肩、肘、腕配置。
8. 支持失败原因返回。

IK 返回：

```ts
interface IkResult {
  ok: boolean;
  joints?: number[];
  iterations: number;
  residualPosition?: number;
  residualOrientation?: number;
  configuration?: RobotConfiguration;
  reason?: "unreachable" | "joint_limit" | "singularity" | "max_iteration" | "invalid_model";
  diagnostics: MotionDiagnostic[];
}
```

可达性检查不应只返回 true/false，还要返回商业软件常见的诊断内容：

1. 最近可达解。
2. 超限关节名称、当前值、上下限。
3. IK 残差。
4. 奇异性指标。
5. 推荐处理方式，例如换姿态、改 seed、改工具、换配置。

### 8.7 MOVEJ 轨迹规划

`MOVEJ` 是关节空间运动，机器人按各轴关节角度差分运行。TCP 轨迹由关节差分后的 FK 结果自然形成，不要求是直线。目标可以是关节目标，也可以是位姿目标：

1. 如果目标是关节数组，直接作为 `qEnd`。
2. 如果目标是位姿，先用 IK 从 `start` 附近求解 `qEnd`。
3. 对每个关节检查位置、速度、加速度限位。
4. 使用同步梯形速度曲线生成归一化路径参数 `s(t)`。
5. 每个采样点计算 `q(t) = qStart + s(t) * (qEnd - qStart)`。
6. 每个采样点执行 FK，得到法兰和 TCP 位姿。
7. 输出完整 `TrajectoryPoint[]`。

MOVEJ 的关键要求：

1. 所有关节同起同停。
2. 采样周期可配置，首版建议默认 `0.004 s` 或 `0.008 s`。
3. 速度倍率 `override` 只影响规划速度，不改变目标点。
4. 对接近限位、超过限位、奇异点附近要产生 warning 或 error。
5. 轨迹必须可重复：同一输入、同一算法版本、同一采样周期输出一致。

### 8.8 MOVEL 轨迹规划

`MOVEL` 是 TCP 直线运动，机器人 TCP 沿起点到终点的空间直线运行。关节角不做简单差分，而是由每个 TCP 采样点 IK 求解。

算法流程：

1. 用 `start` 关节做 FK，得到起点 TCP。
2. 根据目标点、工具、工件坐标得到终点 TCP。
3. 使用 KDL `Path_Line` 或等价实现生成 TCP 直线路径。
4. 姿态按 `orientationMode` 插补，首版推荐四元数 slerp。
5. 使用梯形速度曲线生成路径参数 `s(t)`。
6. 对每个 TCP 采样点执行 IK，seed 使用上一采样点关节值。
7. 检查每个采样点的关节限位、速度、加速度、奇异性和 IK 残差。
8. 输出轨迹点，并保留每个点对应的原始规划点和程序行 source map。

MOVEL 的商业级诊断要求：

1. TCP 直线误差最大值。
2. 姿态误差最大值。
3. 失败采样点的时间、路径比例、TCP 位姿和 IK 失败原因。
4. 关节翻转或配置突变检测。
5. 速度超限点列表。
6. 建议降低速度、调整姿态、插入中间点或切换配置。

### 8.9 MOVEC 轨迹规划

`MOVEC` 是 TCP 圆弧运动，机器人 TCP 经过 via 点并沿圆弧方式运行，关节角由每个圆弧采样点 IK 求解。输入至少包含：

1. 起点：由当前关节 FK 得到。
2. 经由点 `via`。
3. 终点 `target`。

算法流程：

1. 将起点、经由点、终点转换到同一基坐标。
2. 检查三点是否重合或近似共线。
3. 计算圆心、半径、法向量、圆弧角度。
4. 使用 KDL `Path_Circle` 或等价实现生成圆弧 TCP 路径。
5. 使用梯形速度曲线按圆弧长度采样。
6. 姿态按策略插补：首版使用起点到终点 slerp，经由点只约束位置；第二阶段支持经由点姿态约束。
7. 对每个采样 TCP 执行 IK，seed 使用上一采样点关节值。
8. 生成轨迹点、圆弧几何诊断和可达性诊断。

MOVEC 必须返回这些附加信息：

```ts
interface CirclePlanMeta {
  center: [number, number, number];
  radius: number;
  normal: [number, number, number];
  angle: number;
  length: number;
  direction: "cw" | "ccw";
  maxArcError: number;
}
```

### 8.10 梯形速度曲线

用户提到的“梯形图运动方式”，在运动规划上下文中按梯形速度曲线理解。PLC 梯形图属于虚拟 PLC/IO 联调模块，不放在 KDL 运动内核中。

梯形速度曲线用于 MOVEJ、MOVEL、MOVEC 的路径参数采样。统一输出：

```ts
interface TrapSample {
  index: number;
  time: number;
  s: number;
  sd: number;
  sdd: number;
}

interface TrapProfileResult {
  type: "trapezoid" | "triangle";
  length: number;
  duration: number;
  tAccel: number;
  tConst: number;
  tDecel: number;
  vPeak: number;
  samples: TrapSample[];
}
```

基本规则：

1. 输入路径长度 `L`、最大速度 `vMax`、最大加速度 `aMax`、采样周期 `dt`。
2. 如果距离足够长，生成加速、匀速、减速三段梯形速度曲线。
3. 如果距离不足以达到 `vMax`，自动退化为三角速度曲线。
4. `s` 表示归一化路径比例，范围 `[0, 1]`。
5. `sd`、`sdd` 表示归一化速度和加速度。
6. KDL WASM 内核可以使用 `VelocityProfile_Trap`，包装层负责转换为统一 `TrapSample[]`。
7. 所有运动函数必须把实际使用的速度曲线写入 `TrajectoryResult`，便于节拍报告和调试。

MOVEJ 中的路径长度建议定义为满足所有关节限位的归一化长度，而不是简单欧氏长度：

```text
jointRatio_i = abs(qEnd_i - qStart_i) / maxAllowedDelta_i
pathRatio = max(jointRatio_i)
```

实际实现时应根据每个关节的速度、加速度约束计算所需时间，取最大时间作为同步运动时间，再反算每个关节的采样速度和加速度。

### 8.11 多段路径、zone 和商业 OLP 批量能力

商业离线编程软件通常不是一次只算一条运动，而是对整条路径做批量验证。因此 KDL WASM 需要提供 `planPath` 和 `validatePath`：

1. 输入当前关节和多个 `MotionSegmentRequest`。
2. 按程序顺序生成每段 MOVEJ/MOVEL/MOVEC 轨迹。
3. 段间继承上一段末尾关节作为下一段起点。
4. `fine` 表示必须精确到点。
5. `zone` 表示允许过渡，首版可先做减速到点但保留 zone 信息；第二阶段用 `Path_RoundedComposite` 或自研 blend 算法实现连续过渡。
6. 输出整条 path 的总节拍、每段节拍、失败点、警告点、source map。

批量验证结果应支持 UI 直接定位：

```ts
interface MotionDiagnostic {
  severity: "info" | "warning" | "error";
  code: string;
  message: string;
  time?: number;
  pointIndex?: number;
  segmentId?: string;
  targetId?: string;
  sourceMap?: MotionSourceMap;
  data?: Record<string, unknown>;
}
```

### 8.12 和虚拟控制器的关系

虚拟控制器执行运动指令时不直接写机器人关节，而是走统一运动队列：

1. 解释器读到 `movej/movel/movec`。
2. 把当前关节、目标点、速度、zone、tool、frame 解析成 `MotionSegmentRequest`。
3. 调用 KDL WASM 生成 `TrajectoryResult`。
4. Motion Queue 按虚拟时间消费 `TrajectoryPoint`。
5. UI 根据当前点更新 3D 机器人、程序当前行、路径当前点、节拍统计。
6. 如果 KDL 返回 error，虚拟控制器进入 alarm 或 hold 状态。

这样可以保证从规划点生成程序、手写 GRL、多品牌导入程序都走同一套运动学和轨迹采样逻辑。

### 8.13 实施优先级

P0 必须完成：

1. URDF 文件加载、解析、诊断和标准模型缓存。
2. 从 URDF 标准模型创建 KDL Chain。
3. FK、fkAllLinks、Jacobian。
4. IK、ikBatch、关节限位和失败原因。
5. 梯形速度曲线 `makeTrapProfile`、`sampleTrapProfile`。
6. `moveJ` 轨迹点生成。
7. `moveL` 轨迹点生成。
8. `moveC` 基础圆弧轨迹点生成。
9. `validatePath` 批量可达性和诊断。
10. 轨迹结果可写入 OPFS trace，并可被 UI 回放。

P1 扩展：

1. zone/blend 连续过渡。
2. S 曲线速度规划。
3. 多 IK 解稳定排序。
4. 外部轴和变位机。
5. 多机器人协调。
6. 碰撞检测联动。
7. 与真实品牌控制器轨迹差异对比。

## 9. OPFS 工作区设计

### 9.1 文件系统布局

OPFS 内部推荐布局：

```text
/projects/
  /{projectId}/
    project.json
    station/
      station.json
      cells/
      fixtures/
      parts/
      devices/
    libraries/
      robots/
      tools/
      fixtures/
      process_templates/
    geometry/
      meshes/
      cad_sources/
      collision/
    robots/
    programs/
    targets/
    tools/
    frames/
    io/
      io_map.json
      io_scripts/
    generated/
    logs/
      io_trace.jsonl
      simulation_trace.jsonl
    reports/
      reachability/
      collision/
      cycle_time/
      post/
      calibration/
    calibration/
      tcp/
      frames/
      bases/
    snapshots/
    .index.json
    .lock
```

### 9.2 Project Manifest

```json
{
  "schemaVersion": 1,
  "projectId": "demo-cell",
  "name": "Demo Cell",
  "createdAt": "2026-06-26T00:00:00.000Z",
  "updatedAt": "2026-06-26T00:00:00.000Z",
  "robots": ["robots/robot_1.robot.json"],
  "mainProgram": "programs/main.grl",
  "postProfiles": {
    "abb": "post/abb.profile.json",
    "fanuc": "post/fanuc.profile.json",
    "kuka": "post/kuka.profile.json"
  }
}
```

### 9.3 Storage API

```ts
interface WorkspaceStorage {
  listProjects(): Promise<ProjectSummary[]>;
  openProject(projectId: string): Promise<ProjectWorkspace>;
  createProject(input: CreateProjectInput): Promise<ProjectWorkspace>;
  readText(path: string): Promise<string>;
  writeText(path: string, content: string): Promise<void>;
  readJson<T>(path: string): Promise<T>;
  writeJson<T>(path: string, value: T): Promise<void>;
  delete(path: string): Promise<void>;
  snapshot(projectId: string): Promise<ProjectSnapshot>;
  exportZip(projectId: string): Promise<Blob>;
  importZip(file: File): Promise<ProjectWorkspace>;
}
```

### 9.4 存储安全与备份

OPFS 是浏览器 Origin 私有文件系统，用户通常不能像普通目录一样直接看到这些文件。因此必须提供：

1. 显式导出项目包。
2. 显式导入项目包。
3. 自动快照。
4. 项目迁移工具。
5. 存储占用显示。
6. 数据损坏检测。

### 9.5 IO 文件

虚拟 IO 相关文件建议放在：

```text
io/
  io_map.json
  io_scripts/
    clamp_sim.ioscript
    fixture_sim.ioscript
logs/
  io_trace.jsonl
```

要求：

1. `io_map.json` 保存 IO 点定义、别名、品牌映射、初始值。
2. `io_scripts/*.ioscript` 保存虚拟 IO 脚本。
3. `io_trace.jsonl` 保存调试过程中 IO 事件，可按运行会话分文件。
4. 项目导出 zip 时必须包含 IO map 和 IO scripts。
5. trace 文件可选导出，避免项目包过大。

### 9.6 商业级项目交付物

商业 OLP 项目不仅保存程序，还应保存完整交付物：

```text
reports/
  reachability/report.json
  collision/report.json
  cycle_time/report.json
  post/abb_export_report.json
  calibration/tcp_report.json
generated/
  abb/
  fanuc/
  kuka/
packages/
  project_export.zip
  customer_delivery.zip
```

客户交付包建议包含：

1. GRL 源程序。
2. 品牌后处理程序。
3. 目标点和路径数据。
4. IO map。
5. 后处理报告。
6. 可达性报告。
7. 碰撞报告。
8. 节拍报告。
9. 校准数据。
10. 仿真 trace，可选。

## 10. 后处理设计

### 10.1 后处理目标

后处理器输入统一 IR 和 OLP 对象模型，输出目标品牌程序文件：

```text
OLP Object Model + Executable IR
  -> ABB RAPID generator
  -> FANUC LS/TP-compatible text generator
  -> KUKA KRL SRC/DAT generator
```

注意：FANUC 二进制 TP 文件通常需要官方工具或控制器环境转换，Web 端应优先生成可读的 LS 风格文本或中间格式，具体落地方式需按现场 FANUC 工具链确认。

### 10.2 品牌映射示例

GRL：

```text
movel pick speed linear(300 mm/s) zone z10 tool gripper frame fixture
```

ABB RAPID 目标：

```text
MoveL pick, v300, z10, gripper\WObj:=fixture;
```

FANUC 目标：

```text
L P[10] 300mm/sec CNT10 ;
```

KUKA KRL 目标：

```text
$VEL.CP = 0.3
LIN XPICK C_DIS
```

Path 后处理示例：

```text
run_path weld_seam_01
```

后处理器应展开为目标品牌的一组运动语句，并输出对应目标点数据。若目标品牌支持工艺包，可同时生成工艺指令；若不支持，则生成 IO 和注释。

### 10.3 后处理配置

每个品牌一个 profile：

```json
{
  "brand": "abb",
  "controller": "irc5",
  "robot": "irb_1200",
  "units": {
    "length": "mm",
    "angle": "deg"
  },
  "motion": {
    "defaultSpeed": "v300",
    "defaultZone": "z10"
  },
  "ioMap": {
    "clamp_closed": "di1",
    "clamp_open": "do1"
  }
}
```

### 10.4 后处理必须处理的差异

1. 目标点数据格式。
2. 姿态表示方式。
3. 构型参数。
4. 外部轴表示。
5. 工具和工件坐标声明。
6. 速度和过渡等级。
7. IO 地址格式。
8. 程序文件组织。
9. 行号和标签。
10. 不支持指令的降级或报错。
11. Path 默认参数和单点覆盖参数。
12. Operation 工艺参数到品牌工艺包或 IO 的映射。
13. 品牌程序数据文件拆分，例如 KUKA `.src/.dat`。
14. 目标点命名规则和长度限制。
15. FANUC 点位编号、寄存器、程序行号和 LS 格式限制。

### 10.5 后处理质量要求

1. 不能静默丢弃语义。
2. 不支持的指令必须给出明确诊断。
3. 输出程序必须格式化稳定。
4. 每个后处理器必须有 golden file 测试。
5. 必须能生成转换报告，列出警告、限制、映射表和人工确认项。

### 10.6 反向后处理：品牌程序导入

为了虚拟控制器可以解析多品牌机器人程序，需要建立 Brand Importer：

```text
ABB RAPID / FANUC LS / KUKA KRL
  -> Brand Importer
  -> Brand AST
  -> Normalized IR
  -> Reconstructed GRL
  -> Optional OLP Path/Operation Model
```

Brand Importer 输出：

1. `brandAst`：品牌语法树。
2. `ir`：可执行统一 IR。
3. `grlSource`：尽量恢复的 GRL 文本。
4. `olpModelPatch`：恢复出的目标点、路径和操作。
5. `report`：转换报告。

转换报告必须列出：

1. 成功解析的程序、目标点、工具、坐标系。
2. 无法识别的品牌指令。
3. 近似转换的语义。
4. 丢失或需要人工确认的信息。
5. 后续导出到其他品牌时的风险。

## 11. 虚拟控制器界面设计

界面目标是“离线编程和虚拟调试”，不是营销页面。第一屏应直接进入工作台。

### 11.1 主界面布局

推荐五区布局：

```text
┌─────────────────────────────────────────────────────────────┐
│ 顶部工具栏：项目、保存、运行、暂停、停止、单步、后处理      │
├───────────────┬──────────────────────────┬──────────────────┤
│ 项目对象树    │ 程序编辑器 / 路径编辑器   │ 虚拟示教器       │
│ 机器人/路径   │ AST/IR/诊断/日志 tabs     │ 状态/坐标/速度   │
├───────────────┴──────────────────────────┴──────────────────┤
│ 底部面板：报警、变量、IO、运动队列、调用栈、后处理报告       │
└─────────────────────────────────────────────────────────────┘
```

项目对象树应按商业 OLP 软件方式组织，而不是只显示文件：

```text
Station
  Cell Layout
  Robots
  Tools
  Frames
  Fixtures
  Parts
  Devices
  Geometry
  Targets
  Paths
  Operations
  Programs
  Brand Imports
  Generated Programs
  Validation Reports
  Calibration
```

### 11.2 必须页面

1. 项目管理
   - 新建项目
   - 打开项目
   - 导入 zip
   - 导出 zip
   - 项目设置
   - 生成客户交付包
   - 项目版本快照

2. 工作站布局
   - 机器人放置
   - 工具和夹具放置
   - 工件放置
   - 设备和安全区放置
   - 坐标系显示
   - 干涉区显示

3. 资源库
   - 机器人库
   - 工具库
   - 夹具库
   - 工艺模板库
   - 后处理 profile 库
   - 资源导入导出

4. 几何与 CAD
   - 导入 mesh 或 CAD 转换文件
   - 提取点、边、曲线、面法向
   - 从曲线生成 Path
   - 显示 CAD source metadata
   - 更新 CAD 后重建路径

5. 程序编辑
   - GRL 代码编辑
   - 语法高亮
   - 自动补全
   - 错误诊断
   - 跳转定义
   - 格式化
   - 从 Path/Operation 生成 GRL
   - 从品牌程序导入后查看恢复的 GRL

6. 虚拟示教器
   - 控制器状态
   - 手动/自动模式
   - 运行、暂停、停止、复位
   - 单步执行
   - 当前关节值
   - 当前 TCP
   - 当前 Tool / Frame
   - Override 速度倍率

7. IO 面板
   - DI/DO/AI/AO/GI/GO
   - IO 别名
   - 手动切换虚拟输入
   - IO 事件日志
   - Wait 条件监控
   - Pulse 状态
   - IO 脚本启停
   - IO trace 回放

8. 运动监控
   - 当前运动指令
   - Motion Queue
   - 目标点列表
   - 路径点列表
   - Operation 状态
   - IK 状态
   - 奇异点/限位警告
   - 轨迹采样查看

9. 路径编辑器
   - 路径点表格
   - 批量设置速度、zone、tool、frame
   - 接近点/离开点生成
   - 路径方向反转
   - 点位重命名
   - 姿态策略设置
   - 可达性检查
   - 展开为 GRL 预览
   - 碰撞检查结果
   - 节拍估算

10. Operation 编辑器
   - 工艺类型选择
   - 工艺参数编辑
   - start/end action
   - before/after path point event
   - 工艺 trace 显示

11. 验证与报告
   - 可达性报告
   - 碰撞报告
   - 节拍报告
   - IO/Wait 报告
   - 后处理报告
   - 报告导出 JSON/HTML

12. 校准与现场回读
   - TCP 校准数据
   - 工件坐标校准数据
   - Base 校准数据
   - 现场程序回读
   - 离线/现场差异比对

13. 后处理导出
   - 选择品牌
   - 选择 profile
   - 生成程序
   - 查看转换报告
   - 导出文件

14. 品牌程序导入
   - 选择 ABB/FANUC/KUKA
   - 导入文本文件
   - 查看解析结果
   - 查看恢复出的 target/path/program
   - 查看不支持语义
   - 转换为 GRL
   - 加载到虚拟控制器运行

15. 日志和报警
   - 控制器报警
   - 解析错误
   - 运行时错误
   - 后处理警告
   - 品牌导入警告

16. Wait 调试面板
   - 当前 wait 指令
   - 等待表达式
   - 子表达式求值
   - 已等待时间
   - 剩余超时时间
   - 关联 IO 点最近变化
   - 手动满足条件按钮，仅调试模式可用
   - 跳过 wait，仅调试模式可用，并必须写入 trace

### 11.3 控制器面板状态

需要显示：

1. Controller state：Ready、Running、Hold、Fault。
2. Mode：Manual、Auto。
3. Motors：On、Off。
4. Program：当前程序。
5. Line：当前行。
6. Cycle time：仿真周期。
7. Override：速度倍率。
8. TCP：X、Y、Z、RX、RY、RZ。
9. Joints：J1 到 J6。
10. Tool / Frame：当前工具和坐标系。
11. Path：当前路径。
12. Path Point：当前路径点。
13. Operation：当前工艺操作。
14. Source：当前来源，可能是 GRL、Path、Operation、ABB、FANUC、KUKA。
15. Wait：当前是否处于等待状态。
16. Wait Time：当前 wait 已等待时长。
17. Active IO Script：当前启用的 IO 脚本。

### 11.4 编辑器诊断

诊断分级：

| 等级 | 说明 |
| --- | --- |
| Error | 阻止运行或后处理 |
| Warning | 可运行但存在风险 |
| Info | 提示 |
| Hint | 优化建议 |

示例：

```text
E1003: target 'pick' is not reachable by robot_1
W2007: zone z50 may exceed short segment length
W3012: FANUC post does not support this interrupt exactly; generated fallback label logic
W4010: imported KUKA $ADVANCE behavior was approximated by GRL path look-ahead
```

### 11.5 IO 面板设计

IO 面板应采用表格和过滤器，适合调试时快速定位信号：

| 列 | 说明 |
| --- | --- |
| Address | `DI[1]`、`DO[2]`、`GI[1]` |
| Alias | `clamp_closed` |
| Value | 当前值 |
| Previous | 上一 tick 值 |
| Source | 最后写入来源：program/user/script/reset |
| Updated | 最后更新时间 |
| Brand | ABB/FANUC/KUKA 映射 |
| Lock | 是否允许手动修改 |

功能要求：

1. 按类型过滤：DI、DO、AI、AO、GI、GO。
2. 按 alias 搜索。
3. 支持手动切换虚拟输入。
4. 支持批量 reset。
5. 支持查看信号最近 N 条事件。
6. 支持将某个 IO 点加入 watch。
7. 支持显示哪些 wait 条件依赖该 IO。

### 11.6 IO 脚本界面

IO 脚本界面用于模拟 PLC 或夹具：

1. 脚本列表。
2. 启用/停用。
3. 单步触发。
4. 查看已注册 trigger。
5. 查看计划中的 delayed event。
6. 查看脚本产生的 IO 写入。
7. 脚本错误诊断。

### 11.7 Wait 调试体验

当程序停在 wait 时，界面必须避免只显示“程序卡住”。至少显示：

```text
Program waiting:
  line: 42
  expression: io.alias.clamp_closed == true
  DI[1] clamp_closed: false
  waited: 1.24 s / timeout: 2.00 s
  related output: DO[1] clamp_close_cmd = true
```

可选调试动作：

1. Set DI true：手动满足输入。
2. Toggle related IO：切换相关信号。
3. Run IO script：运行关联 IO 脚本。
4. Skip wait：跳过等待，必须标记 trace 为人工干预。
5. Abort program：停止程序并生成报警。

## 12. 实现路线

### 阶段 0：基础工程

目标：

1. 建立 TypeScript 项目结构。
2. 建立 HTML 工作台页面。
3. 建立 OPFS workspace。
4. 建立测试框架。
5. 建立 KDL WASM 构建原型。
6. 建立 OLP Object Model 基础类型。
7. 建立 Station/Resource/Report 基础模型。

交付：

1. 可打开 Web 工作台。
2. 可新建/保存/导出项目。
3. 可加载一个机器人模型 JSON。
4. 可在浏览器调用 KDL WASM 做一次 FK。
5. 可在对象树中显示 Robot、Tool、Frame、Target、Path、Operation、Program。
6. 可保存 station.json 和基础资源库。

### 阶段 1：GRL 语言最小闭环

目标：

1. 实现 GRL lexer/parser。
2. 支持 `module`、`proc`、变量、目标点、`path`、`movej`、`movel`、`run_path`、`call`。
3. 实现 AST、语义检查、诊断。
4. 实现 OLP Model 到 GRL 的生成器原型。

交付：

1. 编辑器能显示语法错误。
2. 能将 `main.grl` 编译为 IR。
3. 能保存 AST/IR 调试输出。
4. 能从一组规划点生成 path 和 GRL。

### 阶段 2：虚拟控制器最小闭环

目标：

1. 实现控制器状态机。
2. 实现程序加载、运行、暂停、停止、单步。
3. 实现变量和调用栈。
4. 实现基础 IO。

交付：

1. 能执行无运动逻辑程序。
2. 能在 UI 看到当前行、变量、调用栈。
3. 能模拟 IO wait 和 timeout。
4. 能执行 `run_path` 展开后的 IR。

### 阶段 3：运动执行闭环

目标：

1. 接入 URDF 机器人模型导入和标准模型缓存。
2. 接入 KDL WASM FK、fkAllLinks、Jacobian、IK、ikBatch。
3. 实现梯形速度曲线生成和采样。
4. 实现 `movej` 关节空间轨迹规划。
5. 实现 `movel` TCP 直线轨迹规划。
6. 实现基础 `movec` 圆弧轨迹规划。
7. 实现关节限位、速度限位、加速度限位和 IK 失败报警。
8. 实现路径点 source map。
9. 实现可达性报告原型。

交付：

1. 程序能驱动虚拟机器人状态变化。
2. UI 能看到关节和 TCP 更新。
3. 能加载 URDF 并显示机器人关节链和 link 位姿。
4. `MOVEJ/MOVEL/MOVEC` 都能输出 `TrajectoryPoint[]`。
5. 能导出轨迹 trace。
6. 能从路径编辑器定位当前运动点。
7. 能生成 Path 可达性报告。
8. 能生成基础节拍估算。

### 阶段 4：完整基础语言

目标：

1. 支持 `movec`。
2. 支持 `if/while/for/switch`。
3. 支持 `Tool`、`Frame`、`Speed`、`Zone`。
4. 支持中断和报警的基础模型。
5. 支持 `operation`、path event、start/end action。

交付：

1. 可编写完整搬运类程序。
2. 可进行基本虚拟调试。
3. 可查看运动队列和报警。
4. 可从 Operation 自动生成可执行 GRL。

### 阶段 5：后处理 MVP

目标：

1. ABB RAPID 后处理。
2. KUKA KRL 后处理。
3. FANUC LS 风格后处理。
4. 后处理报告。
5. 支持 path 和 operation 展开。

交付：

1. 同一 GRL 程序可导出三种品牌程序。
2. 每个后处理器有 golden file 测试。
3. 不支持语义能明确报错。
4. 同一 Path 可生成 ABB/FANUC/KUKA 运动点和数据文件。

### 阶段 6：验证与报告 MVP

目标：

1. 可达性报告。
2. 基础碰撞检测。
3. 节拍估算。
4. IO/Wait 报告。
5. HTML/JSON 报告导出。

交付：

1. 能对单个 Path 生成 reachability report。
2. 能对机器人和工件/夹具做基础碰撞检测。
3. 能计算程序总节拍和 wait 耗时。
4. 能导出验证报告。

### 阶段 7：品牌程序导入

目标：

1. ABB RAPID 文本导入。
2. KUKA KRL `.src/.dat` 导入。
3. FANUC LS 风格文本导入。
4. Brand AST 到统一 IR。
5. 品牌导入转换报告。

交付：

1. 能导入三类品牌程序并显示解析结果。
2. 能加载导入后的 IR 到虚拟控制器运行。
3. 能尽量恢复 target/path/program。
4. 无法等价转换的语义有明确警告。

### 阶段 8：虚拟调试增强

目标：

1. 断点。
2. 单步进入/越过。
3. 运动断点。
4. 轨迹回放。
5. 变量 watch。
6. IO 脚本。
7. 品牌源程序行号与 IR 的联动调试。

交付：

1. 可像调试程序一样调试机器人逻辑。
2. 可复现运行 trace。
3. 可定位 IK、IO、逻辑错误。
4. 可在 GRL、Path、Operation、品牌源程序之间定位同一条运动。

### 阶段 9：商业级 OLP 扩展

目标：

1. 资源库管理。
2. CAD/mesh 导入和曲线路径生成。
3. 工艺模板库。
4. 校准数据管理。
5. 客户交付包生成。

交付：

1. 可从几何曲线生成 Path。
2. 可使用工艺模板生成 Operation。
3. 可生成客户交付包。
4. 可保存 TCP/Frame/Base 校准数据。

### 阶段 10：工程化与扩展

目标：

1. 多机器人。
2. 外部轴。
3. 工艺包。
4. 碰撞检测。
5. 真实控制器校验流程集成。

交付：

1. 支持更复杂工作站。
2. 支持真实项目导入导出流程。
3. 支持品牌差异配置库。

## 13. 测试策略

### 13.1 解析器测试

1. 合法程序解析快照。
2. 非法程序错误位置。
3. 单位解析。
4. 注释保留。
5. 品牌扩展属性解析。
6. `path`、`operation`、`event`、`run_path`、`run_operation` 解析。
7. 从 OLP Model 生成 GRL 后再解析的一致性测试。

### 13.2 语义测试

1. 未定义变量。
2. 类型不匹配。
3. 工具缺失。
4. 坐标系缺失。
5. IO 越界。
6. 不可达点。
7. 关节超限。
8. 空 path。
9. 重复 path point。
10. Operation 引用不存在的 path。
11. Path event 引用不存在的 point。

### 13.3 KDL WASM 测试

1. URDF 导入测试：能从 URDF 解析 link、joint、origin、axis、limit，并生成稳定 `NormalizedRobotModel`。
2. URDF 诊断测试：缺少 limit、非法 joint、base/tip 不连通、单位异常时返回明确诊断。
3. WASM FK 与原生 KDL FK 对比。
4. `fkAllLinks` 输出 link 位姿数量和 joint 顺序正确。
5. Jacobian 维度、数值和奇异点指标正确。
6. IK 求解后再 FK，位置和姿态误差小于容差。
7. IK seed、多 seed、关节限位和失败原因测试。
8. 边界关节值。
9. 奇异点附近诊断。
10. 梯形速度曲线测试：长距离为梯形，短距离自动退化为三角形。
11. 梯形采样测试：起点终点速度为 0，`s` 单调递增，末点精确到 1。
12. `movej` 测试：所有关节同起同停，速度和加速度不超限。
13. `movel` 测试：TCP 直线误差小于容差，逐点 IK 连续。
14. `movec` 测试：圆弧半径、圆心、圆弧长度和采样误差小于容差。
15. `movec` 非法输入测试：三点重合、近似共线、半径过小时返回诊断。
16. 从 path 批量采样后逐点 IK。
17. 大型路径批量可达性性能测试。
18. 轨迹 source map 测试：采样点可定位回 segment、target 和程序行。
19. 轨迹结果序列化测试：`TrajectoryResult` 可写入 OPFS 后重新加载回放。
20. 大批量目标点性能测试。

### 13.4 虚拟控制器测试

1. 状态机转换。
2. 程序启动/暂停/恢复/停止。
3. 单步执行。
4. 调用栈。
5. IO wait timeout。
6. 报警复位。
7. 中断触发。
8. `run_path` 展开执行。
9. `run_operation` start/end action 执行。
10. Source map 能定位到 path point 和品牌源程序行。
11. wait 条件立即满足。
12. wait 条件由用户手动 IO 满足。
13. wait 条件由 IO 脚本延迟满足。
14. wait timeout 后报警。
15. wait timeout 后跳转 `on_timeout`。
16. hold 时 wait timeout 暂停。
17. stop 时 ActiveWait 取消。
18. pulse 输出按虚拟时间自动复位。
19. rising/falling/changed 边沿检测。
20. IO trace 顺序稳定。

### 13.4.1 商业验证测试

1. 可达性报告内容完整。
2. 接近关节限位能产生 warning。
3. IK 不可达能定位到 path point。
4. 基础碰撞检测能定位对象和时间点。
5. 节拍报告能统计 motion time、wait time、IO script delay。
6. 报告 JSON schema 稳定。
7. HTML 报告可打开且包含关键摘要。

### 13.5 后处理测试

1. GRL 到 ABB 输出。
2. GRL 到 FANUC 输出。
3. GRL 到 KUKA 输出。
4. 不支持语义报错。
5. 速度、过渡、工具、坐标系映射。
6. 目标点数值格式稳定。
7. Path 展开后输出稳定。
8. Operation 工艺参数映射。

### 13.6 品牌导入测试

1. ABB RAPID 导入到 IR。
2. KUKA KRL 导入到 IR。
3. FANUC LS 导入到 IR。
4. 品牌导入后再导出 GRL。
5. 品牌导入转换报告。
6. 不支持品牌指令的诊断。
7. 导入程序在虚拟控制器中可执行。

### 13.7 商业 OLP 工作流测试

1. 新建 station。
2. 从机器人库添加机器人。
3. 从工具库添加工具。
4. 导入 mesh。
5. 从规划点生成 Path。
6. 从 Path 生成 GRL。
7. 仿真运行。
8. 生成报告。
9. 后处理导出。
10. 导出客户交付包。

## 14. 风险与边界

| 风险 | 说明 | 对策 |
| --- | --- | --- |
| 品牌语义不完全一致 | 三家控制器的运动规划、过渡、异常、中断语义不同 | GRL 定义通用语义，后处理报告列出差异 |
| FANUC TP 二进制限制 | Web 端难以直接生成真实 `.TP` 二进制 | 初期生成 LS 风格文本或中间格式，配合 FANUC 工具链 |
| KDL 不负责碰撞检测 | KDL 不是完整仿真引擎 | 运动学先闭环，碰撞检测作为独立模块 |
| 浏览器存储不可见 | OPFS 文件不直接暴露给用户 | 必须提供 zip 导入导出和备份 |
| WASM 初始化成本 | 大型 WASM 初次加载慢 | Worker 懒加载、缓存、进度提示 |
| 数值差异 | WebAssembly、C++、真实控制器结果可能存在差异 | 设置容差，建立真实机器人标定与验证流程 |
| 后处理责任边界 | 导出程序不等于现场可直接高速运行 | 必须生成校验报告，并要求现场低速验证 |

## 15. 首版 MVP 范围

首版建议只做这些能力：

1. 单机器人 6 轴串联模型，机器人结构使用 URDF 定义。
2. GRL 程序编辑、解析、诊断。
3. OLP 对象树：Robot、Tool、Frame、Target、Path、Operation、Program。
4. 从规划点生成 Path 和 GRL。
5. `movej`、`movel`、基础 `movec`。
6. `Tool`、`Frame`、`Speed`、`Zone`。
7. 基础变量、条件、循环、子程序。
8. DI/DO 虚拟 IO。
9. `wait`、`wait timeout`、`pulse`、手动 IO 切换。
10. 简单 IO 脚本，例如夹爪 DO 触发 DI 反馈。
11. KDL WASM FK、fkAllLinks、Jacobian、IK、ikBatch。
12. KDL WASM 梯形速度曲线和 `MOVEJ/MOVEL/MOVEC` 轨迹采样函数。
13. 虚拟控制器运行、暂停、停止、单步。
14. OPFS 项目保存。
15. ABB、FANUC、KUKA 后处理原型。
16. 至少一种品牌程序导入原型，建议优先 KUKA KRL 或 ABB RAPID 文本。
17. 基础可达性报告。
18. 基础节拍报告。
19. 客户交付包导出原型。

不建议首版包含：

1. 完整碰撞检测。
2. 多机器人协调。
3. 外部轴同步。
4. 完整焊接/喷涂工艺包。
5. 完整真实控制器通信。
6. 与真实控制器完全一致的 look-ahead 和伺服行为。
7. FANUC 二进制 TP 直接生成或直接解析。
8. 完整 CAD kernel。
9. 完整 PLC/现场总线实时联调。
10. 高精度真实控制器轨迹复现。

## 16. 验收标准

MVP 可按以下标准验收：

1. 用户能在浏览器中新建项目。
2. 用户能导入 URDF 机器人模型，并定义工具、工件坐标和目标点。
3. 用户能从规划点创建 Path。
4. 用户能从 Path 和 Operation 生成 GRL 程序。
5. 用户能手工编辑 GRL 程序。
6. 系统能实时显示语法和语义错误。
7. 系统能运行程序，显示当前行、变量、IO、报警、TCP、关节。
8. KDL WASM 能从 URDF 创建运动链，并提供 FK、fkAllLinks、Jacobian、IK、ikBatch。
9. KDL WASM 能生成梯形速度曲线采样。
10. `movej`、`movel`、`movec` 可生成轨迹采样点。
11. MOVEJ 轨迹按关节角度差分运行并满足关节同起同停，MOVEL 轨迹满足 TCP 直线误差容差，MOVEC 轨迹满足 TCP 圆弧误差容差。
12. 不可达点和超限点能明确报警。
13. 程序执行到 wait 时，能显示等待表达式、关联 IO、已等待时间和剩余超时时间。
14. 用户能通过 IO 面板手动满足 wait。
15. IO 脚本能模拟夹具反馈并自动满足 wait。
16. wait timeout 能产生报警或执行 on_timeout。
17. 项目能保存在 OPFS，并能导出 zip。
18. 同一个 Path/Program 能导出 ABB、FANUC、KUKA 三种目标文本。
19. 后处理输出有转换报告。
20. 至少一种品牌程序能导入、转换为 IR 并在虚拟控制器中运行。
21. 自动测试覆盖解析器、KDL WASM、虚拟控制器、IO/Wait、后处理和品牌导入。
22. 能生成可达性报告和节拍报告。
23. 能导出包含源程序、品牌程序、IO map、报告的客户交付包。

商业级验收可按以下标准扩展：

1. 能从资源库创建完整工作站。
2. 能导入几何模型并从点/曲线生成 Path。
3. 能对 Path 做批量可达性检查。
4. 能执行基础碰撞检测并定位碰撞对象。
5. 能统计程序节拍并分解 motion/wait/IO 时间。
6. 能保存和应用 TCP、Frame、Base 校准数据。
7. 能将导入品牌程序恢复为统一 IR 并参与报告。
8. 能生成客户可交付项目包。

## 17. 推荐目录结构

未来代码工程可采用如下结构：

```text
src/
  app/
    main.ts
    ui/
  station/
    station-model.ts
    cell-layout.ts
    resources.ts
    devices.ts
  resources/
    robot-library.ts
    tool-library.ts
    fixture-library.ts
    process-template-library.ts
  geometry/
    mesh-loader.ts
    curve-sampling.ts
    collision-geometry.ts
  core/
    ast/
    parser/
    semantic/
    ir/
  controller/
    runtime/
    motion/
    io/
      io-service.ts
      wait-registry.ts
      io-script.ts
      io-trace.ts
    alarm/
    debug/
  kdl-wasm/
    bindings/
    loader.ts
    types.ts
  workspace/
    opfs.ts
    project.ts
    import-export.ts
  olp/
    model.ts
    path.ts
    operation.ts
    grl-generator.ts
  importers/
    abb/
    fanuc/
    kuka/
  post/
    abb/
    fanuc/
    kuka/
  robot/
    model.ts
    frames.ts
    targets.ts
  validation/
    reachability.ts
    collision.ts
    cycle-time.ts
    validation-report.ts
  calibration/
    tcp-calibration.ts
    frame-calibration.ts
    base-calibration.ts
    program-diff.ts
  reports/
    report-model.ts
    html-report.ts
    json-report.ts
  tests/
wasm/
  kdl/
docs/
```

## 18. 近期开发任务清单

建议下一步按以下顺序推进：

1. 固化 GRL 语法草案。
2. 建立 TypeScript monorepo 或单包工程。
3. 实现 OPFS 项目读写。
4. 建立 URDF 导入、诊断和 `NormalizedRobotModel` 缓存。
5. 编译 KDL WASM 并提供 FK、fkAllLinks、Jacobian、IK、ikBatch API。
6. 实现 KDL WASM 梯形速度曲线 `makeTrapProfile` 和 `sampleTrapProfile`。
7. 实现 KDL WASM `moveJ` 轨迹采样。
8. 实现 KDL WASM `moveL` 轨迹采样。
9. 实现 KDL WASM `moveC` 轨迹采样。
10. 实现 `validatePath` 批量可达性和轨迹诊断。
11. 实现 GRL parser。
12. 实现语义检查和 IR。
13. 实现虚拟控制器状态机。
14. 将 `movej/movel/movec` 执行接入 Motion Queue。
15. 实现简单 HTML 工作台。
16. 实现 Path 编辑和 Path 到 GRL 生成。
17. 实现 ABB/KUKA/FANUC 后处理 MVP。
18. 实现一个品牌导入 MVP。
19. 实现虚拟 IO Service、wait、pulse、IO 脚本和 IO 调试面板。
20. 实现 station/resource 基础模型。
21. 实现可达性和节拍报告原型。
22. 实现客户交付包导出原型。

## 19. 参考资料

1. ABB RAPID Technical Reference Manual，RAPID Instructions, Functions and Data Types：  
   https://library.e.abb.com/public/b227fcd260204c4dbeb8a58f8002fe64/Rapid_instructions.pdf

2. ABB RAPID Overview：  
   https://search.abb.com/library/Download.aspx?Action=Launch&DocumentID=3HAC050947-001&DocumentPartId=&LanguageCode=en

3. FANUC America Tech Transfer：  
   https://techtransfer.fanucamerica.com/

4. FANUC CRX / Tablet Teach Pendant 公开资料：  
   https://crx.fanucamerica.com/training/programming-part-1-initial-settings  
   https://www.fanucamerica.com/products/teach-pendant/tablet-teach-pendant

5. KUKA KSS 8.7 产品资料与操作编程文档入口：  
   https://my.kuka.com/s/product/kss-87/01t1i000001PTSOAA4?language=en_US

6. Orocos KDL 官方文档：  
   https://docs.orocos.org/kdl/overview.html  
   https://www.orocos.org/kdl.html

7. Emscripten Embind 文档：  
   https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html

8. MDN OPFS 文档：  
   https://developer.mozilla.org/en-US/docs/Web/API/File_System_API/Origin_private_file_system

9. RoboDK Basic Guide，说明离线编程是在离线环境创建、仿真并生成特定机器人和控制器程序：  
   https://robodk.com/doc/en/Basic-Guide.html

10. RoboDK Post Processors，说明后处理器负责按具体机器人控制器规则生成程序：  
    https://robodk.com/doc/en/Post-Processors.html

11. RoboDK Offline Programming，说明仿真达到预期后通过 post processors 生成机器人程序，并覆盖多品牌机器人：  
    https://robodk.com/offline-programming

12. ABB Downloads / RobotStudio SDK，说明 RobotStudio 支持在 PC 上进行机器人仿真和离线编程，而不停止生产：  
    https://www.abb.com/global/en/areas/robotics/downloads

13. Siemens Process Simulate，说明在 3D 虚拟环境中维护和优化机器人过程，支持离线编程：  
    https://www.siemens.com/en-us/products/tecnomatix/process-simulate-software/

14. Siemens Robotics Virtual Commissioning，说明虚拟调试用于验证 OLP 创建的机器人程序是否可行、高效，并验证 reach 和 cycle time：  
    https://www.siemens.com/en-us/technology/robotics-virtual-commissioning/

15. Siemens Robotics Programming and Simulation，说明在虚拟调试环境中结合真实控制器代码、机器人程序和硬件验证完整系统功能：  
    https://www.siemens.com/en-us/products/tecnomatix/offerings/robotics-programming-simulation/

16. Visual Components Robot Offline Programming，说明 OLP 软件面向多工业机器人品牌、工艺和复杂度：  
    https://www.visualcomponents.com/products/robot-offline-programming/

17. Visual Components Robot Programming，用于对标机器人工作站规划、调试和离线编程流程：  
    https://www.visualcomponents.com/use-cases/robot-programming/

## 20. 本次修订摘要

本次修订重点围绕“对标商业离线编程和虚拟调试软件的做法”完善设计：

1. 新增商业 OLP 对标定位，明确系统应采用“OLP 对象模型 + 可执行 GRL 程序 + 统一 IR”的双层结构。
2. 新增商业 OLP 典型工作流，覆盖工作站创建、目标点创建、路径创建、操作创建、GRL 生成、虚拟调试、后处理导出、品牌程序导入。
3. 扩展 GRL 语法，新增 `path`、`operation`、`run_path`、`run_operation`、path event、工艺参数等设计。
4. 明确规划点和规划路径生成 GRL 的规则：优先生成 Path 对象，再由 Path 生成程序，而不是直接散落成运动语句。
5. 新增 OLP Object Model、GRL AST、Brand AST、Executable IR 三层/多树结构，避免路径编辑、仿真执行、品牌导入导出互相耦合。
6. 新增 ABB RAPID、KUKA KRL、FANUC LS 等品牌程序导入解析路线，使虚拟控制器可以解析多品牌机器人程序并统一执行。
7. 扩展虚拟控制器设计，要求 IR 保留 GRL、Path、Operation、品牌源程序的 source map，支持跨视图调试。
8. 扩展界面设计，新增 OLP 对象树、路径编辑器、Operation 编辑器、品牌程序导入向导。
9. 更新实现路线，将品牌程序导入作为独立阶段，并把 Path/Operation 纳入 MVP 和测试策略。
10. 补充虚拟 IO 与 wait 实施方案，覆盖 IO 点模型、IO map、wait 条件、超时、边沿检测、pulse、IO 脚本、IO trace、Wait 调试面板和测试验收。
11. 补充商业级 OLP 能力，覆盖工作站/资源库、CAD 与路径生成、碰撞/可达性/节拍验证、虚拟调试联调、校准与 Sim-to-Real、商业报告和客户交付包。
12. 补充 KDL WASM 可实施计算函数方案，明确 URDF 作为机器人结构源定义，要求提供 FK、IK、Jacobian、MOVEJ、MOVEL、MOVEC、梯形速度曲线、轨迹采样点、批量路径验证和诊断接口。
