
简介工业机器人的上位机开发中通信协议设计与数据交互是核心环节。通过以太网Socket技术上位机可直接与机器人控制器进行实时数据交换实现位置读取、寄存器写入和信号联动。C#作为工程领域广泛使用的语言配合KAREL服务端程序能够稳定实现点位信息的双向传输。理解TCP/IP通信原理、报文协议定义以及机器人坐标系用户坐标系/工具坐标系的应用是保障点位精度与产线安全的关键。本文以FANUC机器人为例分享基于Socket Messaging与KAREL的二次开发实战经验涵盖技术选型、代码实现和现场排障为需要远程下发点位、回读位置的项目提供参考。 做FANUC机器人上位机开发这段时间我踩了不少坑也积累了一些实打实的经验。今天不聊虚的直接分享一套我用C#对接发那科机器人、实现数据读取写入和点位信息获取的完整方案包括技术选型思路、通信协议设计、核心代码实现还有现场调试时最容易踩的坑和排查方法。如果你正打算给产线上的发那科机器人写上位机或者手头有一个需要远程下发点位、回读位置的项目这篇文章可以给你省下不少摸索的时间。1. 方案选型FANUC机器人二次开发的技术路线怎么选1.1 先看懂发那科给你开了哪些口子发那科机器人的控制柜从R-30iA到现在的R-30iB Plus虽然外观变化不算大但软件层面的开放性一直在增强。做二次开发我个人理解其实就是在机器人控制器这张“桌子”上找几个抽屉看你能抽开哪个、往里放什么。目前主流的开放途径大概有四条Socket Messaging套接字通信是最通用、最跨平台的一条路。FANUC在KAREL语言里内置了SOCKET_OPEN、SOCKET_READ、SOCKET_WRITE等指令你可以直接在机器人端写一个TCP服务端程序上位机通过以太网连上来做数据交换。这个方案不需要额外买硬件选项只要机器人开通了以太网端口几乎所有R-30iA及以后的控制器都支持。它的优点是灵活、可控、代码透明缺点是你得自己设计通信协议并且要花时间写KAREL程序。Snapshot快照内存共享是FANUC提供的另一套机制它在控制器里划分出一块共享内存区把机器人状态、位置数据、寄存器值、信号状态等镜像到这块内存中上位机通过以太网按固定格式读取。这种方式数据刷新率高适合需要高频采集中断级别的数据场景比如实时位置追踪。但配置过程相对繁琐需要在机器人端启用Snapshot功能并且需要理解FANUC内部的数据结构布局调试起来门槛高一些。OPC UA是近年来才在FANUC新控制器上普及的选项。机器人作为一个OPC UA Server把点位、信号、寄存器都建模成节点上位机用标准OPC UA客户端去读写。好处是标准化程度高配合现代上位机框架比如基于OPC UA的MES对接非常方便但前提是控制柜购买了OPC UA Server选项型号比较老或者没买选项的机器人就没法用。RIFRobot Interface Function是FANUC专门为外部设备联动开发的一套接口规范走以太网有一套固定的报文格式主要用在视觉系统、PLC联动这类场景。它更偏向于标准功能块式的交互可定制性比Socket Messaging差一些但胜在稳定、有官方文档支撑。1.2 为什么我最终选了Socket Messaging KAREL在对比完上面几条路线后我这个项目最终锁定了Socket Messaging方案原因很直接项目现场有三台不同年份的机器人两台R-30iB、一台R-30iA。如果走OPC UA老那台控制器不支持如果走Snapshot虽然也能统一处理但配置工作量很大而且出了问题不好排查——你很难在机器人示教器上一眼看出Snapshot内存里到底被写成了什么。而Socket Messaging方案本质就是“机器人端一个服务端程序 上位机一个客户端程序”数据格式完全自己定义调试时可以打印每一帧报文思路非常清晰。还有一点很关键Socket Messaging不依赖额外的软件授权。我在机器人上只需要写一个KAREL任务通过以太网端口监听就行。这对于很多预算有限、没法为每台机器人买额外软件选项的产线来说是性价比最高的路径。当然这不代表其他方案没价值。如果你的产线全是新款机器人、而且已经部署了OPC UA架构那直接用OPC UA更省事。如果你需要毫秒级的位置反馈Snapshot的实时性确实比Socket Messaging好。方案这种东西永远是为场景服务的没有绝对的最好只有适不适合。2. 通信链路搭建C#客户端与KAREL服务端的握手细节2.1 先设计好报文协议别急着写代码很多人一上来就写Socket代码结果连上了也不知道怎么对话。做Socket Messaging二次开发第一步应该是定协议。我项目里用的是JSON格式的报文结构很简单但足够完成点位读取、点位写入、寄存器读写、信号读写等操作。请求报文是一个包含指令类型和参数的JSON对象我定义成这样的结构{ cmd: READ_PR, pr_index: 1, req_id: 20240615001 }响应报文则是{ cmd: READ_PR, pr_index: 1, req_id: 20240615001, code: 0, message: OK, data: { x: 123.45, y: 234.56, z: 345.67, w: 0.0, p: 90.0, r: 0.0, uf: 0, ut: 0, config: N U T, 0, 0, 0 } }之所以要带req_id是因为同一时刻可能有多条指令在飞上位机收到响应时靠它来匹配是哪个请求的回复。这个在做异步通信时尤其重要别省。指令类型我设计了这么几个READ_CUR_POS读取机器人当前TCP位置READ_PR/WRITE_PR读取/写入位置寄存器READ_R/WRITE_R读取/写入数据寄存器READ_DO/WRITE_DO读取/写入数字输出信号READ_AI/READ_AO读取模拟量有些项目需要协议定好了后面的工作就是把这个协议在KAREL端和C#端各实现一遍。关键点在于“两边对字段的约定必须完全一致”包括字段名大小写、数值类型、坐标顺序、姿态角单位等。我在现场就遇到过因为KAREL端发的是角度值、C#端按弧度解析导致位置完全错乱的事故协议文档一定白纸黑字写清楚。2.2 KAREL服务端怎么实现一个可靠的TCP ServerFANUC机器人端的KAREL程序本质上是一个跑在机器人控制器上的后台任务它负责监听端口、接收请求、解析指令、执行读取写入操作、返回结果。它的代码结构并不复杂但有几个细节必须处理好。KAREL里SOCKET的打开方式取决于你是作为客户端还是服务端。这里我们需要它作为服务端代码大致是这样的PROGRAM TCP_SERVER VAR sock : INTEGER client_sock : INTEGER status : INTEGER data : STRING[2048] reply : STRING[2048] port : INTEGER run_flag : BOOLEAN BEGIN port 8090 run_flag TRUE -- 开启服务端监听 SOCKET_OPEN(sock, SERVER, port, status) IF status 0 THEN WRITE(SOCKET_OPEN failed, status, status) RETURN ENDIF WHILE run_flag DO -- 等待客户端连接 SOCKET_CONNECT(client_sock, sock, status) IF status 0 THEN -- 循环接收客户端请求 WHILE TRUE DO SOCKET_READ(client_sock, data, 2048, status) IF status 0 THEN EXIT ENDIF -- 解析 data执行操作生成 reply CALL PARSE_REQUEST(data, reply, status) SOCKET_WRITE(client_sock, reply, status) IF status 0 THEN EXIT ENDIF ENDWHILE SOCKET_CLOSE(client_sock, status) ENDIF ENDWHILE SOCKET_CLOSE(sock, status) END PROGRAM这段代码有几个容易踩坑的点KAREL的字符串有长度限制旧版本是256字节新版本支持更长。如果2048的长度编译不过可以在TCP_SERVER程序开头加编译指令$LENGTH 2048或者直接定义成更小的报文。我建议报文别搞得太臃肿点位信息和控制指令这种轻量级交互1024字节完全够用了。SOCKET_READ是阻塞读取它返回的status如果非零表示对方已断开或者发生错误这时候要退出内层循环关闭这个客户端socket然后回到SOCKET_CONNECT继续等待下一个连接。不加这个处理的话可能出现一个客户端断开后机器人端服务直接卡死退出而你还不知道发生了什么。KAREL里没有内置JSON解析库所以我用了一个比较朴素的办法按关键字查字段。比如拿到一段字符串后用STR_FIND去找pr_index这个键名然后从后面截取数字部分再通过STR_TO_INT转成整数。这种方式虽然简陋但足够稳定。如果请求里有字符串类型的数据比如点位名称就需要更小心的字符串分割处理。机器人在执行SOCKET_READ、SOCKET_WRITE时是运行在后台任务中的。如果机器人正处于运动状态后台任务不会被阻塞所以你可以一边跑程序一边读位置。但要注意KAREL程序的优先级和TP程序的执行优先级不同如果KAREL程序里做了重型数据处理比如遍历大量寄存器可能会导致机器人的实时性能受影响。我一般会把数据压缩控制在几毫秒内完成。2.3 C#客户端如何封装才不容易出问题C#端我比较推荐用TcpClient配合NetworkStream做同步通信对于点位读写这类低频、但必须保证可靠的场景同步模型比异步模型好调试得多。核心类大概长这样public class FanucRobotClient : IDisposable { private TcpClient _tcpClient; private NetworkStream _stream; private readonly object _lockObj new object(); private readonly int _timeout 3000; public bool Connect(string ip, int port) { _tcpClient new TcpClient(); IAsyncResult result _tcpClient.BeginConnect(ip, port, null, null); bool success result.AsyncWaitHandle.WaitOne(_timeout); if (success) { _tcpClient.EndConnect(result); _stream _tcpClient.GetStream(); _stream.ReadTimeout _timeout; _stream.WriteTimeout _timeout; return true; } return false; } public string SendCommand(string jsonRequest) { lock (_lockObj) { if (_tcpClient null || !_tcpClient.Connected) throw new InvalidOperationException(连接已断开); byte[] sendBuffer Encoding.UTF8.GetBytes(jsonRequest); _stream.Write(sendBuffer, 0, sendBuffer.Length); _stream.Flush(); byte[] recvBuffer new byte[2048]; int bytesRead _stream.Read(recvBuffer, 0, recvBuffer.Length); return Encoding.UTF8.GetString(recvBuffer, 0, bytesRead); } } public void Dispose() { _stream?.Close(); _tcpClient?.Close(); } }这个封装虽然简单但有几个地方我是特意加上的同步锁。SendCommand加了lock这么做是因为如果项目里有多个线程同时调用比如一个线程读位置刷新UI另一个线程写点位两个请求同时塞进同一个网络流响应就会互相错乱。串行化请求是Socket Messaging通信最简单也最可靠的并发控制方式。超时控制。KAREL端如果正在执行一个较重的命令比如写一批PR寄存器C#端设置的3秒超时有可能不够。我建议把超时时间做成可配置的跟具体指令绑定。读取当前位置这种指令很快1秒就够写一批数据或者执行某些内部逻辑可能需要5秒以上。超时设太短功能正常的指令也会报错。断线重连。机器人端如果重启程序或者断电socket连接就会断开。现场调试中机器人重启是常有的事所以C#端要有重连机制。我的做法是每次调用前检查Connected状态如果已断开则自动尝试重连。如果重连也失败就抛异常让上层逻辑处理。如果要进一步提升稳定性还可以在C#端做一个心跳线程每隔几秒发一个PING指令。这样一旦机器人端异常上位机立刻就能感知到而不是等到用户手动操作时才报错。这个在产线长期运行的项目里非常值得做。3. 点位信息读写核心代码与坐标变换3.1 读取机器人当前TCP位置点位数据是发那科机器人二次开发里最核心的数据类型之一。我最开始做的时候以为读当前位置就是简单获取X、Y、Z三个坐标值就够了实际上完全不是这么回事。FANUC机器人内部的位置数据除了笛卡尔坐标系下的X、Y、Z外还包含姿态角W、P、R分别对应绕Z、Y、X轴的旋转以及当前使用的用户坐标系UF、工具坐标系UT还有轴配置信息CONFIG。如果不把这些信息一起读回来你拿到一个位置数据也无法真正复现这个点。在KAREL端读取当前TCP位置通常用GET_POSITION指令PROCEDURE READ_CUR_POS(reply : STRING) VAR cur_pos : XYZZR_POS status : INTEGER buf : STRING[512] BEGIN GET_POSITION(cur_pos, status, $MACHINE) IF status 0 THEN reply {code:1001,message:GET_POSITION failed} RETURN ENDIF -- 将 cur_pos 转换为 JSON 格式的 reply ... END PROCEDURE这里有个重要的知识点GET_POSITION返回的坐标值是经过工具坐标系和用户坐标系补偿之后的结果也就是示教器上看到的那个“当前TCP位置”。它是位置数据里最有用的形式因为你在TP程序里写的LPOS、PR[i]数值和它是同一个体系。拿到这个位置后我通常会把UF和UT也一起返回。比如{ cmd: READ_CUR_POS, code: 0, data: { x: 123.45, y: 234.56, z: 345.67, w: 10.5, p: 20.3, r: 30.1, uf: 0, ut: 1, axis_pos: [30.0, 45.0, -60.0, 15.0, 20.0, 10.0] } }axis_pos是六个轴的关节角度有些场景下比笛卡尔坐标更实用。比如做奇异性检测、关节限位判断时直接用关节角度判断最准确。3.2 读写位置寄存器PR的完整实现位置寄存器PR是FANUC机器人编程里最常用的点位存储方式。TP程序里的MOVJ PR[1]、MOVL PR[2]就是靠它来执行动作的。上位机通过二次开发写入PR寄存器再触发TP程序执行对应运动这是当前产线上非常典型的交互模式。KAREL端读写PR寄存器可以用系统变量加GET_VAR、SET_VAR指令。位置寄存器的数据格式是一个POSITION类型里面包含坐标、姿态、配置和坐标系信息。读取PR寄存器的KAREL代码PROCEDURE READ_PR(pr_index : INTEGER; VAR reply : STRING) VAR pr_val : POSITION status : INTEGER BEGIN GET_VAR(pr_index, *SYSTEM*, $PR[ NUM_TO_STR(pr_index) ], pr_val, status) IF status 0 THEN reply {code:1002,message:READ_PR failed} RETURN ENDIF -- 将 pr_val 转换为 JSON 格式的 reply ... END PROCEDURE写入PR寄存器的代码PROCEDURE WRITE_PR(pr_index : INTEGER; x, y, z, w, p, r : REAL; uf, ut : INTEGER; VAR reply : STRING) VAR pr_val : POSITION status : INTEGER BEGIN pr_val {X : x, Y : y, Z : z, W : w, P : p, R : r, UF : uf, UT : ut} SET_VAR(pr_index, *SYSTEM*, $PR[ NUM_TO_STR(pr_index) ], pr_val, status) IF status 0 THEN reply {code:1003,message:WRITE_PR failed} RETURN ENDIF reply {code:0,message:OK} END PROCEDURE我强烈建议往PR里写入数值时把UF用户坐标系和UT(工具坐标系也一起写入。很多现场问题都是这么出来的上位机只往PR里写了X、Y、Z默认用的是UF[0]、UT[0]但机器人实际执行这个点位时用的是UF[3]、UT[4]一旦坐标系对不上机器人走出来的位置就完全不对。还有个容易被忽视的点位置寄存器的数据精度。PR在机器人内部存储时用的是毫米和角度如果你在C#端处理的数值带了很多小数位写入后系统会自动做截断。这种情况在精度要求高的加工场景里需要格外小心通常要确认现场使用的精度单位和机器人内部存储精度是一致的。3.3 工具坐标系和用户坐标系的处理要真正用好点位信息就必须搞懂工具坐标系和用户坐标系这两个概念。理解起来其实不难。用户坐标系User Frame就是定义一个“在哪里干活”的参考系相当于给机器人指定工作台的坐标原点、X轴方向和Y轴方向。发那科机器人允许定义多个用户坐标系默认的UF[0]通常是世界坐标系。不同工位可能会定义不同的用户坐标系这样编写程序时可以统一数值逻辑。工具坐标系Tool Frame定义的是“用什么工具干活”它的原点是TCPTool Center Point工具中心点也就是工具实际接触工件的那个点。不同的工具比如吸盘、焊枪、夹爪有不同的TCP切换工具时就要切换对应的UT。当你通过上位机下发一个点位时这个位置是相对于哪个用户坐标系的又是通过哪个工具坐标系来执行运动的这两个参数如果不对下发点位就完全没意义。所以我在协议里强制规定写PR时一定要带上UF和UT读PR时也一定要把UF和UT返回给上位机。还有一个小细节FANUC的位置数据里姿态角的定义方式。我的项目里用的是WPR即绕固定XYZ轴的旋转顺序但有些高级应用里也会用四元数表示姿态。如果上位机软件是自研的建议统一用WPR角调试直观、示教器上也容易核对。如果上位机是跟第三方视觉系统对接视觉系统返回的往往是四元数那么C#端就需要做一次四元数到WPR角的转换这个转换逻辑一定要提前设计好别等接到视觉数据了再临时改。4. 信号与寄存器联动从点位到产线逻辑4.1 DO/DI信号的读取和控制点位信息只是基础生产线上跑逻辑更绕不开信号交互。发那科机器人本身有丰富的I/O系统包括物理I/O、内部继电器、组I/OGroup I/O、PMC信号等。上位机如果能读写这些信号就可以实现很多自动化联动比如给机器人发送启动信号、接收机器人完成信号、读取报警状态等。KAREL端读写DO信号的代码PROCEDURE WRITE_DO(do_index : INTEGER; value : BOOLEAN; VAR reply : STRING) VAR status : INTEGER BEGIN SET_DO(do_index, value, status) IF status 0 THEN reply {code:1004,message:SET_DO failed} RETURN ENDIF reply {code:0,message:OK} END PROCEDURE PROCEDURE READ_DI(di_index : INTEGER; VAR reply : STRING) VAR value : BOOLEAN status : INTEGER BEGIN GET_DI(di_index, value, status) IF status 0 THEN reply {code:1005,message:GET_DI failed} RETURN ENDIF IF value THEN reply {code:0,data:1} ELSE reply {code:0,data:0} ENDIF END PROCEDURE这里有个非常重要且容易踩坑的地方TCP通信的延迟和I/O信号的时间敏感性。如果你通过上位机Socket通信去读取某个DI信号来做安全联锁那一定要搞清楚这个信号的响应时间是否满足安全要求。Socket通信的延迟通常是几十毫秒到几百毫秒不等远不能和安全继电器、硬接线的实时性相比。凡是涉及人身安全、设备安全的信号千万不能走上位机逻辑必须通过硬接线或安全PLC来处理上位机只做监控和记录。4.2 数据寄存器R的读写除了位置寄存器PR发那科机器人还有大量数据寄存器R用来存放整数、实数、字符串等数据。这些寄存器经常作为机器人程序和上位机之间的“传话板”比如上位机给R[10]写一个工单号机器人程序根据R[10]的值选择不同的加工参数。数据一般是数值型的KAREL端读写R寄存器的代码逻辑很简单PROCEDURE READ_R(r_index : INTEGER; VAR reply : STRING) VAR value : REAL status : INTEGER BEGIN GET_VAR(r_index, *SYSTEM*, $R[ NUM_TO_STR(r_index) ], value, status) IF status 0 THEN reply {code:1006,message:READ_R failed} RETURN ENDIF ... END PROCEDURE不过要注意R寄存器的编号范围在不同控制器版本上可能不一样老一点的控制器最大只到R[200]左右新款的可能到R[1000]以上。在程序里访问不存在的R寄存器会直接报错所以上位机写R寄存器前最好先确认一下当前控制器的设置。4.3 点位触发的节拍控制和信号联动在实际产线应用中最常见的一个交互模式是上位机下发点位到PR[1] → 写入DO信号通知机器人启动 → 机器人执行用户程序走到目标点 → 完成后输出一个DI信号给上位机 → 上位机收到信号后继续下发下一条指令。这个模式很常规但有几个细节处理不好就会出问题。时序协调。上位机写入PR[1]之后必须确保数据写完了再给启动信号。有些人写代码是“写了PR[1]紧接着就写DO[1]ON”看起来没问题但由于Socket通信是分成两条独立指令发的中间就有一定时间间隔。如果机器人这边收到启动信号时PR[1]的写入指令还在路上那机器人走到哪去一个旧点位就很难说。我的对策是在C#端做“串行确认”。每发一条指令必须等待机器人的确认响应后再发下一条。比如写PR[1]得到OK后再发写DO[1]的指令确保数据已经落地了再触发启动。虽然牺牲了一点速度但可靠性和可排查性都大大提升。响应超时与重试。机器人端在执行运动指令时可能无法立刻响应新的Socket请求。比如机器人正在走一条运动指令此时上位机来了一条写PR的请求KAREL后台任务仍然可以处理但如果请求本身涉及机器人运动状态查询就有可能出现CNV_ERR之类的错误。因此C#端要有超时重试机制但重试次数不宜过多一般连续重试2-3次还不行就直接报警提示人工介入而不是无限重试掩盖问题。机器人侧的双任务安全。机器人端的KAREL通信程序和用户TP程序并不是同一个任务。如果你的TPS程序正在执行MOTION运动指令此时KAREL后台任务写了一个新的PR值并不会打断当前运动。除非你的程序明确在等待某个信号或位置否则写入的PR值要等到下一次运动指令执行时才会生效。所以在上位机逻辑里千万不能用“写PR后立即认为机器人已经走到那个点”必须等待机器人反馈“到位”信号。5. 现场排障实录常见问题与解决5.1 连接类问题怎么快速定位连不上机器人IP。首先确认机器人控制柜的以太网端口是否启用了。FANUC机器人控制柜有两个网口是很常见的一个用于TP示教器通信一个用于外部通信。外部通信口需要对应的IP设置在示教器上进入“MENU → 系统 → 网络/主机通信”里查看。C#连接时要注意使用的是不是这个外部通信口的IP。另外机器人控制柜的开放式以太网通信选项Ethernet Port必须开通否则操作系统层面根本不会监听端口。能ping通但C#连接被拒。这种情况多半是机器人端KAREL通信程序没有启动或者启动了但崩溃退出了。可以到示教器的程序选择列表里查看KAREL任务是否在运行或者检查系统报警里有没有SOCKET相关错误。我遇到过一次是KAREL程序里SOCKET_OPEN时的端口被占用程序启动失败但屏幕上看不出明显报警排查了半天才反应过来。连接不稳定时断时续。先查网线、交换机工业现场的网络环境远比办公室复杂。我之前遇到过一次很奇怪的现象连接总是几分钟就断开但重新连接就恢复。后来发现是现场有一台变频器产生了强烈的电磁干扰导致双绞线中的传输错误率飙升socket连接被重置。解决办法是换成带屏蔽的工业网线重新走线远离动力电缆问题就没了。5.2 点位数据类问题读取的PR值全部为0。最常见的原因是PR里真的没有数据机器人出厂后PR[1]默认是0。但还有一种情况是访问的PR索引超出了机器人当前配置的PR数量。比如我只配置了20个PR你去读PR[50]KAREL端会报错或者返回0。所以上位机的PR索引范围最好做成跟现场机器人配置一致性校验。写入点位后机器人走的位置不对。这个坑我前面提到过大概率是UF、UT没写对或者默认值不对。还有一种可能是CONFIG配置位问题。FANUC的位置数据里有一组叫N U T, 0, 0, 0的配置值它表示机器人到达这个点位时手臂的形态比如手腕翻转方式。如果你只写坐标值不写CONFIG机器人执行时可能因为无法确定配置而报错或者走了“绕远路”的方式。处理办法是上位机在写入PR时如果需要精确控制的是未定义配置的静态点位最好把配置位保持与示教器上原有点位一致或者从当前机器人姿态里读取配置信息回填进去。读到的W、P、R角度不对。要确认姿态角的表示方式是否匹配。发那科示教器上显示的是度数C#端如果用弧度处理就会差出很离谱的数值。还有一个隐蔽的点同样的姿态用WPR角和四元数表示数值完全不一样如果你的上位机同时对接了视觉系统特别容易在这个地方出问题。5.3 稳定性与安全避坑清单KAREL程序里要做指令白名单校验。通讯端口暴露在局域网里如果不校验输入指令任何人往端口上发一条恶意报文都能让机器人执行奇怪的动作。我做的方案里KAREL端会校验cmd字段是否在允许列表内不在列表内直接拒绝。此外还可以在KAREL端做一个简单的访问密码校验比如报文里固定带一个token字段避免现场误操作。这个token在上位机端保存为配置文件安全性虽然不算高但足够挡住大部分误操作了。上位机写操作权限要分级。我一般会把读指令和写指令分开管理界面上设置不同的操作权限。普通操作员只能读位置、读信号工艺工程师或调试人员才能写PR、写DO。这样才能避免在生产时有人误触发了写操作导致机器人突然换了一个点位运动。通讯异常时要有安全兜底。如果上位机与机器人通信中断超过一定时间机器人端应该怎么做这个一定要和现场工艺人员提前确认好。有些场景要求机器人立即停止有些场景要求机器人完成当前动作后再等待有些场景要求机器人回到安全位。我的做法是在KAREL端加一个通讯超时监测如果超过N秒没收到上位机任何指令包括心跳就把一个专用DO信号置为报警状态由PLC或安全回路来决定后续动作。千万别把安全逻辑完全寄托在通信链路上防的就是通信本身挂了。日志记录一定要做全。现场问题最难复现的往往就是“刚才明明好着的突然就不行了”。如果上位机每一条指令、每一条响应、每一次超时重连都记录下来按时间戳归档遇到问题翻日志很快就能定位。我在日志里除了记录指令内容还会记录当前机器人的报警号这对事后排查非常有帮助。写到最后再多说一句FANUC机器人二次开发最难的部分往往不是写代码而是理解机器人现场的实际工况和操作习惯。方案做得再漂亮如果不符合产线节拍、不贴合操作工的使用习惯落地时一定会阻力重重。我做这个项目的过程中和现场工艺工程师反复对了不知道多少版协议才最终把点位下发、信号联动这些流程理顺。如果你也在做类似的对接建议先花两周时间去现场盯几天机器人的实际运行把交互时序彻底摸清再动手写代码。这样一次成型的概率会大很多。本文还有配套的精品资源点击获取