From 0e50f249c22294f5c84d3a2c5b09f9b6dcb35451 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Fri, 6 Oct 2023 16:02:21 -0700 Subject: [PATCH 1/8] FIX: ensure rising edge while move ok, block other moves if one error --- .../Motion/States/FB_PositionStateMove.TcPOU | 29 +++++++++++++++---- .../States/FB_PositionStateND_Core.TcPOU | 1 + .../Motion/States/FB_StatesInputHandler.TcPOU | 6 ++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU index d7f6e94d..cd4f5fea 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU @@ -91,17 +91,25 @@ VAR_OUTPUT END_VAR VAR fbMotionRequest: FB_MotionRequest; + rtExec: R_TRIG; + rtReset: R_TRIG; + bInnerExec: BOOL; bAllowMove: BOOL; + nLatchAllowErrorID: UDINT; END_VAR ]]> bBusy, bDone => bDone); +rtReset(CLK:=bReset); +IF rtReset.Q THEN + nLatchAllowErrorID := 0; +END_IF + // Inject custom error if we can't move because of bMoveOk or bValid -IF bExecute AND NOT bAllowMove THEN +IF nLatchAllowErrorID <> 0 OR (bExecute AND NOT bAllowMove) THEN bError := TRUE; - IF stPositionState.bValid THEN - nErrorId := 16#7901; + IF nLatchAllowErrorID <> 0 THEN + nErrorID := nLatchAllowErrorID; + ELSIF stPositionState.bValid THEN + nErrorID := 16#7901; ELSE - nErrorId := 16#7902; + nErrorID := 16#7902; END_IF - sErrorMessage := F_MotionErrorCodeLookup(nErrorId := nErrorID); + // Keep error latched until it is cleared, otherwise it can be lost early + nLatchAllowErrorID := nErrorID; + sErrorMessage := CONCAT(CONCAT(F_MotionErrorCodeLookup(nErrorId := nErrorID), " for "), stPositionState.sName); END_IF // This can be useful if we're running this FB standalone for some reason diff --git a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateND_Core.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateND_Core.TcPOU index 6a77b1a9..f6db9d84 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateND_Core.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateND_Core.TcPOU @@ -69,6 +69,7 @@ fbInput( stUserInput:=stEpicsToPlc, bMoveBusy:=fbMove.bBusy, nStartingState:=fbRead.nPositionIndex, + bMoveError:=fbMove.bError, nCurrGoal=>nCurrGoal, bExecMove=>, bResetMove=>, diff --git a/lcls-twincat-motion/Library/POUs/Motion/States/FB_StatesInputHandler.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/States/FB_StatesInputHandler.TcPOU index 925d17fb..149b5f0b 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/States/FB_StatesInputHandler.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/States/FB_StatesInputHandler.TcPOU @@ -19,6 +19,8 @@ VAR_INPUT bMoveBusy: BOOL; // The starting state number to seed nCurrGoal with nStartingState: UINT; + // TRUE if we have a move error, to prevent moves + bMoveError: BOOL; END_VAR VAR_OUTPUT // The goal index to input to the motion FB. This will be clamped to the range 0..GeneralConstants.MAX_STATES @@ -84,6 +86,10 @@ CASE nState OF END_IF END_CASE +IF bMoveError THEN + bExecMove := FALSE; +END_IF + // Help us detect if there is an EPICS put before the next cycle stUserInput.nSetValue := 0; stUserInput.bReset := FALSE; From b101160e5d007644f5afca8282ffab34eb14d7fa Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Fri, 6 Oct 2023 16:59:00 -0700 Subject: [PATCH 2/8] TST: add test for move ok sequencing --- .../Tests/FB_PositionStateMove_Test.TcPOU | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU index c63809d4..b828d626 100644 --- a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU +++ b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU @@ -85,6 +85,8 @@ TestMove(2, 2, FALSE); TestMove(3, 3, TRUE); // Test that we cannot move to an invalid state TestBadStates(4); +// Test that we need a new bExecute to start a new move if a move goes from unsafe to safe +TestMoveOk(5); IF bOneTestDone THEN bOneTestDone := FALSE; @@ -265,6 +267,146 @@ IF fbMove.bDone OR tonTimer.Q OR (bInterruptStarted AND NOT fbMove.bBusy) THEN bInterruptStarted := FALSE; TEST_FINISHED(); END_IF +]]> + + + + + + nTestIndex THEN + RETURN; +END_IF + +CASE nStep OF + // Move to a state that is bad + 0: + fStartPos := stMotionStage.stAxisStatus.fActPosition; + AssertFalse( + fbMove.bError, + 'Started with an error', + ); + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=TRUE, + ); + nStep := 1; + // The move should have failed with an error + 1: + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=TRUE, + ); + AssertTrue( + fbMove.bError, + 'Did not have the expected move not ok error', + ); + nStep := 2; + // Make the state no longer bad, and wait a bit + 2: + stState.bMoveOk := TRUE; + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=TRUE, + ); + tonInternal(IN:=TRUE, PT:=T#100ms); + IF tonInternal.Q THEN + tonInternal(IN:=FALSE); + nStep := 3; + END_IF + // There should be no movement still + 3: + AssertEquals_LREAL( + Expected:=fStartPos, + Actual:=stMotionStage.stAxisStatus.fActPosition, + Delta:=0.1, + Message:='Motor moved without bReset or a new bExecute!', + ); + // Reset the error + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=TRUE, + bReset:=TRUE, + ); + nStep := 4; + // After we reset the error, wait a bit + 4: + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=TRUE, + bReset:=FALSE, + ); + tonInternal(IN:=TRUE, PT:=T#100ms); + IF tonInternal.Q THEN + tonInternal(IN:=FALSE); + nStep := 5; + END_IF + // There should STILL be no movement + 5: + AssertFalse( + fbMove.bError, + 'The error should be reset', + ); + AssertEquals_LREAL( + Expected:=fStartPos, + Actual:=stMotionStage.stAxisStatus.fActPosition, + Delta:=0.1, + Message:='Motor moved without a new bExecute!', + ); + // Set bExecute to FALSE for an upcoming rising edge + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=FALSE, + ); + nStep := 6; + // We should be able to start a move via bExecute now + 6: + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=TRUE, + ); + tonInternal(IN:=TRUE, PT:=T#100ms); + IF tonInternal.Q THEN + tonInternal(IN:=FALSE); + nStep := 7; + END_IF +END_CASE + +IF nStep = 7 OR tonTimer.Q THEN + AssertFalse( + tonTimer.Q, + 'Test timed out', + ); + AssertTrue( + fbMove.bBusy, + 'Motor was not moving at end of test', + ); + bOneTestDone := TRUE; + TEST_FINISHED(); +END_IF ]]> From 051c0347d4078a65b05bbb538af41b1cbf97619a Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Fri, 6 Oct 2023 17:41:45 -0700 Subject: [PATCH 3/8] FIX/TST: compilation errors ans some testing errors --- .../Library/POUs/Motion/States/FB_PositionStateMove.TcPOU | 2 +- .../Library/Tests/FB_PositionStateMove_Test.TcPOU | 7 ++++--- lcls-twincat-motion/_Config/PLC/Library.xti | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU index cd4f5fea..2020b55a 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU @@ -139,7 +139,7 @@ IF nLatchAllowErrorID <> 0 OR (bExecute AND NOT bAllowMove) THEN END_IF // Keep error latched until it is cleared, otherwise it can be lost early nLatchAllowErrorID := nErrorID; - sErrorMessage := CONCAT(CONCAT(F_MotionErrorCodeLookup(nErrorId := nErrorID), " for "), stPositionState.sName); + sErrorMessage := CONCAT(CONCAT(F_MotionErrorCodeLookup(nErrorId := nErrorID), ' for '), stPositionState.sName); END_IF // This can be useful if we're running this FB standalone for some reason diff --git a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU index b828d626..2584bb35 100644 --- a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU +++ b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU @@ -284,12 +284,13 @@ VAR_INST fDelta:=0.5, fVelocity:=1, bValid:=TRUE, - bMoveOk:=FALSE + bMoveOk:=FALSE, + bUpdated:=TRUE ); tonInternal: TON; END_VAR]]> - nTestIndex THEN RETURN; END_IF @@ -388,7 +389,7 @@ CASE nStep OF stPositionState:=stState, bExecute:=TRUE, ); - tonInternal(IN:=TRUE, PT:=T#100ms); + tonInternal(IN:=TRUE, PT:=T#200ms); IF tonInternal.Q THEN tonInternal(IN:=FALSE); nStep := 7; diff --git a/lcls-twincat-motion/_Config/PLC/Library.xti b/lcls-twincat-motion/_Config/PLC/Library.xti index f25d69d2..6462931b 100644 --- a/lcls-twincat-motion/_Config/PLC/Library.xti +++ b/lcls-twincat-motion/_Config/PLC/Library.xti @@ -983,7 +983,7 @@ External Setpoint Generation: - + Library Instance {08500001-0000-0000-F000-000000000064} From 2bd8a3596f506e19c4601a62c301312df3c10323 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 12 Oct 2023 11:48:13 -0700 Subject: [PATCH 4/8] TST: make the test more consistent --- .../Tests/FB_PositionStateMove_Test.TcPOU | 18 +++++++++++------- lcls-twincat-motion/_Config/PLC/Library.xti | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU index 2584bb35..dd2e5a30 100644 --- a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU +++ b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU @@ -280,7 +280,7 @@ VAR_INST fStartPos: LREAL; stState: ST_PositionState := ( sName:='GOAL', - fPosition:=235, + fPosition:=135, fDelta:=0.5, fVelocity:=1, bValid:=TRUE, @@ -384,14 +384,15 @@ CASE nStep OF nStep := 6; // We should be able to start a move via bExecute now 6: + stState.fVelocity := 2000; + stState.fAccel := 15000; + stState.fDecel := 15000; fbMove( stMotionStage:=stMotionStage, stPositionState:=stState, bExecute:=TRUE, ); - tonInternal(IN:=TRUE, PT:=T#200ms); - IF tonInternal.Q THEN - tonInternal(IN:=FALSE); + IF fbMove.bAtState AND stMotionStage.bDone THEN nStep := 7; END_IF END_CASE @@ -401,9 +402,12 @@ IF nStep = 7 OR tonTimer.Q THEN tonTimer.Q, 'Test timed out', ); - AssertTrue( - fbMove.bBusy, - 'Motor was not moving at end of test', + // Check that we've reached the goal + AssertEquals_LREAL( + Expected:=stState.fPosition, + Actual:=stMotionStage.stAxisStatus.fActPosition, + Delta:=0.1, + Message:='Motor did not reach the goal.', ); bOneTestDone := TRUE; TEST_FINISHED(); diff --git a/lcls-twincat-motion/_Config/PLC/Library.xti b/lcls-twincat-motion/_Config/PLC/Library.xti index 6462931b..c97a19ed 100644 --- a/lcls-twincat-motion/_Config/PLC/Library.xti +++ b/lcls-twincat-motion/_Config/PLC/Library.xti @@ -983,7 +983,7 @@ External Setpoint Generation: - + Library Instance {08500001-0000-0000-F000-000000000064} From d39582ddd081c2f834a8c9e1127cd526dffc0d13 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Thu, 12 Oct 2023 16:51:15 -0700 Subject: [PATCH 5/8] TST: make test much more consistent and include more consistency asserts --- .../Tests/FB_PositionStateMove_Test.TcPOU | 178 ++++++++++-------- lcls-twincat-motion/_Config/PLC/Library.xti | 114 +++++------ 2 files changed, 155 insertions(+), 137 deletions(-) diff --git a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU index dd2e5a30..8f401d5c 100644 --- a/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU +++ b/lcls-twincat-motion/Library/Tests/FB_PositionStateMove_Test.TcPOU @@ -21,6 +21,7 @@ VAR bOneTestDone: BOOL; fTestStartPos: LREAL; tonTimer: TON; + tonCleanup: TON; nIter: DINT; bStatesReady: BOOL; END_VAR @@ -88,22 +89,40 @@ TestBadStates(4); // Test that we need a new bExecute to start a new move if a move goes from unsafe to safe TestMoveOk(5); -IF bOneTestDone THEN - bOneTestDone := FALSE; - nTestCounter := nTestCounter + 1; - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stDummyPos, - bExecute:=FALSE, - bReset:=TRUE, - ); - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stDummyPos, - bExecute:=FALSE, - bReset:=FALSE, - ); - tonTimer(IN:=FALSE); +// Wait a few cycles for remaining errors to propagate +tonCleanup(IN:=bOneTestDone, PT:=T#1s); +IF tonCleanup.Q THEN + IF fbMove.bBusy THEN + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stDummyPos, + bExecute:=FALSE, + bReset:=FALSE, + ); + ELSIF stMotionStage.bBusy THEN + stMotionStage.bExecute := FALSE; + ELSIF fbMove.bError THEN + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stDummyPos, + bExecute:=FALSE, + bReset:=TRUE, + ); + ELSIF stMotionStage.bError THEN + stMotionStage.bReset := TRUE; + ELSE + fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stDummyPos, + bExecute:=FALSE, + bReset:=FALSE, + ); + stMotionStage.bReset := FALSE; + + bOneTestDone := FALSE; + nTestCounter := nTestCounter + 1; + tonTimer(IN:=FALSE); + END_IF END_IF // Use this timer to time out any tests that stall tonTimer( @@ -120,7 +139,7 @@ END_VAR ]]> nTestIndex THEN +IF nTestCounter <> nTestIndex OR bOneTestDone THEN RETURN; END_IF @@ -203,11 +222,12 @@ END_VAR VAR_INST bLocalInit: BOOL; bInterruptStarted: BOOL; + tonBusy: TON; END_VAR ]]> nTestIndex THEN +IF nTestCounter <> nTestIndex OR bOneTestDone THEN RETURN; END_IF @@ -224,7 +244,10 @@ IF NOT bLocalInit THEN bLocalInit := TRUE; END_IF -bInterruptStarted S= bInterrupt AND stMotionStage.bBusy; +// Simulate waiting a moment before stopping +tonBusy(IN:=stMotionStage.bBusy, PT:=T#100ms); +bInterruptStarted S= bInterrupt AND tonBusy.Q; + fbMove( stMotionStage:=stMotionstage, stPositionState:=astPositionState[nStateIndex], @@ -270,7 +293,7 @@ END_IF ]]> - + nTestIndex THEN +IF nTestCounter <> nTestIndex OR bOneTestDone THEN RETURN; END_IF CASE nStep OF - // Move to a state that is bad + // Initial setup and checks 0: fStartPos := stMotionStage.stAxisStatus.fActPosition; AssertFalse( fbMove.bError, - 'Started with an error', + 'Started with a fbMove error', ); - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=TRUE, + AssertFalse( + stMotionStage.bError, + 'Started with a motor error', ); - nStep := 1; - // The move should have failed with an error + bLocalExec := FALSE; + bLocalReset := FALSE; + nStep := nStep + 1; + // Move to a state that is bad 1: - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=TRUE, - ); + stState.bMoveOk := FALSE; + bLocalExec := TRUE; + nStep := nStep + 1; + // The move should have failed with an error on the FB that never propagated to the motor itself- we shouldn't have attempted the move at all + 2: AssertTrue( fbMove.bError, 'Did not have the expected move not ok error', ); - nStep := 2; + AssertFalse( + stMotionStage.bError, + 'Had a motion error, but we never should have asked for a move?', + ); + nStep := nStep + 1; // Make the state no longer bad, and wait a bit - 2: + 3: stState.bMoveOk := TRUE; - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=TRUE, - ); - tonInternal(IN:=TRUE, PT:=T#100ms); + tonInternal(IN:=TRUE, PT:=T#500ms); IF tonInternal.Q THEN tonInternal(IN:=FALSE); - nStep := 3; + nStep := nStep + 1; END_IF // There should be no movement still - 3: + 4: AssertEquals_LREAL( Expected:=fStartPos, Actual:=stMotionStage.stAxisStatus.fActPosition, Delta:=0.1, Message:='Motor moved without bReset or a new bExecute!', ); - // Reset the error - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=TRUE, - bReset:=TRUE, - ); - nStep := 4; + // Reset the error (rising edge) + bLocalReset := TRUE; + nStep := nStep + 1; // After we reset the error, wait a bit - 4: - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=TRUE, - bReset:=FALSE, - ); - tonInternal(IN:=TRUE, PT:=T#100ms); + 5: + // Drop for rising edges later + bLocalReset := FALSE; + tonInternal(IN:=TRUE, PT:=T#500ms); IF tonInternal.Q THEN tonInternal(IN:=FALSE); - nStep := 5; + nStep := nStep + 1; END_IF - // There should STILL be no movement - 5: + // There should be no error, and STILL be no movement + 6: AssertFalse( fbMove.bError, 'The error should be reset', @@ -375,29 +394,29 @@ CASE nStep OF Delta:=0.1, Message:='Motor moved without a new bExecute!', ); - // Set bExecute to FALSE for an upcoming rising edge - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=FALSE, - ); - nStep := 6; + // Set bExecute to FALSE for an upcoming rising edge. It should be TRUE at this point. + bLocalExec := FALSE; + nStep := nStep + 1; // We should be able to start a move via bExecute now - 6: + 7: stState.fVelocity := 2000; stState.fAccel := 15000; stState.fDecel := 15000; - fbMove( - stMotionStage:=stMotionStage, - stPositionState:=stState, - bExecute:=TRUE, - ); + bLocalExec := TRUE; IF fbMove.bAtState AND stMotionStage.bDone THEN - nStep := 7; + nStep := END; END_IF END_CASE -IF nStep = 7 OR tonTimer.Q THEN +// Run fbMove exactly once every cycle no matter what +fbMove( + stMotionStage:=stMotionStage, + stPositionState:=stState, + bExecute:=bLocalExec, + bReset:=bLocalReset, +); + +IF nStep = END OR tonTimer.Q THEN AssertFalse( tonTimer.Q, 'Test timed out', @@ -411,8 +430,7 @@ IF nStep = 7 OR tonTimer.Q THEN ); bOneTestDone := TRUE; TEST_FINISHED(); -END_IF -]]> +END_IF]]> diff --git a/lcls-twincat-motion/_Config/PLC/Library.xti b/lcls-twincat-motion/_Config/PLC/Library.xti index c97a19ed..b2b0b29f 100644 --- a/lcls-twincat-motion/_Config/PLC/Library.xti +++ b/lcls-twincat-motion/_Config/PLC/Library.xti @@ -983,7 +983,7 @@ External Setpoint Generation: - + Library Instance {08500001-0000-0000-F000-000000000064} @@ -1488,49 +1488,6 @@ External Setpoint Generation: PRG_TEST.fb_PositionStateReadND_Test.afbSqMotionStage[2].fbDriveVirtual.MasterAxis.NcToPlc NCTOPLC_AXIS_REF - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.NcToPlc - NCTOPLC_AXIS_REF - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitForwardEnable - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitBackwardEnable - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHome - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHardwareEnable - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderULINT - - ULINT - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderUINT - - UINT - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderINT - - INT - - - PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.NcToPlc - NCTOPLC_AXIS_REF - PRG_TEST.fb_PositionStateMoveND_Test.astMotionStage[1].Axis.NcToPlc NCTOPLC_AXIS_REF @@ -3174,6 +3131,49 @@ External Setpoint Generation: INT + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.NcToPlc + NCTOPLC_AXIS_REF + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitForwardEnable + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitBackwardEnable + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHome + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHardwareEnable + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderULINT + + ULINT + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderUINT + + UINT + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderINT + + INT + + + PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.NcToPlc + NCTOPLC_AXIS_REF + PlcTask Outputs @@ -3317,19 +3317,6 @@ External Setpoint Generation: PRG_TEST.fb_PositionStateReadND_Test.afbSqMotionStage[2].fbDriveVirtual.MasterAxis.PlcToNc PLCTONC_AXIS_REF - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.PlcToNc - PLCTONC_AXIS_REF - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bBrakeRelease - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.PlcToNc - PLCTONC_AXIS_REF - PRG_TEST.fb_PositionStateMoveND_Test.astMotionStage[1].Axis.PlcToNc PLCTONC_AXIS_REF @@ -3887,6 +3874,19 @@ External Setpoint Generation: PRG_TEST.fb_PositionStatePMPSND_Test.__FB_POSITIONSTATEPMPSND_TEST__TESTSTARTUP3D__FBFFHWO.q_xFastFaultOut BOOL + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.PlcToNc + PLCTONC_AXIS_REF + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bBrakeRelease + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.PlcToNc + PLCTONC_AXIS_REF + PlcTask Retains From 1170c26791cf8bf6f5f0c0f8a2e1011ab3e221c7 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 1 Nov 2023 16:36:40 -0700 Subject: [PATCH 6/8] MAINT: replace custom error magic numbers with ENUM definition --- .../Library/DUTs/E_LCLSMotionError.TcDUT | 16 ++++++++++++++++ lcls-twincat-motion/Library/Library.plcproj | 3 +++ .../Library/POUs/Motion/FB_MotionRequest.TcPOU | 2 +- .../Motion/States/FB_PositionStateMove.TcPOU | 4 ++-- .../Motion/Utils/F_MotionErrorCodeLookup.TcPOU | 8 ++++---- 5 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 lcls-twincat-motion/Library/DUTs/E_LCLSMotionError.TcDUT diff --git a/lcls-twincat-motion/Library/DUTs/E_LCLSMotionError.TcDUT b/lcls-twincat-motion/Library/DUTs/E_LCLSMotionError.TcDUT new file mode 100644 index 00000000..489723eb --- /dev/null +++ b/lcls-twincat-motion/Library/DUTs/E_LCLSMotionError.TcDUT @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/lcls-twincat-motion/Library/Library.plcproj b/lcls-twincat-motion/Library/Library.plcproj index afd87bb6..8d7b1f24 100644 --- a/lcls-twincat-motion/Library/Library.plcproj +++ b/lcls-twincat-motion/Library/Library.plcproj @@ -105,6 +105,9 @@ Code + + Code + Code diff --git a/lcls-twincat-motion/Library/POUs/Motion/FB_MotionRequest.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/FB_MotionRequest.TcPOU index 20c02013..c77d6dfe 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/FB_MotionRequest.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/FB_MotionRequest.TcPOU @@ -104,7 +104,7 @@ CASE nState OF E_MotionRequest.ABORT: nState := ERROR; bError := TRUE; - nErrorId := 16#7900; + nErrorId := E_LCLSMotionError.ABORTED; END_CASE ELSE nState := START_MOVE; diff --git a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU index 2020b55a..ded35361 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU @@ -133,9 +133,9 @@ IF nLatchAllowErrorID <> 0 OR (bExecute AND NOT bAllowMove) THEN IF nLatchAllowErrorID <> 0 THEN nErrorID := nLatchAllowErrorID; ELSIF stPositionState.bValid THEN - nErrorID := 16#7901; + nErrorID := E_LCLSMotionError.UNSAFE; ELSE - nErrorID := 16#7902; + nErrorID := E_LCLSMotionError.INVALID; END_IF // Keep error latched until it is cleared, otherwise it can be lost early nLatchAllowErrorID := nErrorID; diff --git a/lcls-twincat-motion/Library/POUs/Motion/Utils/F_MotionErrorCodeLookup.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/Utils/F_MotionErrorCodeLookup.TcPOU index f98306f9..4496017b 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/Utils/F_MotionErrorCodeLookup.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/Utils/F_MotionErrorCodeLookup.TcPOU @@ -29,10 +29,10 @@ END_VAR 16#4FFF: msg:='Unknown NC error (not in manual)'; // Custom error definitions - 16#7900: msg:='Aborted move request with active move in progress'; - 16#7901: msg:='Position state unsafe'; - 16#7902: msg:='Position state invalid'; - 16#FFFF: msg:='Fake testing error'; + E_LCLSMotionError.ABORTED: msg:='Aborted move request with active move in progress'; + E_LCLSMotionError.UNSAFE: msg:='Position state unsafe'; + E_LCLSMotionError.INVALID: msg:='Position state invalid'; + E_LCLSMotionError.TEST: msg:='Fake testing error'; // Fallbacks 0: msg:=''; From cc683b2eff1adc02ef9082efaa88601d23c5522e Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 1 Nov 2023 16:41:19 -0700 Subject: [PATCH 7/8] ENH: also stop execution internally if we have an error state --- .../Library/POUs/Motion/States/FB_PositionStateMove.TcPOU | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU index ded35361..1d7d5d17 100644 --- a/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU +++ b/lcls-twincat-motion/Library/POUs/Motion/States/FB_PositionStateMove.TcPOU @@ -103,7 +103,7 @@ END_VAR bAllowMove := stPositionState.bMoveOk AND stPositionState.bValid AND stPositionState.bUpdated; rtExec(CLK:=bExecute); -bInnerExec S= rtExec.Q AND bAllowMove; +bInnerExec S= rtExec.Q AND bAllowMove AND NOT bError; bInnerExec R= NOT bExecute; // Do the move From 02f3c640ac54bd631630e619052693b9ff478db1 Mon Sep 17 00:00:00 2001 From: Zachary Lentz Date: Wed, 1 Nov 2023 16:45:46 -0700 Subject: [PATCH 8/8] BLD: rebuild PLC project to run unit tests --- lcls-twincat-motion/_Config/PLC/Library.xti | 114 ++++++++++---------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/lcls-twincat-motion/_Config/PLC/Library.xti b/lcls-twincat-motion/_Config/PLC/Library.xti index b2b0b29f..dd51a693 100644 --- a/lcls-twincat-motion/_Config/PLC/Library.xti +++ b/lcls-twincat-motion/_Config/PLC/Library.xti @@ -983,7 +983,7 @@ External Setpoint Generation: - + Library Instance {08500001-0000-0000-F000-000000000064} @@ -1488,6 +1488,49 @@ External Setpoint Generation: PRG_TEST.fb_PositionStateReadND_Test.afbSqMotionStage[2].fbDriveVirtual.MasterAxis.NcToPlc NCTOPLC_AXIS_REF + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.NcToPlc + NCTOPLC_AXIS_REF + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitForwardEnable + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitBackwardEnable + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHome + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHardwareEnable + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderULINT + + ULINT + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderUINT + + UINT + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderINT + + INT + + + PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.NcToPlc + NCTOPLC_AXIS_REF + PRG_TEST.fb_PositionStateMoveND_Test.astMotionStage[1].Axis.NcToPlc NCTOPLC_AXIS_REF @@ -3131,49 +3174,6 @@ External Setpoint Generation: INT - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.NcToPlc - NCTOPLC_AXIS_REF - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitForwardEnable - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bLimitBackwardEnable - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHome - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bHardwareEnable - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderULINT - - ULINT - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderUINT - - UINT - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.nRawEncoderINT - - INT - - - PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.NcToPlc - NCTOPLC_AXIS_REF - PlcTask Outputs @@ -3317,6 +3317,19 @@ External Setpoint Generation: PRG_TEST.fb_PositionStateReadND_Test.afbSqMotionStage[2].fbDriveVirtual.MasterAxis.PlcToNc PLCTONC_AXIS_REF + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.PlcToNc + PLCTONC_AXIS_REF + + + PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bBrakeRelease + + BOOL + + + PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.PlcToNc + PLCTONC_AXIS_REF + PRG_TEST.fb_PositionStateMoveND_Test.astMotionStage[1].Axis.PlcToNc PLCTONC_AXIS_REF @@ -3874,19 +3887,6 @@ External Setpoint Generation: PRG_TEST.fb_PositionStatePMPSND_Test.__FB_POSITIONSTATEPMPSND_TEST__TESTSTARTUP3D__FBFFHWO.q_xFastFaultOut BOOL - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.Axis.PlcToNc - PLCTONC_AXIS_REF - - - PRG_TEST.fb_PositionStateMove_Test.stMotionStage.bBrakeRelease - - BOOL - - - PRG_TEST.fb_PositionStateMove_Test.fbMotionStage.fbDriveVirtual.MasterAxis.PlcToNc - PLCTONC_AXIS_REF - PlcTask Retains