DUTs ---- E_GasType ^^^^^^^^^ :: TYPE E_GasType : ( none := 0, Neon, Argon, Krypton, Xenon ); END_TYPE Related: * `E_GasType`_ 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_PressureSensor ^^^^^^^^^^^^^^^^^ :: TYPE ST_PressureSensor : STRUCT {attribute 'pytmc' := ' pv: PRESS; io: i; '} rPRESS: REAL; //This is the human-readable pressure {attribute 'pytmc' := ' pv: iPRESS; io: i; '} iPRESS_R : INT ; //input pressure in machine form {attribute 'pytmc' := ' pv: PRESS_SP; io: io; '} rPressSP: REAL ; // EPICS Pressure setpoint {attribute 'pytmc' := ' pv: MIN_SP; io: io; '} rMinPressSP : REAL; // Low limit of pressure setpoint {attribute 'pytmc' := ' pv: MAX_SP; io: io; '} rMaxPressSP : REAL; // High limit of pressure setpoint {attribute 'pytmc' := ' pv: SCALE; io: io; '} rFULL_SCALE: REAL; // Full scale {attribute 'pytmc' := ' pv: ALARM; field: ZNAM Normal; field: ONAM Alarm; io: i; '} xPstateAlarm : BOOL; // 0:Normal, 1:Alarm 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 Related: * `E_MoveState`_ GVLs ---- GVL_GMD ^^^^^^^ :: VAR_GLOBAL // To Remove: // Includes 'fake' elements for satisfying interlocks. Delete these after creating better interlock functions // Defaults to the closed position. No command required. fake_always_closed_vent_valve : ST_VVC; // FB_MKS317 {attribute 'pytmc' := ' pv: EM1K0:GMD:GPI:10 '} fb_EM1K0_GMD_GPI_10 : FB_MKS317; {attribute 'pytmc' := ' pv: EM1K0:GMD:GPI:40 '} fb_EM1K0_GMD_GPI_40 : FB_MKS317; {attribute 'pytmc' := ' pv: EM1K0:GMD:GPI:70 '} fb_EM1K0_GMD_GPI_70 : FB_MKS317; // FB_PTM_TwisTorr {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:10 '} fb_EM1K0_GMD_PTM_10 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:20 '} fb_EM1K0_GMD_PTM_20 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:30 '} fb_EM1K0_GMD_PTM_30 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:40 '} fb_EM1K0_GMD_PTM_40 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:50 '} fb_EM1K0_GMD_PTM_50 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:60 '} fb_EM1K0_GMD_PTM_60 : FB_PTM_TwisTorr; {attribute 'pytmc' := ' pv: EM1K0:GMD:PTM:70 '} fb_EM1K0_GMD_PTM_70 : FB_PTM_TwisTorr; // FB_VRC {attribute 'pytmc' := ' pv: EM1K0:GMD:VRC:10 '} fb_EM1K0_GMD_VRC_10 : FB_VRC; {attribute 'pytmc' := ' pv: EM1K0:GMD:VRC:20 '} fb_EM1K0_GMD_VRC_20 : FB_VRC; {attribute 'pytmc' := ' pv: EM1K0:GMD:VRC:30 '} fb_EM1K0_GMD_VRC_30 : FB_VRC; {attribute 'pytmc' := ' pv: EM1K0:GMD:VRC:50 '} fb_EM1K0_GMD_VRC_50 : FB_VRC; {attribute 'pytmc' := ' pv: EM1K0:GMD:VRC:60 '} fb_EM1K0_GMD_VRC_60 : FB_VRC; {attribute 'pytmc' := ' pv: EM1K0:GMD:VRC:70 '} fb_EM1K0_GMD_VRC_70 : FB_VRC; // FB_MKS422 {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:10 '} fb_EM1K0_GMD_GCC_10 : FB_MKS422; {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:20 '} fb_EM1K0_GMD_GCC_20 : FB_MKS422; {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:30 '} fb_EM1K0_GMD_GCC_30 : FB_MKS422; {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:40 '} fb_EM1K0_GMD_GCC_40 : FB_MKS422; {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:50 '} fb_EM1K0_GMD_GCC_50 : FB_MKS422; {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:60 '} fb_EM1K0_GMD_GCC_60 : FB_MKS422; {attribute 'pytmc' := ' pv: EM1K0:GMD:GCC:70 '} fb_EM1K0_GMD_GCC_70 : FB_MKS422; // FB_EbaraEVA {attribute 'pytmc' := ' pv: EM1K0:GMD:PRT:40 '} fb_EM1K0_GMD_PRT_40 : FB_EbaraEVA; // FB_VVC {attribute 'pytmc' := ' pv: EM1K0:GMD:VVC:40 '} fb_EM1K0_GMD_VVC_40 : FB_VVC; //Roughing DC Valves {attribute 'pytmc' := ' pv: EM1K0:GMD:VRO:40 '} {attribute 'TcLinkTo' := '.q_xOPN_DO := TIIB[EL2212_03_09]^DOX Control Channel 2^Control^Output'} fb_EM1K0_GMD_VRO_40 : FB_VVC; // Hot Cathode gauge {attribute 'pytmc' := ' pv: EM1K0:GMD:GHC:40 '} {attribute 'TcLinkTo' := '.q_xHV_DIS := TIIB[EL2794_03_01]^Channel 1^Output; .i_iPRESS_R := TIIB[EL3068_03_02]^AI Standard Channel 1^Value '} fb_EM1K0_GMD_GHC_40 : FB_MKS_937b; END_VAR GVL_INJ ^^^^^^^ :: VAR_GLOBAL //GVL_Devices {attribute 'pytmc' :=' pv: EM1K0:GMD:VCN:40 '} VCN_40 : FB_VCN; {attribute 'pytmc' :=' pv: EM1K0:GMD:VGP:40 '} VGP_40 : FB_VGP; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:80 '} VVC_80:FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:81 '} VVC_81:FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:82 '} VVC_82:FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:83 '} VVC_83 : FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:84 '} VVC_84 : FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:85 '} VVC_85 : FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:VVC:86 '} VVC_86 : FB_VVC; {attribute 'pytmc' :=' pv: EM1K0:GMD:GCM:80 '} GCM_80: FB_GCM; {attribute 'pytmc' :=' pv: EM1K0:GMD:INJ_Override '} xOverrideMode : BOOL:= false; (*Additional VCN Interlock*) {attribute 'pytmc' :=' pv: EM1K0:GMD:VCN_ILK; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} bAdditionalVCNIlk : BOOL:=TRUE; //GVL_Sensors (*Pressure Meter*) {attribute 'pytmc' :=' pv: EM1K0:GMD:GFM:86 '} GFM_86 :FB_PressureTransducer; {attribute 'pytmc' :=' pv: EM1K0:GMD:GFM:85 '} GFM_85 :FB_PressureTransducer; {attribute 'pytmc' :=' pv: EM1K0:GMD:GFM:84 '} GFM_84 :FB_PressureTransducer; {attribute 'pytmc' :=' pv: EM1K0:GMD:GFM:83 '} GFM_83 :FB_PressureTransducer; (*HV*) {attribute 'pytmc' :=' pv: EM1K0:GMD:PSV:1 '} hv1 : FB_HighVoltage; // {attribute 'pytmc' :=' pv: EM1K0:GMD:HV:2 '} // hv2 : FB_HighVoltage; {attribute 'pytmc' :=' pv: EM1K0:GMD:RTD:1 '} RTD : FB_RTD; (* Pressure Control*) {attribute 'pytmc' := ' pv: EM1K0:GMD:GCP:40 '} GCP: ST_VG; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:SP; field: HOPR 1000; field: LOPR 0; field: PREC 2; field: EGU "TORR"; '} fSetpointValue :REAL; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:GO; field: ZNAM STOP; field: ONAM START; io: io; '} bGo: BOOL:=FALSE; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:RESET; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} bReset : BOOL; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:ERROR; field: ZNAM FALSE; field: ONAM TRUE; io: io; '} bError : BOOL; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:Kp1 '} fKp1 : REAL:= 0.5; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:Tn1 '} fTn1 : REAL:= 0.5; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:Kp2 '} fKp2 : REAL:= 0.01; {attribute 'pytmc' :=' pv: EM1K0:GMD:CNTRL:Tn2 '} fTn2 : REAL:= 0.5; END_VAR Related: * `FB_HighVoltage`_ * `FB_PressureTransducer`_ * `FB_RTD`_ * `FB_VGP`_ GVL_VAC_INTF ^^^^^^^^^^^^ :: VAR_GLOBAL ads_watch_dog : FB_ADS_WATCHDOG; END_VAR GVL_VARIABLES ^^^^^^^^^^^^^ :: VAR_GLOBAL {attribute 'pytmc' :=' pv: EM1K0:GMD:OVERRIDE_VAC '} xSystemOverrideMode : BOOL; (* Global system override for the prototype section*) {attribute 'pytmc' :=' pv: EM1K0:GMD:AUTO_VVC_40 '} bAutoVVC40 : BOOL := TRUE; {attribute 'pytmc' := ' pv: EM1K0:GMD:GAS_TYPE ; type: mbbi ; field: ZRST none ; field: ONST Neon; field: TWST Argon ; field: THST Krypton ; field: FRST Xenon ; io: i '} SelectedGas: E_GasType; // Purge COMMANDS FROM epics //pragma {attribute 'pytmc' :=' pv: EM1K0:GMD:Purge_SW'} bStartPurge_sw : BOOL :=false; {attribute 'pytmc' :=' pv: EM1K0:GMD:Purge_Active'} bPurgeActive : BOOL:=false; {attribute 'pytmc' :=' pv: EM1K0:GMD:PurgeDone'} bPurgeDone : BOOL :=false; fbLogHandler : FB_LogHandler; END_VAR Related: * `E_GasType`_ 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 Related: * `ST_HV`_ F_TURBO_PROT_SLND_ILK ^^^^^^^^^^^^^^^^^^^^^ :: 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 Related: * `ST_HV`_ FB_PressureTransducer ^^^^^^^^^^^^^^^^^^^^^ :: FUNCTION_BLOCK FB_PressureTransducer VAR_OUTPUT {attribute 'pytmc' := 'pv:'} Sensor : ST_PressureSensor; END_VAR VAR_INPUT rDefaultSP : REAL; (* Must assign a default value at instantiation*) i_rFULL_SCALE: REAL; END_VAR VAR iCurrent : REAL; AlarmTOF : TOF; (*IOs to be linked*) iError AT %I* : BOOL; // Link to terminal diagnostics i_iPRESS_R AT %I* :INT; // input Pressure // Link to analog Input END_VAR // for SETRA 4-20mA outout (* Real-value calculation *) Sensor.rFull_Scale:=i_rFULL_SCALE; iCurrent := 20*INT_TO_REAL(Sensor.iPRESS_R)/32767; IF iError THEN; //reading less than 4mA Sensor.rPRESS := -1; Sensor.xPStateAlarm:= TRUE; ELSE Sensor.rPRESS := LREAL_TO_REAL(iCurrent*Sensor.rFull_Scale); //FULL scale in Psi for pressure transducer ??? END_IF (* Validate setpoint *) IF (Sensor.rPressSP < Sensor.rMinPressSP OR Sensor.rPressSP > Sensor.rMaxPressSP) THEN; Sensor.rPressSP := rDefaultSP; END_IF (* Set alarm bit when pressure lower and equal to setpoint, delay off for 60s*) AlarmTOF (IN := Sensor.rPRESS <= Sensor.rPressSP, PT := T#60S, Q => Sensor.xPstateAlarm); (*Soft IO Mapping*) ACT_IO(); END_FUNCTION_BLOCK ACTION ACT_IO: Sensor.iPRESS_R := i_iPRESS_R; END_ACTION Related: * `ST_PressureSensor`_ FB_RTD ^^^^^^ :: FUNCTION_BLOCK FB_RTD VAR_INPUT iScale: INT := 10; END_VAR VAR_OUTPUT {attribute 'pytmc' := ' pv: TEMP io: input field: EGU C field: PREC 2 '} fTemp: LREAL; {attribute 'pytmc' := ' pv: CONN io: input ONAM: Connected ZNAM: Disconnected '} bConnected: BOOL; {attribute 'pytmc' := ' pv: ERR io: input '} bError AT %I*: BOOL; bUnderrange AT %I*: BOOL; bOverrange AT %I*: BOOL; END_VAR VAR iRaw AT %I*: INT; END_VAR bConnected := NOT (bOverrange AND bError); fTemp := INT_TO_LREAL(iRaw) / iScale; 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 METHOD ConfigEncoder : BOOL VAR_INPUT EncoderMax: REAl; // Maximum encoder reading from fully closed to fully open invert: Bool; // Invert Encoder Counting Direction END_VAR VAR fbWriteParameter1: MC_WriteBoolParameter; END_VAR rOpenPosition := EncoderMax; // fEncScaleFactor - AxisEncoderScalingFactor // bEncIsInverse - if (invert) THEN fbWriteParameter1.ParameterNumber := MC_AxisParameter.AxisEncoderDirectionInverse; fbWriteParameter1.Value := True; END_IF // Write Parameters fbWriteParameter1( Axis:= Axis , Execute:= , ParameterNumber:= , Value:= , Done=> , Busy=> , Error=> , ErrorID=> ); END_METHOD METHOD M_INIT : BOOL VAR_INPUT arrTable : ARRAY[1..14,1..2] OF FLOAT; arrTable_ENC : ARRAY[1..14,1..2] OF FLOAT; END_VAR (* 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 *) 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); END_METHOD METHOD M_SetGoSw : BOOL VAR_INPUT bGo:BOOL; END_VAR q_stVGP.pv_xGo_SW:=bGo; END_METHOD METHOD M_ValveControl : BOOL VAR_INPUT state:E_VCN; // Close, Open, Pressure, Manual END_VAR q_stVGP.eValveControl := state; END_METHOD METHOD PUBLIC SetEncoderMax : BOOL VAR_INPUT EncoderMax: REAl; END_VAR rOpenPosition := EncoderMax; END_METHOD Related: * `E_HomeState`_ * `ST_VGP`_ MAIN ^^^^ :: PROGRAM MAIN VAR vgp_debug_mode :BOOL := False; gas_selection_debug_mode : BOOL := FALSE; press_cntrl :BOOL := FALSE; END_VAR PRG_DIAGNOSTIC(); PRG_GMD(); PRG_VAC_INTF(); (*INJ*) PRG_INJ(); PRG_PressureControl(); PRG_Gas_Selection(); PRG_Purge(); IF NOT vgp_debug_mode THEN PRG_VGP(); END_IF // instaniate the RTD and HV PRG_HV_ILK(); fbLogHandler(); END_PROGRAM Related: * `PRG_DIAGNOSTIC`_ * `PRG_GMD`_ * `PRG_Gas_Selection`_ * `PRG_HV_ILK`_ * `PRG_INJ`_ * `PRG_PressureControl`_ * `PRG_Purge`_ * `PRG_VAC_INTF`_ * `PRG_VGP`_ 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*) // 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 NOT (CurrentGas=E_GasType.none) then bStartPurge_sw := true; END_IF if NOT(bStartPurge_sw) 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 *) /// vcn and vgp on manual or auto?? END_PROGRAM Related: * `E_GasType`_ PRG_GMD ^^^^^^^ :: PROGRAM PRG_GMD VAR f_: INT; fb_EM1K0_GMD_PTM_10i_xExtILKOk: BOOL; END_VAR // FB_MKS317 fb_EM1K0_GMD_GPI_10(PG=>); fb_EM1K0_GMD_GPI_40(PG=>); fb_EM1K0_GMD_GPI_70(PG=>); // FB_PTM_TwisTorr fb_EM1K0_GMD_PTM_10(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_10.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GCC_10.IG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); fb_EM1K0_GMD_PTM_20(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_20.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GCC_20.IG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); fb_EM1K0_GMD_PTM_30(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_30.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GCC_30.IG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); fb_EM1K0_GMD_PTM_40(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_40.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GPI_40.PG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); fb_EM1K0_GMD_PTM_50(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_50.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GCC_50.IG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); fb_EM1K0_GMD_PTM_60(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_60.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GCC_60.IG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); fb_EM1K0_GMD_PTM_70(i_xExtILKOk := F_TurboExtILKLogic_2( Turbo:= fb_EM1K0_GMD_PTM_70.iq_stPtm, BackingGauge:= fb_EM1K0_GMD_GPI_10.PG, InletGauge:= fb_EM1K0_GMD_GCC_70.IG, ScrollPump:= fb_EM1K0_GMD_PRT_40.stPump)); // FB_VRC fb_EM1K0_GMD_VRC_10( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM1K0_GMD_PTM_10.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM1K0_GMD_VRC_20( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM1K0_GMD_PTM_20.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM1K0_GMD_VRC_30( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM1K0_GMD_PTM_30.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM1K0_GMD_VRC_50( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM1K0_GMD_PTM_50.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM1K0_GMD_VRC_60( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM1K0_GMD_PTM_60.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ), i_xOverrideMode := xSystemOverrideMode ); fb_EM1K0_GMD_VRC_70( i_xExtILK_OK := F_TurboGateValve_Protection_ILK_local( i_Turbo := fb_EM1K0_GMD_PTM_70.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ), i_xOverrideMode := xSystemOverrideMode ); // FB_MKS422 fb_EM1K0_GMD_GCC_10(PG := fb_EM1K0_GMD_GPI_40.PG); fb_EM1K0_GMD_GCC_20(PG := fb_EM1K0_GMD_GPI_40.PG); fb_EM1K0_GMD_GCC_30(PG := fb_EM1K0_GMD_GPI_40.PG); fb_EM1K0_GMD_GCC_40(PG := fb_EM1K0_GMD_GPI_40.PG); fb_EM1K0_GMD_GCC_50(PG := fb_EM1K0_GMD_GPI_40.PG); fb_EM1K0_GMD_GCC_60(PG := fb_EM1K0_GMD_GPI_40.PG); fb_EM1K0_GMD_GCC_70(PG := fb_EM1K0_GMD_GPI_40.PG); // Hot Cathode Gauge fb_EM1K0_GMD_GHC_40(PG := fb_EM1K0_GMD_GPI_40.PG); // FB_EbaraEVA fb_EM1K0_GMD_PRT_40(i_xExtIlkOK := TRUE); // FB_VVC IF bAutoVVC40 THEN IF fb_EM1K0_GMD_PTM_40.iq_stPtm.eState = pumpRUNNING OR fb_EM1K0_GMD_PTM_40.iq_stPtm.eState = pumpSTARTING THEN fb_EM1K0_GMD_VVC_40.M_Open(True); ELSE fb_EM1K0_GMD_VVC_40.M_Open(False); END_IF END_IF fb_EM1K0_GMD_VVC_40( i_xExtILK_OK := fb_EM1K0_GMD_PTM_40.iq_stPtm.eState = pumpRUNNING OR fb_EM1K0_GMD_PTM_40.iq_stPtm.eState = pumpSTARTING,(*F_TURBO_PROT_SLND_ILK( i_Turbo := fb_EM1K0_GMD_PTM_40.iq_stPtm, i_stISG := fb_EM1K0_GMD_GPI_40.PG, i_stBSG := fb_EM1K0_GMD_GPI_10.PG, ScrollPump := fb_EM1K0_GMD_PRT_40.stPump ),*) i_xOverrideMode := xSystemOverrideMode, ); // Roughing valve IF( fb_EM1K0_GMD_PRT_40.stPump.eState = pumpSTARTING ) OR ( fb_EM1K0_GMD_PRT_40.stPump.eState = pumpRUNNING ) THEN fb_EM1K0_GMD_VRO_40.M_Open(TRUE); END_IF fb_EM1K0_GMD_VRO_40(i_xExtILK_OK:= (fb_EM1K0_GMD_PRT_40.stPump.eState = pumpRUNNING OR fb_EM1K0_GMD_PRT_40.stPump.eState = pumpSTARTING ), i_xOverrideMode:= , iq_stValve=> ); END_PROGRAM Related: * `F_TURBO_PROT_SLND_ILK`_ * `F_TurboGateValve_Protection_ILK_local`_ PRG_HV_ILK ^^^^^^^^^^ :: PROGRAM PRG_HV_ILK VAR HV_ILK_OK: bool := false; END_VAR //evaluate the HV ILK_OK bit //HV_ILK_OK := GCC_40.IG.xAT_VAC; hv1(i_xExtIlkOK := F_HV_ILK( IG := fb_EM1K0_GMD_GCC_40.IG, HV := hv1.hv) ); END_PROGRAM Related: * `F_HV_ILK`_ 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 ); GFM_86(i_rFULL_SCALE:= rFULL_SCALE,rDefaultSP:=DefaultSP); i:=i+1; // Vent Valves // interlock evaluation VVC_80.i_xExtILK_OK := (VCN_40.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=> ); RTD(); END_PROGRAM PRG_PressureControl ^^^^^^^^^^^^^^^^^^^ :: PROGRAM PRG_PressureControl VAR CONSTANT nDataTable_NumberOfRows : INT:=9; END_VAR VAR 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..nDataTable_NumberOfRows,1..2] OF FLOAT; (* controller *) fbCTRL_PID : FB_CTRL_PID; fbCTRL_Normalize : FB_CTRL_NORMALIZE; fbCTRL_LIN_INTERPOLATION : FB_CTRL_LIN_INTERPOLATION; bInit : BOOL := TRUE; FTrig: F_TRIG; END_VAR //Set VRC upper limit IF bInit THEN VCN_40.M_SetThrottle(30); // default at start up, should be overridedn through epics pv END_IF //VCN //bAdditionalVCNIlk IF (bAdditionalVCNIlk) THEN VCN_40.i_xExtIlkOK := ( fb_EM1K0_GMD_GCC_10.IG.xAT_VAC AND fb_EM1K0_GMD_GCC_20.IG.xAT_VAC AND fb_EM1K0_GMD_GCC_30.IG.xAT_VAC AND fb_EM1K0_GMD_GCC_40.IG.xAT_VAC AND fb_EM1K0_GMD_GCC_50.IG.xAT_VAC AND fb_EM1K0_GMD_GCC_60.IG.xAT_VAC AND fb_EM1K0_GMD_GCC_70.IG.xAT_VAC) AND fb_EM1K0_GMD_GPI_40.PG.xAT_VAC AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO); ELSE VCN_40.i_xExtIlkOK := fb_EM1K0_GMD_GPI_40.PG.xAT_VAC AND (NOT VVC_81.iq_stValve.q_xOPN_DO) AND(NOT VVC_82.iq_stValve.q_xOPN_DO); END_IF //VCN VCN_40(i_xExtIlkOK :=, i_ReqPos:= ); (* Gauge selection *) (*Assign reading to psuedo gauge*) IF (fb_EM1K0_GMD_GCC_40.IG.rPRESS <=0.0001) AND (fb_EM1K0_GMD_GCC_40.IG.rPRESS >0) THEN GCP := fb_EM1K0_GMD_GCC_40.IG; ElSE GCP := fb_EM1K0_GMD_GPI_40.PG; END_IF (*-------------------------------------------------------------------*) (* PI CONTROL *) (*-------------------------------------------------------------------*) IF bInit THEN (* 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 := 20; (* maximum output limit *) stCTRL_PID_PARAMS.fOutMinLimit := -100; (* minimum output limit *) (* init array with the interpolation points *) (* fIn | fOut *) arrTable[1,1] := 0; arrTable[1,2] := 5; arrTable[2,1] := 0.000000265; arrTable[1,2] := 10; arrTable[3,1] := 0.00000319; arrTable[3,2] := 15; arrTable[4,1] := 0.0000036; arrTable[4,2] := 17; arrTable[5,1] := 0000412; arrTable[5,2] := 20; arrTable[6,1] := 0.001282; arrTable[6,2] := 31; arrTable[7,1] := 0.002136; arrTable[7,2] := 39; arrTable[8,1] := 0.0417; arrTable[8,2] := 49; arrTable[9,1] := 0.1929; arrTable[8,2] := 62; (* 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(nDataTable_NumberOfRows); (* set the mode to ACTIVE --> normal operation *) eMode := eCTRL_MODE_PASSIVE; (* 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_40.i_ReqPos:= fbCTRL_PID.fOut + fbCTRL_LIN_INTERPOLATION.fOut; IF (bReset) THEN (* set the mode to RESET*) eMode := eCTRL_MODE_RESET ; VCN_40.M_ValveControl(CloseValve); //bReset := False; ELSE (* set the mode to ACTIVE --> normal operation *) eMode := eCTRL_MODE_ACTIVE ; VCN_40.M_ValveControl(PressureControl); END_IF END_IF FTRIG(CLK := bGo); IF(FTrig.Q)THEN eMode := eCTRL_MODE_PASSIVE; VCN_40.M_ValveControl(CloseValve); fSetpointValue :=0; END_IF (* call interpolation fb *) fbCTRL_LIN_INTERPOLATION ( fIn := fSetpointValue, fManValue := fManValue, bExtrapolate := bExtrapolate, stParams := stCTRL_LIN_INTERPOLATION_PARAMS, eMode := eMode, fOut => , eErrorId => eErrorId, bError => bError ); (* call controller *) fbCTRL_PID( fSetpointValue := fSetpointValue, fActualValue := GCP.rPRESS , fManSyncValue := , bSync := bSync, eMode := eMode, bHold := bHold, stParams := stCTRL_PID_PARAMS, fOut => , bARWactive => bARWactive, eErrorId => eErrorId, bError => ); bError := fbCTRL_PID.bError OR fbCTRL_LIN_INTERPOLATION.bError; END_PROGRAM PRG_Purge ^^^^^^^^^ :: PROGRAM PRG_Purge VAR step: INT:=0; {attribute 'pytmc' := ' pv: EM1K0:GMD:sPURGE '} sMessage : STRING; {attribute 'pytmc' := ' pv: EM1K0:GMD:RESET '} bReset:BOOL := False; {attribute 'pytmc' := ' pv: EM1K0:GMD:PurgeError '} bError:BOOL := False; {attribute 'pytmc' :=' pv: EM1K0:GMD:PURGE:SP1; field: HOPR 1000; field: LOPR 0; field: PREC 2; field: EGU "TORR"; '} rPurge_SP1 :REAL :=0.01; {attribute 'pytmc' :=' pv: EM1K0:GMD:PURGE:SP2; field: HOPR 1000; field: LOPR 0; field: PREC 2; field: EGU "TORR"; '} rPurge_SP2 :REAL :=0.1; {attribute 'pytmc' :=' pv: EM1K0:GMD: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_81_Timer : TON; VVC_82_Timer : TON; 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; bPurgeActive := FALSE; VCN_40.i_xPurge := FALSE; IF (bStartPurge_sw) Then step:=10; bGo :=FALSE; bPurgeActive := true; bPurgeDone := false; iVGP_POS := VGP_40.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_40.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_40.M_ValveControl( E_VCN.CloseValve); // 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_40.M_ValveControl(E_VCN.CloseValve); VGP_40.M_SetGoSw(TRUE); IF NOT(VGP_40.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_40.q_stVGP.pv_xError ) OR NOT (VGP_40.i_xExtIlkOK) OR NOT (VGP_40.q_stVGP.pv_xHomed) THEN step:=900+step; END_IF 31: IF (VGP_40.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_40.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: VVC80 and VVC82 are 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: VVC80, 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: //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_40.M_ValveControl(E_VCN.OpenValve); IF NOT(VGP_40.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_40.q_stVGP.pv_xError ) OR NOT (VGP_40.i_xExtIlkOK) OR NOT (VGP_40.q_stVGP.pv_xHomed) THEN step:=900+step; END_IF 56: IF (VGP_40.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_40.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_40.M_ValveControl(E_VCN.PressureControl); VCN_40.i_xPurge := TRUE; VCN_40.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_40.i_xPurge := TRUE; VCN_40.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_40.i_xPurge := TRUE; VCN_40.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_40.i_xPurge := TRUE; VCN_40.i_ReqPos := 31; sMessage:= 'VCN Burp: VCN to 31%'; IF (VCN_Timer.Q) THEN step:=64; END_IF 64: VCN_40.i_xPurge := TRUE; VCN_40.i_ReqPos := 39; sMessage:= 'VCN Burp: VCN to 39%'; IF (NeedleVlvPurgeTmr.Q) THEN step:=65; END_IF 65: VCN_40.i_xPurge := TRUE; VCN_40.i_ReqPos := 49; sMessage:= 'VCN Burp: VCN to 49%'; IF (VCN_Timer.Q) THEN step:=66; END_IF 66: VCN_40.i_xPurge := TRUE; VCN_40.i_ReqPos := 62; sMessage:= 'VCN Burp: VCN to 62%'; IF (NeedleVlvPurgeTmr.Q) THEN step:=67; END_IF 67: VCN_40.i_xPurge := TRUE; VCN_40.i_ReqPos := 78; sMessage:= 'VCN Burp: VCN to 78%'; IF (VCN_Timer.Q) THEN step:=68; END_IF 68: VCN_40.i_xPurge := TRUE; VCN_40.i_ReqPos := 100; sMessage:= 'VCN Burp: VCN to 100%'; IF (NeedleVlvPurgeTmr.Q) THEN step:=70; END_IF 70: //Close Needle valve VCN_40.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_40.M_ValveControl(E_VCN.ManualControl); VGP_40.i_ReqPos:= iVGP_POS; //50% open VGP_40.M_SetGoSw(TRUE); sMessage:= 'Post: VGP to previous position'; IF NOT(VGP_40.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP encoder reads Open //use motion ready step:=91; END_IF if (VGP_40.q_stVGP.pv_xError )then step:=900+step; END_IF 91: IF (VGP_40.q_stVGP.eState = E_MoveState.READY ) THEN // wait until the VGP encoder reads Open //use motion ready VGP_40.M_ValveControl(E_VCN.ManualControl); VGP_40.i_ReqPos:= 0; VGP_40.M_SetGoSw(FALSE); step:=100; sMessage:= 'Purge Complete'; END_IF if (VGP_40.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_40.i_xPurge := FALSE; VCN_40.M_ValveControl(E_VCN.CloseValve); VGP_40.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_40.i_xPurge := FALSE; VCN_40.M_ValveControl(E_VCN.CloseValve); VGP_40.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_40.M_ValveControl(E_VCN.CloseValve); VGP_40.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_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_40.q_stVGP.pv_xError ) OR NOT (VGP_40.i_xExtIlkOK)) AND (bPurgeActive) AND (step >=55) AND (step <=70) THEN step:=900; END_IF IF NOT (VCN_40.i_xExtIlkOK) AND (bPurgeActive) AND (step >=60) AND (step <=70) THEN step:=900; END_IF IF (NOT (fb_EM1K0_GMD_PRT_40.stPump.eState = E_PumpState.pumpRUNNING)) AND (bPurgeActive) THEN step:=900; END_IF //Extra purge interlock IF (VVC_83.M_IsOpen()) OR (VVC_84.M_IsOpen()) OR (VVC_85.M_IsOpen()) OR (VVC_86.M_IsOpen()) THEN VCN_40.i_xPurge := FALSE; END_IF END_PROGRAM Related: * `E_GasType`_ * `E_MoveState`_ 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) nPort := 851, // ADS port of the PLC reading from this PLC sVarName := 'GVL_VAC_INTF.n_EM1K0_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 Related: * `GVL_VAC_INTF`_ 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] := 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; (* reset the init flag *) bInit := FALSE; END_IF VGP_40.i_xOpenIlkOK := (fb_EM1K0_GMD_PTM_40.iq_stPtm.eState = pumpRUNNING) ; VGP_40( i_xExtIlkOK:= TRUE,//(fb_EM1K0_GMD_PTM_40.iq_stPtm.eState = pumpRUNNING), i_ReqPos:= , arrTable:= arrTable , q_stVGP=> ); END_PROGRAM