1. KUKA语境下"原点"的三个含义,别一上来就写PTP HOME
我见过太多人接到的需求是"加个回原点程序",结果写出来的东西和现场想让机器人做的事完全对不上。第一次遇到这个需求,你最好先别打开示教器,先问清楚对方嘴里的"原点"到底指什么。在KUKA机器人的日常语境里,这个词至少对应三个完全不同的东西,混在一起讨论必然返工。
第一个含义是机械零点,也就是每根轴的绝对零位,由电机编码器和厂内标定决定,A1到A6每根轴都有一个独立的0度定义。这个东西正常情况下你不需要"回",断电重启后编码器数据靠电池保持,只要没拆电机、没换编码器、没触发过编码器校准流程,它就一直有效。真正会用到机械零点的场合是重新标定之后需要用EMD(电子校零规)做一次零点校准,或者同步外部轴。
第二个含义是程序HOME点,也就是控制系统里那个被写死的、由$H_POS保存的位置。你在示教器上用PTP HOME写的运动指令,最终就是把机器人带到这个位置。它不代表任何机械精度上的意义,纯粹是当年调试的人认为"这个姿态比较安全、比较靠边、不容易挡着工装"而示教下来的一个点。换一批人调试,这个点就可能完全不一样。
第三个含义是工件基准点,也就是有人会说的"回到工位原点""回到取件位"。这个位置和机器人本体没关系,和夹具、定位销、视觉标定的坐标系绑定,本质上是程序里的一个E6POS点,只不过被现场的人顺口叫成了原点。
1.1 需求含糊带来的典型返工
我给一个真实发生过的场景。产线停机以后要恢复生产,操作工要按一个按钮让机器人从任意姿态回到"待机位置",而"待机位置"在工艺员的脑子里是取件口上方50毫米的那个点,在调试员的程序里却写成了PTP HOME。程序一上线,机器人回到本体HOME点,离取件口有一米多的距离,操作工当场判定程序没问题但"机器人回错了地方",扯了两天。
判断标准很简单:如果对方说"回到原点"的时候手里拿着工艺卡或者节拍表,他说的基本是第三个含义;如果他说"安全位置、别挡着人走路",那是第二个;如果他说"轴角度要归到零、手轮上显示0度",那才是第一个。
1.2 三种原点的运动特征差异
明确之后,回原点的实现方式就分开了,区别非常明显:
| 原点类型 | 目标值确定方式 | 典型指令 | 是否受工具/基坐标影响 |
|---|---|---|---|
| 机械零点 | 编码器绝对零位 | 手动/轴坐标运动 | 否 |
| 程序HOME点 | $H_POS保存的笛卡尔位姿 | PTP HOME | 否,但受工具数据影响末端判断 |
| 工件基准点 | DAT文件中的E6POS点 | PTP XP_PICK | 是,切换$BASE会直接改变到达姿态 |
这张表值得贴在电柜门上。后面所有的防撞逻辑、轴序编排、速度设置,都要先落到这张表的某一列上,不然你根本不知道自己在优化什么。
1.3 我推荐的确认话术
实际沟通时我一般这么问:"你要的位置,是机器人自己的HOME点,还是工件上的某个点?"对方大概率会愣一下,然后你补充:"如果是工件上的点,麻烦告诉我夹具或者定位销的位置。"这两个问题基本能把需求锁死。至于机械零点,除非在做编码器标定,否则几乎不会出现在"自动化程序"的需求里,最多是要求回原点之后六根轴的读数在某个范围内,方便下次开机比对。
把这三个含义分清之后,你会发现真正需要写程序的是第二和第三种,第一种是底层状态,检查即可。而这两者的差别,也决定了程序是"轴坐标编排"还是"笛卡尔点运动",这是后面所有技术选择的起点。
2. 自动回原点程序的最小可跑骨架
需求确认完之后,先不要急着堆中断和异常处理,先搭一个能跑、能看、能验证的最小骨架。KUKA的程序天生分成两个文件:.src和.dat,很多人第一次接触会觉得莫名其妙,其实这是KRL语言的一个很务实的设计——运动逻辑和数据分开存放,逻辑改动频繁,数据在示教器上"示教"时会被覆盖,分开存能避免互相干扰。
2.1 SRC与DAT各自该放什么
.src文件里放的是可执行逻辑,也就是DEF ... END这一整块。.dat文件里放的是声明和常量,也就是DECL ...这些。一个典型的回原点程序长这样:
DEF HOME_RETURN( ) INI ; 这里是逻辑 ENDDEFDAT HOME_RETURN DECL E6POS XP_HOME DECL E6AXIS XA_HOME DECL REAL R_TOL ENDDAT如果在.src里写DECL E6POS XP_HOME,程序也能编译通过,但只要有人用示教器重新示教这个点,或者你做了"覆盖备份",声明和数据就容易错位。我的习惯是:所有会被示教覆盖的点,一律放DAT;所有只在本次执行内用到的临时变量,放SRC里。
2.2 INI不是可有可无的摆设
很多人把INI当成一个可有可无的占位符,直接删掉。这是第一个坑。INI这个折叠块背后是一条INITIALIZE子程序调用(在$config.dat里),它会把一大批系统变量拉回默认值:$ADVANCE设成3、$VEL和$ACC恢复默认、$TOOL和$BASE按当前激活号重新装载、$BWDSTART清零。这些默认值决定了你后续PTP用什么速度和加速度走。
如果你删掉INI,上一次程序运行遗留的$VEL.CP、$APO.CPTP、甚至$TOOL都可能被你继承下来,回原点时可能会出现"这次快、下次慢""这次到了、下次差20毫米"这种玄学现象。我处理过的一个案例,就是前后两个程序共用一个$TOOL,前一个程序把工具从TOOL[0]切到了TOOL[1],回原点程序没做INI,于是末端在错误的工具坐标系下运动,肉眼看到的就是"机器人姿态对了但多走了一段"。
提示:如果项目上确实有理由不调用
INI(比如需要在回原点过程中保留上一个程序的$BASE),那就在程序开头显式地把$TOOL、$BASE、$VEL、$ACC全部赋值一遍。不写INI可以,但必须自己承担全部初始化责任。
2.3 一个"能用但很危险"的最小版本
最低限度的可用回原点程序,其实是两行:
DEF HOME_RETURN( ) INI PTP HOME Vel=30 % DEFAULT END这段代码在我手上跑过不下一百次,只要机器人在安全区、速度给得克制,它确实能把机器人带回HOME点。但它有三个致命前提:机器人在运动的整个路径上不会撞到任何东西;HOME点本身示教正确;上一次程序的姿态不会导致轴序干涉。三个前提任何一个不成立,轻则报K1数值错误,重则撞工装。
我现在的习惯是,PTP HOME只作为最后一步,前面一定插两级轴坐标的"预归位",先把危险姿态化解掉。这套思路就是下一节要讲的轴序编排,也是我认为整个回原点程序里唯一真正需要动脑子的部分。
3. 轴序编排才是防撞的核心:先动哪个轴
如果说回原点程序有"心法",那一定是轴序。笛卡尔点位运动看起来优雅,但它在机器人远离目标姿态时走得是一条不确定的路径,路径上的干涉你无法预先想象。而轴坐标编排的本质是——人为规定每一根轴的运动顺序和中间姿态,把一条不可控的曲线拆成几段可控的直线。
3.1 典型干涉场景和轴的先后关系
先说最常见的三种干涉。
第一种是腕部扫过工装。机器人停在取件位,末端贴着夹具,A5(腕部摆动轴)如果处于大角度,A1(回转轴)一转动,末端就会以法兰为圆心画一个很大的圆弧,直接扫掉旁边的定位气缸。解决办法是先把A5收到接近0度,让末端尽量靠近法兰轴线,再转A1。
第二种是A2/A3塌肩撞台面。有些程序结束后机器人是"趴"在台面上的姿态,A2和A3大角度展开。直接回HOME,如果目标HOME点是直立姿态,A2和A3需要大幅收拢,中间过程容易碰到工作台边缘。做法是先把A3往回收一段,再抬A2,最后再一起走到目标。
第三种是线缆和软管拉扯。这个最容易被忽略,A4、A6这两个腕部旋转轴如果长时间在同一方向拧着,线束会被拧紧。回原点时如果继续往同方向转,可能直接扯断气管。所以A4和A6的中间姿态最好结合线束方向判断,我的做法是先把A6归到接近0,再处理A4,最后A4/A6一起回零。
3.2 用$AXIS_ACT做"就近方向"判断
KUKA提供了一个很实用的系统变量$AXIS_ACT,它返回机器人全部六根轴(含外部轴)的当前实际角度值。有了它,你就能让程序自己决定"从哪边转过去更近、更安全"。
DEF HOME_RETURN( ) INI ; 第一步:腕部收拢,脱离工件区域 PTP {A5 0.0, A6 0.0} C_PTP ; 第二步:A1 就近旋转 IF $AXIS_ACT.A1 >= 0.0 THEN PTP {A1 90.0, A2 -90.0, A3 90.0, A4 0.0, A5 0.0, A6 0.0} C_PTP ELSE PTP {A1 -90.0, A2 -90.0, A3 90.0, A4 0.0, A5 0.0, A6 0.0} C_PTP ENDIF ; 第三步:回到真正的HOME点 PTP HOME Vel=30 % DEFAULT END这里有几个细节值得拆开讲。C_PTP表示这个点是逼近运动,也就是机器人走到这个点时不做停顿,直接连到下一个点,节拍能省下来半秒到一秒。对回原点这种"中间点无工艺意义"的场景很合适。
PTP {A1 90.0, ...}这种写法是直接给出轴坐标的目标值,语法上等价于先声明一个E6AXIS再引用,优点是直观、不用在DAT里堆一堆点。它和PTP XHOME的区别只在于数据存在哪儿,运动学上完全一样。
3.3 分级回原点:从快速版本到保守版本
在实际产线上,我一般会给回原点做三个等级,由上位机或按钮选择,日常用快版,异常恢复用慢版。
| 等级 | 前置条件 | 轴序 | 典型耗时 |
|---|---|---|---|
| L1 快速 | 机器人处于普通作业姿态,无异常 | 单条PTP HOME | 3~6秒 |
| L2 标准 | 末端靠近工装或姿态偏离较大 | A5/A6收拢 → A1就近 → HOME | 8~14秒 |
| L3 保守 | 曾发生碰撞、报警、线束疑似缠绕 | A6归零 → A4归零 → A3回收 → A2抬升 → A1回中 → HOME | 20~35秒 |
这套分级的依据不是"等级越高越安全",而是"信息越少越保守"。上位机知道机器人停在哪一工步,就能选等级;操作工不知道,就统一按L3走。这个逻辑我用了好几年,误操作率比"一律回HOME"低了非常多。
顺带说一个经验:L3里A3回收那一步,回收量不要照搬理论值。同一个程序在不同场地,A3需要回收多少度,取决于台面高度和工装尺寸,必须现场示教。我一般先给20度,然后在慢速下手动看着,一点点往上加,直到末端刚好离开台面边缘10毫米以上为止。
4. 让程序自己判断该用哪条路径
光有分级还不够,程序最好能自己看一眼现场情况,再做决策。这一步做扎实了,回原点程序就从"可执行脚本"变成了"带判断的保护逻辑"。
4.1 进程序之前先做前置条件检查
我会在运动之前插一段只读检查,不满足条件就直接返回错误码,让上位机弹提示,而不是硬着头皮往下走。
IF $OV_PRO < 20 THEN ; 手动倍率过低,回原点可能中途停住,直接退出 RETURN ENDIF$OV_PRO是程序倍率,现场操作工经常把它拧到10%甚至更低去做精细操作。如果回原点程序在低倍率下启动,机器人会以极慢速度爬行,上位机按标准节拍等不到"完成"信号,就会误判故障。所以低倍率直接不让他们启动,是一个很省事的策略。
类似的检查还包括:当前激活的工具号和基坐标号是否和回原点程序假设的一致;系统是否在自动模式($MODE_OP);安全门状态是否正常。这些检查每一项也就两三行,但能挡掉大批"程序跑完了但没动"的投诉。
4.2$POS_ACT适合做粗判,不适合做精判
$POS_ACT返回的是机器人当前末端位姿(相对于当前$BASE,在$TOOL下),拿来判断"机器人大致在工位的哪一侧"非常好用:
IF $POS_ACT.X > 800.0 THEN ; 在工位外侧,直接回HOME PTP HOME Vel=30 % DEFAULT ELSE ; 在工位内侧,走保守轴序 HOME_SAFE( ) ENDIF但要注意它有两个局限。第一,它受$TOOL和$BASE影响,如果上一步程序切换过坐标系,读出来的值含义就变了,必须和$BASE_NO、$TOOL_NO一起判断。第二,它反映的是末端法兰位姿,不是机器人本体所有部位的位置,末端在工位外侧不代表手肘一定安全。所以我的原则是:$POS_ACT用来做区域粗筛,$AXIS_ACT用来做轴级精判,两者配合使用。
4.3 奇异区附近一定要绕开笛卡尔运动
KUKA六轴机器人在A5接近0度的时候会进入腕部奇异区,此时用LIN或CIRC这类笛卡尔运动指令,会出现关节速度瞬间暴涨甚至报K1值。回原点过程中如果目标HOME点的A5就是0度,而你从A5接近0度的姿态用笛卡尔方式走过去,就很容易踩到这个坑。
我的处理方式是:所有回原点路径里的运动,一律用PTP,不用LIN。PTP是同步轴插补,不经过笛卡尔求逆,天然避开奇异问题。代价是路径不可控,所以才需要前面的轴序编排来弥补。二者是配套的,拆开任何一个都会出问题。
注意:如果工艺上确实需要回原点过程走直线(比如穿过一个窄通道),那必须把工具姿态预先摆好,让A5远离0度,再执行直线运动。这属于特殊场景,不要把它当成常规回原点方案。
5. 中断、BCO与急停复位后的现实情况
理论上完美的程序,在现场遇到的第一个问题往往是"为什么第一次启动这么慢"。这不是程序写错了,而是KUKA的BCO机制在起作用,理解它才能写出让操作工不抱怨的回原点程序。
5.1 首次启动的BCO运动为什么这么慢
KRL程序在启动后,第一次执行运动指令时,控制系统做的不是"直接运动到目标点",而是先做一次BCO(Block Change Over)运动:从当前实际位置沿上一次的轨迹逆向前进到程序轨迹的起点,然后才按程序往下跑。这段BCO运动的速度上限大约在250毫米/秒的量级,而且它是在你按下启动后的第一瞬间发生的。
更麻烦的是,如果机器人断电重启或者长时间处于"无轨迹"状态,BCO运动可能需要走很长一段距离,视觉上就是"启动以后机器人慢悠悠地挪了一大截才开始干正事"。很多操作工这时候会以为程序卡住了,反复点暂停和启动,反而触发BCO反复重走。
我一般的处理有两招。第一,在回原点程序的最前面加一句PTP $AXIS_ACT,让BCO尽快结束在当前位置,代价是精确度下降,但对于回原点这种非加工任务影响极小。第二,在程序里给上位机一个"正在初始化"的状态位,让它在BCO阶段不判定超时。第二招尤其重要,因为BCO的耗时和断电前的位置强相关,你可能根本估不准。
5.2 中断程序里为什么不能直接写PTP
回原点程序经常要挂在中断上,比如按急停或者安全门打开时触发。这时候有一个硬性限制:中断程序里不允许使用带轨迹规划的运动指令(PTP、LIN、CIRC都不行)。因为中断发生时主程序可能正处于一个运动的中间状态,控制系统无法保证新运动指令的轨迹能与原轨迹正确衔接。
如果中断里确实要做运动,只能用PTP_REL或LIN_REL,也就是相对运动,而且通常是小幅度的让位动作,比如退回10毫米。我见过有人在中断里写PTP HOME,示教器直接报语法错误。
正确做法是在中断里只做三件事:置一个标志位、让机器人BRAKE停住、把解除信号传给上位机。真正回原点的动作,等中断解除后由主程序按正常指令执行。
DEF INTERRUPT_HANDLE( ) ; 中断程序:只停不动的典型写法 BRAKE FLAG_HOME_TASK = TRUE END5.3 急停恢复之后到底该不该自动回原点
这个问题每次做方案都会被拿出来讨论。我的立场比较明确:自动回原点可以做,但必须带二次确认。原因是急停发生时,机器人可能停在任意姿态,包括末端插在工装里的姿态。此时直接自动回原点,就是把一个已知危险姿态变成一个未知运动过程。
我通常的做法是:急停恢复后,让机器人进入一个"等待复位姿态"的状态,在示教器上提示操作工确认是否解除干涉,人工确认之后才按L2或L3等级执行回原点。整个流程里,人能看见的只有中间那个确认步骤,但这一步骤挡掉了绝大多数二次事故。
提示:如果产线要求"无人化",确实不能有人确认,那就把回原点等级统一降到L3,并且把速度上限压到20%以下,同时在外围加装机械式的碰撞检测。速度换安全,这是没有任何技巧可以绕过的取舍。
6. 调试台上踩出来的坑
程序写得再整齐,第一次上机还是要面对一堆现场问题。下面这几个是我反复踩、也反复帮别人解决的,按"最容易发生"到"最隐蔽"排序。
6.1 HOME点差一度带来的连锁反应
$H_POS这个点是用示教方式记录下来的,而示教的精度取决于当时机器人的姿态和操作人的手感。差1度在肉眼上几乎看不出来,但后果可能很严重:如果HOME点附近有检测开关,1度的偏差可能导致末端法兰碰不到开关,机器人到了HOME点但开关没信号,上位机判定"回原点失败"。
避免这个问题的办法是:HOME点的位置不要贴着任何开关或挡块,留出至少3~5度的角度余量。如果必须贴,那就用另一个专用点位(比如DAT里单独示教的XP_STANDBY)来碰开关,HOME点只负责姿态。
另外我强烈建议在首次调试时把HOME点的六轴读数抄下来,存档在程序注释里:
; HOME 点实测轴角度(2024-06 首次标定) ; A1=0.32 A2=-89.85 A3=90.12 A4=0.08 A5=-0.21 A6=1.05这样半年后有人说"机器人回原点的姿态和以前不一样",你能马上比对出是不是标定被改过。
6.2 速度倍率和循环时间的博弈
回原点速度快一倍,循环时间可能省两秒,但干涉风险也翻倍。我的经验值是这样:L1快速版本用30%,L2标准版本用20%,L3保守版本用10%或者手动倍率。这里说的是Vel=参数,和$OV_PRO是两回事,两者是相乘关系。
有人会问,为什么不直接用默认速度100%。因为PTP运动在接近目标点时会有一个自动减速段,速度设得越高,减速段的行程越长,末端在减速过程中的实际姿态越难预测。30%这个值是我试过很多次之后比较平衡的点——节拍够用,姿态可控。
还有一点,$APO.CPTP这个逼近距离参数会影响运动的平滑度。默认值大约是50毫米量级,把它改大一点(比如150毫米)能让C_PTP的衔接更顺,但也会让中间点的实际位置偏差变大。回原点的中间点本来就是"路过点",所以我一般会调大到100~200毫米,节拍上能明显感觉到顺。但目标点附近的$APO不要动,否则定位精度会掉。
6.3 外部轴和工装联动时的顺序问题
只要机器人带了变位机或者行走轴,回原点的顺序就多了一层约束。原则是:先让外部轴回到安全位,再让机器人回HOME。反过来做,机器人先回了HOME,变位机再转,很可能让工件直接撞到已经归位的机器人。
如果外部轴也是通过$AXIS_ACT表示的,那判断逻辑可以和主六轴统一:
; 先让变位机回到0度附近 PTP {E1 0.0} C_PTP WAIT SEC 0.3 ; 再执行机器人本体的回原点 HOME_RETURN( )这里的WAIT SEC 0.3不是多余。外部轴的机械到位和信号到位之间经常有滞后,尤其是液压驱动的变位机。等这0.3秒,能避免机器人启动时变位机还在细微抖动而导致的相对位置偏差。
7. 从单机到产线的封装思路
单台机器人的回原点程序能跑了,接下来要面对的是多台设备、多条产线的复用问题。这一步做得好不好,直接决定你后面两年是在改代码还是在喝茶。
7.1 把回原点做成带参数的全局子程序
我一般会把回原点封装成一个全局子程序,放在$config.dat能访问到的位置(或者放到一个共享的SRC里),参数化关键变量:
| 参数 | 含义 | 建议取值 |
|---|---|---|
LVL | 回原点等级 1/2/3 | 默认2 |
VEL | 运动速度百分比 | 10~30 |
TOL_A1 | A1到位判定容差(度) | 0.5 |
TIMEOUT | 最长允许时间(秒) | 40 |
子程序内部负责全部轴序逻辑、检查逻辑和错误码返回,调用方只需要给一个等级。这样换产线时改动量极小,也方便把同一套逻辑复制到其他KUKA机型上。
7.2 状态回传与上位机对接
回原点程序一定要给上位机一个明确的完成信号,而且最好分成三种:开始、到位、失败。只给一个"完成"信号是最常见的偷懒做法,会导致上位机无法区分"机器人真的回到位了"和"程序因为异常直接退出了"。
失败的原因也可以细化,比如"倍率过低""超时""软限位触发",这些信息传到HMI上,操作工基本能自己判断要不要叫维修。我实际统计过,把这些原因区分开之后,维修呼叫量下降明显,因为大部分"故障"其实是倍率忘了拧回去。
7.3 版本管理和变更记录
回原点程序是典型"改一次忘一次"的重灾区。轴序里多插一个中间点,半年后没人记得为什么。我现在的做法是强制三件套:程序头部注释写清版本号和修改日期;关键中间点后面写一行注释说明它存在的理由;每次示教覆盖DAT之后,把新的轴读数补进注释。
; --- V1.3 2024-07-11 --- ; 在A1就近判断之后增加A3回收20度, ; 原因:新换的夹具比原夹具高80mm,直接转A1会扫到夹具上沿这几行注释在出问题时能救你一命。我处理过一次夜间停线,靠的就是半年前留下的这行注释,直接定位到是新换工装导致的干涉,不用再从头推一遍。
我个人在实际项目里的体会是,回原点程序的复杂度从来不在代码本身,而在于你有没有把"现场的人和设备"这个变量一起考虑进去。轴序、等级、超时、提示语,都是为了让一个不知道机器人内部在干什么的人,能安全地让设备回到起点。程序写得再漂亮,操作工看不懂提示语、没人告诉他为什么启动后慢吞吞地挪了一截,最终都会变成一次次的现场求助。所以我现在的习惯是,回原点程序交付时一定附一页A4说明:什么时候按哪个等级、看到哪个提示该怎么办、什么情况下必须叫人。程序之外的这一页纸,往往比代码本身更值钱。