2. URScript程序结构解析
URScript 程序在控制器中并不是以“一个文件跑到底”的方式存在,而是由若干结构单元组合而成。理解这些结构单元,是后续编写可维护、可复用程序的基础。本节围绕 .script 文件的组织方式、主程序与子程序的关系、def/end 关键字的作用,以及程序从加载到结束的生命周期展开。
一、.script 文件的组织方式
UR 控制器中,一个可被加载执行的程序通常以 .script 为扩展名保存。它本质上是纯文本文件,内部由若干“定义块”组成。每个定义块以 def 开头、以 end 结尾,中间是该程序段的语句。一个 .script 文件可以只包含一个定义块,也可以包含多个定义块,其中第一个定义块通常作为入口程序,其余定义块作为可被调用的子程序。
从工程实践看,.script 文件常见的组织方式有两种:
- 单文件单程序:整个文件只有一个
def ... end,适合简单任务,例如只做一次抓取放置。 - 单文件多程序:文件内包含一个主程序和若干子程序,主程序负责流程调度,子程序负责具体动作,例如
pick()、place()、move_home()。
需要特别注意的是,UR 控制器在加载 .script 文件时,会解析其中的所有定义块,但只有被显式调用的程序才会真正执行。因此,文件内定义多个子程序不会自动运行,必须由主程序或其它程序通过名称调用。
二、主程序与子程序
主程序是程序的入口,通常命名为 main 或与任务同名的名称。它负责初始化、流程控制、调用子程序以及异常处理。子程序则是被主程序调用的独立定义块,用于封装重复动作或复杂逻辑。
主程序与子程序之间通过“调用”建立关系。调用时,控制器会暂停当前程序的执行,跳转到被调用程序的第一条语句,执行完毕后返回调用点继续执行。这种关系可以用下面的结构图表示:
图中可以看到,主程序按顺序调用三个子程序,每个子程序内部完成一组具体动作后返回。这种结构让主程序保持简洁,子程序各自独立,便于修改和复用。
三、def/end 关键字
def 和 end 是 URScript 中定义程序块的一对关键字。def 后面跟程序名和参数列表,end 标记该程序块的结束。语法形式如下:
def 程序名(参数1, 参数2, ...):
语句1
语句2
...
end
程序名必须符合标识符规则:以字母或下划线开头,由字母、数字、下划线组成,不能与 URScript 内置函数重名。参数列表可以为空,也可以包含多个参数,参数之间用逗号分隔。参数在程序内部作为局部变量使用,调用时传入实际值。
一个常见的误区是认为 def 只是“声明”,实际上它同时完成了定义和可调用注册。只要文件被加载,所有 def 块都会被解析并注册为可调用程序。因此,子程序可以定义在主程序之前或之后,调用顺序不受定义位置影响。
下面是一个带参数的子程序示例:
def move_to(x, y, z, speed):
movel(p[x, y, z, 0, 0, 0], a=1.2, v=speed)
end
调用时传入具体数值,例如 move_to(0.3, 0.1, 0.2, 0.25),程序内部使用这些值完成直线运动。参数化让子程序具备通用性,避免为每个位置单独写一个程序。
四、程序生命周期
URScript 程序从加载到结束,经历若干阶段。理解这些阶段有助于判断程序在何时被解析、何时被调用、何时释放资源。
| 阶段 | 发生位置 | 关键行为 |
|---|---|---|
| 加载 | 控制器文件系统 | 读取 .script 文件,解析所有 def/end 块,注册程序名 |
| 启动 | 主程序入口 | 从第一个 def 块开始执行,初始化变量和运动参数 |
| 调用 | 主程序内部 | 遇到子程序名时跳转执行,执行完返回调用点 |
| 运行 | 控制器实时层 | 按语句顺序执行运动、IO、逻辑判断等指令 |
| 结束 | 主程序 end | 释放局部变量,程序停止,等待下一次启动 |
需要强调的是,程序“结束”并不等于控制器断电或文件被删除。程序结束后,定义块仍然保留在控制器中,可以再次启动。只有重新加载文件或删除文件,才会改变已注册的程序集合。
pick_part()、open_gripper(),避免使用 p1、test 这类含义模糊的名称。
五、一个完整的结构示例
下面给出一个包含主程序和两个子程序的完整 .script 文件示例,用于演示本节所述结构:
def main():
set_tcp(p[0, 0, 0.15, 0, 0, 0])
set_speed(0.3)
pick()
place()
end
def pick():
movel(p[0.3, 0.1, 0.2, 0, 0, 0], a=1.2, v=0.25)
set_digital_out(0, True)
sleep(0.3)
end
def place():
movel(p[0.1, 0.3, 0.2, 0, 0, 0], a=1.2, v=0.25)
set_digital_out(0, False)
sleep(0.3)
end
该文件加载后,控制器注册 main、pick、place 三个程序。启动 main 后,先设置工具中心和速度,然后依次调用 pick 和 place。每个子程序内部完成运动与 IO 操作,执行完毕后返回主程序,最终到达 main 的 end,程序停止。
从工程角度看,这种“主程序调度 + 子程序执行”的结构,是 URScript 程序组织的基本范式。它让程序逻辑分层清晰,便于调试、复用和后期维护。掌握 .script 文件组织、主程序与子程序关系、def/end 语法以及程序生命周期,是进一步学习 URScript 运动控制、IO 操作和异常处理的前提。