DUTs ---- E_GasType ^^^^^^^^^ :: TYPE E_GasType : ( none := 0, Neon, Argon, Krypton, Xenon ); END_TYPE E_HomeState ^^^^^^^^^^^ :: TYPE E_HomeState : ( H_READY, H_INIT, H_RESET_LL, H_RESET_HL, H_ENABLE, H_MOVING, H_MOVING2, H_CHECK, H_RESET, H_SET_POS, H_ERROR, H_WRITE_LL, H_WRITE_HL, H_DONE ) UDINT; END_TYPE E_MoveState ^^^^^^^^^^^ :: TYPE E_MoveState : ( ABORT, INIT, ENABLE, FORWARD, BACKWARDS, READY, MOVING, NEWTARGETPOSITION, NEWTARGETPOSITION2, ERROR, RESET, HALT, HOME ) UDINT; END_TYPE ST_HV ^^^^^ :: TYPE ST_HV : STRUCT {attribute 'pytmc' := ' pv: HV_SW; io: io; '} HV_sw: BOOL:=True; // EPICS control for switching the HV on or off. {attribute 'pytmc' := ' pv: HV_DO; io: i; '} q_HV_DO: BOOL; // Readout of the HV's ouput value {attribute 'pytmc' := ' pv: ILK_OK; io: i; '} xIlkOK : BOOL := FALSE; // Interlock Bit {attribute 'pytmc' := ' pv: PRO_SP; io: io; '} rPRO_SP: REAL := 0.0001; // Pressure below which the HV signal may turn o END_STRUCT END_TYPE ST_VGP ^^^^^^ :: TYPE ST_VGP : STRUCT {attribute 'pytmc' := ' pv: POS_RBV; io: i; '} // Inputs i_iPosition : REAL; //Encoder position readback (if it exists) {attribute 'pytmc' := ' pv: ENC_RBV; io: i; '} // Inputs rEnoder_Position : REAL; //Encoder position readback (if it exists) {attribute 'pytmc' := ' pv: ERROR; field: ZNAM FALSE; field: ONAM TRUE; io: i; '} // Inputs pv_xError : BOOL; {attribute 'pytmc' := ' pv: IS_HOMED; field: ZNAM FALSE; field: ONAM TRUE; io: i; '} // Inputs pv_xHomed : BOOL :=false; //Softvariables {attribute 'pytmc' := ' pv: ILK_OK; field: ZNAM FALSE; field: ONAM TRUE; io: i; '} xIlkOK : BOOL := FALSE; // Interlock Bit //Manually Pressing valve "Open/Close" on EDM {attribute 'pytmc' := ' pv: OPN_SW; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} pv_xOPN_SW : BOOL; {attribute 'pytmc' := ' pv: GO_SW; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} pv_xGo_SW : BOOL; {attribute 'pytmc' := ' pv: HOME_SW; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} pv_xHome_SW : BOOL; {attribute 'pytmc' := ' pv: Reset_SW; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} pv_xReset_SW : BOOL; {attribute 'pytmc' := ' pv: Busy; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} xBusy : BOOL; {attribute 'pytmc' := ' pv: ABORT; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} pv_xABORT_SW : BOOL; {attribute 'pytmc' := ' pv: POS_CTRL; io: io; '} rReqPosition : REAL; // Outputs {attribute 'pytmc' := ' pv: POS_DES; io: io; '} q_iRawPosition : INT; //Position control {attribute 'pytmc' := ' pv: STATE; type: mbbi ; field: ZRST CLOSE ; field: ONST OPEN; field: TWST PRESS CNTRL; field: THST MANUAL CNTRL ; io: io; '} eValveControl : E_VCN := CloseValve; // Valve control state /// state machine state {attribute 'pytmc' := ' pv: Axis_STATE; io: io; '} eState: E_MoveState; //Axis Move state ftIlk : F_TRIG; {attribute 'pytmc' := ' pv: ERR_ID; io: i; '} nErrorID: UDINT; {attribute 'pytmc' := ' pv: ERR_MSG; io: i; '} sErrorMessage : STRING; END_STRUCT END_TYPE GVLs ---- GVL_Devices ^^^^^^^^^^^ :: VAR_GLOBAL {attribute 'pytmc' :=' pv: EM2K0:XGMD:OVERRIDE_INJ '} xOverrideMode : BOOL:= false; {attribute 'pytmc' :=' pv: EM2K0:XGMD:GHC:50 '} GHC_50 : FB_ITR90; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VCN:50 '} VCN_50 : FB_VCN; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VGP:50 '} VGP_50 : FB_VGP; {attribute 'pytmc' :=' pv: EM2K0:XGMD:GCM:80 '} GCM_80 : FB_GCM; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:80 '} VVC_80:FB_VVC; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:81 '} VVC_81:FB_VVC; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:82 '} VVC_82:FB_VVC; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:83 '} VVC_83 : FB_VVC; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:84 '} VVC_84 : FB_VVC; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:85 '} VVC_85 : FB_VVC; {attribute 'pytmc' :=' pv: EM2K0:XGMD:VVC:86 '} VVC_86 : FB_VVC; (* Pressure Control*) {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCP:50 '} GCP: ST_VG; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:SP; field: HOPR 1000; field: LOPR 0; field: PREC 2; field: EGU "TORR"; '} fSetpointValue :REAL; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:GO; field: ZNAM STOP; field: ONAM START; io: io; '} bGo: BOOL; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:RESET; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} bReset : BOOL; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:ERROR; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} bError : BOOL; {attribute 'pytmc' :=' pv: EM2K0:XGMDCNTRL:Kp1 '} fKp1 : REAL:= 0.5; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:Tn1 '} fTn1 : REAL:= 0.5; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:Kp2 '} fKp2 : REAL:= 0.01; {attribute 'pytmc' :=' pv: EM2K0:XGMD:CNTRL:Tn2 '} fTn2 : REAL:= 0.5; (*Additional VCN Interlock*) {attribute 'pytmc' :=' pv: EM2K0:XGMD:VCN_ILK; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} bAdditionalVCNIlk : BOOL:=TRUE; (*HV*) {attribute 'pytmc' :=' pv: EM2K0:XGMD:PSV:1 '} hv1 : FB_HighVoltage; //{attribute 'pytmc' :=' pv: EM2K0:XGMD:PSV '} //hv2 : FB_HighVoltage; (*RTD*) {attribute 'pytmc' :=' pv: EM2K0:XGMD:RTD:1 '} {attribute 'TcLinkTo' := '.iRaw := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Value; .bError := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Status^Error; .bUnderrange := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Status^Underrange; .bOverrange := TIIB[EL3202_03_08]^RTD Inputs Channel 1^Status^Overrange'} RTD_1 : FB_TempSensor; {attribute 'pytmc' :=' pv: EM2K0:XGMD:RTD:2 '} {attribute 'TcLinkTo' := '.iRaw := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Value; .bError := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Status^Error; .bUnderrange := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Status^Underrange; .bOverrange := TIIB[EL3202_03_08]^RTD Inputs Channel 2^Status^Overrange'} RTD_2 : FB_TempSensor; END_VAR GVL_GMD ^^^^^^^ :: VAR_GLOBAL // FB_MKS317 {attribute 'pytmc' := ' pv: EM2K0:XGMD:GPI:10 '} fb_EM2K0_XGMD_GPI_10 : FB_MKS317; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GPI:50 '} fb_EM2K0_XGMD_GPI_50 : FB_MKS317; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GPI:90 '} fb_EM2K0_XGMD_GPI_90 : FB_MKS317; // FB_PTM_TwisTorr {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:10 '} fb_EM2K0_XGMD_PTM_10 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:20 '} fb_EM2K0_XGMD_PTM_20 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:30 '} fb_EM2K0_XGMD_PTM_30 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:40 '} fb_EM2K0_XGMD_PTM_40 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:50 '} fb_EM2K0_XGMD_PTM_50 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:60 '} fb_EM2K0_XGMD_PTM_60 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:70 '} fb_EM2K0_XGMD_PTM_70 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:80 '} fb_EM2K0_XGMD_PTM_80 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PTM:90 '} fb_EM2K0_XGMD_PTM_90 : FB_PTM_TwisTorr; // FB_VRC {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:10 '} fb_EM2K0_XGMD_VRC_10 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:20 '} fb_EM2K0_XGMD_VRC_20 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:30 '} fb_EM2K0_XGMD_VRC_30 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:40 '} fb_EM2K0_XGMD_VRC_40 : FB_VRC; //{attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:50 '} //fb_EM2K0_XGMD_VRC_50 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:60 '} fb_EM2K0_XGMD_VRC_60 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:70 '} fb_EM2K0_XGMD_VRC_70 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:80 '} fb_EM2K0_XGMD_VRC_80 : FB_VRC; {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRC:90 '} fb_EM2K0_XGMD_VRC_90 : FB_VRC; // FB_MKS422 {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:10 '} fb_EM2K0_XGMD_GCC_10 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:20 '} fb_EM2K0_XGMD_GCC_20 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:30 '} fb_EM2K0_XGMD_GCC_30 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:40 '} fb_EM2K0_XGMD_GCC_40 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:50 '} fb_EM2K0_XGMD_GCC_50 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:60 '} fb_EM2K0_XGMD_GCC_60 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:70 '} fb_EM2K0_XGMD_GCC_70 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:80 '} fb_EM2K0_XGMD_GCC_80 : FB_MKS422; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GCC:90 '} fb_EM2K0_XGMD_GCC_90 : FB_MKS422; // FB_EbaraEVA {attribute 'pytmc' := ' pv: EM2K0:XGMD:PRT:50 '} fb_EM2K0_XGMD_PRT_50 : FB_EbaraEVA; // FB_VVC {attribute 'pytmc' := ' pv: EM2K0:XGMD:VVC:50 '} fb_EM2K0_XGMD_VVC_50 : FB_VVC; //Roughing DC Valves {attribute 'pytmc' := ' pv: EM2K0:XGMD:VRO:50 '} {attribute 'TcLinkTo' := '.q_xOPN_DO := TIIB[EL2212_02_19]^DOX Control Channel 2^Control^Output'} fb_EM1K0_GMD_VRO_50 : FB_VVC; END_VAR GVL_VAC_INTF ^^^^^^^^^^^^ :: VAR_GLOBAL ads_watch_dog : FB_ADS_WATCHDOG; END_VAR GVL_VARIABLES ^^^^^^^^^^^^^ :: VAR_GLOBAL {attribute 'pytmc' :=' pv: EM2K0:XGMD:OVERRIDE_VAC '} xSystemOverrideMode : BOOL; (* Global system override for the prototype section*) {attribute 'pytmc' :=' pv: EM2K0:XGMD:AUTO_VVC_50 '} bAutoVVC50 : BOOL := TRUE; // Purge COMMANDS FROM epics //pragma {attribute 'pytmc' :=' pv: EM2K0:XGMD:Purge_SW'} bStartPurge_sw : BOOL :=false; {attribute 'pytmc' :=' pv: EM2K0:XGMD:Purge_Active'} bPurgeActive : BOOL:=false; {attribute 'pytmc' :=' pv: EM2K0:XGMD:PurgeDone'} bPurgeDone : BOOL :=false; {attribute 'pytmc' := ' pv: EM2K0:XGMD:GAS_TYPE ; type: mbbi ; field: ZRST none ; field: ONST Neon; field: TWST Argon ; field: THST Krypton ; field: FRST Xenon ; io: i '} SelectedGas: E_GasType; END_VAR POUs ---- F_HV_ILK ^^^^^^^^ :: FUNCTION F_HV_ILK : BOOL VAR_INPUT IG : ST_VG; // Gauge used for interlocking the high voltage supply HV : ST_HV; // Structure representing HV control END_VAR VAR END_VAR F_HV_ILK := ((IG.xPRESS_OK = TRUE) AND (IG.rPRESS < HV.rPRO_SP)); END_FUNCTION F_TURBO_PROT_SLND_ILK ^^^^^^^^^^^^^^^^^^^^^ :: (* Interlock function for solenoid valve located behind the central turbo pump. *) FUNCTION F_TURBO_PROT_SLND_ILK : BOOL VAR_INPUT i_Turbo : ST_PTM; // Turbo Pump i_stISG : ST_VG; //Gauge measuring inlet Pressure e.g Pirani i_stBSG : ST_VG; //Gauge measuring backing Pressure e.g Pirani ScrollPump : ST_RoughPump; // Roughing pump END_VAR VAR END_VAR F_TURBO_PROT_SLND_ILK := (i_stISG.xPRESS_OK AND i_stISG.rPRESS < i_Turbo.rInletPressureSP) AND (i_stBSG.xPRESS_OK AND i_stBSG.rPRESS < i_Turbo.rBackingPressureSP) AND (ScrollPump.eState = pumpRUNNING) AND (i_Turbo.eState = pumpRUNNING); END_FUNCTION F_TurboGateValve_Protection_ILK_local ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: (* This Function Block evaluates the ILK condition of the Turbo Gate valve *) (* The logic Protects the Turbo pump from inlet pressure above the SP*) (* And Protects the Turbo pump from backing pressure above the SP*) (* And Protects the Turbo pump in the case of backing pump not running*) (* This is to be used whle the vacuum library has not yet updated to watch for the pumpRUNNING state. Switch to the vacuum library's version at earliest convenience. *) FUNCTION F_TurboGateValve_Protection_ILK_local : BOOL(* function return TRUE when ILK is OK*) VAR_INPUT i_Turbo : ST_PTM; // Turbo Pump i_stISG : ST_VG; //Gauge measuring inlet Pressure e.g Pirani i_stBSG : ST_VG; //Gauge measuring backing Pressure e.g Pirani ScrollPump : ST_RoughPump; // Roughing pump END_VAR VAR END_VAR (* This Function Block evaluates the ILK condition of the Turbo Gate valve *) (* The logic Protects the Turbo pump from inlet pressure above the SP*) F_TurboGateValve_Protection_ILK_local := (i_Turbo.eState = pumpRUNNING) AND (i_stISG.xPRESS_OK AND i_stISG.rPRESS < i_Turbo.rInletPressureSP) AND (i_stBSG.xPRESS_OK AND i_stBSG.rPRESS < i_Turbo.rBackingPressureSP) AND (ScrollPump.eState = pumpRUNNING); END_FUNCTION FB_HighVoltage ^^^^^^^^^^^^^^ :: FUNCTION_BLOCK FB_HighVoltage VAR_INPUT i_xExtIlkOK : BOOL; //External Interlock, SET to TRUE if not used END_VAR VAR_OUTPUT {attribute 'pytmc' := ' pv: '} hv:ST_HV; END_VAR VAR (*outputs*) q_HV_DO AT %Q*: BOOL; END_VAR hv.xIlkOK := i_xExtIlkOK; q_HV_DO := hv.HV_sw AND hv.xIlkOK; (*soft io mapping*) hv.q_HV_DO := q_HV_DO; END_FUNCTION_BLOCK FB_VGP ^^^^^^ :: (* This function implements the Basic functions for the Vat Motorized valve*) {attribute 'no_check'} FUNCTION_BLOCK FB_VGP VAR_INPUT i_xExtIlkOK : BOOL; //External Interlock, SET to TRUE if not used i_xOpenIlkOK: BOOL; //Interlock Bit that allows the valve to open i_xCloseIlkOK: BOOL; //Interlock Bit that allows the valve to Close i_ReqPos : REAL; //Requested position arrTable : ARRAY[1..14,1..2] OF FLOAT; END_VAR VAR_OUTPUT {attribute 'pytmc' := ' pv: '} q_stVGP : ST_VGP; // valve structure END_VAR VAR_IN_OUT END_VAR VAR CONSTANT rUpperLimit : REAL:=100; //Percentage Upper limit on valve open rClosePosition : REAL:=0; // Encoder Min. Fully Closed rMaxDiffPressure: REAL:= 22.5; //Torr END_VAR VAR rOpenPosition: REAL:=1660; // Encoder MAX. Fully Open rTargetPosition : REAL; rTargetVelocity: REAL:=30; rHomingVelocity: REAL:=10; rHomingDistance: REAL:=-20;//every 150 is 10% , 1% is 14.975 rOldTargetPosition: REAL; rHyst:REAL :=10; // /// axis reference data structure Axis: AXIS_REF; // InfoData_State AT %I*: UINT ; // Axis MC functions fbPowerAxis: MC_Power; /// debug function block output data PowerAxisOut: ST_McOutputs; fbMoveAxisABS: MC_MoveAbsolute; /// debug function block output data MoveAbsoluteOut: ST_McOutputs; fbMoveAxisABS2: MC_MoveAbsolute; /// debug function block output data MoveAbsoluteOut2: ST_McOutputs; fbReset: MC_Reset; /// debug function block output data ResetOut: ST_McOutputs; MoveAxisREL: MC_MoveAbsolute; MoveRelativeOut: ST_McOutputs; rOverride: LREAL := 100; fbHalt: MC_Halt; // Homing Functions bGo:BOOL := FALSE; //to execute motion bHome:BOOL :=FALSE; // should be set to true bEnable:Bool; //to be removed fbMoveRel: MC_MoveRelative; fbSetPosition: MC_SetPosition; fbWriteParameter: MC_WriteBoolParameter; HomeState: E_HomeState; // For Monitoring while Axis moving rPrevEncoderPosition : REAL; // interpolation bInit : BOOL := TRUE; eMode : E_CTRL_MODE; iCounter:INT; //CONTROL stCTRL_LIN_INTERPOLATION_PARAMS : ST_CTRL_LIN_INTERPOLATION_PARAMS; fbCTRL_LIN_INTERPOLATION : FB_CTRL_LIN_INTERPOLATION; arrTable_ENC : ARRAY[1..14,1..2] OF FLOAT; //Readdback stCTRL_LIN_INTERPOLATION_PARAMS_ENC : ST_CTRL_LIN_INTERPOLATION_PARAMS; fbCTRL_LIN_INTERPOLATION_ENC : FB_CTRL_LIN_INTERPOLATION; // Logger // For logging fbLogger : FB_LogMessage := (eSubsystem:=E_SubSystem.VACUUM); ePrevState : E_VCN; tErrorPresent : R_TRIG; tAction : R_TRIG; // Primary action of this device (OPN_DO, PUMP_RUN, etc.) rt_close :R_TRIG; rt_Open :R_TRIG; END_VAR /// Interpolation function initialization ACT_INIT(); // Interlocking q_stVGP.xIlkOK := i_xExtIlkOK; (*Checking which Control mode is selected*) IF i_xExtIlkOK AND NOT (q_stVGP.pv_xError) THEN IF q_stVGP.eValveControl = OpenValve THEN q_stVGP.rReqPosition := rUpperLimit; ELSIF q_stVGP.eValveControl = CloseValve THEN q_stVGP.rReqPosition := 0; ELSIF q_stVGP.eValveControl = ManualControl THEN q_stVGP.rReqPosition := LIMIT(0, q_stVGP.rReqPosition, rUpperLimit); ELSIF q_stVGP.eValveControl = PressureControl THEN q_stVGP.rReqPosition := LIMIT(0, i_ReqPos, rUpperLimit); END_IF ELSIF NOT i_xExtIlkOK THEN q_stVGP.rReqPosition := 0; q_stVGP.eValveControl := CloseValve;//CloseValve; END_IF rt_close (CLK:= q_stVGP.eValveControl = CloseValve); rt_Open (CLK:= q_stVGP.eValveControl = OpenValve); IF (rt_close.Q) OR (rt_Open.Q) THEN q_stVGP.pv_xGo_SW:=TRUE; END_IF //Check the Drive State IF (*(InfoData_State<>16#8) OR*) (q_stVGP.eState = ERROR) THEN q_stVGP.pv_xError:=TRUE; ELSE q_stVGP.pv_xError:=FALSE; // Call function to execute move // call motion function blocks??? END_IF IF (q_stVGP.pv_xABORT_SW ) THEN q_stVGP.pv_xABORT_SW := FALSE; q_stVGP.eState:= ABORT; HomeState:= H_READY; END_IF ACT_LIN_INTERPOLATION(); ACT_AXIS(); ACT_HOME(); ACT_MONITOR(); END_FUNCTION_BLOCK ACTION ACT_AXIS: //update the axis status AXIS(); q_stVGP.rEnoder_Position := LREAL_TO_REAL(Axis.NcToPlc.ActPos); // encoder position (* IF NOT (i_xExtIlkOK) THEN q_stVGP.eState := NEWTARGETPOSITION; END_IF*) //Homing STATE is missing // state machine for axis motion (* move axis using a state machine *) CASE q_stVGP.eState OF INIT : (* initialisation *) (* initialize all function blocks *) fbMoveAxisABS.Execute := FALSE; fbMoveAxisABS2.Execute := FALSE; fbReset.Execute := FALSE; fbHALT.Execute :=FALSE;// q_stVGP.eState := ENABLE; // Check homing first HomeState:= H_READY; ENABLE : fbPowerAxis.Enable := TRUE; fbPowerAxis.Enable_Positive := TRUE; fbPowerAxis.Enable_Negative := TRUE; IF fbPowerAxis.Status THEN q_stVGP.eState := READY; ELSIF fbPowerAxis.Error THEN q_stVGP.eState := ERROR; END_IF READY: // waiting for move command IF NOT fbPowerAxis.Status THEN q_stVGP.eState := ENABLE; ELSIF fbPowerAxis.Error THEN q_stVGP.eState := ERROR; END_IF IF (HomeState = H_READY) AND (q_stVGP.pv_xHome_SW) THEN HomeState:= H_INIT; q_stVGP.pv_xHome_SW:=false; q_stVGP.eState := HOME; ELSE q_stVGP.eState := READY; END_IF IF (q_stVGP.pv_xGo_SW) AND q_stVGP.pv_xHomed(* AND( rOldTargetPosition <> rTargetPosition) *) THEN q_stVGP.pv_xGo_SW := false; q_stVGP.eState := NEWTARGETPOSITION; rOldTargetPosition := rTargetPosition; END_IF HOME: if (HomeState = H_DONE) THEN q_stVGP.eState := INIT; q_stVGP.pv_xHomed := TRUE; HomeState := H_READY; END_IF if (HomeState = H_ERROR) THEN q_stVGP.eState := ERROR; q_stVGP.pv_xHomed := FALSE; END_IF NEWTARGETPOSITION: fbMoveAxisABS.Position := rTargetPosition; fbMoveAxisABS.Velocity := rTargetVelocity; //fbMoveAxisABS.BufferMode := MC_BlendingNext; fbMoveAxisABS.Execute := TRUE; IF fbMoveAxisABS.Active THEN (* axis is executing job but is not yet finished *) fbMoveAxisABS.Execute := FALSE; (* leave this state and buffer a second command *) q_stVGP.eState := MOVING; ElSIF fbMoveAxisABS.Done THEN fbMoveAxisABS.Execute := FALSE; q_stVGP.eState := READY; ELSIF fbMoveAxisABS.CommandAborted OR fbMoveAxisABS.Error THEN q_stVGP.eState := ERROR; END_IF MOVING:// IF fbMoveAxisABS.CommandAborted OR fbMoveAxisABS.Error THEN q_stVGP.eState := ERROR; END_IF IF NOT ( Axis.Status.Moving) OR (fbMoveAxisABS.Done) THEN //(fbMoveAxisABS.Done) AND (fbMoveAxisABS2.Done) THEN q_stVGP.eState := READY; END_IF HALT: fbHALT.Execute :=TRUE; IF Axis.Status.Error THEN q_stVGP.eState := RESET; (* axis error requires reset *) ELSE q_stVGP.eState := INIT; (* function block errors don't need a reset *) END_IF ERROR : IF HomeState = H_READY THEN q_stVGP.eState := RESET; ELSE q_stVGP.eState := HOME; END_IF RESET : //fbReset.Execute := TRUE; IF fbReset.Done THEN q_stVGP.eState :=INIT; // HomeState := H_READY; ELSIF fbReset.Error THEN q_stVGP.eState := ERROR; (* keep trying to reset*) END_IF ABORT: fbMoveAxisABS.Execute := FALSE; fbMoveAxisABS2.Execute := FALSE; fbReset.Execute := FALSE; (* save target position*) rOldTargetPosition := q_stVGP.i_iPosition; fbHALT.Execute :=FALSE; fbPowerAxis.Enable := FALSE; fbPowerAxis.Enable_Positive := FALSE; fbPowerAxis.Enable_Negative := FALSE; q_stVGP.eState := ENABLE; // Check homing first END_CASE /// Motion Function Blocks (* AXIS POWER*) fbPowerAxis( Axis:= Axis, Enable:= , Enable_Positive:= i_xOpenIlkOK, Enable_Negative:= , Override:= rOverride, BufferMode:= , Options:= , Status=> , Busy=> PowerAxisOut.Busy , Active=> PowerAxisOut.Active , Error=> PowerAxisOut.Error, ErrorID=> PowerAxisOut.ErrorID); (* AXIS MOVE ABSOLUTE*) fbMoveAxisABS( Axis:= Axis , Execute:= , Position:= , Velocity:= , Acceleration:= , Deceleration:= , Jerk:= , BufferMode:= MC_BlendingNext , Options:= , Done=>MoveAbsoluteOut.Done, Busy=> MoveAbsoluteOut.Busy, Active=> MoveAbsoluteOut.Active, CommandAborted=> MoveAbsoluteOut.CommandAborted , Error=> MoveAbsoluteOut.Error, ErrorID=> MoveAbsoluteOut.ErrorID); (* AXIS MOVE ABSOLUTE*) fbMoveAxisABS2( Axis:= Axis , Execute:= , Position:= , Velocity:= , Acceleration:= , Deceleration:= , Jerk:= , BufferMode:= MC_BlendingNext , Options:= , Done=>MoveAbsoluteOut2.Done, Busy=> MoveAbsoluteOut2.Busy, Active=> MoveAbsoluteOut2.Active, CommandAborted=> MoveAbsoluteOut2.CommandAborted , Error=> MoveAbsoluteOut2.Error, ErrorID=> MoveAbsoluteOut2.ErrorID); (*AXIS RESET*) fbReset( Axis:= Axis, Execute:= This^.q_stVGP.pv_xReset_SW , Done=>ResetOut.Done , Busy=>ResetOut.Busy , Error=> ResetOut.Error, ErrorID=> ResetOut.ErrorID); (*HALT*) fbHalt( Axis:= Axis, Execute:= , Deceleration:= , Jerk:= , BufferMode:= MC_BlendingNext , Options:= , Done=> , Busy=> , Active=> , CommandAborted=> , Error=> , ErrorID=> ); /// ERROR IF Axis.Status.Error THEN q_stVGP.eState := ERROR; END_IF; // Error Handling if( fbPowerAxis.Error and fbPowerAxis.Active ) then This^.q_stVGP.pv_xError:= fbPowerAxis.Error; This^.q_stVGP.nErrorID:= fbPowerAxis.ErrorID; END_IF if( fbMoveAxisABS.Error and fbMoveAxisABS.Active ) then This^.q_stVGP.pv_xError:= fbMoveAxisABS.Error; This^.q_stVGP.nErrorID:= fbMoveAxisABS.ErrorID; END_IF IF This^.q_stVGP.pv_xReset_SW THEN This^.q_stVGP.pv_xReset_SW:=FALSE; END_IF (*Convert nErrorID to string*) This^.q_stVGP.sErrorMessage:=WORD_TO_HEXSTR(in:=TO_WORD(This^.q_stVGP.nErrorID) , iPrecision:= 4, bLoCase:=0 ); This^.q_stVGP.xBusy := (NOT(q_stVGP.eState = READY) AND (HomeState = H_READY)); END_ACTION ACTION ACT_HOME: CASE HomeState OF H_READY: fbSetPosition.Execute := FALSE; fbWriteParameter.Execute := FALSE; fbMoveRel.Execute := FALSE; H_INIT: HomeState:=H_RESET_LL; H_RESET_LL: // disable soft limits in order to be able to move the drive fbWriteParameter.ParameterNumber := MC_AxisParameter.EnableLimitNeg;//EnableLimitPos;// .EnableLimitNeg; fbWriteParameter.Value := FALSE; fbWriteParameter.Execute := TRUE; if (fbWriteParameter.Done) THEN fbWriteParameter.Execute := FALSE; HomeState:= H_RESET_HL; END_IF H_RESET_HL: // disable soft limits in order to be able to move the drive fbWriteParameter.ParameterNumber := MC_AxisParameter.EnableLimitPos; fbWriteParameter.Value := FALSE; fbWriteParameter.Execute := TRUE; if (fbWriteParameter.Done) THEN fbWriteParameter.Execute := FALSE; HomeState:= H_ENABLE; END_IF H_ENABLE: // Make Sure drive is enabled fbPowerAxis.Enable := TRUE; fbPowerAxis.Enable_Positive := TRUE; fbPowerAxis.Enable_Negative := TRUE; IF fbPowerAxis.Status THEN HomeState:= H_MOVING; ELSIF fbPowerAxis.Error THEN HomeState := H_ERROR; END_IF H_MOVING: fbMoveRel.Execute := TRUE; IF fbMoveRel.Active THEN (* axis is executing job but is not yet finished *) fbMoveRel.Execute := FALSE; (* leave this state and buffer a second command *) HomeState := H_MOVING2; ElSIF fbMoveRel.Done THEN fbMoveRel.Execute := FALSE; HomeState := H_MOVING;//2? ELSIF fbMoveRel.CommandAborted OR fbMoveRel.Error THEN fbMoveRel.Execute := FALSE; HomeState := H_CHECK; END_IF H_MOVING2: IF fbMoveRel.CommandAborted OR fbMoveRel.Error THEN HomeState := H_CHECK; END_IF IF NOT ( Axis.Status.Moving) OR (fbMoveRel.Done) THEN //(fbMoveAxisABS.Done) AND (fbMoveAxisABS2.Done) THEN HomeState := H_MOVING; fbMoveRel.Execute := FALSE; END_IF H_CHECK: //Check position lag monitoring error if (Axis.Status.ErrorID = 16#00004550)THEN This^.q_stVGP.pv_xReset_SW := TRUE; HomeState := H_RESET; ELSE HomeState := H_ERROR; END_IF H_RESET: IF fbReset.Done THEN This^.q_stVGP.pv_xReset_SW := FALSE; HomeState := H_SET_POS; END_IF H_SET_POS: // Set Current Position fbSetPosition.Position := 0; fbSetPosition.Execute := TRUE; IF ( fbSetPosition.Done ) THEN fbSetPosition.Execute := FALSE; HomeState:= H_WRITE_LL; ELSIF (fbSetPosition.Error) THEN HomeState := H_ERROR; END_IF H_WRITE_LL: // Re Enable the Soft limits fbWriteParameter.ParameterNumber := MC_AxisParameter.AxisEnMinSoftPosLimit;//AxisEnMaxSoftPosLimit;// .AxisEnMinSoftPosLimit; fbWriteParameter.Value := TRUE; fbWriteParameter.Execute := TRUE; if (fbWriteParameter.Done) THEN fbWriteParameter.Execute := FALSE; HomeState:= H_WRITE_HL; END_IF H_WRITE_HL: // Re Enable the Soft limits fbWriteParameter.ParameterNumber := MC_AxisParameter.AxisEnMaxSoftPosLimit; fbWriteParameter.Value := TRUE; fbWriteParameter.Execute := TRUE; if (fbWriteParameter.Done) THEN fbWriteParameter.Execute := FALSE; HomeState:= H_DONE; END_IF H_ERROR: //taken care of in the axis motion state machine H_DONE: //taken care of in the axis motion state machine END_CASE // Move backward to fully closed fbMoveRel( Axis:= Axis , Execute:= , Distance:= rHomingDistance , Velocity:= rHomingVelocity, Acceleration:= , Deceleration:= , Jerk:= , BufferMode:= MC_BlendingNext, Options:= , Done=> , Busy=> , Active=> , CommandAborted=> , Error=> , ErrorID=> ); // Set Encoder Position fbSetPosition( Axis:= Axis , Execute:= , Position:= 0 , Mode:= FALSE, //Absolute Options:= , Done=> , Busy=> , Error=> , ErrorID=> ); // Write Parameters fbWriteParameter( Axis:= Axis , Execute:= , ParameterNumber:= , Value:= , Done=> , Busy=> , Error=> , ErrorID=> ); If ( fbWriteParameter.Error) OR (fbSetPosition.Error)(* OR (fbMoveRel.Error) *)THEN HomeState:= H_ERROR; q_stVGP.eState := ERROR; END_IF END_ACTION ACTION ACT_INIT: {attribute no_check} IF bInit THEN (* (* init array with the interpolation points *) (* fIn | fOut *) arrTable[1,1] := 0; arrTable[1,2] := 0; arrTable[2,1] := 5; arrTable[2,2] := 135; arrTable[3,1] := 10; arrTable[3,2] := 245; arrTable[4,1] := 20; arrTable[4,2] := 405; arrTable[5,1] := 30; arrTable[5,2] := 535; arrTable[6,1] := 40; arrTable[6,2] := 689; arrTable[7,1] := 50; arrTable[7,2] := 830; arrTable[8,1] := 60; arrTable[8,2] := 960; arrTable[9,1] := 70; arrTable[9,2] := 1095; arrTable[10,1] := 80; arrTable[10,2] := 1225; arrTable[11,1] := 90; arrTable[11,2] := 1415; arrTable[12,1] := 95; arrTable[12,2] := 1495; arrTable[13,1] := 98; arrTable[13,2] := 1559; arrTable[14,1] := 100; arrTable[14,2] := 1645; *) (* init parameter struct *) stCTRL_LIN_INTERPOLATION_PARAMS.tCtrlCycleTime := T#10ms; stCTRL_LIN_INTERPOLATION_PARAMS.tTaskCycleTime := T#10ms; stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_NumberOfRows := INT_TO_UINT(14); (* set the addresses *) stCTRL_LIN_INTERPOLATION_PARAMS.pDataTable_ADR := ADR(arrTable); stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_SIZEOF := SIZEOF(arrTable); (* set the mode to ACTIVE --> normal operation *) eMode := eCTRL_MODE_ACTIVE; (* init array with the interpolation points *) (* fIn | fOut *) FOR iCounter:=1 TO 14 BY 1 DO arrTable_ENC[iCounter,1] := arrTable[iCounter,2]; arrTable_ENC[iCounter,2] := arrTable[iCounter,1]; END_FOR; (* arrTable_ENC[1,1] := 0; arrTable_ENC[1,2] := 0; arrTable_ENC[2,1] := 135; arrTable_ENC[2,2] := 5; arrTable_ENC[3,1] := 245; arrTable_ENC[3,2] := 10; arrTable_ENC[4,1] := 405; arrTable_ENC[4,2] := 20; arrTable_ENC[5,1] := 535; arrTable_ENC[5,2] := 30; arrTable_ENC[6,1] := 689; arrTable_ENC[6,2] := 40; arrTable_ENC[7,1] := 830; arrTable_ENC[7,2] := 50; arrTable_ENC[8,1] := 960; arrTable_ENC[8,2] := 60; arrTable_ENC[9,1] := 1095; arrTable_ENC[9,2] := 70; arrTable_ENC[10,1] := 1225; arrTable_ENC[10,2] := 80; arrTable_ENC[11,1] := 1415; arrTable_ENC[11,2] := 90; arrTable_ENC[12,1] := 1495; arrTable_ENC[12,2] := 95; arrTable_ENC[13,1] := 1559; arrTable_ENC[13,2] := 98; arrTable_ENC[14,1] := 1645; arrTable_ENC[14,2] := 100;*) (* init parameter struct *) stCTRL_LIN_INTERPOLATION_PARAMS_ENC.tCtrlCycleTime := T#10ms; stCTRL_LIN_INTERPOLATION_PARAMS_ENC.tTaskCycleTime := T#10ms; stCTRL_LIN_INTERPOLATION_PARAMS_ENC.nDataTable_NumberOfRows := INT_TO_UINT(14); (* set the addresses *) stCTRL_LIN_INTERPOLATION_PARAMS_ENC.pDataTable_ADR := ADR(arrTable_ENC); stCTRL_LIN_INTERPOLATION_PARAMS_ENC.nDataTable_SIZEOF := SIZEOF(arrTable_ENC); (* reset the init flag *) bInit := FALSE; END_IF; END_ACTION ACTION ACT_LIN_INTERPOLATION: {attribute 'no_check'} fbCTRL_LIN_INTERPOLATION( fIn:= q_stVGP.rReqPosition , fManValue:= 0, bExtrapolate:= , eMode:= eMode, fOut=> , bInIsGreaterThanMaxElement=> , bInIsLessThanMinElement=> , eState=> , eErrorId=> , bError=> , stParams:= stCTRL_LIN_INTERPOLATION_PARAMS ); // Target position Calculation rTargetPosition := LREAL_TO_REAL(fbCTRL_LIN_INTERPOLATION.fOut); //rTargetPosition := LIMIT(rClosePosition, rTargetPosition, rOpenPosition); fbCTRL_LIN_INTERPOLATION_ENC( fIn:= Axis.NcToPlc.ActPos , fManValue:= 0, bExtrapolate:= , eMode:= eMode, fOut=> , bInIsGreaterThanMaxElement=> , bInIsLessThanMinElement=> , eState=> , eErrorId=> , bError=> , stParams:= stCTRL_LIN_INTERPOLATION_PARAMS_ENC ); q_stVGP.i_iPosition := LREAL_TO_REAL(fbCTRL_LIN_INTERPOLATION_ENC.fOut); END_ACTION ACTION ACT_MONITOR: IF (This^.q_stVGP.xBusy) THEN rPrevEncoderPosition:= This^.q_stVGP.rEnoder_Position; ELSIF NOT((rPrevEncoderPosition < This^.q_stVGP.rEnoder_Position +rHyst) AND (rPrevEncoderPosition > This^.q_stVGP.rEnoder_Position -rHyst)) AND NOT( q_stVGP.eState =HOME) AND NOT( q_stVGP.eState =ERROR) THEN q_stVGP.eState := ERROR; q_stVGP.pv_xHomed := FALSE; This^.q_stVGP.pv_xError := TRUE; This^.q_stVGP.sErrorMessage := 'Encoder Position Error'; END_IF tErrorPresent(CLK:=q_stVGP.pv_xError); IF tErrorPresent.Q THEN fbLogger(sMsg:=q_stVGP.sErrorMessage, eSevr:=TcEventSeverity.Error); END_IF // Log valve motion tAction(CLK:= q_stVGP.pv_xGo_SW); IF tAction.Q THEN fbLogger(sMsg:='Valve commanded to move', eSevr:=TcEventSeverity.Info); END_IF IF ePrevState <> q_stVGP.eValveControl THEN CASE q_stVGP.eValveControl OF CloseValve: fbLogger(sMsg:='Valve set to Close.', eSevr:=TcEventSeverity.Info); OpenValve: fbLogger(sMsg:='Valve set to Open.', eSevr:=TcEventSeverity.Info); PressureControl: fbLogger(sMsg:='Valve set to pressure control mode.', eSevr:=TcEventSeverity.Info); ManualControl: fbLogger(sMsg:='Valve set to manual control mode.', eSevr:=TcEventSeverity.Info); END_CASE ePrevState := q_stVGP.eValveControl; END_IF END_ACTION MAIN ^^^^ :: PROGRAM MAIN VAR fbLogHandler : FB_LogHandler; gas_selection_debug_mode : BOOL := FALSE; vgp_debug_mode : BOOL := FALSE; END_VAR PRG_DIAGNOSTIC(); PRG_GMD(); PRG_VAC_INTF(); //MG PRG_INJ(); PRG_PressureControl(); PRG_Gas_Selection(); PRG_Purge(); IF NOT vgp_debug_mode THEN PRG_VGP(); END_IF // Call the RTD Function blocks //RTD RTD_1(); RTD_2(); // Operate high voltage interlocking logic PRG_HV_ILK(); fbLogHandler(); END_PROGRAM PRG_DIAGNOSTIC ^^^^^^^^^^^^^^ :: PROGRAM PRG_DIAGNOSTIC VAR fbTime : FB_LocalSystemTime := ( bEnable := TRUE, dwCycle := 1 ); logTimer : TON := ( IN := TRUE, PT := T#1000ms ); plcName : STRING[15]; {attribute 'pytmc' := ' pv: simHeartbeat '} simHeartbeat AT %I* : UINT := 0; {attribute 'pytmc' := ' pv: plcHeartbeat '} plcHeartbeat : UDINT := 0; {attribute 'pytmc' := ' pv: plcInfo '} plcInfo : STRING[40]; {attribute 'pytmc' := ' pv: plcLocalTime '} plcLocalTime : STRING[25]; END_VAR plcHeartbeat := plcHeartbeat + 1; IF plcHeartbeat > 4294967000 THEN plcHeartbeat := 0; END_IF // get timestamp as string every second fbTime(); logTimer( IN := fbTime.bValid ); IF logTimer.Q THEN logTimer( IN := FALSE ); logTimer( IN := fbTime.bValid ); plcLocalTime := SYSTEMTIME_TO_STRING(fbTime.systemTime); END_IF // make an info string plcName := 'Prototype PLC: '; plcInfo := CONCAT(plcName, plcLocalTime); END_PROGRAM PRG_Gas_Selection ^^^^^^^^^^^^^^^^^ :: PROGRAM PRG_Gas_Selection VAR CurrentGas: E_GasType; END_VAR (* Gas selection includes a purge and checks interlocks*) //fix // Initialize the selected gas if ( VVC_83.iq_stValve.q_xOPN_DO) then SelectedGas := E_GasType.Neon; elsif ( VVC_84.iq_stValve.q_xOPN_DO) then SelectedGas := E_GasType.Argon; elsif ( VVC_85.iq_stValve.q_xOPN_DO) then SelectedGas := E_GasType.Krypton; elsif ( VVC_86.iq_stValve.q_xOPN_DO) then SelectedGas := E_GasType.Xenon; //else SelectedGas := E_GasType.none; END_IF (* If( CurrentGas <> SelectedGas) AND bStartPurge_sw (*AND NOT (CurrentGas=E_GasType.none)*) THEN if NOT(bStartPurge_sw) AND NOT(bPurgeActive)AND(bPurgeDone) then case SelectedGas of E_GasType.none: // all valves closed VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(false); E_GasType.Neon: VVC_83.M_Set_OPN_SW(TRUE); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(false); E_GasType.Argon: VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(TRUE); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(false); E_GasType.Krypton: VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(TRUE); VVC_86.M_Set_OPN_SW(false); E_GasType.Xenon: VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(TRUE); END_CASE END_IF END_IF *) /// vcn and vgp on manual or auto?? END_PROGRAM PRG_GMD ^^^^^^^ :: PROGRAM PRG_GMD VAR END_VAR // FB_MKS317 fb_EM2K0_XGMD_GPI_10(PG=>); fb_EM2K0_XGMD_GPI_50(PG=>); fb_EM2K0_XGMD_GPI_90(PG=>); // FB_PTM_TwisTorr fb_EM2K0_XGMD_PTM_10(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_10.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_10.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_20(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_20.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_20.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_30(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_30.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_30.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_40(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_40.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_40.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_50(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_50.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GPI_50.PG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_60(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_60.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_60.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_70(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_70.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_70.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_80(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_80.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_80.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); fb_EM2K0_XGMD_PTM_90(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM2K0_XGMD_PTM_90.iq_stPtm, BackingGauge:= fb_EM2K0_XGMD_GPI_10.PG, InletGauge:= fb_EM2K0_XGMD_GCC_90.IG, ScrollPump:= fb_EM2K0_XGMD_PRT_50.stPump) ); // FB_VRC fb_EM2K0_XGMD_VRC_10( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_10.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_20( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_20.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_30( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_30.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_40( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_40.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_60( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_60.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_70( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_70.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_80( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_80.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM2K0_XGMD_VRC_90( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM2K0_XGMD_PTM_90.iq_stPtm, i_stISG := fb_EM2K0_XGMD_GPI_50.PG, i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump ), i_xOverrideMode := xSystemOverrideMode ); // FB_MKS422 fb_EM2K0_XGMD_GCC_10(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_20(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_30(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_40(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_50(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_60(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_70(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_80(PG := fb_EM2K0_XGMD_GPI_50.PG); fb_EM2K0_XGMD_GCC_90(PG := fb_EM2K0_XGMD_GPI_50.PG); // FB_EbaraEVA fb_EM2K0_XGMD_PRT_50(i_xExtIlkOK := TRUE); // FB_VVC IF bAutoVVC50 THEN IF fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING OR fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpStarting THEN fb_EM2K0_XGMD_VVC_50.M_Open(True); ELSE fb_EM2K0_XGMD_VVC_50.M_Open(False); END_IF END_IF fb_EM2K0_XGMD_VVC_50( i_xExtILK_OK := fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING OR fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpStarting,//F_TURBO_PROT_SLND_ILK( // i_Turbo := fb_EM2K0_XGMD_PTM_50.iq_stPtm, // i_stISG := fb_EM2K0_XGMD_GPI_50.PG, // i_stBSG := fb_EM2K0_XGMD_GPI_10.PG, // ScrollPump := fb_EM2K0_XGMD_PRT_50.stPump //), i_xOverrideMode := xSystemOverrideMode, ); // Roughing valve IF( fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpSTARTING ) OR ( fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpRUNNING ) THEN fb_EM1K0_GMD_VRO_50.M_Open(TRUE); END_IF fb_EM1K0_GMD_VRO_50(i_xExtILK_OK:= (fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpRUNNING OR fb_EM2K0_XGMD_PRT_50.stPump.eState = pumpSTARTING ), i_xOverrideMode:= , iq_stValve=> ); END_PROGRAM PRG_HV_ILK ^^^^^^^^^^ :: PROGRAM PRG_HV_ILK VAR END_VAR //evaluate the HV ILK_OK bit //HV_ILK_OK := GCC_40.IG.xAT_VAC; hv1(i_xExtIlkOK := F_HV_ILK( IG := fb_EM2K0_XGMD_GCC_50.IG, HV := hv1.hv) ); //hv2(i_xExtIlkOK := HV_ILK_OK); END_PROGRAM PRG_INJ ^^^^^^^ :: PROGRAM PRG_INJ VAR i:INT; fullScale: REAL :=2000; DefaultSP :REAL:=0; rFULL_SCALE:REAL:=3000;//psig END_VAR // GCM GCM_80(i_rFULL_SCALE := fullScale ); GCM_80.M_SetBits(30518); i:=i+1; //GHC GHC_50.M_SetBits(30518); GHC_50(PG=> ); // Vent Valves // interlock evaluation VVC_80.i_xExtILK_OK := (VCN_50.iq_stVCN.eValveControl = E_VCN.CloseValve) OR( (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO)); // we need to purge all the way up to the VCN VVC_81.i_xExtILK_OK := (VVC_82.iq_stValve.q_xOPN_DO) AND(NOT VVC_83.iq_stValve.q_xOPN_DO) AND(NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO);// AND (NOT VVC_80.iq_stValve.q_xOPN_DO); VVC_82.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND(NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO);// AND (NOT VVC_80.iq_stValve.q_xOPN_DO); // instanitation VVC_80(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); VVC_81(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); VVC_82(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); // Gas panel // Interlock evaluation VVC_83.i_xExtILK_OK := (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive; VVC_84.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive ; VVC_85.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive; VVC_86.i_xExtILK_OK := (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND NOT bPurgeActive ; //Gas Panel VVC_83(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); VVC_84(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); VVC_85(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); VVC_86(i_xExtILK_OK:= , i_xOverrideMode:= xOverrideMode, iq_stValve=> ); END_PROGRAM PRG_PressureControl ^^^^^^^^^^^^^^^^^^^ :: PROGRAM PRG_PressureControl VAR CONSTANT nDataTable_NumberOfRows : INT:=9; END_VAR VAR fActualValue : FLOAT; fCtrlOutput : FLOAT; fBasicCtrlOutput : FLOAT; f_Rep_POS: Float; fManValue : FLOAT; bExtrapolate : BOOL; fManSyncValue : FLOAT; bSync : BOOL; bHold : BOOL; eMode : E_CTRL_MODE; stCTRL_PID_PARAMS : ST_CTRL_PID_PARAMS; stCTRL_LIN_INTERPOLATION_PARAMS : ST_CTRL_LIN_INTERPOLATION_PARAMS; eErrorId : E_CTRL_ERRORCODES; bARWactive : BOOL; arrTable : ARRAY[1..31,1..2] OF FLOAT; (* controller *) fbCTRL_PID : FB_CTRL_PID; fbCTRL_Normalize : FB_CTRL_NORMALIZE; fbCTRL_LIN_INTERPOLATION : FB_CTRL_LIN_INTERPOLATION; fbCTRL_DEADBAND : FB_CTRL_DEADBAND; stCTRL_DEADBAND_PARAMS : ST_CTRL_DEADBAND_PARAMS; bInit : BOOL := TRUE; wait : time := T#10S; FTrig: F_TRIG; END_VAR //Set VRC upper limit IF bInit THEN VCN_50.M_SetThrottle(30); // default at start up, should be changed through epics pv END_IF //VCN //bAdditionalVCNIlk IF (bAdditionalVCNIlk) THEN VCN_50.i_xExtIlkOK := ( fb_EM2K0_XGMD_GCC_10.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_20.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_30.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_40.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_50.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_60.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_70.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_80.IG.xAT_VAC AND fb_EM2K0_XGMD_GCC_90.IG.xAT_VAC) AND fb_EM2K0_XGMD_GPI_50.PG.xAT_VAC AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO); ELSE VCN_50.i_xExtIlkOK := fb_EM2K0_XGMD_GPI_50.PG.xAT_VAC AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO); END_IF VCN_50(i_xExtIlkOK :=, i_ReqPos:= ); (* Gauge selection *) (*Assign reading to psuedo gauge*) IF (fb_EM2K0_XGMD_GCC_50.IG.rPRESS <=0.0001) AND (fb_EM2K0_XGMD_GCC_50.IG.rPRESS >0) THEN GCP := fb_EM2K0_XGMD_GCC_50.IG; ElSE GCP := fb_EM2K0_XGMD_GPI_50.PG; END_IF (*-------------------------------------------------------------------*) (* PI CONTROL *) (*-------------------------------------------------------------------*) IF bInit THEN (*FBCNTRL*) (* init parameter struct *) stCTRL_PID_PARAMS.tCtrlCycleTime := T#10ms; stCTRL_PID_PARAMS.tTaskCycleTime := T#10ms; stCTRL_PID_PARAMS.fKp := fKp1; (* proportional gain Kp *) stCTRL_PID_PARAMS.tTn := T#500ms; (* Tn *) stCTRL_PID_PARAMS.tTv := T#200ms; (* Tv *) stCTRL_PID_PARAMS.tTd := T#100ms; (* Td *) stCTRL_PID_PARAMS.fOutMaxLimit := 78; (* maximum output limit *) stCTRL_PID_PARAMS.fOutMinLimit := -100; (* minimum output limit *) (* init array with the interpolation points *) (* fIn | fOut *) (* fIn | fOut *) arrTable[1,1] := 0; arrTable[1,2] := 5; arrTable[2,1] := 0.0000412; arrTable[2,2] := 34; arrTable[3,1] := 0.001282; arrTable[3,2] := 36; arrTable[4,1] := 0.002136; arrTable[4,2] := 38; arrTable[5,1] := 0.005884; arrTable[5,2] := 40; arrTable[6,1] := 0.00907; arrTable[6,2] := 42; arrTable[7,1] := 0.01183; arrTable[7,2] := 44; arrTable[8,1] := 0.01799; arrTable[8,2] := 46; arrTable[9,1] := 0.0302; arrTable[9,2] := 47; arrTable[10,1] := 0.0417; arrTable[10,2] := 50; arrTable[11,1] := 0.06635; arrTable[11,2] := 51; arrTable[12,1] := 0.08118; arrTable[12,2] := 53; arrTable[13,1] := 0.0998; arrTable[13,2] := 56; arrTable[14,1] := 0.10644; arrTable[14,2] := 56.5; arrTable[15,1] := 0.1359; arrTable[15,2] := 58; arrTable[16,1] := 0.1929; arrTable[16,2] := 60; arrTable[17,1] := 0.2922; arrTable[17,2] := 62; arrTable[18,1] := 0.3428; arrTable[18,2] := 64; arrTable[19,1] := 0.405;; arrTable[19,2] :=66; arrTable[20,1] := 0.481; arrTable[20,2] := 68; arrTable[21,1] := 0.5542; arrTable[21,2] := 69; arrTable[22,1] := 0.6333; arrTable[22,2] := 70; arrTable[23,1] := 0.7901; arrTable[23,2] := 72; arrTable[24,1] := 0.9307; arrTable[24,2] := 73.04; arrTable[25,1] := 1.0448; arrTable[25,2] := 73.64; arrTable[26,1] := 1.31919;; arrTable[26,2] := 74.45; arrTable[27,1] := 1.324; arrTable[27,2] :=74.46; arrTable[28,1] := 1.71941; arrTable[28,2] := 75; arrTable[29,1] := 1.963194; arrTable[29,2] :=75.5; arrTable[30,1] := 1.99999; arrTable[30,2] := 75.505; arrTable[31,1] := 2; arrTable[31,2] := 75.55; (* init parameter struct *) stCTRL_LIN_INTERPOLATION_PARAMS.tCtrlCycleTime := T#10ms; stCTRL_LIN_INTERPOLATION_PARAMS.tTaskCycleTime := T#10ms; stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_NumberOfRows := INT_TO_UINT(31); (* set the mode to ACTIVE --> normal operation *) eMode := eCTRL_MODE_ACTIVE; (* reset the init flag *) bInit := FALSE; END_IF (* set the addresses *) stCTRL_LIN_INTERPOLATION_PARAMS.pDataTable_ADR := ADR(arrTable); stCTRL_LIN_INTERPOLATION_PARAMS.nDataTable_SIZEOF := SIZEOF(arrTable); fSetpointValue:= LIMIT(0,fSetpointValue,0.001); if (VVC_80.M_IsClosed() ) THEN //eMode := eCTRL_MODE_PASSIVE; fSetpointValue :=0; END_IF if (bGo) THEN VCN_50.i_ReqPos:= fbCTRL_LIN_INTERPOLATION.fOut + fbCTRL_PID.fOut; IF (bReset) THEN (* set the mode to RESET*) eMode := eCTRL_MODE_RESET ; VCN_50.M_ValveControl(CloseValve); //bReset := False; ELSE (* set the mode to ACTIVE --> normal operation *) eMode := eCTRL_MODE_ACTIVE ; VCN_50.M_ValveControl(PressureControl); END_IF END_IF If(FTrig.Q)THEN eMode := eCTRL_MODE_PASSIVE; VCN_50.M_ValveControl(CloseValve); fSetpointValue :=0; END_IF (* call interpolation fb *) fbCTRL_LIN_INTERPOLATION( fIn:= fSetpointValue , fManValue:= fManValue , bExtrapolate:= bExtrapolate, eMode:= eMode, stParams:= stCTRL_LIN_INTERPOLATION_PARAMS, fOut=> , bInIsGreaterThanMaxElement=> , bInIsLessThanMinElement=> , eState=> , eErrorId=> , bError=> ); (* call controller *) fbCTRL_PID( fSetpointValue := fSetpointValue, fActualValue := , fManSyncValue := , bSync := bSync, eMode := eMode, bHold := bHold, stParams := stCTRL_PID_PARAMS, fOut => , bARWactive => bARWactive, eErrorId => eErrorId, bError => ); (*deadband/clipper *) (* call function block *) stCTRL_DEADBAND_PARAMS.fThreshold := fSetpointValue*0.0016 ; (*fbCTRL_DEADBAND ( fIn := , stParams := stCTRL_DEADBAND_PARAMS, bInIsUnderThreshold => , eErrorId => , bError => );*) bError := fbCTRL_PID.bError OR fbCTRL_LIN_INTERPOLATION.bError; FTRIG(CLK := bGo); END_PROGRAM PRG_Purge ^^^^^^^^^ :: PROGRAM PRG_Purge VAR step: INT:=0; {attribute 'pytmc' := ' pv: EM2K0:XGMD:sPURGE '} sMessage : STRING; {attribute 'pytmc' := ' pv: EM2K0:XGMD:RESET '} bReset:BOOL := False; {attribute 'pytmc' := ' pv: EM2K0:XGMD:PurgeError '} bError:BOOL := False; {attribute 'pytmc' :=' pv: EM2K0:XGMD:PURGE:SP1; field: HOPR 1000; field: LOPR 0; field: PREC 2; field: EGU "TORR"; '} rPurge_SP1 :REAL :=0.01; {attribute 'pytmc' :=' pv: EM2K0:XGMD:PURGE:SP2; field: HOPR 1000; field: LOPR 0; field: PREC 2; field: EGU "TORR"; '} rPurge_SP2 :REAL :=0.1; {attribute 'pytmc' :=' pv: EM2K0:XGMD:PURGE:REPEAT; '} NeedlePurgeRepeat : INT:= 1; NeedleVlvPurgeTmr : TON; (* Declaration for the needle valve Purge timer *) tNeedlePurgeTime : TIME:=T#5S; NeedlePurgeTime : TIME:=T#5S; BurpET : TIME; NeedlePurgeRun : BOOL; NeedlePurgeDone : BOOL; VCN_Timer :TON; rt_reset: R_TRIG; // Timers VVC_80_Timer : TON; VVC_81_Timer : TON; VVC_82_Timer : TON; VVC_80_Time : TIME:=T#30S; VVC_81_Time : TIME:=T#5S; VVC_82_Time : TIME:=T#5S; VCN_Time : TIME := T#5S; iVGP_POS: REAL:=0; END_VAR (* PURGE CYCLE The purge cycle consists of the following steps; 1. Close all gas valves 83-86 and Close Needle valve and switch off PID control 2. Wait till needle valve closes 3. Close VGP, to protect the Detector chamber in case a pressure spike on the roughing line stops the turbo. 4. PUMP DOWN MANIFOLD: Open VVC-80 then Open VVC82 for certain pressure on the baratron 5. Open VIC:81 and keep it open while the manifold pumps down to pressure set point for a certain time to avoid flukes then close VVC-80 - THEN Fully open VGP:40 6. BURP NEEDLE VALVE: Once the manifold is pumped down, open the needle valve (burp) to evacuate gases that may be trapped in its mechanism - this step is done gradually to avoid sending pressure spike into the detector 7. Close needle valve 8. Release VGP:40 *) CASE step OF 0: // READY STATE sMessage:= 'Purge Ready'; bError := FALSE; IF (bStartPurge_sw) Then step:=10; bGo :=FALSE; bPurgeActive := true; bPurgeDone := false; iVGP_POS := VGP_50.q_stVGP.rReqPosition; sMessage:= 'Purge Start'; END_IF 10: // start purge sequence by closing all gas valves and needle valve VVC_80.M_Set_OPN_SW(FALSE); VVC_81.M_Set_OPN_SW(FALSE); VVC_82.M_Set_OPN_SW(FALSE); VVC_83.M_Set_OPN_SW(FALSE); VVC_84.M_Set_OPN_SW(FALSE); VVC_85.M_Set_OPN_SW(FALSE); VVC_86.M_Set_OPN_SW(FALSE); VCN_50.M_ValveControl(E_VCN.CloseValve); IF (NOT VVC_80.iq_stValve.q_xOPN_DO) AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND (NOT VVC_82.iq_stValve.q_xOPN_DO) AND (NOT VVC_83.iq_stValve.q_xOPN_DO) AND (NOT VVC_84.iq_stValve.q_xOPN_DO) AND (NOT VVC_85.iq_stValve.q_xOPN_DO) AND (NOT VVC_86.iq_stValve.q_xOPN_DO) THEN step:= 20; sMessage:= 'Prep: All valves are closed'; END_IF 20: //Close Needle valve VCN_50.M_ValveControl( E_VCN.CloseValve); //sMessage:= 'Prep: Needle Valve is closed'; // wait for a period of time to ensure that the Valve is fully closed IF (VCN_Timer.Q) THEN step:=30; sMessage:= 'Prep: Needle Valve is closed'; END_IF 30: //Fully close VGP:40 VGP_50.M_ValveControl(E_VCN.CloseValve); VGP_50.M_SetGoSw(TRUE); IF NOT(VGP_50.q_stVGP.eState = E_MoveState.READY)THEN // wait until the VGP Starts moving step:=31; sMessage:= 'Prep: VGP to fully closed'; END_IF if (VGP_50.q_stVGP.pv_xError ) OR NOT (VGP_50.i_xExtIlkOK) OR NOT (VGP_50.q_stVGP.pv_xHomed) THEN step:=900+step; END_IF 31: IF (VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP motion is done step:=40; sMessage:= 'Prep: VGP is closed'; END_IF if (VGP_50.q_stVGP.pv_xError )then step:=900+step; END_IF 40: // open vavle 80 to pump down all the way to the needle valve //VVC_80.M_Set_OPN_SW(TRUE); //if (VVC_80.iq_stValve.q_xOPN_DO ) THEN step:=41; //END_IF 41: //PUMP DOWN MANIFOLD: Open VIC82 for a certain peroid of time or till certain pressure VVC_82.M_Set_OPN_SW(TRUE); sMessage:= 'Pumping down: VVC82 is open'; if (VVC_82.iq_stValve.q_xOPN_DO) AND (VVC_82_Timer.Q) AND (GCM_80.PG.rPRESS <= rPurge_SP1) THEN step:=50; END_IF 50:// Open VIC:81 and keep it open while the manifold pumps down to pressure set point VVC_81.M_Set_OPN_SW(TRUE); sMessage:= 'Pumping down: VVC81 and VVC82 are open'; IF (VVC_81.iq_stValve.q_xOPN_DO ) AND (VVC_81_Timer.Q) AND (GCM_80.PG.rPRESS <= rPurge_SP2) THEN // or a certain pressure reading and check timeouts step:=51; END_IF 51: // open vavle 80 to pump down all the way to the needle valve VVC_80.M_Set_OPN_SW(TRUE); if (VVC_80.iq_stValve.q_xOPN_DO ) THEN step:=52; END_IF 52:// Open VIC:81 and keep it open while the manifold pumps down to pressure set point VVC_81.M_Set_OPN_SW(TRUE); sMessage:= 'Pumping down: VVC80, VVC81 and VVC82 are open'; IF (VVC_81.iq_stValve.q_xOPN_DO ) AND (VVC_80_Timer.Q) AND (GCM_80.PG.rPRESS <= rPurge_SP2) THEN // or a certain pressure reading and check timeouts step:=54; END_IF 54: //Close VIC:81 and VIC:82 VVC_80.M_Set_OPN_SW(false); VVC_81.M_Set_OPN_SW(false); VVC_82.M_Set_OPN_SW(false); sMessage:= 'Pumping down complete: valves are closed'; IF (NOT VVC_80.iq_stValve.q_xOPN_DO) AND(NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO) THEN step:=55; END_IF 55: //Fully close VGP VGP_50.M_ValveControl(E_VCN.OpenValve); IF NOT(VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP Starts moving step:=56; sMessage:= 'Prep: VGP to fully open'; END_IF if (VGP_50.q_stVGP.pv_xError ) OR NOT (VGP_50.i_xExtIlkOK) OR NOT (VGP_50.q_stVGP.pv_xHomed) THEN step:=900+step; END_IF 56: IF (VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP motion is done step:=60; sMessage:= 'Prep: VGP is Open'; END_IF if (VGP_50.q_stVGP.pv_xError )then step:=900+step; END_IF 60: //BURP NEEDLE VALVE: Once the manifold is pumped down, open the needle valve (burp) to evacuate gases that may be trapped in its mechanism VCN_50.M_ValveControl(E_VCN.PressureControl); VCN_50.i_ReqPos := 15; sMessage:= 'VCN Burp: VCN to 15%'; // wait for a period of time to ensure that the Valve is fully closed IF (NeedleVlvPurgeTmr.Q) THEN step:=61; END_IF 61: VCN_50.i_ReqPos := 19; sMessage:= 'VCN Burp: VCN to 19%'; IF (VCN_Timer.Q) THEN step:=62; END_IF 62: //BURP NEEDLE VALVE: Once the manifold is pumped down, open the needle valve (burp) to evacuate gases that may be trapped in its mechanism VCN_50.i_ReqPos := 25; sMessage:= 'VCN Burp: VCN to 25%'; // wait for a period of time to ensure that the Valve is fully closed IF (NeedleVlvPurgeTmr.Q) THEN step:=63; END_IF 63: VCN_50.i_ReqPos := 31; sMessage:= 'VCN Burp: VCN to 31%'; IF (VCN_Timer.Q) THEN step:=64; END_IF 64: VCN_50.i_ReqPos := 39; sMessage:= 'VCN Burp: VCN to 39%'; IF (NeedleVlvPurgeTmr.Q) THEN step:=65; END_IF 65: VCN_50.i_ReqPos := 49; sMessage:= 'VCN Burp: VCN to 49%'; IF (VCN_Timer.Q) THEN step:=66; END_IF 66: VCN_50.i_ReqPos := 62; sMessage:= 'VCN Burp: VCN to 62%'; IF (NeedleVlvPurgeTmr.Q) THEN step:=67; END_IF 67: VCN_50.i_ReqPos := 78; sMessage:= 'VCN Burp: VCN to 78%'; IF (VCN_Timer.Q) THEN step:=68; END_IF 68: VCN_50.i_ReqPos := 100; sMessage:= 'VCN Burp: VCN to 100%'; IF (NeedleVlvPurgeTmr.Q) THEN step:=70; END_IF 70: //Close Needle valve VCN_50.M_ValveControl(E_VCN.CloseValve); sMessage:= 'VCN Burp Complete: VCN to 0%'; // wait for a period of time to ensure that the Valve is fully closed IF (VCN_Timer.Q) THEN step:=80; END_IF 80: // Repeat IF (NeedlePurgeRepeat > 0) THEN NeedlePurgeRepeat := NeedlePurgeRepeat-1; step:= 60; ELSE NeedlePurgeRepeat := 1; step:=90; END_IF 90: //Release VGP:40 VGP_50.M_ValveControl(E_VCN.ManualControl); VGP_50.i_ReqPos:= iVGP_POS; //50% open VGP_50.M_SetGoSw(TRUE); sMessage:= 'Post: VGP to previous position'; IF NOT(VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP encoder reads Open //use motion ready step:=91; END_IF if (VGP_50.q_stVGP.pv_xError )then step:=900+step; END_IF 91: IF (VGP_50.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP encoder reads Open //use motion ready VGP_50.M_ValveControl(E_VCN.ManualControl); VGP_50.i_ReqPos:= 0; VGP_50.M_SetGoSw(FALSE); step:=100; sMessage:= 'Purge Complete'; END_IF if (VGP_50.q_stVGP.pv_xError )then step:=900+step; END_IF 100: // DONE bStartPurge_sw := false; bPurgeActive := false; bPurgeDone := TRUE; VVC_80.M_Set_OPN_SW(false); VVC_81.M_Set_OPN_SW(false); VVC_82.M_Set_OPN_SW(false); VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(false); VCN_50.M_ValveControl(E_VCN.CloseValve); VGP_50.M_ValveControl(E_VCN.ManualControl); // reset selected gas to none SelectedGas := E_GasType.none; step :=0; 900: //Error bStartPurge_sw := false; bPurgeActive := false; bPurgeDone := FALSE; bError := TRUE; VVC_80.M_Set_OPN_SW(false); VVC_81.M_Set_OPN_SW(false); VVC_82.M_Set_OPN_SW(false); VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(false); VCN_50.M_ValveControl(E_VCN.CloseValve); VGP_50.M_ValveControl(E_VCN.ManualControl); // CLOSE or OPEN to pump down sMessage:= 'Purge Error: Interlock'; END_CASE //shouldn't be here (* if (bPurgeActive) then VVC_83.i_xExtILK_OK := VVC_84.i_xExtILK_OK := VVC_85.i_xExtILK_OK := VVC_86.i_xExtILK_OK := false; END_IF *) //Errors if (step >900 ) Then //Error bStartPurge_sw := false; bPurgeActive := false; bPurgeDone := false; bError := TRUE; VVC_80.M_Set_OPN_SW(false); VVC_81.M_Set_OPN_SW(false); VVC_82.M_Set_OPN_SW(false); VVC_83.M_Set_OPN_SW(false); VVC_84.M_Set_OPN_SW(false); VVC_85.M_Set_OPN_SW(false); VVC_86.M_Set_OPN_SW(false); VCN_50.M_ValveControl(E_VCN.CloseValve); VGP_50.M_ValveControl(E_VCN.ManualControl); sMessage:= CONCAT('Purge Error: ',TO_STRING(step)); END_IF rt_reset(CLK:= bReset); IF rt_reset.Q THEN Step:=100; bReset:=False; bPurgeDone:=False; END_IF //Timers VVC_80_Timer(IN:=(step = 52), PT:=VVC_80_Time); VVC_81_Timer(IN:= (step = 50) , PT:=VVC_81_Time); VVC_82_Timer(IN:= (step = 41), PT:=VVC_82_Time); VCN_Timer(IN:= (step = 20) OR (step = 61) OR (step = 63) OR (step = 65) OR (step = 67) OR (step = 70), PT:=VCN_Time); NeedleVlvPurgeTmr(IN:= (step = 60) OR (step = 62) OR (step = 64) OR (step = 66) OR (step = 68), PT:=NeedlePurgeTime ); // IF (bStartPurge_sw) THEN bGo :=FALSE; END_IF /// If at any point the VGP interlocked or in an error state, we stop purge. IF ((VGP_50.q_stVGP.pv_xError ) OR NOT (VGP_50.i_xExtIlkOK)) AND (bPurgeActive) AND (step >=55) AND (step <=70) THEN step:=900; END_IF IF NOT (VCN_50.i_xExtIlkOK) AND (bPurgeActive) AND (step >=60) AND (step <=70) THEN step:=900; END_IF IF (NOT (fb_EM2K0_XGMD_PRT_50.stPump.eState = E_PumpState.pumpRUNNING)) AND (bPurgeActive) THEN step:=900; END_IF END_PROGRAM PRG_VAC_INTF ^^^^^^^^^^^^ :: PROGRAM PRG_VAC_INTF VAR END_VAR ads_watch_dog( sNetId := '172.21.92.61.1.1', // AMS NET ID of the PLC reading from this PLC (SXR Vacuum PLC) nPort := 851, // ADS port of the PLC reading from this PLC sVarName := 'GVL_VAC_INTF.n_EM2K0_VAC_counter', // Full name of the UDINT provided to the 'iWatchdog' parameter in the interface functions on the PLC reading from this PLC ); END_PROGRAM PRG_VGP ^^^^^^^ :: PROGRAM PRG_VGP VAR arrTable : ARRAY[1..14,1..2] OF FLOAT; arrTable_ENC : ARRAY[1..14,1..2] OF FLOAT; bInit: BOOL:=true; VGP_REQ_POS: LREAL; VGP_OUT_POS:LREAL; END_VAR IF bInit THEN (* init array with the interpolation points *) (* fIn | fOut *) arrTable[1,1] := 0; arrTable[1,2] := 0; arrTable[2,1] := 5; arrTable[2,2] := 170; arrTable[3,1] := 10; arrTable[3,2] := 280; arrTable[4,1] := 20; arrTable[4,2] := 445; arrTable[5,1] := 30; arrTable[5,2] := 575; arrTable[6,1] := 40; arrTable[6,2] := 725; arrTable[7,1] := 50; arrTable[7,2] := 860; arrTable[8,1] := 60; arrTable[8,2] := 980; arrTable[9,1] := 70; arrTable[9,2] := 1120; arrTable[10,1] := 80; arrTable[10,2] := 1250; arrTable[11,1] := 90; arrTable[11,2] := 1420; arrTable[12,1] := 95; arrTable[12,2] := 1550; arrTable[13,1] := 98; arrTable[13,2] := 1600; arrTable[14,1] := 100; arrTable[14,2] := 1660; (* reset the init flag *) bInit := FALSE; END_IF VGP_50.i_xOpenIlkOK := (fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING) ; VGP_50( i_xExtIlkOK:= (fb_EM2K0_XGMD_PTM_50.iq_stPtm.eState = pumpRUNNING), i_ReqPos:= , arrTable:= arrTable , q_stVGP=> ); END_PROGRAM