欧姆龙PLC程序大型程序NJ系列 ST语言EtherCat总线控制24个伺服轴大型程序电池生产线 包括PLC NJ-1400和威纶通触摸屏程序 PLC通过EtherCat总线连接24个IS620N伺服 伺服轴已经写好FB块,可以直接复制粘贴 通过EtherCat连接6个扫描枪 扫描枪通讯已经写好FB块 通过EtherCat连接将近100个远程IO终端 详细IO表,中文详细注释,工艺,位置变量等详细说明
深夜的电池生产车间里,24台伺服电机在EtherCat总线的调度下同步运转,扫码枪的红光在流水线上此起彼伏。作为某新能源项目的主程,我叼着烟在NJ-1400的调试界面敲下第N版ST代码——这活儿真不是人干的。
伺服轴控制是重头戏。IS620N伺服参数配置模板我直接封装成FB块,ST语言里调用起来比梯形图爽快得多。比如这个轴控功能块:
FUNCTION_BLOCK AxisControl
VAR_INPUT
bEnable: BOOL; // 使能信号
fTargetPos: LREAL; // 目标位置(mm)
END_VAR
VAR_OUTPUT
bInPosition: BOOL; // 到位信号
fActualPos: LREAL; // 实际位置
END_VAR
VAR
tState: INT := 0; // 状态机
END_VAR
CASE tState OF
0: // 初始化
MC_Power(Axis:=axis1, Enable:=TRUE);
tState := 10;
10: // 定位
IF bEnable THEN
MC_MoveAbsolute(axis1, fTargetPos, 200.0, 1000.0);
tState := 20;
END_IF
20: // 等待到位
bInPosition := MC_ReadStatus(axis1).InPosition;
fActualPos := MC_ReadActualPosition(axis1);
IF NOT bEnable THEN tState := 0; END_IF
END_CASE
这状态机结构比传统自锁逻辑清晰多了。24个轴实例化时直接复制粘贴,改改axis1~axis24的变量名完事。注意EtherCat节点的PDO映射必须按拓扑顺序来,某个愣头青实习生曾经把第18轴的COE参数配到第17轴,导致整条线跳闸——那场面堪比烟花秀。
扫码枪通讯模块更刺激。6台扫码枪通过EtherCat转Profinet网关接入,数据采集FB里藏着这样的处理逻辑:
WHILE TRUE DO
FOR i:=1 TO 6 DO
IF scanGun[i].bNewData THEN
sBarcode := BYTETOSTRING(scanGun[i].Data);
欧姆龙PLC程序大型程序NJ系列 ST语言EtherCat总线控制24个伺服轴大型程序电池生产线 包括PLC NJ-1400和威纶通触摸屏程序 PLC通过EtherCat总线连接24个IS620N伺服 伺服轴已经写好FB块,可以直接复制粘贴 通过EtherCat连接6个扫描枪 扫描枪通讯已经写好FB块 通过EtherCat连接将近100个远程IO终端 详细IO表,中文详细注释,工艺,位置变量等详细说明
IF STRLEN(sBarcode) = 20 THEN // 验证条码长度
arrBarcodeQueue[i] := sBarcode;
scanGun[i].bAck := TRUE;
ELSE
AlarmLog(ERRINVALIDBARCODE);
END_IF
END_IF
END_FOR
DELAY 50; // 50ms轮询周期
END_WHILE
别小看这50ms延时,实测发现低于30ms会导致某些型号扫码枪通讯异常。现场还遇到过电磁干扰导致的数据位跳变,最后在EtherCat帧头加了CRC16校验才解决。
至于那100多个远程IO点,我的做法是把整个车间的设备按工艺段划分成多个IO_Group结构体:
TYPE IO_Group :
STRUCT
// 上料段
bConveyorRun : BOOL; // 输送带运行
bSafetyDoor : BOOL; // 安全门状态
// 注液段
fElectrolytePressure : REAL; // 电解液压力
bHeaterStatus : ARRAY[1..4] OF BOOL; // 加热管状态
// ...其他200+个信号
END_STRUCT
END_TYPE
调试时最怕遇到"幽灵信号",某个DI点突然自己抖起来。后来在程序里加了数字滤波才算消停:
FUNCTION DigitalFilter : BOOL
VAR_INPUT
bRawSignal : BOOL;
tDebounceTime : TIME := T#200ms;
END_VAR
VAR
tTimer : TON;
END_VAR
tTimer(IN:=bRawSignal, PT:=tDebounceTime);
DigitalFilter := tTimer.Q;
现在产线每小时吞吐量稳定在1200支电池,但想起当初调试时凌晨三点盯着EtherCat主站拓扑图抓狂的日子,还是忍不住把威纶通触摸屏的咖啡渍擦得更用力了些——鬼知道这些污渍里有多少是程序员的血泪。