diff --git a/solution/tc_project_app/POUs/MAIN.TcPOU b/solution/tc_project_app/POUs/MAIN.TcPOU index ba6aaca..9161868 100644 --- a/solution/tc_project_app/POUs/MAIN.TcPOU +++ b/solution/tc_project_app/POUs/MAIN.TcPOU @@ -7,28 +7,45 @@ 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 -//Startup, Shutdown and UPS + //Startup, Shutdown and UPS fbCX5130UPS: FB_S_UPS_CX51x0; fbC6017UPS: FB_S_UPS_BAPI; - eUpsMode: E_S_UPS_Mode := eSUPS_WrPersistData_Shutdown; - eStartUp: (eColdStart, eReadAxisFeedbackType, eCheckReadDone, eExecuteRestore, eCheckRestore, eFinishRestore); + eSelUpsMode: E_S_UPS_Mode := eSUPS_WrPersistData_Shutdown; //Selected UPS mode + eStartUp: (eColdStart, eReadAxisFeedbackType, eCheckReadDone, eExecuteRestore, eCheckRestore, eNextAxis, eRestoreFinished); 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 + 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; - afbSetPosition: ARRAY [1..GVL_APP.nAXIS_NUM] OF MC_SetPosition; + afbSetHomePosition: ARRAY[1..GVL_APP.nAXIS_NUM] OF MC_Home; + 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 + //Read position at a specific time interval + fbReadPositionTimer: TON; + bReadPosition: BOOL:= TRUE; + 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 + 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 @@ -37,6 +54,10 @@ END_VAR @@ -75,11 +96,11 @@ END_FOR 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 ]]> - '') THEN CHECK_UPS(); RESTORE_POSITIONS(); @@ -142,7 +176,7 @@ Pneumatic_Box(); - 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 - afbSetPosition[iAxes]( - Axis := GVL.astAxes[iAxes].Axis, - Position := astAxesPersistent[iAxes].fPositionAtShutdown); - - afbWritePositionBias[iAxes]( - Axis:= GVL.astAxes[iAxes].Axis, - ParameterNumber:= E_AxisParameters.AxisEncoderOffset, - Value:= astAxesPersistent[iAxes].fEncoderBiasAtShutdown); - END_FOR + 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); + + //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 + CASE eStartUp OF eColdStart: @@ -198,96 +249,113 @@ IF bRestoreExecute AND NOT bPositionRestoreDone THEN END_IF 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 + IF NOT GVL.astAxesPersistent[iCurrentAxis].bInitializedAtShutdown 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; 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.STARTUP 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 + //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_FOR - //If the code gets here all axes have .valid=TRUE for all axes + 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 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 - afbSetPosition[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 - eStartUp := eCheckRestore; + 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.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 + afbWritePositionBias[iCurrentAxis].Execute := TRUE; + END_CASE + 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 THEN - IF NOT astAxesPersistent[iAxes].bMovingAtShutdown AND - (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 - 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; - END_IF - END_FOR - eStartUp := eFinishRestore; - - eFinishRestore: - //Remove execute = TRUE for afbRestorePosition and fbWritePositionBias - FOR iAxes := 1 TO GVL_APP.nAXIS_NUM DO - afbSetPosition[iAxes].Execute := FALSE; - afbWritePositionBias[iAxes].Execute := FALSE; + IF GVL.astAxes[iCurrentAxis].stConfig.eRestorePosition <> E_RestorePosition.eDontRestore 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.astAxesPersistent[iCurrentAxis].bMovingAtShutdown THEN + IF NOT afbSetPosition[iCurrentAxis].Done THEN + afbSetPosition[iCurrentAxis].Execute := FALSE; + eStartUp := eExecuteRestore; + RETURN; + END_IF + END_IF + + IF GVL.astAxesPersistent[iAxes].bHomedAtShutdown AND NOT GVL.astAxesPersistent[iAxes].bMovingAtShutdown 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 + + 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; - END_FOR + ELSE + eStartUp := eReadAxisFeedbackType; + END_IF + + eRestoreFinished: + //Do nothing END_CASE END_IF ]]> @@ -296,19 +364,27 @@ END_IF