DUTs
E_GasType
TYPE E_GasType :
(
none := 0,
Neon,
Argon,
Krypton,
Xenon
);
END_TYPE
- Related:
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:
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:
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:
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:
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:
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:
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:
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
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:
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
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:
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:
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:
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