diff --git a/DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT b/DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT
new file mode 100644
index 0000000..ca843cd
--- /dev/null
+++ b/DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DUTs/E_AxisParamCheckState.TcDUT b/DUTs/E_AxisParamCheckState.TcDUT
new file mode 100644
index 0000000..454580b
--- /dev/null
+++ b/DUTs/E_AxisParamCheckState.TcDUT
@@ -0,0 +1,20 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DUTs/E_AxisParameters.TcTLEO b/DUTs/E_AxisParameters.TcTLEO
index 4c799dd..82c72bc 100644
--- a/DUTs/E_AxisParameters.TcTLEO
+++ b/DUTs/E_AxisParameters.TcTLEO
@@ -3,6 +3,7 @@
diff --git a/DUTs/E_SlitSoftLimits.TcDUT b/DUTs/E_SlitSoftLimits.TcDUT
new file mode 100644
index 0000000..71496e1
--- /dev/null
+++ b/DUTs/E_SlitSoftLimits.TcDUT
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU
index adde001..793d10b 100644
--- a/POUs/Motion/FB_SlitPair.TcPOU
+++ b/POUs/Motion/FB_SlitPair.TcPOU
@@ -1,17 +1,30 @@
-
- 0) OR (stBladePositive.stStatus.nErrorID > 0) THEN
+ eSlitPairState := E_SlitPairStates.eError;
END_IF
- E_SlitPairStates.HOME_GAP: //"Home" the virtual axes
- GVL.astAxes[iGapSize].stConfig.eHomeSeq := E_HomingRoutines.eHomeDirect;
- GVL.astAxes[iGapCentre].stConfig.eHomeSeq := E_HomingRoutines.eHomeDirect;
- GVL.astAxes[iGapSize].stConfig.fHomePosition := fGapSizePosition;
- GVL.astAxes[iGapCentre].stConfig.fHomePosition := fGapCentrePosition;
- GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eHome;
- GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eHome;
- GVL.astAxes[iGapSize].stControl.bExecute := TRUE;
- GVL.astAxes[iGapCentre].stControl.bExecute := TRUE;
- eSlitPairState := E_SlitPairStates.CHECK_GAP_HOME_COMPLETE;
-
- E_SlitPairStates.CHECK_GAP_HOME_COMPLETE: //Wait for virtual homing completion
- IF bGapHomed THEN
- eSlitPairState := E_SlitPairStates.GEARIN_SLITS;
+ E_SlitPairStates.eHomeGap: //"Home" the virtual axes
+ stGapSize.stConfig.eHomeSeq := E_HomingRoutines.eHomeDirect;
+ stGapCentre.stConfig.eHomeSeq := E_HomingRoutines.eHomeDirect;
+ stGapSize.stConfig.fHomePosition := fGapSizePosition;
+ stGapCentre.stConfig.fHomePosition := fGapCentrePosition;
+ stGapSize.stControl.eCommand := E_MotionFunctions.eHome;
+ stGapCentre.stControl.eCommand := E_MotionFunctions.eHome;
+ stGapSize.stControl.bExecute := TRUE;
+ stGapCentre.stControl.bExecute := TRUE;
+ eSlitPairState := E_SlitPairStates.eCheckGapHomeComplete;
+
+ E_SlitPairStates.eCheckGapHomeComplete: //Wait for virtual homing completion
+ IF bGapHomed AND NOT stGapSize.stStatus.bBusy AND NOT stGapCentre.stStatus.bBusy THEN
+ eSlitPairState := E_SlitPairStates.eGearInSlits;
END_IF
- E_SlitPairStates.GEARIN_SLITS: //Setup gearing
+ E_SlitPairStates.eGearInSlits: //Setup gearing
actSetupSlitGearing();
- eSlitPairState := E_SlitPairStates.CHECK_GEARIN_SLITS_COMPLETE;
+ eSlitPairState := E_SlitPairStates.eCheckGearInSlitsComplete;
- E_SlitPairStates.CHECK_GEARIN_SLITS_COMPLETE: //Wait for gearing complete
+ E_SlitPairStates.eCheckGearInSlitsComplete: //Wait for gearing complete
IF bBladesCoupled THEN
- eSlitPairState := E_SlitPairStates.SLITS_OPERATIONAL;
+ eSlitPairState := E_SlitPairStates.eSlitsOperational;
+ ELSIF NOT stGapSize.stStatus.bEnabled AND NOT stGapCentre.stStatus.bEnabled THEN
+ eSlitPairState := E_SlitPairStates.eErrorGearOut;
END_IF
- E_SlitPairStates.SLITS_OPERATIONAL: //SLITS OPERATIONAL - Monitor for any gear outs and re-gear when no busy blades
+ E_SlitPairStates.eSlitsOperational: //SLITS OPERATIONAL - Monitor for any gear outs and re-gear when no busy blades
bEnabled := TRUE;
- IF NOT bBladesCoupled AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN
- eSlitPairState := E_SlitPairStates.GEAROUT_BLADES;
+ checkSoftLimits(stGapSize, stGapCentre); //Soft limits are updated when axes are stopped
+ IF (NOT bBladesCoupled OR NOT bEnable) AND NOT stBladeNegative.stStatus.bBusy AND NOT stBladePositive.stStatus.bBusy THEN
+ eSlitPairState := E_SlitPairStates.eGearOutBlades;
+ END_IF
+ IF (stGapSize.stControl.eCommand = E_MotionFunctions.eHome AND stGapSize.stControl.bExecute) OR
+ (stGapCentre.stControl.eCommand = E_MotionFunctions.eHome AND stGapCentre.stControl.bExecute) THEN
+ eSlitPairState := E_SlitPairStates.eGearOutBlades;
+ bHomingRequested := TRUE;
END_IF
- E_SlitPairStates.GEAROUT_BLADES: //Clear amy residual gearing
+ E_SlitPairStates.eGearOutBlades: //Clear any residual gearing
actClearSlitGearing();
- eSlitPairState := E_SlitPairStates.CHECK_GEAROUT_COMPLETE;
+ eSlitPairState := E_SlitPairStates.eCheckGearOutComplete;
- E_SlitPairStates.CHECK_GEAROUT_COMPLETE: //Check gearing cleared
+ E_SlitPairStates.eCheckGearOutComplete: //Check gearing cleared
IF bBladesUncoupled THEN
- eSlitPairState := E_SlitPairStates.CLEAR_GAP_CALIBRATION; //Back to homing, this ensures the setpoint position of the axis is updated.
+ IF bHomingRequested THEN
+ eSlitPairState := E_SlitPairStates.eResetCalibration;
+ bEnabled := FALSE;
+ ELSE
+ eSlitPairState := E_SlitPairStates.eInit;
+ END_IF
END_IF
- E_SlitPairStates.CLEAR_GAP_CALIBRATION:
- mcHomeGapSize.Execute := TRUE;
- mcHomeGapCentre.Execute := TRUE;
- IF mcHomeGapSize.Done AND mcHomeGapCentre.Done THEN
- eSlitPairState := E_SlitPairStates.HOME_GAP; //Back to homing, this ensures the setpoint position of the axis is updated.
+ E_SlitPairStates.eResetCalibration:
+ IF checkResetCalibrationDone() THEN
+ eSlitPairState := E_SlitPairStates.eCheckHomeStatus;
+ ELSIF checkResetCalibrationFailed() THEN
+ eSlitPairState := E_SlitPairStates.eError;
END_IF
- E_SlitPairStates.ERROR: //ERROR STATE
- resetCounterTimeout := 0;
+ E_SlitPairStates.eError: //ERROR STATE
+ nAutoErrorResetCounter := 0;
bError := TRUE;
bEnabled := FALSE;
+ actStopAxes();
IF bReset THEN
bResetting := TRUE;
- eSlitPairState := E_SlitPairStates.ERROR_GEAROUT;
+ eSlitPairState := E_SlitPairStates.eErrorGearOut;
END_IF
- E_SlitPairStates.ERROR_GEAROUT: //Try to clear issues
+ E_SlitPairStates.eErrorGearOut: //Try to clear issues
actClearSlitGearing();
- eSlitPairState := E_SlitPairStates.ERROR_GEAROUT_CHECK;
+ eSlitPairState := E_SlitPairStates.eErrorGearOutCheck;
- E_SlitPairStates.ERROR_GEAROUT_CHECK:
+ E_SlitPairStates.eErrorGearOutCheck:
IF bBladesUncoupled THEN
- eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES; //Back to homing, this ensures the setpoint position of the axis is updated.
+ eSlitPairState := E_SlitPairStates.eErrorResetAxes;
END_IF
- E_SlitPairStates.ERROR_RESET_AXES: //RESET ALL AXES
- GVL.astAxes[iBladeNegative].stControl.bReset := TRUE;
- GVL.astAxes[iBladePositive].stControl.bReset := TRUE;
- GVL.astAxes[iGapSize].stControl.bReset := TRUE;
- GVL.astAxes[iGapCentre].stControl.bReset := TRUE;
- resetCounterTimeout := resetCounterTimeout + 1;
- eSlitPairState := E_SlitPairStates.ERROR_RESET_CHECK;
-
- E_SlitPairStates.ERROR_RESET_CHECK:
- IF resetCounterTimeout > 10 THEN
- eSlitPairState := E_SlitPairStates.ERROR;
- bResetting := FALSE;
- RETURN;
- END_IF
+ E_SlitPairStates.eErrorResetAxes: //RESET ALL AXES
+ stBladeNegative.stControl.bReset := TRUE;
+ stBladePositive.stControl.bReset := TRUE;
+ stGapSize.stControl.bReset := TRUE;
+ stGapCentre.stControl.bReset := TRUE;
+ nAutoErrorResetCounter := nAutoErrorResetCounter + 1;
+ eSlitPairState := E_SlitPairStates.eErrorResetCheck;
+
+ E_SlitPairStates.eErrorResetCheck:
IF bAxisErrorsPresent THEN
- eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES;
+ //If the errors persists after 10 auto reset, then manual intervention is required
+ IF nAutoErrorResetCounter <= 10 THEN
+ eSlitPairState := E_SlitPairStates.eErrorResetAxes;
+ END_IF
ELSE
- eSlitPairState := E_SlitPairStates.INIT;
+ eSlitPairState := E_SlitPairStates.eInit;
+ nAutoErrorResetCounter := 0;
bError := FALSE;
bResetting := FALSE;
END_IF
END_CASE
+
bReset := FALSE;
]]>
+
+
+ = (stBladePositive.stStatus.fActPosition - fAnticollisionMargin);
+
+ E_MotionFunctions.eMoveRelative:
+ stBladeNegative.stControl.bInterlockFwd := stBladeNegative.stControl.bExecute
+ AND (stBladeNegative.stControl.fPosition + stBladeNegative.stStatus.fActPosition) >= (stBladePositive.stStatus.fActPosition - fAnticollisionMargin);
+
+ ELSE
+ stBladeNegative.stControl.bInterlockFwd := FALSE;
+
+END_CASE
+
+//Check if current position is outside the anticollision margin
+stBladeNegative.stControl.bInterlockFwd :=
+ (stBladeNegative.stControl.bInterlockFwd OR stBladeNegative.stStatus.fActPosition >= (stBladePositive.stStatus.fActPosition - fAnticollisionMargin))
+ AND bBladesHomed
+ AND bBladesUncoupled
+ AND bAnticollisionEnable;
+
+//Positive Blade
+
+//If executing absolute / relative movement commands also check target position
+CASE stBladePositive.stControl.eCommand OF
+
+ E_MotionFunctions.eMoveAbsolute:
+ stBladePositive.stControl.bInterlockBwd := stBladePositive.stControl.bExecute
+ AND stBladePositive.stControl.fPosition <= (stBladeNegative.stStatus.fActPosition + fAnticollisionMargin);
+
+ E_MotionFunctions.eMoveRelative:
+ stBladePositive.stControl.bInterlockBwd := stBladePositive.stControl.bExecute
+ AND (stBladePositive.stControl.fPosition + stBladePositive.stStatus.fActPosition) <= (stBladeNegative.stStatus.fActPosition + fAnticollisionMargin);
+
+ ELSE
+ stBladePositive.stControl.bInterlockBwd := FALSE;
+
+END_CASE
+
+//Check if current position is outside the anticollision margin
+stBladePositive.stControl.bInterlockBwd :=
+ (stBladePositive.stControl.bInterlockBwd OR stBladePositive.stStatus.fActPosition <= (stBladeNegative.stStatus.fActPosition + fAnticollisionMargin))
+ AND bBladesHomed
+ AND bBladesUncoupled
+ AND bAnticollisionEnable;
+]]>
+
+
+
+
+
+
+
+
+
+
+
+
@@ -206,77 +377,156 @@ IF bResetting THEN //ignore setting in error state if FB going through a reset
RETURN;
END_IF
-IF NOT bError AND bAxisErrorsPresent THEN
- eSlitPairState := E_SlitPairStates.ERROR;
-END_IF
-IF eSlitPairState <> E_SlitPairStates.INIT AND NOT bAxesEnabled THEN
- eSlitPairState := E_SlitPairStates.ERROR;
+//RESET - Use the reset from the virtual axes in order to reset the slits
+bReset := stGapCentre.stControl.bReset OR stGapSize.stControl.bReset;
+
+IF NOT bError AND bAxisErrorsPresent AND (stGapCentre.stStatus.bEnabled OR stGapSize.stStatus.bEnabled) THEN
+ eSlitPairState := E_SlitPairStates.eError;
END_IF
-IF (eSlitPairState <> E_SlitPairStates.INIT AND NOT bFunctionInErrorState) AND NOT bEnable THEN
- eSlitPairState := E_SlitPairStates.ERROR;
+
+//Report error to virtual axes
+IF eSlitPairState = E_SlitPairStates.eError THEN
+ stGapCentre.stStatus.bError := TRUE;
+ stGapSize.stStatus.bError := TRUE;
END_IF
+
IF bEnabled AND NOT bBladesHomed THEN
- eSlitPairState := E_SlitPairStates.ERROR;
+ eSlitPairState := E_SlitPairStates.eError;
END_IF
]]>
-
-
+
- bAxesEnabled);
-checkBladesHomed(bOutput => bBladesHomed);
-checkVirtualHomed(bOutput => bGapHomed);
-checkBladesCoupled(bOutput => bBladesCoupled);
-checkBladesUncoupled(bOutput => bBladesUncoupled);
-checkAllAxisErrors(bOutput => bAxisErrorsPresent);
-checkErrorState(bOutput => bFunctionInErrorState);
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
@@ -285,145 +535,249 @@ END_IF
-
-
+
-
-
-
-
-
-
+
-
-
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+ cParameters[iParamCheck].fValue THEN
+ sWarnMsg := CONCAT(
+ STR1 := 'Slit virtual axis Gap Size (AxisId=%d) has an invalid parameter of ',
+ STR2 := TO_STRING(cParameters[iParamCheck].eParam));
+
+ ADSLOGDINT(
+ msgCtrlMask := ADSLOG_MSGTYPE_WARN,
+ msgFmtStr := sWarnMsg,
+ dintArg := TO_DINT(iGapSize));
+ END_IF
+ //Gap Centre
+ IF stGapCentre.stConfig.fReadAxisParameter <> cParameters[iParamCheck].fValue THEN
+ sWarnMsg := CONCAT(
+ STR1 := 'Slit virtual axis Gap Centre (AxisId=%d) has an invalid parameter of ',
+ STR2 := TO_STRING(cParameters[iParamCheck].eParam));
+
+ ADSLOGDINT(
+ msgCtrlMask := ADSLOG_MSGTYPE_WARN,
+ msgFmtStr := sWarnMsg,
+ dintArg := TO_DINT(iGapCentre));
+ END_IF
+ bInvalidParamFound := TRUE;
+
+ eParameterCheck := E_AxisParamCheckState.eNext;
+
+ E_AxisParamCheckState.eNext:
+ IF iParamCheck = cMaxParams THEN
+ IF NOT bInvalidParamFound THEN
+ ADSLOGSTR(
+ msgCtrlMask := ADSLOG_MSGTYPE_LOG,
+ msgFmtStr := 'Slit all parameters of both virtual axes are valid',
+ strArg := '');
+ END_IF
+ eParameterCheck := E_AxisParamCheckState.eFinish;
+ ELSE
+ ;
+ iParamCheck := iParamCheck + 1;
+ eParameterCheck := E_AxisParamCheckState.eSelectParam;
+ END_IF
+
+
+ E_AxisParamCheckState.eFinish:
+ ;
+
+END_CASE
]]>