3. UR程序结构与节拍瓶颈识别
在UR机器人(以PolyScope 5.x、UR5e/UR10e为例)的节拍优化中,一个常见误区是只盯着运动指令的示教点速度,而忽略了程序结构本身对循环时间的放大效应。UR控制器采用单核实时调度,主程序、子程序、线程(Thread)和中断(Interrupt)共享同一个控制周期。理解它们如何被调度、如何阻塞、如何抢占,是定位节拍瓶颈的前提。
一、UR程序结构的执行模型
UR程序由主程序(Main Program)和若干子程序(Sub Program)组成。主程序自上而下顺序执行,遇到子程序调用时进入子程序体,执行完毕后返回调用点继续。子程序本身不产生并行,它只是把代码组织成可复用的块,调用开销极小(微秒级),因此子程序数量本身通常不是瓶颈,真正影响节拍的是子程序内部是否包含阻塞型指令。
线程是UR中实现并行的主要手段。通过 Thread 指令可以启动一个独立线程,线程与主程序并行运行,但共享同一个控制周期。线程适合处理与主运动无关的辅助动作,例如控制夹爪、点亮指示灯、发送IO信号。需要注意的是,线程中的运动指令(MoveJ/MoveL)会与主程序争夺运动资源,若两个线程同时下发运动指令,控制器会按优先级和到达顺序排队,可能导致主程序运动被延迟。
中断(Interrupt)用于响应外部事件,例如数字输入上升沿触发。中断处理程序(Interrupt Handler)具有最高优先级,一旦触发会立即抢占当前执行流。中断处理应尽量短小,只做标志位设置或简单IO操作,避免在中断中执行运动指令或等待指令,否则会显著拉长循环时间。
二、四类结构对循环时间的典型影响
主程序是节拍的主干。主程序中每一条运动指令的加速度、速度、混合半径(Blend)都会直接影响单次循环时间。若主程序在循环末尾包含大量非运动逻辑(如字符串拼接、复杂条件判断),这些逻辑虽然单次耗时短,但在高频循环中会累积成可观的固定开销。
子程序本身不增加并行开销,但子程序内部的阻塞指令是隐藏瓶颈。例如在子程序中执行 Wait DI=1 等待夹爪到位信号,若信号延迟200ms,则每次循环都会增加200ms。子程序调用层级过深时,示教器时间日志中会显示为嵌套条目,需要逐层展开才能定位到真正的耗时点。
线程的节拍影响具有隐蔽性。线程中若包含 Wait 或 Sync 指令,会与主程序产生同步等待。更常见的是线程中执行了运动指令,导致主程序运动被排队延迟。建议线程只处理IO和逻辑,不执行运动。
中断的影响取决于处理程序长度。中断处理程序若包含 Wait 或运动指令,会直接阻塞主程序。正确做法是在中断中只设置一个布尔标志,由主程序轮询该标志后执行具体动作。
三、用示教器时间日志定位耗时动作
PolyScope示教器提供了时间日志功能,路径为:运行程序 → 日志 → 时间日志。日志按程序结构树形展示,每一行显示指令名称、执行次数、总耗时和平均耗时。定位瓶颈时按以下顺序操作:
- 运行完整循环至少10次,确保日志统计稳定。
- 按“总耗时”降序排列,找到占比最高的条目。
- 展开子程序节点,查看内部哪条指令耗时最长。
- 对比“平均耗时”与理论运动时间,判断是否存在等待或阻塞。
- 检查线程和中断条目,确认是否有非预期抢占。
以下是一段示例时间日志片段(数据为教学假设,非实测):
程序结构 次数 总耗时(ms) 平均(ms)
Main 10 12500 1250
├─ MoveJ 接近点 10 3200 320
├─ Pick 子程序 10 6800 680
│ ├─ MoveL 下降 10 1800 180
│ ├─ Wait DI=1 10 3500 350 ← 瓶颈
│ ├─ Set DO 夹紧 10 200 20
│ └─ MoveL 上升 10 1300 130
├─ MoveL 放置 10 2100 210
└─ Thread 监控 10 400 40
从日志可见,Wait DI=1 平均耗时350ms,占子程序总时间的51%。这说明夹爪到位信号延迟是主要瓶颈。优化方向包括:调整夹爪气路响应速度、将等待改为条件轮询、或提前触发夹爪动作使其与运动重叠。
四、结构优化的判断依据
当时间日志显示某条 Wait 指令平均耗时超过50ms,或某线程条目总耗时占比超过10%,或中断条目频繁出现且单次超过20ms时,应优先重构程序结构。具体策略:将等待型指令改为非阻塞轮询;将线程中的运动指令移回主程序;将中断处理精简为标志位设置。每次修改后重新采集时间日志,对比循环总时间的变化,确认优化有效。