前阵子调试一台在线检测设备,甲方现场工程师在设备旁蹲了三天后问了句:你们这套程序,一边做三菱FX-5U的轴定位,一边用Modbus RTU从RS-485接口的测微计上拉数据,一条串口线真能扛得住?我当时跟他解释了半天,回来后又把整个项目的设计思路、接线方式、程序结构和调试记录重新捋了一遍。发现这种“定位轴+串口测量”的搭配在中小型自动化设备里其实非常典型,但网上能把两块内容串起来完整讲清楚的资料很少,要么只讲定位指令,要么只讲Modbus轮询,很少有把轴定位、RS-485物理层、寄存器映射、联锁时序放在同一个案例里讲透的。
这篇文章不搞玄乎的“大揭秘”,就以我调试过的这个模拟项目为例(在线厚度/直径检测设备,电缸送料定位,测微计测量),把硬件选型、通信参数、寄存器表、PLC程序思路、调试踩坑这几件事挨个说清楚。适合正在用FX-5U做设备改造、准备把带RS-485的仪表传感器接入PLC、或者想把定位和通信联动起来做闭环检测的电气工程师。
1. 这套系统的需求拆解:轴定位和在线测量为什么绕不开RS-485
1.1 被测对象与工艺节拍:测微计不能只当“数显表”用
先还原一下这个项目的原始需求。设备要完成的工作并不复杂:一个工件被放到滑台上,电缸或步进丝杆把它推到测量工位,测微计下压接触工件表面,读出厚度或直径数据,PLC判断合格还是不合格,再根据结果决定往哪个料道排料。看起来就是“走位—测量—判断”三步,但真要让设备稳定跑起来,有几个问题绕不开。
测微计本身在大多数现场是作为独立数显表使用的,操作员看屏幕记录数据。但这里不行——节拍要求是每件产品自动测量、自动判定,数据要进入PLC参与逻辑判断,还要能被触摸屏查询甚至上传到MES。让操作员肉眼读数再手动输入,既慢又容易错,完全违背了在线检测的初衷。所以必须让测微计的数据能直接被PLC读走,而且是数字量直接进程序,不是模拟量进AD模块再换算。串行通信就成了最自然的选择。
另外一个容易被忽略的需求是追溯。现场后来明确要求每件产品的测量值都要存下来,按批次导出。这意味着PLC不仅要读数据,还要能区分“当前读到的数据属于哪一件产品”,这靠的就是和轴定位动作严格绑定:只有滑台到位、测微计压下、通讯稳定这一串动作全部满足,数据才有效。这也是我后面把定位到位信号和测量有效标志做成联锁的原因。
1.2 一条485总线上的设备拓扑与主从关系
确定要用串行通信后,我第一时间看的是FX-5U本体带不带串口。FX-5U的标准型号中很多自带一个RS-485通信口,如果没有也可以用FX5-485-BD通信板扩展一个,这个后面专门说。多数带Modbus RTU从站功能的测微计出厂默认是485接口,支持标准Modbus RTU协议,站号可通过面板或配置软件设置。
整个系统的拓扑可以用一句话描述:PLC是唯一的Modbus主站,测微计是从站,两者用一对双绞线连接,总线上只有两个节点。
这里必须强调一个很多新手会误解的点:Modbus RTU是一主多从协议,从站永远不会主动上报数据。你指望测微计“测完自动把数据发给PLC”是不可能的,必须PLC主动去问(读寄存器),测微计收到请求后才返回应答。所以程序结构上一定会有一个周期执行的“轮询任务”——比如每隔50ms发一次读请求,读回来后刷新数据寄存器。如果测微计的测量速率远高于轮询周期,那就以轮询周期为准,读到的值就是“最近一次被采样的测量值”。
除了通信链路本身,系统里还有第二条关键链路:FX-5U内置定位输出的脉冲信号。它通过高速脉冲输出口接到步进或伺服驱动器,再驱动电缸/丝杆滑台。这条链路和485链路物理上互不相干,但在程序里必须紧密配合,因为测量数据只有在正确的机械位置下才有意义。
2. FX-5U的轴定位方案:内置定位与脉冲当量的折算
2.1 晶体管输出型FX-5U自带四轴脉冲,不需要额外定位模块
先聊轴定位这部分,因为它是整个动作的执行基础。FX-5U选型时有个关键分支:继电器输出型不能做高速脉冲定位,晶体管输出型才有内置定位功能。如果你订货时选了继电器输出的FX-5U,后面想加定位轴,基本只能靠扩展模块,成本和占位都上去了。所以做带定位需求的项目,建议直接选晶体管输出型。
晶体管输出型的FX-5U本体最多可以支持四轴脉冲输出,单轴频率做到200kHz这个量级(具体视模块规格和接线方式而定,选型时以对应手册为准)。对大部分电缸、丝杆滑台、小功率伺服来说,这个频率完全够用。我这台设备用的是步进电机方案,电缸行程只有150mm,负载不大,200kHz对应到丝杆导程上完全可以达到需要的速度。
程序实现定位动作可以直接用定位指令,比如DDRVA(绝对定位)、DDRVI(相对定位)、ZRN(原点回归)等。GX Works3里可以写梯形图,也可以混用结构化文本ST。我个人习惯是:简单动作用梯形图看得清楚,复杂多步骤流程用ST写状态机更好维护。后面第5章给的流程框架就是ST风格的状态机,实际项目里我一部分逻辑也用ST写,但要说明的是这并不代表梯形图不行,纯粹是个人习惯。
2.2 电子齿轮比与脉冲当量:从丝杆导程到用户单位
定位精度不是靠PLC“想”出来的,必须把机械参数折算成脉冲量。这里有一个必做的计算:一个脉冲对应多少毫米,也就是脉冲当量。
拿我手头这台设备举例:滚珠丝杆导程10mm,步进电机步距角1.8°,驱动器细分设置为8细分。那么电机每转一圈需要的脉冲数是:200 × 8 = 1600。因为丝杆转一圈螺母走一个导程,所以一个脉冲对应的位移是:10mm ÷ 1600 = 0.00625mm。
这个“0.00625mm/脉冲”就是实际的脉冲当量。但0.00625这种小数在程序里直接做换算很别扭,所以我通常在FX-5U的定位参数里设置“单位倍率”,让程序里直接以0.001mm(1μm)为单位来下发目标位置和速度。也就是说,PLC里写DDRVA的定位地址如果是15000,代表目标位置是15.000mm;速度如果是5000,代表5mm/s。
这里有个容易出错的细节:如果你用的是伺服而不是步进,电子齿轮比往往在驱动器侧设置,PLC看到的实际还是“位置指令脉冲数 = 机械位移 / (导程 / 每转脉冲数)”。无论怎么设,最后系统里必须有一个明确的“PLC脉冲数 ↔ 机械毫米”的换算关系。建议写一个交接文档把计算过程固定下来,别靠脑子记,半年后现场改参数时你会感谢这份记录。
2.3 定位完成信号别只信指令标志,要看伺服驱动器的到位信号
轴定位程序里最容易踩的坑不是算不对脉冲数,而是“到底什么时候算到位”。FX-5U定位指令执行完成后会有定位完成标志(比如某个状态继电器),程序里如果只等这个标志就立刻触发测微计动作,十有八九会在高速定位时出问题。
原因是定位指令标志只代表“PLC已经把规定的脉冲数发完了”,不代表机械已经真正停稳。步进电机尤其明显:速度快、负载惯性大的情况下,脉冲发完那一刻电机可能还在微动甚至过冲。测微计是精密测量仪器,如果机械没停稳就压下去,读数会抖,严重时还会撞坏测头。
我在这台设备上做了双重确认:第一重是PLC定位完成标志,第二重是伺服/驱动器反馈的“到位输出”(有些驱动器叫INP、定位完成、Servo Ready),只有两个信号都有效才认为定位真正结束。另外,考虑到机械振动,我在定位完成后还强制加了50~200ms的稳定延时(看负载大小调整),再触发测量动作。这个延时不长,但对测量稳定性帮助极大。
3. 测微计的Modbus RTU接入:寄存器映射与RS-485物理层
3.1 先看说明书:通信参数、站号、寄存器地址一张表搞定
测微计这类仪表实现Modbus RTU从站,通信参数一般都比较固定。我实测过的某款测微计出厂默认是:波特率9600、8位数据、无校验、1位停止位(简称9600/8/N/1),从站地址默认为1。不同品牌默认值可能有差异,有些老款日本仪表甚至默认是7位数据偶校验(7/E/1),所以第一步永远是查说明书或用手持配置器确认,不能拍脑袋。
寄存器地址也是同样的道理。不同厂家的测微计寄存器映射差异很大,常见的做法是把当前测量值放在保持寄存器或输入寄存器里,可能是16位整数,也可能是32位整数或单精度浮点。下表是我根据某款测微计手册整理的简化映射,仅用于展示思路,实际编程时务必对着自己的仪表手册核对:
| 寄存器地址 | 内容 | 数据类型 | 读写属性 |
|---|---|---|---|
| 0000H | 当前测量值(带符号) | 32位整数 | 只读 |
| 0004H | 状态字(0=正常,1=超量程,2=未定位) | 16位整数 | 只读 |
| 0100H | 清零/去皮命令 | 16位整数 | 读/写 |
| 0200H | 测量值上限设定 | 32位整数 | 读/写 |
这里要特别提醒:地址可能是“Modbus协议地址”也可能是“寄存器编号(PLC地址)”,两者差1,写程序前先确认清楚。很多通信不成功、读回来的数据明显不对,都是因为地址偏移了1位,这类问题用串口调试助手一帧一帧对比就能发现。
3.2 RS-485的物理层处理:A/B、屏蔽层、终端电阻三件事
485通信看着简单,就两根线,但现场80%的通信故障出在物理层。我这台设备调试时也遇到过读数偶尔跳变、时通时断的问题,最后排查下来基本都跟下面这三个细节有关。
第一是A/B线的定义。RS-485规范里A和B是标准叫法,但很多设备端子上标的是D+/D-、DATA+/DATA-,甚至有的标TX+/TX-。不同厂家的命名有时候还会把A/B反着标,PLC和测微计之间的A/B接反,通信是完全没有反应的。处理办法是:不要只看端子丝印,先拿万用表量一下两端A线之间、B线之间的通断,并且用示波器或调试助手验证数据波形方向,最快的办法是先把A/B对调试一次。
第二是屏蔽层和接地。485通信线建议使用带屏蔽层的双绞线,屏蔽层要单端接地——一般接在PLC侧或电源地,不要两端都接,也不要悬空。我这次现场故障之一就是屏蔽层没接地,导致电机运行瞬间测微计读数跳字,接地后问题消失。另外,485通信线要尽量远离动力线、变频器输出线,平行走线间距至少保持20cm以上,无法避开时要垂直交叉。
第三是终端电阻。Modbus RTU的RS-485总线两端需要各并联一个120Ω终端电阻。两点通信时,在PLC通信口端和测微计端各加一个就可以了(很多仪表内置了终端电阻开关,拨码选上即可)。如果忘记接,距离短、波特率低时可能没问题,但距离稍微拉长或现场干扰一上来,通信就会不稳定。注意:终端电阻只加在总线的物理两端,不是每个节点都加,否则会拉低信号幅值。
3.3 轮询周期与读数滤波:不是读得越快越好
Modbus RTU轮询周期并不需要追求极短。测微计本身有测量响应时间(有的几十毫秒,有的上百毫秒),PLC扫描周期一般几毫秒,两者之间的瓶颈在仪表侧。如果PLC每隔5ms就发一次读请求,仪表根本来不及更新数据,读到的全是一样的旧值,还白白占用CPU和总线。
我实际设定是:轮询间隔50ms,每次读回当前测量值和状态字两个寄存器(用一次功能码03连续读2个地址就能完成),读回后立即把数据锁存到一组专用寄存器里。测量阶段,取最后连续5次有效读数的平均值作为判定值,这样能滤掉仪表本身输出时的微小抖动。平均值算法不做复杂处理,就是累加除以次数,但在工业现场比单次读数可靠得多。
读到的测量数据也不能“无条件信任”。状态字如果显示“未定位”或“超量程”,即使数值寄存器有数据,也要当成无效数据处理。这就是第1章说的“测量有效标志”,它必须是“轴已到位、测微计已压下、通信已成功、状态字正常”四件事同时成立时的综合结果。
4. 通信指令选型:RS指令手拼CRC与ADPRW自动读写
4.1 RS指令的报文帧长与CRC16手算逻辑
FX-5U实现Modbus RTU主站,最基础的方式是使用RS指令(无协议通信指令),也就是PLC自己组报文、自己解析响应。这种方式灵活,但工作量在:要自己组装请求帧、计算CRC16校验码、解析响应帧、处理超时。
先看标准请求帧格式。以“读取测微计地址0000H开始的2个寄存器”为例,功能码是03(读保持寄存器),站号是01,请求帧如下:
01 03 00 00 00 02 CRC_L CRC_H- 01:从站地址
- 03:功能码,读保持寄存器
- 00 00:起始寄存器地址(高字节在前)
- 00 02:读取寄存器个数(高字节在前),2个寄存器占4字节
- CRC_L CRC_H:CRC16校验码,低字节在前
测微计收到请求后正常会返回:
01 03 04 XX XX XX XX CRC_L CRC_H其中04表示后面有4个字节数据,XX就是两个寄存器的原始值。如果站号、功能码、寄存器地址组合有误,从站会返回异常帧(功能码最高位置1),这时候拿到的是错误码而不是数据,程序里必须区分这两种响应。
CRC16(Modbus)的算法规则是:初始值0xFFFF,多项式0xA001,按位异或后右移。C语言或Python实现很成熟,我贴一个参考逻辑:
def crc16_modbus(data): crc = 0xFFFF for b in data: crc ^= b for _ in range(8): if crc & 1: crc = (crc >> 1) ^ 0xA001 else: crc >>= 1 return crc在PLC里实现这个计算,通常用查表法更快,把256个低字节的CRC表放在寄存器区里,逐字节查表计算。用梯形图写CRC会显得占用很多程序步,但拆成ST函数块就清爽了。如果你不想自己写CRC,可以直接用标准RS指令通信库或下面的ADPRW。
4.2 ADPRW把参数化读写简化到什么程度
FX-5U相比FX3U一个很大的进步是提供了ADPRW指令,专门用于Modbus通信。这个指令相当于把“组帧、算CRC、发送、接收、校验”这些工作大部分封装好了,你要做的只是告诉它:从站号是多少、功能码是什么、起始地址在哪、读几个数据、结果放到哪个寄存器区。
ADPRW指令大概的结构是:前面放一个执行条件,接着指定“完成标志”软元件、“控制数据”首地址、通道号,以及数据存储软元件首地址。控制数据里就包括从站号、功能码、起始地址、读写点数这些参数,每个参数在分配好的连续字软元件里按固定顺序填写。PLC执行后会自动完成请求发送、响应接收和CRC校验,你只需要等完成标志置位再去读数据区。
使用ADPRW的一个额外好处是程序结构非常清晰,尤其是从站数量多的时候:每个从站建一组控制数据区和数据区,一条ADPRW对应一个读操作,别人看程序一目了然。缺点是按特定仪表做特殊报文(比如厂家自定义的非标准命令)时,还是得回到RS指令自己拼帧。
4.3 超时、重试、异常码的兜底逻辑
不管是RS还是ADPRW,通信程序必须有一个兜底逻辑:如果从站没响应怎么办?如果响应了但异常怎么办?如果没有兜底逻辑,现场一出现干扰,整个状态机就可能卡死在“等数据”这一步。
我的做法是:每条读指令执行时启动一个超时定时器,超时时间设为300ms(Modbus RTU响应一般在百毫秒内,300ms足够)。超时或收到异常码就判定这一次通信失败,重试次数加1;连续失败3次后,系统给出“测微计通信报警”并锁停测量动作,不让设备带着不可靠数据继续跑。单次失败并不立即报警,因为偶发的干扰帧重试一次就能恢复。
另外,响应帧的解析不能只看“收到数据”,还要验证站号和功能码是否和请求一致。曾经遇到过现场总线上接了不止一个从站的情况,另一个从站的响应帧被误收进来,导致数据张冠李戴。加校验后这种问题就彻底杜绝了。
5. 轴定位与测微计联动的程序流程:从取料到判定NG
5.1 主流程状态机:定位、测量、判定如何串起来
轴定位和测微计读取这两个功能在程序里不是两段独立代码,而是必须放进同一个动作状态机里。我习惯用ST写这个流程,结构清晰也容易扩展。简化后的逻辑框架如下:
CASE state OF 0: (* 空闲,等待启动 *) IF start THEN state := 10; END_IF; 10: (* 取料完成,绝对定位到测量位 *) DDRVA(measure_pos, speed, ...); IF servo_done AND stabilize_timer THEN state := 20; END_IF; 20: (* 请求测微计清零并开始测量 *) write_clear_cmd(); (* 写去皮命令 *) measure_req := TRUE; IF measure_valid THEN save_measured_value(); state := 30; END_IF; 30: (* 根据测量值判定OK/NG *) IF value > upper_limit THEN ng_reason := 1; ELSIF value < lower_limit THEN ng_reason := 2; ELSE ng_reason := 0; END_IF; state := 40; 40: (* 分流卸料并复位 *) unload_action(); state := 0; END_CASE;这段代码只是逻辑框架示意,实际工程里DDRVA的完成判断、测量有效标志的生成、定时器管理都要单独做成功能块。但核心思想已经很清楚:状态切换的每一道门槛都由上一个动作的完成信号控制,绝不允许用延时硬顶过去。这是设备稳定运行的关键。
5.2 用测量值修正定位目标值:“以测代调”的工艺用法
这台设备还有一个特色需求:由于装配公差和刀具磨损,工件的测量基准会缓慢漂移。如果定位目标值永远固定,测微计下压深度会随基准漂移而变化,影响测量一致性。解决思路是用测量值做反馈,自动修正定位目标。
具体做法是:第一件工件按初始设定定位测量,如果测微计读数偏大,说明实际工件尺寸偏高,那么下次定位时把目标位置补偿掉偏差值(比如整体下移0.02mm)。这个修正量在程序里单独存一个“补偿寄存器”,每次测量后经过一阶滤波再叠加到定位目标上。相当于把测微计当成一个闭环反馈传感器,轴定位不再只是“开环发脉冲”,而是由测量数据闭环微调。
要注意的是:补偿量必须设上下限和防突变保护。如果读数突然跳变几十丝,说明可能出现了异常(工件摆放歪了或测头卡住),这时候补偿量不能跟着乱跳,要限制单次修正幅度并触发人工检查。
5.3 数值转换与小数点对齐:HEX、BCD、float的处理
通信读回来的原始数据,经常不是PLC里直接能用的浮点数。测微计常见的返回值格式有三种:16位带符号整数、32位带符号整数、单精度浮点(IEEE 754)。不管哪一种,都必须先确认单位和量纲,再换算成μm或mm级别的小数。
以32位整数为例:假设仪表说明书表示“返回值为32位有符号整数,单位0.001mm(1μm)”,PLC读回的原始值如3264,代表3.264mm。PLC里需要使用32位数据寄存器组合(比如D100和D101配合),注意符号扩展——负数时高16位应为FFFF,否则正负号会丢失。如果是浮点格式,还要确认字节序(大端还是小端),并检查是否有“NaN”或“Infinity”等非法浮点值,程序里发现非法值应直接判定通信数据无效。
另外有些老式仪表返回的是BCD码,用PLC内置的BIN指令转成二进制数再参与运算,否则你对比上下限时算出来的数字会“看着对又完全不对”。这些转换逻辑建议封装成一个“数值标准化”功能块,输入原始寄存器数据,输出一个统一的32位浮点测量值(单位固定为mm),程序里所有比较和显示都用这个标准化结果。
6. 现场调试踩坑记录与最终运行参数
6.1 故障一:测微计读数偶发跳变,真凶是屏蔽层悬空
第一天上电测试时,空跑定位动作一切正常,但电机一开始运动,测微计读数就会出现偶发的跳变,有时一秒内从3.264mm跳到3.312mm再跳回来。最初怀疑是电机干扰电源,给PLC和仪表都加了滤波器也没用。
后来用示波器挂在485通信线上观察,发现电机启动瞬间A/B线波形出现明显毛刺,通信帧校验错误率升高。排查到通信线屏蔽层——现场看到屏蔽层两端都悬空没有接地,等于这根屏蔽线完全没用。把屏蔽层在PLC侧单点接地后,波形毛刺明显消失,读数稳定下来。
这里给所有做485通信调试的朋友一个建议:别把屏蔽层视为“可选项”,它和大地的连接是RS-485抗干扰的重要一环。标准做法是屏蔽层在总线主站侧单端接地,接地点离PLC电源地越近越好,并且避免形成接地环路。
6.2 故障二:定位过冲让测微计压到工件翻边
另一个挫败感很强的问题是:测微计偶尔会压到工件的翻边或毛刺,虽然设备有防撞机构,但测头是精密部件,这样折腾几次精度就让人不放心了。查程序发现定位完成后虽然等待了伺服驱动器到位信号,但稳定延时被我图省事设成了10ms,在高速模式下机械实际还有残留振动。
把稳定延时调整到120ms,并加了一个测微计下压到位信号作为最后互锁后,问题没有再出现。调试这类问题时,建议把延时参数放到触摸屏的“工艺调整页”上,让现场工程师可以根据不同产品重量、速度现场微调,而不需要改程序重新下载。
6.3 故障三:PLC发请求后从站完全无响应
还有一次是程序下载后通信完全没反应,串口调试助手直接抓PLC发出的报文也看不到数据。逐一排查后确定是485转换器端口插拔时把A/B接线弄反了。这听起来很基础,但越是低级错误越容易在现场忙乱时出现,而且如果不是用调试助手单测仪表,光看PLC程序很难定位。
通信无响应时的排查顺序,我总结为:先确认物理连接(A/B是否反、屏蔽层是否接、终端电阻是否在两端)、再用电脑串口助手直接发Modbus帧给仪表验证仪表本身是否正常、最后才回到PLC程序看轮询是否执行。按照这个顺序,大部分无响应问题可以在5分钟内定位。
6.4 稳定运行后的参数清单与个人习惯
设备稳定运行后,我把几组关键参数固化进了程序注释和交接文档:
| 项目 | 参数值 | 说明 |
|---|---|---|
| 测微计站号 | 1 | 可从面板修改 |
| 通信参数 | 9600/8/N/1 | 以仪表实际配置为准 |
| 轮询周期 | 50ms | 读取2个寄存器 |
| 通信超时 | 300ms | 单次请求超时 |
| 连续失败报警 | 3次 | 触发后锁停测量 |
| 读数滤波 | 5点平均 | 测量阶段处理 |
| 定位稳定延时 | 120ms | 根据负载现场调整 |
| 脉冲当量 | 0.00625mm/脉冲 | 丝杆导程/每转脉冲数 |
我个人在调试这类混合系统时还有个习惯:每一个功能块里都留一个“调试用强制标志”,可以让轴和通信分开测试。先把轴定位空跑顺了,再用串口调试助手把测微计一侧确认干净,最后合在一起联调,这样出问题只需要判断“是谁破坏了这个稳定状态”,而不是在混沌里瞎猜。
这类“轴定位+Modbus RTU测微计”的方案,做完后回头看,真正的难点其实不在PLC指令本身,而在于把机械参数换算清楚、把485物理层处理规矩、把状态机里的完成信号做扎实。这几件事做踏实,设备在现场就能省很多心。