Files
KDL_WORK/work/doc/通用机器人编程语法规范.md
2026-06-28 20:58:18 +08:00

46 KiB
Raw Blame History

通用机器人编程语法规范

版本0.1
适用范围:离线编程、虚拟控制器、虚拟调试、多品牌后处理
目标品牌ABB RAPID、FANUC TP/LS/KAREL 语义、KUKA KRL

1. 设计目标

本规范定义一种用于离线编程和虚拟调试的通用机器人程序语言,暂定名为 GRLGeneric 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/.datDEF module
子程序 PROC CALL DEF 子程序 proc
函数 FUNC KAREL function DEFFCT func
中断/陷阱 TRAP、interrupt 条件监控、后台逻辑 INTERRUPT trapinterrupt
关节运动 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
过渡 zonedatafine FINECNT C_DISC_PTPAPO zone
IO SetDOWaitDI DO[]DI[]WAIT $OUT[]$IN[]WAIT FOR io.*wait
标签跳转 GOTO LBLJMP GOTO labeljump

2.2 中性语法风格

GRL 采用“声明式数据 + 结构化程序 + Path/Operation 对象”的风格:

  1. 目标点、工具、坐标系、速度、过渡作为数据声明。
  2. 程序流程使用 procifwhileforswitch 等结构化控制。
  3. 短程序和调试程序可直接写 movej/movel/movec
  4. 自动离线编程优先生成 pathoperation,程序中通过 run_pathrun_operation 调用。
  5. 所有运动语句显式绑定目标点、速度、过渡、工具、坐标系,允许默认值,但编译到 IR 前必须解析为确定值。
  6. 品牌特性通过 post_hint@brand.* 元数据保留,不污染通用语义。

3. 文件与工程结构

推荐一个 OLP 项目使用以下结构:

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 注释

// 单行注释

/*
  多行注释
*/

自动生成程序应在关键对象上保留来源注释,但不要为每个采样点生成大量冗余注释。

4.3 标识符

identifier = letter { letter | digit | "_" }

示例:

pick_path
weld_op_01
T_curve_032_000

不建议使用中文标识符。UI 可显示中文别名,但程序内部名称应保持 ASCII便于后处理和版本管理。

4.4 字面量和单位

支持带单位数值:

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 保留关键字

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 最小文件

language grl 0.1

module Main
  proc main()
    // program entry
  end
end

language grl 0.1 用于版本控制。后续语言升级时,编译器可按版本选择兼容规则。

5.2 顶层声明

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 变量声明

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. 逻辑:andornot;可兼容 &&||! 作为输入别名IR 中统一为 GRL 关键字。
  4. 括号:(...) 显式改变优先级。
  5. 函数调用:callee(args...),参数内部允许完整表达式。
  6. 单位后缀:可作用于数字字面量、标识符、函数调用或括号表达式,例如 100 mmblend_base mmsqrt(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 自然常数

首版内置函数:

类别 函数
三角函数 sincostanasinacosatanatan2
数值函数 sqrtabspowminmaxclampfloorceilround

函数规则:

  1. sin/cos/tan 接收角度量;带 degrad 单位时归一化为弧度,纯数按弧度处理。
  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/sangular(...) 默认 deg/sz(...) 默认 mmpose(...) 前三项默认 mm、后三项默认 degjoint_target.joints 默认 degtimeout/duration 默认 s
  5. 因此 linear(100 + 50 mm/s)linear 速度上下文中等价于 linear(150 mm/s);自动生成程序推荐输出显式单位,减少人工歧义。

7.4 编译期求值位置

常量表达式必须在编译阶段求值,并把结果写入 Semantic IR / KDL request而不是把表达式字符串传到运动规划层。

必须支持的求值位置:

  1. 数据声明 initializerconstpersistent、需要静态初值的 var
  2. speedlinear(...)joint(...)angular(...)acc ... 参数。
  3. zonefinez(...)cnt(...)
  4. pose(...)poseq(...)robot_config(...)
  5. joint_target { joints: [...] }
  6. pose_target { pose: ... }
  7. tool { tcp: ..., mass: ... }frame { origin: ... }
  8. path defaultssource 属性和 path point 内联 speedzonetoolframeviatarget 参数。
  9. path event 的 distance
  10. wait ... timeout ...pulse ... duration ... 中的时间常量。
  11. operation process 中需要数值常量的工艺参数。
  12. switch case 值。

比较和逻辑表达式也必须进入 AST。纯常量比较/逻辑可在编译期折叠;依赖 IO、变量或运行态状态的条件先保留为结构化控制表达式供虚拟控制器和后续品牌映射使用。

7.5 示例

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 工具

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 工件坐标

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

8.3 关节目标点

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 笛卡尔目标点

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() 参数顺序为:

pose(x, y, z, rx, ry, rz)

首版 rx/ry/rz 使用固定约定的欧拉角,建议内部立即转换为四元数。为了避免姿态歧义,也允许使用四元数:

poseq(500 mm, 120 mm, 300 mm, 0, 0, 0.7071068, 0.7071068)

8.5 偏移目标点

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 下解释。需要明确坐标系时:

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 速度

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. 加速度可作为可选参数:
const speed v_slow = linear(100 mm/s, acc 500 mm/s2)

9.2 过渡

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 基本语法

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]

示例:

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. 后处理映射:
    • ABBMoveJ
    • FANUCJ P[...]
    • KUKAPTP

10.3 MOVEL 语义

movel 表示 TCP 直线运动。TCP 沿起点到终点的空间直线运行,关节角由每个 TCP 采样点 IK 求解。

编译规则:

  1. 目标必须能解析为笛卡尔位姿。
  2. 当前点作为直线起点。
  3. 姿态按默认策略插补,首版推荐固定姿态或 slerp。
  4. 后处理映射:
    • ABBMoveL
    • FANUCL P[...]
    • KUKALIN

10.4 MOVEC 语义

movec 表示 TCP 圆弧运动。TCP 从当前点出发,经过 via 点,到达 target 点,沿圆弧运行,关节角由每个圆弧采样点 IK 求解。

编译规则:

  1. 起点为当前 TCP。
  2. viatarget 必须能解析为笛卡尔位姿。
  3. 三点不能重合或近似共线。
  4. 首版使用 via 点位置约束圆弧,姿态按起点到终点插补。
  5. 后处理映射:
    • ABBMoveC
    • FANUCC P[...]
    • KUKACIRC

10.5 当前工具和当前坐标

set_tool gripper
set_frame fixture
set_speed linear(300 mm/s)
set_zone z10

参数优先级:

  1. 运动语句显式参数最高。
  2. path defaults 次之。
  3. 目标点自带 tool/frame 次之。
  4. 当前控制器状态最低。

编译到 IR 时,所有运动必须有确定的 toolframespeedzone

11. Path 语法

Path 是自动离线编程的核心对象。CAD 曲线、规划点、示教点、工艺模板应优先生成 Path而不是直接生成散乱运动语句。

11.1 基本语法

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 圆弧点

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 来源元数据

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

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

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 更高一层。

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

proc main()
  run_operation weld_op_01
end

编译语义:

  1. 执行 start_action
  2. 执行 operation 引用的 path。
  3. 执行 end_action
  4. 保留工艺参数,供仿真 UI、报告和后处理使用。

13. IO 与等待

13.1 IO 地址

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 提供别名:

io.alias.clamp_open
io.alias.clamp_closed
io.alias.gripper_close_cmd

13.2 IO 写入

io.do[1] = true
io.go[1] = 16
io.ao[1] = 3.5

13.3 wait

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

超时处理:

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

pulse io.do[3] duration 200 ms

虚拟控制器语义:

  1. 立即置位输出。
  2. 虚拟时间到达 duration 后自动复位。
  3. trace 中必须记录置位和复位事件。

14. 流程控制

流程控制用于表达工艺分支、重试、配方选择、批量工位循环和异常恢复。GRL 新程序应优先使用结构化控制流;label/jump 主要用于兼容 FANUC TP/LS 等已有程序导入。

14.1 条件 if / elseif / else

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 可解析。

常用条件表达式:

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 循环

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除非循环体内包含明确的 breakreturnraisewait

14.3 for 循环

for i = 0 to 9 step 1
  call process_slot(i)
end

也允许省略 step,默认步长为 1

for layer = 1 to layer_count
  call weld_layer(layer)
end

反向循环:

for i = 10 to 0 step -1
  call clear_slot(i)
end

语义规则:

  1. 循环变量默认是当前 for 块局部变量。
  2. 起点、终点、步长必须是整数或可安全转换为整数。
  3. step 不能为 0
  4. breakcontinue 只影响当前最近一层循环。
  5. 后处理到不支持结构化 for 的品牌时,可展开为标签和跳转,但必须保持 source map。

14.4 switch / case / default

switch recipe_id
  case 1
    run_operation op_a
  case 2
    run_operation op_b
  default
    alarm "Unknown recipe"
end

语义规则:

  1. switch 表达式可以是 intboolstring 或枚举型。
  2. case 值必须是常量表达式。
  3. 每个 case 默认不向下贯穿,不需要写 break
  4. default 最多出现一次。
  5. 若需要多个值进入同一分支,可以使用逗号:
switch recipe_id
  case 1, 2, 3
    run_operation common_recipe
  case 10
    run_operation special_recipe
  default
    alarm "Unknown recipe"
end
  1. 导出到 FANUC TP/LS 时,switch 可转换为 SELECT、条件跳转或 LBL/JMP 组合。
  2. 导出到 ABB/KUKA 时,优先转换为品牌结构化分支。

14.5 breakcontinue

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 只能出现在 whileforswitch 中。
  2. continue 只能出现在 whilefor 中。
  3. switch 中不需要 break 防止贯穿,因为 GRL 默认不贯穿。

14.6 label 和 jump

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 流程和恢复逻辑。

proc pick_part(int slot)
  movej home speed joint(60 %) zone fine
  run_path pick_path
end

调用:

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 参数方向

参数支持 inoutinout 三种方向。未写方向时默认为 in

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. outinout 实参必须是可赋值左值,不能是字面量或表达式。
  5. 后处理到不支持显式参数方向的品牌时,可生成临时变量、寄存器或转换报告。

调用示例:

var bool ok = false
var int retry = 0

call read_part(ok)
call increment_retry(retry)

15.3 func 函数

func 有返回值,适合计算条件、选择目标点、计算偏移、读取配方参数。函数应尽量无副作用。

func bool is_part_ready()
  return io.di[1] == true and io.di[2] == false
end

带参数函数:

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

调用方式:

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 默认不允许执行运动指令、waitpulserun_pathrun_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

alarm "Part not detected"
raise E_PICK_FAILED

16.2 try/catch

try
  run_operation pick_op
catch E_PICK_FAILED
  call recover_pick()
finally
  io.do[1] = false
end

首版可先实现 alarmraise 和简单 catch,复杂品牌错误恢复分阶段支持。

16.3 trap 和 interrupt

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 DECLINTERRUPT ON/OFF 等近似结构。
  3. FANUC 首版可生成后台逻辑、条件监控或转换报告。

17. 多任务

首版只定义语法,不要求完整实现多任务实时调度:

task background monitor_io cycle 20 ms
  if io.di[99] == true
    alarm "Safety signal lost"
  end
end

虚拟控制器可先按周期任务模拟;后处理时根据品牌能力生成后台任务或转换报告。

18. 品牌扩展和后处理提示

18.1 post_hint

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

@brand.abb {
  conf_l: true
}

@brand.fanuc {
  group: 1
  cnt: 50
}

@brand.kuka {
  c_dis: true
}

规则:

  1. @brand.* 只影响指定品牌后处理。
  2. 通用虚拟控制器不应依赖品牌 metadata 才能执行。
  3. 无法支持的品牌扩展必须进入转换报告。

19. 自动编程生成规则

自动生成 GRL 时,应遵循以下规则:

  1. 优先生成 targetpathoperation,不要直接把大量运动语句塞进 proc main()
  2. 目标点命名稳定,推荐 T_{path}_{index} 或语义名称,例如 T_PICK_APPROACH
  3. 路径点命名稳定,推荐 p000p001p002
  4. 路径整体参数放入 defaults,单点差异写在 point 上。
  5. 接近点、工艺开始点、工艺结束点、离开点必须显式标注。
  6. IO、夹具、焊接开关、喷涂开关应生成 path event 或 operation action。
  7. CAD 来源、曲线 ID、采样距离、法向策略必须写入 source
  8. 自动生成文本必须格式化稳定,同一输入重复生成结果一致。
  9. 编译器应能把 GRL 再解析回等价 OLP 对象模型。
  10. 后处理器应能选择 compactexpanded 输出风格。

生成风格:

// 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
finez(10 mm) finez10 或自定义 zonedata
io.do[1] = true SetDO do1, 1
wait io.di[1] == true WaitDI di1, 1

示例:

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

可后处理为:

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

示例:

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

可后处理为:

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
continuousz(...) C_DIS$APO
io.do[1] = true $OUT[1] = TRUE
wait io.di[1] == true WAIT FOR $IN[1] == TRUE

示例:

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

可后处理为:

$VEL.CP = 0.3
LIN XPICK C_DIS

21. 编译语义和 IR

编译管线:

GRL Source
  -> Lexer
  -> Parser
  -> AST
  -> Symbol Table
  -> Semantic Analyzer
  -> Executable IR
  -> Virtual Controller
  -> Post Processor

运动 IR 示例:

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. inoutout 实参是否为可赋值左值。
  16. func 是否在所有正常返回路径上返回正确类型。
  17. breakcontinue 是否出现在合法结构内。
  18. switch case 是否为常量表达式,是否存在重复 case。
  19. jump 是否跳入非法块结构。
  20. wait 是否有可执行条件。
  21. Path 是否为空。
  22. Path point 名称是否重复。
  23. Operation 是否引用不存在的 Path。
  24. 目标点是否可达。
  25. 关节是否超限。
  26. 后处理目标品牌是否支持所用语义。

诊断格式建议:

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

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. 完整示例

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. languagemoduleproc
  2. constvarpersistent
  3. toolframespeedzone
  4. joint_targetpose_target
  5. movejmovelmovec
  6. pathpointeventrun_path
  7. operationrun_operation
  8. ifelseifelsewhileforswitch
  9. callreturnbreakcontinue
  10. proc 参数方向 in/out/inout
  11. func、函数调用表达式和返回值检查。
  12. 表达式 parser、单位后缀、内置数学函数、三角函数和编译期常量求值。
  13. io.do/diwaitpulse
  14. AST、语义检查、IR、source map。
  15. ABB、FANUC、KUKA 后处理原型。

P1 扩展:

  1. label/jump 和品牌标签程序导入。
  2. trapinterrupt
  3. 多任务 task
  4. 更完整的 IO 类型。
  5. 工艺模板库。
  6. 品牌程序导入。
  7. 复杂品牌扩展和转换报告。

26. 参考资料

  1. ABB RAPID Technical Reference ManualRAPID 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