简介:面向FANUC数控系统二次开发人员,这份压缩包围绕FOCAS(FANUC Open CNC Access System)协议展开,解决上位机与发那科CNC设备通信难的问题,可应用于远程监控、数据采集、程序管理、参数设置和报警处理等场景。FOCAS基于HTTP与XML,支持TCP/IP网络通信,开发者可借助标准编程语言快速构建客户端,也适合先从文档了解协议原理再动手编码。包内共1627个文件,压缩后约6.22MB;其中705个xml和699个htm构成了协议文档与API说明的主体,覆盖函数定义、数据结构、调用流程和网络配置说明;169个gif图示直观展示交互过程;另有12个dll、11个h、10个bas、1个lib等动态库、头文件与VB示例模块,以及少量xsl/txt/css辅助文件,便于直接调用或对照学习。已有1598人学习下载。开发者可按文档步骤配置网络参数,参考基础示例实现连接、读写、报警处理等操作,再根据实际需求扩展代码,快速完成数控系统集成项目开发,提升产线自动化水平。
1. 从采集需求说起:FOCAS 协议为什么值得用
做产线设备联网时,最常碰到的需求就是把 FANUC 数控系统的实时数据拿上来:主轴转速、各轴坐标、倍率、报警号、PMC 信号。机床侧没有现成的 MQTT 或 OPC UA 服务,简单 TCP 抓包又抓不到内部变量,这时候“FANUC FOCAS 协议开发包”就是那条最直接的通道。发那科把这套接口封装成一组 C 函数库,通过以太网口或 HSSB 总线连接 CNC,函数命名一眼能看出用途,上手成本比想象中低。这个方案解决的是数据采集层从“无”到“有”的问题,适合做 MES 采集、设备状态监控、PMC 二次开发的工程师。后面的步骤多数照抄就能跑通,坑主要集中在选型、权限和调用时序上。
2. 先看懂 FOCAS 的通信结构和开发包:以太网口怎么连、库从哪来
2.1 FOCAS 是“函数库”不是“报文协议”:和裸 TCP、OPC UA 的本质区别
不少第一次接触 FOCAS 的人会先抓包,想从以太网报文里解析出数据格式,这是最常见的弯路。FOCAS 的全称是 FANUC Open CNC API Specifications,它本质上是一套由发那科提供的 C 语言函数库,通信层已经封装好了。你调cnc_rdspindle读主轴转速,库内部自己组帧、校验、应答,你拿到的只有结构体里的数值和返回值。把 FOCAS 当成“带文档的 TCP 服务”更合适,而不是“自己定制协议格式”。
和 OPC UA 相比,FOCAS 的定位不一样。OPC UA 解决的是多厂商设备统一建模的问题,服务器端和客户端都要理解信息模型;FOCAS 则直接暴露 CNC 内部地址和数据字典,读 PMC 的 G 地址、F 地址就像直接看梯形图里的信号点,几乎没有语义映射成本。代价是它只认 FANUC,适配面窄。同一条产线上如果你又遇到西门子、三菱,那就得再配别的采集通道,FOCAS 解决不了跨品牌的问题。
常见的开发包分两类:一类走以太网,对应fwlib32.dll那套库,适合绝大多数产线改造场景;另一类走 HSSB 高速串行总线,需要机床侧插专用板卡,适合老机型或对实时性要求极高的场合。选型上优先以太网,部署简单,不占机床额外 IO,而且 30i/31i/0i 系列基本都支持。拿到开发包后先别急着写代码,第一件事是确认机床侧参数 1410 号或者其他网络参数里有没有把以太网口分配给 FOCAS 使用,很多“连不上”就是这一步没做。
2.2 拿到开发包后先确认四样东西:库文件、头文件、说明书和选项功能
开发包下载下来是个压缩包,解压后内容各家渠道略有差异,但核心四样东西一般不会缺。第一是头文件,Windows 下最常见的是fwlib32.h,里面定义了所有函数原型、结构体、宏常量,写代码时几乎离不开它;第二是导入库和动态库,Windows 下对应fwlib32.lib和fwlib32.dll,Linux 下是对应的.so或静态库;第三是 FOCAS 说明书,通常是一份几百页的 PDF,里面每个函数有详细参数说明、返回值和错误码表;第四是示例代码,有些开发包自带简单的 C 例子,有些需要去发那科官网单独申请。
很多人在“选项功能”上栽跟头。FOCAS 库本身提供上百个函数,但某个函数能不能用,取决于 CNC 的系统版本和购买的功能选项。比如读 PMC 信号、写 PMC 信号、读刀具寿命数据,这些在部分 0i 系统上要么需要额外选项,要么被系统版本限制。处理办法很笨但很有效:先调cnc_getversion拿到系统软件版本,再对照说明书里的“功能与版本对应表”确认目标函数是否支持。
提示:开发包里的说明书错误码表一定要留着。FOCAS 返回值是负数,比如常见的“功能未提供”“连接拒绝”,不同数值对应不同原因,排查时第一条就是查错误码表。
2.3 连接与断开的固定节奏:cnc_allclibhndl / cnc_open / cnc_close
FOCAS 的连接流程是一套固定套路,和数据库连接有点像:先建立库句柄,再用句柄打开 TCP 连接,用完后断开并释放句柄。三个关键函数是cnc_allclibhndl、cnc_open和cnc_close。cnc_allclibhndl负责初始化并返回一个句柄,同时可以设置连接超时时间;cnc_open接受 IP 地址、端口和超时参数;cnc_close断开连接。
端口号默认是 8193,这是 FOCAS 以太网通信的固定端口,不需要猜测,也不要随意改。连接超时一般设 3 到 5 秒比较合适,太短在机床负载高时容易超时失败,太长会让上位机线程卡死。还有一点要注意:大部分 FANUC 系统同一时间只允许一个 FOCAS 客户端连接,如果机床上有其他软件已经占着连接,你的应用就会连不上。老工程师的一台笔记本同时开了两个采集程序互相抢连接,就是典型翻车现场。
#include "fwlib32.h" #include <stdio.h> int main(void) { unsigned short handle = 0; /* FOCAS 库句柄 */ short ret = 0; /* 返回值 */ char ip[] = "192.168.1.10"; /* CNC 以太网 IP */ /* 1. 初始化库句柄,3 秒连接超时 */ ret = cnc_allclibhndl(ip, 3, &handle); if (ret != 0) { printf("库初始化失败,错误码: %d\n", ret); return -1; } /* 2. 打开以太网连接,端口用默认 8193,超时 3 秒 */ ret = cnc_open(handle, ip, 8193, 3); if (ret != 0) { printf("连接失败,错误码: %d\n", ret); cnc_freehndl(handle); /* 失败也要释放句柄 */ return -1; } printf("连接成功\n"); /* 3. 断开连接并释放句柄,顺序不能反 */ cnc_close(handle); cnc_freehndl(handle); return 0; }这段代码里有两个细节容易忽略。第一是cnc_allclibhndl失败后不需要也不能再调用cnc_open,但句柄可能已经被分配,所以返回错误时直接结束即可;第二是cnc_close和cnc_freehndl必须都调用,一个负责断开 TCP,一个负责释放库资源,漏掉后者在长时间运行的采集程序里会积压句柄。超时参数的单位是秒,cnc_open的第三个参数是端口号,Windows 下的 socket 底层调用不同,但这些对我们透明,不用管。
3. 用 C 语言跑通最小采集:读主轴转速和绝对坐标
3.1 搭一个最小可编译工程:包含头文件、链接库
写 FOCAS 采集程序我习惯用 C 或 C++,C# 也能做但 P/Invoke 声明结构体麻烦,不如 C 直接。Visual Studio 里新建一个控制台应用,配置分三步:把fwlib32.h所在目录加进“附加包含目录”,把fwlib32.lib所在目录加进“附加库目录”,然后在“附加依赖项”里写入fwlib32.lib。如果用的是动态库,编译时只需要 lib,运行时保证 dll 和 exe 在同一个目录或系统 PATH 里。
如果是 Linux 上位机,常见做法是用 GCC 直接编译,链接时指定-lfwlib32,但前提是你从发那科拿到了对应平台的库。不同操作系统的库不通用,Windows 的 dll 拿到 Linux 上没用,这点不要踩坑。开发阶段不用急着连真机,先让工程编译通过,再逐步加调用。
# Linux 下编译 FOCAS 采集程序的常见写法 gcc -o focas_demo focas_demo.c -I./fwlib32/include -L./fwlib32/lib -lfwlib32 -lm这段命令的-I指定头文件路径,-L指定库文件路径,-lfwlib32链接 FOCAS 库。如果你的开发包里库名不是libfwlib32.so这种形式,先解压看实际文件名再改链接参数。我遇到过拿到的是老版本fwlib32.dll,在 Linux 上根本没法用,最后只能换 Windows 工控机,所以选平台前先确认库形态。
3.2 建立连接并做版本握手:为什么不能跳过 cnc_getversion
连接成功后先别急着读数据,调一次cnc_getversion做版本握手是值得养成的习惯。这个函数返回 CNC 的系统软件版本、系列信息,写入一个ODB_VER结构体。作用是双重的:一是确认通信确实建立,二是拿到版本后可以判断后续某些函数能否使用。不同系统版本的 FOCAS 支持度有差异,比如 0i-D 和 0i-F 对 PMC 读写的限制不一样,先看版本再选函数能省掉不少排查时间。
#include "fwlib32.h" #include <stdio.h> ODB_VER version_info; /* 版本信息结构体 */ short ret = cnc_getversion(handle, &version_info); if (ret == 0) { printf("系统版本: %d.%02d\n", version_info.dummy2[0], /* 主版本号所在位置 */ version_info.dummy2[1]); /* 次版本号所在位置 */ } else { printf("版本读取失败: %d\n", ret); }结构体ODB_VER的定义在fwlib32.h里是明确的,dummy2数组里存的就是版本号字节,不要自己想当然改偏移。说明书里还写了cnc_getversion不需要机床处于特定模式,手动模式也能调。这个函数也是后面排查“功能不支持”时的重要工具,先知道系统版本,再对照说明书的功能矩阵,比反复试错快得多。
3.3 读主轴转速 cnc_rdspindle:结构体里哪个字段才是实际转速
主轴转速是设备监控最常用的信号之一。FOCAS 提供cnc_rdspindle函数,一次调用能同时拿到主轴程序指令转速、实际转速、倍率、负载等数据,存放在SPINDLE_MSG结构体里。容易搞混的是“程序指令转速”和“实际转速”两个字段:程序里写 S1000,实际可能因为倍率开关打到 50% 而只有 500,采集设备状态时应读实际转速字段。
#include "fwlib32.h" #include <stdio.h> SPINDLE_MSG spindle; /* 主轴数据结构体 */ short ret = cnc_rdspindle(handle, &spindle); if (ret == 0) { /* S1_ACT 是主轴 1 的实际转速,单位是 min-1 */ printf("主轴实际转速: %d r/min\n", spindle.S1_ACT); /* S1_LOAD 是主轴负载百分比,做预测性维护时会用到 */ printf("主轴负载: %d%%\n", spindle.S1_LOAD); }SPINDLE_MSG里的关键字段包括S1_ACT(主轴 1 实际转速)、S1_PDIR(程序指令转速)、S1_LOAD(主轴负载)。如果你机床是双主轴,结构体里还有S2_开头的一组字段,读取逻辑完全一样。有一个常见翻车点:部分系统返回的转速单位是检测单位而不是转每分,说明书里专门有说明,需要根据机床参数 3716 号之类的检测单位设置换算。如果发现读出来的值比实际大了 10 倍或小 10 倍,先想到单位换算。
3.4 读绝对坐标 cnc_rdposition:判断该用哪一个位置类型
坐标读数比主轴转速略复杂,因为 FOCAS 不只给一种“位置”。cnc_rdposition通过第一个参数指定位置类型:相对坐标、绝对坐标、机械坐标、剩余移动量、伺服位置等。做设备状态监控通常读机械坐标,因为它是机床坐标系下不经工件坐标系偏移的原始值;做加工分析则可能要绝对坐标或剩余移动量。选错类型读出来的数跟机床画面显示对不上,会让人误以为采数程序有 bug。
#include "fwlib32.h" #include <stdio.h> ODB_POS position; /* 位置结构体 */ short ret = cnc_rdposition(handle, 1, &position); /* 1 表示绝对坐标 */ if (ret == 0) { /* position.data[i] 里存的是各轴坐标,具体轴号对应结构体中的索引 */ printf("X 轴绝对坐标: %d 检测单位\n", position.data[0]); printf("Y 轴绝对坐标: %d 检测单位\n", position.data[1]); }结构体ODB_POS的data数组按轴顺序存放坐标值,但单位是检测单位而不是毫米或英寸,需要换算。换算公式在说明书里写得很清楚:如果是公制机床,通常要乘上进给当量(常见是 0.001mm);如果机床开了分子分母驱动,这个换算系数就必须看参数。我的习惯是把换算逻辑单独封装成一个函数,后面换机床或者换轴配置只改系数,不碰采集主逻辑。
提示:写采集程序时顺便把
cnc_rdaxisdata也试一下。FOCAS 里读坐标有好几个函���,cnc_rdposition适合整组坐标,单独读某一轴的数据用cnc_rdaxisdata更轻量,二者返回值的单位逻辑不完全一样。
4. 从只读走向控制:PMC 信号读写与写回边界
4.1 PMC 地址的层级关系:X/Y/G/F 地址和梯形图的关系
FOCAS 采集做到后面,一定会碰到 PMC 信号读写。CNC 里梯形图程序操作的是 X(外部输入)、Y(外部输出)、G(从 PMC 送给 NC 的信号)、F(从 NC 送给 PMC 的信号)这些地址,而 FOCAS 提供了cnc_rdpmc和cnc_wrpmc两个函数访问它们。这里的关键是理解地址不是“内存地址”,而是梯形图里的软元件号。
在 PMC 程序里,G 地址通常是上位机或者 PMC 逻辑控制 NC 的通道,比如进给保持、程序暂停、倍率信号;F 地址是 NC 反馈给 PMC 的状态,比如运行中、报警中、到位信号。你在梯形图监控界面上看到 G8.0 这样的信号点,在 FOCAS 里调用cnc_rdpmc时同样指定地址类型和地址号就能读到。很多 MES 系统做“远程暂停”“远程启动”就是通过写 G 地址实现的,但写之前必须搞清楚这个点位在梯形图里有没有被别的逻辑驱动。
和 PMC 地址打交道前,最好先打开机床的 PMC 梯形图监控页,确认目标地址的注释和程序段。与其漫无目的地搜“fanuc 机器人指令大全 pdf”,不如直接看手上这台机床的 PMC 程序注释,信号名往往就在注释里。FOCAS 只是给你一扇读写窗口,信号本身的语义是机床厂在梯形图里定义好的。
4.2 cnc_rdpmc 和 cnc_wrpmc 的最小调用:地址类型、长度和格式
cnc_rdpmc的函数原型看起来略复杂,实际参数就是“地址类型、地址号、读取长度、数据缓冲区”。地址类型用常量区分,比如PMC_ADDR_TYPE_G、PMC_ADDR_TYPE_F、PMC_ADDR_TYPE_Y等。读取长度按字节算,不是按位算,读一个字节会把 8 个位一起读回来。最小调用示例:
#include "fwlib32.h" #include <stdio.h> short data[1024]; /* 数据缓冲区 */ short ret = cnc_rdpmc(handle, PMC_ADDR_TYPE_G, /* G 地址 */ 8, /* 从 G8 开始 */ 1, /* 读取 1 个字节 */ data); /* 输出数据 */ if (ret == 0) { /* data[0] 的低 8 位对应 G8.0 到 G8.7 */ printf("G8 字节值: 0x%02X\n", data[0] & 0xFF); }这里的data是按 short 数组接收的,但实际只用低 8 位,说明书里的例子也是这么写的。读 F、X、Y 地址的写法完全一样,只要换第一个常量。cnc_wrpmc的参数结构也一样,区别是data变成输入参数,把要写的值填进去。写单个位时最好先读后写,把原字节读回来,改其中一位再写回,不然容易把其他位覆盖掉。
PMC 信号读写最容易踩的坑在“读到的值和梯形图监控不一致”。原因通常是你用了错误的地址类型:G 地址和 F 地址在画面里都显示为 G/F 开头,但它们的 IO 映射完全不同,FOCAS 里的地址类型常量选错,读出来的数据自然不对。还有一点,PMC 信号是字节寻址的,不要试图跨字节连续读一大段,长数据分段读更稳。
4.3 写回时的三条边界:梯形图覆写、厂家宏、KAREL socket 的岔路
写 G 地址实现远程控制,听起来很诱人,但真正上线前要确认三件事。第一,梯形图程序本身会不会在每个扫描周期重新计算这个地址。如果梯形图里有线圈一直驱动同一个 G 信号,你通过 FOCAS 写进去的值会在下一个扫描周期被覆写,表现为“写了没反应”,这不是 FOCAS 的问题,而是控制逻辑冲突。
第二,发那科系统里有“厂家宏”和梯形图交互的机制,有些机床厂已经把远程启动、远程暂停做成了宏程序接口,你直接写 PMC 地址反而绕过了他们设置的保护逻辑。碰到这种情况,先看机床附带的技术资料里有没有宏程序调用说明,能走厂家预留接口就优先走接口。
第三,如果需求是让 NC 主动上报数据给上位机,而不是上位机轮询,那 FOCAS 只能算一半方案。PC 侧调用 FOCAS 永远是被动轮询模式,NC 侧主动发起 socket 通信是另一条技术路线,发那科系统上常见做法是写 KAREL 程序配合 socket 函数在 NC 内部建立客户端连接。FOCAS 负责密集采数,KAREL 负责事件触发上报,各管一段,比改 PMC 梯形图安全得多。
5. FOCAS 开发常见问题排查:连不上、读错值、程序卡死
5.1 连不上:能 ping 通但 cn c_open 超时
现象:PC 能 ping 通机床 IP,但cnc_open一直超时,返回值是超时类错误。原因有两类:一类是机床侧 FOCAS 以太网功能没启用或者端口被占用,另一类是连接已经被人占了。0i 系列机床的参数设定页里有专门的“以太网/FOCAS”设置项,需要把 FOCAS 和嵌入式以太网功能分配好,否则即使 ping 得通,TCP 8193 端口也没有服务在监听。
解决:先拔掉可能占用的连接(比如其他上位机软件),再在机床 MDI 上检查以太网设定页和 FOCAS 相关参数。如果机床侧一切正常,就抓包看 TCP 握手有没有完成,SYN 发出去有没有回包。很多情况下是现场网段有防火墙或交换机端口隔离,工控机到机床之间做了访问控制,ping 通 ICMP 不见得 TCP 就通。
5.2 读主轴转速一直是 0:倍率位置和单位换算双确认
现象:连接正常,cnc_rdspindle返回值是 0,但S1_ACT恒为 0,机床画面上明明有转速。原因通常是两个:第一,机床主轴倍率开关在 0% 位置,实际转速本来就是 0,这是数据对但业务判断错误;第二,读取的函数用错了,FOCAS 里主轴数据有几个函数,cnc_rdspindle读的是当前主轴状态,有的系统需要先确认主轴编号,如果主轴上电状态异常也会读到 0。
解决:先把倍率开关打到 100%,确认机械动作正常再判断是通信问题还是数据问题。再用机床诊断页面核对主轴诊断号的实际值,如果诊断号有值而 FOCAS 读出来是 0,就要检查检测单位换算和主轴号参数。我的排查习惯是先背书上的数据字典,再背程序的赋值语句,顺序反了容易白查。
5.3 读出来的坐标和画面差很多:检测单位、当量与坐标系类型
现象:坐标读数能变化,但值比机床画面大 1000 倍或者带乱七八糟的小数。原因基本锁定在检测单位换算:FOCAS 返回的是“检测单位”,不是显示单位。常见公制机床下 1 个检测单位等于 0.001mm,但遇到有分子分母驱动的轴,换算系数变成 0.001 乘以分子除以分母。坐标系类型选错也会造成偏差,绝对坐标、机械坐标、相对坐标读数各不相同,画面上显示的是“相对坐标”而你程序里读的是“机械坐标”,两者自然不一样。
解决:把cnc_rdposition的位置类型参数从 1 到 5 都试一遍,跟画面逐一对上。这个办法靠得住,因为位置类型枚举在不同版本里基本稳定。然后把换算系数写成一个配置项,别硬编码在代码里,换机床时只改配置不改程序。
5.4 程序跑久了卡死:没有正确设置超时和线程模型
现象:采集程序刚启动正常,跑几小时后界面卡死或者线程堆积。原因多数是 FOCAS 调用是阻塞式的,你把它放在了 UI 线程里,机床偶尔通信延迟几秒,界面就卡住了;或者循环里调用cnc_rdposition后没有检查返回值,连接已经断开了还继续读,库内部一直等超时。
解决:一是调用cnc_settimeout显式设置通信超时,建议单次读取超时不超过 3 秒;二是把所有 FOCAS 调用放到独立采集线程,UI 和采集之间用缓存队列解耦;三是循环里没读到的数据直接丢,不要阻塞重试,下个周期再读。FOCAS 的返回值是排查依据,每次调用后把ret打出来,卡死之前一定有先导现象。
5.5 写 PMC 信号无效:梯形图覆写和地址占用排查
现象:cnc_wrpmc返回 0,但写进去的信号马上变回去,或者机床完全没反应。原因优先级最高的是梯形图里该地址被线圈驱动,PMC 每个扫描周期都按程序逻辑重算,外部写入相当于“比赛跑步”永远跑不过扫描周期。其次该地址可能被系统设定为只读,或者被别的程序占用。
解决:先在 PMC 梯形图监控界面里看这个地址有没有线圈和触点引用,如果有,要么改梯形图程序,要么换一个没有驱动信号的备用地址。用诊断功能监控该地址一个扫描周期内的变化,确认是不是被覆写。这个排查过程需要梯形图编程软件支持,光靠 FOCAS 看不到梯形图内部逻辑,要请现场电气工程师协助。
| 症状 | 优先排查项 | 常见原因 |
|---|---|---|
| 连接超时 | 机床侧 FOCAS 设置、端口占用 | 功能未分配、连接被占 |
| 读数恒为 0 | 倍率位置、主轴状态 | 倍率为 0、函数选错 |
| 坐标偏差大 | 检测单位换算 | 当量系数、位置类型 |
| 程序卡死 | 超时设置、线程模型 | 阻塞调用、循环无超时 |
| 写信号无效 | 梯形图驱动、地址占用 | 线圈覆写、地址只读 |
6. 把 FOCAS 采集线程接进产线系统:缓存、超时与上线验证
到了这一步,基本功已经够了,真正决定这个方案能不能长期稳定跑的是线程模型和验证方式。我的习惯是一个 FOCAS 连接只属于一个采集线程,绝不在多个线程里共用同一个句柄,库内部没有为并发访问做完整支持。采集周期按设备类型区分,普通状态监控设 500ms,主轴负载、振动这类需要做趋势分析的设 100ms 以内,但不要低于 50ms,频繁轮询会加重 CNC 通信负载,反而影响机床执行。
线程之间用环形缓冲或消息队列传递数据,采集线程只负责把数据塞进队列,业务处理线程负责落库或转发。这样即使数据库偶发阻塞,采集线程也不会被拖死。超时设置上,cnc_settimeout我一般设 3 秒,读取函数单次超过 3 秒就放弃本轮,下一轮继续。上线前用 CNC 模拟器或直接在机床手动画面做三件事:先核对主轴转速在倍率 100%、50%、0% 时的数据,再核对零点附近各轴坐标与画面的误差,最后连续跑 24 小时看有没有句柄泄漏或偶发超时。
我在现场养成的习惯是每台机床写一个独立配置文件,IP、端口、检测单位系数、PMC 地址清单全放进去,绝不把参数写死在代码里。有一次换了一台 0i-F 机床,坐标当量系数不同,因为配置化做得好,只改了配置就上线。FOCAS 开发包这套方案,前期投入主要在权限确认和地址梳理上,一旦跑通,后续接 MES、做看板、上预测性维护都只是加函数的事。希望帮到你。
本文还有配套的精品资源,点击获取