ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

C#上位机与KUKA机器人联动:EthernetKRL通讯实战

C#上位机与KUKA机器人联动:EthernetKRL通讯实战 简介面向需要实现工业机器人远程监控与控制的C#开发者和机器人集成工程师这套基于TCP通讯的库卡KUKA机器人上位机控制方案提供了一份可运行的完整工程。程序适配KUKA系统软件8.3版本PC端基于.NET Framework 4.0开发支持实时读取机器人各关节位置、导出CSV数据并可通过上位机下发指令完成单步运动和指定坐标点运动。资源共68个文件压缩包约36.47MB主要包含C#上位机源码、KUKA端程序文件src/sps/dat、XML参数配置以及KUKA官方Ethernet KRL中文文档和TCP通讯参数配置说明便于对照学习与二次开发。目前已有737人学习下载适合具备一定C#基础、正在调试库卡机器人以太网通讯的工程技术人员参考可有效缩短通讯联调周期。 前段时间刚在产线上做完一套C#上位机与库卡KUKA机器人联动的项目需求很典型操作员在触摸屏上实时看到机器人当前末端坐标输入目标点位后机器人自动走位。听起来就是一台TCP通讯的事但真正把位置刷起来、把运动指令安全可靠地发下去中间涉及KRL编程、EKI协议配置、C#端Socket处理和大量联调排错还是有不少设计取舍的。这篇文章就把能直接复用的方案完整梳理一遍从机器人端配置到上位机代码该给的代码给全该踩的坑也一并说清楚给正在做机器人上位机开发的朋友当个参考。1. 方案选型KUKA对外通讯方式为什么是EthernetKRL需求拆解下来其实只有两点一是上位机要周期性拿机器人的实时位置刷新率几十毫秒级别就够二是上位机能下发目标坐标并控制机器人运动。基于这两点KUKA对外通讯的常用路线基本就排除掉一大半了。先看最传统的数字量I/O。通过CC20.1等通讯板卡配置数字量输入输出确实能传输信号但一个点位只能表示一位要传X/Y/Z坐标就得按浮点数拆位去实现工程量大且效率低下适合做启停和到位信号这种简单场景不适合做连续坐标传输。再看总线方案比如Profinet或者EtherNet/IP。这种方案在工业现场很常见但配置过程比较重需要硬件支持、配置GSD组态文件还要在机器人控制器里做好地址映射。它更适合PLC作为主站去组态纯C#上位机去接Profinet的话要么引入额外的通讯库要么就得有总线主站硬件没必要。OPC UA是近年来流行的一种选择。KUKA KSS 8.5以上版本可以通过选项包支持OPC UA服务器上位机用现成的UA客户端库就能读写变量。它的优势在于信息模型标准化适合MES、SCADA这类需要集成大量数据点的场景。但在实时性上OPC UA的典型轮询周期在100ms级别而且对于高频的位置数据刷新来说协议开销偏大做实时位置显示和运动控制都有点使不上劲。最后落在两个方案上EthernetKRLEKI和RobotSensorInterfaceRSI。RSI支持毫秒级实时反馈官方文档推荐用于视觉伺服、力控这类需要闭环控制的场景但配置极其繁琐需要在WorkVisual里挂RSI对象写大量的XML配置文件开发周期长对普通坐标监控项目来说属于杀鸡用牛刀。EthernetKRL的定位恰好卡在中间。它是KUKA官方提供的基于TCP/IP的XML数据交换方案通过KRL程序里的EKI函数库读取和发送数据。配置简单开发效率高通讯周期可以做到10到50毫秒对HMI显示坐标和常规点位运动控制完全够用。下表把几种方案放在一起对比结论很直观通讯方案典型刷新率开发难度适合场景数字量I/O几十ms级PLC周期简单但传坐标很累启停、到位信号Profinet/总线1-10ms复杂需硬件组态PLC为主站的控制系统OPC UA100ms级中等MES/SCADA数据集成EthernetKRL10-50ms较低纯Socket上位机坐标监控与点位控制RSI1-12ms高需WorkVisual配置视觉伺服、力控闭环所以我的结论很明确没有特殊实时性要求的话C#上位机和KUKA机器人的TCP通讯直接选EthernetKRL就是成本最低、见效最快的路线。2. 机器人端部署EKI配置文件和KRL程序骨架EKI用起来像做菜先备料机器人端需要把两件事准备好一个是两个XML配置文件一个是KRL收发程序。2.1 两个配置文件分别管什么EKI的配置存放在KRC控制器的C:\KRC\ROBOTER\Config\User\Common\EthernetKRL\目录下KSS版本不同路径略有差异核心文件是EthernetKRLConfiguration.xml和EthernetKRLCell.xml。EthernetKRLConfiguration.xml定义通讯的基本属性我习惯把它理解成通讯开关?xml version1.0 encodingUTF-8? ETHERNETKRL CONFIGURATION EXTERNAL TYPEServer/TYPE IPADDRESS/IPADDRESS PORT54600/PORT /EXTERNAL /CONFIGURATION CELLFILEEthernetKRLCell.xml/CELLFILE /ETHERNETKRL这里TYPE填Server表示机器人作为TCP服务器端由上位机主动连接这是最容易理解的模式。PORT默认是54600没特殊需求不用改。IPADDRESS在Server模式下可以留空机器人打开4660端口监听上位机直接连机器人控制器的IP即可。EthernetKRLCell.xml才是真正定义实时位置返回和运动控制数据流的文件可以理解成数据字典?xml version1.0 encodingUTF-8? ETHERNETKRL SEND XML ELEMENT TAGKRC ELEMENT TAGPOS TYPEFRAME SETVARCUR_POS/ ELEMENT TAGRUN TYPEBOOL SETVARIS_RUNNING/ /ELEMENT /XML /SEND RECEIVE XML ELEMENT TAGHMI ELEMENT TAGCMD TYPEINT SETVARCMD/ ELEMENT TAGX TYPEREAL SETVARTAR_X/ ELEMENT TAGY TYPEREAL SETVARTAR_Y/ ELEMENT TAGZ TYPEREAL SETVARTAR_Z/ /ELEMENT /XML /RECEIVE /ETHERNETKRLSEND部分定义机器人往外发什么SETVAR指定了数据来源是KRL程序里的CUR_POS和IS_RUNNING这两个变量。RECEIVE部分定义机器人收什么上位机发过来的XML会被解析到TAR_X、TAR_Y、TAR_Z和CMD变量里。配置改完以后记得重启控制器或者重新激活EKI服务修改才能生效。这个坑我在项目里踩过第一次改完EthernetKRLCell.xml后没重启上位机连是能连上但收发的数据字段还是旧的折腾了半天才反应过来。2.2 KRL主程序接收指令、执行运动、回传位置机器人端的主逻辑我用了一个KRL后台循环程序大致逻辑是这样DEF EKI_LOOP() DECL EKI_STRUC EKI_SRV DECL FRAME CUR_POS DECL FRAME TAR_POS DECL REAL TAR_X, TAR_Y, TAR_Z DECL INT CMD TAR_X 0.0 TAR_Y 0.0 TAR_Z 0.0 CMD 0 ; 初始化并打开EKI服务参数“Server”对应配置文件中的连接名称 EKI_SRV EKI_Init(Server) IF EKI_SRV.OK THEN IF EKI_Open(EKI_SRV) THEN LOOP IF EKI_Check(EKI_SRV) THEN ; 读取上位机下发的运动指令 CMD EKI_GetInt(EKI_SRV, CMD) TAR_X EKI_GetReal(EKI_SRV, X) TAR_Y EKI_GetReal(EKI_SRV, Y) TAR_Z EKI_GetReal(EKI_SRV, Z) ; 上位机把CMD置1表示请求运动 IF CMD 1 THEN ; 基于当前实际位姿只改X/Y/Z坐标保持A/B/C姿态不变 TAR_POS $POS_ACT TAR_POS.X TAR_X TAR_POS.Y TAR_Y TAR_POS.Z TAR_Z PTP TAR_POS ; 运动完成后把CMD回置为0握手协议告知上位机 CMD 0 EKI_SetInt(EKI_SRV, CMD, CMD) ENDIF ; 实时读取当前位置并回传 CUR_POS $POS_ACT EKI_SetFrame(EKI_SRV, POS, CUR_POS) ENDIF WAIT SEC 0.02 ENDLOOP ENDIF ENDIF EKI_Close(EKI_SRV) END这个循环里的核心设计点是先读后写的流程每一轮先取出上位机发来的指令判断是否需要运动然后把当前实际位置回传。WAIT SEC 0.02把循环周期控制在20毫秒即50Hz的刷新率对于坐标监控和常规点位控制来说非常充裕。有一点必须提醒我这里的EKI程序放在机器人运行的主程序里。实际项目里更推荐把它放到SPS后台程序中因为SPS不占用机器人主程序的控制资源也不影响运动指令的执行。SPS是KUKA的后台循环程序适合做通讯和IO处理。另外EKI的FRAME类型数据在上位机收到的格式是XML属性不是子元素。比如EKI_SetFrame把CUR_POS发给上位机后报文是这样KRC POS X123.45 Y234.56 Z78.90 A10.5 B-3.2 C45.6/ RUNTRUE/RUN /KRCX、Y、Z、A、B、C是POS元素的属性对应的坐标值全在属性里。这个细节如果不注意写解析代码时容易一头雾水。3. C#上位机实现TCP连接、XML收发与数据解析机器人端准备好了C#这边的工作就清晰了。整个上位机核心模块可以拆成四块连接管理、指令发送、数据接收解析、UI刷新。3.1 TCP连接管理我封装了一个KukaEkiClient类用TcpClient实现基础通讯。有几个关键点要说一下public class KukaEkiClient : IDisposable { private TcpClient _tcp; private NetworkStream _stream; private readonly object _sendLock new object(); private CancellationTokenSource _cts; public event Actionstring OnXmlReceived; public event Action OnConnectionLost; public async Taskbool ConnectAsync(string ip, int port, int timeoutMs 3000) { _tcp new TcpClient(); _tcp.NoDelay true; // 禁用Nagle算法降低延迟 var connectTask _tcp.ConnectAsync(IPAddress.Parse(ip), port); var completed await Task.WhenAny(connectTask, Task.Delay(timeoutMs)); if (completed ! connectTask) throw new TimeoutException($连接超时: {ip}:{port}); await connectTask; _stream _tcp.GetStream(); _cts new CancellationTokenSource(); _ Task.Run(() ReceiveLoop(_cts.Token)); return true; } }第一是NoDelay true。TCP默认开启Nagle算法会把小雨滴攒成大包再发虽然提高了网络利用率但增加了延迟。我们和机器人通讯的数据本身就不大追求的是及时性必须关掉。第二是连接超时用Task.WhenAny配合Task.Delay实现避免机器人没开机时上位机界面卡死。第三是接收循环放到后台线程用CancellationToken来管理线程退出。3.2 粘包拆包处理这是TCP通讯里永远绕不开的话题。EKI发送数据是按报文发送的但TCP协议是流式传输数据到达对端时可能粘连、可能拆开。如果上位机简单粗暴地Read一次然后当完整XML解析大概率会遇到解析异常。我用了一个字符串缓存区每次有数据先追加到缓存然后尝试从缓存中提取完整报文private StringBuilder _receiveBuffer new StringBuilder(); private void ReceiveLoop(CancellationToken token) { try { byte[] buffer new byte[4096]; while (!token.IsCancellationRequested) { int bytesRead _stream.Read(buffer, 0, buffer.Length); if (bytesRead 0) { string data Encoding.UTF8.GetString(buffer, 0, bytesRead); _receiveBuffer.Append(data); TryParseCompleteMessages(); } else { break; } } } catch { OnConnectionLost?.Invoke(); } } private void TryParseCompleteMessages() { string content _receiveBuffer.ToString(); // 以KRC为根元素的报文为一条完整数据 while (true) { int start content.IndexOf(KRC); if (start 0) { _receiveBuffer.Clear(); return; } if (start 0) content content.Substring(start); int end content.IndexOf(/KRC); if (end 0) { // 数据不完整保留到下一轮 _receiveBuffer.Clear(); _receiveBuffer.Append(content); return; } string xml content.Substring(0, end /KRC.Length); content content.Substring(end /KRC.Length); OnXmlReceived?.Invoke(xml); } }这里明确以KRC到/KRC作为一条完整报文遇到不完整就留在缓存里等下一个TCP段。实际项目中这个逻辑覆盖率很高唯一的前提是和机器人端约定好了SEND报文的根元素。3.3 解析位置数据并更新界面当收到完整的XML报文后解析就顺理成章了private void OnXmlReceived(string xml) { XDocument doc XDocument.Parse(xml); XElement root doc.Root; XElement posElem root.Element(POS); double x (double)posElem.Attribute(X); double y (double)posElem.Attribute(Y); double z (double)posElem.Attribute(Z); double a (double)posElem.Attribute(A); double b (double)posElem.Attribute(B); double c (double)posElem.Attribute(C); bool isRunning (bool)root.Element(RUN); // 非UI线程需要封送 BeginInvoke(new Action(() { txtX.Text x.ToString(F2); txtY.Text y.ToString(F2); txtZ.Text z.ToString(F2); // ... })); }有一个容易忽略的坑XML属性值可能带科学计数法比如1.5E-05这种(double)转换能处理好。但如果机器人端坐标数值很大KRL的REAL精度是单精度浮点C#这边用double接收后本文还有配套的精品资源点击获取
返回列表