1718 lines
46 KiB
Markdown
1718 lines
46 KiB
Markdown
# 通用机器人编程语法规范
|
||
|
||
版本:0.1
|
||
适用范围:离线编程、虚拟控制器、虚拟调试、多品牌后处理
|
||
目标品牌:ABB RAPID、FANUC TP/LS/KAREL 语义、KUKA KRL
|
||
|
||
## 1. 设计目标
|
||
|
||
本规范定义一种用于离线编程和虚拟调试的通用机器人程序语言,暂定名为 GRL,Generic Robot Language。GRL 不是复制某一家机器人厂商语言,而是抽象 ABB、FANUC、KUKA 等主流工业机器人共同具备的程序语义,形成稳定、可解析、可仿真、可自动生成、可后处理的中性机器人程序。
|
||
|
||
核心目标:
|
||
|
||
1. 支持离线编程的完整流程:目标点、路径、工艺、IO、等待、流程控制、报警、仿真执行、报告和后处理。
|
||
2. 方便由规划点、CAD 曲线、工艺模板、AI 规划器自动生成程序。
|
||
3. 方便转换为 ABB RAPID、FANUC LS/TP 风格文本、KUKA KRL。
|
||
4. 方便反向导入品牌程序,恢复为统一 IR、GRL 和 OLP 对象模型。
|
||
5. 程序文本稳定、可读、可 diff,便于版本管理。
|
||
6. 语义确定,编译后能生成统一可执行 IR,虚拟控制器不依赖品牌控制器细节。
|
||
|
||
非目标:
|
||
|
||
1. 不追求完全复刻某一品牌控制器所有系统变量和内部调度细节。
|
||
2. 不直接作为真实机器人安全运行的唯一依据,后处理输出必须经过品牌控制器验证和现场低速试运行。
|
||
3. 不把 CAD、碰撞检测、机器人运动学全部写入语言本身;这些由 OLP 模型和仿真内核承担。
|
||
|
||
## 2. 对标原则
|
||
|
||
### 2.1 品牌能力映射
|
||
|
||
| 能力 | ABB RAPID | FANUC TP/LS | KUKA KRL | GRL |
|
||
| --- | --- | --- | --- | --- |
|
||
| 程序模块 | `MODULE` | TP 程序、KAREL 程序 | `.src/.dat`、`DEF` | `module` |
|
||
| 子程序 | `PROC` | `CALL` | `DEF` 子程序 | `proc` |
|
||
| 函数 | `FUNC` | KAREL function | `DEFFCT` | `func` |
|
||
| 中断/陷阱 | `TRAP`、interrupt | 条件监控、后台逻辑 | `INTERRUPT` | `trap`、`interrupt` |
|
||
| 关节运动 | `MoveJ` | `J P[...]` | `PTP` | `movej` |
|
||
| 直线运动 | `MoveL` | `L P[...]` | `LIN` | `movel` |
|
||
| 圆弧运动 | `MoveC` | `C P[...]` | `CIRC` | `movec` |
|
||
| 笛卡尔目标点 | `robtarget` | `P[]`、`PR[]` | `E6POS` | `pose_target` |
|
||
| 关节目标点 | `jointtarget` | joint position data | `E6AXIS` | `joint_target` |
|
||
| 工具 | `tooldata` | UTOOL | `$TOOL` | `tool` |
|
||
| 工件/基坐标 | `wobjdata` | 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.*`、`wait` |
|
||
| 标签跳转 | `GOTO` | `LBL`、`JMP` | `GOTO` | `label`、`jump` |
|
||
|
||
### 2.2 中性语法风格
|
||
|
||
GRL 采用“声明式数据 + 结构化程序 + Path/Operation 对象”的风格:
|
||
|
||
1. 目标点、工具、坐标系、速度、过渡作为数据声明。
|
||
2. 程序流程使用 `proc`、`if`、`while`、`for`、`switch` 等结构化控制。
|
||
3. 短程序和调试程序可直接写 `movej/movel/movec`。
|
||
4. 自动离线编程优先生成 `path` 和 `operation`,程序中通过 `run_path`、`run_operation` 调用。
|
||
5. 所有运动语句显式绑定目标点、速度、过渡、工具、坐标系,允许默认值,但编译到 IR 前必须解析为确定值。
|
||
6. 品牌特性通过 `post_hint` 和 `@brand.*` 元数据保留,不污染通用语义。
|
||
|
||
## 3. 文件与工程结构
|
||
|
||
推荐一个 OLP 项目使用以下结构:
|
||
|
||
```text
|
||
project.json
|
||
robots/
|
||
robot_1.urdf
|
||
robot_1.meta.json
|
||
programs/
|
||
main.grl
|
||
weld.grl
|
||
targets/
|
||
main.targets.json
|
||
paths/
|
||
weld_path.path.json
|
||
operations/
|
||
weld_op.operation.json
|
||
io/
|
||
io_map.json
|
||
post/
|
||
abb.profile.json
|
||
fanuc.profile.json
|
||
kuka.profile.json
|
||
generated/
|
||
abb/
|
||
fanuc/
|
||
kuka/
|
||
reports/
|
||
reachability.json
|
||
cycle_time.json
|
||
```
|
||
|
||
GRL 文件扩展名建议使用 `.grl`。
|
||
|
||
## 4. 词法规则
|
||
|
||
### 4.1 编码和大小写
|
||
|
||
1. 文件编码使用 UTF-8。
|
||
2. 关键字建议小写。
|
||
3. 标识符大小写敏感,推荐使用 `snake_case`。
|
||
4. 后处理器输出到品牌程序时按品牌习惯调整大小写。
|
||
|
||
### 4.2 注释
|
||
|
||
```text
|
||
// 单行注释
|
||
|
||
/*
|
||
多行注释
|
||
*/
|
||
```
|
||
|
||
自动生成程序应在关键对象上保留来源注释,但不要为每个采样点生成大量冗余注释。
|
||
|
||
### 4.3 标识符
|
||
|
||
```text
|
||
identifier = letter { letter | digit | "_" }
|
||
```
|
||
|
||
示例:
|
||
|
||
```text
|
||
pick_path
|
||
weld_op_01
|
||
T_curve_032_000
|
||
```
|
||
|
||
不建议使用中文标识符。UI 可显示中文别名,但程序内部名称应保持 ASCII,便于后处理和版本管理。
|
||
|
||
### 4.4 字面量和单位
|
||
|
||
支持带单位数值:
|
||
|
||
```text
|
||
100 mm
|
||
0.25 m
|
||
180 deg
|
||
3.14159 rad
|
||
300 mm/s
|
||
50 %
|
||
2 s
|
||
200 ms
|
||
2.5 kg
|
||
```
|
||
|
||
编译器内部统一规范化:
|
||
|
||
| 物理量 | 内部单位 |
|
||
| --- | --- |
|
||
| 长度 | meter |
|
||
| 角度 | radian |
|
||
| 时间 | second |
|
||
| 质量 | kilogram |
|
||
| 线速度 | meter/second |
|
||
| 角速度 | radian/second |
|
||
| 加速度 | meter/second^2 或 radian/second^2 |
|
||
|
||
### 4.5 保留关键字
|
||
|
||
```text
|
||
language module import end
|
||
persistent const var
|
||
robot tool frame load target speed zone path operation process
|
||
proc func return call
|
||
if elseif else switch case default while for to step break continue
|
||
label jump
|
||
movej movel movec run_path run_operation
|
||
set_tool set_frame set_speed set_zone
|
||
wait pulse timer
|
||
io true false and or not mod all any rising falling changed
|
||
trap interrupt enable disable raise alarm try catch finally
|
||
task sync
|
||
post_hint source defaults point event before after at
|
||
joint_target pose_target pose poseq joints robot_config ext_axis
|
||
fine continuous cnt z
|
||
```
|
||
|
||
## 5. 顶层结构
|
||
|
||
### 5.1 最小文件
|
||
|
||
```text
|
||
language grl 0.1
|
||
|
||
module Main
|
||
proc main()
|
||
// program entry
|
||
end
|
||
end
|
||
```
|
||
|
||
`language grl 0.1` 用于版本控制。后续语言升级时,编译器可按版本选择兼容规则。
|
||
|
||
### 5.2 顶层声明
|
||
|
||
```text
|
||
module ModuleName
|
||
import CommonTools
|
||
|
||
persistent tool gripper = ...
|
||
persistent frame fixture = ...
|
||
const speed v_pick = linear(300 mm/s)
|
||
const zone z_pick = z10
|
||
|
||
target home = ...
|
||
path pick_path { ... }
|
||
operation pick_op { ... }
|
||
|
||
proc main()
|
||
...
|
||
end
|
||
end
|
||
```
|
||
|
||
顶层可包含:
|
||
|
||
1. `import`
|
||
2. `persistent`
|
||
3. `const`
|
||
4. `target`
|
||
5. `path`
|
||
6. `operation`
|
||
7. `proc`
|
||
8. `func`
|
||
9. `trap`
|
||
10. `task`
|
||
11. `post_hint`
|
||
|
||
## 6. 类型系统
|
||
|
||
### 6.1 基础类型
|
||
|
||
| 类型 | 说明 |
|
||
| --- | --- |
|
||
| `bool` | 布尔值 |
|
||
| `int` | 整数 |
|
||
| `real` | 浮点数 |
|
||
| `string` | 字符串 |
|
||
| `time` | 时间 |
|
||
| `length` | 长度 |
|
||
| `angle` | 角度 |
|
||
| `percent` | 百分比 |
|
||
|
||
### 6.2 机器人类型
|
||
|
||
| 类型 | 说明 |
|
||
| --- | --- |
|
||
| `pose` | 笛卡尔位姿 |
|
||
| `joint_array` | 关节数组 |
|
||
| `pose_target` | 笛卡尔目标点 |
|
||
| `joint_target` | 关节目标点 |
|
||
| `tool` | 工具 TCP、负载、惯量 |
|
||
| `frame` | 工件坐标或基坐标 |
|
||
| `speed` | 运动速度参数 |
|
||
| `zone` | 到点/过渡参数 |
|
||
| `load` | 负载 |
|
||
| `robot_config` | 肩、肘、腕等机器人配置 |
|
||
| `ext_axis` | 外部轴 |
|
||
| `path` | 路径对象 |
|
||
| `operation` | 工艺操作对象 |
|
||
|
||
### 6.3 变量声明
|
||
|
||
```text
|
||
const int max_retry = 3
|
||
var int retry = 0
|
||
var bool part_ok = false
|
||
var pose_target p_tmp = pick offset z 100 mm
|
||
persistent real counter = 0
|
||
```
|
||
|
||
规则:
|
||
|
||
1. `const` 编译后不可修改。
|
||
2. `persistent` 在项目或控制器状态中持久化。
|
||
3. `var` 默认为局部变量。
|
||
4. 类型可以显式写出,自动生成程序建议显式写出。
|
||
|
||
## 7. 表达式与运算
|
||
|
||
GRL 表达式是数据声明、运动参数、路径参数、IO 条件和流程控制的公共基础。首版按 ABB RAPID、FANUC LS/KAREL、KUKA KRL 共同具备的数学能力建模,优先保证同一 GRL 程序能稳定编译到统一 IR,再由后处理器输出品牌程序。
|
||
|
||
### 7.1 语法范围
|
||
|
||
表达式必须支持:
|
||
|
||
1. 算术:一元 `+`、一元 `-`、二元 `+`、`-`、`*`、`/`、`mod`。
|
||
2. 比较:`==`、`!=`、`<`、`<=`、`>`、`>=`。
|
||
3. 逻辑:`and`、`or`、`not`;可兼容 `&&`、`||`、`!` 作为输入别名,IR 中统一为 GRL 关键字。
|
||
4. 括号:`(...)` 显式改变优先级。
|
||
5. 函数调用:`callee(args...)`,参数内部允许完整表达式。
|
||
6. 单位后缀:可作用于数字字面量、标识符、函数调用或括号表达式,例如 `100 mm`、`blend_base mm`、`sqrt(90000) mm`、`(10 + 5) deg`。
|
||
7. 现有结构表达式:数组、对象、构造器调用、标识符引用、IO 引用和 `offset` 表达式必须继续兼容。
|
||
|
||
优先级从高到低:
|
||
|
||
| 层级 | 运算 |
|
||
| --- | --- |
|
||
| 1 | 函数调用、对象、数组、括号、构造器、offset |
|
||
| 2 | 一元 `+`、`-`、`not`、`!` |
|
||
| 3 | `*`、`/`、`mod` |
|
||
| 4 | `+`、`-` |
|
||
| 5 | `<`、`<=`、`>`、`>=` |
|
||
| 6 | `==`、`!=` |
|
||
| 7 | `and`、`&&` |
|
||
| 8 | `or`、`||` |
|
||
|
||
### 7.2 内置常量和函数
|
||
|
||
首版内置常量:
|
||
|
||
| 名称 | 含义 |
|
||
| --- | --- |
|
||
| `pi` | 圆周率 |
|
||
| `e` | 自然常数 |
|
||
|
||
首版内置函数:
|
||
|
||
| 类别 | 函数 |
|
||
| --- | --- |
|
||
| 三角函数 | `sin`、`cos`、`tan`、`asin`、`acos`、`atan`、`atan2` |
|
||
| 数值函数 | `sqrt`、`abs`、`pow`、`min`、`max`、`clamp`、`floor`、`ceil`、`round` |
|
||
|
||
函数规则:
|
||
|
||
1. `sin/cos/tan` 接收角度量;带 `deg` 或 `rad` 单位时归一化为弧度,纯数按弧度处理。
|
||
2. `asin/acos` 接收无单位数值,定义域为 `[-1, 1]`;`atan` 接收无单位数值;`atan2(y, x)` 的两个参数必须同维度或均为无单位数值。
|
||
3. `asin/acos/atan/atan2` 返回角度量;在 `pose(...)` 姿态项或 `joint_target.joints` 等角度上下文中可直接使用。
|
||
4. `sqrt` 首版只要求支持无单位数值或编译器明确支持的上下文,负数必须报定义域错误。
|
||
5. `min/max/clamp` 的参数必须维度兼容;`clamp(value, min, max)` 的边界顺序错误应给出 diagnostic。
|
||
6. 函数参数数量必须严格检查,例如 `atan2` 为 2 个参数,`clamp` 为 3 个参数。
|
||
|
||
### 7.3 单位和求值语义
|
||
|
||
数值求值采用统一 SI 归一化:
|
||
|
||
| GRL 输入 | IR/KDL 归一化 |
|
||
| --- | --- |
|
||
| `mm` | m |
|
||
| `m` | m |
|
||
| `mm/s` | m/s |
|
||
| `mm/s2` | m/s2 |
|
||
| `deg` | rad |
|
||
| `rad` | rad |
|
||
| `%` | 0 到 1 的比例 |
|
||
| `s` | s |
|
||
| `ms` | s |
|
||
| `kg` | kg |
|
||
|
||
规则:
|
||
|
||
1. 同维度数值可以相加、相减和比较,结果保留该维度并归一化。
|
||
2. 纯数可以参与乘除;维度乘除首版只允许编译器明确支持的上下文,避免产生复杂复合单位。
|
||
3. 不同维度相加、相减或比较必须报错,例如 `10 mm + 2 s`。
|
||
4. 构造器可以提供默认上下文单位:`linear(...)` 默认 `mm/s`,`angular(...)` 默认 `deg/s`,`z(...)` 默认 `mm`,`pose(...)` 前三项默认 `mm`、后三项默认 `deg`,`joint_target.joints` 默认 `deg`,`timeout/duration` 默认 `s`。
|
||
5. 因此 `linear(100 + 50 mm/s)` 在 `linear` 速度上下文中等价于 `linear(150 mm/s)`;自动生成程序推荐输出显式单位,减少人工歧义。
|
||
|
||
### 7.4 编译期求值位置
|
||
|
||
常量表达式必须在编译阶段求值,并把结果写入 Semantic IR / KDL request,而不是把表达式字符串传到运动规划层。
|
||
|
||
必须支持的求值位置:
|
||
|
||
1. 数据声明 initializer:`const`、`persistent`、需要静态初值的 `var`。
|
||
2. `speed`:`linear(...)`、`joint(...)`、`angular(...)`、`acc ...` 参数。
|
||
3. `zone`:`fine`、`z(...)`、`cnt(...)`。
|
||
4. `pose(...)`、`poseq(...)`、`robot_config(...)`。
|
||
5. `joint_target { joints: [...] }`。
|
||
6. `pose_target { pose: ... }`。
|
||
7. `tool { tcp: ..., mass: ... }` 和 `frame { origin: ... }`。
|
||
8. path `defaults`、`source` 属性和 path point 内联 `speed`、`zone`、`tool`、`frame`、`via`、`target` 参数。
|
||
9. path event 的 `distance`。
|
||
10. `wait ... timeout ...` 和 `pulse ... duration ...` 中的时间常量。
|
||
11. operation `process` 中需要数值常量的工艺参数。
|
||
12. `switch case` 值。
|
||
|
||
比较和逻辑表达式也必须进入 AST。纯常量比较/逻辑可在编译期折叠;依赖 IO、变量或运行态状态的条件先保留为结构化控制表达式,供虚拟控制器和后续品牌映射使用。
|
||
|
||
### 7.5 示例
|
||
|
||
```text
|
||
const real blend_base = 5 + 5
|
||
const speed v_pick = linear(100 + 50 mm/s)
|
||
const speed v_safe = linear(max(50 mm/s, 200 mm/s / 2))
|
||
const zone z_app = z(clamp(blend_base mm, 1 mm, 50 mm))
|
||
|
||
target home = joint_target {
|
||
joints: [0 deg, (10 + 5) deg, -90 deg, 0 deg, 0 deg, 0 deg]
|
||
}
|
||
|
||
target pick = pose_target {
|
||
pose: pose(400 + 50 mm, 20 * 2 mm, sqrt(90000) mm, 0 deg, 0 deg, atan2(1, 1))
|
||
}
|
||
|
||
wait io.ai[2] > sin(30 deg) timeout 1 + 1 s
|
||
```
|
||
|
||
编译期结果要求:
|
||
|
||
1. `v_pick` 进入 IR 后为 `linear`,速度 `0.15 m/s`。
|
||
2. `z_app` 进入 IR 后为 `distance`,距离 `0.01 m`。
|
||
3. `home.joints[1]` 进入 IR 后为 `15 deg` 对应的弧度值。
|
||
4. `pick.pose.position[0]` 进入 IR 后为 `0.45 m`。
|
||
5. `atan2(1, 1)` 进入姿态上下文后为 `45 deg` 对应的弧度值。
|
||
|
||
### 7.6 诊断
|
||
|
||
运算功能必须输出稳定 diagnostic:
|
||
|
||
| code | 场景 |
|
||
| --- | --- |
|
||
| `GRL_EXPR_PARSE` | 表达式语法错误或括号不匹配。 |
|
||
| `GRL_EXPR_UNKNOWN_SYMBOL` | 常量求值遇到未知标识符。 |
|
||
| `GRL_EXPR_UNKNOWN_FUNCTION` | 未知函数。 |
|
||
| `GRL_EXPR_ARITY` | 函数参数数量错误。 |
|
||
| `GRL_EXPR_DOMAIN` | 数学定义域错误,例如 `sqrt(-1)`、`acos(2)`。 |
|
||
| `GRL_EXPR_DIV_ZERO` | 除零。 |
|
||
| `GRL_EXPR_UNIT_MISMATCH` | 单位维度不兼容。 |
|
||
| `GRL_EXPR_NON_CONSTANT` | 需要常量的位置出现运行时表达式。 |
|
||
| `GRL_EXPR_UNSUPPORTED_RUNTIME` | 后处理暂不支持的复杂运行时表达式。 |
|
||
|
||
每个 diagnostic 必须包含 severity、message、source range,并能通过 source map 定位到 GRL 源文件行列。
|
||
|
||
### 7.7 跨品牌边界
|
||
|
||
首版跨品牌输出不直接翻译复杂表达式字符串,而是优先输出编译期折叠后的常量:
|
||
|
||
1. `linear(100 + 50 mm/s)` 输出为各品牌可表达的具体速度值。
|
||
2. `z(clamp(...))` 输出为具体 ABB zone、FANUC CNT 或 KUKA 近似 blend。
|
||
3. runtime 条件表达式如果后处理器无法保真映射,必须进入转换报告,不得静默丢失。
|
||
4. 品牌专用数学函数、控制器系统变量和复杂运行时表达式不作为首版公共能力,后续通过 post/import report 增量支持。
|
||
|
||
## 8. 坐标、工具和目标点
|
||
|
||
### 8.1 工具
|
||
|
||
```text
|
||
persistent tool gripper = tool {
|
||
tcp: pose(0 mm, 0 mm, 180 mm, 0 deg, 0 deg, 0 deg),
|
||
mass: 2.5 kg,
|
||
cog: [0 mm, 0 mm, 80 mm]
|
||
}
|
||
```
|
||
|
||
### 8.2 工件坐标
|
||
|
||
```text
|
||
persistent frame fixture = frame {
|
||
origin: pose(800 mm, 0 mm, 200 mm, 0 deg, 0 deg, 0 deg)
|
||
}
|
||
```
|
||
|
||
### 8.3 关节目标点
|
||
|
||
```text
|
||
target home = joint_target {
|
||
joints: [0 deg, -30 deg, 60 deg, 0 deg, 60 deg, 0 deg]
|
||
}
|
||
```
|
||
|
||
`joint_target` 主要用于 `movej`,后处理可映射到 ABB `jointtarget`、KUKA `E6AXIS` 或 FANUC 关节位置数据。
|
||
|
||
### 8.4 笛卡尔目标点
|
||
|
||
```text
|
||
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
|
||
}
|
||
```
|
||
|
||
`pose()` 参数顺序为:
|
||
|
||
```text
|
||
pose(x, y, z, rx, ry, rz)
|
||
```
|
||
|
||
首版 `rx/ry/rz` 使用固定约定的欧拉角,建议内部立即转换为四元数。为了避免姿态歧义,也允许使用四元数:
|
||
|
||
```text
|
||
poseq(500 mm, 120 mm, 300 mm, 0, 0, 0.7071068, 0.7071068)
|
||
```
|
||
|
||
### 8.5 偏移目标点
|
||
|
||
```text
|
||
var pose_target approach = pick offset z 100 mm
|
||
var pose_target p2 = pick offset x 20 mm y -10 mm z 50 mm
|
||
```
|
||
|
||
偏移默认在目标点所属 `frame` 下解释。需要明确坐标系时:
|
||
|
||
```text
|
||
var pose_target p3 = pick offset_in tool z -50 mm
|
||
var pose_target p4 = pick offset_in frame fixture x 100 mm
|
||
```
|
||
|
||
## 9. 速度和过渡
|
||
|
||
### 9.1 速度
|
||
|
||
```text
|
||
const speed v_joint_fast = joint(80 %)
|
||
const speed v_joint_abs = joint(90 deg/s)
|
||
const speed v_pick = linear(300 mm/s)
|
||
const speed v_weld = linear(120 mm/s)
|
||
const speed v_orient = angular(90 deg/s)
|
||
```
|
||
|
||
运动语义:
|
||
|
||
1. `joint(...)` 用于关节运动速度。
|
||
2. `linear(...)` 用于 TCP 线速度。
|
||
3. `angular(...)` 可作为姿态插补角速度限制。
|
||
4. 加速度可作为可选参数:
|
||
|
||
```text
|
||
const speed v_slow = linear(100 mm/s, acc 500 mm/s2)
|
||
```
|
||
|
||
### 9.2 过渡
|
||
|
||
```text
|
||
const zone z_fine = fine
|
||
const zone z10 = z(10 mm)
|
||
const zone z50 = z(50 mm)
|
||
const zone z_cnt = cnt(30)
|
||
const zone z_cont = continuous
|
||
```
|
||
|
||
语义:
|
||
|
||
1. `fine`:精确到点,不做过渡。
|
||
2. `z(distance)`:以距离近似表示过渡半径,便于映射 ABB `zonedata` 和 KUKA `APO`。
|
||
3. `cnt(percent)`:以百分比表示连续过渡,便于映射 FANUC `CNT`。
|
||
4. `continuous`:允许连续通过,实际过渡由后处理器或虚拟控制器策略决定。
|
||
|
||
## 10. 运动指令
|
||
|
||
### 10.1 基本语法
|
||
|
||
```text
|
||
movej TargetExpr [speed Speed] [zone Zone] [tool Tool] [frame Frame]
|
||
movel TargetExpr [speed Speed] [zone Zone] [tool Tool] [frame Frame]
|
||
movec via ViaTargetExpr target EndTargetExpr [speed Speed] [zone Zone] [tool Tool] [frame Frame]
|
||
```
|
||
|
||
示例:
|
||
|
||
```text
|
||
movej home speed joint(60 %) zone fine tool gripper frame fixture
|
||
movel pick speed linear(300 mm/s) zone z10
|
||
movec via arc_mid target arc_end speed linear(150 mm/s) zone fine
|
||
```
|
||
|
||
### 10.2 MOVEJ 语义
|
||
|
||
`movej` 表示关节空间运动。机器人按各轴关节角度差分运行,关节同起同停,TCP 轨迹不要求是直线。
|
||
|
||
编译规则:
|
||
|
||
1. 目标为 `joint_target` 时直接使用关节数组。
|
||
2. 目标为 `pose_target` 时先用 IK 求终点关节。
|
||
3. 轨迹按关节空间插补。
|
||
4. 后处理映射:
|
||
- ABB:`MoveJ`
|
||
- FANUC:`J P[...]`
|
||
- KUKA:`PTP`
|
||
|
||
### 10.3 MOVEL 语义
|
||
|
||
`movel` 表示 TCP 直线运动。TCP 沿起点到终点的空间直线运行,关节角由每个 TCP 采样点 IK 求解。
|
||
|
||
编译规则:
|
||
|
||
1. 目标必须能解析为笛卡尔位姿。
|
||
2. 当前点作为直线起点。
|
||
3. 姿态按默认策略插补,首版推荐固定姿态或 slerp。
|
||
4. 后处理映射:
|
||
- ABB:`MoveL`
|
||
- FANUC:`L P[...]`
|
||
- KUKA:`LIN`
|
||
|
||
### 10.4 MOVEC 语义
|
||
|
||
`movec` 表示 TCP 圆弧运动。TCP 从当前点出发,经过 via 点,到达 target 点,沿圆弧运行,关节角由每个圆弧采样点 IK 求解。
|
||
|
||
编译规则:
|
||
|
||
1. 起点为当前 TCP。
|
||
2. `via` 和 `target` 必须能解析为笛卡尔位姿。
|
||
3. 三点不能重合或近似共线。
|
||
4. 首版使用 via 点位置约束圆弧,姿态按起点到终点插补。
|
||
5. 后处理映射:
|
||
- ABB:`MoveC`
|
||
- FANUC:`C P[...]`
|
||
- KUKA:`CIRC`
|
||
|
||
### 10.5 当前工具和当前坐标
|
||
|
||
```text
|
||
set_tool gripper
|
||
set_frame fixture
|
||
set_speed linear(300 mm/s)
|
||
set_zone z10
|
||
```
|
||
|
||
参数优先级:
|
||
|
||
1. 运动语句显式参数最高。
|
||
2. `path defaults` 次之。
|
||
3. 目标点自带 `tool/frame` 次之。
|
||
4. 当前控制器状态最低。
|
||
|
||
编译到 IR 时,所有运动必须有确定的 `tool`、`frame`、`speed`、`zone`。
|
||
|
||
## 11. Path 语法
|
||
|
||
Path 是自动离线编程的核心对象。CAD 曲线、规划点、示教点、工艺模板应优先生成 Path,而不是直接生成散乱运动语句。
|
||
|
||
### 11.1 基本语法
|
||
|
||
```text
|
||
path pick_path {
|
||
defaults {
|
||
tool: gripper,
|
||
frame: fixture,
|
||
speed: linear(300 mm/s),
|
||
zone: z10
|
||
}
|
||
|
||
point approach movej home zone fine
|
||
point p1 movel pick offset z 100 mm
|
||
point p2 movel pick zone fine
|
||
}
|
||
```
|
||
|
||
### 11.2 圆弧点
|
||
|
||
```text
|
||
path arc_path {
|
||
defaults {
|
||
tool: torch,
|
||
frame: part_frame,
|
||
speed: linear(120 mm/s),
|
||
zone: fine
|
||
}
|
||
|
||
point p0 movej start
|
||
point p1 movec via mid target end
|
||
}
|
||
```
|
||
|
||
### 11.3 来源元数据
|
||
|
||
```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 T_curve_032_000 zone fine
|
||
point p001 movel T_curve_032_001
|
||
point p002 movel T_curve_032_002
|
||
}
|
||
```
|
||
|
||
来源元数据用于:
|
||
|
||
1. 路径重采样。
|
||
2. 目标点重命名。
|
||
3. 重新生成程序。
|
||
4. 报告中定位到 CAD 曲线或工艺对象。
|
||
|
||
### 11.4 Path event
|
||
|
||
```text
|
||
event before p001 io.do[10] = true
|
||
event after p010 io.do[10] = false
|
||
event at p005 distance -20 mm pulse io.do[20] duration 100 ms
|
||
```
|
||
|
||
语义:
|
||
|
||
1. `before`:到达路径点之前执行。
|
||
2. `after`:完成路径点之后执行。
|
||
3. `at ... distance`:相对路径点提前或滞后触发,首版可编译为最近采样点事件。
|
||
4. 后处理到品牌程序时,若品牌不支持精确路径触发,应生成转换报告。
|
||
|
||
### 11.5 `run_path`
|
||
|
||
```text
|
||
proc main()
|
||
run_path pick_path
|
||
end
|
||
```
|
||
|
||
编译语义:
|
||
|
||
1. 展开 Path 的 defaults、points、events。
|
||
2. 每个 point 变为 Motion IR。
|
||
3. event 变为 IO/Wait/Process IR。
|
||
4. 保留 source map,调试时可从程序行定位到路径点。
|
||
|
||
## 12. 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
|
||
}
|
||
```
|
||
|
||
首版建议支持的 `kind`:
|
||
|
||
| kind | 用途 |
|
||
| --- | --- |
|
||
| `handling` | 搬运、上下料 |
|
||
| `arc_welding` | 弧焊 |
|
||
| `spot_welding` | 点焊 |
|
||
| `dispensing` | 涂胶 |
|
||
| `spraying` | 喷涂 |
|
||
| `grinding` | 打磨 |
|
||
| `cutting` | 切割 |
|
||
| `generic_path` | 通用路径 |
|
||
|
||
`run_operation`:
|
||
|
||
```text
|
||
proc main()
|
||
run_operation weld_op_01
|
||
end
|
||
```
|
||
|
||
编译语义:
|
||
|
||
1. 执行 `start_action`。
|
||
2. 执行 operation 引用的 path。
|
||
3. 执行 `end_action`。
|
||
4. 保留工艺参数,供仿真 UI、报告和后处理使用。
|
||
|
||
## 13. IO 与等待
|
||
|
||
### 13.1 IO 地址
|
||
|
||
```text
|
||
io.di[1]
|
||
io.do[1]
|
||
io.ai[1]
|
||
io.ao[1]
|
||
io.gi[1]
|
||
io.go[1]
|
||
io.ri[1]
|
||
io.ro[1]
|
||
```
|
||
|
||
推荐通过 `io_map.json` 提供别名:
|
||
|
||
```text
|
||
io.alias.clamp_open
|
||
io.alias.clamp_closed
|
||
io.alias.gripper_close_cmd
|
||
```
|
||
|
||
### 13.2 IO 写入
|
||
|
||
```text
|
||
io.do[1] = true
|
||
io.go[1] = 16
|
||
io.ao[1] = 3.5
|
||
```
|
||
|
||
### 13.3 wait
|
||
|
||
```text
|
||
wait io.di[1] == true
|
||
wait io.alias.clamp_closed == true timeout 2 s
|
||
wait io.ai[2] > 3.5 timeout 1.5 s
|
||
wait all(io.di[1] == true, io.di[2] == false)
|
||
wait any(io.di[10] == true, timer.done("T_PICK"))
|
||
wait rising(io.di[4]) timeout 5 s
|
||
wait falling(io.di[5]) timeout 5 s
|
||
```
|
||
|
||
超时处理:
|
||
|
||
```text
|
||
wait io.di[1] == true timeout 2 s on_timeout alarm "Clamp close timeout"
|
||
wait io.di[1] == true timeout 2 s on_timeout call recover_clamp()
|
||
```
|
||
|
||
### 13.4 pulse
|
||
|
||
```text
|
||
pulse io.do[3] duration 200 ms
|
||
```
|
||
|
||
虚拟控制器语义:
|
||
|
||
1. 立即置位输出。
|
||
2. 虚拟时间到达 duration 后自动复位。
|
||
3. trace 中必须记录置位和复位事件。
|
||
|
||
## 14. 流程控制
|
||
|
||
流程控制用于表达工艺分支、重试、配方选择、批量工位循环和异常恢复。GRL 新程序应优先使用结构化控制流;`label/jump` 主要用于兼容 FANUC TP/LS 等已有程序导入。
|
||
|
||
### 14.1 条件 `if / elseif / else`
|
||
|
||
```text
|
||
if part_ok
|
||
run_path good_path
|
||
elseif retry < 3
|
||
call retry_pick()
|
||
else
|
||
alarm "Pick failed"
|
||
end
|
||
```
|
||
|
||
语义规则:
|
||
|
||
1. `if` 条件表达式必须能转换为 `bool`。
|
||
2. `elseif` 可以出现零次或多次。
|
||
3. `else` 最多出现一次,且必须位于所有 `elseif` 之后。
|
||
4. 条件按顺序求值,命中第一条为 true 的分支后,不再执行后续分支。
|
||
5. 每个 `if` 必须以 `end` 结束。
|
||
6. 条件表达式允许访问变量、IO、函数返回值和比较表达式。
|
||
7. 运动指令允许出现在任意分支内,但编译器必须保证每条分支中的工具、坐标系、速度和 zone 可解析。
|
||
|
||
常用条件表达式:
|
||
|
||
```text
|
||
if io.di[1] == true
|
||
if count >= 3 and not part_ok
|
||
if is_part_ready()
|
||
if recipe_id == 2 or recipe_id == 3
|
||
```
|
||
|
||
### 14.2 `while` 循环
|
||
|
||
```text
|
||
while retry < 3
|
||
call try_pick()
|
||
if part_ok
|
||
break
|
||
end
|
||
retry = retry + 1
|
||
end
|
||
```
|
||
|
||
语义规则:
|
||
|
||
1. `while` 条件必须为 `bool`。
|
||
2. 每次进入循环前求值。
|
||
3. `break` 立即退出当前循环。
|
||
4. `continue` 跳过本轮剩余语句,进入下一轮条件判断。
|
||
5. 编译器建议对可能无限循环的 `while true` 给出 warning,除非循环体内包含明确的 `break`、`return`、`raise` 或 `wait`。
|
||
|
||
### 14.3 `for` 循环
|
||
|
||
```text
|
||
for i = 0 to 9 step 1
|
||
call process_slot(i)
|
||
end
|
||
```
|
||
|
||
也允许省略 `step`,默认步长为 `1`:
|
||
|
||
```text
|
||
for layer = 1 to layer_count
|
||
call weld_layer(layer)
|
||
end
|
||
```
|
||
|
||
反向循环:
|
||
|
||
```text
|
||
for i = 10 to 0 step -1
|
||
call clear_slot(i)
|
||
end
|
||
```
|
||
|
||
语义规则:
|
||
|
||
1. 循环变量默认是当前 `for` 块局部变量。
|
||
2. 起点、终点、步长必须是整数或可安全转换为整数。
|
||
3. `step` 不能为 `0`。
|
||
4. `break` 和 `continue` 只影响当前最近一层循环。
|
||
5. 后处理到不支持结构化 `for` 的品牌时,可展开为标签和跳转,但必须保持 source map。
|
||
|
||
### 14.4 `switch / case / default`
|
||
|
||
```text
|
||
switch recipe_id
|
||
case 1
|
||
run_operation op_a
|
||
case 2
|
||
run_operation op_b
|
||
default
|
||
alarm "Unknown recipe"
|
||
end
|
||
```
|
||
|
||
语义规则:
|
||
|
||
1. `switch` 表达式可以是 `int`、`bool`、`string` 或枚举型。
|
||
2. `case` 值必须是常量表达式。
|
||
3. 每个 `case` 默认不向下贯穿,不需要写 `break`。
|
||
4. `default` 最多出现一次。
|
||
5. 若需要多个值进入同一分支,可以使用逗号:
|
||
|
||
```text
|
||
switch recipe_id
|
||
case 1, 2, 3
|
||
run_operation common_recipe
|
||
case 10
|
||
run_operation special_recipe
|
||
default
|
||
alarm "Unknown recipe"
|
||
end
|
||
```
|
||
|
||
6. 导出到 FANUC TP/LS 时,`switch` 可转换为 `SELECT`、条件跳转或 `LBL/JMP` 组合。
|
||
7. 导出到 ABB/KUKA 时,优先转换为品牌结构化分支。
|
||
|
||
### 14.5 `break` 和 `continue`
|
||
|
||
```text
|
||
while true
|
||
call check_part()
|
||
if part_ok
|
||
break
|
||
end
|
||
retry = retry + 1
|
||
if retry < max_retry
|
||
continue
|
||
end
|
||
alarm "Retry failed"
|
||
break
|
||
end
|
||
```
|
||
|
||
规则:
|
||
|
||
1. `break` 只能出现在 `while`、`for` 或 `switch` 中。
|
||
2. `continue` 只能出现在 `while` 或 `for` 中。
|
||
3. 在 `switch` 中不需要 `break` 防止贯穿,因为 GRL 默认不贯穿。
|
||
|
||
### 14.6 label 和 jump
|
||
|
||
```text
|
||
label retry
|
||
call try_pick()
|
||
if not part_ok
|
||
jump retry
|
||
end
|
||
```
|
||
|
||
新程序不建议优先使用 `label/jump`,但必须支持它,因为 FANUC TP/LS 程序常用 `LBL/JMP`,导入时需要映射。
|
||
|
||
`label/jump` 规则:
|
||
|
||
1. `label` 名称在当前 `proc` 内唯一。
|
||
2. `jump` 只能跳转到当前 `proc` 内的 label。
|
||
3. 禁止 `jump` 进入另一个 `if/while/for/switch/try` 块内部。
|
||
4. 允许 `jump` 跳出块结构,但编译器应生成 warning。
|
||
5. 自动生成的新程序不应使用 `label/jump`,除非目标后处理配置要求 FANUC 风格输出。
|
||
|
||
## 15. 子程序和函数
|
||
|
||
### 15.1 `proc` 子程序
|
||
|
||
`proc` 是无返回值子程序,用于组织工艺步骤、运动流程、IO 流程和恢复逻辑。
|
||
|
||
```text
|
||
proc pick_part(int slot)
|
||
movej home speed joint(60 %) zone fine
|
||
run_path pick_path
|
||
end
|
||
```
|
||
|
||
调用:
|
||
|
||
```text
|
||
call pick_part(1)
|
||
call pick_part(slot_id)
|
||
```
|
||
|
||
语义规则:
|
||
|
||
1. `proc` 可以执行运动、IO、wait、run_path、run_operation。
|
||
2. `proc` 可以调用其他 `proc`。
|
||
3. 默认不允许无限递归。编译器应检测直接递归和明显的间接递归,并给出 warning 或 error。
|
||
4. `return` 可以提前退出 `proc`,但不能携带返回值。
|
||
5. `proc main()` 是默认入口。一个模块中最多一个默认入口。
|
||
|
||
### 15.2 参数方向
|
||
|
||
参数支持 `in`、`out`、`inout` 三种方向。未写方向时默认为 `in`。
|
||
|
||
```text
|
||
proc pick_part(in int slot)
|
||
call move_to_slot(slot)
|
||
end
|
||
|
||
proc read_part(out bool ok)
|
||
ok = io.di[1]
|
||
end
|
||
|
||
proc increment_retry(inout int retry)
|
||
retry = retry + 1
|
||
end
|
||
```
|
||
|
||
规则:
|
||
|
||
1. `in` 参数按值传入,子程序内修改不影响调用者。
|
||
2. `out` 参数调用前不要求有有效值,子程序必须在所有正常返回路径上赋值。
|
||
3. `inout` 参数按引用语义传入,子程序内修改会回写调用者。
|
||
4. `out` 和 `inout` 实参必须是可赋值左值,不能是字面量或表达式。
|
||
5. 后处理到不支持显式参数方向的品牌时,可生成临时变量、寄存器或转换报告。
|
||
|
||
调用示例:
|
||
|
||
```text
|
||
var bool ok = false
|
||
var int retry = 0
|
||
|
||
call read_part(ok)
|
||
call increment_retry(retry)
|
||
```
|
||
|
||
### 15.3 `func` 函数
|
||
|
||
`func` 有返回值,适合计算条件、选择目标点、计算偏移、读取配方参数。函数应尽量无副作用。
|
||
|
||
```text
|
||
func bool is_part_ready()
|
||
return io.di[1] == true and io.di[2] == false
|
||
end
|
||
```
|
||
|
||
带参数函数:
|
||
|
||
```text
|
||
func pose_target slot_pose(int slot)
|
||
return base_pick offset x (slot * 50 mm)
|
||
end
|
||
|
||
func bool can_retry(int retry, int max_retry)
|
||
return retry < max_retry
|
||
end
|
||
```
|
||
|
||
调用方式:
|
||
|
||
```text
|
||
if can_retry(retry, max_retry)
|
||
call retry_pick()
|
||
end
|
||
|
||
movel slot_pose(slot_id) speed linear(200 mm/s) zone z10
|
||
```
|
||
|
||
规则:
|
||
|
||
1. `func` 必须声明返回类型。
|
||
2. 所有正常返回路径必须返回兼容类型的值。
|
||
3. `func` 允许调用其他 `func`。
|
||
4. `func` 默认不允许执行运动指令、`wait`、`pulse`、`run_path`、`run_operation`。编译器应把这类用法作为 error 或强 warning。
|
||
5. 如果确实需要带副作用的逻辑,应使用 `proc`。
|
||
|
||
### 15.4 作用域和名称解析
|
||
|
||
名称解析顺序:
|
||
|
||
1. 当前块局部变量。
|
||
2. 当前 `proc/func` 参数。
|
||
3. 当前模块中的 `const/var/persistent/target/path/operation/proc/func`。
|
||
4. `import` 模块导出的符号。
|
||
5. 内置函数和内置类型。
|
||
|
||
规则:
|
||
|
||
1. 内层局部变量允许遮蔽外层变量,但编译器应对同名遮蔽给出 warning。
|
||
2. 不允许局部变量与同一作用域内的 `proc/func/target/path/operation` 重名。
|
||
3. `for` 循环变量只在循环体内有效。
|
||
4. `label` 只在当前 `proc` 内有效。
|
||
|
||
### 15.5 子程序调用和后处理
|
||
|
||
后处理映射:
|
||
|
||
| GRL | ABB RAPID | FANUC LS/TP | KUKA KRL |
|
||
| --- | --- | --- | --- |
|
||
| `proc name()` | `PROC name()` | `/PROG NAME` 或子程序 | `DEF name()` |
|
||
| `call sub()` | `sub;` 或 `sub()` | `CALL SUB` | `sub()` |
|
||
| `return` | `RETURN` | `END`/跳转近似 | `RETURN` |
|
||
| `out/inout` 参数 | `VAR` 参数或数据变量 | 寄存器/PR/临时变量近似 | 参数或全局变量近似 |
|
||
|
||
如果目标品牌或输出格式不支持某种参数模式,后处理器必须生成转换报告,不能静默丢失语义。
|
||
|
||
## 16. 异常、报警和中断
|
||
|
||
### 16.1 alarm 和 raise
|
||
|
||
```text
|
||
alarm "Part not detected"
|
||
raise E_PICK_FAILED
|
||
```
|
||
|
||
### 16.2 try/catch
|
||
|
||
```text
|
||
try
|
||
run_operation pick_op
|
||
catch E_PICK_FAILED
|
||
call recover_pick()
|
||
finally
|
||
io.do[1] = false
|
||
end
|
||
```
|
||
|
||
首版可先实现 `alarm`、`raise` 和简单 `catch`,复杂品牌错误恢复分阶段支持。
|
||
|
||
### 16.3 trap 和 interrupt
|
||
|
||
```text
|
||
trap emergency_stop()
|
||
stop_motion
|
||
io.do[100] = false
|
||
alarm "Emergency stop input"
|
||
end
|
||
|
||
interrupt e_stop when io.di[100] == true call emergency_stop()
|
||
enable interrupt e_stop
|
||
disable interrupt e_stop
|
||
```
|
||
|
||
后处理映射:
|
||
|
||
1. ABB 可映射到 `TRAP` 和 interrupt 机制。
|
||
2. KUKA 可映射到 `INTERRUPT DECL`、`INTERRUPT ON/OFF` 等近似结构。
|
||
3. FANUC 首版可生成后台逻辑、条件监控或转换报告。
|
||
|
||
## 17. 多任务
|
||
|
||
首版只定义语法,不要求完整实现多任务实时调度:
|
||
|
||
```text
|
||
task background monitor_io cycle 20 ms
|
||
if io.di[99] == true
|
||
alarm "Safety signal lost"
|
||
end
|
||
end
|
||
```
|
||
|
||
虚拟控制器可先按周期任务模拟;后处理时根据品牌能力生成后台任务或转换报告。
|
||
|
||
## 18. 品牌扩展和后处理提示
|
||
|
||
### 18.1 post_hint
|
||
|
||
```text
|
||
post_hint abb {
|
||
module_name: "MainModule"
|
||
use_wobj: true
|
||
}
|
||
|
||
post_hint fanuc {
|
||
program_name: "MAIN"
|
||
default_uframe: 1
|
||
default_utool: 1
|
||
}
|
||
|
||
post_hint kuka {
|
||
src_name: "MAIN"
|
||
dat_name: "MAIN"
|
||
advance: 3
|
||
}
|
||
```
|
||
|
||
### 18.2 brand metadata
|
||
|
||
```text
|
||
@brand.abb {
|
||
conf_l: true
|
||
}
|
||
|
||
@brand.fanuc {
|
||
group: 1
|
||
cnt: 50
|
||
}
|
||
|
||
@brand.kuka {
|
||
c_dis: true
|
||
}
|
||
```
|
||
|
||
规则:
|
||
|
||
1. `@brand.*` 只影响指定品牌后处理。
|
||
2. 通用虚拟控制器不应依赖品牌 metadata 才能执行。
|
||
3. 无法支持的品牌扩展必须进入转换报告。
|
||
|
||
## 19. 自动编程生成规则
|
||
|
||
自动生成 GRL 时,应遵循以下规则:
|
||
|
||
1. 优先生成 `target`、`path`、`operation`,不要直接把大量运动语句塞进 `proc main()`。
|
||
2. 目标点命名稳定,推荐 `T_{path}_{index}` 或语义名称,例如 `T_PICK_APPROACH`。
|
||
3. 路径点命名稳定,推荐 `p000`、`p001`、`p002`。
|
||
4. 路径整体参数放入 `defaults`,单点差异写在 point 上。
|
||
5. 接近点、工艺开始点、工艺结束点、离开点必须显式标注。
|
||
6. IO、夹具、焊接开关、喷涂开关应生成 path event 或 operation action。
|
||
7. CAD 来源、曲线 ID、采样距离、法向策略必须写入 `source`。
|
||
8. 自动生成文本必须格式化稳定,同一输入重复生成结果一致。
|
||
9. 编译器应能把 GRL 再解析回等价 OLP 对象模型。
|
||
10. 后处理器应能选择 `compact` 或 `expanded` 输出风格。
|
||
|
||
生成风格:
|
||
|
||
```text
|
||
// compact
|
||
proc main()
|
||
run_operation weld_op_01
|
||
end
|
||
|
||
// expanded
|
||
proc main()
|
||
movel T001 speed linear(120 mm/s) zone z5 tool torch frame part_frame
|
||
movel T002 speed linear(120 mm/s) zone z5 tool torch frame part_frame
|
||
end
|
||
```
|
||
|
||
## 20. 后处理映射规则
|
||
|
||
### 20.1 ABB RAPID
|
||
|
||
| GRL | ABB RAPID |
|
||
| --- | --- |
|
||
| `module` | `MODULE` |
|
||
| `proc` | `PROC` |
|
||
| `movej` | `MoveJ` |
|
||
| `movel` | `MoveL` |
|
||
| `movec` | `MoveC` |
|
||
| `pose_target` | `robtarget` |
|
||
| `joint_target` | `jointtarget` |
|
||
| `tool` | `tooldata` |
|
||
| `frame` | `wobjdata` |
|
||
| `linear(300 mm/s)` | `v300` 或自定义 `speeddata` |
|
||
| `fine`、`z(10 mm)` | `fine`、`z10` 或自定义 `zonedata` |
|
||
| `io.do[1] = true` | `SetDO do1, 1` |
|
||
| `wait io.di[1] == true` | `WaitDI di1, 1` |
|
||
|
||
示例:
|
||
|
||
```text
|
||
movel pick speed linear(300 mm/s) zone z10 tool gripper frame fixture
|
||
```
|
||
|
||
可后处理为:
|
||
|
||
```text
|
||
MoveL pick, v300, z10, gripper\WObj:=fixture;
|
||
```
|
||
|
||
### 20.2 FANUC LS/TP 风格
|
||
|
||
| GRL | FANUC |
|
||
| --- | --- |
|
||
| `proc main()` | `/PROG MAIN` |
|
||
| `movej` | `J P[...]` |
|
||
| `movel` | `L P[...]` |
|
||
| `movec` | `C P[...]` |
|
||
| `pose_target` | `P[...]` 或 `PR[...]` |
|
||
| `tool` | UTOOL |
|
||
| `frame` | UFRAME |
|
||
| `joint(50 %)` | `50%` |
|
||
| `linear(300 mm/s)` | `300mm/sec` |
|
||
| `fine` | `FINE` |
|
||
| `cnt(50)` | `CNT50` |
|
||
| `io.do[1] = true` | `DO[1]=ON` |
|
||
| `wait io.di[1] == true` | `WAIT DI[1]=ON` |
|
||
|
||
示例:
|
||
|
||
```text
|
||
movel P10 speed linear(300 mm/s) zone cnt(10)
|
||
```
|
||
|
||
可后处理为:
|
||
|
||
```text
|
||
L P[10] 300mm/sec CNT10 ;
|
||
```
|
||
|
||
### 20.3 KUKA KRL
|
||
|
||
| GRL | KUKA KRL |
|
||
| --- | --- |
|
||
| `proc main()` | `DEF MAIN()` |
|
||
| `movej` | `PTP` |
|
||
| `movel` | `LIN` |
|
||
| `movec` | `CIRC` |
|
||
| `pose_target` | `E6POS` |
|
||
| `joint_target` | `E6AXIS` |
|
||
| `tool` | `$TOOL` |
|
||
| `frame` | `$BASE` |
|
||
| `linear(300 mm/s)` | `$VEL.CP = 0.3` |
|
||
| `fine` | no approximation |
|
||
| `continuous`、`z(...)` | `C_DIS` 或 `$APO` |
|
||
| `io.do[1] = true` | `$OUT[1] = TRUE` |
|
||
| `wait io.di[1] == true` | `WAIT FOR $IN[1] == TRUE` |
|
||
|
||
示例:
|
||
|
||
```text
|
||
movel XPICK speed linear(300 mm/s) zone continuous
|
||
```
|
||
|
||
可后处理为:
|
||
|
||
```text
|
||
$VEL.CP = 0.3
|
||
LIN XPICK C_DIS
|
||
```
|
||
|
||
## 21. 编译语义和 IR
|
||
|
||
编译管线:
|
||
|
||
```text
|
||
GRL Source
|
||
-> Lexer
|
||
-> Parser
|
||
-> AST
|
||
-> Symbol Table
|
||
-> Semantic Analyzer
|
||
-> Executable IR
|
||
-> Virtual Controller
|
||
-> Post Processor
|
||
```
|
||
|
||
运动 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;
|
||
sourceObject?: {
|
||
pathId?: string;
|
||
pointId?: string;
|
||
operationId?: string;
|
||
};
|
||
brandMeta?: Record<string, unknown>;
|
||
}
|
||
```
|
||
|
||
## 22. 语义检查
|
||
|
||
编译器必须检查:
|
||
|
||
1. 标识符是否重复或未声明。
|
||
2. 类型是否匹配。
|
||
3. 目标点类型是否适合运动指令。
|
||
4. `movec` 是否缺少 via 点。
|
||
5. 圆弧三点是否重合或共线。
|
||
6. 工具、坐标系、速度、过渡是否可解析。
|
||
7. 单位是否正确。
|
||
8. 表达式优先级、括号、函数调用参数是否解析正确。
|
||
9. 内置函数名称、参数数量、定义域和单位维度是否正确。
|
||
10. 需要常量的位置是否只使用常量表达式。
|
||
11. 除零、未知符号、未知函数和复杂运行时表达式是否产生稳定 diagnostic。
|
||
12. IO 地址是否存在于 IO map 或允许范围。
|
||
13. 子程序参数数量和类型是否匹配。
|
||
14. `out` 参数是否在所有正常返回路径上赋值。
|
||
15. `inout` 和 `out` 实参是否为可赋值左值。
|
||
16. `func` 是否在所有正常返回路径上返回正确类型。
|
||
17. `break`、`continue` 是否出现在合法结构内。
|
||
18. `switch case` 是否为常量表达式,是否存在重复 case。
|
||
19. `jump` 是否跳入非法块结构。
|
||
20. `wait` 是否有可执行条件。
|
||
21. Path 是否为空。
|
||
22. Path point 名称是否重复。
|
||
23. Operation 是否引用不存在的 Path。
|
||
24. 目标点是否可达。
|
||
25. 关节是否超限。
|
||
26. 后处理目标品牌是否支持所用语义。
|
||
|
||
诊断格式建议:
|
||
|
||
```text
|
||
E1001: target 'pick' is not defined
|
||
E2003: movec points are collinear: start=p0, via=p1, target=p2
|
||
W3002: zone z50 is larger than segment length
|
||
W4001: KUKA post approximates GRL cnt(30) by C_DIS
|
||
```
|
||
|
||
## 23. EBNF 语法草案
|
||
|
||
以下是首版解析器可采用的简化 EBNF:
|
||
|
||
```text
|
||
program = [ language_decl ] module_decl ;
|
||
language_decl = "language" "grl" version ;
|
||
module_decl = "module" identifier { top_decl } "end" ;
|
||
|
||
top_decl = import_decl
|
||
| data_decl
|
||
| target_decl
|
||
| path_decl
|
||
| operation_decl
|
||
| proc_decl
|
||
| func_decl
|
||
| trap_decl
|
||
| task_decl
|
||
| post_hint_decl ;
|
||
|
||
import_decl = "import" identifier ;
|
||
data_decl = ( "persistent" | "const" | "var" ) type identifier "=" expr ;
|
||
target_decl = "target" identifier "=" ( joint_target | pose_target ) ;
|
||
|
||
joint_target = "joint_target" "{" "joints" ":" array [ "," ext_axis ] "}" ;
|
||
pose_target = "pose_target" "{" "pose" ":" pose_expr
|
||
[ "," "config" ":" config_expr ]
|
||
[ "," "tool" ":" identifier ]
|
||
[ "," "frame" ":" identifier ] "}" ;
|
||
|
||
path_decl = "path" identifier "{" { path_item } "}" ;
|
||
path_item = defaults_block | source_block | path_point | path_event ;
|
||
defaults_block = "defaults" "{" { property } "}" ;
|
||
source_block = "source" "{" { property } "}" ;
|
||
path_point = "point" identifier motion_stmt ;
|
||
path_event = "event" ( ( "before" | "after" ) identifier
|
||
| "at" identifier "distance" expr ) statement ;
|
||
|
||
operation_decl = "operation" identifier "{"
|
||
"kind" ":" identifier
|
||
"path" ":" identifier
|
||
[ process_block ]
|
||
[ action_block ]
|
||
"}" ;
|
||
|
||
proc_decl = "proc" identifier "(" [ param_list ] ")" { statement } "end" ;
|
||
func_decl = "func" type identifier "(" [ param_list ] ")" { statement } "end" ;
|
||
trap_decl = "trap" identifier "(" ")" { statement } "end" ;
|
||
|
||
statement = motion_stmt
|
||
| run_stmt
|
||
| assign_stmt
|
||
| wait_stmt
|
||
| pulse_stmt
|
||
| if_stmt
|
||
| while_stmt
|
||
| for_stmt
|
||
| switch_stmt
|
||
| call_stmt
|
||
| return_stmt
|
||
| break_stmt
|
||
| continue_stmt
|
||
| label_stmt
|
||
| jump_stmt
|
||
| alarm_stmt
|
||
| try_stmt ;
|
||
|
||
motion_stmt = movej_stmt | movel_stmt | movec_stmt ;
|
||
target_expr = target_ref [ offset_clause ] | pose_expr ;
|
||
offset_clause = "offset" { axis length }
|
||
| "offset_in" ( "tool" | "frame" identifier ) { axis length } ;
|
||
movej_stmt = "movej" target_expr motion_params ;
|
||
movel_stmt = "movel" target_expr motion_params ;
|
||
movec_stmt = "movec" "via" target_expr "target" target_expr motion_params ;
|
||
|
||
motion_params = [ "speed" speed_expr ] [ "zone" zone_expr ]
|
||
[ "tool" identifier ] [ "frame" identifier ] ;
|
||
|
||
run_stmt = "run_path" identifier | "run_operation" identifier ;
|
||
wait_stmt = "wait" expr [ "timeout" duration ] [ "on_timeout" timeout_action ] ;
|
||
pulse_stmt = "pulse" io_ref "duration" duration ;
|
||
assign_stmt = lvalue "=" expr ;
|
||
call_stmt = "call" identifier "(" [ arg_list ] ")" ;
|
||
return_stmt = "return" [ expr ] ;
|
||
break_stmt = "break" ;
|
||
continue_stmt = "continue" ;
|
||
|
||
if_stmt = "if" expr { statement }
|
||
{ "elseif" expr { statement } }
|
||
[ "else" { statement } ]
|
||
"end" ;
|
||
|
||
while_stmt = "while" expr { statement } "end" ;
|
||
for_stmt = "for" identifier "=" expr "to" expr [ "step" expr ] { statement } "end" ;
|
||
|
||
switch_stmt = "switch" expr { case_clause } [ default_clause ] "end" ;
|
||
case_clause = "case" const_expr { "," const_expr } { statement } ;
|
||
default_clause = "default" { statement } ;
|
||
|
||
label_stmt = "label" identifier ;
|
||
jump_stmt = "jump" identifier ;
|
||
|
||
param_list = param { "," param } ;
|
||
param = [ "in" | "out" | "inout" ] type identifier ;
|
||
arg_list = expr { "," expr } ;
|
||
const_expr = expr ;
|
||
duration = expr ;
|
||
length = expr ;
|
||
speed_expr = expr ;
|
||
zone_expr = expr ;
|
||
|
||
expr = or_expr ;
|
||
or_expr = and_expr { ( "or" | "||" ) and_expr } ;
|
||
and_expr = equality_expr { ( "and" | "&&" ) equality_expr } ;
|
||
equality_expr = relation_expr { ( "==" | "!=" ) relation_expr } ;
|
||
relation_expr = additive_expr { ( "<" | "<=" | ">" | ">=" ) additive_expr } ;
|
||
additive_expr = multiply_expr { ( "+" | "-" ) multiply_expr } ;
|
||
multiply_expr = unary_expr { ( "*" | "/" | "mod" ) unary_expr } ;
|
||
unary_expr = [ "+" | "-" | "not" | "!" ] postfix_expr ;
|
||
postfix_expr = primary_expr { unit_suffix | offset_clause } ;
|
||
unit_suffix = unit ;
|
||
primary_expr = literal
|
||
| identifier
|
||
| io_ref
|
||
| call_expr
|
||
| array
|
||
| object
|
||
| "(" expr ")" ;
|
||
call_expr = identifier "(" [ arg_list ] ")" ;
|
||
literal = number | string | "true" | "false" ;
|
||
```
|
||
|
||
## 24. 完整示例
|
||
|
||
```text
|
||
language grl 0.1
|
||
|
||
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)
|
||
}
|
||
|
||
const speed v_fast = joint(70 %)
|
||
const speed v_pick = linear(300 mm/s)
|
||
const zone z_pick = z(10 mm)
|
||
|
||
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
|
||
}
|
||
|
||
target place = pose_target {
|
||
pose: pose(650 mm, -100 mm, 320 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: v_pick,
|
||
zone: z_pick
|
||
}
|
||
|
||
point approach movej home speed v_fast zone fine
|
||
point above_pick movel pick offset z 100 mm
|
||
point at_pick movel pick zone fine
|
||
event after at_pick io.do[1] = true
|
||
event after at_pick wait io.di[1] == true timeout 2 s on_timeout alarm "Clamp close timeout"
|
||
point leave_pick movel pick offset z 100 mm
|
||
}
|
||
|
||
path place_path {
|
||
defaults {
|
||
tool: gripper,
|
||
frame: fixture,
|
||
speed: v_pick,
|
||
zone: z_pick
|
||
}
|
||
|
||
point above_place movel place offset z 100 mm
|
||
point at_place movel place zone fine
|
||
event after at_place io.do[1] = false
|
||
event after at_place wait io.di[2] == true timeout 2 s on_timeout alarm "Clamp open timeout"
|
||
point leave_place movel place offset z 100 mm
|
||
}
|
||
|
||
operation pick_op {
|
||
kind: handling
|
||
path: pick_path
|
||
process {
|
||
gripper: "main_clamp"
|
||
}
|
||
}
|
||
|
||
operation place_op {
|
||
kind: handling
|
||
path: place_path
|
||
process {
|
||
gripper: "main_clamp"
|
||
}
|
||
}
|
||
|
||
proc main()
|
||
set_tool gripper
|
||
set_frame fixture
|
||
|
||
run_operation pick_op
|
||
run_operation place_op
|
||
|
||
movej home speed v_fast zone fine
|
||
end
|
||
|
||
end
|
||
```
|
||
|
||
## 25. 实施优先级
|
||
|
||
P0 必须实现:
|
||
|
||
1. `language`、`module`、`proc`。
|
||
2. `const`、`var`、`persistent`。
|
||
3. `tool`、`frame`、`speed`、`zone`。
|
||
4. `joint_target`、`pose_target`。
|
||
5. `movej`、`movel`、`movec`。
|
||
6. `path`、`point`、`event`、`run_path`。
|
||
7. `operation`、`run_operation`。
|
||
8. `if`、`elseif`、`else`、`while`、`for`、`switch`。
|
||
9. `call`、`return`、`break`、`continue`。
|
||
10. `proc` 参数方向 `in/out/inout`。
|
||
11. `func`、函数调用表达式和返回值检查。
|
||
12. 表达式 parser、单位后缀、内置数学函数、三角函数和编译期常量求值。
|
||
13. `io.do/di`、`wait`、`pulse`。
|
||
14. AST、语义检查、IR、source map。
|
||
15. ABB、FANUC、KUKA 后处理原型。
|
||
|
||
P1 扩展:
|
||
|
||
1. `label/jump` 和品牌标签程序导入。
|
||
2. `trap`、`interrupt`。
|
||
3. 多任务 `task`。
|
||
4. 更完整的 IO 类型。
|
||
5. 工艺模板库。
|
||
6. 品牌程序导入。
|
||
7. 复杂品牌扩展和转换报告。
|
||
|
||
## 26. 参考资料
|
||
|
||
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. KUKA System Software,说明 KSS 支持 InLine forms 和 KRL 专家编程:
|
||
https://www.kuka.com/de-de/produkte-leistungen/robotersysteme/software/systemsoftware/kuka_systemsoftware
|
||
|
||
4. KUKA Application and Robot Programming,说明 KRL、Sunrise programming、simulation/offline programming 等工作流:
|
||
https://www.kuka.com/en-de/services/service_robots-and-machines/installation-start-up-and-programming-of-robots/application-and-robot-programming
|
||
|
||
5. FANUC PLC Motion Interface,说明 FANUC 可从上位控制发起 linear、joint、circular robot motion,并管理 speeds 与 termination types:
|
||
https://www.fanucamerica.com/products/software/plc-motion-interface
|
||
|
||
6. FANUC ROBOGUIDE,说明 FANUC 离线编程可生成机器人程序,并支持 CAD to Path、仿真和路径开发:
|
||
https://www.fanucamerica.com/products/software/roboguide
|
||
|
||
7. FANUC ASCII Program Loader,说明 FANUC LS 可读程序可编译为 TP 程序:
|
||
https://www.fanucamerica.com/products/controller-series/r-50ia
|