From 5a7fe5b546919a7211358fa993b486ac4ec81ccd Mon Sep 17 00:00:00 2001 From: rubenmess Date: Fri, 12 Sep 2025 13:32:56 +0200 Subject: [PATCH 01/39] FB_SlitPair updated with improvements (soft limits update, operational mode, homing --- DUTs/E_SlitSoftLimits.TcDUT | 16 +++ POUs/Motion/FB_SlitPair.TcPOU | 256 ++++++++++++++++++++++++++++------ 2 files changed, 228 insertions(+), 44 deletions(-) create mode 100644 DUTs/E_SlitSoftLimits.TcDUT diff --git a/DUTs/E_SlitSoftLimits.TcDUT b/DUTs/E_SlitSoftLimits.TcDUT new file mode 100644 index 00000000..97e44d26 --- /dev/null +++ b/DUTs/E_SlitSoftLimits.TcDUT @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index adde0016..0f2d221c 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -1,8 +1,7 @@  - + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; // Sequence steps for update of soft limits + fbNoMovingRising: R_TRIG; + fbInOpRising: R_TRIG; + bUpdateSoftLimits: BOOL := FALSE; + bHomingRequested: BOOL := FALSE; + fbEnableRising: R_TRIG; + fbStopRising: R_TRIG; + fbDisableRising: R_TRIG; + fbDisabledRising: R_TRIG; + fbHomingRising: R_TRIG; +END_VAR]]> 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID >0) THEN + eSlitPairState := E_SlitPairStates.ERROR; END_IF E_SlitPairStates.HOME_GAP: //"Home" the virtual axes @@ -111,8 +131,9 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.CHECK_GAP_HOME_COMPLETE; E_SlitPairStates.CHECK_GAP_HOME_COMPLETE: //Wait for virtual homing completion - IF bGapHomed THEN + IF bGapHomed AND NOT GVL.astAxes[iGapSize].stStatus.bBusy AND NOT GVL.astAxes[iGapCentre].stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.GEARIN_SLITS; + bHomingRequested := FALSE; END_IF E_SlitPairStates.GEARIN_SLITS: //Setup gearing @@ -126,9 +147,15 @@ CASE eSlitPairState OF E_SlitPairStates.SLITS_OPERATIONAL: //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 + checkSoftLimits(); // Soft limits are updated when axes are stopped + IF (NOT bBladesCoupled OR NOT bEnable) AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; END_IF + IF (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR + (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN + eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; + bHomingRequested := TRUE; + END_IF E_SlitPairStates.GEAROUT_BLADES: //Clear amy residual gearing actClearSlitGearing(); @@ -136,20 +163,19 @@ CASE eSlitPairState OF E_SlitPairStates.CHECK_GEAROUT_COMPLETE: //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. - 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. + IF bHomingRequested THEN + eSlitPairState := E_SlitPairStates.HOME_BLADES; + bEnabled := FALSE; + ELSE + eSlitPairState := E_SlitPairStates.INIT; + END_IF END_IF E_SlitPairStates.ERROR: //ERROR STATE resetCounterTimeout := 0; bError := TRUE; bEnabled := FALSE; + actStopAxes(); IF bReset THEN bResetting := TRUE; eSlitPairState := E_SlitPairStates.ERROR_GEAROUT; @@ -186,6 +212,7 @@ CASE eSlitPairState OF bResetting := FALSE; END_IF END_CASE + bReset := FALSE; ]]> @@ -196,6 +223,41 @@ GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eGearOut; GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eGearOut; GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; +]]> + + + + + @@ -206,15 +268,18 @@ IF bResetting THEN //ignore setting in error state if FB going through a reset RETURN; END_IF +// RESET - Use the reset from the virtual axes in order to reset the slits +bReset := GVL.astAxes[iGapCentre].stControl.bReset OR GVL.astAxes[iGapSize].stControl.bReset; + 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; -END_IF -IF (eSlitPairState <> E_SlitPairStates.INIT AND NOT bFunctionInErrorState) AND NOT bEnable THEN - eSlitPairState := E_SlitPairStates.ERROR; -END_IF +//IF eSlitPairState <> E_SlitPairStates.INIT AND NOT bAxesEnabled THEN +// eSlitPairState := E_SlitPairStates.ERROR; +//END_IF +//IF (eSlitPairState <> E_SlitPairStates.INIT AND NOT bFunctionInErrorState) AND NOT bEnable THEN +// eSlitPairState := E_SlitPairStates.ERROR; +//END_IF IF bEnabled AND NOT bBladesHomed THEN eSlitPairState := E_SlitPairStates.ERROR; END_IF @@ -224,11 +289,19 @@ END_IF +GVL.astAxes[iGapSize].stInputs.bLimitBwd := GVL.astAxes[iBladeNegative].stInputs.bLimitFwd OR GVL.astAxes[iBladePositive].stInputs.bLimitBwd; +GVL.astAxes[iGapSize].stInputs.bLimitFwd := GVL.astAxes[iBladeNegative].stInputs.bLimitBwd OR GVL.astAxes[iBladePositive].stInputs.bLimitFwd;; +GVL.astAxes[iGapCentre].stInputs.bLimitBwd := GVL.astAxes[iBladeNegative].stInputs.bLimitFwd OR GVL.astAxes[iBladePositive].stInputs.bLimitBwd;; +GVL.astAxes[iGapCentre].stInputs.bLimitFwd :=GVL.astAxes[iBladeNegative].stInputs.bLimitBwd OR GVL.astAxes[iBladePositive].stInputs.bLimitFwd;;]]> + + + + + = GVL.astAxes[iBladePositive].stStatus.fActPosition + OR GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition ; +GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition + OR GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition ;]]> @@ -260,6 +333,68 @@ GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; ]]> + + + + + + + + = 0.0 THEN + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit + - GVL.astAxes[iGapCentre].stStatus.fActPosition); + ELSE + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + - GVL.astAxes[iGapCentre].stStatus.fActPosition); + END_IF + END_IF + +E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: //WRITE GAP SIZE FWD SOFT LIMIT DONE. + + IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.START; + bUpdateSoftLimits := FALSE; + END_IF + +END_CASE]]> + + +END_IF]]> @@ -409,6 +543,40 @@ END_IF ]]> + + + + + + + + + + + + Date: Fri, 12 Sep 2025 14:46:04 +0200 Subject: [PATCH 02/39] formating fix --- POUs/Motion/FB_SlitPair.TcPOU | 221 ++++++++++++++++++---------------- 1 file changed, 114 insertions(+), 107 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 0f2d221c..65c1c919 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -11,7 +11,7 @@ VAR_INPUT bReset: BOOL; //Reset the slit set fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; // Blades homing is automatically done if they are not homed - bAnticolisionEnable : BOOL := FALSE; // Blades anticolision option, only for when blades are moved independiently + bAnticolisionEnable : BOOL := FALSE; // Blades anticolision option, only for when blades are moved independiently END_VAR VAR_OUTPUT @@ -25,7 +25,7 @@ VAR //Internal statuses for logic bResetting: BOOL := FALSE; //TRUE if axis going through a reset bAxesEnabled: BOOL := FALSE; //TRUE if all axes enabled - bSlitsHomed : BOOL := FALSE; //TRUE if all axes Homed after reboot + bSlitsHomed : BOOL := FALSE; //TRUE if all axes Homed after reboot bBladesHomed: BOOL:= FALSE; //TRUE if blade axes are calibrated bGapHomed: BOOL:= FALSE; //TRUE if virtual axes are calibrated bBladesCoupled: BOOL:= FALSE; //TRUE if both blade axes are coupled @@ -37,17 +37,18 @@ VAR fGapCentrePosition: LREAL; iGapCentrePosition AT %Q*: UDINT := 0; resetCounterTimeout: UINT :=0; - eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; // Sequence steps for update of soft limits - fbNoMovingRising: R_TRIG; - fbInOpRising: R_TRIG; - bUpdateSoftLimits: BOOL := FALSE; - bHomingRequested: BOOL := FALSE; - fbEnableRising: R_TRIG; - fbStopRising: R_TRIG; - fbDisableRising: R_TRIG; - fbDisabledRising: R_TRIG; - fbHomingRising: R_TRIG; -END_VAR]]> + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; // Sequence steps for update of soft limits + fbNoMovingRising: R_TRIG; + fbInOpRising: R_TRIG; + bUpdateSoftLimits: BOOL := FALSE; + bHomingRequested: BOOL := FALSE; + fbEnableRising: R_TRIG; + fbStopRising: R_TRIG; + fbDisableRising: R_TRIG; + fbDisabledRising: R_TRIG; + fbHomingRising: R_TRIG; +END_VAR +]]> 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID >0) THEN - eSlitPairState := E_SlitPairStates.ERROR; + ELSIF (GVL.astAxes[iBladeNegative].stStatus.nErrorID > 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID >0) THEN + eSlitPairState := E_SlitPairStates.ERROR; END_IF E_SlitPairStates.HOME_GAP: //"Home" the virtual axes @@ -133,7 +134,7 @@ CASE eSlitPairState OF E_SlitPairStates.CHECK_GAP_HOME_COMPLETE: //Wait for virtual homing completion IF bGapHomed AND NOT GVL.astAxes[iGapSize].stStatus.bBusy AND NOT GVL.astAxes[iGapCentre].stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.GEARIN_SLITS; - bHomingRequested := FALSE; + bHomingRequested := FALSE; END_IF E_SlitPairStates.GEARIN_SLITS: //Setup gearing @@ -147,15 +148,15 @@ CASE eSlitPairState OF E_SlitPairStates.SLITS_OPERATIONAL: //SLITS OPERATIONAL - Monitor for any gear outs and re-gear when no busy blades bEnabled := TRUE; - checkSoftLimits(); // Soft limits are updated when axes are stopped + checkSoftLimits(); // Soft limits are updated when axes are stopped IF (NOT bBladesCoupled OR NOT bEnable) AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; END_IF - IF (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR - (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN - eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; - bHomingRequested := TRUE; - END_IF + IF (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR + (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN + eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; + bHomingRequested := TRUE; + END_IF E_SlitPairStates.GEAROUT_BLADES: //Clear amy residual gearing actClearSlitGearing(); @@ -163,19 +164,19 @@ CASE eSlitPairState OF E_SlitPairStates.CHECK_GEAROUT_COMPLETE: //Check gearing cleared IF bBladesUncoupled THEN - IF bHomingRequested THEN - eSlitPairState := E_SlitPairStates.HOME_BLADES; - bEnabled := FALSE; - ELSE - eSlitPairState := E_SlitPairStates.INIT; - END_IF + IF bHomingRequested THEN + eSlitPairState := E_SlitPairStates.HOME_BLADES; + bEnabled := FALSE; + ELSE + eSlitPairState := E_SlitPairStates.INIT; + END_IF END_IF E_SlitPairStates.ERROR: //ERROR STATE resetCounterTimeout := 0; bError := TRUE; bEnabled := FALSE; - actStopAxes(); + actStopAxes(); IF bReset THEN bResetting := TRUE; eSlitPairState := E_SlitPairStates.ERROR_GEAROUT; @@ -233,11 +234,11 @@ GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; fbEnableRising(CLK := GVL.astAxes[iGapSize].stControl.bEnable OR GVL.astAxes[iGapCentre].stControl.bEnable ); IF fbEnableRising.Q THEN - GVL.astAxes[iBladePositive].stControl.bEnable := TRUE; - GVL.astAxes[iBladeNegative].stControl.bEnable := TRUE; - GVL.astAxes[iGapSize].stControl.bEnable := TRUE; - GVL.astAxes[iGapCentre].stControl.bEnable := TRUE; - bEnable := TRUE; + GVL.astAxes[iBladePositive].stControl.bEnable := TRUE; + GVL.astAxes[iBladeNegative].stControl.bEnable := TRUE; + GVL.astAxes[iGapSize].stControl.bEnable := TRUE; + GVL.astAxes[iGapCentre].stControl.bEnable := TRUE; + bEnable := TRUE; END_IF @@ -245,19 +246,19 @@ END_IF fbDisableRising(CLK := NOT GVL.astAxes[iGapSize].stControl.bEnable OR NOT GVL.astAxes[iGapCentre].stControl.bEnable ); IF fbDisableRising.Q THEN - GVL.astAxes[iBladePositive].stControl.bEnable := FALSE; - GVL.astAxes[iBladeNegative].stControl.bEnable := FALSE; - GVL.astAxes[iGapSize].stControl.bEnable := FALSE; - GVL.astAxes[iGapCentre].stControl.bEnable := FALSE; + GVL.astAxes[iBladePositive].stControl.bEnable := FALSE; + GVL.astAxes[iBladeNegative].stControl.bEnable := FALSE; + GVL.astAxes[iGapSize].stControl.bEnable := FALSE; + GVL.astAxes[iGapCentre].stControl.bEnable := FALSE; END_IF // Set Enable flag when all axes are enabled -bEnable := GVL.astAxes[iBladePositive].stStatus.bEnabled AND GVL.astAxes[iBladeNegative].stStatus.bEnabled - AND GVL.astAxes[iGapSize].stStatus.bEnabled AND GVL.astAxes[iGapCentre].stStatus.bEnabled; +bEnable := GVL.astAxes[iBladePositive].stStatus.bEnabled AND GVL.astAxes[iBladeNegative].stStatus.bEnabled + AND GVL.astAxes[iGapSize].stStatus.bEnabled AND GVL.astAxes[iGapCentre].stStatus.bEnabled; -// Set flag when all axis are disable -fbDisabledRising(CLK := NOT GVL.astAxes[iBladePositive].stStatus.bEnabled AND GVL.astAxes[iBladeNegative].stStatus.bEnabled - AND GVL.astAxes[iGapSize].stStatus.bEnabled AND GVL.astAxes[iGapCentre].stStatus.bEnabled); +// Set flag when all axis are disable +fbDisabledRising(CLK := NOT GVL.astAxes[iBladePositive].stStatus.bEnabled AND GVL.astAxes[iBladeNegative].stStatus.bEnabled + AND GVL.astAxes[iGapSize].stStatus.bEnabled AND GVL.astAxes[iGapCentre].stStatus.bEnabled); ]]> @@ -292,16 +293,18 @@ END_IF GVL.astAxes[iGapSize].stInputs.bLimitBwd := GVL.astAxes[iBladeNegative].stInputs.bLimitFwd OR GVL.astAxes[iBladePositive].stInputs.bLimitBwd; GVL.astAxes[iGapSize].stInputs.bLimitFwd := GVL.astAxes[iBladeNegative].stInputs.bLimitBwd OR GVL.astAxes[iBladePositive].stInputs.bLimitFwd;; GVL.astAxes[iGapCentre].stInputs.bLimitBwd := GVL.astAxes[iBladeNegative].stInputs.bLimitFwd OR GVL.astAxes[iBladePositive].stInputs.bLimitBwd;; -GVL.astAxes[iGapCentre].stInputs.bLimitFwd :=GVL.astAxes[iBladeNegative].stInputs.bLimitBwd OR GVL.astAxes[iBladePositive].stInputs.bLimitFwd;;]]> +GVL.astAxes[iGapCentre].stInputs.bLimitFwd :=GVL.astAxes[iBladeNegative].stInputs.bLimitBwd OR GVL.astAxes[iBladePositive].stInputs.bLimitFwd;; +]]> = GVL.astAxes[iBladePositive].stStatus.fActPosition - OR GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition ; -GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition - OR GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition ;]]> + OR GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition ; +GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition + OR GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition ; +]]> @@ -351,48 +354,49 @@ GVL.astAxes[iGapCentre].stControl.bStop := TRUE; CASE eSoftLimitsUpdate OF E_SlitSoftLimits.START: //START SEQ Software limit center gap fwd (When not busy start) - IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := (GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - GVL.astAxes[iGapSize].stStatus.fActPosition/2); - END_IF - + IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN + eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD; + GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; + GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := (GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit + - GVL.astAxes[iGapSize].stStatus.fActPosition/2); + END_IF + E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: //WRITE GAP CENTRE FWD SOFT LIMIT DONE. Calculate software limit center gap bwd - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := (GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - + GVL.astAxes[iGapSize].stStatus.fActPosition/2); - END_IF - + IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD; + GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; + GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; + GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := (GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + + GVL.astAxes[iGapSize].stStatus.fActPosition/2); + END_IF + E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: //WRITE GAP CENTRE BWD SOFT LIMIT DONE. Calculate software limit gap size fwd - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_SIZE_FWD; - GVL.astAxes[iGapSize].stControl.bExecute := TRUE; - GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - IF GVL.astAxes[iGapCentre].stStatus.fActPosition >= 0.0 THEN - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - GVL.astAxes[iGapCentre].stStatus.fActPosition); - ELSE - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - - GVL.astAxes[iGapCentre].stStatus.fActPosition); - END_IF - END_IF - + IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_SIZE_FWD; + GVL.astAxes[iGapSize].stControl.bExecute := TRUE; + GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + IF GVL.astAxes[iGapCentre].stStatus.fActPosition >= 0.0 THEN + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit + - GVL.astAxes[iGapCentre].stStatus.fActPosition); + ELSE + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + - GVL.astAxes[iGapCentre].stStatus.fActPosition); + END_IF + END_IF + E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: //WRITE GAP SIZE FWD SOFT LIMIT DONE. - - IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.START; - bUpdateSoftLimits := FALSE; - END_IF -END_CASE]]> + IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.START; + bUpdateSoftLimits := FALSE; + END_IF + +END_CASE +]]> @@ -497,7 +501,8 @@ END_VAR END_IF IF NOT GVL.astAxes[iBladePositive].stStatus.bHomed THEN bOutput := FALSE; -END_IF]]> +END_IF +]]> @@ -552,11 +557,12 @@ VAR_OUTPUT END_VAR ]]> - + bSlitsHomed := TRUE; +END_IF +]]> @@ -569,12 +575,13 @@ END_VAR fbInOpRising(CLK := eSlitPairState = E_SlitPairStates.SLITS_OPERATIONAL); IF fbNoMovingRising.Q OR fbInOpRising.Q THEN - bUpdateSoftLimits := TRUE; + bUpdateSoftLimits := TRUE; END_IF IF bUpdateSoftLimits THEN - actUpdateSoftLimits(); -END_IF]]> + actUpdateSoftLimits(); +END_IF +]]> From 21c4fc3f570f8dedff1e9c4392ec35a5e1577cab Mon Sep 17 00:00:00 2001 From: rubenmess Date: Fri, 12 Sep 2025 16:31:49 +0200 Subject: [PATCH 03/39] FB_Axis update, take away multiaxes 3 and 4 to avoid issue coupling issues --- POUs/Motion/FB_Axis.TcPOU | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/POUs/Motion/FB_Axis.TcPOU b/POUs/Motion/FB_Axis.TcPOU index 3cf7d837..ef4ed29d 100644 --- a/POUs/Motion/FB_Axis.TcPOU +++ b/POUs/Motion/FB_Axis.TcPOU @@ -643,8 +643,8 @@ IF _stAxis.stControl.eCommand = E_MotionFunctions.eGearInMultiMaster AND _stAxis //Transfer gear ratios to FB fbGearInMultiMaster.GearRatio1 := _stAxis.stConfig.astMultiMasterAxisLatched[1].fRatio; fbGearInMultiMaster.GearRatio2 := _stAxis.stConfig.astMultiMasterAxisLatched[2].fRatio; - fbGearInMultiMaster.GearRatio3 := _stAxis.stConfig.astMultiMasterAxisLatched[3].fRatio; - fbGearInMultiMaster.GearRatio4 := _stAxis.stConfig.astMultiMasterAxisLatched[4].fRatio; +// fbGearInMultiMaster.GearRatio3 := _stAxis.stConfig.astMultiMasterAxisLatched[3].fRatio; (Not in use, commented due to slits code) +// fbGearInMultiMaster.GearRatio4 := _stAxis.stConfig.astMultiMasterAxisLatched[4].fRatio; (Not in use, commented due to slits code) fbGearInMultiMaster.Enable := TRUE; END_IF From 379e4506b5b814aee25dbefea7c66d5fe00e5b46 Mon Sep 17 00:00:00 2001 From: rubenmess Date: Fri, 19 Sep 2025 15:41:40 +0200 Subject: [PATCH 04/39] enable and reset out of the inputs var --- POUs/Motion/FB_SlitPair.TcPOU | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 65c1c919..7782b03b 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -7,8 +7,6 @@ VAR_INPUT iBladePositive: UINT; //Axis ID for positively positioned blade iGapSize: UINT; //Axis ID for the size of gap between slit blades iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades - bEnable: BOOL; //Enable/disable the slit set - bReset: BOOL; //Reset the slit set fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; // Blades homing is automatically done if they are not homed bAnticolisionEnable : BOOL := FALSE; // Blades anticolision option, only for when blades are moved independiently @@ -23,6 +21,8 @@ VAR eSlitPairState: E_SlitPairStates := E_SlitPairStates.INIT; //statemachine index //Internal statuses for logic + bEnable: BOOL; //Enable/disable the slit set + bReset: BOOL; //Reset the slit set bResetting: BOOL := FALSE; //TRUE if axis going through a reset bAxesEnabled: BOOL := FALSE; //TRUE if all axes enabled bSlitsHomed : BOOL := FALSE; //TRUE if all axes Homed after reboot From 8cbfe3ebf24bb5daf81be973fd5a604e4ee1d67f Mon Sep 17 00:00:00 2001 From: rubenmess Date: Mon, 29 Sep 2025 09:47:54 +0200 Subject: [PATCH 05/39] error report to virtual axis --- POUs/Motion/FB_SlitPair.TcPOU | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 7782b03b..3e3e21e0 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -275,6 +275,13 @@ bReset := GVL.astAxes[iGapCentre].stControl.bReset OR GVL.astAxes[iGapSize].stCo IF NOT bError AND bAxisErrorsPresent THEN eSlitPairState := E_SlitPairStates.ERROR; END_IF + +// Report error to virtual axes +IF eSlitPairState = E_SlitPairStates.ERROR THEN + GVL.astAxes[iGapCentre].stStatus.bError := TRUE; + GVL.astAxes[iGapSize].stStatus.bError := TRUE; +END_IF + //IF eSlitPairState <> E_SlitPairStates.INIT AND NOT bAxesEnabled THEN // eSlitPairState := E_SlitPairStates.ERROR; //END_IF From 7db5edc2ce4ae5b9b94c554c7fcde681c107caee Mon Sep 17 00:00:00 2001 From: rubenmess Date: Fri, 10 Oct 2025 14:02:47 +0200 Subject: [PATCH 06/39] multimaster index 3&4 not used, gear out if axes disabled --- POUs/Motion/FB_Axis.TcPOU | 6 +++--- POUs/Motion/FB_SlitPair.TcPOU | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/POUs/Motion/FB_Axis.TcPOU b/POUs/Motion/FB_Axis.TcPOU index ef4ed29d..5d8b5ee3 100644 --- a/POUs/Motion/FB_Axis.TcPOU +++ b/POUs/Motion/FB_Axis.TcPOU @@ -650,9 +650,9 @@ END_IF fbGearInMultiMaster(Slave := _stAxis.Axis, Master1 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[1].nIndex].Axis, - Master2 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[2].nIndex].Axis, - Master3 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[3].nIndex].Axis, - Master4 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[4].nIndex].Axis); + Master2 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[2].nIndex].Axis); +// Master3 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[3].nIndex].Axis, +// Master4 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[4].nIndex].Axis); fbGearInMultiMaster.Enable:= FALSE; IF fbGearInMultiMaster.InGear THEN diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 3e3e21e0..d0d05761 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -144,6 +144,8 @@ CASE eSlitPairState OF E_SlitPairStates.CHECK_GEARIN_SLITS_COMPLETE: //Wait for gearing complete IF bBladesCoupled THEN eSlitPairState := E_SlitPairStates.SLITS_OPERATIONAL; + ELSIF NOT GVL.astAxes[iGapSize].stStatus.bEnabled AND NOT GVL.astAxes[iGapCentre].stStatus.bEnabled THEN + eSlitPairState := E_SlitPairStates.ERROR_GEAROUT; END_IF E_SlitPairStates.SLITS_OPERATIONAL: //SLITS OPERATIONAL - Monitor for any gear outs and re-gear when no busy blades From 94ae53e1e8d20ab66fb37997ecd1601fe188a08e Mon Sep 17 00:00:00 2001 From: rubenmess Date: Mon, 24 Nov 2025 08:23:19 +0100 Subject: [PATCH 07/39] SOFT LIMITS FUNCTION UPDATE Update soft limits to have a better understanding of the sequence. New step finish added --- DUTs/E_SlitSoftLimits.TcDUT | 3 ++- POUs/Motion/FB_SlitPair.TcPOU | 44 ++++++++++++++++++----------------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/DUTs/E_SlitSoftLimits.TcDUT b/DUTs/E_SlitSoftLimits.TcDUT index 97e44d26..c2610442 100644 --- a/DUTs/E_SlitSoftLimits.TcDUT +++ b/DUTs/E_SlitSoftLimits.TcDUT @@ -8,7 +8,8 @@ TYPE E_SlitSoftLimits : START := 0, WRITE_GAP_CENTRE_FWD, WRITE_GAP_CENTRE_BWD, - WRITE_GAP_SIZE_FWD + WRITE_GAP_SIZE_FWD, + FINISH ); END_TYPE ]]> diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index d0d05761..24bdaf68 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -9,7 +9,7 @@ VAR_INPUT iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; // Blades homing is automatically done if they are not homed - bAnticolisionEnable : BOOL := FALSE; // Blades anticolision option, only for when blades are moved independiently + bAnticollisionEnable : BOOL := FALSE; // Blades anticolision option, only for when blades are moved independiently END_VAR VAR_OUTPUT @@ -50,8 +50,7 @@ VAR END_VAR ]]> - @@ -271,14 +270,14 @@ IF bResetting THEN //ignore setting in error state if FB going through a reset RETURN; END_IF -// RESET - Use the reset from the virtual axes in order to reset the slits +//RESET - Use the reset from the virtual axes in order to reset the slits bReset := GVL.astAxes[iGapCentre].stControl.bReset OR GVL.astAxes[iGapSize].stControl.bReset; IF NOT bError AND bAxisErrorsPresent THEN eSlitPairState := E_SlitPairStates.ERROR; END_IF -// Report error to virtual axes +//Report error to virtual axes IF eSlitPairState = E_SlitPairStates.ERROR THEN GVL.astAxes[iGapCentre].stStatus.bError := TRUE; GVL.astAxes[iGapSize].stStatus.bError := TRUE; @@ -347,7 +346,7 @@ GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; - - - Date: Fri, 12 Dec 2025 09:10:37 +0100 Subject: [PATCH 08/39] Fix formatting and spelling Aligns the FB_SlitPair with the coding style guide. Removes unused VAR_INPUTRemoves unused VAR_INPUT. Corrects spelling. --- POUs/Motion/FB_SlitPair.TcPOU | 74 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 24bdaf68..78c2b4a4 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -8,8 +8,8 @@ VAR_INPUT iGapSize: UINT; //Axis ID for the size of gap between slit blades iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 - bAutoHome: BOOL := TRUE; // Blades homing is automatically done if they are not homed - bAnticollisionEnable : BOOL := FALSE; // Blades anticolision option, only for when blades are moved independiently + bAutoHome: BOOL := TRUE; //Blades homing is automatically done if they are not homed + bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently END_VAR VAR_OUTPUT @@ -25,7 +25,7 @@ VAR bReset: BOOL; //Reset the slit set bResetting: BOOL := FALSE; //TRUE if axis going through a reset bAxesEnabled: BOOL := FALSE; //TRUE if all axes enabled - bSlitsHomed : BOOL := FALSE; //TRUE if all axes Homed after reboot + bSlitsHomed: BOOL := FALSE; //TRUE if all axes Homed after reboot bBladesHomed: BOOL:= FALSE; //TRUE if blade axes are calibrated bGapHomed: BOOL:= FALSE; //TRUE if virtual axes are calibrated bBladesCoupled: BOOL:= FALSE; //TRUE if both blade axes are coupled @@ -37,7 +37,7 @@ VAR fGapCentrePosition: LREAL; iGapCentrePosition AT %Q*: UDINT := 0; resetCounterTimeout: UINT :=0; - eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; // Sequence steps for update of soft limits + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; //Sequence steps for update of soft limits fbNoMovingRising: R_TRIG; fbInOpRising: R_TRIG; bUpdateSoftLimits: BOOL := FALSE; @@ -68,7 +68,7 @@ actGapLimits(); //Set virtual axis limits to TRUE actVirtualAxisPositions(); //Virtual axis encoder position subroutine actRunMethods(); //Update statuses actEnableAxes(); //Enable the axes -checkSlitsHomed(); // Status of the axes homing +checkSlitsHomed(); //Status of the axes homing IF bAnticollisionEnable THEN //Blades anticollision enabled actInterlocking(); END_IF @@ -154,7 +154,7 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; END_IF IF (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR - (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN + (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; bHomingRequested := TRUE; END_IF @@ -230,11 +230,10 @@ GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; - @@ -297,21 +296,21 @@ END_IF - - = GVL.astAxes[iBladePositive].stStatus.fActPosition - OR GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition ; + OR GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition - OR GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition ; + OR GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; ]]> @@ -346,7 +345,7 @@ GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; - - = 0.0 THEN - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - GVL.astAxes[iGapCentre].stStatus.fActPosition); + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit + - GVL.astAxes[iGapCentre].stStatus.fActPosition); ELSE - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - - GVL.astAxes[iGapCentre].stStatus.fActPosition); + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + - GVL.astAxes[iGapCentre].stStatus.fActPosition); END_IF END_IF E_SlitSoftLimits.FINISH: //FINISHED WHEN LAST WRITING OF PARAMETERS IS DONE - IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.START; - bUpdateSoftLimits := FALSE; + eSoftLimitsUpdate := E_SlitSoftLimits.START; + bUpdateSoftLimits := FALSE; END_IF END_CASE @@ -568,7 +566,11 @@ VAR_OUTPUT END_VAR ]]> - Date: Wed, 4 Mar 2026 09:22:20 +0100 Subject: [PATCH 09/39] MBP-369: Restore multimaster gearing in FB_Axis The original issue was, that if the MC_GearInMultiMaster has an axis reference to the same axis, both as slave and as master, then it throws an error. This was the case usually if the physical axis had the id of 1, which is also the initial values of the masters. But by commenting out these, you also block yourself from using master3 and master4 through other means, e.g. MainVisu. --- POUs/Motion/FB_Axis.TcPOU | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/POUs/Motion/FB_Axis.TcPOU b/POUs/Motion/FB_Axis.TcPOU index 5d8b5ee3..df43c12a 100644 --- a/POUs/Motion/FB_Axis.TcPOU +++ b/POUs/Motion/FB_Axis.TcPOU @@ -643,16 +643,16 @@ IF _stAxis.stControl.eCommand = E_MotionFunctions.eGearInMultiMaster AND _stAxis //Transfer gear ratios to FB fbGearInMultiMaster.GearRatio1 := _stAxis.stConfig.astMultiMasterAxisLatched[1].fRatio; fbGearInMultiMaster.GearRatio2 := _stAxis.stConfig.astMultiMasterAxisLatched[2].fRatio; -// fbGearInMultiMaster.GearRatio3 := _stAxis.stConfig.astMultiMasterAxisLatched[3].fRatio; (Not in use, commented due to slits code) -// fbGearInMultiMaster.GearRatio4 := _stAxis.stConfig.astMultiMasterAxisLatched[4].fRatio; (Not in use, commented due to slits code) + fbGearInMultiMaster.GearRatio3 := _stAxis.stConfig.astMultiMasterAxisLatched[3].fRatio; + fbGearInMultiMaster.GearRatio4 := _stAxis.stConfig.astMultiMasterAxisLatched[4].fRatio; fbGearInMultiMaster.Enable := TRUE; END_IF fbGearInMultiMaster(Slave := _stAxis.Axis, Master1 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[1].nIndex].Axis, - Master2 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[2].nIndex].Axis); -// Master3 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[3].nIndex].Axis, -// Master4 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[4].nIndex].Axis); + Master2 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[2].nIndex].Axis, + Master3 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[3].nIndex].Axis, + Master4 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[4].nIndex].Axis); fbGearInMultiMaster.Enable:= FALSE; IF fbGearInMultiMaster.InGear THEN From e839284b87b6382e05fceb28130e39db4715ead0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 10:15:20 +0100 Subject: [PATCH 10/39] MBP-369: Fix blades homing sequence not starting Homing of blades were not starting, it was waiting for the homing command for either of the virtual axis. --- POUs/Motion/FB_SlitPair.TcPOU | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 78c2b4a4..df737e62 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -90,26 +90,19 @@ CASE eSlitPairState OF END_IF E_SlitPairStates.CHECK_HOME_STATUS: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed - IF NOT bSlitsHomed THEN - //Perform homing - eSlitPairState := E_SlitPairStates.HOME_BLADES; - ELSIF bBladesHomed THEN + IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.HOME_GAP; //Skip to functioning ELSIF bAutoHome THEN eSlitPairState := E_SlitPairStates.HOME_BLADES; //If autohome enabled, home the blades END_IF E_SlitPairStates.HOME_BLADES: //Initiate homing of blade axes. Homing routine must be pre-configured by user - IF (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR - (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) OR bHomingRequested THEN - GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eHome; GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eHome; GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; bHoming := TRUE; eSlitPairState := E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE; - END_IF E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE: //Wait for completion of blade homing routines IF bBladesHomed AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN From 9c8796d32ff4748375eb40fdfc83de803b74c35b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 10:25:34 +0100 Subject: [PATCH 11/39] MBP-369: Rework automatic error reset Previously after 10 automatic error reset tries, the state machine jumped back to error state and the automatic reset started again, repeating infinitly. Now it should stop after 10 tries and wait for manual intervention. --- POUs/Motion/FB_SlitPair.TcPOU | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index df737e62..91b00c3c 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -194,15 +194,14 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.ERROR_RESET_CHECK; E_SlitPairStates.ERROR_RESET_CHECK: - IF resetCounterTimeout > 10 THEN - eSlitPairState := E_SlitPairStates.ERROR; - bResetting := FALSE; - RETURN; - END_IF IF bAxisErrorsPresent THEN + //If the errors persists after 10 auto reset, then manual intervention is required + IF resetCounterTimeout <= 10 THEN eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES; + END_IF ELSE eSlitPairState := E_SlitPairStates.INIT; + resetCounterTimeout := 0; bError := FALSE; bResetting := FALSE; END_IF From e7f23f338612f88976e29a87badb4f0fe6a398b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 10:29:22 +0100 Subject: [PATCH 12/39] MBP-369: Update multimaster config To avoid the issues with master3 and master4 matches their id with the slave axis, we use one of the virtual axis with a gear ratio of 0.0 --- POUs/Motion/FB_SlitPair.TcPOU | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 91b00c3c..225223e8 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -320,16 +320,27 @@ checkErrorState(bOutput => bFunctionInErrorState); - From 5b19c03dd630d48f4ba6d473003c291919401adf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 10:41:44 +0100 Subject: [PATCH 13/39] MBP-369: Fix calculation for virtual soft limits --- POUs/Motion/FB_SlitPair.TcPOU | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 225223e8..282bfc79 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -372,8 +372,8 @@ E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: //WRITE GAP CENTRE FWD SOFT LIMIT GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := (GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - GVL.astAxes[iGapSize].stStatus.fActPosition/2); + GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit + - ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladePositive].stStatus.fActPosition); END_IF E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: //WRITE GAP CENTRE BWD SOFT LIMIT @@ -382,8 +382,8 @@ E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: //WRITE GAP CENTRE BWD SOFT LIMIT GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := (GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - + GVL.astAxes[iGapSize].stStatus.fActPosition/2); + GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + + ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladeNegative].stStatus.fActPosition); END_IF E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: //WRITE GAP SIZE FWD SOFT LIMIT @@ -392,13 +392,9 @@ E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: //WRITE GAP SIZE FWD SOFT LIMIT GVL.astAxes[iGapSize].stControl.bExecute := TRUE; GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - IF GVL.astAxes[iGapCentre].stStatus.fActPosition >= 0.0 THEN - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - GVL.astAxes[iGapCentre].stStatus.fActPosition); - ELSE - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2 * ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - - GVL.astAxes[iGapCentre].stStatus.fActPosition); - END_IF + GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2.0 * MIN( + ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iBladePositive].stStatus.fActPosition), + ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iBladeNegative].stStatus.fActPosition)); END_IF E_SlitSoftLimits.FINISH: //FINISHED WHEN LAST WRITING OF PARAMETERS IS DONE From 71886aae323fa90da102072bf19513b0644439df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 10:44:53 +0100 Subject: [PATCH 14/39] MBP-369: Add a small delta gap between limits Sometimes while the virtual axis was stopping in time, the phyiscal axis just barely sliped trough their own soft limits. Adding a small marginal gap to the soft limit solves the issue. --- POUs/Motion/FB_SlitPair.TcPOU | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 282bfc79..60edaa9b 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -48,6 +48,9 @@ VAR fbDisabledRising: R_TRIG; fbHomingRising: R_TRIG; END_VAR +VAR CONSTANT + cSoftLimitDelta: LREAL := 0.05; //Delta between the softlimits of physical and virtual axes +END_VAR ]]> Date: Wed, 4 Mar 2026 10:52:16 +0100 Subject: [PATCH 15/39] MBP-369: Fix issue with homing of virtual master If the slits are operational, executing a homing command on any of the virtual masters should also initiate a homing for the physical axes. For a clean homing, we should reset the calibration flag of the axes, then jump back to homing check, where the state machine takes care of the rest of the process. --- DUTs/E_SlitPairStates.TcDUT | 2 +- POUs/Motion/FB_SlitPair.TcPOU | 68 +++++++++++++++++++++++++++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/DUTs/E_SlitPairStates.TcDUT b/DUTs/E_SlitPairStates.TcDUT index 3f57b3e4..eac3b34a 100644 --- a/DUTs/E_SlitPairStates.TcDUT +++ b/DUTs/E_SlitPairStates.TcDUT @@ -18,7 +18,7 @@ TYPE E_SlitPairStates : SLITS_OPERATIONAL, GEAROUT_BLADES, CHECK_GEAROUT_COMPLETE, - CLEAR_GAP_CALIBRATION, + RESET_CALIBRATION, ERROR, ERROR_GEAROUT, ERROR_GEAROUT_CHECK, diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 60edaa9b..236ff66c 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -47,6 +47,10 @@ VAR fbDisableRising: R_TRIG; fbDisabledRising: R_TRIG; fbHomingRising: R_TRIG; + fbResetCalibrationPositiveBlade: MC_Home; + fbResetCalibrationNegativeBlade: MC_Home; + fbResetCalibrationGapSize: MC_Home; + fbResetCalibrationGapCenter: MC_Home; END_VAR VAR CONSTANT cSoftLimitDelta: LREAL := 0.05; //Delta between the softlimits of physical and virtual axes @@ -71,7 +75,7 @@ actGapLimits(); //Set virtual axis limits to TRUE actVirtualAxisPositions(); //Virtual axis encoder position subroutine actRunMethods(); //Update statuses actEnableAxes(); //Enable the axes -checkSlitsHomed(); //Status of the axes homing +actClearCalibration(); //Clear calibration flag for all axes IF bAnticollisionEnable THEN //Blades anticollision enabled actInterlocking(); END_IF @@ -162,12 +166,19 @@ CASE eSlitPairState OF E_SlitPairStates.CHECK_GEAROUT_COMPLETE: //Check gearing cleared IF bBladesUncoupled THEN IF bHomingRequested THEN - eSlitPairState := E_SlitPairStates.HOME_BLADES; + eSlitPairState := E_SlitPairStates.RESET_CALIBRATION; bEnabled := FALSE; ELSE eSlitPairState := E_SlitPairStates.INIT; END_IF END_IF + + E_SlitPairStates.RESET_CALIBRATION: + IF checkResetCalibrationDone() THEN + eSlitPairState := E_SlitPairStates.CHECK_HOME_STATUS; + ELSIF checkResetCalibrationFailed() THEN + eSlitPairState := E_SlitPairStates.ERROR; + END_IF E_SlitPairStates.ERROR: //ERROR STATE resetCounterTimeout := 0; @@ -213,6 +224,29 @@ END_CASE bReset := FALSE; ]]> + + + + + + + + + + + + + + + + + Date: Wed, 4 Mar 2026 10:59:22 +0100 Subject: [PATCH 16/39] MBP-369: Fix issue with auto collision detection Previously fPosition was checked generally, but it should be used differently based on the movement type we are executing. --- POUs/Motion/FB_SlitPair.TcPOU | 55 +++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 236ff66c..73cfbadc 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -336,11 +336,56 @@ GVL.astAxes[iGapCentre].stInputs.bLimitFwd := GVL.astAxes[iBladeNegative].stInpu = GVL.astAxes[iBladePositive].stStatus.fActPosition - OR GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; -GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition - OR GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; -]]> + +//Forward interlock of negative blade +CASE GVL.astAxes[iBladeNegative].stControl.eCommand OF + + E_MotionFunctions.eMoveAbsolute: + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + + E_MotionFunctions.eMoveRelative: + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + (GVL.astAxes[iBladeNegative].stControl.fPosition + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + + E_MotionFunctions.eMoveVelocity: + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + (GVL.astAxes[iBladeNegative].stControl.fVelocity * 0.01 + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + + E_MotionFunctions.eMoveModulo: + ; //TODO! Implement logic for modulo movement + + ELSE + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := FALSE; +END_CASE + +GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := GVL.astAxes[iBladeNegative].stControl.bInterlockFwd + OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + +//Backward interlock of positive blade +CASE GVL.astAxes[iBladePositive].stControl.eCommand OF + + E_MotionFunctions.eMoveAbsolute: + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + + E_MotionFunctions.eMoveRelative: + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + (GVL.astAxes[iBladePositive].stControl.fPosition + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + + E_MotionFunctions.eMoveVelocity: + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + (GVL.astAxes[iBladePositive].stControl.fVelocity * 0.01 + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + + E_MotionFunctions.eMoveModulo: + ; //TODO! Implement logic for modulo movement + + ELSE + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := FALSE; +END_CASE + +GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stControl.bInterlockBwd + OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition;]]> From 1d96a430778c3c01dd43a65d41f83d025556f892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 11:07:55 +0100 Subject: [PATCH 17/39] MBP-369: Cleanup comments and identations --- POUs/Motion/FB_SlitPair.TcPOU | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 73cfbadc..687e08ab 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -10,7 +10,6 @@ VAR_INPUT fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; //Blades homing is automatically done if they are not homed bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently - END_VAR VAR_OUTPUT bEnabled: BOOL := FALSE; //Enabled status of function @@ -311,12 +310,6 @@ IF eSlitPairState = E_SlitPairStates.ERROR THEN GVL.astAxes[iGapSize].stStatus.bError := TRUE; END_IF -//IF eSlitPairState <> E_SlitPairStates.INIT AND NOT bAxesEnabled THEN -// eSlitPairState := E_SlitPairStates.ERROR; -//END_IF -//IF (eSlitPairState <> E_SlitPairStates.INIT AND NOT bFunctionInErrorState) AND NOT bEnable THEN -// eSlitPairState := E_SlitPairStates.ERROR; -//END_IF IF bEnabled AND NOT bBladesHomed THEN eSlitPairState := E_SlitPairStates.ERROR; END_IF @@ -445,10 +438,10 @@ GVL.astAxes[iGapCentre].stControl.bStop := TRUE; CASE eSoftLimitsUpdate OF -E_SlitSoftLimits.START: //START SEQ + E_SlitSoftLimits.START: eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD; -E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: //WRITE GAP CENTRE FWD SOFT LIMIT + E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD; GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; @@ -459,7 +452,7 @@ E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: //WRITE GAP CENTRE FWD SOFT LIMIT - cSoftLimitDelta; END_IF -E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: //WRITE GAP CENTRE BWD SOFT LIMIT + E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_SIZE_FWD; GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; @@ -470,7 +463,7 @@ E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: //WRITE GAP CENTRE BWD SOFT LIMIT + cSoftLimitDelta; END_IF -E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: //WRITE GAP SIZE FWD SOFT LIMIT + E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN eSoftLimitsUpdate := E_SlitSoftLimits.FINISH; GVL.astAxes[iGapSize].stControl.bExecute := TRUE; @@ -483,7 +476,7 @@ E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: //WRITE GAP SIZE FWD SOFT LIMIT 0.0); END_IF -E_SlitSoftLimits.FINISH: //FINISHED WHEN LAST WRITING OF PARAMETERS IS DONE + E_SlitSoftLimits.FINISH: IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN eSoftLimitsUpdate := E_SlitSoftLimits.START; bUpdateSoftLimits := FALSE; From b8491ebe1acafeae6f437822142cdde3d6a76e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 11:11:53 +0100 Subject: [PATCH 18/39] MBP-369: Move notes above FB declaration This way the message will be displayed when hovering over the FB. Also extended the notes with some extra information. --- POUs/Motion/FB_SlitPair.TcPOU | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 687e08ab..ff838c75 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -1,7 +1,17 @@  - - Date: Wed, 4 Mar 2026 11:14:51 +0100 Subject: [PATCH 19/39] MBP-369: Fix indentations --- POUs/Motion/FB_SlitPair.TcPOU | 72 +++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index ff838c75..1c6a4396 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -97,7 +97,7 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.CHECK_HOME_STATUS; END_IF - E_SlitPairStates.CHECK_HOME_STATUS: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed + E_SlitPairStates.CHECK_HOME_STATUS: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.HOME_GAP; //Skip to functioning ELSIF bAutoHome THEN @@ -105,12 +105,12 @@ CASE eSlitPairState OF END_IF E_SlitPairStates.HOME_BLADES: //Initiate homing of blade axes. Homing routine must be pre-configured by user - GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eHome; - GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eHome; - GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; - GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; - bHoming := TRUE; - eSlitPairState := E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE; + GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eHome; + GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eHome; + GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; + GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; + bHoming := TRUE; + eSlitPairState := E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE; E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE: //Wait for completion of blade homing routines IF bBladesHomed AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN @@ -179,7 +179,7 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.CHECK_HOME_STATUS; ELSIF checkResetCalibrationFailed() THEN eSlitPairState := E_SlitPairStates.ERROR; - END_IF + END_IF E_SlitPairStates.ERROR: //ERROR STATE resetCounterTimeout := 0; @@ -212,7 +212,7 @@ CASE eSlitPairState OF IF bAxisErrorsPresent THEN //If the errors persists after 10 auto reset, then manual intervention is required IF resetCounterTimeout <= 10 THEN - eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES; + eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES; END_IF ELSE eSlitPairState := E_SlitPairStates.INIT; @@ -441,48 +441,48 @@ GVL.astAxes[iGapCentre].stControl.bStop := TRUE; CASE eSoftLimitsUpdate OF E_SlitSoftLimits.START: - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD; - + eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD; + E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: - IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN + eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD; + GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; + GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladePositive].stStatus.fActPosition) - cSoftLimitDelta; - END_IF - + END_IF + E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_SIZE_FWD; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; + IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_SIZE_FWD; + GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; + GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladeNegative].stStatus.fActPosition) + cSoftLimitDelta; - END_IF - + END_IF + E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.FINISH; - GVL.astAxes[iGapSize].stControl.bExecute := TRUE; - GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.FINISH; + GVL.astAxes[iGapSize].stControl.bExecute := TRUE; + GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2.0 * MAX(MIN( ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iBladePositive].stStatus.fActPosition), ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iBladeNegative].stStatus.fActPosition)) - cSoftLimitDelta, 0.0); - END_IF - + END_IF + E_SlitSoftLimits.FINISH: - IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.START; - bUpdateSoftLimits := FALSE; - END_IF + IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.START; + bUpdateSoftLimits := FALSE; + END_IF END_CASE ]]> From 623ee7b99eb1b8b7536adeeb8ef799a037f376c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 12:05:15 +0100 Subject: [PATCH 20/39] MBP-369: Fix naming to match coding standard --- POUs/Motion/FB_SlitPair.TcPOU | 104 +++++++++++++--------------------- 1 file changed, 38 insertions(+), 66 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 1c6a4396..e6fb23b6 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -5,7 +5,7 @@ For the virtual axis setup, the encoders need their type changed from "simulation encoder" to "Encoder (Universal)". In addition the scale factor needs to be changed to a numerator of 1 and denominator of fEncoderScaling which is 10,000 by default) Care needs to be taken with scaling and setup of both real and virtual axes to ensure velocities are not too fast and axes have time to settle before they submit a "complete move" -Link the virtual encoder inputs to the Gap and Center position calculations iGapSizePosition iGapCentrePosition +Link the virtual encoder inputs to the Gap and Centre position calculations nGapSizePosition and nGapCentrePosition Encoder needs to be set as ABSOLUTE Encoder Mask has to be set to 0xFFFFFFFF otherwise UDINT will overflow NOTES TO FB_SlitPair: @@ -27,39 +27,36 @@ VAR_OUTPUT bHoming: BOOL := FALSE; //TRUE if function is homing axes END_VAR VAR - eSlitPairState: E_SlitPairStates := E_SlitPairStates.INIT; //statemachine index + //Internal state machines + eSlitPairState: E_SlitPairStates := E_SlitPairStates.INIT; //equence steps for operating the slits + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; //Sequence steps for update of soft limits -//Internal statuses for logic + //Internal statuses for logic bEnable: BOOL; //Enable/disable the slit set bReset: BOOL; //Reset the slit set bResetting: BOOL := FALSE; //TRUE if axis going through a reset bAxesEnabled: BOOL := FALSE; //TRUE if all axes enabled - bSlitsHomed: BOOL := FALSE; //TRUE if all axes Homed after reboot - bBladesHomed: BOOL:= FALSE; //TRUE if blade axes are calibrated - bGapHomed: BOOL:= FALSE; //TRUE if virtual axes are calibrated - bBladesCoupled: BOOL:= FALSE; //TRUE if both blade axes are coupled + bBladesHomed: BOOL := FALSE; //TRUE if blade axes are calibrated + bGapHomed: BOOL := FALSE; //TRUE if virtual axes are calibrated + bBladesCoupled: BOOL := FALSE; //TRUE if both blade axes are coupled bBladesUncoupled: BOOL := FALSE; //TRUE if both blade axes are uncoupled bAxisErrorsPresent: BOOL := FALSE; //TRUE if error present on any real or virtual axis bFunctionInErrorState: BOOL := FALSE; //TRUE if function block is in one of the error related states - fGapSizePosition: LREAL; - iGapSizePosition AT %Q*: UDINT := 0; - fGapCentrePosition: LREAL; - iGapCentrePosition AT %Q*: UDINT := 0; - resetCounterTimeout: UINT :=0; - eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; //Sequence steps for update of soft limits - fbNoMovingRising: R_TRIG; - fbInOpRising: R_TRIG; - bUpdateSoftLimits: BOOL := FALSE; - bHomingRequested: BOOL := FALSE; - fbEnableRising: R_TRIG; - fbStopRising: R_TRIG; - fbDisableRising: R_TRIG; - fbDisabledRising: R_TRIG; - fbHomingRising: R_TRIG; + bUpdateSoftLimits: BOOL := FALSE; //TRUE if update of soft limits are being executed + bHomingRequested: BOOL := FALSE; //TRUE if homing is requested for all axis + fGapSizePosition: LREAL; //Virtual axis gap size calculated position + nGapSizePosition AT %Q*: UDINT := 0; //Virtual axis gap size encoder position/counter + fGapCentrePosition: LREAL; //Virtual axis gap centre calculated position + nGapCentrePosition AT %Q*: UDINT := 0; //Virtual axis gap centre encoder position/counter + nAutoErrorResetCounter: UINT := 0; //Error automatic reset counter + rtrigSlitOperational: R_TRIG; + rtrigVirtualAxisNotMoving: R_TRIG; + rtrigVirtualAxisEnable: R_TRIG; + rtrigVirtualAxisDisable: R_TRIG; fbResetCalibrationPositiveBlade: MC_Home; fbResetCalibrationNegativeBlade: MC_Home; fbResetCalibrationGapSize: MC_Home; - fbResetCalibrationGapCenter: MC_Home; + fbResetCalibrationGapCentre: MC_Home; END_VAR VAR CONSTANT cSoftLimitDelta: LREAL := 0.05; //Delta between the softlimits of physical and virtual axes @@ -116,7 +113,7 @@ CASE eSlitPairState OF IF bBladesHomed AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.HOME_GAP; bHoming := FALSE; - ELSIF (GVL.astAxes[iBladeNegative].stStatus.nErrorID > 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID >0) THEN + ELSIF (GVL.astAxes[iBladeNegative].stStatus.nErrorID > 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID > 0) THEN eSlitPairState := E_SlitPairStates.ERROR; END_IF @@ -182,7 +179,7 @@ CASE eSlitPairState OF END_IF E_SlitPairStates.ERROR: //ERROR STATE - resetCounterTimeout := 0; + nAutoErrorResetCounter := 0; bError := TRUE; bEnabled := FALSE; actStopAxes(); @@ -205,18 +202,18 @@ CASE eSlitPairState OF GVL.astAxes[iBladePositive].stControl.bReset := TRUE; GVL.astAxes[iGapSize].stControl.bReset := TRUE; GVL.astAxes[iGapCentre].stControl.bReset := TRUE; - resetCounterTimeout := resetCounterTimeout + 1; + nAutoErrorResetCounter := nAutoErrorResetCounter + 1; eSlitPairState := E_SlitPairStates.ERROR_RESET_CHECK; E_SlitPairStates.ERROR_RESET_CHECK: IF bAxisErrorsPresent THEN //If the errors persists after 10 auto reset, then manual intervention is required - IF resetCounterTimeout <= 10 THEN + IF nAutoErrorResetCounter <= 10 THEN eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES; END_IF ELSE eSlitPairState := E_SlitPairStates.INIT; - resetCounterTimeout := 0; + nAutoErrorResetCounter := 0; bError := FALSE; bResetting := FALSE; END_IF @@ -242,7 +239,7 @@ fbResetCalibrationGapSize( Execute := eSlitPairState = E_SlitPairStates.RESET_CALIBRATION, HomingMode := MC_HomingMode.MC_ResetCalibration); -fbResetCalibrationGapCenter( +fbResetCalibrationGapCentre( Axis := GVL.astAxes[iGapCentre].Axis, Execute := eSlitPairState = E_SlitPairStates.RESET_CALIBRATION, HomingMode := MC_HomingMode.MC_ResetCalibration); ]]> @@ -261,9 +258,9 @@ GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; @@ -501,10 +494,10 @@ fGapCentrePosition := (GVL.astAxes[iBladePositive].stStatus.fActPosition + GVL.a IF bBladesHomed THEN IF ABS(fGapSizePosition) < 100000 THEN - iGapSizePosition := LREAL_TO_UDINT(fGapSizePosition*fEncoderScaling); + nGapSizePosition := LREAL_TO_UDINT(fGapSizePosition*fEncoderScaling); END_IF IF ABS(fGapCentrePosition) < 100000 THEN - iGapCentrePosition := LREAL_TO_UDINT(fGapCentrePosition*fEncoderScaling); + nGapCentrePosition := LREAL_TO_UDINT(fGapCentrePosition*fEncoderScaling); END_IF END_IF ]]> @@ -646,7 +639,7 @@ END_VAR @@ -660,42 +653,21 @@ END_VAR - - - - - - + OR fbResetCalibrationGapCentre.CommandAborted;]]> - Date: Wed, 4 Mar 2026 12:26:37 +0100 Subject: [PATCH 21/39] MBP-369: Update enum names to coding standard --- DUTs/E_SlitPairStates.TcDUT | 38 ++++----- DUTs/E_SlitSoftLimits.TcDUT | 10 +-- POUs/Motion/FB_SlitPair.TcPOU | 145 +++++++++++++++++----------------- 3 files changed, 97 insertions(+), 96 deletions(-) diff --git a/DUTs/E_SlitPairStates.TcDUT b/DUTs/E_SlitPairStates.TcDUT index eac3b34a..cc3ea098 100644 --- a/DUTs/E_SlitPairStates.TcDUT +++ b/DUTs/E_SlitPairStates.TcDUT @@ -5,25 +5,25 @@ {attribute 'strict'} TYPE E_SlitPairStates : ( - INIT := 0, - INIT_CLEAR_GEARING, - INIT_GEAROUT_CHECK, - CHECK_HOME_STATUS, - HOME_BLADES, - CHECK_BLADE_HOME_COMPLETE, - HOME_GAP, - CHECK_GAP_HOME_COMPLETE, - GEARIN_SLITS, - CHECK_GEARIN_SLITS_COMPLETE, - SLITS_OPERATIONAL, - GEAROUT_BLADES, - CHECK_GEAROUT_COMPLETE, - RESET_CALIBRATION, - ERROR, - ERROR_GEAROUT, - ERROR_GEAROUT_CHECK, - ERROR_RESET_AXES, - ERROR_RESET_CHECK + eInit := 0, + eInitClearGearing, + eInitGearOutCheck, + eCheckHomeStatus, + eHomeBlades, + eCheckBladeHomeComplete, + eHomeGap, + eCheckGapHomeComplete, + eGearInSlits, + eCheckGearInSlitsComplete, + eSlitsOperational, + eGearOutBlades, + eCheckGearOutComplete, + eResetCalibration, + eError, + eErrorGearOut, + eErrorGearOutCheck, + eErrorResetAxes, + eErrorResetCheck ); END_TYPE ]]> diff --git a/DUTs/E_SlitSoftLimits.TcDUT b/DUTs/E_SlitSoftLimits.TcDUT index c2610442..71496e13 100644 --- a/DUTs/E_SlitSoftLimits.TcDUT +++ b/DUTs/E_SlitSoftLimits.TcDUT @@ -5,11 +5,11 @@ {attribute 'strict'} TYPE E_SlitSoftLimits : ( - START := 0, - WRITE_GAP_CENTRE_FWD, - WRITE_GAP_CENTRE_BWD, - WRITE_GAP_SIZE_FWD, - FINISH + eStart := 0, + eWriteGapCentreFwd, + eWriteGapCentreBwd, + eWriteGapSizeFwd, + eFinish ); END_TYPE ]]> diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index e6fb23b6..f9e4ea41 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -28,8 +28,8 @@ VAR_OUTPUT END_VAR VAR //Internal state machines - eSlitPairState: E_SlitPairStates := E_SlitPairStates.INIT; //equence steps for operating the slits - eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.START; //Sequence steps for update of soft limits + eSlitPairState: E_SlitPairStates := E_SlitPairStates.eInit; //equence steps for operating the slits + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits //Internal statuses for logic bEnable: BOOL; //Enable/disable the slit set @@ -79,45 +79,45 @@ IF bAnticollisionEnable THEN //Blades anticollision enabled END_IF CASE eSlitPairState OF - E_SlitPairStates.INIT: + E_SlitPairStates.eInit: bEnabled := FALSE; IF bAxesEnabled AND bEnable THEN - eSlitPairState := E_SlitPairStates.INIT_CLEAR_GEARING; + eSlitPairState := E_SlitPairStates.eInitClearGearing; END_IF - E_SlitPairStates.INIT_CLEAR_GEARING: + E_SlitPairStates.eInitClearGearing: actClearSlitGearing(); - eSlitPairState := E_SlitPairStates.INIT_GEAROUT_CHECK; + eSlitPairState := E_SlitPairStates.eInitGearOutCheck; - E_SlitPairStates.INIT_GEAROUT_CHECK: //Check gearOut completion + E_SlitPairStates.eInitGearOutCheck: //Check gearOut completion IF bBladesUncoupled THEN - eSlitPairState := E_SlitPairStates.CHECK_HOME_STATUS; + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; END_IF - E_SlitPairStates.CHECK_HOME_STATUS: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed + E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed IF bBladesHomed THEN - eSlitPairState := E_SlitPairStates.HOME_GAP; //Skip to functioning + eSlitPairState := E_SlitPairStates.eHomeGap; //Skip to functioning ELSIF bAutoHome THEN - eSlitPairState := E_SlitPairStates.HOME_BLADES; //If autohome enabled, home the blades + eSlitPairState := E_SlitPairStates.eHomeBlades; //If autohome enabled, home the blades END_IF - E_SlitPairStates.HOME_BLADES: //Initiate homing of blade axes. Homing routine must be pre-configured by user + E_SlitPairStates.eHomeBlades: //Initiate homing of blade axes. Homing routine must be pre-configured by user GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eHome; GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eHome; GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; bHoming := TRUE; - eSlitPairState := E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE; + eSlitPairState := E_SlitPairStates.eCheckBladeHomeComplete; - E_SlitPairStates.CHECK_BLADE_HOME_COMPLETE: //Wait for completion of blade homing routines + E_SlitPairStates.eCheckBladeHomeComplete: //Wait for completion of blade homing routines IF bBladesHomed AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN - eSlitPairState := E_SlitPairStates.HOME_GAP; + eSlitPairState := E_SlitPairStates.eHomeGap; bHoming := FALSE; ELSIF (GVL.astAxes[iBladeNegative].stStatus.nErrorID > 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID > 0) THEN - eSlitPairState := E_SlitPairStates.ERROR; + eSlitPairState := E_SlitPairStates.eError; END_IF - E_SlitPairStates.HOME_GAP: //"Home" the virtual axes + E_SlitPairStates.eHomeGap: //"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; @@ -126,93 +126,93 @@ CASE eSlitPairState OF 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; + eSlitPairState := E_SlitPairStates.eCheckGapHomeComplete; - E_SlitPairStates.CHECK_GAP_HOME_COMPLETE: //Wait for virtual homing completion + E_SlitPairStates.eCheckGapHomeComplete: //Wait for virtual homing completion IF bGapHomed AND NOT GVL.astAxes[iGapSize].stStatus.bBusy AND NOT GVL.astAxes[iGapCentre].stStatus.bBusy THEN - eSlitPairState := E_SlitPairStates.GEARIN_SLITS; + eSlitPairState := E_SlitPairStates.eGearInSlits; bHomingRequested := FALSE; 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 GVL.astAxes[iGapSize].stStatus.bEnabled AND NOT GVL.astAxes[iGapCentre].stStatus.bEnabled THEN - eSlitPairState := E_SlitPairStates.ERROR_GEAROUT; + 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; checkSoftLimits(); //Soft limits are updated when axes are stopped IF (NOT bBladesCoupled OR NOT bEnable) AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN - eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; + eSlitPairState := E_SlitPairStates.eGearOutBlades; END_IF IF (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN - eSlitPairState := E_SlitPairStates.GEAROUT_BLADES; + eSlitPairState := E_SlitPairStates.eGearOutBlades; bHomingRequested := TRUE; END_IF - E_SlitPairStates.GEAROUT_BLADES: //Clear any 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 IF bHomingRequested THEN - eSlitPairState := E_SlitPairStates.RESET_CALIBRATION; + eSlitPairState := E_SlitPairStates.eResetCalibration; bEnabled := FALSE; ELSE - eSlitPairState := E_SlitPairStates.INIT; + eSlitPairState := E_SlitPairStates.eInit; END_IF END_IF - E_SlitPairStates.RESET_CALIBRATION: + E_SlitPairStates.eResetCalibration: IF checkResetCalibrationDone() THEN - eSlitPairState := E_SlitPairStates.CHECK_HOME_STATUS; + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; ELSIF checkResetCalibrationFailed() THEN - eSlitPairState := E_SlitPairStates.ERROR; + eSlitPairState := E_SlitPairStates.eError; END_IF - E_SlitPairStates.ERROR: //ERROR STATE + 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; //Back to homing, this ensures the setpoint position of the axis is updated. END_IF - E_SlitPairStates.ERROR_RESET_AXES: //RESET ALL AXES + E_SlitPairStates.eErrorResetAxes: //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; nAutoErrorResetCounter := nAutoErrorResetCounter + 1; - eSlitPairState := E_SlitPairStates.ERROR_RESET_CHECK; + eSlitPairState := E_SlitPairStates.eErrorResetCheck; - E_SlitPairStates.ERROR_RESET_CHECK: + E_SlitPairStates.eErrorResetCheck: IF bAxisErrorsPresent THEN //If the errors persists after 10 auto reset, then manual intervention is required IF nAutoErrorResetCounter <= 10 THEN - eSlitPairState := E_SlitPairStates.ERROR_RESET_AXES; + eSlitPairState := E_SlitPairStates.eErrorResetAxes; END_IF ELSE - eSlitPairState := E_SlitPairStates.INIT; + eSlitPairState := E_SlitPairStates.eInit; nAutoErrorResetCounter := 0; bError := FALSE; bResetting := FALSE; @@ -226,22 +226,22 @@ bReset := FALSE; @@ -296,17 +296,17 @@ END_IF bReset := GVL.astAxes[iGapCentre].stControl.bReset OR GVL.astAxes[iGapSize].stControl.bReset; IF NOT bError AND bAxisErrorsPresent THEN - eSlitPairState := E_SlitPairStates.ERROR; + eSlitPairState := E_SlitPairStates.eError; END_IF //Report error to virtual axes -IF eSlitPairState = E_SlitPairStates.ERROR THEN +IF eSlitPairState = E_SlitPairStates.eError THEN GVL.astAxes[iGapCentre].stStatus.bError := TRUE; GVL.astAxes[iGapSize].stStatus.bError := TRUE; END_IF IF bEnabled AND NOT bBladesHomed THEN - eSlitPairState := E_SlitPairStates.ERROR; + eSlitPairState := E_SlitPairStates.eError; END_IF ]]> @@ -347,9 +347,10 @@ CASE GVL.astAxes[iBladeNegative].stControl.eCommand OF GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := FALSE; END_CASE -GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := GVL.astAxes[iBladeNegative].stControl.bInterlockFwd +GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := GVL.astAxes[iBladeNegative].stControl.bInterlockFwd OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + //Backward interlock of positive blade CASE GVL.astAxes[iBladePositive].stControl.eCommand OF @@ -372,7 +373,7 @@ CASE GVL.astAxes[iBladePositive].stControl.eCommand OF GVL.astAxes[iBladePositive].stControl.bInterlockBwd := FALSE; END_CASE -GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stControl.bInterlockBwd +GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stControl.bInterlockBwd OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition;]]> @@ -433,12 +434,12 @@ GVL.astAxes[iGapCentre].stControl.bStop := TRUE; CASE eSoftLimitsUpdate OF - E_SlitSoftLimits.START: - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD; + E_SlitSoftLimits.eStart: + eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreFwd; - E_SlitSoftLimits.WRITE_GAP_CENTRE_FWD: + E_SlitSoftLimits.eWriteGapCentreFwd: IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD; + eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreBwd; GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; @@ -447,9 +448,9 @@ CASE eSoftLimitsUpdate OF - cSoftLimitDelta; END_IF - E_SlitSoftLimits.WRITE_GAP_CENTRE_BWD: + E_SlitSoftLimits.eWriteGapCentreBwd: IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.WRITE_GAP_SIZE_FWD; + eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapSizeFwd; GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; @@ -458,9 +459,9 @@ CASE eSoftLimitsUpdate OF + cSoftLimitDelta; END_IF - E_SlitSoftLimits.WRITE_GAP_SIZE_FWD: + E_SlitSoftLimits.eWriteGapSizeFwd: IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.FINISH; + eSoftLimitsUpdate := E_SlitSoftLimits.eFinish; GVL.astAxes[iGapSize].stControl.bExecute := TRUE; GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; @@ -471,9 +472,9 @@ CASE eSoftLimitsUpdate OF 0.0); END_IF - E_SlitSoftLimits.FINISH: + E_SlitSoftLimits.eFinish: IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.START; + eSoftLimitsUpdate := E_SlitSoftLimits.eStart; bUpdateSoftLimits := FALSE; END_IF @@ -612,19 +613,19 @@ VAR_OUTPUT END_VAR ]]> - @@ -665,7 +666,7 @@ END_VAR ]]> Date: Wed, 4 Mar 2026 13:33:28 +0100 Subject: [PATCH 22/39] MBP-369: Update anticollision to check slits homed Anticollision have to consider that the phsysical axes are not calibrated, and their positions cannot be assessed. --- POUs/Motion/FB_SlitPair.TcPOU | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index f9e4ea41..6c8b82fe 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -347,9 +347,9 @@ CASE GVL.astAxes[iBladeNegative].stControl.eCommand OF GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := FALSE; END_CASE -GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := GVL.astAxes[iBladeNegative].stControl.bInterlockFwd - OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; - +GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + (GVL.astAxes[iBladeNegative].stControl.bInterlockFwd OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition) + AND bBladesHomed; //Backward interlock of positive blade CASE GVL.astAxes[iBladePositive].stControl.eCommand OF @@ -373,8 +373,9 @@ CASE GVL.astAxes[iBladePositive].stControl.eCommand OF GVL.astAxes[iBladePositive].stControl.bInterlockBwd := FALSE; END_CASE -GVL.astAxes[iBladePositive].stControl.bInterlockBwd := GVL.astAxes[iBladePositive].stControl.bInterlockBwd - OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition;]]> +GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + (GVL.astAxes[iBladePositive].stControl.bInterlockBwd OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition) + AND bBladesHomed;]]> From dc4ede2d8ec248b6746401d28849e269b29a971e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 14:30:50 +0100 Subject: [PATCH 23/39] MBP-369: Add plc task cylce time to inputs --- POUs/Motion/FB_SlitPair.TcPOU | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 6c8b82fe..92a74f1b 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -20,6 +20,7 @@ VAR_INPUT fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; //Blades homing is automatically done if they are not homed bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently + fCycleTime: LREAL := 0.01; //PlcTask cycle time in seconds END_VAR VAR_OUTPUT bEnabled: BOOL := FALSE; //Enabled status of function @@ -338,7 +339,7 @@ CASE GVL.astAxes[iBladeNegative].stControl.eCommand OF E_MotionFunctions.eMoveVelocity: GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.fVelocity * 0.01 + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + (GVL.astAxes[iBladeNegative].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; E_MotionFunctions.eMoveModulo: ; //TODO! Implement logic for modulo movement @@ -364,7 +365,7 @@ CASE GVL.astAxes[iBladePositive].stControl.eCommand OF E_MotionFunctions.eMoveVelocity: GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.fVelocity * 0.01 + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + (GVL.astAxes[iBladePositive].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; E_MotionFunctions.eMoveModulo: ; //TODO! Implement logic for modulo movement From 8ccbb8dd8f03bca6691e4017c84265db03545416 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 14:31:58 +0100 Subject: [PATCH 24/39] MBP-369: Fix calculation using the wrong indexes --- POUs/Motion/FB_SlitPair.TcPOU | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 92a74f1b..99eec501 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -468,8 +468,8 @@ CASE eSoftLimitsUpdate OF GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2.0 * MAX(MIN( - ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iBladePositive].stStatus.fActPosition), - ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iBladeNegative].stStatus.fActPosition)) + ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition), + ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition)) - cSoftLimitDelta, 0.0); END_IF From 164e2cc6af693d09ee570e9b4c74e34b75fd6f2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 4 Mar 2026 14:37:51 +0100 Subject: [PATCH 25/39] MBP-369: Fix whitespaces --- POUs/Motion/FB_Axis.TcPOU | 8 +- POUs/Motion/FB_SlitPair.TcPOU | 288 +++++++++++++++++----------------- 2 files changed, 150 insertions(+), 146 deletions(-) diff --git a/POUs/Motion/FB_Axis.TcPOU b/POUs/Motion/FB_Axis.TcPOU index df43c12a..3cf7d837 100644 --- a/POUs/Motion/FB_Axis.TcPOU +++ b/POUs/Motion/FB_Axis.TcPOU @@ -643,16 +643,16 @@ IF _stAxis.stControl.eCommand = E_MotionFunctions.eGearInMultiMaster AND _stAxis //Transfer gear ratios to FB fbGearInMultiMaster.GearRatio1 := _stAxis.stConfig.astMultiMasterAxisLatched[1].fRatio; fbGearInMultiMaster.GearRatio2 := _stAxis.stConfig.astMultiMasterAxisLatched[2].fRatio; - fbGearInMultiMaster.GearRatio3 := _stAxis.stConfig.astMultiMasterAxisLatched[3].fRatio; - fbGearInMultiMaster.GearRatio4 := _stAxis.stConfig.astMultiMasterAxisLatched[4].fRatio; + fbGearInMultiMaster.GearRatio3 := _stAxis.stConfig.astMultiMasterAxisLatched[3].fRatio; + fbGearInMultiMaster.GearRatio4 := _stAxis.stConfig.astMultiMasterAxisLatched[4].fRatio; fbGearInMultiMaster.Enable := TRUE; END_IF fbGearInMultiMaster(Slave := _stAxis.Axis, Master1 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[1].nIndex].Axis, Master2 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[2].nIndex].Axis, - Master3 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[3].nIndex].Axis, - Master4 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[4].nIndex].Axis); + Master3 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[3].nIndex].Axis, + Master4 := GVL.astAxes[_stAxis.stConfig.astMultiMasterAxisLatched[4].nIndex].Axis); fbGearInMultiMaster.Enable:= FALSE; IF fbGearInMultiMaster.InGear THEN diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 99eec501..87079376 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -20,7 +20,7 @@ VAR_INPUT fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; //Blades homing is automatically done if they are not homed bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently - fCycleTime: LREAL := 0.01; //PlcTask cycle time in seconds + fCycleTime: LREAL := 0.01; //PlcTask cycle time in seconds END_VAR VAR_OUTPUT bEnabled: BOOL := FALSE; //Enabled status of function @@ -28,11 +28,11 @@ VAR_OUTPUT bHoming: BOOL := FALSE; //TRUE if function is homing axes END_VAR VAR - //Internal state machines + //Internal state machines eSlitPairState: E_SlitPairStates := E_SlitPairStates.eInit; //equence steps for operating the slits - eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits - //Internal statuses for logic + //Internal statuses for logic bEnable: BOOL; //Enable/disable the slit set bReset: BOOL; //Reset the slit set bResetting: BOOL := FALSE; //TRUE if axis going through a reset @@ -43,7 +43,7 @@ VAR bBladesUncoupled: BOOL := FALSE; //TRUE if both blade axes are uncoupled bAxisErrorsPresent: BOOL := FALSE; //TRUE if error present on any real or virtual axis bFunctionInErrorState: BOOL := FALSE; //TRUE if function block is in one of the error related states - bUpdateSoftLimits: BOOL := FALSE; //TRUE if update of soft limits are being executed + bUpdateSoftLimits: BOOL := FALSE; //TRUE if update of soft limits are being executed bHomingRequested: BOOL := FALSE; //TRUE if homing is requested for all axis fGapSizePosition: LREAL; //Virtual axis gap size calculated position nGapSizePosition AT %Q*: UDINT := 0; //Virtual axis gap size encoder position/counter @@ -51,16 +51,16 @@ VAR nGapCentrePosition AT %Q*: UDINT := 0; //Virtual axis gap centre encoder position/counter nAutoErrorResetCounter: UINT := 0; //Error automatic reset counter rtrigSlitOperational: R_TRIG; - rtrigVirtualAxisNotMoving: R_TRIG; + rtrigVirtualAxisNotMoving: R_TRIG; rtrigVirtualAxisEnable: R_TRIG; rtrigVirtualAxisDisable: R_TRIG; - fbResetCalibrationPositiveBlade: MC_Home; - fbResetCalibrationNegativeBlade: MC_Home; - fbResetCalibrationGapSize: MC_Home; - fbResetCalibrationGapCentre: MC_Home; + fbResetCalibrationPositiveBlade: MC_Home; + fbResetCalibrationNegativeBlade: MC_Home; + fbResetCalibrationGapSize: MC_Home; + fbResetCalibrationGapCentre: MC_Home; END_VAR VAR CONSTANT - cSoftLimitDelta: LREAL := 0.05; //Delta between the softlimits of physical and virtual axes + cSoftLimitDelta: LREAL := 0.05; //Delta between the softlimits of physical and virtual axes END_VAR ]]> @@ -95,7 +95,7 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.eCheckHomeStatus; END_IF - E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed + E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.eHomeGap; //Skip to functioning ELSIF bAutoHome THEN @@ -103,12 +103,12 @@ CASE eSlitPairState OF END_IF E_SlitPairStates.eHomeBlades: //Initiate homing of blade axes. Homing routine must be pre-configured by user - GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eHome; - GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eHome; - GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; - GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; - bHoming := TRUE; - eSlitPairState := E_SlitPairStates.eCheckBladeHomeComplete; + GVL.astAxes[iBladeNegative].stControl.eCommand := E_MotionFunctions.eHome; + GVL.astAxes[iBladePositive].stControl.eCommand := E_MotionFunctions.eHome; + GVL.astAxes[iBladeNegative].stControl.bExecute := TRUE; + GVL.astAxes[iBladePositive].stControl.bExecute := TRUE; + bHoming := TRUE; + eSlitPairState := E_SlitPairStates.eCheckBladeHomeComplete; E_SlitPairStates.eCheckBladeHomeComplete: //Wait for completion of blade homing routines IF bBladesHomed AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN @@ -171,13 +171,13 @@ CASE eSlitPairState OF eSlitPairState := E_SlitPairStates.eInit; END_IF END_IF - - E_SlitPairStates.eResetCalibration: - IF checkResetCalibrationDone() THEN - eSlitPairState := E_SlitPairStates.eCheckHomeStatus; - ELSIF checkResetCalibrationFailed() THEN - eSlitPairState := E_SlitPairStates.eError; - END_IF + + E_SlitPairStates.eResetCalibration: + IF checkResetCalibrationDone() THEN + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; + ELSIF checkResetCalibrationFailed() THEN + eSlitPairState := E_SlitPairStates.eError; + END_IF E_SlitPairStates.eError: //ERROR STATE nAutoErrorResetCounter := 0; @@ -208,13 +208,13 @@ CASE eSlitPairState OF E_SlitPairStates.eErrorResetCheck: IF bAxisErrorsPresent THEN - //If the errors persists after 10 auto reset, then manual intervention is required - IF nAutoErrorResetCounter <= 10 THEN - eSlitPairState := E_SlitPairStates.eErrorResetAxes; - END_IF + //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.eInit; - nAutoErrorResetCounter := 0; + nAutoErrorResetCounter := 0; bError := FALSE; bResetting := FALSE; END_IF @@ -226,24 +226,25 @@ bReset := FALSE; + Axis := GVL.astAxes[iGapCentre].Axis, + Execute := eSlitPairState = E_SlitPairStates.eResetCalibration, + HomingMode := MC_HomingMode.MC_ResetCalibration); +]]> @@ -328,55 +329,56 @@ GVL.astAxes[iGapCentre].stInputs.bLimitFwd := GVL.astAxes[iBladeNegative].stInpu //Forward interlock of negative blade CASE GVL.astAxes[iBladeNegative].stControl.eCommand OF - - E_MotionFunctions.eMoveAbsolute: - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; - - E_MotionFunctions.eMoveRelative: - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.fPosition + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; - - E_MotionFunctions.eMoveVelocity: - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; - - E_MotionFunctions.eMoveModulo: - ; //TODO! Implement logic for modulo movement - - ELSE - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := FALSE; + + E_MotionFunctions.eMoveAbsolute: + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + GVL.astAxes[iBladeNegative].stControl.fPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + + E_MotionFunctions.eMoveRelative: + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + (GVL.astAxes[iBladeNegative].stControl.fPosition + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + + E_MotionFunctions.eMoveVelocity: + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + (GVL.astAxes[iBladeNegative].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + + E_MotionFunctions.eMoveModulo: + ; //TODO! Implement logic for modulo movement + + ELSE + GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := FALSE; END_CASE -GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.bInterlockFwd OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition) - AND bBladesHomed; +GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := + (GVL.astAxes[iBladeNegative].stControl.bInterlockFwd OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition) + AND bBladesHomed; //Backward interlock of positive blade CASE GVL.astAxes[iBladePositive].stControl.eCommand OF - - E_MotionFunctions.eMoveAbsolute: - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; - - E_MotionFunctions.eMoveRelative: - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.fPosition + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; - - E_MotionFunctions.eMoveVelocity: - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; - - E_MotionFunctions.eMoveModulo: - ; //TODO! Implement logic for modulo movement - - ELSE - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := FALSE; + + E_MotionFunctions.eMoveAbsolute: + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + + E_MotionFunctions.eMoveRelative: + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + (GVL.astAxes[iBladePositive].stControl.fPosition + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + + E_MotionFunctions.eMoveVelocity: + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + (GVL.astAxes[iBladePositive].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + + E_MotionFunctions.eMoveModulo: + ; //TODO! Implement logic for modulo movement + + ELSE + GVL.astAxes[iBladePositive].stControl.bInterlockBwd := FALSE; END_CASE -GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.bInterlockBwd OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition) - AND bBladesHomed;]]> +GVL.astAxes[iBladePositive].stControl.bInterlockBwd := + (GVL.astAxes[iBladePositive].stControl.bInterlockBwd OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition) + AND bBladesHomed; +]]> @@ -436,49 +438,49 @@ GVL.astAxes[iGapCentre].stControl.bStop := TRUE; CASE eSoftLimitsUpdate OF - E_SlitSoftLimits.eStart: - eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreFwd; - - E_SlitSoftLimits.eWriteGapCentreFwd: - IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN - eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreBwd; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladePositive].stStatus.fActPosition) - - cSoftLimitDelta; - END_IF - - E_SlitSoftLimits.eWriteGapCentreBwd: - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapSizeFwd; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - + ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladeNegative].stStatus.fActPosition) - + cSoftLimitDelta; - END_IF - - E_SlitSoftLimits.eWriteGapSizeFwd: - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.eFinish; - GVL.astAxes[iGapSize].stControl.bExecute := TRUE; - GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + E_SlitSoftLimits.eStart: + eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreFwd; + + E_SlitSoftLimits.eWriteGapCentreFwd: + IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN + eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreBwd; + GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; + GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit + - ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladePositive].stStatus.fActPosition) + - cSoftLimitDelta; + END_IF + + E_SlitSoftLimits.eWriteGapCentreBwd: + IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapSizeFwd; + GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; + GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; + GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit + + ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladeNegative].stStatus.fActPosition) + + cSoftLimitDelta; + END_IF + + E_SlitSoftLimits.eWriteGapSizeFwd: + IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.eFinish; + GVL.astAxes[iGapSize].stControl.bExecute := TRUE; + GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; + GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2.0 * MAX(MIN( - ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition), - ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition)) - - cSoftLimitDelta, - 0.0); - END_IF - - E_SlitSoftLimits.eFinish: - IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN - eSoftLimitsUpdate := E_SlitSoftLimits.eStart; - bUpdateSoftLimits := FALSE; - END_IF + ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition), + ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition)) + - cSoftLimitDelta, + 0.0); + END_IF + + E_SlitSoftLimits.eFinish: + IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN + eSoftLimitsUpdate := E_SlitSoftLimits.eStart; + bUpdateSoftLimits := FALSE; + END_IF END_CASE ]]> @@ -639,12 +641,13 @@ VAR_INPUT END_VAR ]]> - + @@ -653,14 +656,15 @@ VAR_INPUT END_VAR ]]> - + From c91dd587cf65072a4008af849c598322340e0236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Thu, 5 Mar 2026 09:42:45 +0100 Subject: [PATCH 26/39] MBP-369: Update anticollision enable/disable Previously bAnticollisionEnabled was not used, when the interlocks were updated. This caused an issue, where disabling anticollision, while the axis was interlocked, did not removed the interlock. --- POUs/Motion/FB_SlitPair.TcPOU | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 87079376..2bc22d2d 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -75,9 +75,7 @@ actVirtualAxisPositions(); //Virtual axis encoder position subroutine actRunMethods(); //Update statuses actEnableAxes(); //Enable the axes actClearCalibration(); //Clear calibration flag for all axes -IF bAnticollisionEnable THEN //Blades anticollision enabled - actInterlocking(); -END_IF +actInterlocking(); //Handle blades anticollision CASE eSlitPairState OF E_SlitPairStates.eInit: @@ -351,7 +349,8 @@ END_CASE GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := (GVL.astAxes[iBladeNegative].stControl.bInterlockFwd OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition) - AND bBladesHomed; + AND bBladesHomed + AND bAnticollisionEnable; //Backward interlock of positive blade CASE GVL.astAxes[iBladePositive].stControl.eCommand OF @@ -377,7 +376,8 @@ END_CASE GVL.astAxes[iBladePositive].stControl.bInterlockBwd := (GVL.astAxes[iBladePositive].stControl.bInterlockBwd OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition) - AND bBladesHomed; + AND bBladesHomed + AND bAnticollisionEnable; ]]> From 3600fdcb1c3ef55135cae323cb6a99cad6515076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Thu, 5 Mar 2026 15:25:24 +0100 Subject: [PATCH 27/39] MBP-369: Remove unused variable --- POUs/Motion/FB_SlitPair.TcPOU | 2 -- 1 file changed, 2 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 2bc22d2d..bd45d7e6 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -42,7 +42,6 @@ VAR bBladesCoupled: BOOL := FALSE; //TRUE if both blade axes are coupled bBladesUncoupled: BOOL := FALSE; //TRUE if both blade axes are uncoupled bAxisErrorsPresent: BOOL := FALSE; //TRUE if error present on any real or virtual axis - bFunctionInErrorState: BOOL := FALSE; //TRUE if function block is in one of the error related states bUpdateSoftLimits: BOOL := FALSE; //TRUE if update of soft limits are being executed bHomingRequested: BOOL := FALSE; //TRUE if homing is requested for all axis fGapSizePosition: LREAL; //Virtual axis gap size calculated position @@ -389,7 +388,6 @@ checkVirtualHomed(bOutput => bGapHomed); checkBladesCoupled(bOutput => bBladesCoupled); checkBladesUncoupled(bOutput => bBladesUncoupled); checkAllAxisErrors(bOutput => bAxisErrorsPresent); -checkErrorState(bOutput => bFunctionInErrorState); ]]> From b4938d2bb709452f7dec81e51350d674a5ad19e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Thu, 5 Mar 2026 15:32:19 +0100 Subject: [PATCH 28/39] MBP-369: Remove usage of global variables Removed usage of GVL.astAxes inside the functionblock, now uses VAR_IN_OUT of the struct, where its passed by reference and must be asigned. --- POUs/Motion/FB_SlitPair.TcPOU | 423 +++++++++++++++------------------- 1 file changed, 190 insertions(+), 233 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index bd45d7e6..73d88cc8 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -12,9 +12,13 @@ NOTES TO FB_SlitPair: The instance of the function block should be called before the call of FB_Axis, so that it gets bExecute before FB_Axis *) FUNCTION_BLOCK FB_SlitPair +VAR_IN_OUT + stBladeNegative: ST_AxisStruct; //Axis data of the negative blade + stBladePositive: ST_AxisStruct; //Axis data of the positive blade + stGapSize: ST_AxisStruct; //Axis data of the gap size + stGapCentre: ST_AxisStruct; //Axis data of the gap centre +END_VAR VAR_INPUT - iBladeNegative: UINT; //Axis ID for negatively positioned blade - iBladePositive: UINT; //Axis ID for positively positioned blade iGapSize: UINT; //Axis ID for the size of gap between slit blades iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 @@ -64,14 +68,14 @@ END_VAR ]]> 0) OR (GVL.astAxes[iBladePositive].stStatus.nErrorID > 0) THEN + ELSIF (stBladeNegative.stStatus.nErrorID > 0) OR (stBladePositive.stStatus.nErrorID > 0) THEN eSlitPairState := E_SlitPairStates.eError; END_IF E_SlitPairStates.eHomeGap: //"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; + 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 GVL.astAxes[iGapSize].stStatus.bBusy AND NOT GVL.astAxes[iGapCentre].stStatus.bBusy THEN + IF bGapHomed AND NOT stGapSize.stStatus.bBusy AND NOT stGapCentre.stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.eGearInSlits; bHomingRequested := FALSE; END_IF @@ -139,18 +143,18 @@ CASE eSlitPairState OF E_SlitPairStates.eCheckGearInSlitsComplete: //Wait for gearing complete IF bBladesCoupled THEN eSlitPairState := E_SlitPairStates.eSlitsOperational; - ELSIF NOT GVL.astAxes[iGapSize].stStatus.bEnabled AND NOT GVL.astAxes[iGapCentre].stStatus.bEnabled THEN + ELSIF NOT stGapSize.stStatus.bEnabled AND NOT stGapCentre.stStatus.bEnabled THEN eSlitPairState := E_SlitPairStates.eErrorGearOut; END_IF E_SlitPairStates.eSlitsOperational: //SLITS OPERATIONAL - Monitor for any gear outs and re-gear when no busy blades bEnabled := TRUE; - checkSoftLimits(); //Soft limits are updated when axes are stopped - IF (NOT bBladesCoupled OR NOT bEnable) AND NOT GVL.astAxes[iBladeNegative].stStatus.bBusy AND NOT GVL.astAxes[iBladePositive].stStatus.bBusy THEN + 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 (GVL.astAxes[iGapSize].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapSize].stControl.bExecute) OR - (GVL.astAxes[iGapCentre].stControl.eCommand = E_MotionFunctions.eHome AND GVL.astAxes[iGapCentre].stControl.bExecute) THEN + 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 @@ -192,14 +196,14 @@ CASE eSlitPairState OF E_SlitPairStates.eErrorGearOutCheck: IF bBladesUncoupled THEN - eSlitPairState := E_SlitPairStates.eErrorResetAxes; //Back to homing, this ensures the setpoint position of the axis is updated. + eSlitPairState := E_SlitPairStates.eErrorResetAxes; END_IF E_SlitPairStates.eErrorResetAxes: //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; + stBladeNegative.stControl.bReset := TRUE; + stBladePositive.stControl.bReset := TRUE; + stGapSize.stControl.bReset := TRUE; + stGapCentre.stControl.bReset := TRUE; nAutoErrorResetCounter := nAutoErrorResetCounter + 1; eSlitPairState := E_SlitPairStates.eErrorResetCheck; @@ -223,22 +227,22 @@ bReset := FALSE; @@ -247,40 +251,40 @@ fbResetCalibrationGapCentre( @@ -292,7 +296,7 @@ IF bResetting THEN //ignore setting in error state if FB going through a reset END_IF //RESET - Use the reset from the virtual axes in order to reset the slits -bReset := GVL.astAxes[iGapCentre].stControl.bReset OR GVL.astAxes[iGapSize].stControl.bReset; +bReset := stGapCentre.stControl.bReset OR stGapSize.stControl.bReset; IF NOT bError AND bAxisErrorsPresent THEN eSlitPairState := E_SlitPairStates.eError; @@ -300,8 +304,8 @@ END_IF //Report error to virtual axes IF eSlitPairState = E_SlitPairStates.eError THEN - GVL.astAxes[iGapCentre].stStatus.bError := TRUE; - GVL.astAxes[iGapSize].stStatus.bError := TRUE; + stGapCentre.stStatus.bError := TRUE; + stGapSize.stStatus.bError := TRUE; END_IF IF bEnabled AND NOT bBladesHomed THEN @@ -313,10 +317,10 @@ END_IF @@ -325,107 +329,96 @@ GVL.astAxes[iGapCentre].stInputs.bLimitFwd := GVL.astAxes[iBladeNegative].stInpu = GVL.astAxes[iBladePositive].stStatus.fActPosition; + stBladeNegative.stControl.bInterlockFwd := + stBladeNegative.stControl.fPosition >= stBladePositive.stStatus.fActPosition; E_MotionFunctions.eMoveRelative: - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.fPosition + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + stBladeNegative.stControl.bInterlockFwd := + (stBladeNegative.stControl.fPosition + stBladeNegative.stStatus.fActPosition) >= stBladePositive.stStatus.fActPosition; E_MotionFunctions.eMoveVelocity: - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladeNegative].stStatus.fActPosition) >= GVL.astAxes[iBladePositive].stStatus.fActPosition; + stBladeNegative.stControl.bInterlockFwd := + (stBladeNegative.stControl.fVelocity * fCycleTime + stBladeNegative.stStatus.fActPosition) >= stBladePositive.stStatus.fActPosition; E_MotionFunctions.eMoveModulo: ; //TODO! Implement logic for modulo movement ELSE - GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := FALSE; + stBladeNegative.stControl.bInterlockFwd := FALSE; END_CASE -GVL.astAxes[iBladeNegative].stControl.bInterlockFwd := - (GVL.astAxes[iBladeNegative].stControl.bInterlockFwd OR GVL.astAxes[iBladeNegative].stStatus.fActPosition >= GVL.astAxes[iBladePositive].stStatus.fActPosition) +stBladeNegative.stControl.bInterlockFwd := + (stBladeNegative.stControl.bInterlockFwd OR stBladeNegative.stStatus.fActPosition >= stBladePositive.stStatus.fActPosition) AND bBladesHomed AND bAnticollisionEnable; //Backward interlock of positive blade -CASE GVL.astAxes[iBladePositive].stControl.eCommand OF +CASE stBladePositive.stControl.eCommand OF E_MotionFunctions.eMoveAbsolute: - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - GVL.astAxes[iBladePositive].stControl.fPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + stBladePositive.stControl.bInterlockBwd := + stBladePositive.stControl.fPosition <= stBladeNegative.stStatus.fActPosition; E_MotionFunctions.eMoveRelative: - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.fPosition + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + stBladePositive.stControl.bInterlockBwd := + (stBladePositive.stControl.fPosition + stBladePositive.stStatus.fActPosition) <= stBladeNegative.stStatus.fActPosition; E_MotionFunctions.eMoveVelocity: - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.fVelocity * fCycleTime + GVL.astAxes[iBladePositive].stStatus.fActPosition) <= GVL.astAxes[iBladeNegative].stStatus.fActPosition; + stBladePositive.stControl.bInterlockBwd := + (stBladePositive.stControl.fVelocity * fCycleTime + stBladePositive.stStatus.fActPosition) <= stBladeNegative.stStatus.fActPosition; E_MotionFunctions.eMoveModulo: ; //TODO! Implement logic for modulo movement ELSE - GVL.astAxes[iBladePositive].stControl.bInterlockBwd := FALSE; + stBladePositive.stControl.bInterlockBwd := FALSE; END_CASE -GVL.astAxes[iBladePositive].stControl.bInterlockBwd := - (GVL.astAxes[iBladePositive].stControl.bInterlockBwd OR GVL.astAxes[iBladePositive].stStatus.fActPosition <= GVL.astAxes[iBladeNegative].stStatus.fActPosition) +stBladePositive.stControl.bInterlockBwd := + (stBladePositive.stControl.bInterlockBwd OR stBladePositive.stStatus.fActPosition <= stBladeNegative.stStatus.fActPosition) AND bBladesHomed AND bAnticollisionEnable; -]]> - - - - - bAxesEnabled); -checkBladesHomed(bOutput => bBladesHomed); -checkVirtualHomed(bOutput => bGapHomed); -checkBladesCoupled(bOutput => bBladesCoupled); -checkBladesUncoupled(bOutput => bBladesUncoupled); -checkAllAxisErrors(bOutput => bAxisErrorsPresent); ]]> @@ -440,47 +433,58 @@ CASE eSoftLimitsUpdate OF eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreFwd; E_SlitSoftLimits.eWriteGapCentreFwd: - IF NOT GVL.astAxes[iGapCentre].stStatus.bBusy AND NOT GVL.astAxes[iGapSize].stStatus.bBusy THEN + IF NOT stGapCentre.stStatus.bBusy AND NOT stGapSize.stStatus.bBusy THEN eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapCentreBwd; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - - ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladePositive].stStatus.fActPosition) + stGapCentre.stControl.bExecute := TRUE; + stGapCentre.stControl.eCommand := E_MotionFunctions.eWriteParameter; + stGapCentre.stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + stGapCentre.stConfig.fWriteAxisParameter := stBladePositive.stConfig.fMaxSoftPosLimit + - ABS(stGapCentre.stStatus.fActPosition - stBladePositive.stStatus.fActPosition) - cSoftLimitDelta; END_IF E_SlitSoftLimits.eWriteGapCentreBwd: - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + IF stGapCentre.stStatus.bDone AND NOT stGapCentre.stControl.bExecute THEN eSoftLimitsUpdate := E_SlitSoftLimits.eWriteGapSizeFwd; - GVL.astAxes[iGapCentre].stControl.bExecute := TRUE; - GVL.astAxes[iGapCentre].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapCentre].stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; - GVL.astAxes[iGapCentre].stConfig.fWriteAxisParameter := GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - + ABS(GVL.astAxes[iGapCentre].stStatus.fActPosition - GVL.astAxes[iBladeNegative].stStatus.fActPosition) + stGapCentre.stControl.bExecute := TRUE; + stGapCentre.stControl.eCommand := E_MotionFunctions.eWriteParameter; + stGapCentre.stConfig.eAxisParameters := E_AxisParameters.SWLimitBackward; + stGapCentre.stConfig.fWriteAxisParameter := stBladeNegative.stConfig.fMinSoftPosLimit + + ABS(stGapCentre.stStatus.fActPosition - stBladeNegative.stStatus.fActPosition) + cSoftLimitDelta; END_IF E_SlitSoftLimits.eWriteGapSizeFwd: - IF GVL.astAxes[iGapCentre].stStatus.bDone AND NOT GVL.astAxes[iGapCentre].stControl.bExecute THEN + IF stGapCentre.stStatus.bDone AND NOT stGapCentre.stControl.bExecute THEN eSoftLimitsUpdate := E_SlitSoftLimits.eFinish; - GVL.astAxes[iGapSize].stControl.bExecute := TRUE; - GVL.astAxes[iGapSize].stControl.eCommand := E_MotionFunctions.eWriteParameter; - GVL.astAxes[iGapSize].stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; - GVL.astAxes[iGapSize].stConfig.fWriteAxisParameter := 2.0 * MAX(MIN( - ABS(GVL.astAxes[iBladePositive].stConfig.fMaxSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition), - ABS(GVL.astAxes[iBladeNegative].stConfig.fMinSoftPosLimit - GVL.astAxes[iGapCentre].stStatus.fActPosition)) + stGapSize.stControl.bExecute := TRUE; + stGapSize.stControl.eCommand := E_MotionFunctions.eWriteParameter; + stGapSize.stConfig.eAxisParameters := E_AxisParameters.SWLimitForward; + stGapSize.stConfig.fWriteAxisParameter := 2.0 * MAX(MIN( + ABS(stBladePositive.stConfig.fMaxSoftPosLimit - stGapCentre.stStatus.fActPosition), + ABS(stBladeNegative.stConfig.fMinSoftPosLimit - stGapCentre.stStatus.fActPosition)) - cSoftLimitDelta, 0.0); END_IF E_SlitSoftLimits.eFinish: - IF GVL.astAxes[iGapSize].stStatus.bDone AND NOT GVL.astAxes[iGapSize].stControl.bExecute THEN + IF stGapSize.stStatus.bDone AND NOT stGapSize.stControl.bExecute THEN eSoftLimitsUpdate := E_SlitSoftLimits.eStart; bUpdateSoftLimits := FALSE; END_IF END_CASE +]]> + + + + + @@ -492,8 +496,8 @@ If this is not done, it can cause overflow when connected to the encoder input a To preserve decimal position data of the LREAL (i.e. anything <1mm) it is necessary to scale the value before converting to UDINT. This can be reversed with the correct scaling at the NC encoder level. *) -fGapSizePosition := GVL.astAxes[iBladePositive].stStatus.fActPosition - GVL.astAxes[iBladeNegative].stStatus.fActPosition; -fGapCentrePosition := (GVL.astAxes[iBladePositive].stStatus.fActPosition + GVL.astAxes[iBladeNegative].stStatus.fActPosition) / 2; +fGapSizePosition := stBladePositive.stStatus.fActPosition - stBladeNegative.stStatus.fActPosition; +fGapCentrePosition := (stBladePositive.stStatus.fActPosition + stBladeNegative.stStatus.fActPosition) / 2; IF bBladesHomed THEN IF ABS(fGapSizePosition) < 100000 THEN @@ -509,132 +513,99 @@ END_IF - - + - - - - - - + - - @@ -649,7 +620,7 @@ END_VAR - @@ -666,10 +637,14 @@ END_VAR - - - - - - - - From 1fafa5c1b9081e1d092feabf38cc7019728ef975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Fri, 6 Mar 2026 11:04:10 +0100 Subject: [PATCH 29/39] MBP-369: Fix typo --- POUs/Motion/FB_SlitPair.TcPOU | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 73d88cc8..81aeb81a 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -33,7 +33,7 @@ VAR_OUTPUT END_VAR VAR //Internal state machines - eSlitPairState: E_SlitPairStates := E_SlitPairStates.eInit; //equence steps for operating the slits + eSlitPairState: E_SlitPairStates := E_SlitPairStates.eStartup; //Sequence steps for operating the slits eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits //Internal statuses for logic From 77bf7ad1b7ce2bc016e4f68197c5ae0c27f3f84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Fri, 6 Mar 2026 13:09:08 +0100 Subject: [PATCH 30/39] MBP-369: Add virtual axis parameter validation On startup validate the required parameters for the virtual axes. When all parameters are valid then check state finishes with eAllParamValid. On encountering an invalid parameter check state ends with eInvalidParam. --- DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT | 12 +++ DUTs/E_AxisParamCheckState.TcDUT | 18 +++++ DUTs/E_SlitPairStates.TcDUT | 3 +- POUs/Motion/FB_SlitPair.TcPOU | 81 ++++++++++++++++++++- 4 files changed, 112 insertions(+), 2 deletions(-) create mode 100644 DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT create mode 100644 DUTs/E_AxisParamCheckState.TcDUT diff --git a/DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT b/DUTs/Axis_Structures/ST_AxisParamSpec.TcDUT new file mode 100644 index 00000000..ca843cd5 --- /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 00000000..51028946 --- /dev/null +++ b/DUTs/E_AxisParamCheckState.TcDUT @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/DUTs/E_SlitPairStates.TcDUT b/DUTs/E_SlitPairStates.TcDUT index cc3ea098..e2c46322 100644 --- a/DUTs/E_SlitPairStates.TcDUT +++ b/DUTs/E_SlitPairStates.TcDUT @@ -5,7 +5,8 @@ {attribute 'strict'} TYPE E_SlitPairStates : ( - eInit := 0, + eStartup := 0, + eInit, eInitClearGearing, eInitGearOutCheck, eCheckHomeStatus, diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 81aeb81a..179ea66b 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -21,7 +21,7 @@ END_VAR VAR_INPUT iGapSize: UINT; //Axis ID for the size of gap between slit blades iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades - fEncoderScaling: LREAL := 10000; //default scaling denominator of 10000 + fEncoderScaling: LREAL := 10000.0; //default scaling denominator of 10000 bAutoHome: BOOL := TRUE; //Blades homing is automatically done if they are not homed bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently fCycleTime: LREAL := 0.01; //PlcTask cycle time in seconds @@ -34,6 +34,7 @@ END_VAR VAR //Internal state machines eSlitPairState: E_SlitPairStates := E_SlitPairStates.eStartup; //Sequence steps for operating the slits + eParameterCheck: E_AxisParamCheckState := E_AxisParamCheckState.eInit; //Sequence steps for checking params of virtual axes eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits //Internal statuses for logic @@ -53,6 +54,7 @@ VAR fGapCentrePosition: LREAL; //Virtual axis gap centre calculated position nGapCentrePosition AT %Q*: UDINT := 0; //Virtual axis gap centre encoder position/counter nAutoErrorResetCounter: UINT := 0; //Error automatic reset counter + iParamCheck: USINT := 1; //Index of current parameter to be validated rtrigSlitOperational: R_TRIG; rtrigVirtualAxisNotMoving: R_TRIG; rtrigVirtualAxisEnable: R_TRIG; @@ -64,6 +66,14 @@ VAR END_VAR VAR CONSTANT cSoftLimitDelta: LREAL := 0.05; //Delta between the softlimits of physical and virtual axes + cMaxParams: USINT := 6; + cParameters: ARRAY [1..cMaxParams] OF ST_AxisParamSpec := [ //Parameters required to be validated + (eParam := E_AxisParameters.AxisEncoderScalingNumerator, fValue := 1.0), + (eParam := E_AxisParameters.AxisEncoderScalingDenominator, fValue := 10000.0), + (eParam := E_AxisParameters.AxisEncoderMask, fValue := 4294967295.0), //0xFFFFFFF = 4294967295.0 + (eParam := E_AxisParameters.AxisEncoderReferenceSystem, fValue := 1.0), //0.0 = INCREMENTAL, 1.0 = ABSOLUTE + (eParam := E_AxisParameters.EnableLimitBackward, fValue := 1.0), //0.0 = FALSE, 1.0 = TRUE + (eParam := E_AxisParameters.EnableLimitForward, fValue := 1.0)]; //0.0 = FALSE, 1.0 = TRUE END_VAR ]]> @@ -81,6 +91,14 @@ actClearCalibration(); //Clear calibration flag for all axes actInterlocking(); //Handle blades anticollision CASE eSlitPairState OF + E_SlitPairStates.eStartup: + checkStartupParams(stGapSize, stGapCentre); + IF eParameterCheck = E_AxisParamCheckState.eAllParamValid + OR eParameterCheck = E_AxisParamCheckState.eInvalidParam + THEN + eSlitPairState := E_SlitPairStates.eInit; + END_IF + E_SlitPairStates.eInit: bEnabled := FALSE; IF bAxesEnabled AND bEnable THEN @@ -654,6 +672,67 @@ END_IF IF bUpdateSoftLimits THEN actUpdateSoftLimits(); END_IF +]]> + + + + + + From 3056b08eb490e0fa7d8f03d0dc81a09acc01bbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Tue, 10 Mar 2026 15:32:32 +0100 Subject: [PATCH 31/39] MBP-369: Add option to home without bAutoHome If bAutoHome was not enabled, you had to do manual homing of the physical axes. This change adds the option to request and execute the homing of all the axes inside the slit system without enabling bAutoHome. --- POUs/Motion/FB_SlitPair.TcPOU | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 179ea66b..3bcb87d9 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -117,8 +117,11 @@ CASE eSlitPairState OF E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.eHomeGap; //Skip to functioning - ELSIF bAutoHome THEN - eSlitPairState := E_SlitPairStates.eHomeBlades; //If autohome enabled, home the blades + ELSIF bAutoHome + OR (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.eHomeBlades; //If autohome enabled or commanded through one of the virtual axis, home the blades END_IF E_SlitPairStates.eHomeBlades: //Initiate homing of blade axes. Homing routine must be pre-configured by user From 784bb1dae82d81b1dd0c88c037408d038120cd16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Tue, 10 Mar 2026 15:39:54 +0100 Subject: [PATCH 32/39] MBP-369: Fix whitespaces --- POUs/Motion/FB_SlitPair.TcPOU | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 3bcb87d9..461c3f04 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -117,10 +117,10 @@ CASE eSlitPairState OF E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.eHomeGap; //Skip to functioning - ELSIF bAutoHome - OR (stGapSize.stControl.eCommand = E_MotionFunctions.eHome AND stGapSize.stControl.bExecute) - OR (stGapCentre.stControl.eCommand = E_MotionFunctions.eHome AND stGapCentre.stControl.bExecute) - THEN + ELSIF bAutoHome + OR (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.eHomeBlades; //If autohome enabled or commanded through one of the virtual axis, home the blades END_IF From 43559094620ec20d4f35d604e21458fdcced20ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 11 Mar 2026 14:10:24 +0100 Subject: [PATCH 33/39] MBP-369: Change bAutoHome initial value to FALSE After further discussion, the automatic homing feature is usually disabled. --- POUs/Motion/FB_SlitPair.TcPOU | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 461c3f04..379cebc7 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -22,7 +22,7 @@ VAR_INPUT iGapSize: UINT; //Axis ID for the size of gap between slit blades iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades fEncoderScaling: LREAL := 10000.0; //default scaling denominator of 10000 - bAutoHome: BOOL := TRUE; //Blades homing is automatically done if they are not homed + bAutoHome: BOOL := FALSE; //Blades homing is automatically done if they are not homed bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently fCycleTime: LREAL := 0.01; //PlcTask cycle time in seconds END_VAR From 3de25560976da322fbfacf1bc2a69480e48090b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 11 Mar 2026 14:15:42 +0100 Subject: [PATCH 34/39] MBP-369: Fix homing request did not work properly When the slit was operational and bAutoHome was not enabled, if a new homing request was issued, then after the decouple and calibration flag reset the state machine waited for a second home command execution. --- POUs/Motion/FB_SlitPair.TcPOU | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 379cebc7..1edd0e78 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -118,10 +118,12 @@ CASE eSlitPairState OF IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.eHomeGap; //Skip to functioning ELSIF bAutoHome + OR bHomingRequested OR (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.eHomeBlades; //If autohome enabled or commanded through one of the virtual axis, home the blades + bHomingRequested := FALSE; //If homing fails do not automatically start homing again + eSlitPairState := E_SlitPairStates.eHomeBlades; END_IF E_SlitPairStates.eHomeBlades: //Initiate homing of blade axes. Homing routine must be pre-configured by user @@ -154,7 +156,6 @@ CASE eSlitPairState OF 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; - bHomingRequested := FALSE; END_IF E_SlitPairStates.eGearInSlits: //Setup gearing From 8be5cc9c6e4324051704d2f0c6701c74f0a89288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 11 Mar 2026 14:23:11 +0100 Subject: [PATCH 35/39] MBP-369: Add stop/halt homing through virtual axis If stop/halt command is issued through one of the virtual master axis during the homing of the blades, the command should stop/halt the blades as well. --- POUs/Motion/FB_SlitPair.TcPOU | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 1edd0e78..5f5e089e 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -138,6 +138,14 @@ CASE eSlitPairState OF IF bBladesHomed AND NOT stBladeNegative.stStatus.bBusy AND NOT stBladePositive.stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.eHomeGap; bHoming := FALSE; + ELSIF stGapSize.stControl.bStop OR stGapCentre.stControl.bStop THEN + stBladeNegative.stControl.bStop := TRUE; + stBladePositive.stControl.bStop := TRUE; + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; + ELSIF stGapSize.stControl.bHalt OR stGapCentre.stControl.bHalt THEN + stBladeNegative.stControl.bHalt := TRUE; + stBladePositive.stControl.bHalt := TRUE; + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; ELSIF (stBladeNegative.stStatus.nErrorID > 0) OR (stBladePositive.stStatus.nErrorID > 0) THEN eSlitPairState := E_SlitPairStates.eError; END_IF From 0199fe624f3d25571a65b9bd78184d0592156d05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Wed, 11 Mar 2026 14:27:16 +0100 Subject: [PATCH 36/39] MPB-369: Update comments --- POUs/Motion/FB_SlitPair.TcPOU | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 5f5e089e..1d727950 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -109,20 +109,20 @@ CASE eSlitPairState OF actClearSlitGearing(); eSlitPairState := E_SlitPairStates.eInitGearOutCheck; - E_SlitPairStates.eInitGearOutCheck: //Check gearOut completion + E_SlitPairStates.eInitGearOutCheck: //Check gearout completion IF bBladesUncoupled THEN eSlitPairState := E_SlitPairStates.eCheckHomeStatus; END_IF - E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, if blades not homed and autohome enabled then home blades, otherwise wait for blades to be homed + E_SlitPairStates.eCheckHomeStatus: //If blades are already homed, skip to virtual homing, otherwise wait for manual/auto homing signal IF bBladesHomed THEN eSlitPairState := E_SlitPairStates.eHomeGap; //Skip to functioning ELSIF bAutoHome - OR bHomingRequested + OR bHomingRequested OR (stGapSize.stControl.eCommand = E_MotionFunctions.eHome AND stGapSize.stControl.bExecute) OR (stGapCentre.stControl.eCommand = E_MotionFunctions.eHome AND stGapCentre.stControl.bExecute) THEN - bHomingRequested := FALSE; //If homing fails do not automatically start homing again + bHomingRequested := FALSE; //If homing fails do not automatically start homing again eSlitPairState := E_SlitPairStates.eHomeBlades; END_IF @@ -134,18 +134,18 @@ CASE eSlitPairState OF bHoming := TRUE; eSlitPairState := E_SlitPairStates.eCheckBladeHomeComplete; - E_SlitPairStates.eCheckBladeHomeComplete: //Wait for completion of blade homing routines + E_SlitPairStates.eCheckBladeHomeComplete: //Wait for completion of blade homing routines or stop/halt command IF bBladesHomed AND NOT stBladeNegative.stStatus.bBusy AND NOT stBladePositive.stStatus.bBusy THEN eSlitPairState := E_SlitPairStates.eHomeGap; bHoming := FALSE; - ELSIF stGapSize.stControl.bStop OR stGapCentre.stControl.bStop THEN - stBladeNegative.stControl.bStop := TRUE; - stBladePositive.stControl.bStop := TRUE; - eSlitPairState := E_SlitPairStates.eCheckHomeStatus; - ELSIF stGapSize.stControl.bHalt OR stGapCentre.stControl.bHalt THEN - stBladeNegative.stControl.bHalt := TRUE; - stBladePositive.stControl.bHalt := TRUE; - eSlitPairState := E_SlitPairStates.eCheckHomeStatus; + ELSIF stGapSize.stControl.bStop OR stGapCentre.stControl.bStop THEN + stBladeNegative.stControl.bStop := TRUE; + stBladePositive.stControl.bStop := TRUE; + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; + ELSIF stGapSize.stControl.bHalt OR stGapCentre.stControl.bHalt THEN + stBladeNegative.stControl.bHalt := TRUE; + stBladePositive.stControl.bHalt := TRUE; + eSlitPairState := E_SlitPairStates.eCheckHomeStatus; ELSIF (stBladeNegative.stStatus.nErrorID > 0) OR (stBladePositive.stStatus.nErrorID > 0) THEN eSlitPairState := E_SlitPairStates.eError; END_IF @@ -301,7 +301,6 @@ IF rtrigVirtualAxisEnable.Q THEN bEnable := TRUE; END_IF - //Disable blade axes when both the virtuals are disabled rtrigVirtualAxisDisable(CLK := NOT stGapSize.stControl.bEnable OR NOT stGapCentre.stControl.bEnable); From 566d3b632a48eca6d0df3eab45435fed9fafea9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Fri, 13 Mar 2026 13:26:16 +0100 Subject: [PATCH 37/39] MBP-369: Rework anticollision logic The anticollision now stops the blades, when they are in a marginal distance from eachother. This is safer than calculate with the deceleration curves or cycle times to stop them as close as possible. actInterlock renamed to actAnticollision to better convey functionality --- POUs/Motion/FB_SlitPair.TcPOU | 124 ++++++++++++++++------------------ 1 file changed, 59 insertions(+), 65 deletions(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 1d727950..346ddbe4 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -23,8 +23,8 @@ VAR_INPUT iGapCentre: UINT; //Axis ID for the centre position of the gap formed by slit blades fEncoderScaling: LREAL := 10000.0; //default scaling denominator of 10000 bAutoHome: BOOL := FALSE; //Blades homing is automatically done if they are not homed - bAnticollisionEnable: BOOL := FALSE; //Blades anticollision option, only for when blades are moved independently - fCycleTime: LREAL := 0.01; //PlcTask cycle time in seconds + bAnticollisionEnable: BOOL := TRUE; //Blades anticollision option, only for when blades are moved independently + fAnticollisionMargin: LREAL := 5.0; //Margin between the the blades for anticollision END_VAR VAR_OUTPUT bEnabled: BOOL := FALSE; //Enabled status of function @@ -35,7 +35,7 @@ VAR //Internal state machines eSlitPairState: E_SlitPairStates := E_SlitPairStates.eStartup; //Sequence steps for operating the slits eParameterCheck: E_AxisParamCheckState := E_AxisParamCheckState.eInit; //Sequence steps for checking params of virtual axes - eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits + eSoftLimitsUpdate: E_SlitSoftLimits := E_SlitSoftLimits.eStart; //Sequence steps for update of soft limits for virtual axes //Internal statuses for logic bEnable: BOOL; //Enable/disable the slit set @@ -56,9 +56,9 @@ VAR nAutoErrorResetCounter: UINT := 0; //Error automatic reset counter iParamCheck: USINT := 1; //Index of current parameter to be validated rtrigSlitOperational: R_TRIG; - rtrigVirtualAxisNotMoving: R_TRIG; rtrigVirtualAxisEnable: R_TRIG; rtrigVirtualAxisDisable: R_TRIG; + rtrigVirtualAxisNotMoving: R_TRIG; fbResetCalibrationPositiveBlade: MC_Home; fbResetCalibrationNegativeBlade: MC_Home; fbResetCalibrationGapSize: MC_Home; @@ -88,7 +88,7 @@ actVirtualAxisPositions(); //Virtual axis encoder position subroutine actUpdateStatus(); //Update statuses actEnableAxes(); //Enable the axes actClearCalibration(); //Clear calibration flag for all axes -actInterlocking(); //Handle blades anticollision +actAnticollision(); //Handle blades anticollision CASE eSlitPairState OF E_SlitPairStates.eStartup: @@ -254,6 +254,60 @@ 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; +]]> + + - - - - - = stBladePositive.stStatus.fActPosition; - - E_MotionFunctions.eMoveRelative: - stBladeNegative.stControl.bInterlockFwd := - (stBladeNegative.stControl.fPosition + stBladeNegative.stStatus.fActPosition) >= stBladePositive.stStatus.fActPosition; - - E_MotionFunctions.eMoveVelocity: - stBladeNegative.stControl.bInterlockFwd := - (stBladeNegative.stControl.fVelocity * fCycleTime + stBladeNegative.stStatus.fActPosition) >= stBladePositive.stStatus.fActPosition; - - E_MotionFunctions.eMoveModulo: - ; //TODO! Implement logic for modulo movement - - ELSE - stBladeNegative.stControl.bInterlockFwd := FALSE; -END_CASE - -stBladeNegative.stControl.bInterlockFwd := - (stBladeNegative.stControl.bInterlockFwd OR stBladeNegative.stStatus.fActPosition >= stBladePositive.stStatus.fActPosition) - AND bBladesHomed - AND bAnticollisionEnable; - -//Backward interlock of positive blade -CASE stBladePositive.stControl.eCommand OF - - E_MotionFunctions.eMoveAbsolute: - stBladePositive.stControl.bInterlockBwd := - stBladePositive.stControl.fPosition <= stBladeNegative.stStatus.fActPosition; - - E_MotionFunctions.eMoveRelative: - stBladePositive.stControl.bInterlockBwd := - (stBladePositive.stControl.fPosition + stBladePositive.stStatus.fActPosition) <= stBladeNegative.stStatus.fActPosition; - - E_MotionFunctions.eMoveVelocity: - stBladePositive.stControl.bInterlockBwd := - (stBladePositive.stControl.fVelocity * fCycleTime + stBladePositive.stStatus.fActPosition) <= stBladeNegative.stStatus.fActPosition; - - E_MotionFunctions.eMoveModulo: - ; //TODO! Implement logic for modulo movement - - ELSE - stBladePositive.stControl.bInterlockBwd := FALSE; -END_CASE - -stBladePositive.stControl.bInterlockBwd := - (stBladePositive.stControl.bInterlockBwd OR stBladePositive.stStatus.fActPosition <= stBladeNegative.stStatus.fActPosition) - AND bBladesHomed - AND bAnticollisionEnable; ]]> From bfc78ccb83ec357a5f18343bd82b8c314f09b517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Fri, 13 Mar 2026 13:44:29 +0100 Subject: [PATCH 38/39] MPB-369: Change error propogation Previously when blades were operated without the virtual masters, propogated their errors to virtual axes, without the virtual ones being turned on. --- POUs/Motion/FB_SlitPair.TcPOU | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/POUs/Motion/FB_SlitPair.TcPOU b/POUs/Motion/FB_SlitPair.TcPOU index 346ddbe4..9858a403 100644 --- a/POUs/Motion/FB_SlitPair.TcPOU +++ b/POUs/Motion/FB_SlitPair.TcPOU @@ -381,7 +381,7 @@ END_IF //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 THEN +IF NOT bError AND bAxisErrorsPresent AND (stGapCentre.stStatus.bEnabled OR stGapSize.stStatus.bEnabled) THEN eSlitPairState := E_SlitPairStates.eError; END_IF From f91dd469cd012fd1de8063eb6bf0ee7b144aee0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szil=C3=A1rd=20H=C3=B6kk=C3=B6n?= Date: Tue, 24 Mar 2026 12:16:28 +0100 Subject: [PATCH 39/39] MBP-369: Add warn/info messages to param check --- DUTs/E_AxisParamCheckState.TcDUT | 10 +++-- DUTs/E_AxisParameters.TcTLEO | 1 + POUs/Motion/FB_SlitPair.TcPOU | 74 ++++++++++++++++++++++++-------- 3 files changed, 64 insertions(+), 21 deletions(-) diff --git a/DUTs/E_AxisParamCheckState.TcDUT b/DUTs/E_AxisParamCheckState.TcDUT index 51028946..454580be 100644 --- a/DUTs/E_AxisParamCheckState.TcDUT +++ b/DUTs/E_AxisParamCheckState.TcDUT @@ -6,11 +6,13 @@ TYPE E_AxisParamCheckState : ( eInit, - eSelect, - eRead, + eSelectParam, + eWaitRead, eCheck, - eAllParamValid, - eInvalidParam + eParamValid, + eParamInvalid, + eNext, + eFinish ); END_TYPE ]]> diff --git a/DUTs/E_AxisParameters.TcTLEO b/DUTs/E_AxisParameters.TcTLEO index 4c799dd9..82c72bc8 100644 --- a/DUTs/E_AxisParameters.TcTLEO +++ b/DUTs/E_AxisParameters.TcTLEO @@ -3,6 +3,7 @@ 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 - eParameterCheck := E_AxisParamCheckState.eInvalidParam; + ; + iParamCheck := iParamCheck + 1; + eParameterCheck := E_AxisParamCheckState.eSelectParam; END_IF - E_AxisParamCheckState.eAllParamValid: - ; - E_AxisParamCheckState.eInvalidParam: - ; //Atleast one invalid parameter found + E_AxisParamCheckState.eFinish: + ; END_CASE ]]>