为什么会写下这篇?摘要:8 月份旅游回来之后,这段时间我一直挺迷茫的。工作不忙了,我就自学起了 C++和 QT。寻思着反正也不太忙,就打算总结一下过去的经验,写一篇文章讲讲我对 PLC 以及 codesys 程序架构的理解。最初接触基恩士 KV7000 和台达的 EH、AS 系列 P
8 月份旅游回来之后,这段时间我一直挺迷茫的。工作不忙了,我就自学起了 C++和 QT。寻思着反正也不太忙,就打算总结一下过去的经验,写一篇文章讲讲我对 PLC 以及 codesys 程序架构的理解。最初接触基恩士 KV7000 和台达的 EH、AS 系列 PLC,后来 我能独当一面,用上了基于 codesys 的台达 AX8 和汇川的 AC800,这可是我八年多积累的经验。同行们,咱们可以一起探讨探讨。
开始思考对于一台或者一条自动化设备的程序来讲,基本上就是各种信号的相互交流,像传感器的输入、电磁阀的输出、伺服驱动器的输入输出以及收发信息、视觉控制器的信号对接,还有触摸屏的界面输入和显示。那要怎么把这些信息整合到一块儿,弄出能正常运行而且还挺完美的设备呢?以前刚从电工变成助理编程工程师的时候,我也一开始就在琢磨这样的问题。刚开始弄的那一两台设备还撞机了,现在回想起来,真是觉得挺不好意思的。从现在开始,我来和大家分享一下我的经验。
思路流程图一台设备从流程上可以分成初始化模块、手动模块、自动运行模块、异常处理模块、统计模块以及通讯模块。
初始化模块:
设备上电之后,要处理所有非保持变量,把所有非保持的变量复位到工程师依照设备运行状况设定的状态,简单说就是给所有非保持变量设定一个初始值。比如说,所有电磁阀的输出肯定是处于 OFF 状态,但要是机构有干涉,担心会撞机,那就可以用保持型的电磁阀,或者保持型的变量,来保持开机时的输出。
手动模块:
这里面包含了电磁阀、继电器、伺服步进、UV 控制器、点胶控制器、四轴运动控制卡。在非自动运行的情况下,可以通过外部按钮输入,还能通过人机界面来操纵设备的机构。比如说,在触摸屏上点击按钮,就能操作气缸进行伸缩,也能操作伺服轴进行点到点的运动,这样能方便调试人员去调整结构的位置。
以下是在codesys里面,电磁阀控制的模块的代码:
FUNCTION_BLOCK CylControlVAR_INPUT In : Cyl_In ; CylSection : INT ;//气缸模式选择 0:单线圈气缸 1:吸真空,破真空 2:继电器输出 3:双线圈保持型电磁阀 4:UV控制输出 5:双线圈中泄型电磁阀 6:针对夹爪气缸,空夹原限位亮和夹治具动限位亮 HideCylHomeSensor : BOOL ;//是否屏蔽气缸原限位 HideCylMotionSensor : BOOL ;//是否屏蔽气缸动限位 ChooseAlrm : BOOL ;//TRUE: UNAlarm FALSE:Alarm AutoHandMode : BOOL ;// 手自动切换选择 ClearAlarm : BOOL ;//解除报警 DelayAlarm : TIME ;//报警延时 EMGS : BOOL ;//急停 bCylMoveLimit : BOOL := TRUE ;// 气缸移动限制,为TRUE时可运行END_VARVAR_OUTPUT Out : Cyl_Out ;END_VARVAR tCylAlarm : ARRAY[0..6] OF TON ; tCylAlarmOK : BOOL ; CylGOTR : BOOL ;//气缸GOT控制上升沿 CylGOTF : BOOL ;//气缸GOT控制下降沿 CylGOTRb : BOOL ;//气缸GOT控制上升沿 CylGOTFb : BOOL ;//气缸GOT控制下降沿 tCylGOTRreset : TON ; tCylGOTFreset : TON ; tCylGOTRresetOK : BOOL ; tCylGOTFresetOK : BOOL ; R_TRIG : ARRAY[0..6] OF R_TRIG ;//上升沿保持 F_TRIG : ARRAY[0..6] OF F_TRIG ;//下降沿保持aEND_VARCASE CylSection OF 0,6: Out.CylA S= ((CylGOTR AND AutoHandMode) OR (In.CylPLCa AND NOT AutoHandMode AND NOT Out.CylAlarm AND EMGS)) AND bCylMoveLimit; //提取手动GOT的上升沿 R_TRIG[0](CLK:=In.CylGOTa,Q=>CylGOTR); //上升沿标志的自复位,目前发现会自复位 //tCylGOTRreset(IN:=CylGOTR,PT:=T#10000MS,Q=> tCylGOTRresetOK,ET=>); //CylGOTR R= tCylGOTRresetOK; Out.CylA R= ((CylGOTF AND AutoHandMode) OR (NOT In.CylPLCa AND NOT AutoHandMode AND NOT Out.CylAlarm AND EMGS)) AND bCylMoveLimit; //提取手动GOT的下降沿 F_TRIG[0](CLK:=In.CylGOTa,Q=>CylGOTF); //下降沿标志的自复位 //tCylGOTFreset(IN:=CylGOTF,PT:=T#10000MS,Q=> tCylGOTFresetOK,ET=>); //CylGOTF R= tCylGOTFresetOK; 1: Out.CylA S= (CylGOTR AND AutoHandMode) OR (In.CylPLCa AND NOT AutoHandMode ); R_TRIG[1](CLK:=In.CylGOTa,Q=>CylGOTR); Out.CylA R= (CylGOTF AND AutoHandMode) OR (NOT In.CylPLCa AND NOT AutoHandMode ); F_TRIG[1](CLK:=In.CylGOTa,Q=>CylGOTF); Out.CylB S= (CylGOTRb AND AutoHandMode) OR (In.CylPLCb AND NOT AutoHandMode ); R_TRIG[2](CLK:=In.CylGOTb,Q=>CylGOTRb); Out.CylB R= (CylGOTFb AND AutoHandMode) OR (NOT In.CylPLCb AND NOT AutoHandMode); F_TRIG[2](CLK:=In.CylGOTb,Q=>CylGOTFb); 2: Out.CylA S= (CylGOTR AND AutoHandMode) OR (In.CylPLCa AND NOT AutoHandMode ); R_TRIG[4](CLK:=In.CylGOTa,Q=>CylGOTR); Out.CylA R= (CylGOTF AND AutoHandMode) OR (NOT In.CylPLCa AND NOT AutoHandMode ); F_TRIG[4](CLK:=In.CylGOTa,Q=>CylGOTF); 3: Out.CylB S= (CylGOTR AND AutoHandMode) OR (In.CylPLCa AND NOT AutoHandMode AND NOT Out.CylAlarm AND EMGS); Out.CylA R= (CylGOTR AND AutoHandMode) OR (In.CylPLCa AND NOT AutoHandMode AND NOT Out.CylAlarm AND EMGS); R_TRIG[3](CLK:=In.CylGOTa,Q=>CylGOTR); Out.CylB R= (CylGOTF AND AutoHandMode) OR (NOT In.CylPLCa AND NOT AutoHandMode AND NOT Out.CylAlarm AND EMGS); Out.CylA S= (CylGOTF AND AutoHandMode) OR (NOT In.CylPLCa AND NOT AutoHandMode AND NOT Out.CylAlarm AND EMGS); F_TRIG[3](CLK:=In.CylGOTa,Q=>CylGOTF); 4: Out.CylA := (In.CylGOTa AND AutoHandMode) OR (In.CylPLCa AND NOT AutoHandMode ); 5: R_TRIG[5](CLK:=In.CylGOTa,Q=>CylGOTR); F_TRIG[5](CLK:=In.CylGOTa,Q=>CylGOTF); R_TRIG[6](CLK:=In.CylGOTb,Q=>CylGOTRb); F_TRIG[6](CLK:=In.CylGOTb,Q=>CylGOTFb); IF NOT In.CylPLCa AND NOT AutoHandMode THEN Out.CylA S= TRUE; END_IF IF In.CylPLCa AND NOT AutoHandMode THEN Out.CylA R= TRUE; END_IF IF F_TRIG[5].Q AND AutoHandMode THEN Out.CylA S= TRUE; END_IF IF R_TRIG[5].Q AND AutoHandMode THEN Out.CylA R= TRUE; END_IFEND_CASE(*****************气缸的报警的产生以及清除,还有是否屏蔽气缸的传感器CASE CylSection OF 0: tCylAlarm[0](IN:=(((Out.CylA AND NOT In.CylMotion) OR (NOT Out.CylA AND In.CylMotion)) AND NOT HideCylMotionSensor)OR(((NOT Out.CylA AND NOT In.CylHome)OR(Out.CylA AND In.CylHome))AND NOT HideCylHomeSensor),PT:=DelayAlarm,Q=> tCylAlarmOK,ET=>); 1:// 当破真空有反应,吸真空关闭和吸真空有感应,也不会报警 tCylAlarm[1](IN:=(Out.CylA AND NOT In.CylMotion)OR(NOT Out.CylA AND NOT Out.CylB AND In.CylMotion),PT:=DelayAlarm,Q=> tCylAlarmOK,ET=>); 3: tCylAlarm[2](IN:=((Out.CylB AND NOT In.CylMotion) AND NOT HideCylMotionSensor)OR((Out.CylA AND NOT In.CylHome)AND NOT HideCylHomeSensor),PT:=DelayAlarm,Q=> tCylAlarmOK,ET=>); 4: tCylAlarm[4](IN:=In.CylMotion,PT:=DelayAlarm,Q=> tCylAlarmOK,ET=>); 5: tCylAlarm[5](IN:=(Out.CylA AND (NOT In.CylHome OR In.CylMotion))OR(NOT Out.CylA AND (In.CylHome OR NOT In.CylMotion)),PT:=DelayAlarm,Q=> tCylAlarmOK,ET=>); 6: tCylAlarm[6](IN:=(Out.CylA AND In.CylMotion) OR (Out.CylA AND In.CylHome) OR(NOT Out.CylA AND NOT In.CylHome AND NOT In.CylMotion),PT:=DelayAlarm,Q=> tCylAlarmOK,ET=>);END_CASEOut.CylAlarm S= tCylAlarmOK AND NOT ChooseAlrm;Out.CylAlarm R= ClearAlarm;In.CylAutoRunningAlarm R= ClearAlarm;自动运行模块:
设备处于自动状态时,能够实现机械工程师和工艺工程师最初对设备的构想,生产出合格的产品,而且产能也能达到要求。这个模块只要按下启动按钮,在设备没有异常的情况下,就能进行自动化运行。这部分或许对于初学者来说是最难的了。
以下的代码是最新的自动线其中一个模块的自动化的程序:
程序急停后处理 IF NOT GVL.bEMGS THEN //模块状态的复位 Mode.AMacA3Mode.bIniting := FALSE; Mode.AMacA3Mode.bInitOK := FALSE; Mode.AMacA3Mode.bAlone := FALSE; Mode.AMacA3Mode.bAloneRunning := FALSE; Mode.AMacA3Mode.bAutoHandMode := FALSE; //自动运行标志的复位 bAMacA3ModeAuto := FALSE; //吸真空 破真空的关闭 //各模块信号对接的信号复位 //托盘当前数目的复位 //各程序控制流程标志的复位 Mode.AMacA3Mode.iInit := 0; Mode.AMacA3Mode.iAutoRunning[0] := 0; //停料标志的复位 END_IF 自动线可运动处理 Mode.AMacA3Mode.bAutoMacMoveSafe := NOT IOVar.Cyl_A3_Fixed.In.CylHome OR NOT IOVar.Cyl_A3_Rise.In.CylHome程序托盘处理程序单独运行处理 IF Mode.AMacA3Mode.bAlone THEN GVL.bAutoRunning R= TRUE; GVL.bAutoHandMode S= TRUE; Mode.AMacA3Mode.bUnAloneRunning R= TRUE; END_IF Mode.AMacA3Mode.bAloneRunning S= NOT Mode.AMacA3Mode.bAlarm AND GVL.bEMGS AND Mode.AMacA3Mode.bAlone AND NOT Mode.AMacA3Mode.bAutoHandMode AND Mode.AMacA3Mode.bInitOK AND Mode.AMacA3Mode.bGOTRunButton AND NOT GVL.bAutoRunning; Mode.AMacA3Mode.bAloneRunning R= Mode.AMacA3Mode.bAlarm OR NOT GVL.bEMGS OR NOT Mode.AMacA3Mode.bAlone OR Mode.AMacA3Mode.bAutoHandMode OR NOT Mode.AMacA3Mode.bInitOK OR Mode.AMacA3Mode.bGOTStopButton OR GVL.bAutoRunning程序非单独整机自动运行处理 // 自动运行处理 Mode.AMacA3Mode.bUnAloneRunning S= NOT GVL.bAutoHandMode AND NOT Mode.AMacA3Mode.bAlarm AND Mode.Line.bInitOK AND GVL.bRunButton AND NOT GVL.b_Tips_ModeInAlone; Mode.AMacA3Mode.bUnAloneRunning R= GVL.bAutoHandMode OR Mode.AMacA3Mode.bAlarm OR NOT Mode.Line.bInitOK OR GVL.bStopButton OR GVL.b_Tips_ModeInAlone 模块报警处理 Mode.AMacA3Mode.bAlarm := IOVar.Cyl_A3_Fixed.Out.CylAlarm OR IOVar.Cyl_A3_Rise.Out.CylAlarm OR GVL.b_Alarm_A3_HightNG 报警解除处理 GVL.b_Alarm_A3_HightNG R= GVL.bClearAlarm OR Mode.AMacA3Mode.bGOT_ClearAlarm调用节拍功能快 FBModeCycleTime(bCycleTime:= Mode.AMacA3Mode.bAutoMacTellModeStart, bAutoRunning:= bAMacA3ModeAuto, uiCycleTime=> Mode.AMacA3Mode.uiCycleTime当前模块自动运行处理 bAMacA3ModeAuto := (Mode.AMacA3Mode.bAlone AND Mode.AMacA3Mode.bAloneRunning ) OR (NOT Mode.AMacA3Mode.bAlone AND Mode.AMacA3Mode.bUnAloneRunningA机台A3模块延时处理 // 升降气缸压合治具到位后 TonDelay[0]( IN:=IOVar.Cyl_A3_Rise.Out.CylA AND IOVar.Cyl_A3_Rise.In.CylMotion, PT:=UINT_TO_TIME(PG.ui_A3_Mode_TiemDelay[0]) ); // 升降气缸压合治具到位后检测时长 TonDelay[1]( IN:=IOVar.Cyl_A3_Rise.Out.CylA AND IOVar.Cyl_A3_Rise.In.CylMotion, PT:=UINT_TO_TIME(PG.ui_A3_Mode_TiemDelay[1]) ); A机台A3模块复位流程 CASE Mode.AMacA3Mode.iInit OF 0: //单独运行的复位程序 IF Mode.AMacA3Mode.bGOTInit AND Mode.AMacA3Mode.bAlone AND NOT Mode.AMacA3Mode.bInitOK THEN Mode.AMacA3Mode.bIniting := TRUE; Mode.AMacA3Mode.bInitOK := FALSE; Mode.AMacA3Mode.iInit := SEL(Mode.AMacA3Mode.bAlone AND NOT Mode.AMacA3Mode.bAutoHandMode AND NOT Mode.AMacA3Mode.bAlarm,0,10); END_IF //整机运行的复位程序 IF GVL.bInitButton AND NOT Mode.AMacA3Mode.bInitOK THEN Mode.AMacA3Mode.bIniting := TRUE; Mode.AMacA3Mode.bInitOK := FALSE; Mode.AMacA3Mode.iInit := SEL(NOT GVL.bAutoHandMode AND NOT GVL.bAlarm,0,10); END_IF 10://定位气缸 升降气缸回原 Mode.AMacA3Mode.bIniting S= TRUE; IOVar.Cyl_A3_Fixed.In.CylPLCa R= TRUE; IOVar.Cyl_A3_Rise.In.CylPLCa R= TRUE; IF Mode.AMacA3Mode.bIniting AND NOT IOVar.Cyl_A3_Fixed.In.CylPLCa AND IOVar.Cyl_A3_Fixed.In.CylHome AND NOT IOVar.Cyl_A3_Rise.In.CylPLCa AND IOVar.Cyl_A3_Rise.In.CylHome THEN Mode.AMacA3Mode.iInit := SEL((Mode.AMacA3Mode.bAlone AND NOT Mode.AMacA3Mode.bAutoHandMode AND NOT Mode.AMacA3Mode.bAlarm)OR (NOT GVL.bAutoHandMode AND NOT GVL.bAlarm),10,100); END_IF 100://复位完成 Mode.AMacA3Mode.bIniting R= TRUE; Mode.AMacA3Mode.bInitOK S= TRUE; Mode.AMacA3Mode.iInit := 0; END_CASEA机台A3治具压合兼高度检测循环 CASE Mode.AMacA3Mode.iAutoRunning[0] OF 0:// 等待自动运行 Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,0,10); 10:// 等待主线体通知运行 IF Mode.AMacA3Mode.bAutoMacTellModeStart OR (Mode.AMacA3Mode.bGotSimulationTellModelStart AND Mode.AMacA3Mode.bAlone) THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,10,20); END_IF 20:// 空 Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,20,30); 30:// 判定治具左右穴是否有盆架 Mode.AMacA3Mode.bGotSimulationTellModelStart R= TRUE; // 单模块开启:单模块运行下,A3小车定位气缸动作 IF Mode.AMacA3Mode.bAlone THEN IOVar.Cyl_A3_Fixed.In.CylPLCa S= TRUE; IF IOVar.Cyl_A3_Fixed.In.CylPLCa AND IOVar.Cyl_A3_Fixed.In.CylMotion THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,30,40); END_IF END_IF // 单模块关闭: IF NOT Mode.AMacA3Mode.bAlone AND IOVar.Cyl_A3_Fixed.In.CylPLCa AND IOVar.Cyl_A3_Fixed.In.CylMotion THEN //模块开启运行,左右穴有盆架 IF PG.b_A3_ModeUse AND (Mode.AMacA3Mode.b_F4_Left_Frame_Have OR Mode.AMacA3Mode.b_F4_Right_Frame_Have) THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,30,40); END_IF //模块没有开启运行,左右穴没有盆架 IF NOT PG.b_A3_ModeUse OR (NOT Mode.AMacA3Mode.b_F4_Left_Frame_Have AND NOT Mode.AMacA3Mode.b_F4_Right_Frame_Have) THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,30,10000); END_IF END_IF 40:// 升降气缸下降 IOVar.Cyl_A3_Rise.In.CylPLCa S= IOVar.Cyl_A3_Rise.In.CylHome; IF IOVar.Cyl_A3_Rise.In.CylPLCa AND IOVar.Cyl_A3_Rise.In.CylMotion AND TonDelay[0].Q THEN // 不是单模块单独运行,则不需要进行高度的判定 IF NOT Mode.AMacA3Mode.bAlone THEN // 使用高度检测 IF PG.b_A3_Mode_High_Use THEN // 高度检测NG,报警 IF NOT IOVar.Sensor_A3_High THEN GVL.b_Alarm_A3_HightNG S= TRUE; END_IF // 检测高度在设定检测时间内合格 IF IOVar.Sensor_A3_High AND TonDelay[1].Q THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,40,50); END_IF END_IF // 不使用高度检测 IF NOT PG.b_A3_Mode_High_Use THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,40,50); END_IF END_IF //单模块单独运行开启 IF Mode.AMacA3Mode.bAlone THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,40,50); END_IF END_IF 50:// 升降气缸缩回 IOVar.Cyl_A3_Rise.In.CylPLCa R= TRUE; IF NOT IOVar.Cyl_A3_Rise.In.CylPLCa AND IOVar.Cyl_A3_Rise.In.CylHome THEN Mode.AMacA3Mode.iAutoRunning[0]:=SEL(bAMacA3ModeAuto,50,60); END_IF 60:// 是否单机运行? // 是单机运行 IF Mode.AMacA3Mode.bAlone THEN IOVar.Cyl_A3_Fixed.In.CylPLCa R= TRUE; IF NOT IOVar.Cyl_A3_Fixed.In.CylPLCa AND IOVar.Cyl_A3_Fixed.In.CylHome THEN Mode.AMacA3Mode.iAutoRunning[0]:=0; END_IF END_IF // 非单机运行,通知主线放治具完成 IF NOT Mode.AMacA3Mode.bAlone THEN Mode.AMacA3Mode.bModeTellAutoMacDone S= TRUE; IF Mode.AMacA3Mode.bModeTellAutoMacDone AND NOT Mode.AMacA3Mode.bAutoMacTellModeStart THEN Mode.AMacA3Mode.iAutoRunning[0]:=70; END_IF END_IF 70:// 信号处理 Mode.AMacA3Mode.bModeTellAutoMacDone R= TRUE; IF NOT Mode.AMacA3Mode.bModeTellAutoMacDone THEN Mode.AMacA3Mode.iAutoRunning[0]:=0; END_IF 10000:// 通知主线此岗位没有开启运行,左右穴没有盆架 Mode.AMacA3Mode.bModeTellAutoMacDone S= TRUE; IF Mode.AMacA3Mode.bModeTellAutoMacDone AND NOT Mode.AMacA3Mode.bAutoMacTellModeStart THEN Mode.AMacA3Mode.iAutoRunning[0]:=10010; END_IF 10010:// 信号处理 Mode.AMacA3Mode.bModeTellAutoMacDone R= TRUE; IF NOT Mode.AMacA3Mode.bModeTellAutoMacDone THEN Mode.AMacA3Mode.iAutoRunning[0]:=0; END_IF END_CASE异常处理模块:
当设备出现这样的情况:电磁阀已经动作了,但是气缸却没有到达动限位,这部分会有一个报警延时。当报警延时结束后,首先设备得切换成手动状态,然后在触摸屏上会有个提醒,这时三色灯的红色灯就得亮起。当操机人员在手动状态下处理完异常后,就能够进入自动运行状态。
统计模块:
就是在生产过程中,对物料的投入、损耗和产出做一个统计。这样能方便对产线进行每小时的监控,从大概的方向排查不良情况。
通讯模块:
其实有一个模块,它可以包含在手动模块和自动模块之中,这个模块包括了提供网口、串口、IO 口用于外接设备的通讯,这样能方便我们使用和控制。
PLC程序架构(基于codesys st编写) PLC论坛-全力打造可编程控制器专业技术论坛 -
#codesys#
来源:PLC技术玩一点号