尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

发那科机器人二次开发:C#上位机通过KAREL TCP实现点位读写

发那科机器人二次开发:C#上位机通过KAREL TCP实现点位读写 简介工业机器人与上位机之间的数据交互是产线信息化与智能化的基础而发那科机器人作为市场常见品牌其二次开发常涉及KAREL语言和自定义通讯协议。本文从工业通讯的基本概念出发讲解如何利用KAREL在机器人控制器端搭建TCP服务程序使C#上位机能够通过Socket读取和写入位置寄存器、数字寄存器及IO信号从而支持MES系统对接、点位批量导入导出和实时状态监控。文章覆盖方案选型、核心代码实现、现场调试要点及常见故障排查帮助工程师理解数据采集与设备联动的完整链路。 发那科机器人的二次开发绕不开一个现实问题机器人自己的示教器和TP程序已经能干活了但一牵扯到数据采集、MES对接、点位批量导入导出就没那么灵光了。这个项目的起因很简单产线上一条发那科机器人工作站客户要求上位机一键切换产品型号点位参数全部从MES系统下发同时还要把机器人当前的坐标、寄存器数据实时读回来显示。说白了就是要用C#写一个上位机程序和发那科控制柜打通数据通道重点是能读写点位信息。我最后采用的方案是机器人端跑一个KAREL语言写的TCP服务程序C#上位机作为TCP客户端通过自定义文本协议和机器人通讯。这篇文章就把整个过程拆开讲清楚包括方案选型、KAREL端实现、C#端实现、以及现场调试时踩过的坑。适合正在做发那科机器人上位机集成、需要远程读写机器人数据的工程师也适合想了解工业机器人和PC之间怎么通讯的新手。1. 项目整体思路为什么选C#为什么用TCP Socket1.1 发那科机器人二次开发的几条技术路径发那科机器人不像PLC那样有统一的通讯接口它给了几条不同的二次开发路径我先把主流方案梳理一下方案原理适用场景开发难度KAREL自定义程序在控制器上运行类Pascal语言程序可访问寄存器、位置寄存器、IO信号自定义通讯、数据采集、复杂逻辑中TP程序示教器用示教器编写机器人程序通过IO和寄存器与外部交互简单信号交互、自动运行逻辑低Focas Library发那科官方API库主要用于CNC数控系统机器人支持相对有限CNC数据采集为主中EtherNet/IP现场总线协议机器人作为从站和PLC通讯PLC联锁控制、信号交互中Profinet西门子生态的工业以太网协议机器人作为从站西门子PLC场景中自定义TCP Socket通过KAREL程序开启TCP服务PC端自由定义协议PC上位机、MES对接中我最终选了KAREL加TCP Socket这条路。原因很直接Focas库对机器人的支持不如对CNC那么完整文档也少上手成本高Profinet和EtherNet/IP需要额外硬件选项和配置而且数据内容是固定映射的IO区没办法方便地读位置寄存器和数字寄存器KAREL写的TCP服务则完全自由想读什么写什么协议自己定一台带以太网口的控制柜就能跑起来。1.2 C#做上位机的几个实际优势选择C#做主语言不是因为什么语言信仰纯粹是它在工业上位机场景里确实顺手。第一WinForm和WPF做监控界面、数据表格、趋势曲线都快开发速度比MFC快一个量级。第二C#连接数据库非常方便点位数据可以直接存到SQLite或者SQL Server批量导入导出Excel也简单。第三TCP通讯、多线程、串口这些基础库都很成熟第三方NuGet包也丰富做工业通讯不用从零造轮子。你可能会问Python行不行当然可以现场用Python做原型验证也很快。但客户通常要的是长期运行的Windows上位机程序要和产线MES做接口还要有登录权限、日志审计这些功能C#在这种场景下更合适部署也方便一台工控机装个.NET运行时就行。1.3 自定义文本协议比想象中靠谱有人可能觉得既然是设备通讯是不是应该用某种标准的二进制协议更规范我建议在这个场景下不要纠结。我用的是一条非常简单直接的文本协议比如C#发GET_POS,1机器人就返回OK,GET_POS,1,X100.5,Y200.3,...。用逗号做分隔符以回车换行结尾。好处是显而易见的调试的时候用TCP调试助手直接手工发指令就能验证机器人端逻辑出了问题一眼就能看出是C#发的指令格式不对还是KAREL解析错了。对团队成员交接也友好不用对着二进制文档一个个数偏移量。缺点就是数据量略大、解析速度稍慢但读点位、写寄存器这种操作频率根本到不了性能瓶颈所以完全不用纠结。2. 整体方案设计机器人端KAREL服务加C#客户端2.1 系统架构和数据流向整个系统分两层机器人控制柜一侧运行KAREL服务程序它创建一个TCP Socket并监听固定端口我用的是9000端口C#上位机作为客户端通过网络连接控制柜的IP地址。C#发送请求指令KAREL程序解析指令访问机器人控制器内部的寄存器、位置寄存器或者IO信号然后构造响应文本返回给C#。这套架构不需要额外硬件控制柜自带的以太网口就够了。需要注意的是机器人控制柜的IP地址、子网掩码需要在示教器的网络设置页面里配置好PC和机器人要处于同一个局域网段这个我在现场可没少吃亏。2.2 数据模型机器人端能读写的对象在发那科机器人控制器里常见的可读写数据大概是这样的数据类型表示方式典型用途C#侧映射数字寄存器R[1] ~ R[200]计数、测量值、配方参数double位置寄存器PR[1] ~ PR[100]目标坐标点位Pose类X,Y,Z,W,P,R离散输入DI[1] ~ DI[80]传感器信号、干涉区信号bool离散输出DO[1] ~ DO[80]控制抓手、指示灯bool组输入GI[1] ~ GI[10]模拟量、编码值int这里面最核心的就是位置寄存器PR。发那科的PR点位信息有两种存储形式一种是关节坐标J1到J6另一种是直角坐标X、Y、Z、W、P、R也就是位置加欧拉角姿态。在KAREL程序里读取PR的时候返回的数据类型可以根据需要转换这块是后面代码实现的重点。2.3 通讯协议的具体定义协议是我自己定义的格式很简单每条指令以回车换行结尾字段用逗号分隔。请求侧支持的指令有GET_REG,1读取数字寄存器R[1]SET_REG,1,123.45把数字寄存器R[1]写入123.45GET_POS,3读取位置寄存器PR[3]SET_POS,3,X,Y,Z,W,P,R写入位置寄存器PR[3]的六个分量GET_DI,5读取离散输入DI[5]SET_DO,3,ON写离散输出DO[3]为ONPING测试连接是否正常响应侧有两种成功格式OK,指令原文,附加数据失败格式ERR,错误码例如读取PR[1]成功后返回OK,GET_POS,1,X10.5,Y20.5,Z30.5,W0.0,P0.0,R0.0定义这个协议的时候我特意把指令原文放在响应里回传这样C#侧做异步请求匹配的时候非常方便多线程同时发指令也不容易搞混。3. 实操核心机器人端KAREL程序实现3.1 KAREL开发环境和准备工作KAREL是发那科机器人的一种编程语言语法类似Pascal需要在机器人控制器上编译运行。开发流程一般是在电脑上装ROBOGUIDE发那科的机器人仿真软件在里面创建一个虚拟控制器版本要和现场控制柜保持一致比如V9.1然后编写KAREL源文件扩展名通常是.kl编译生成.pc文件再通过FTP或者U盘传到控制柜上运行。这里一个重要前提控制柜必须启用KAREL选项如果没有这个选项KAREL程序无法运行。怎么确认可以在示教器上查看系统信息页面看软件选项列表里有没有KAREL。正规采购的发那科机器人一般都有但山寨版或者二手机器人我见过没有的这个要提前确认清楚。3.2 KAREL TCP服务端主框架KAREL里创建TCP Socket的操作和C#的TcpListener很类似。我写了一个简化版的服务主框架PROGRAM TCP_SERVER VAR server_sock : SOCKET client_sock : SOCKET ip_addr : STRING[16] port : INTEGER status : INTEGER recv_buf : STRING[512] send_buf : STRING[512] BEGIN -- 初始化 ip_addr 0.0.0.0 port 9000 SOCKET_CREATE(server_sock, TCP, status) IF status 0 THEN WRITE(CREATE FAIL, status) RETURN ENDIF SOCKET_BIND(server_sock, ip_addr, port, status) SOCKET_LISTEN(server_sock, 5, status) -- 主循环 WHILE TRUE DO SOCKET_ACCEPT(server_sock, client_sock, status) SOCKET_READ(client_sock, recv_buf, 512, status) -- 解析recv_buf执行相应操作 -- 构造send_buf SOCKET_WRITE(client_sock, send_buf, 512, status) END_WHILE END TCP_SERVER这段代码在真实项目里不能直接照搬因为接收缓冲区的处理要考虑粘包和半包问题。但作为框架已经足够了。实际KAREL里SOCKET相关函数的使用方式和参数个数不同控制柜版本会有差异我建议先翻一下你手上的KAREL参考手册对照Version信息来写。3.3 点位和寄存器读写核心代码在KAREL里读数字寄存器用GET_REG写用SET_REG。读位置寄存器用GET_POS_REG写用SET_POS_REG。下面是一段处理GET_POS指令的示例-- 假设recv_buf中的内容是GET_POS,1 str_index 9 -- 跳过GET_POS, pr_no STR_TO_INT(SUBSTR(recv_buf, str_index, 2)) GET_POS_REG(pr_no, pos_data, status) send_buf OK,GET_POS, pr_no ,X REAL_TO_STR(pos_data.x) ...这里有个容易踩的坑发那科的位置寄存器数据类型是XYZWPR结构体但其中W、P、R是欧拉角单位是度。在C#端转换坐标的时候要注意角度制还是弧度制的问题。我们做焊接工位的时候因为要和第三方视觉系统做手眼标定坐标单位不统一导致偏差了好几毫米后来统一成毫米和角度制才解决。3.4 编译、上传和后台运行KAREL源文件在ROBOGUIDE里编译生成.pc文件之后需要上传到控制柜的指定存储目录一般是通过FTP功能传到FRAMEWORK目录下。然后在示教器上创建一个TP程序用CALL指令调用这个KAREL程序CALL TCP_SERVER这样KAREL程序在TP程序被运行时才会启动。如果想开机自动运行可以配置成后台任务在控制器系统配置里添加一个后台程序把TCP_SERVER设进去这样它会在控制器启动后自动运行。注意千万不要在KAREL程序里写任何可能影响机器人安全运动的指令。Socket服务只做数据读写不做运动控制运动控制逻辑全部保留在TP程序里。这个原则一定要守住否则出安全事故就是大问题。3.5 KAREL版本兼容和调试经验我在R-30iB和R-30iC两种控制柜上都跑过这套代码发现SOCKET相关函数在R-30iC上可以正常编译但在老版本R-30iB上部分函数名有差异比如某些版本需要额外指定最大连接数量。遇到编译不过去的情况不要硬改先在ROBOGUIDE里对应版本仿真环境中测试确认函数签名正确再上控制柜。现场调试的时候我习惯先在PC上用一个TCP调试助手连接控制柜手工发送指令验证KAREL程序能正常返回。这步通过了再写C#端程序能省去很多不必要的排错时间。4. 实操核心C#上位机读写数据实现4.1 C#侧TCP客户端基础封装C#端的核心是一个TCP客户端类封装连接、指令收发、断线重连和日志功能。基础结构如下public class FanucRobotClient : IDisposable { private TcpClient _tcp; private NetworkStream _stream; private readonly object _sendLock new object(); private readonly byte[] _buffer new byte[8192]; public bool Connect(string ip, int port, int timeout 3000) { _tcp new TcpClient(); var asyncResult _tcp.BeginConnect(ip, port, null, null); if (!asyncResult.AsyncWaitHandle.WaitOne(timeout)) throw new TimeoutException(连接机器人超时); _tcp.EndConnect(asyncResult); _stream _tcp.GetStream(); _stream.ReadTimeout timeout; _stream.WriteTimeout timeout; return true; } public string SendCommand(string command) { lock (_sendLock) { byte[] data Encoding.ASCII.GetBytes(command \r\n); _stream.Write(data, 0, data.Length); // 读取响应按\r\n截断 string response ReadLine(); return response; } } private string ReadLine() { // 从流中逐字节读取直到遇到\r\n // 注意处理网络异常和超时 } public void Dispose() { _stream?.Close(); _tcp?.Close(); } }这个类的关键在于SendCommand和ReadLine的同步机制。因为现场轮询和数据写入可能来自不同的线程我用了一个lock对象串行化所有Socket操作避免多个线程同时写同一个NetworkStream导致数据交叉错乱。4.2 编码、超时和字节序的注意事项和发那科通讯的时候编码一定统一用ASCII。之前试过UTF-8发现KAREL端对中文字符或者扩展字符的处理不太靠谱传英文字母、数字和标点符号最稳。每条指令结尾要带上\r\nKAREL端的SOCKET_READ是按字符串读取的如果没有回车换行机器人端可能一直等不到一条完整指令。另外C#解析返回数据里的浮点数时一定要用CultureInfo.InvariantCulture。我们的电脑中文环境下double.Parse默认使用本地化设置如果字符串里正好是英文小数点或者反过来系统区域设置把小数分隔符改了解析就会出错。我遇到过一台工控机区域设置改了解析数值直接崩溃的情况排查了半天才找到原因。4.3 点位批量导入导出从数据库到机器人这个是整个项目里最实用的功能。我们的点表存在SQLite里有几十个产品的点位数据每个产品包含几十个PR点位。写一个批量下发方法public void BatchWritePositions(Dictionaryint, Pose positions, IProgressint progress, CancellationToken ct) { int total positions.Count; int index 0; foreach (var item in positions) { ct.ThrowIfCancellationRequested(); string cmd string.Format(CultureInfo.InvariantCulture, SET_POS,{0},{1},{2},{3},{4},{5},{6}, item.Key, item.Value.X, item.Value.Y, item.Value.Z, item.Value.W, item.Value.P, item.Value.R); string resp SendCommand(cmd); if (!resp.StartsWith(OK)) { throw new Exception($点位PR[{item.Key}]写入失败: {resp}); } index; progress?.Report(index); } }批量写入的时候我建议每批之间加个10毫秒到20毫秒的延迟不要一次性把几十条指令毫无间隙地发出去。机器人控制柜的Socket处理能力没有PC那么强同时涌进来的大数据量可能导致缓冲区溢出丢掉部分指令。实测下来每条指令间隔15毫秒左右最稳定总体耗时也不长。4.4 监控DI信号干涉区触发时的状态变化现场热词里有干涉区di信号触发时反应这正是上位机监控的一个重要场景。发那科机器人控制系统里干涉区检测信号一般通过DI点映射出来当机器人TCP进入干涉区域或者某个安全互锁条件触发的时候对应的DI信号会从OFF变ON。C#端需要做的是定时轮询这些DI点的状态一旦发现信号跳变立刻在UI上弹窗报警并记录日志。我用的轮询是Task加Thread.Sleep的方式private async Task PollDiStatusAsync(CancellationToken ct) { while (!ct.IsCancellationRequested) { try { string resp _client.SendCommand(GET_DI,101); bool current resp.Contains(ON); if (current ! _lastDiStatus) { _lastDiStatus current; OnDiStatusChanged(101, current); } } catch (Exception ex) { logger.Error(ex, 读取DI状态失败); } await Task.Delay(100, ct); } }这里一个很重要的经验干涉区DI信号触发意味着机器人可能已经进入减速或者停止状态上位机在这个状态下绝对不要发送SET_POS或者其他任何影响机器人运动数据的写指令。只能记录报警等现场确认处理完后DI信号复位了再恢复操作。4.5 多线程轮询与界面刷新C#上位机里WPF或者WinForm的UI线程不能直接在其他线程里更新控件。轮询线程读到的数据要显示在界面上需要用Dispatcher.InvokeWPF或者Control.InvokeWinForm同步到UI线程。不过高频率刷新会有性能问题我一般采用缓存加定时刷新的方式轮询线程把数据写入一个共享的ConcurrentDictionaryUI线程用定时器每500毫秒从字典里取一次数据刷新界面这样即使用户拖动窗口也不会卡。另外轮询频率不要盲目调高。发那科控制柜Socket服务是单线程处理的如果PC每50毫秒就发一条指令机器人端可能处理不过来进而导致轮询超时。我最终把普通寄存器轮询设在200毫秒DI状态轮询100毫秒点位坐标读取只在需要时手动触发这样现场运行很稳定。5. 现场常见问题与排查经验5.1 干涉区DI信号触发但上位机收不到变化现象是示教器上能看到DI状态已经变了但上位机界面没有反应。排查方向先确认C#轮询的DI号是否和示教器上看到的一致有时候客户整改IO接线后DI号变了程序里没同步改。再确认轮询异常有没有被记录下来Socket超时或者网络闪断都可能导致状态没更新。如果DI读取正常但机器人没停那就要去看机器人本身的干涉区配置比如干涉区检测是否启用、对应的信号映射是否正确。5.2 控制柜保险丝熔断后的排查步骤控制柜突然上电无反应或者某个轴报警有可能是控制柜保险丝烧了。发那科控制柜里的保险丝一般集中在电源模块附近打开控制柜门能看到。排查步骤断开控制柜总电源等放电完成再操作用万用表电阻档测保险丝两端确认是否导通如果熔断看保险丝规格一般是T型慢熔断保险丝尺寸和电流值要拍照记录换同规格保险丝不要为了省事换大电流的上电前先测一下输入侧有没有短路如果换上去再次熔断说明后面有短路点不要反复换要查负载侧这个过程中最容易犯的错是不断电就拆保险丝有触电风险一定要等控制柜完全断电再动手。5.3 控制柜换电池能不能断电很多做保养的人问过这个问题。发那科控制柜里的电池是用来保持SRAM数据的包括程序、点位、寄存器、原点数据都靠它维持。如果你把控制柜断电然后把电池拔了那数据十有八九会丢重新恢复原点是很麻烦的事。正确做法是不断电换电池。控制柜保持通电先做一次完整的程序备份到CF卡或者U盘然后断电更换电池不对——正确的顺序是如果不断电就不需要做备份如果控制柜已经关机了千万不能直接拔电池要先把控制柜重新上电备份完程序再在通电状态下更换电池。换电池要快几分钟内完成换完后检查一下系统日期时间有没有被重置。5.4 Socket通讯常见的网络问题连不上机器人IP先检查控制柜网络设置和PC网段是否一致最简单的办法是PC上ping一下机器人IP连上了但命令没响应确认KAREL程序是否被TP程序调用运行控制柜是否重启过导致后台任务没起来读取数据乱码编码没统一把C#端Encoding统一用ASCII偶发超时检查现场网线水晶头、交换机端口是否松动不要把机器人和视频监控等大流量设备混在同一个交换机对方端口被占用9000端口可能被其他程序占用换一个冷门端口比如189005.5 位置数据坐标格式换算问题发那科的PR点位可以在关节坐标和直角坐标之间切换显示但KAREL里读出来的内容和示教器上看到的内容不一定完全一致。实际项目中焊接工作站经常需要把机器人坐标和视觉系统坐标对齐这时候就要搞清楚工具坐标系和用户坐标系的值。我们有一次写入了视觉系统给的目标点但机器人到达位置偏了几厘米最后排查发现是视觉返回的是工件坐标系下的坐标而机器人PR里记录的是世界坐标系下的坐标需要加一个坐标变换矩阵。这个坑在点位信息读写时特别普遍建议在上位机设计阶段就把坐标系参数做成可配置的。6. 进阶扩展从Socket到Profinet、OPC UA6.1 加一个PLC怎么办Profinet配置思路如果现场有西门子PLC需要和发那科机器人联动比如PLC控制机器人启停、选择程序号那就需要配置Profinet。发那科机器人作为Profinet IO从站需要在控制柜里安装相应的硬件选项和软件配置然后在PLC组态软件里导入机器人对应的GSD文件分配设备名称和IP地址。Profinet和自定义TCP Socket的区别在于Profinet通信的数据内容是固定映射在机器人内部IO区的PLC直接读写这些IO区数据。点位信息这种高频、复杂的坐标数据不适合走ProfinetIO区更适合传启动、停止、程序号、报警ID这类简单信号。所以现场合理的方式是Profinet负责PLC和机器人的联锁信号自定义Socket负责上位机和机器人的点位数据交互两者各干各的互不干扰。6.2 企业级数据采集考虑OPC UA如果客户希望把数据接到MES、SCADA系统并且对数据安全性、历史存储、多客户端并发访问有要求那么可以在这套自定义Socket上面加一层OPC UA网关。把KAREL Socket读到的寄存器、点位信息通过OPC UA服务器暴露出去这样上位机和企业系统都能通过标准OPC UA客户端读取数据。6.3 横向扩展其他品牌机器人的思路做过发那科这套方案之后你会发现机器人通讯的底层逻辑其实是相通的。ABB有PC SDK和RAPID程序KUKA有KUKA.Variable和WorkVisual本质都是控制器侧跑一个服务程序开放数据接口PC侧写客户端去读写。如果后续项目有ABB或者KUKA的机器人思路完全可以复用只是协议细节和API名称不同而已。最后说一点个人体会。做机器人上位机开发最容易出问题的不是代码本身而是对现场环境的理解。我一开始在ROBOGUIDE里怎么都调不通Socket后来发现是虚拟控制器的网络配置不对到了现场又发现机器人和PC之间隔了车间交换机网络延迟偶尔会飙到几百毫秒轮询周期只能被迫拉长。这些经验在教程里是找不到的。所以如果你也准备做类似的二次开发建议先花半天时间把示教器上的IO画面、寄存器画面、网络设置页全部翻一遍再动手写代码真的会少走很多弯路。另外所有对机器人运行状态有影响的写操作都要加二次确认和权限控制。上位机写坏一个寄存器最多重新写回去写坏点位坐标导致机器人撞了工件那就不只是程序的问题了。本文还有配套的精品资源点击获取
返回列表