# 02-项目程序开发详细步骤 版本:0.1 日期:2026-06-27 ## 1. 开发原则 1. 先把 ABB120 fixture、测试程序、运行器和报告数据模型稳定下来,再扩展 UI。 2. 每个任务必须有自动化测试或可复核证据。 3. 运行链路以统一 GRL/IR 为中心,品牌程序只作为输入输出格式。 4. HTML 虚拟控制器先接入现有 runtime/facade,避免在 UI 中重复实现业务逻辑。 5. 对标 ABB RobotStudio 的工程流程,不复制视觉资产和品牌资源。 6. GRL 运算功能必须贯穿 parser、AST、常量求值、语义编译和 motion/path 编译,不接受只解析不求值的半成品。 ## 2. 阶段 0:基准资产整理 ### A120-001:固化 ABB120 URDF fixture 步骤: 1. 将 `ABB_IRB120_3_58_URDF` 从测试 fixture 抽成可复用项目 fixture,或建立明确导出入口。 2. 保留来源记录:ROS-Industrial repository、branch、entrypoint、macro。 3. 增加 fixture 校验:base/tip、DOF、joint names、joint limits、fixed links。 4. 生成 `abb120.robot.json`,包含 URDF、load options、标准关节位和测试元数据。 验收: 1. `loadRobotFromUrdf` 能加载 ABB120。 2. `getRobotInfo` 输出 6 轴链。 3. 限位和标准关节位在范围内。 ### A120-002:建立测试目录结构 建议新增: ```text kdl-wasm/web/tests/fixtures/abb120/ abb120.robot.ts programs/ A120_00_Smoke.grl A120_10_JointPickPlace.grl A120_20_CartesianBlend.grl A120_30_IOWaitPulse.grl A120_40_ErrorDiagnostics.grl A120_50_OperationProcess.grl expected/ abb/ fanuc/ kuka/ reports/ ``` 验收:测试能通过稳定路径读取所有 fixture。 ## 3. 阶段 1:GRL 运算表达式基础 ### GRL-EXPR-001:表达式 AST 扩展 当前相关文件: 1. `kdl-wasm/web/src/grl/ast/ast.ts` 2. `kdl-wasm/web/src/grl/parser/expressionParser.ts` 3. `kdl-wasm/web/src/grl/parser/parser.ts` 4. `kdl-wasm/web/src/grl/semantic/compileData.ts` 5. `kdl-wasm/web/src/grl/semantic/compileMotion.ts` 步骤: 1. 在 AST 中新增 `UnaryExpression`、`BinaryExpression`、必要时新增 `LogicalExpression` 或统一二元节点。 2. 保留现有 `NumberLiteral`、`BooleanLiteral`、`StringLiteral`、`IdentifierExpression`、`CallExpression`、`ArrayExpression`、`ObjectExpression`、`OffsetExpression`。 3. 节点必须保留 source range,方便 diagnostic 和 source map。 4. 兼容当前 `linear(300 mm/s)`、`pose(...)`、`joint_target {...}`、`offset` 语法。 验收: 1. AST snapshot 能显示 `1 + 2 * 3` 的优先级树。 2. `-(10 mm)`、`not (a == b)`、`sin(30 deg)` source range 稳定。 3. 当前 parser 测试不回退。 ### GRL-EXPR-002:表达式 parser 优先级 步骤: 1. 将 `expressionParser.ts` 从当前 primary/offset 解析扩展为递归下降或 Pratt parser。 2. 支持 `+ - * / mod`、比较、逻辑、括号、一元运算。 3. 函数调用参数内部允许完整表达式,例如 `linear(100 + 50 mm/s)`。 4. array/object 属性值允许完整表达式,例如 `joints: [(10 + 5) deg, -90 deg]`。 5. offset 轴值允许常量表达式,例如 `offset z (5 + 5) mm`,并在语义阶段求值。 验收: 1. `linear(100 + 50 mm/s)` 可 parse。 2. `pose(400 + 50 mm, 20 * 2 mm, sqrt(90000) mm, 0 deg, 0 deg, atan2(1, 1))` 可 parse。 3. `wait io.di[1] == true and not io.di[2] timeout 1 + 1 s` 的条件和 timeout 均可保留 source range。 4. 非法表达式输出 `GRL_EXPR_PARSE` 或现有 parse error,并定位行列。 ### GRL-EXPR-003:常量求值器和单位系统 建议新增: ```text kdl-wasm/web/src/grl/semantic/constantExpression.ts kdl-wasm/web/tests/grl/expressionCompile.test.ts ``` 步骤: 1. 实现 `evaluateConstantExpression(expression, context)`。 2. context 提供符号表、期望单位维度、默认单位和 diagnostic sink。 3. 支持 `pi`、`e`。 4. 支持 `sin/cos/tan/asin/acos/atan/atan2/sqrt/abs/pow/min/max/clamp/floor/ceil/round`。 5. 支持 `mm/mm/s/mm/s2/deg/rad/%/s/ms/kg` 归一化。 6. 做除零、函数定义域、单位不兼容、未知符号、未知函数和非常量表达式诊断。 验收: 1. `100 + 50 mm/s` 在速度上下文求值为 `0.15 m/s`。 2. `(10 + 5) deg` 在角度上下文求值为 `0.261799... rad`。 3. `clamp(20 mm, 1 mm, 10 mm)` 求值为 `0.01 m`。 4. `sqrt(-1)` 输出 `GRL_EXPR_DOMAIN`。 5. `10 mm + 2 s` 输出 `GRL_EXPR_UNIT_MISMATCH`。 ### GRL-EXPR-004:数据声明和 target 编译接入 步骤: 1. 在 `compileData.ts` 中把原来只接受 `NumberLiteral` 的位置改为常量表达式求值。 2. 覆盖 `tool.tcp`、`tool.mass`、`frame.origin`、`speed`、`zone`。 3. 覆盖 `joint_target.joints`、`pose_target.pose`、`poseq`、`robot_config`。 4. 变量引用只允许引用已知 const/persistent 常量或已编译数据符号;需要静态值的位置遇到运行态变量报 `GRL_EXPR_NON_CONSTANT`。 验收: 1. `const speed v = linear(100 + 50 mm/s)` 编译为 `0.15 m/s`。 2. `const zone z = z(max(5 mm, 10 mm))` 编译为 `0.01 m`。 3. `target home = joint_target { joints: [(10 + 5) deg, -90 deg] }` 编译为弧度数组。 4. `target pick = pose_target { pose: pose(400 + 50 mm, 0 mm, sqrt(90000) mm, 0 deg, 0 deg, atan2(1, 1)) }` 编译通过。 ### GRL-EXPR-005:motion/path/IO 编译接入 步骤: 1. 在 `compileMotion.ts` 中把内联 `speed`、`zone`、path defaults/source 属性改为常量表达式求值。 2. path point 的 `via`、`target`、`tool`、`frame` 若使用内联结构表达式,必须支持内部数值表达式。 3. path event `distance` 支持表达式。 4. IO/wait/pulse 中的 `timeout`、`duration` 支持表达式,归一化为秒。 5. runtime 条件中的比较/逻辑表达式至少保留结构化 AST 或稳定文本,并能在虚拟控制器 trace 中显示。 验收: 1. `point p0 movej home speed linear(100 + 50 mm/s) zone z(5 + 5 mm)` 编译到 KDL request。 2. `event at p0 distance 5 + 5 mm ...` 编译为 `0.01 m`。 3. `wait io.di[1] == true timeout 1 + 1 s` timeout 为 `2 s`。 4. `pulse io.do[1] duration 50 + 50 ms` duration 为 `0.1 s`。 ### GRL-EXPR-006:三品牌后处理和报告边界 步骤: 1. 后处理器优先使用已求值 IR,不输出未折叠常量表达式。 2. ABB/FANUC/KUKA 输出速度、zone、pose、joint 值时,使用各品牌可接受的具体数值。 3. runtime 条件表达式如无法保真输出,转换报告记录 `GRL_EXPR_UNSUPPORTED_RUNTIME`。 4. roundtrip report 标注表达式已折叠,回读结果以数值等价为准。 验收: 1. `linear(100 + 50 mm/s)` 在 ABB/FANUC/KUKA 输出中体现为具体速度。 2. `z(clamp(...))` 输出具体 zone/CNT/C_DIS 近似,并在 report 记录近似。 3. 后处理 report 不允许静默丢失 runtime 逻辑表达式。 ## 4. 阶段 2:通用机器人测试程序 ### A120-010:编写 GRL 程序集 步骤: 1. 按 `01-项目功能内容.md` 第 3 章创建 6 个 GRL 程序。 2. 每个程序声明 `module`、`speed`、`zone`、`tool/frame` 需求和 source metadata。 3. 关节目标使用 fixture 标准关节位。 4. pose 目标由 FK 自动生成,避免手写不可达姿态误判。 5. 故障程序单独放入 error suite,不进入 happy path 汇总。 验收: 1. 所有 happy path 程序可 parse。 2. error suite 输出稳定 diagnostic。 3. source map 覆盖每个 motion、wait、io、operation。 ### A120-011:建立程序 golden snapshot 步骤: 1. 保存 AST snapshot。 2. 保存 Semantic IR snapshot。 3. 保存 KDL bridge request snapshot。 4. 保存 source map snapshot。 验收:同一输入重复生成一致;非预期 diff 会导致测试失败。 ## 5. 阶段 3:运行器和 KDL 全面测试 ### A120-030:ABB120 KDL 基线测试 步骤: 1. 加载 ABB120 URDF。 2. 执行 `fk(home)`,校验 TCP 位置和姿态。 3. 执行 `fkAllLinks(home)`,校验 link 顺序。 4. 执行 `jacobian(pick)`,校验矩阵维度和有限值。 5. 执行 `checkJointLimits`,覆盖合法和非法关节。 6. 执行 `checkSingularity`,输出 manipulability 和 conditionNumber。 验收:测试报告包含 robot info、FK、link poses、Jacobian、limits、singularity。 ### A120-031:轨迹规划测试 步骤: 1. 对 `A120_10_JointPickPlace` 执行 `planPath`。 2. 对 `A120_20_CartesianBlend` 执行 `planMoveL/planMoveC`。 3. 对故障路径执行 `validatePath`。 4. 输出轨迹点数、duration、max velocity、max acceleration、blend diagnostics。 验收:happy path `ok=true`;error path 有稳定 `code/severity/sourceMap`。 ### A120-032:虚拟控制器运行测试 步骤: 1. `compileSemanticProgram` 得到 IR。 2. `VirtualController.load` 加载程序。 3. 分别执行 run、pause、step、stop、reset。 4. Motion Queue 绑定 KDL planner。 5. IO runtime 注入 DI script。 6. 记录 trace、program counter、scope、alarm、wait、motion activeIndex。 验收:控制器状态机合法;trace 可回放;wait 卡住和 timeout 可诊断。 ### A120-033:job runner 步骤: 1. 新增 `runAbb120Suite` 或 CLI 脚本。 2. 输入:suite id、程序列表、robot fixture、输出目录。 3. 输出:`job_id`、`job.json`、`trace.json`、`trajectory.json`、`diagnostics.json`。 4. job id 格式:`A120-JOB-YYYYMMDD-HHMMSS-`。 验收:CI 可运行并生成稳定证据目录。 ## 6. 阶段 4:跨品牌转换和回读 ### A120-050:三品牌后处理 golden 步骤: 1. 对每个 happy path GRL 编译 IR。 2. 调用 `postProcessAllBrands`。 3. 生成 ABB `.mod`、FANUC `.ls`、KUKA `.src/.dat`。 4. 保存 golden 文件。 5. 生成 post report。 验收: 1. ABB 输出包含 `MoveJ/MoveL/MoveC/SetDO/WaitUntil/PulseDO`。 2. FANUC 输出包含 `J/L/C/DO/WAIT/PULSE`。 3. KUKA 输出包含 `PTP/LIN/CIRC/$OUT/WAIT FOR`。 4. unsupported/approximation 不允许静默丢失。 ### A120-051:品牌导入回读 步骤: 1. 将后处理输出重新导入。 2. 对比 target 数量、motion 顺序、operation 结构。 3. 对不可逆语义生成 diff report。 4. 输出 `roundtrip.json`。 验收:happy path 结构等价;近似项全部进入 report。 ## 7. 阶段 5:离线编程全面测试 ### A120-070:OLP 项目生成 步骤: 1. 根据 ABB120 fixture 创建 Station。 2. 添加 Robot、Tool、Frame、Target、Path、Operation、Program。 3. 保存到 workspace。 4. 导出 bundle,再导入恢复。 验收:恢复后项目对象等价,manifest 完整。 ### A120-071:验证报告 步骤: 1. 生成 reachability report。 2. 生成 cycle time report。 3. 生成 IO/Wait report。 4. 生成 collision report。 5. 生成 post/import report。 6. 汇总为 HTML report,预留 PDF/print。 验收:每个 report 有 `report_id`、status、summary、sections、diagnostics、source map。 ### A120-072:客户交付包 步骤: 1. 打包 GRL 源程序。 2. 打包 ABB/FANUC/KUKA 输出程序。 3. 打包 IO map、校准数据、trace、trajectory、report。 4. 输出 bundle manifest。 验收:交付包可解包并追溯每个输出来源。 ## 8. 阶段 6:HTML 虚拟控制器 ### A120-090:页面骨架 建议新增: ```text kdl-wasm/web/app/virtual-controller.html kdl-wasm/web/app/virtual-controller.css kdl-wasm/web/app/virtual-controller.js kdl-wasm/web/scripts/verify-virtual-controller.mjs ``` 步骤: 1. 页面直接进入 ABB120 工作台。 2. 顶部命令栏、左侧对象树、中央 station viewport、右侧示教器、底部诊断面板。 3. 接入 WorkbenchFacade 和 VirtualController snapshot。 4. 无数据时显示空工程状态;加载 fixture 后显示对象树和程序。 验收:浏览器直接打开 HTML 即可看到 ABB120 项目工作台;`npm run verify:virtual-controller` 能生成桌面和移动截图证据。 ### A120-091:运行控制 步骤: 1. 实现 Load、Run、Pause、Step、Stop、Reset。 2. 显示状态灯、mode、motors、program pointer、cycle time。 3. 显示 joint/TCP 值。 4. Motion Queue 与时间轴同步。 验收:按钮触发 runtime 状态变化,页面数据同步。 ### A120-092:编辑器和 source map 步骤: 1. GRL/ABB/FANUC/KUKA 多标签只读查看。 2. 当前执行行高亮。 3. 点击诊断跳转源码。 4. 点击 path point 高亮 viewport 和 source。 验收:source map 双向定位可用。 ### A120-093:IO、Wait、报警和报告 步骤: 1. IO 面板显示 DI/DO 当前值和最近事件。 2. wait 面板显示表达式、elapsed、remaining timeout、子表达式值。 3. alarm 面板显示 severity、code、source。 4. report 面板打开 HTML report。 验收:wait 卡住时可以定位并手动置位 DI 继续运行。 ### A120-094:视觉验证 步骤: 1. 使用 Playwright 打开 HTML 页面。 2. 截图桌面和移动视口。 3. 如果有 canvas/3D,做非空像素检查。 4. 保存截图到证据目录。 验收:页面无重叠、核心文字不溢出、主要面板可见。 ## 9. 阶段 7:全量验收 ### A120-900:CI 全量命令 命令: ```bash cd /home/meswork/kdl_work npm run typecheck npm test cmake --build kdl-wasm/build-wasm -j16 ``` 新增后还应包含: ```bash npm run test -- abb120 npm run test -- post import workbench controller runtime reports ``` 验收:所有测试通过,`05-验收证据.md` 记录 job/report/screenshot 路径。