FANUC数控系统数据采集实战:FOCAS协议函数详解与开发指南
2026/9/7 3:49:46 网站建设 项目流程

简介:面向FANUC数控系统二次开发工程师,这份资源为FOCAS1/2 4.2版函数库的完整说明文档。该版本发布于2013年,支持Windows 32/64位及32位Linux系统,覆盖机床数据采集、刀具管理、报警监控等常用接口调用方法,是当前较为新颖的FOCAS1/2参考资料。压缩包共1657个文件,主要由741个xml与738个htm说明页组成,辅以173张gif示意图、xsl样式表及css样式表,用户可通过浏览器快速检索函数原型、参数定义与返回值,阅读体验接近在线帮助文档,整体仅2.69MB,便于携带。目前已有945人学习使用,值得参考。对于需要基于FANUC CNC进行智能产线集成、设备状态监控或OPC UA网关开发的工程师,可按模块查阅重点函数,也可对照htm与xml数据交叉定位细节,省去零散查找资料的麻烦,是一份轻量而实用的开发助手。 作为一个常年跟车间设备打交道的上位机工程师,我太清楚FANUC数控系统数据采集的痛点了:要么开着DNC软件人工看屏幕,要么就是靠操作工拿U盘导程序,等到MES要产量、要报警、要主轴负载的时候,才发现数据根本拿不出来。而FANUC官方提供的FOCAS1/2协议,就是专门解决这个问题的标准接口。这玩意儿说白了就是一套Windows或者Linux下的动态库,你通过TCP/IP就能把CNC内部的坐标、程序、报警、宏变量、刀具信息一股脑读出来,也能往里写宏变量、传程序。

这篇文章我结合FOCAS1/2 Version 4.2这个库版本,把常用的几十个函数按用途分类拆开讲,从环境准备、连接建立、数据读取到异常排查,全流程走一遍。适合正在做设备数据采集、MES对接、DNC远程传输、刀具寿命管理的工程师参考,也适合刚接手车间信息化项目、对FOCAS还一脸懵的新手快速入门。

1. FOCAS是个什么“黑盒”:先说清楚协议本身的逻辑

1.1 从命名看门道:FOCAS1和FOCAS2到底差在哪

FOCAS的全称是FANUC Open CNC API Specification,就是发那科开放CNC应用程序接口规范。名字里带“Open”,是因为发那科从FS16/18系列开始,不再把数控系统当成一个封闭的黑盒子,而是通过以太网口把系统内部的数据访问能力对外开放。你只要按规范调用库函数,就能用C/C++、C#、VB、LabVIEW这些语言和CNC通信。

先说容易被绕晕的FOCAS1和FOCAS2。FOCAS1是早期协议,面向FS6、FS11、FS15这些老型号,物理上走的是串口或者专用内存板,现在基本没有新项目用了。FOCAS2则面向FS16/18/21/30i/31i/32i这些主流系统,底层走以太网或者HSSB高速串行总线,我们平时做数据采集用的基本都是FOCAS2。标题里的“FOCAS1/2”是指这套API规范覆盖了两代协议,而4.2这个版本号对应的是官方提供的开发库版本,比如Fwlib32.dll的版本信息。

1.2 通信模型和端口:为什么连个CNC还要IP地址

FOCAS2的通信模型特别简单,就是一个标准的TCP/IP客户端-服务器架构。CNC端是服务器,开机后自动在8193端口监听(这个端口是FANUC固定使用的),上位机作为客户端主动发起连接。连接建立后,你调用的每个函数都对应一组请求-响应报文,底层库帮你封装好了,你不需要关心报文格式。

这里有个容易忽略的概念:FOCAS库处理的是一次“会话”。一个句柄(ODBHND类型)代表一条与某台CNC的连接,多台设备就是多个句柄。不要在一个句柄上并发调多个函数,一会儿读坐标一会儿读报警,同一个句柄的底层Socket不是线程安全的,我见过有人用多线程并发读导致数据错乱,最后不得不加锁。

2. 动手前的准备:环境、头文件和系统侧设置

2.1 官方库文件与开发环境搭建

FANUC官方提供的FOCAS2库文件分平台,Windows下主要是Fwlib32.dll、Fwlib32.lib和fwlib32.h,另外还有供C#调用的Focas32.dll封装(实际是对DLL的P/Invoke封装,官方一般随库一起给)。Linux下对应的是libfwlib32.so和fwlib32.h。安装过程不复杂,就是拷贝库文件到工程目录、配置头文件路径、链接库,但有几个细节坑很多新人会踩:

  • 32位和64位问题:Fwlib32.dll这个名字里的32不代表只能在32位系统用,实际有x86和x64两个版本。如果你的上位机是64位程序,必须用64位的DLL,否则加载就会报错。
  • 语言绑定:C#开发时,如果不用官方封装,要自己写DllImport声明。比如[DllImport("Fwlib32.dll")] public static extern short cnc_allclibhndl3(string ip, ushort port, int timeout, out IntPtr handle);声明错了会导致调用约定不匹配,直接崩溃。

用表格总结一下常用库文件和对应语言:

文件/库适用场景备注
Fwlib32.dllC/C++、C#(DllImport)需区分x86/x64
libfwlib32.soLinux C/C++服务端编译时加 -lfwlib32
Fwlib32.hC/C++工程包含所有函数声明和结构体
Focas32.dllC#快速开发封装了常用函数,直接引用

2.2 CNC侧的参数与以太网设置:连不上时先查这里

很多人写好了代码却连不上CNC,原因往往不在电脑上,而在机床参数上。FOCAS2以太网功能需要在CNC面板上先激活,这几项是必须确认的:

  • 确认机床安装有以太网功能板或内置以太网口,一般从系统版本画面能看到“Embedded Ethernet”字样。
  • 按SYSTEM键,进入以太网参数设置界面,给CNC分配一个空闲的IP地址,子网掩码和上位机要在同一网段。
  • 参数设置里确认端口号是8193,一般默认不用改。
  • 有些系统还需要在“数据服务器/DNC”相关参数里把FOCAS接口置为有效。

具体参数号因系统系列而异,不能一概而论,但思路是一样的:IP通、端口通、功能激活,三个条件缺一个都连不上。我在现场还遇到过某台设备IP能PING通,但FOCAS就是不响应,最后查出来是这台机器的FOCAS功能授权没开通,折腾了半天。

3. 核心函数分类拆解:这些函数占了实际开发的八成工作量

3.1 连接管理三件套:cnc_allclibhndl3、cnc_releaseclibhndl

连接函数是整个FOCAS开发的第一步,也是最容易出错的一步。新版本推荐用cnc_allclibhndl3,它比老的cnc_allclibhndl多了端口号参数,适用于以太网连接:

#include "fwlib32.h" ODBHND handle; short ret; // 参数:IP地址,端口号8193,超时时间10秒,输出句柄 ret = cnc_allclibhndl3("192.168.0.100", 8193, 10, &handle); if (ret == EW_OK) { printf("连接成功\n"); } else { printf("连接失败,错误码: %d\n", ret); }

返回值的判断必须重视。我见过不少人在连接后不检查ret,直接往下读数据,结果句柄是无效的,读出来的数据全是垃圾值。EW_OK是0,其余的错误码在fwlib32.h里都有宏定义,比如EW_BUSY(-9)代表CNC忙、EW_PROT(-15)代表以太网协议错误、EW_SOCKET(-17)是Socket相关错误。

对应的断开函数是cnc_releaseclibhndl

ret = cnc_releaseclibhndl(handle);

这个函数的返回值一般不用太纠结,程序退出前调用一次就好。但注意不要在回调函数或者线程终止时忘记释放句柄,长时间运行的服务端程序频繁连接断开不释放,会耗尽系统Socket资源。

3.2 必读的状态与坐标函数:cnc_rdstat、cnc_rdposition

状态读取是FOCAS最常用的功能。cnc_rdstat返回一个ODBSTAT结构体,里面最关键的是status字段,它是一个按位定义的状态字,可以用来判断机床当前是自动、手动、MDI还是编辑模式,以及是不是处于运行状态、是否急停、是否有报警。

ODBSTAT stat; ret = cnc_rdstat(handle, &stat); if (ret == EW_OK) { unsigned short status = stat.status; // 判断自动模式:status & 0x0001 等位运算 // 不同系统版本位定义有细微差异,建议对照头文件注释 }

位置读取用的是cnc_rdposition,这个函数参数里有个type,用来指定读取哪种坐标:0是绝对坐标,1是机械坐标,2是相对坐标,-1是全部坐标。输出结构体是ODBPOS,里面的Position是一个联合体,按轴索引存了double类型的坐标值。

ODBPOS pos; ret = cnc_rdposition(handle, 0, &pos); // 读绝对坐标 if (ret == EW_OK) { printf("X: %.3f\n", pos.Position.m_abs[0]); printf("Y: %.3f\n", pos.Position.m_abs[1]); }

这里有个细节坑:拿到的轴坐标顺序是按系统轴定义的,不一定X是0、Y是1,最好用cnc_rdaxisname先读出每个轴的名字,再和坐标数组对应起来。我曾经在五轴机上踩过这个坑,想当然地按前三个轴就是XYZ,结果把A轴数据当成了Z轴来统计,工件尺寸监控直接偏了十万八千里。

3.3 报警和程序读取:别看不上这几个函数

报警读取cnc_rdalm的用处非常大,尤其是做车间集中监控大屏的时候。它返回ODBALM结构体,包含报警号(AlarmNo)和报警类型(Type),Type区分了NC报警、操作报警、PMC报警等不同类型。

ODBALM alm; ret = cnc_rdalm(handle, &alm); if (ret == EW_OK && alm.AlarmNo != 0) { printf("当前报警号: %d\n", alm.AlarmNo); }

要注意cnc_rdalm一次只返回第一条报警,如果机床同时有多个报警,需要循环读取还是只读一条,取决于报警类型字段。官方文档里对每种Type有说明,有些类型支持随后一条一条读取。

程序相关的两个常用函数是cnc_rdopn读取当前打开的程序路径和cnc_rdprgnum读取当前程序号。这两个函数配合起来就能知道机床在跑哪个程序、程序号是多少,再结合坐标数据就能做产量统计和程序运行状态追溯。

3.4 宏变量读写:车间柔性化改造的“万能钥匙”

宏变量读写是FOCAS里最灵活的一对函数:cnc_rdmacrocnc_wrmacro。变量号从1到999,公共变量从100到249(各系统有差异),用起来就是一个按变量号存取的数值空间。你可以在CNC程序里通过#100=1这样的指令把状态写到宏变量里,上位机再去读,这样就不用去解析复杂的系统状态位了。

ODBMACRO macro; ret = cnc_rdmacro(handle, 100, &macro); // 读#100 if (ret == EW_OK) { printf("#100 = %d\n", macro.value); }

反过来,上位机往宏变量里写值,就能实现远程设定坐标系偏移量、刀具寿命计数清零等功能。很多自动化改造项目,比如自动门控制、夹具切换、工单号下发,都是靠宏变量作为“中间媒介”实现的,因为CNC程序里可以很方便地读取和判断#变量,避免了直接去改系统内部偏置的复杂操作。实际用下来,宏变量读写比直接操作刀补参数安全得多,不容易把系统弄乱。

4. 编一套完整的采集流程:从连接到容错

4.1 建连的正确姿势:重试和超时策略

实际项目里,我建议把FOCAS连接封装成一个独立的类或者模块,不要到处裸调连接函数。以C#为例,一个稳定可用的连接流程大概是这样的:

public bool Connect(string ip, int timeout = 10) { if (_connected) return true; short ret = FocasAPI.cnc_allclibhndl3(ip, 8193, timeout, out _handle); if (ret == FocasAPI.EW_OK) { _connected = true; return true; } // 断开后重试,最多3次 for (int i = 0; i < 3; i++) { Thread.Sleep(2000); ret = FocasAPI.cnc_allclibhndl3(ip, 8193, timeout, out _handle); if (ret == FocasAPI.EW_OK) { _connected = true; return true; } } Log.Error($"{ip} 连接失败,错误码 {ret}"); return false; }

为什么一定要重试?因为CNC在开机启动过程中,以太网服务并不是瞬间就绪的,有时候系统刚上电,你上位机采集程序启动得比CNC快,就会连不上。加个重试逻辑,程序就稳定得多。同时建议每台设备用独立的连接标识,把设备号、IP、当前连接状态放在一起管理。

4.2 数据采集循环:怎么读才能不卡死

连接建立后,就要进入采集循环了。一个典型的采集任务间隔可能是500毫秒或者1秒,具体取决于业务需求。采集循环里要注意:FOCAS调用是同步的,如果CNC响应慢或者网络抖动,单次调用可能阻塞数秒。所以采集线程别开一个死循环傻等,建议用一个定时器或者带超时机制的任务队列来触发采集。

private void PollData(object state) { int cncId = (int)state; // 先判断连接是否有效 if (!_sessions[cncId].IsConnected) return; // 读取坐标 FocasAPI.ODBPOS pos = new FocasAPI.ODBPOS(); short ret = FocasAPI.cnc_rdposition(_handle, 0, ref pos); if (ret != FocasAPI.EW_OK) { // 如果返回EW_BUSY,说明上一次调用还没完成,跳过本次 return; } // 解析坐标数据,写入数据库或消息队列 double x = pos.Position.m_abs[0]; double y = pos.Position.m_abs[1]; SaveToDatabase(cncId, x, y); }

特别要提醒:有些开发者发现采集偶尔卡一下,就以为是FOCAS有问题,其实很多时候是采集线程把数据库写入操作也放在同一个线程里,数据库慢了,FOCAS调用就被堵住了。建议把“读FOCAS”和“写库/上报”拆成两个线程,中间用队列解耦,读到的数据先丢队列,写库线程慢慢消化。这样即使数据库抖动,也不会反过来拖垮FOCAS采集。

4.3 断开和重连:长时间运行的保命逻辑

车间采集程序一般要求7乘24小时运行,所以断线重连机制是必须的。我的习惯是:每次采集前先验证连接,如果发现连接失效,就调用cnc_releaseclibhndl强制释放旧句柄,然后按启动时的连接参数重新连接。

这里有个细节:如果同一台CNC被多个上位机程序同时连接,FANUC系统有最大连接数限制(一般有限制数量,具体要看系统设置),超出后新的连接请求会失败。在重连逻辑中,如果返回的错误码表示连接数已满,不要无限重试,要通过日志或者消息推送通知现场人员处理。

5. 常见问题与排查技巧:那些文档上没写的坑

5.1 连接不上:先PING还是先查参数

我总结了一个排查顺序,遇到连接不上先照着走:

  1. 上位机是否可以PING通CNC的IP地址?如果不通,查网线、交换机端口、IP网段。
  2. 如果PING通但cnc_allclibhndl3失败,检查CNC侧FOCAS功能是否激活,以太网端口是否是8193。可以在CNC侧用系统自带的网络诊断功能查看连接状态。
  3. 检查Windows防火墙是否放行了8193端口,或者临时关掉防火墙测试。
  4. 看错误码。EW_HOST(-16)一般是主机名错误,EW_SOCKET(-17)大概率是网络不通或对端拒绝,EW_PROT(-15)可能是CNC的FOCAS服务未启动。不同错误码对应的排查方向差别很大。

我遇到过最离奇的一次是上位机换了新IP后FOCAS连不上,但PING是通的。查了半天发现是因为新IP网段跟CNC侧设置的“允许访问IP白名单”不一致,CNC侧的安全设置限制了连接来源。这种问题不会体现在报错里,纯靠排查经验。

5.2 数据读取失败:注意返回值与结构体占用

读数据的时候,返回EW_BUSY(-9)表示CNC正在执行上一个请求,这时候重试或者跳过即可。返回EW_LENGTH(-11)表示传入的缓冲区长度不对,检查结构体大小是否和库版本匹配。不同版本的FOCAS库结构体可能增加了字段,如果你用旧的头文件编译,但运行时加载了新版本的DLL,就可能出现长度不匹配。

还有,读取数据和读取参数用的结构体定义在头文件里都是紧凑排列的,但在C#里默认使用的是Auto布局,可能导致结构体大小和C++不一致。解决办法是给结构体加[StructLayout(LayoutKind.Sequential)],强制按字段顺序排列。这个坑我排了一个下午,最后一行特性解决。

5.3 老版本兼容性和系统差异

FOCAS Library Version 4.2算是比较新的库版本,函数基本向下兼容,但有一个注意点:老版本FOCAS1的函数和FOCAS2的函数不能混用,比如cnc_rdposition的自定义类型在不同CNC系统上返回的轴数不一样,不能假设永远是三轴。五轴机读出来的数组就有5个有效值。

在开发多型号CNC数据采集系统时,我一般会建议先调用cnc_getcncinfo读取系统型号和系列,根据返回值做适配。不同系列的CNC在报警类型定义、状态位定义上有细微差别,不能拿FS16的经验直接套到FS30i上。

6. 几个常用函数速查:开发时随手翻

下面把FOCAS2最常用、我在项目中确实频繁使用的函数整理成速查表,方便参考:

功能分类函数名用途说明
连接管理cnc_allclibhndl3以太网连接,推荐用这个
连接管理cnc_allclibhndl老式连接(串口/板卡)
连接管理cnc_releaseclibhndl断开连接
状态cnc_rdstat读CNC状态(自动/手动/运行/暂停)
报警cnc_rdalm读当前报警
坐标cnc_rdposition读绝对/相对/机械坐标
轴名cnc_rdaxisname读轴名称映射
程序cnc_rdopn读当前程序路径/名
程序cnc_rdprgnum读当前程序号
程序传输cnc_uplod上传程序到上位机
程序传输cnc_downlod下载程序到CNC
宏变量cnc_rdmacro读#变量
宏变量cnc_wrmacro写#变量
参数cnc_rdparam读CNC参数
参数cnc_wrparam写CNC参数
诊断cnc_rddiagnosis读诊断信息
伺服负载cnc_rdsvmeter读伺服轴负载率(部分库版本支持)
主轴负载cnc_rdspmeter读主轴负载率(部分库版本支持)
系统信息cnc_getcncinfo读系统型号序列信息

这个表不用背,开发的时候对照着查就行。真正的重点不是记住每个函数签名,而是理解每个函数在什么业务场景下用。比如做设备开机率统计,核心是cnc_rdstat;做刀具寿命监控,核心是读宏变量和主轴负载;做DNC远程传输,核心是cnc_uplod与cnc_downlod。

再提醒一句:FOCAS库自带了一份官方手册,叫FOCAS2 Library User's Manual,里面每个函数都有参数说明、返回值和示例,是权威参考资料。任何人跟你说“我手头有整理好的函数大全”都不如官方手册靠谱。开发前先花两天把手册里常用函数的说明过一遍,比在网上搜各种零碎代码高效得多。

7. 给刚入坑的工程师几个实在建议

说实话,FOCAS开发的门槛不在函数调用本身,而在你对数控系统工作方式的理解。我见过不少写代码很溜的同事,到了现场看到FANUC系统面板就懵了,不知道IP在哪设置,也不知道怎么在MDI模式下测试宏变量。做这行,光会调API是不够的,至少得懂一点CNC的基本操作:怎么开机、怎么进入SYSTEM设置界面、怎么在MDI模式下跑一段小程序、怎么看报警履历。这些看似基础的东西,在调试FOCAS上位机时天天用得上。

另外,不要一上来就想读所有数据。先从连接成功、读状态、读坐标这三个最小功能做起,跑通一条链路,再逐步扩展。我早期一个项目就是贪多,想一步到位把所有采集项都做出来,结果报警解析的程序没处理好,连基础数据都采集不连续,返工了好几次。先小步快跑,把采集链路做稳定,后面加功能就只是加函数调用的问题了。

最后再分享一个调试技巧:抓包工具很好用。FOCAS走的是TCP协议,用Wireshark抓包可以看到上位机和CNC之间的报文交互。虽然报文是FANUC私有格式,但至少能看到TCP握手是否正常、请求发出后有没有响应。很多时候排查连接故障,抓包一看就明白了。比如TCP握手都成功但应用层没数据,基本可以断定是CNC侧FOCAS服务没就绪;如果连握手都失败,就是网络链路的问题。多抓几次包,你对FOCAS通信的体感会比看十遍文档都来得深。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询