From 9f34f85a255873d009bd08a0f34a9cb1f0ebb4e9 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 13:37:57 +0100 Subject: [PATCH 01/25] MBP-247: Change variable of eUpsMode for clarity --- solution/tc_project_app/POUs/MAIN.TcPOU | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index ba6aaca..d6b888f 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -13,7 +13,7 @@ VAR //Startup, Shutdown and UPS fbCX5130UPS: FB_S_UPS_CX51x0; fbC6017UPS: FB_S_UPS_BAPI; - eUpsMode: E_S_UPS_Mode := eSUPS_WrPersistData_Shutdown; + eSelUpsMode: E_S_UPS_Mode := eSUPS_WrPersistData_Shutdown; //Selected UPS mode eStartUp: (eColdStart, eReadAxisFeedbackType, eCheckReadDone, eExecuteRestore, eCheckRestore, eFinishRestore); bPositionRestoreDone: BOOL := FALSE; bRestoreExecute: BOOL := FALSE; From 37923c17639419cece237b19d8b6eb1408f388c8 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 13:42:55 +0100 Subject: [PATCH 02/25] MBP-247: Add system time variables in MAIN --- solution/tc_project_app/POUs/MAIN.TcPOU | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index d6b888f..e150608 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -25,7 +25,10 @@ VAR afbReadPositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbWritePositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_WriteParameter; fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; - + fbSystemTime : GETSYSTEMTIME; + timeAsFileTime : T_FILETIME; + timeAsDT : DT; + timeAsDTAtStartup : DT; nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number END_VAR From 70f458b47105668901b1d22ce7b3a0a1a827517d Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 13:49:02 +0100 Subject: [PATCH 03/25] MBP-247: Add SYSTEM_TIME() in CHECK_UPS() --- solution/tc_project_app/POUs/MAIN.TcPOU | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index e150608..cdd4eef 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -78,11 +78,11 @@ END_FOR eSUPS_PowerOK THEN From e60531c9f511b5711145d16aa132fbd6af29fc0c Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 13:52:37 +0100 Subject: [PATCH 04/25] MBP-247: Change description in RESTORE_POSITIONS --- solution/tc_project_app/POUs/MAIN.TcPOU | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index cdd4eef..2b30b5c 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -146,7 +146,7 @@ Pneumatic_Box(); - Date: Fri, 6 Mar 2026 13:57:11 +0100 Subject: [PATCH 05/25] MBP-247: Timestamp startup and check axis init --- solution/tc_project_app/POUs/MAIN.TcPOU | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 2b30b5c..d480f4e 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -167,8 +167,17 @@ Pneumatic_Box(); IF bRestoreOnStartup AND eGlobalSUpsState = eSUPS_PowerOK THEN - bRestoreOnStartup := FALSE; - bRestoreExecute := TRUE; + bRestoreOnStartup := FALSE; + bRestoreExecute := TRUE; + SYSTEM_TIME(); + timeAsDTAtStartup := timeAsDT; + + FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO + IF NOT astAxes[iAxes].stStatus.bAxisInitialized THEN + //Do nothing if axis has not been initialized + RETURN; + END_IF + END_FOR END_IF //Upon startup bPositionRestoreDone will be set to FALSE, after successfully completing the following code it will be set TRUE From 15bc9830feb81429f8d7d3e8b19aa2d13a472ee9 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 14:01:02 +0100 Subject: [PATCH 06/25] MBP-247: Incorporate eRestoreWithoutHome Incorporate eRestoreWithoutHome in RESTORE_POSITIONS() action. --- solution/tc_project_app/POUs/MAIN.TcPOU | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index d480f4e..01f1011 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -225,7 +225,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO IF NOT afbReadEncRefSys[iAxes].Valid THEN IF afbReadEncRefSys[iAxes].Busy THEN - //Exit MAIN.STARTUP Action and wait till next cycle, needs to cycle through whole program in order for data to update + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update RETURN; ELSE //Sometimes the code gets here and the afbReadEncRefSys[iAxes] misses the rising edge. If the code gets here it means @@ -244,7 +244,8 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN eExecuteRestore: //Execute position and encoder BIAS restore by setting Execute = TRUE FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR + GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN //Restore position value for incremental encoders IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND (afbReadEncRefSys[iAxes].Value = 0 OR @@ -269,7 +270,8 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN //Nothing actually happens if the restore is not done, the code just returns from here each cycle and the //bPositionRestoreDone will never get set to TRUE and will take up cycle time FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR + GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND (afbReadEncRefSys[iAxes].Value = 0 OR afbReadEncRefSys[iAxes].Value = 2 OR @@ -301,6 +303,11 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN afbWritePositionBias[iAxes].Execute := FALSE; bPositionRestoreDone := TRUE; bRestoreExecute := FALSE; + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + GVL.astAxes[iAxes].stControl.bEnable := TRUE; + GVL.astAxes[iAxes].stControl.eCommand := E_MotionFunctions.eHome; + GVL.astAxes[iAxes].stControl.bExecute := TRUE; + END_IF END_FOR END_CASE END_IF From cf46730c84ebacad263162bbcca787e1099a2442 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 14:04:14 +0100 Subject: [PATCH 07/25] MBP-247: Add afbSetPosition[iAxes].Busy check Check that BUSY bit is false, before the check of the DONE bit is made. --- solution/tc_project_app/POUs/MAIN.TcPOU | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 01f1011..75ea1bb 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -276,11 +276,15 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN (afbReadEncRefSys[iAxes].Value = 0 OR afbReadEncRefSys[iAxes].Value = 2 OR afbReadEncRefSys[iAxes].Value = 4) THEN - IF NOT afbSetPosition[iAxes].Done THEN - afbSetPosition[iAxes].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF + IF afbSetPosition[iAxes].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + END_IF + IF NOT afbSetPosition[iAxes].Done THEN + afbSetPosition[iAxes].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF ELSIF afbReadEncRefSys[iAxes].Value = 1 OR afbReadEncRefSys[iAxes].Value = 3 OR afbReadEncRefSys[iAxes].Value = 5 THEN From 2ee587a8cb4bb6395089e0e5cdf0985db4b096c9 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 14:08:59 +0100 Subject: [PATCH 08/25] MBP-247: Store date and time at shutdown --- solution/tc_project_app/POUs/MAIN.TcPOU | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 75ea1bb..aa6d6ce 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -321,7 +321,7 @@ END_IF + + + + + timeAsFileTime.dwLowDateTime, timeHiDW => timeAsFileTime.dwHighDateTime); +timeAsDT := FILETIME_TO_DT(timeAsFileTime); + ]]> From 380075954c56124d1650fdc00f1a71912cecfe4a Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Fri, 6 Mar 2026 14:16:54 +0100 Subject: [PATCH 09/25] MBP-247: Fix whitespace --- solution/tc_project_app/POUs/MAIN.TcPOU | 64 ++++++++++++------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index aa6d6ce..2f9d257 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -25,10 +25,10 @@ VAR afbReadPositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbWritePositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_WriteParameter; fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; - fbSystemTime : GETSYSTEMTIME; + fbSystemTime : GETSYSTEMTIME; timeAsFileTime : T_FILETIME; timeAsDT : DT; - timeAsDTAtStartup : DT; + timeAsDTAtStartup : DT; nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number END_VAR @@ -99,7 +99,7 @@ IF eGlobalSUpsState = eSUPS_PowerFailure THEN //First cycle of powerfailure //Execute code that should only be done once with each powerfailure, i.e. increase powerfailure counter bRestoreOnStartup := TRUE; - SYSTEM_TIME(); + SYSTEM_TIME(); STORE_PERSISTENT(); RETURN; ELSIF eGlobalSUpsState <> eSUPS_PowerOK THEN @@ -167,17 +167,17 @@ Pneumatic_Box(); IF bRestoreOnStartup AND eGlobalSUpsState = eSUPS_PowerOK THEN - bRestoreOnStartup := FALSE; - bRestoreExecute := TRUE; - SYSTEM_TIME(); - timeAsDTAtStartup := timeAsDT; + bRestoreOnStartup := FALSE; + bRestoreExecute := TRUE; + SYSTEM_TIME(); + timeAsDTAtStartup := timeAsDT; - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF NOT astAxes[iAxes].stStatus.bAxisInitialized THEN - //Do nothing if axis has not been initialized - RETURN; - END_IF - END_FOR + FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO + IF NOT astAxes[iAxes].stStatus.bAxisInitialized THEN + //Do nothing if axis has not been initialized + RETURN; + END_IF + END_FOR END_IF //Upon startup bPositionRestoreDone will be set to FALSE, after successfully completing the following code it will be set TRUE @@ -244,8 +244,8 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN eExecuteRestore: //Execute position and encoder BIAS restore by setting Execute = TRUE FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR - GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR + GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN //Restore position value for incremental encoders IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND (afbReadEncRefSys[iAxes].Value = 0 OR @@ -270,21 +270,21 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN //Nothing actually happens if the restore is not done, the code just returns from here each cycle and the //bPositionRestoreDone will never get set to TRUE and will take up cycle time FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR - GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR + GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND (afbReadEncRefSys[iAxes].Value = 0 OR afbReadEncRefSys[iAxes].Value = 2 OR afbReadEncRefSys[iAxes].Value = 4) THEN - IF afbSetPosition[iAxes].Busy THEN - //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update - RETURN; - END_IF - IF NOT afbSetPosition[iAxes].Done THEN - afbSetPosition[iAxes].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF + IF afbSetPosition[iAxes].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + END_IF + IF NOT afbSetPosition[iAxes].Done THEN + afbSetPosition[iAxes].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF ELSIF afbReadEncRefSys[iAxes].Value = 1 OR afbReadEncRefSys[iAxes].Value = 3 OR afbReadEncRefSys[iAxes].Value = 5 THEN @@ -307,11 +307,11 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN afbWritePositionBias[iAxes].Execute := FALSE; bPositionRestoreDone := TRUE; bRestoreExecute := FALSE; - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - GVL.astAxes[iAxes].stControl.bEnable := TRUE; - GVL.astAxes[iAxes].stControl.eCommand := E_MotionFunctions.eHome; - GVL.astAxes[iAxes].stControl.bExecute := TRUE; - END_IF + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + GVL.astAxes[iAxes].stControl.bEnable := TRUE; + GVL.astAxes[iAxes].stControl.eCommand := E_MotionFunctions.eHome; + GVL.astAxes[iAxes].stControl.bExecute := TRUE; + END_IF END_FOR END_CASE END_IF @@ -343,7 +343,7 @@ GVL.timeAtShutdownPersistent := timeAsDT; timeAsFileTime.dwLowDateTime, timeHiDW => timeAsFileTime.dwHighDateTime); -timeAsDT := FILETIME_TO_DT(timeAsFileTime); +timeAsDT := FILETIME_TO_DT(timeAsFileTime); ]]> From 9836ed10aaf9e5653073d3ac5f4af0a263dba237 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Wed, 11 Mar 2026 14:25:18 +0100 Subject: [PATCH 10/25] MBP-247: Remove extra apostrophe RestoreWithHome --- solution/tc_project_app/POUs/MAIN.TcPOU | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 2f9d257..66788c7 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -155,7 +155,7 @@ Pneumatic_Box(); //There is a enum to allow for different types of restore modes, currently only one is implemented. //0 'DontRestore' //1 'RestoreWithoutHome' - Restores the position using a set position fb and does not set the home bit in the axis struct. -//2 ''RestoreWithHome' - Restores the position using a set position fb and does set the home bit in the axis struct. +//2 'RestoreWithHome' - Restores the position using a set position fb and does set the home bit in the axis struct. //Note from Beckhoff: "A maximum of 1 MB persistent data can be reliably saved over the entire service life." //Encoder Reference system types: https://infosys.beckhoff.com/english.php?content=../content/1033/tf50x0_tc3_nc_ptp/3439907723.html&id= //INCREMENTAL=0; From 25e09a769e72c6d019f43f237199bac2824bf587 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Wed, 11 Mar 2026 14:30:02 +0100 Subject: [PATCH 11/25] MBP-247: Remove action SYSTEM_TIME() Make the timestamping a one-liner, instead of an action. --- solution/tc_project_app/POUs/MAIN.TcPOU | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 66788c7..25d3933 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -25,10 +25,7 @@ VAR afbReadPositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbWritePositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_WriteParameter; fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; - fbSystemTime : GETSYSTEMTIME; - timeAsFileTime : T_FILETIME; - timeAsDT : DT; - timeAsDTAtStartup : DT; + timeAsDTAtStartup: DT; nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number END_VAR @@ -99,7 +96,6 @@ IF eGlobalSUpsState = eSUPS_PowerFailure THEN //First cycle of powerfailure //Execute code that should only be done once with each powerfailure, i.e. increase powerfailure counter bRestoreOnStartup := TRUE; - SYSTEM_TIME(); STORE_PERSISTENT(); RETURN; ELSIF eGlobalSUpsState <> eSUPS_PowerOK THEN @@ -169,8 +165,7 @@ Pneumatic_Box(); IF bRestoreOnStartup AND eGlobalSUpsState = eSUPS_PowerOK THEN bRestoreOnStartup := FALSE; bRestoreExecute := TRUE; - SYSTEM_TIME(); - timeAsDTAtStartup := timeAsDT; + timeAsDTAtStartup := FILETIME64_TO_DT(F_GetSystemTime()); FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO IF NOT astAxes[iAxes].stStatus.bAxisInitialized THEN @@ -336,15 +331,7 @@ END_IF END_FOR //Store date and time at shutdown -GVL.timeAtShutdownPersistent := timeAsDT; -]]> - - - - - timeAsFileTime.dwLowDateTime, timeHiDW => timeAsFileTime.dwHighDateTime); -timeAsDT := FILETIME_TO_DT(timeAsFileTime); - +GVL.timeAtShutdownPersistent := FILETIME64_TO_DT(F_GetSystemTime()); ]]> From 943176f7bb2b860663f5eec936852d26a566e9f8 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Wed, 11 Mar 2026 14:34:22 +0100 Subject: [PATCH 12/25] MBP-247: Replace MC_SetPosition with MC_Home MC_SetPosition is replaced by MC_Home, thus it sets the home position to actual position and the calibration flag. --- solution/tc_project_app/POUs/MAIN.TcPOU | 36 +++++++++++-------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 25d3933..9b5357a 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -21,14 +21,14 @@ VAR nRetry: INT; //A counter for startup actions iAxes: UINT; //index for for loops in Position recovery actions afbReadEncRefSys: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; - afbSetPosition: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_SetPosition; + afbSetHomePosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_Home; + stHomingParameter: MC_HomingParameter; afbReadPositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbWritePositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_WriteParameter; fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; timeAsDTAtStartup: DT; nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number END_VAR - VAR PERSISTENT bRestoreOnStartup: BOOL; //Determines whether the axis positions should be restored automatically during system startup END_VAR @@ -188,14 +188,15 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN //Cycle through set position and MC_WritePArameter function blocks for each axis FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbSetPosition[iAxes]( + afbSetHomePosition[iAxes]( Axis := GVL.astAxes[iAxes].Axis, - Position := astAxesPersistent[iAxes].fPositionAtShutdown); + Position := astAxesPersistent[iAxes].fPositionAtShutdown, + HomingMode := MC_HomingMode.MC_Direct); afbWritePositionBias[iAxes]( - Axis:= GVL.astAxes[iAxes].Axis, - ParameterNumber:= E_AxisParameters.AxisEncoderOffset, - Value:= astAxesPersistent[iAxes].fEncoderBiasAtShutdown); + Axis := GVL.astAxes[iAxes].Axis, + ParameterNumber := E_AxisParameters.AxisEncoderOffset, + Value := astAxesPersistent[iAxes].fEncoderBiasAtShutdown); END_FOR CASE eStartUp OF @@ -246,7 +247,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN (afbReadEncRefSys[iAxes].Value = 0 OR afbReadEncRefSys[iAxes].Value = 2 OR afbReadEncRefSys[iAxes].Value = 4) THEN - afbSetPosition[iAxes].Execute := TRUE; + afbSetHomePosition[iAxes].Execute := TRUE; //Restore encoder position BIAS for absolute encoders ELSIF afbReadEncRefSys[iAxes].Value = 1 OR afbReadEncRefSys[iAxes].Value = 3 OR @@ -259,7 +260,6 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN END_FOR eStartUp := eCheckRestore; - eCheckRestore: //Check the set position and write enocder BIAS fbs are finished //Nothing actually happens if the restore is not done, the code just returns from here each cycle and the @@ -271,16 +271,15 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN (afbReadEncRefSys[iAxes].Value = 0 OR afbReadEncRefSys[iAxes].Value = 2 OR afbReadEncRefSys[iAxes].Value = 4) THEN - IF afbSetPosition[iAxes].Busy THEN + IF afbSetHomePosition[iAxes].Busy THEN //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update RETURN; - END_IF - IF NOT afbSetPosition[iAxes].Done THEN - afbSetPosition[iAxes].Execute := FALSE; + ELSIF NOT afbSetHomePosition[iAxes].Done THEN + afbSetHomePosition[iAxes].Execute := FALSE; eStartUp := eExecuteRestore; RETURN; - END_IF - ELSIF afbReadEncRefSys[iAxes].Value = 1 OR + END_IF + ELSIF afbReadEncRefSys[iAxes].Value = 1 OR afbReadEncRefSys[iAxes].Value = 3 OR afbReadEncRefSys[iAxes].Value = 5 THEN IF NOT afbWritePositionBias[iAxes].Done THEN @@ -298,15 +297,10 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN eFinishRestore: //Remove execute = TRUE for afbRestorePosition and fbWritePositionBias FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbSetPosition[iAxes].Execute := FALSE; + afbSetHomePosition[iAxes].Execute := FALSE; afbWritePositionBias[iAxes].Execute := FALSE; bPositionRestoreDone := TRUE; bRestoreExecute := FALSE; - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - GVL.astAxes[iAxes].stControl.bEnable := TRUE; - GVL.astAxes[iAxes].stControl.eCommand := E_MotionFunctions.eHome; - GVL.astAxes[iAxes].stControl.bExecute := TRUE; - END_IF END_FOR END_CASE END_IF From 5013e57c15d6aebbf167f27eee5f4743cd253710 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Wed, 11 Mar 2026 14:36:50 +0100 Subject: [PATCH 13/25] MBP-247: Add the homing status as persistent --- solution/tc_project_app/POUs/MAIN.TcPOU | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 9b5357a..3d438bb 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -310,12 +310,15 @@ END_IF Date: Tue, 17 Mar 2026 16:29:28 +0100 Subject: [PATCH 14/25] MBP-247: Add enum eNextAxis --- solution/tc_project_app/POUs/MAIN.TcPOU | 35 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 3d438bb..247ada8 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -10,11 +10,11 @@ VAR hmiAxisSelection: INT := 1; //Specifies the currently selected axis for HMI operations, allowing the user to control a specific axis hmiPneumaticAxisSelection: INT := 1; //Specifies the currently selected pneumatic axis for HMI operation, allowing the user to control the specific axis -//Startup, Shutdown and UPS + //Startup, Shutdown and UPS fbCX5130UPS: FB_S_UPS_CX51x0; fbC6017UPS: FB_S_UPS_BAPI; eSelUpsMode: E_S_UPS_Mode := eSUPS_WrPersistData_Shutdown; //Selected UPS mode - eStartUp: (eColdStart, eReadAxisFeedbackType, eCheckReadDone, eExecuteRestore, eCheckRestore, eFinishRestore); + eStartUp: (eColdStart, eReadAxisFeedbackType, eCheckReadDone, eExecuteRestore, eCheckRestore, eNextAxis, eRestoreFinished); bPositionRestoreDone: BOOL := FALSE; bRestoreExecute: BOOL := FALSE; bExecuteReadEncRefSys: BOOL := FALSE; @@ -291,17 +291,26 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN ELSE RETURN; END_IF - END_FOR - eStartUp := eFinishRestore; - - eFinishRestore: - //Remove execute = TRUE for afbRestorePosition and fbWritePositionBias - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbSetHomePosition[iAxes].Execute := FALSE; - afbWritePositionBias[iAxes].Execute := FALSE; - bPositionRestoreDone := TRUE; - bRestoreExecute := FALSE; - END_FOR + //ELSE + //RETURN; + END_IF + + afbSetHomePosition[iCurrentAxis].Execute := FALSE; + afbWritePositionBias[iCurrentAxis].Execute := FALSE; + eStartUp := eNextAxis; + + eNextAxis: + iCurrentAxis := iCurrentAxis + 1; + IF iCurrentAxis > GVL_APP.nAXIS_NUM THEN + eStartUp := eRestoreFinished; + bPositionRestoreDone := TRUE; + bRestoreExecute := FALSE; + ELSE + eStartUp := eReadAxisFeedbackType; + END_IF + + eRestoreFinished: + //Do nothing END_CASE END_IF ]]> From b75774fba8f35ed1b4fb25a9eac4c2eb7384bd3f Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 17 Mar 2026 16:33:25 +0100 Subject: [PATCH 15/25] MBP-247: Change to loop with different index Changed solution to loop using the iCurrentAxis index, and incrementing if position restore was properly executed or if axis was not initialized properly or if axis was not homed before power failure. --- solution/tc_project_app/POUs/MAIN.TcPOU | 205 +++++++++++++----------- 1 file changed, 110 insertions(+), 95 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 247ada8..74f62ce 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -18,8 +18,9 @@ VAR bPositionRestoreDone: BOOL := FALSE; bRestoreExecute: BOOL := FALSE; bExecuteReadEncRefSys: BOOL := FALSE; - nRetry: INT; //A counter for startup actions - iAxes: UINT; //index for for loops in Position recovery actions + nRetry: INT; //Counter for startup actions + iAxes: UINT := 1; //Index for, for loops in position recovery actions + iCurrentAxis: UINT := 1; //Index for position recovery actions (not in for loops) afbReadEncRefSys: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbSetHomePosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_Home; stHomingParameter: MC_HomingParameter; @@ -166,38 +167,44 @@ IF bRestoreOnStartup AND eGlobalSUpsState = eSUPS_PowerOK THEN bRestoreOnStartup := FALSE; bRestoreExecute := TRUE; timeAsDTAtStartup := FILETIME64_TO_DT(F_GetSystemTime()); + iCurrentAxis := 1; +END_IF - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF NOT astAxes[iAxes].stStatus.bAxisInitialized THEN - //Do nothing if axis has not been initialized - RETURN; - END_IF - END_FOR +IF iCurrentAxis > GVL_APP.nAXIS_NUM THEN + RETURN; END_IF //Upon startup bPositionRestoreDone will be set to FALSE, after successfully completing the following code it will be set TRUE //and should stay TRUE for the rest of the time the PLC is operational, thus this routine should only be completed once. IF bRestoreExecute AND NOT bPositionRestoreDone THEN - //Cycle through function blocks that read the encoder reference system i.e. whether axis is incremental or absolute - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbReadEncRefSys[iAxes]( - Axis := GVL.astAxes[iAxes].Axis, - ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, - ReadMode := E_READMODE.READMODE_ONCE); - END_FOR - - //Cycle through set position and MC_WritePArameter function blocks for each axis - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbSetHomePosition[iAxes]( - Axis := GVL.astAxes[iAxes].Axis, - Position := astAxesPersistent[iAxes].fPositionAtShutdown, - HomingMode := MC_HomingMode.MC_Direct); - - afbWritePositionBias[iAxes]( - Axis := GVL.astAxes[iAxes].Axis, - ParameterNumber := E_AxisParameters.AxisEncoderOffset, - Value := astAxesPersistent[iAxes].fEncoderBiasAtShutdown); - END_FOR + + IF NOT astAxes[iCurrentAxis].stStatus.bAxisInitialized OR NOT astAxesPersistent[iCurrentAxis].bHomedAtShutdown THEN + //If current axis has not been initialized or was not homed before power failure, perform position recovery for next axis + eStartUp := eNextAxis; + ELSE + //Cycle through function blocks that read the encoder reference system i.e. whether axis is incremental or absolute + //Cycle through set position and MC_WritePArameter function blocks for each axis + afbReadEncRefSys[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, + ReadMode := E_READMODE.READMODE_ONCE); + + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + afbSetPosition[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown); + ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + afbSetHomePosition[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown, + HomingMode := MC_HomingMode.MC_Direct); + END_IF + + afbWritePositionBias[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + ParameterNumber := E_AxisParameters.AxisEncoderOffset, + Value := astAxesPersistent[iCurrentAxis].fEncoderBiasAtShutdown); + END_IF CASE eStartUp OF eColdStart: @@ -209,87 +216,95 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN eReadAxisFeedbackType: //Exectute the function blocks to read the encoder reference system (0=inc OR 1=ABS) - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbReadEncRefSys[iAxes].Enable := TRUE; - eStartUp := eCheckReadDone; - END_FOR + afbReadEncRefSys[iCurrentAxis].Enable := TRUE; + eStartUp := eCheckReadDone; eCheckReadDone: //Check the encoder reference system has been read for all axis -> if busy then continue with PLC cycle and check again next time. //If afbReadEncRefSys not started then go back a step. - //If any axes result in an error the code will get stuck here, this happens if GVL_APP.nAXIS_NUM is not set correctly - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF NOT afbReadEncRefSys[iAxes].Valid THEN - IF afbReadEncRefSys[iAxes].Busy THEN - //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update - RETURN; - ELSE - //Sometimes the code gets here and the afbReadEncRefSys[iAxes] misses the rising edge. If the code gets here it means - //valid=FALSE and .busy=FALSE which indicateds the FB probably hasn't started and thus needs to see a rising edge. - //Set execute to low, Exit MAIN.STARTUP and go back a step in the CASE statement. - afbReadEncRefSys[iAxes].Enable := FALSE; - eStartUp := eReadAxisFeedbackType; - nRetry := nRetry + 1; //counter used for troubleshooting to see how many cycles it takes before afbReadEncRefSys function blocks are read correctly - RETURN; - END_IF - END_IF - END_FOR - //If the code gets here all axes have .valid=TRUE for all axes + //If the current axis result in an error the code will get stuck here, this happens if GVL_APP.nAXIS_NUM is not set correctly + IF NOT afbReadEncRefSys[iCurrentAxis].Valid THEN + IF afbReadEncRefSys[iCurrentAxis].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + ELSE + //Sometimes the code gets here and the afbReadEncRefSys[iCurrentAxis] misses the rising edge. If the code gets here it means + //valid=FALSE and .busy=FALSE which indicateds the FB probably hasn't started and thus needs to see a rising edge. + //Set execute to low, Exit MAIN.STARTUP and go back a step in the CASE statement. + afbReadEncRefSys[iCurrentAxis].Enable := FALSE; + eStartUp := eReadAxisFeedbackType; + nRetry := nRetry + 1; //Counter used for troubleshooting to see how many cycles it takes before afbReadEncRefSys function blocks are read correctly + RETURN; + END_IF + END_IF + + //If the code gets here the current axis has .valid=TRUE eStartUp := eExecuteRestore; eExecuteRestore: //Execute position and encoder BIAS restore by setting Execute = TRUE - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR - GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - //Restore position value for incremental encoders - IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND - (afbReadEncRefSys[iAxes].Value = 0 OR - afbReadEncRefSys[iAxes].Value = 2 OR - afbReadEncRefSys[iAxes].Value = 4) THEN - afbSetHomePosition[iAxes].Execute := TRUE; - //Restore encoder position BIAS for absolute encoders - ELSIF afbReadEncRefSys[iAxes].Value = 1 OR - afbReadEncRefSys[iAxes].Value = 3 OR - afbReadEncRefSys[iAxes].Value = 5 THEN - afbWritePositionBias[iAxes].Execute := TRUE; - END_IF - ELSE - RETURN; - END_IF - END_FOR + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN + IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF + INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: + // Restore position value for incremental encoders + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + afbSetPosition[iCurrentAxis].Execute := TRUE; + ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + afbSetHomePosition[iCurrentAxis].Execute := TRUE; + END_IF + ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: + // Restore encoder position BIAS for absolute encoders + afbWritePositionBias[iCurrentAxis].Execute := TRUE; + END_CASE + ELSE + RETURN; + END_IF + END_IF + eStartUp := eCheckRestore; eCheckRestore: //Check the set position and write enocder BIAS fbs are finished //Nothing actually happens if the restore is not done, the code just returns from here each cycle and the //bPositionRestoreDone will never get set to TRUE and will take up cycle time - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR - GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND - (afbReadEncRefSys[iAxes].Value = 0 OR - afbReadEncRefSys[iAxes].Value = 2 OR - afbReadEncRefSys[iAxes].Value = 4) THEN - IF afbSetHomePosition[iAxes].Busy THEN - //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update - RETURN; - ELSIF NOT afbSetHomePosition[iAxes].Done THEN - afbSetHomePosition[iAxes].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF - ELSIF afbReadEncRefSys[iAxes].Value = 1 OR - afbReadEncRefSys[iAxes].Value = 3 OR - afbReadEncRefSys[iAxes].Value = 5 THEN - IF NOT afbWritePositionBias[iAxes].Done THEN - afbWritePositionBias[iAxes].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF - END_IF - ELSE - RETURN; + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN + IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF + INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: + IF afbSetPosition[iCurrentAxis].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + END_IF + + IF afbSetHomePosition[iCurrentAxis].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + END_IF + + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF NOT afbSetPosition[iCurrentAxis].Done THEN + afbSetPosition[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_IF + + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + IF NOT afbSetHomePosition[iCurrentAxis].Done THEN + afbSetHomePosition[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_IF + + ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: + IF NOT afbWritePositionBias[iCurrentAxis].Done THEN + afbWritePositionBias[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_CASE END_IF //ELSE //RETURN; From 17978971edb1d3852f2a2e3ebbfce2656aa8a5b2 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 17 Mar 2026 16:42:18 +0100 Subject: [PATCH 16/25] MBP-247: Add constants for the encoder reference Changed encoder reference to be constants, for better readability. --- solution/tc_project_app/POUs/MAIN.TcPOU | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 74f62ce..aa4473f 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -23,13 +23,21 @@ VAR iCurrentAxis: UINT := 1; //Index for position recovery actions (not in for loops) afbReadEncRefSys: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbSetHomePosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_Home; - stHomingParameter: MC_HomingParameter; + afbSetPosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_SetPosition; afbReadPositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbWritePositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_WriteParameter; fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; timeAsDTAtStartup: DT; nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number END_VAR +VAR CONSTANT + INCREMENTAL: UINT := 0; + ABSOLUTE: UINT := 1; + ABSOLUTE_MODULO: UINT := 2; + ABSOLUTE_MULTITURN_RANGE: UINT := 3; //(with single overflow) + INCREMENTAL_SINGLETURN_ABSOLUTE: UINT := 4; + ABSOLUTE_SINGLETURN_RANGE: UINT :=5; //(with single overflow) +END_VAR VAR PERSISTENT bRestoreOnStartup: BOOL; //Determines whether the axis positions should be restored automatically during system startup END_VAR From c3f8aea2917486be480f363871a389755967b494 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 17 Mar 2026 16:46:12 +0100 Subject: [PATCH 17/25] MBP-247: Remove redundant return statements --- solution/tc_project_app/POUs/MAIN.TcPOU | 2 -- 1 file changed, 2 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index aa4473f..3303d41 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -106,11 +106,9 @@ IF eGlobalSUpsState = eSUPS_PowerFailure THEN //Execute code that should only be done once with each powerfailure, i.e. increase powerfailure counter bRestoreOnStartup := TRUE; STORE_PERSISTENT(); - RETURN; ELSIF eGlobalSUpsState <> eSUPS_PowerOK THEN //Next cycles of powerfailure //Skip regular code execution for the remaining cycles of the powerfailure/writing of persistent data/quick shutdown... - RETURN; END_IF ]]> From fe35dd29315681ab1ff0629e3c56dbcc28dfc358 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 17 Mar 2026 16:50:49 +0100 Subject: [PATCH 18/25] MBP-247: Check whitespace --- solution/tc_project_app/POUs/MAIN.TcPOU | 264 ++++++++++++------------ 1 file changed, 134 insertions(+), 130 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 3303d41..470f147 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -10,7 +10,7 @@ VAR hmiAxisSelection: INT := 1; //Specifies the currently selected axis for HMI operations, allowing the user to control a specific axis hmiPneumaticAxisSelection: INT := 1; //Specifies the currently selected pneumatic axis for HMI operation, allowing the user to control the specific axis - //Startup, Shutdown and UPS + //Startup, Shutdown and UPS fbCX5130UPS: FB_S_UPS_CX51x0; fbC6017UPS: FB_S_UPS_BAPI; eSelUpsMode: E_S_UPS_Mode := eSUPS_WrPersistData_Shutdown; //Selected UPS mode @@ -20,10 +20,10 @@ VAR bExecuteReadEncRefSys: BOOL := FALSE; nRetry: INT; //Counter for startup actions iAxes: UINT := 1; //Index for, for loops in position recovery actions - iCurrentAxis: UINT := 1; //Index for position recovery actions (not in for loops) + iCurrentAxis: UINT := 1; //Index for position recovery actions (not in for loops) afbReadEncRefSys: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbSetHomePosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_Home; - afbSetPosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_SetPosition; + afbSetPosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_SetPosition; afbReadPositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbWritePositionBias: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_WriteParameter; fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; @@ -31,12 +31,12 @@ VAR nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number END_VAR VAR CONSTANT - INCREMENTAL: UINT := 0; - ABSOLUTE: UINT := 1; - ABSOLUTE_MODULO: UINT := 2; - ABSOLUTE_MULTITURN_RANGE: UINT := 3; //(with single overflow) - INCREMENTAL_SINGLETURN_ABSOLUTE: UINT := 4; - ABSOLUTE_SINGLETURN_RANGE: UINT :=5; //(with single overflow) + INCREMENTAL: UINT := 0; + ABSOLUTE: UINT := 1; + ABSOLUTE_MODULO: UINT := 2; + ABSOLUTE_MULTITURN_RANGE: UINT := 3; //(with single overflow) + INCREMENTAL_SINGLETURN_ABSOLUTE: UINT := 4; + ABSOLUTE_SINGLETURN_RANGE: UINT :=5; //(with single overflow) END_VAR VAR PERSISTENT bRestoreOnStartup: BOOL; //Determines whether the axis positions should be restored automatically during system startup @@ -46,6 +46,10 @@ END_VAR @@ -173,44 +177,44 @@ IF bRestoreOnStartup AND eGlobalSUpsState = eSUPS_PowerOK THEN bRestoreOnStartup := FALSE; bRestoreExecute := TRUE; timeAsDTAtStartup := FILETIME64_TO_DT(F_GetSystemTime()); - iCurrentAxis := 1; + iCurrentAxis := 1; END_IF -IF iCurrentAxis > GVL_APP.nAXIS_NUM THEN - RETURN; +IF iCurrentAxis > GVL_APP.nAXIS_NUM THEN + RETURN; END_IF //Upon startup bPositionRestoreDone will be set to FALSE, after successfully completing the following code it will be set TRUE //and should stay TRUE for the rest of the time the PLC is operational, thus this routine should only be completed once. IF bRestoreExecute AND NOT bPositionRestoreDone THEN - - IF NOT astAxes[iCurrentAxis].stStatus.bAxisInitialized OR NOT astAxesPersistent[iCurrentAxis].bHomedAtShutdown THEN - //If current axis has not been initialized or was not homed before power failure, perform position recovery for next axis - eStartUp := eNextAxis; - ELSE - //Cycle through function blocks that read the encoder reference system i.e. whether axis is incremental or absolute - //Cycle through set position and MC_WritePArameter function blocks for each axis - afbReadEncRefSys[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, - ReadMode := E_READMODE.READMODE_ONCE); - - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN - afbSetPosition[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown); - ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - afbSetHomePosition[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown, - HomingMode := MC_HomingMode.MC_Direct); - END_IF - - afbWritePositionBias[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - ParameterNumber := E_AxisParameters.AxisEncoderOffset, - Value := astAxesPersistent[iCurrentAxis].fEncoderBiasAtShutdown); - END_IF + + IF NOT astAxes[iCurrentAxis].stStatus.bAxisInitialized OR NOT astAxesPersistent[iCurrentAxis].bHomedAtShutdown THEN + //If current axis has not been initialized or was not homed before power failure, perform position recovery for next axis + eStartUp := eNextAxis; + ELSE + //Cycle through function blocks that read the encoder reference system i.e. whether axis is incremental or absolute + //Cycle through set position and MC_WritePArameter function blocks for each axis + afbReadEncRefSys[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, + ReadMode := E_READMODE.READMODE_ONCE); + + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + afbSetPosition[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown); + ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + afbSetHomePosition[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown, + HomingMode := MC_HomingMode.MC_Direct); + END_IF + + afbWritePositionBias[iCurrentAxis]( + Axis := GVL.astAxes[iCurrentAxis].Axis, + ParameterNumber := E_AxisParameters.AxisEncoderOffset, + Value := astAxesPersistent[iCurrentAxis].fEncoderBiasAtShutdown); + END_IF CASE eStartUp OF eColdStart: @@ -222,116 +226,116 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN eReadAxisFeedbackType: //Exectute the function blocks to read the encoder reference system (0=inc OR 1=ABS) - afbReadEncRefSys[iCurrentAxis].Enable := TRUE; - eStartUp := eCheckReadDone; + afbReadEncRefSys[iCurrentAxis].Enable := TRUE; + eStartUp := eCheckReadDone; eCheckReadDone: //Check the encoder reference system has been read for all axis -> if busy then continue with PLC cycle and check again next time. //If afbReadEncRefSys not started then go back a step. //If the current axis result in an error the code will get stuck here, this happens if GVL_APP.nAXIS_NUM is not set correctly - IF NOT afbReadEncRefSys[iCurrentAxis].Valid THEN - IF afbReadEncRefSys[iCurrentAxis].Busy THEN - //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update - RETURN; - ELSE - //Sometimes the code gets here and the afbReadEncRefSys[iCurrentAxis] misses the rising edge. If the code gets here it means - //valid=FALSE and .busy=FALSE which indicateds the FB probably hasn't started and thus needs to see a rising edge. - //Set execute to low, Exit MAIN.STARTUP and go back a step in the CASE statement. - afbReadEncRefSys[iCurrentAxis].Enable := FALSE; - eStartUp := eReadAxisFeedbackType; - nRetry := nRetry + 1; //Counter used for troubleshooting to see how many cycles it takes before afbReadEncRefSys function blocks are read correctly - RETURN; - END_IF - END_IF - + IF NOT afbReadEncRefSys[iCurrentAxis].Valid THEN + IF afbReadEncRefSys[iCurrentAxis].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + ELSE + //Sometimes the code gets here and the afbReadEncRefSys[iCurrentAxis] misses the rising edge. If the code gets here it means + //valid=FALSE and .busy=FALSE which indicateds the FB probably hasn't started and thus needs to see a rising edge. + //Set execute to low, Exit MAIN.STARTUP and go back a step in the CASE statement. + afbReadEncRefSys[iCurrentAxis].Enable := FALSE; + eStartUp := eReadAxisFeedbackType; + nRetry := nRetry + 1; //Counter used for troubleshooting to see how many cycles it takes before afbReadEncRefSys function blocks are read correctly + RETURN; + END_IF + END_IF + //If the code gets here the current axis has .valid=TRUE eStartUp := eExecuteRestore; eExecuteRestore: //Execute position and encoder BIAS restore by setting Execute = TRUE - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN - IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN - CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF - INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: - // Restore position value for incremental encoders - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN - afbSetPosition[iCurrentAxis].Execute := TRUE; - ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - afbSetHomePosition[iCurrentAxis].Execute := TRUE; - END_IF - ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: - // Restore encoder position BIAS for absolute encoders - afbWritePositionBias[iCurrentAxis].Execute := TRUE; - END_CASE - ELSE - RETURN; - END_IF - END_IF - + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN + IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF + INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: + // Restore position value for incremental encoders + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + afbSetPosition[iCurrentAxis].Execute := TRUE; + ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + afbSetHomePosition[iCurrentAxis].Execute := TRUE; + END_IF + ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: + // Restore encoder position BIAS for absolute encoders + afbWritePositionBias[iCurrentAxis].Execute := TRUE; + END_CASE + ELSE + RETURN; + END_IF + END_IF + eStartUp := eCheckRestore; eCheckRestore: //Check the set position and write enocder BIAS fbs are finished //Nothing actually happens if the restore is not done, the code just returns from here each cycle and the //bPositionRestoreDone will never get set to TRUE and will take up cycle time - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN - IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN - CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF - INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: - IF afbSetPosition[iCurrentAxis].Busy THEN - //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update - RETURN; - END_IF - - IF afbSetHomePosition[iCurrentAxis].Busy THEN - //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update - RETURN; - END_IF - - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN - IF NOT afbSetPosition[iCurrentAxis].Done THEN - afbSetPosition[iCurrentAxis].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF - END_IF - - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - IF NOT afbSetHomePosition[iCurrentAxis].Done THEN - afbSetHomePosition[iCurrentAxis].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF - END_IF - - ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: - IF NOT afbWritePositionBias[iCurrentAxis].Done THEN - afbWritePositionBias[iCurrentAxis].Execute := FALSE; - eStartUp := eExecuteRestore; - RETURN; - END_IF - END_CASE + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN + IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF + INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: + IF afbSetPosition[iCurrentAxis].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + END_IF + + IF afbSetHomePosition[iCurrentAxis].Busy THEN + //Exit MAIN.RESTORE_POSITIONS Action and wait till next cycle, needs to cycle through whole program in order for data to update + RETURN; + END_IF + + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF NOT afbSetPosition[iCurrentAxis].Done THEN + afbSetPosition[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_IF + + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + IF NOT afbSetHomePosition[iCurrentAxis].Done THEN + afbSetHomePosition[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_IF + + ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: + IF NOT afbWritePositionBias[iCurrentAxis].Done THEN + afbWritePositionBias[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_CASE END_IF - //ELSE - //RETURN; - END_IF - - afbSetHomePosition[iCurrentAxis].Execute := FALSE; + //ELSE + //RETURN; + END_IF + + afbSetHomePosition[iCurrentAxis].Execute := FALSE; afbWritePositionBias[iCurrentAxis].Execute := FALSE; eStartUp := eNextAxis; - - eNextAxis: - iCurrentAxis := iCurrentAxis + 1; - IF iCurrentAxis > GVL_APP.nAXIS_NUM THEN - eStartUp := eRestoreFinished; - bPositionRestoreDone := TRUE; - bRestoreExecute := FALSE; - ELSE - eStartUp := eReadAxisFeedbackType; - END_IF - + + eNextAxis: + iCurrentAxis := iCurrentAxis + 1; + IF iCurrentAxis > GVL_APP.nAXIS_NUM THEN + eStartUp := eRestoreFinished; + bPositionRestoreDone := TRUE; + bRestoreExecute := FALSE; + ELSE + eStartUp := eReadAxisFeedbackType; + END_IF + eRestoreFinished: - //Do nothing + //Do nothing END_CASE END_IF ]]> From 62fd6305c1567122ba36afa0051fd8a2326e2e8b Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Thu, 26 Mar 2026 08:23:20 +0100 Subject: [PATCH 19/25] MBP-247: Change logic restore position Always restore position despite an axis not being initilized or homed during shutdown. --- solution/tc_project_app/POUs/MAIN.TcPOU | 52 +++++++++++++------------ 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 470f147..c31b197 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -188,33 +188,35 @@ END_IF //and should stay TRUE for the rest of the time the PLC is operational, thus this routine should only be completed once. IF bRestoreExecute AND NOT bPositionRestoreDone THEN - IF NOT astAxes[iCurrentAxis].stStatus.bAxisInitialized OR NOT astAxesPersistent[iCurrentAxis].bHomedAtShutdown THEN - //If current axis has not been initialized or was not homed before power failure, perform position recovery for next axis - eStartUp := eNextAxis; - ELSE +// //If current axis has not been initialized properly or was not homed before power failure, perform position recovery for next axis +// IF NOT astAxes[iCurrentAxis].stStatus.bAxisInitialized OR NOT astAxesPersistent[iCurrentAxis].bHomedAtShutdown THEN +// eStartUp := eNextAxis; +// ELSE //Cycle through function blocks that read the encoder reference system i.e. whether axis is incremental or absolute //Cycle through set position and MC_WritePArameter function blocks for each axis - afbReadEncRefSys[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, - ReadMode := E_READMODE.READMODE_ONCE); - - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN - afbSetPosition[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown); - ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - afbSetHomePosition[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - Position := astAxesPersistent[iCurrentAxis].fPositionAtShutdown, - HomingMode := MC_HomingMode.MC_Direct); - END_IF - - afbWritePositionBias[iCurrentAxis]( - Axis := GVL.astAxes[iCurrentAxis].Axis, - ParameterNumber := E_AxisParameters.AxisEncoderOffset, - Value := astAxesPersistent[iCurrentAxis].fEncoderBiasAtShutdown); - END_IF + FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO + afbReadEncRefSys[iAxes]( + Axis := GVL.astAxes[iAxes].Axis, + ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, + ReadMode := E_READMODE.READMODE_ONCE); + + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + afbSetPosition[iAxes]( + Axis := GVL.astAxes[iAxes].Axis, + Position := astAxesPersistent[iAxes].fPositionAtShutdown); + ELSIF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + afbSetHomePosition[iAxes]( + Axis := GVL.astAxes[iAxes].Axis, + Position := astAxesPersistent[iAxes].fPositionAtShutdown, + HomingMode := MC_HomingMode.MC_Direct); + END_IF + + afbWritePositionBias[iAxes]( + Axis := GVL.astAxes[iAxes].Axis, + ParameterNumber := E_AxisParameters.AxisEncoderOffset, + Value := astAxesPersistent[iAxes].fEncoderBiasAtShutdown); + END_FOR +// END_IF CASE eStartUp OF eColdStart: From 9b0532b43c1564201ef4020d51862e7c5d21a86b Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 7 Apr 2026 08:15:21 +0200 Subject: [PATCH 20/25] MBP-247: Sample position at specific time interval For incremental encoders the moving status of the axis cannot be determined before a power failure, therefore the position of the axis is sampled every 5 seconds with a difference limit of 0.001 mm. These values can be changed. --- solution/tc_project_app/POUs/MAIN.TcPOU | 26 +++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index c31b197..f707d63 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -7,6 +7,7 @@ VAR aIAxes: ARRAY [1..GVL_APP.nAXIS_NUM] OF I_Axis; //Array of axis interfaces, size determined by the total number of axes in the system afbAxes: ARRAY [1..GVL_APP.nAXIS_NUM] OF FB_Axis; //Array of axis function blocks, one for each axis afbPneumaticAxes: ARRAY [1..GVL_APP.nPNEUMATIC_AXIS_NUM] OF FB_PneumaticAxis; //Array of pneumatic axis function blocks, size determined by the number of pneumatic axes + afCurrentPosition: ARRAY [1..GVL_APP.nAXIS_NUM] OF LREAL; //Stores the current position of each axis at defined time intervals, see timeReadPosition hmiAxisSelection: INT := 1; //Specifies the currently selected axis for HMI operations, allowing the user to control a specific axis hmiPneumaticAxisSelection: INT := 1; //Specifies the currently selected pneumatic axis for HMI operation, allowing the user to control the specific axis @@ -29,6 +30,12 @@ VAR fbGetDeviceIdentification: FB_GetDeviceIdentificationEx; timeAsDTAtStartup: DT; nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number + + //Read position at a specific time interval + tonReadPosition: TON; + bReadPosition: BOOL:= TRUE; + timeReadPosition: TIME := T#5S; //Interval time + fPositionDifferenceLimit: LREAL := 0.001; //The acceptable difference between the sampled position and position at shutdown END_VAR VAR CONSTANT INCREMENTAL: UINT := 0; @@ -119,7 +126,22 @@ END_IF - '') THEN CHECK_UPS(); RESTORE_POSITIONS(); @@ -356,7 +378,7 @@ END_IF astAxesPersistent[iAxes].bHomedAtShutdown := GVL.astAxes[iAxes].stStatus.bHomed; //Store value of moving at shutdown - IF GVL.astAxes[iAxes].Axis.Status.StandStill OR GVL.astAxes[iAxes].Axis.Status.Disabled THEN + IF GVL.astAxes[iAxes].Axis.Status.Disabled OR astAxesPersistent[iAxes].fPositionDifference < fPositionDifferenceLimit THEN astAxesPersistent[iAxes].bMovingAtShutdown := FALSE; ELSE astAxesPersistent[iAxes].bMovingAtShutdown := TRUE; From 7502455a78a66c00c6b861534ceff70311442b57 Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 7 Apr 2026 08:25:37 +0200 Subject: [PATCH 21/25] MBP-247: Execution logic change Cleanup of the execution logic for restore position action. --- solution/tc_project_app/POUs/MAIN.TcPOU | 35 +++++++++---------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index f707d63..ad7e64f 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -19,8 +19,9 @@ VAR bPositionRestoreDone: BOOL := FALSE; bRestoreExecute: BOOL := FALSE; bExecuteReadEncRefSys: BOOL := FALSE; - nRetry: INT; //Counter for startup actions - iAxes: UINT := 1; //Index for, for loops in position recovery actions + nRetry: INT; //A counter for startup actions + iAxes: UINT; //Index for, for-loops in position recovery actions + iCurrentAxis: UINT := 1; //Index for position recovery actions (not in for loops) afbReadEncRefSys: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_ReadParameter; afbSetHomePosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_Home; @@ -210,19 +211,13 @@ END_IF //and should stay TRUE for the rest of the time the PLC is operational, thus this routine should only be completed once. IF bRestoreExecute AND NOT bPositionRestoreDone THEN -// //If current axis has not been initialized properly or was not homed before power failure, perform position recovery for next axis -// IF NOT astAxes[iCurrentAxis].stStatus.bAxisInitialized OR NOT astAxesPersistent[iCurrentAxis].bHomedAtShutdown THEN -// eStartUp := eNextAxis; -// ELSE - //Cycle through function blocks that read the encoder reference system i.e. whether axis is incremental or absolute - //Cycle through set position and MC_WritePArameter function blocks for each axis FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO afbReadEncRefSys[iAxes]( Axis := GVL.astAxes[iAxes].Axis, ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, ReadMode := E_READMODE.READMODE_ONCE); - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR NOT GVL.astAxesPersistent[iAxes].bHomedAtShutdown THEN afbSetPosition[iAxes]( Axis := GVL.astAxes[iAxes].Axis, Position := astAxesPersistent[iAxes].fPositionAtShutdown); @@ -238,7 +233,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN ParameterNumber := E_AxisParameters.AxisEncoderOffset, Value := astAxesPersistent[iAxes].fEncoderBiasAtShutdown); END_FOR -// END_IF + CASE eStartUp OF eColdStart: @@ -249,7 +244,11 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN END_IF eReadAxisFeedbackType: - //Exectute the function blocks to read the encoder reference system (0=inc OR 1=ABS) + IF NOT GVL.astAxesPersistent[iCurrentAxis].bInitialized THEN + eStartUp := eNextAxis; + RETURN; + END_IF + //Execute the function blocks to read the encoder reference system (0=inc OR 1=ABS) afbReadEncRefSys[iCurrentAxis].Enable := TRUE; eStartUp := eCheckReadDone; @@ -278,11 +277,10 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN eExecuteRestore: //Execute position and encoder BIAS restore by setting Execute = TRUE IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN - IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: // Restore position value for incremental encoders - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN afbSetPosition[iCurrentAxis].Execute := TRUE; ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN afbSetHomePosition[iCurrentAxis].Execute := TRUE; @@ -291,9 +289,6 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN // Restore encoder position BIAS for absolute encoders afbWritePositionBias[iCurrentAxis].Execute := TRUE; END_CASE - ELSE - RETURN; - END_IF END_IF eStartUp := eCheckRestore; @@ -303,7 +298,6 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN //Nothing actually happens if the restore is not done, the code just returns from here each cycle and the //bPositionRestoreDone will never get set to TRUE and will take up cycle time IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN - IF NOT astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: IF afbSetPosition[iCurrentAxis].Busy THEN @@ -316,7 +310,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN RETURN; END_IF - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome THEN + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN IF NOT afbSetPosition[iCurrentAxis].Done THEN afbSetPosition[iCurrentAxis].Execute := FALSE; eStartUp := eExecuteRestore; @@ -324,7 +318,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN END_IF END_IF - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome AND NOT GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN IF NOT afbSetHomePosition[iCurrentAxis].Done THEN afbSetHomePosition[iCurrentAxis].Execute := FALSE; eStartUp := eExecuteRestore; @@ -339,9 +333,6 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN RETURN; END_IF END_CASE - END_IF - //ELSE - //RETURN; END_IF afbSetHomePosition[iCurrentAxis].Execute := FALSE; From 0d4ac6594a4db5dd7fa6f657ec53ad8ab80b84bf Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 7 Apr 2026 08:30:24 +0200 Subject: [PATCH 22/25] MBP-247: Save axis status variables as persistent --- solution/tc_project_app/POUs/MAIN.TcPOU | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index ad7e64f..24b46f0 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -365,8 +365,20 @@ END_IF //Store encoder position BIAS at shutdown astAxesPersistent[iAxes].fEncoderBiasAtShutdown := afbReadPositionBias[iAxes].Value; - //Store homing status at shutdown + //Store axis status at shutdown + astAxesPersistent[iAxes].bInitialized := GVL.astAxes[iAxes].stStatus.bAxisInitialized; astAxesPersistent[iAxes].bHomedAtShutdown := GVL.astAxes[iAxes].stStatus.bHomed; + astAxesPersistent[iAxes].stMotionState := GVL.astAxes[iAxes].Axis.Status.MotionState; + astAxesPersistent[iAxes].bError := GVL.astAxes[iAxes].Axis.Status.Error; + astAxesPersistent[iAxes].nErrorID := GVL.astAxes[iAxes].Axis.Status.ErrorID; + astAxesPersistent[iAxes].bErrorStop := GVL.astAxes[iAxes].Axis.Status.ErrorStop; + astAxesPersistent[iAxes].bStandStill := GVL.astAxes[iAxes].Axis.Status.StandStill; + astAxesPersistent[iAxes].bHasBeenStopped := GVL.astAxes[iAxes].Axis.Status.HasBeenStopped; + astAxesPersistent[iAxes].bDisabled := GVL.astAxes[iAxes].Axis.Status.Disabled; + astAxesPersistent[iAxes].bMoving := GVL.astAxes[iAxes].Axis.Status.Moving; + + astAxesPersistent[iAxes].nCycles := astAxesPersistent[iAxes].nCycles + 1; + astAxesPersistent[iAxes].fPositionDifference := ABS(afCurrentPosition[iAxes] - astAxesPersistent[iAxes].fPositionAtShutdown); //Store value of moving at shutdown IF GVL.astAxes[iAxes].Axis.Status.Disabled OR astAxesPersistent[iAxes].fPositionDifference < fPositionDifferenceLimit THEN From f5968a57f8c7d5af540e156e28b28b9a6835fabe Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 7 Apr 2026 10:58:46 +0200 Subject: [PATCH 23/25] MBP-247: Correct naming convention Change to correct naming for TON-timers and time. --- solution/tc_project_app/POUs/MAIN.TcPOU | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 24b46f0..6e55c18 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -33,9 +33,9 @@ VAR nTestNum: UINT :=0 ; //Variable used in ESS's FAT_SAT_tools scripts to keep track of the test number //Read position at a specific time interval - tonReadPosition: TON; + fbReadPositionTimer: TON; bReadPosition: BOOL:= TRUE; - timeReadPosition: TIME := T#5S; //Interval time + tReadPosition: TIME := T#5S; //Interval time fPositionDifferenceLimit: LREAL := 0.001; //The acceptable difference between the sampled position and position at shutdown END_VAR VAR CONSTANT @@ -127,16 +127,16 @@ END_IF - Date: Tue, 7 Apr 2026 11:00:59 +0200 Subject: [PATCH 24/25] MBP-247: Adjust execution logic MBP-247: Adjust execution logic to match E_RestorePosition changes. --- solution/tc_project_app/POUs/MAIN.TcPOU | 41 ++++++++++++++----------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 6e55c18..6d1bc0b 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -217,21 +217,26 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN ParameterNumber := MC_AxisParameter.AxisEncoderReferenceSystem, ReadMode := E_READMODE.READMODE_ONCE); - IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR NOT GVL.astAxesPersistent[iAxes].bHomedAtShutdown THEN - afbSetPosition[iAxes]( - Axis := GVL.astAxes[iAxes].Axis, - Position := astAxesPersistent[iAxes].fPositionAtShutdown); - ELSIF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN - afbSetHomePosition[iAxes]( - Axis := GVL.astAxes[iAxes].Axis, - Position := astAxesPersistent[iAxes].fPositionAtShutdown, - HomingMode := MC_HomingMode.MC_Direct); + //Position recovery for incremental encoders + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestorePosition THEN + IF GVL.astAxesPersistent[iAxes].bHomedAtShutdown AND NOT GVL.astAxesPersistent[iAxes].bMovingAtShutdown THEN + afbSetHomePosition[iAxes]( + Axis := GVL.astAxes[iAxes].Axis, + Position := astAxesPersistent[iAxes].fPositionAtShutdown, + HomingMode := MC_HomingMode.MC_Direct); + ELSE + afbSetPosition[iAxes]( + Axis := GVL.astAxes[iAxes].Axis, + Position := astAxesPersistent[iAxes].fPositionAtShutdown); + END_IF END_IF - + //Position recovery for absolute encoders + IF GVL.astAxes[iAxes].stConfig.eRestorePosition = E_RestorePosition.eRestorePositionBias THEN afbWritePositionBias[iAxes]( Axis := GVL.astAxes[iAxes].Axis, ParameterNumber := E_AxisParameters.AxisEncoderOffset, Value := astAxesPersistent[iAxes].fEncoderBiasAtShutdown); + END_IF END_FOR @@ -244,7 +249,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN END_IF eReadAxisFeedbackType: - IF NOT GVL.astAxesPersistent[iCurrentAxis].bInitialized THEN + IF NOT GVL.astAxesPersistent[iCurrentAxis].bInitializedAtShutdown THEN eStartUp := eNextAxis; RETURN; END_IF @@ -279,14 +284,14 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore THEN CASE LREAL_TO_UINT(afbReadEncRefSys[iCurrentAxis].Value) OF INCREMENTAL, ABSOLUTE_MODULO, INCREMENTAL_SINGLETURN_ABSOLUTE: - // Restore position value for incremental encoders - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN - afbSetPosition[iCurrentAxis].Execute := TRUE; - ELSIF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome THEN + //Restore position value for incremental encoders + IF GVL.astAxesPersistent[iAxes].bHomedAtShutdown AND NOT GVL.astAxesPersistent[iAxes].bMovingAtShutdown THEN afbSetHomePosition[iCurrentAxis].Execute := TRUE; + ELSE + afbSetPosition[iCurrentAxis].Execute := TRUE; END_IF ABSOLUTE, ABSOLUTE_MULTITURN_RANGE, ABSOLUTE_SINGLETURN_RANGE: - // Restore encoder position BIAS for absolute encoders + //Restore encoder position BIAS for absolute encoders afbWritePositionBias[iCurrentAxis].Execute := TRUE; END_CASE END_IF @@ -310,7 +315,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN RETURN; END_IF - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithoutHome OR GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + IF GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN IF NOT afbSetPosition[iCurrentAxis].Done THEN afbSetPosition[iCurrentAxis].Execute := FALSE; eStartUp := eExecuteRestore; @@ -318,7 +323,7 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN END_IF END_IF - IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition = E_RestorePosition.eRestoreWithHome AND NOT GVL.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + IF GVL.astAxesPersistent[iAxes].bHomedAtShutdown AND NOT GVL.astAxesPersistent[iAxes].bMovingAtShutdown THEN IF NOT afbSetHomePosition[iCurrentAxis].Done THEN afbSetHomePosition[iCurrentAxis].Execute := FALSE; eStartUp := eExecuteRestore; From 2661cd4487bfa700ba28fbcb215b4ce3ef5e6c7f Mon Sep 17 00:00:00 2001 From: aslanliafichev Date: Tue, 7 Apr 2026 11:03:30 +0200 Subject: [PATCH 25/25] MBP-247: Simplify STORE_PERSISTENT --- solution/tc_project_app/POUs/MAIN.TcPOU | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index 6d1bc0b..9161868 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -371,22 +371,12 @@ END_IF astAxesPersistent[iAxes].fEncoderBiasAtShutdown := afbReadPositionBias[iAxes].Value; //Store axis status at shutdown - astAxesPersistent[iAxes].bInitialized := GVL.astAxes[iAxes].stStatus.bAxisInitialized; + astAxesPersistent[iAxes].bInitializedAtShutdown := GVL.astAxes[iAxes].stStatus.bAxisInitialized; astAxesPersistent[iAxes].bHomedAtShutdown := GVL.astAxes[iAxes].stStatus.bHomed; - astAxesPersistent[iAxes].stMotionState := GVL.astAxes[iAxes].Axis.Status.MotionState; - astAxesPersistent[iAxes].bError := GVL.astAxes[iAxes].Axis.Status.Error; - astAxesPersistent[iAxes].nErrorID := GVL.astAxes[iAxes].Axis.Status.ErrorID; - astAxesPersistent[iAxes].bErrorStop := GVL.astAxes[iAxes].Axis.Status.ErrorStop; - astAxesPersistent[iAxes].bStandStill := GVL.astAxes[iAxes].Axis.Status.StandStill; - astAxesPersistent[iAxes].bHasBeenStopped := GVL.astAxes[iAxes].Axis.Status.HasBeenStopped; - astAxesPersistent[iAxes].bDisabled := GVL.astAxes[iAxes].Axis.Status.Disabled; - astAxesPersistent[iAxes].bMoving := GVL.astAxes[iAxes].Axis.Status.Moving; - - astAxesPersistent[iAxes].nCycles := astAxesPersistent[iAxes].nCycles + 1; - astAxesPersistent[iAxes].fPositionDifference := ABS(afCurrentPosition[iAxes] - astAxesPersistent[iAxes].fPositionAtShutdown); + astAxesPersistent[iAxes].fPositionDifferenceAtShutdown := ABS(afCurrentPosition[iAxes] - astAxesPersistent[iAxes].fPositionAtShutdown); //Store value of moving at shutdown - IF GVL.astAxes[iAxes].Axis.Status.Disabled OR astAxesPersistent[iAxes].fPositionDifference < fPositionDifferenceLimit THEN + IF astAxes[iAxes].Axis.Status.Disabled OR astAxesPersistent[iAxes].fPositionDifferenceAtShutdown < fPositionDifferenceLimit THEN astAxesPersistent[iAxes].bMovingAtShutdown := FALSE; ELSE astAxesPersistent[iAxes].bMovingAtShutdown := TRUE;