首页 / 资讯中心 / 文章详情

C#写CNC数据采集:串口、FOCAS与Modbus选型及落地

C#写CNC数据采集:串口、FOCAS与Modbus选型及落地 ★ FEATURED ARTICLE
简介基于C#的CNC数据采集系统源码与配套数据集面向机械制造、工业自动化方向的个人学习者适合用来理解.NET环境下CNC机床实时状态采集、参数记录与基础故障诊断的实现思路。压缩包共29个文件约652KB包含9个C#源码文件含FanucOpe.cs、connectmachine.cs等、4个备份文件、2个DLL运行库、数据集及相关配置另外还有项目工程文件与说明文档基本构成一个完整的Windows窗体应用程序。已有167人浏览学习。通过学习这份资源可掌握C#与FANUC数控系统交互的常见模式了解数据表结构设计、界面资源组织以及工程编译要点源码配合数据集使用能帮助练习从真实机床数据中提炼信息为后续开发更完整的采集系统打下基础。1. C# 写 CNC 数据采集给“哑巴机床”开一扇窗工厂里最常见的痛点不是设备开不起来而是设备在正常干活管理系统里却一片空白。想算 OEE、做预测性维护、揪出那台“一到夜班就慢”的机床结果发现控制系统就是个黑匣子——协议、字段、接口全要自己一点一点摸。C# 写 CNC 数据采集系统就是在这层黑匣子上开一扇窗通过串口或以太网协议把坐标、主轴负载、报警、程序名这些运行数据周期性读出来清洗后落成本地数据集或推给 MES。这类项目在车间里通常就叫“C# 上位机”适合设备管理员、MES 实施工程师、以及想用数据做工艺优化的人入门。2. CNC 数据怎么读串口、FOCAS、Modbus 三条路线的选型与边界采集系统的第一课不是写代码而是搞清楚机床“讲什么语言”。FANUC 老系统多半支持 RS-232 宏程序应答新系统走 FOCAS 以太网库三菱有 EZSocket西门子 840D 常见走 S7 或 OPC UA不少国产控制器直接开放 Modbus TCP。协议选错代码再漂亮也是废的。这章先把路线选明白再谈实现。2.1 先想清楚你到底要采什么数据很多人第一版需求只有一句“把机床数据采上来”从这一步就开始踩坑。我一般先分四类状态与报警、坐标、负载与速度、程序与工艺。状态与报警包括运行、待机、急停、报警代码这组数据决定 OEE 能不能算准坐标指 X/Y/Z/A/C 的绝对坐标和机械坐标用来算节拍、统计行程、复核轨迹负载与速度包括主轴负载百分比、主轴转速、进给速度、各轴负载和主轴扭矩故障预警主要靠这组。如果你接到“读 power focus 6000 扭矩值”这类需求其实是把测力系统当作独立设备接进采集链路协议走厂商私有接口但数据进入数据集之后的处理逻辑和主轴负载曲线完全一致。这四类不是都要采。采集点每多一列后续的字段一致性维护、缺失值处理和模型适配成本都会翻倍。我的建议是先采状态、负载、报警三大类坐标作为第二阶段再加。数据项可以后续补但协议字段设计一开始就不要贪多否则光是清洗对齐就够你忙两周。2.2 两种主流通讯路线RS-232 串口与以太网老机床最可靠的方案是 RS-232 串口。优点是几乎没有许可成本接线简单不受以太网网段干扰缺点是半双工一问一答一次只能问一个量波特率常见 9600、19200、38400通信周期做到 100ms 量级就算不错。还有一个硬条件机床侧要配置宏程序应答协议由设备手册给同一品牌不同年代的系统命令格式经常对不上必须逐台核对。以太网是现代上位机的主流。FANUC 的 FOCAS、三菱的 EZSocket、西门子的 S7/OPC UA 都属于这一类共同点是机床控制器作为 TCP 服务器PC 端做客户端周期读数据。差异在库FOCAS 提供 fwlib32.dll 这类原生库C# 侧要用 DllImport西门子 OPC UA 则是标准化的订阅式采集实时性和规范性最好但选型和授权成本也最高。除此之外很多国产控制器直接开放 Modbus TCP 寄存器映射表这是开发量最小的一条路前提是设备厂肯把寄存器表完整给你。2.3 选型对照与我的建议路线适合系统开发量数据实时性关键注意点RS-232 宏老 FANUC、老三菱中100ms 级必须有设备手册一次一问串口参数要严格一致FOCAS 以太网FANUC 带网口型号中可到 50msfwlib32.dll 位数要匹配句柄要释放EZSocket三菱数控中可到 50ms厂家资料少需要时间去磨S7 / OPC UA西门子、新系统大但标准化高10ms 级授权和组态成本高订阅机制体验最好Modbus TCP国产控制器、PLC小10ms 级寄存器映射表一定要找设备厂要到我一般会先问设备部门要三样东西机床型号清单、通讯选项清单、控制器手册。先看有没有 FOCAS、EZSocket 或 Modbus有就走以太网没有就买串口服务器转 RS-232。别一上来就上 OPC UA——对产线改造项目它的组态和授权会吃掉大量时间而收益要到几十台设备的规模才明显。3. 用 C# 跑通一台 CNC 采集串口版与 FOCAS 版的最小实现协议定了代码就简单了。C# 侧落地基本是两条路串口读写或者 DllImport 调设备厂提供的本地库。下面两个最小骨架都在我自己的项目里跑通过参数部分需要你按手里的设备手册替换。3.1 串口采集的一个最小骨架using System.IO.Ports; SerialPort port new SerialPort { PortName COM3, BaudRate 19200, // 以机床侧设置为准常见 9600/19200/38400 Parity Parity.Even, // 老机床常见 Even也有 None DataBits 8, StopBits StopBits.One, ReadTimeout 1000, WriteTimeout 1000 }; port.Open(); port.WriteLine(?X); // 伪指令按设备手册替换成真实读坐标命令 Thread.Sleep(30); // 半双工给机床应答留时间 string response port.ReadLine().Trim(); port.Close(); Console.WriteLine(response);这个骨架的关键不是 SerialPort API而是三个容易忽略的参数。波特率必须和机床侧面板设置完全一致差一位就是乱码串口线是交叉线还是直连线、机床侧是否把 RS-232 口配置成“远程读”直接决定你能不能收到响应每次发命令后要留 20~50ms 延时否则下一问会把上一答冲掉。另外很多老机床响应不带回车换行ReadLine() 会一直堵到超时这种时候要改成读固定字节数——先用串口调试助手抓包确认返回格式再写解析逻辑。3.2 以太网FOCAS的最小调用FANUC 是市场保有量最大的系统我以它为例。FOCAS 提供的是原生导出函数C# 里用 P/Invoke 调用using System.Runtime.InteropServices; internal static class Focas { // 连接 CNCip、端口、超时毫秒返回句柄 [DllImport(fwlib32.dll, CallingConvention CallingConvention.Cdecl, CharSet CharSet.Ansi)] internal static extern short cnc_allclibhndl3(string ip, ushort port, short timeout, out ushort handle); // 断开连接 [DllImport(fwlib32.dll, CallingConvention CallingConvention.Cdecl)] internal static extern short cnc_freehndl(ushort handle); // 读轴数据axis 是轴序号data 是输出 [DllImport(fwlib32.dll, CallingConvention CallingConvention.Cdecl)] internal static extern short cnc_rdaxisdata(ushort handle, short axis, out ushort type, out double data); } ushort handle; Focas.cnc_allclibhndl3(192.168.1.31, 8193, 1000, out handle); ushort type; // 0绝对坐标 1机械坐标具体以手册为准 double axisX 0; Focas.cnc_rdaxisdata(handle, 0, out type, out axisX); // axis 0 对应哪个轴查手册 Console.WriteLine($type{type}, X{axisX}); Focas.cnc_freehndl(handle);说明几个必须核对的地方。cnc_allclibhndl3 的端口默认一般是 8193但不同版本有差异以 FOCAS 协议手册为准axis 编号不是简单按 X/Y/Z 排进给轴和主轴常在同一张轴表里要查控制器参数。P/Invoke 有三项必查DLL 名字、调用约定Cdecl 还是 StdCall、结构体布局都要和你手里的 fwlib 头文件对齐。fwlib32.dll 是 32 位库项目必须发布成 x86进程位数不匹配会在加载时就崩。3.3 数据清洗与落库别一条一条 Insert采集端不能每 100ms 写一条数据库。常见做法是攒够一秒的批量再落库用参数化 SQL。表结构我建议起步就按下边的建后面做数据集分析不用重构CREATE TABLE cnc_samples ( ts TEXT NOT NULL, -- 服务器时间ISO8601 device_id TEXT NOT NULL, -- 机床编码 axis_x REAL, -- mm axis_y REAL, axis_z REAL, spindle_load INTEGER, -- 0-100 百分比 spindle_speed REAL, -- rpm feedrate REAL, -- mm/min mode_code INTEGER, -- 0自动 1手动 2MDI alarm_code INTEGER, -- 0 表示无报警 prog_name TEXT, line_no INTEGER ); CREATE INDEX idx_samples_ts ON cnc_samples(ts); CREATE INDEX idx_samples_dev_ts ON cnc_samples(device_id, ts);落库前先把 FOCAS 返回的 -1、NaN 这类无效值过滤掉。很多设备库在没有有效数据时返回 -1直接写进数据集后面做负载趋势分析会得到一堆“假停机”。这个过滤必须放在协议适配层而不是数据库层否则每个消费数据的下游都要重复踩一次。4. 把采集数据变成可用数据集字段设计、清洗与公开数据集参照很多项目死在“数据采上来了但没法用”。原因不是采集器不行是数据集在设计时没约定清楚单位、枚举、时间基准都是乱的后面所有分析都要返工。这一章讲清楚现场数据集怎么做才耐得住建模。4.1 CNC 数据集的标准字段与单位约定先定义一个稳定字段表比写采集器更重要。单位写错一个后面所有模型全作废。字段含义单位/取值范围示例ts服务器时间UTCISO86012025-06-01T08:00:00.123Zdevice_id设备唯一编码字符串MC-A03axis_x / axis_y / axis_z机械/绝对坐标mm125.40spindle_load主轴负载0-100%68spindle_speed主轴转速rpm3200feedrate进给速度mm/min800mode_code运行模式0自动 1手动 2MDI0alarm_code当前报警代码0 无报警0prog_name当前程序名字符串O1234line_no当前行号整数108约定三点。时间戳一律取服务器时间机床时钟只作为 raw 字段备份坐标单位 mm、速度 mm/min写进表注释枚举值必须在字典表里登记不要在程序里散落魔法数字。早年的 C# 上位机资料喜欢把数据放 Access单机采集没问题多台机床并发写就会锁库建议用 SQLite 起步量大了再换时序库这个迁移成本远低于一开始就上重型数据库。4.2 自己做现场数据集对齐、去重、打标签时间对齐是第一件事。采集机本机配 NTP时间戳用 DateTime.UtcNow每台机床保留一个“机床时间”字段用于排查控制器时钟误差。去重也很关键一个设备一个轮询周期只允许一条样本FOCAS 轮询时偶尔会重复返回同一帧数据要按 device_id ts 做去重否则统计分布会偏。打标签的思路决定数据集价值。标签来源尽量用 MES 的工单、工序 ID不要自己手填停机原因由设备人员录入作为分类 label。纯自动推断停机原因属于玄学准确率上不去训练模型时你会发现标签噪声比数据噪声更致命。另一个原则缺失值宁可为 null 也不填 0。现场数据很多字段是“当前不可用”填成 0 会让模型把“没数据”当成“数据是 0”这是预测性维护项目最常见的翻车点。4.3 公开数据集怎么参照做主轴或轴承故障诊断时很多人会去对照 PHM2012 或帕德劳恩Paderborn轴承故障数据集。这两套都是公开数据PHM2012 提供轴承和齿轮箱的退化过程数据Paderborn 提供多种故障类型的轴承数据把它们当成算法验证基准是行业惯例。但要清楚现场数据和公开数据的差异。公开数据集采样率高、标签干净、工况固定CNC 轮询采集通常只有几十到几百毫秒一条低频、工况混杂、标签要靠 MES 关联。所以不要拿公开数据集的分布直接套现场要用它验证“算法能不能分辨”再用现场数据集做适配和重训。真正想优化加工节拍还要把 CNC 编程里的工序与工艺参数和采集数据关联起来这一步依赖 4.1 里的 device_id 和时间戳做得够不够规整。5. 避坑CNC 采集中最常翻车的 5 个细节以下五条我在不同项目里都踩过按现象、原因、解决三个层次写省得你在现场绕远路。5.1 现象P/Invoke 调用 FOCAS 一进去就崩溃一调 cnc_allclibhndl3 就抛异常或进程直接退出最常见原因是 fwlib32.dll 的位数和进程位数不一致。DLL 名字带 32很多人却用 AnyCPU 或 x64 发布加载类型时直接翻车。另一个是调用约定不对FOCAS 常见是 Cdecl但不同版本有出入默认 StdCall 会导致栈错乱。解决发布配置固定 x86用 dumpbin /headers 或官方头文件确认导出函数的调用约定在 DllImport 里显式声明结构体布局严格按头文件排不要自己猜字段顺序。这一条解决后能省下半天定位崩溃的时间。5.2 现象读出来的程序名全是乱码FANUC 返回的程序名按机床语言编码日文和中文系统常见是 Shift-JIS 或 GB2312C# 字符串默认按 UTF-8 解码拿到就是乱码。程序名和工单关联不上数据集里这一列基本作废。解决P/Invoke 里不要用 string 直接接改成接收 byte[]再按 Encoding.GetEncoding(GB2312)代码页 936或对应的机床语言编码转成字符串。这一步看着小实际影响所有和程序名相关的下游分析乱码一天数据就白采了。5.3 现象坐标数据一直是 -1 或全是 0FOCAS 的 -1 不是坐标值是“该数据当前无效”的标记。常见原因是机床没在伺服使能、轴还没建立或者 axis 序号不对另一个隐藏点是读的是“绝对坐标”还是“机械坐标”type 字段没设置对。解决先在机床面板人工看一眼当前坐标记住轴号和 type再对照代码输出把所有 API 返回值先打印出来确认再写业务逻辑。不要觉得这一步多余现场环境里伺服没使能、急停未复位都会让数值异常尽早暴露出问题比攒一天坏数据强得多。5.4 现象机床操作面板变得卡顿轮询周期设得太短串口一直被占FOCAS 高频轮询几十个数据项也会增加控制器负载。机床是生产工具不是你的测试沙盒。每 50ms 一轮全家桶操作工按面板按钮都延迟这锅只能自己背。解决默认从 1000ms 周期开始稳定后慢慢降到 500ms、200ms采集 500 条无效数据不如采 1 条有效数据。换刀、急停等动作期间暂停高频轮询等状态稳定再恢复。要实时性优先减数据项而不是加频率。5.5 现象做趋势分析时发现时间戳前后跳变机床控制器时钟和服务器不同步或者服务器本身没配 NTP导致多台机床数据时间基准不一致。趋势分析一错位所有模型都白做更隐蔽的是这种错位往往要等到建模阶段才暴露。解决采集程序一律以服务器 UTC 时间为标准时间戳机床时间单独存 raw 字段给采集网段配 NTP每周核对一次偏差。时间戳是数据集的骨架骨架歪了后面再怎么精细清洗都救不回来。6. 从单机走向产线MQTT 上报与采集质量验证一台机床跑通只是开始。几十台设备往一个平台汇数据我通常把采集端做成“协议适配 MQTT 上报”的两段式适配器负责和机床对话网关负责把数据发到总线。这样的好处是换协议只动适配层上行链路完全不变。6.1 用 MQTT 把数据送上工厂总线using MQTTnet; using MQTTnet.Client; using System.Text.Json; var factory new MqttFactory(); using var client factory.CreateMqttClient(); var options new MqttClientOptionsBuilder() .WithTcpServer(192.168.1.50, 1883) .WithClientId(cnc-gateway-mc01) .WithCleanSession() .Build(); await client.ConnectAsync(options, CancellationToken.None); var sample new CncSample { DeviceId MC-01, SpindleLoad 68 }; var message new MqttApplicationMessageBuilder() .WithTopic($factory/cnc/{sample.DeviceId}/samples) .WithPayload(JsonSerializer.Serialize(sample)) .WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce) .Build(); await client.PublishAsync(message, CancellationToken.None);参数说明topic 按设备 ID 分区便于下游按机床订阅QoS 用 AtLeastOnce 保证不丢量但不要密集用 ExactlyOnce量大时性能差很多payload 里建议带 schema 字段将来加列下游能平滑升级这是避免解析翻车的小技巧。断线重连的逻辑不能省后台 Task 里要做退避重试否则网络抖动一次设备数据就缺半小时。6.2 一天的数据质量体检脚本上线第一天不要急着训练先做数据体检。我一般写一个每日检查脚本查三个指标缺失窗口、无效值占比、时间戳单调性。# 查 MC-01 超过 5 分钟没有数据的缺失窗口数量 sqlite3 cnc.db WITH t AS ( SELECT ts, ROW_NUMBER() OVER (ORDER BY ts) AS rn FROM cnc_samples WHERE device_idMC-01 ) SELECT COUNT(*) FROM t t1 JOIN t t2 ON t1.rn t2.rn - 1 WHERE strftime(%s, t2.ts) - strftime(%s, t1.ts) 300;无效值比例可以在采集侧统计超过 1% 就要回头查协议层是不是在硬读未使能的轴。时间戳检查更简单相邻 ts 差值出现负数就是 bug。我现在新接一条产线会先拿一天原始数据做这三项体检再谈建模这个习惯救过我很多次希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站