Centroid CNC control sales, service, training and support
Devices such as tool changers, gear shifters, and pallet changers usually require step-by-step sequencing to perform their functions. This can be programmed in a variety of ways.
I find that breaking down the sequence into discrete steps, and defining a PLC program Stage for each step, provides a clear structure. Clear structure, with clearly defined entry and exit conditions and with clearly delineated responsibilities, improves readability, reliability and maintainability.
The following example is for a twin-turret lathe, with hydraulically actuated turrets. Each turret has one solenoid valve for operation. If the solenoid valve is powered, the turret lifts, then rotates continuously. When the solenoid valve is unpowered, the turret stops and locks back down. Each turret has one switch which detects whether the turret is unlocked, plus a series of switches which encode the turret position. Each turret has four positions. The front turret holds T01 - T04; the rear turret holds T05 - T08.
To implement automatic tool changing on this lathe, I added the following code to a standard "basic" MPU11 lathe PLC program:
INVALID_TN_ERR IS 27906;(2+256*109) FRONT_TURRET_UNLOCK_TIMEOUT IS 28162;(2+256*110) FRONT_TURRET_ROTATE_TIMEOUT IS 28418;(2+256*111) FRONT_TURRET_LOCK_TIMEOUT IS 28674;(2+256*112) REAR_TURRET_UNLOCK_TIMEOUT IS 28930;(2+256*113) REAR_TURRET_ROTATE_TIMEOUT IS 29186;(2+256*114) REAR_TURRET_LOCK_TIMEOUT IS 29442;(2+256*115) ATC_DONE_TIMEOUT_ERR IS 29698;(2+256*116) ATC_FINAL_POSITION_ERR IS 29954;(2+256*117) INVALID_FRONT_SWITCHES_ERR IS 30978;(2+256*121) INVALID_REAR_SWITCHES_ERR IS 31234;(2+256*122) FRONT_NOT_LOCKED_ERR IS 31490;(2+256*123) REAR_NOT_LOCKED_ERR IS 31746;(2+256*124)
TurretPosT01 IS INP33 ; 1 = in this position 0 = not in this position TurretPosT02 IS INP34 ; 1 = in this position 0 = not in this position TurretPosT03 IS INP35 ; 1 = in this position 0 = not in this position TurretPosT04 IS INP36 ; 1 = in this position 0 = not in this position TurretPosT05 IS INP37 ; 1 = in this position 0 = not in this position TurretPosT06 IS INP38 ; 1 = in this position 0 = not in this position TurretPosT07 IS INP39 ; 1 = in this position 0 = not in this position TurretPosT08 IS INP40 ; 1 = in this position 0 = not in this position FrontTurretUnlocked IS INP41 ; 1 = turret unlocked 0 = turret locked RearTurretUnlocked IS INP42 ; 1 = turret unlocked 0 = turret locked
FrontTurretIndexSol IS OUT33 ; 1 = unlock and rotate 0 = lock down RearTurretIndexSol IS OUT34 ; 1 = unlock and rotate 0 = lock down
ATCDone_M IS MEM20 ; cnctch.mac depends on this location M6InProgress_M IS MEM21 IndexInProgress_M IS MEM22 ;... RearTurretActive_M IS MEM35 TurretsShouldBeLocked_M IS MEM36 ;... Blink_M IS MEM88
M6 IS SV_M94_M95_6 ; Tool Change
ATCError_W IS W8 ATCStage_W IS W9 ;... FrontTurretPosition_W IS W26 RearTurretPosition_W IS W27 RequestedPosition_W IS W28 TurretPattern_W IS W29
FrontTurretNewPosPD IS PD28 RearTurretNewPosPD IS PD29
Blink_T IS T8 ;... ATCUnlock_T IS T15 ATCRotate_T IS T16 ATCPause_T IS T17 ATCLock_T IS T18 ATCCheck_T IS T19 ATCDone_T IS T20 InvalidFrontPos_T IS T21 InvalidRearPos_T IS T22
ATCStartStage IS STG30 ATCFrontUnlockStage IS STG31 ATCFrontRotateStage IS STG32 ATCFrontPauseStage IS STG33 ATCFrontLockStage IS STG34 ATCRearUnlockStage IS STG35 ATCRearRotateStage IS STG36 ATCRearPauseStage IS STG37 ATCRearLockStage IS STG38 ATCCheckStage IS STG39 ATCDoneStage IS STG40 ATCErrorStage IS STG41 ATCResetStage IS STG42
(inserted along with all the other tasks which are performed just once as the PLC program starts up, in a lengthy "IF (1==1)" block)
WTB SV_NV_W1 RearTurretActive_M 1,
(to be performed on every scan)
; Cancel M6 request if the CNC program cycle is no longer running IF !SV_PROGRAM_RUNNING THEN RST M6 ; Run 1Hz blinker for Aux LEDs IF True THEN Blink_T = 500, SET Blink_T IF Blink_T ^ Blink_M THEN (Blink_M) IF Blink_T THEN RST Blink_T ; Read positions of both turrets ; Turret switch patterns, reading four bits into an integer: ; T01 or T05 = 0001 = 1 ; T02 or T06 = 0010 = 2 ; T03 or T07 = 0100 = 4 ; T04 or T08 = 1000 = 8 ; Read and validate front turret position IF True THEN Temp_W = 0, BTW TurretPattern_W TurretPosT01 4 IF TurretPattern_W == 1 THEN Temp_W = 1 IF TurretPattern_W == 2 THEN Temp_W = 2 IF TurretPattern_W == 4 THEN Temp_W = 3 IF TurretPattern_W == 8 THEN Temp_W = 4 IF Temp_W != 0 && Temp_W != FrontTurretPosition_W THEN (FrontTurretNewPosPD), FrontTurretPosition_W = Temp_W ; if switch pattern is invalid for too long a time, report error IF Temp_W == 0 THEN InvalidFrontPos_T = 1000, SET InvalidFrontPos_T IF Temp_W != 0 THEN RST InvalidFrontPos_T IF InvalidFrontPos_T && SV_PROGRAM_RUNNING THEN ErrorMsg_W = INVALID_FRONT_SWITCHES_ERR, SET ErrorFlag_M ; Read and validate rear turret position IF True THEN Temp_W = 0, BTW TurretPattern_W TurretPosT05 4 IF TurretPattern_W == 1 THEN Temp_W = 5 IF TurretPattern_W == 2 THEN Temp_W = 6 IF TurretPattern_W == 4 THEN Temp_W = 7 IF TurretPattern_W == 8 THEN Temp_W = 8 IF Temp_W != 0 && Temp_W != RearTurretPosition_W THEN (RearTurretNewPosPD), RearTurretPosition_W = Temp_W ; if switch pattern is invalid for too long a time, report error IF Temp_W == 0 THEN InvalidRearPos_T = 1000, SET InvalidRearPos_T IF Temp_W != 0 THEN RST InvalidRearPos_T IF InvalidRearPos_T && SV_PROGRAM_RUNNING THEN ErrorMsg_W = INVALID_REAR_SWITCHES_ERR, SET ErrorFlag_M IF SV_JOB_IN_PROGRESS && SpindleEnableOut && !M6InProgress_M THEN (TurretsShouldBeLocked_M) IF TurretsShouldBeLocked_M && FrontTurretUnlocked THEN ErrorMsg_W = FRONT_NOT_LOCKED_ERR, SET ErrorFlag_M IF TurretsShouldBeLocked_M && RearTurretUnlocked THEN ErrorMsg_W = REAR_NOT_LOCKED_ERR, SET ErrorFlag_M ; Report currently-active tool (turret position) to CNC11 software. ; CNC11 expects to receive this value in BCD format, so convert it. IF !RearTurretActive_M THEN Temp_W = FrontTurretPosition_W IF RearTurretActive_M THEN Temp_W = RearTurretPosition_W IF True THEN BCD Temp_W, SV_PLC_CAROUSEL_POSITION = Temp_W ; Detect incoming tool-change request and dispatch to ATC stages IF M6 && !M6InProgress_M THEN SET M6InProgress_M, SET ATCStartStage ; Write the turret status bit(s) into SV_NV_W1 ; so they can be retrieved on next power-up. IF True THEN BTW Temp_W RearTurretActive_M 1, SV_NV_W1 = Temp_W ; Detect Aux5 and Aux8 key presses, use to initiate manual turret indexing ; when no CNC program is running and no faults are present IF Aux5Key && !IndexInProgress_M && !SV_JOB_IN_PROGRESS && !SV_STOP THEN SET IndexInProgress_M, SET ATCRearUnlockStage IF Aux8Key && !IndexInProgress_M && !SV_JOB_IN_PROGRESS && !SV_STOP THEN SET IndexInProgress_M, SET ATCFrontUnlockStage ; Use the Aux5 and Aux8 LEDs to indicate turret operation: ; LED on = turret index solenoid powered ; LED blinking = solenoid not powered, but turret not locked IF RearTurretIndexSol || (RearTurretUnlocked && Blink_M) THEN (Aux5LED) IF FrontTurretIndexSol || (FrontTurretUnlocked && Blink_M) THEN (Aux8LED)
;================================================================ ATCStartStage ;================================================================ ; Validate requested tool number, determine whether a turret index ; is required, and dispatch to the appropriate turret stages if needed IF True THEN ATCStage_W = 1, RequestedPosition_W = SV_TOOL_NUMBER IF RequestedPosition_W < 1 || RequestedPosition_W > 8 THEN SET ErrorFlag_M, ErrorMsg_W = INVALID_TN_ERR, JMP ATCResetStage IF RequestedPosition_W == FrontTurretPosition_W THEN RST RearTurretActive_M, JMP ATCDoneStage IF RequestedPosition_W == RearTurretPosition_W THEN SET RearTurretActive_M, JMP ATCDoneStage IF RequestedPosition_W >= 1 && RequestedPosition_W <= 4 && RequestedPosition_W != FrontTurretPosition_W THEN JMP ATCFrontUnlockStage IF RequestedPosition_W >= 5 && RequestedPosition_W <= 8 && RequestedPosition_W != RearTurretPosition_W THEN JMP ATCRearUnlockStage ;================================================================ ATCFrontUnlockStage ;================================================================ ; Power the turret's index solenoid, wait for the turret to be unlocked IF True THEN ATCStage_W = 2, ATCUnlock_T = 1000, SET ATCUnlock_T, RST RearTurretActive_M, SET FrontTurretIndexSol IF FrontTurretUnlocked THEN JMP ATCFrontRotateStage IF ATCUnlock_T THEN ErrorMsg_W = FRONT_TURRET_UNLOCK_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCFrontUnlockStage THEN RST ATCUnlock_T ;================================================================ ATCFrontRotateStage ;================================================================ ; Wait while the turret rotates to the target position IF True THEN ATCStage_W = 3 IF M6InProgress_M THEN ATCRotate_T = 8000, SET ATCRotate_T ; For a programmed change, rotate until we are at the requested position. ; For a manual index, wait until the first position arrival after the ; Aux key has been released. IF M6InProgress_M && FrontTurretPosition_W == RequestedPosition_W || IndexInProgress_M && FrontTurretNewPosPD && !Aux8Key THEN JMP ATCFrontPauseStage IF ATCRotate_T THEN ErrorMsg_W = FRONT_TURRET_ROTATE_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCFrontRotateStage THEN RST ATCRotate_T ;================================================================ ATCFrontPauseStage ;================================================================ ; Continue to rotate a short additional time after the turret-position ; switches showed us to be at the target position IF True THEN ATCStage_W = 4, ATCPause_T = 60, SET ATCPause_T IF ATCPause_T THEN JMP ATCFrontLockStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCFrontPauseStage THEN RST ATCPause_T ;================================================================ ATCFrontLockStage ;================================================================ ; Turn off the turret's index solenoid and wait for it to lock back down IF True THEN ATCStage_W = 5, ATCLock_T = 2000, SET ATCLock_T, RST FrontTurretIndexSol IF !FrontTurretUnlocked THEN JMP ATCCheckStage IF ATCLock_T THEN ErrorMsg_W = FRONT_TURRET_LOCK_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCFrontLockStage THEN RST ATCLock_T ;================================================================ ATCRearUnlockStage ;================================================================ IF True THEN ATCStage_W = 4, ATCUnlock_T = 1000, SET ATCUnlock_T, SET RearTurretActive_M, SET RearTurretIndexSol IF RearTurretUnlocked THEN JMP ATCRearRotateStage IF ATCUnlock_T THEN ErrorMsg_W = REAR_TURRET_UNLOCK_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCRearUnlockStage THEN RST ATCUnlock_T ;================================================================ ATCRearRotateStage ;================================================================ IF True THEN ATCStage_W = 5 IF M6InProgress_M THEN ATCRotate_T = 8000, SET ATCRotate_T IF M6InProgress_M && RearTurretPosition_W == RequestedPosition_W || IndexInProgress_M && RearTurretNewPosPD && !Aux5Key THEN JMP ATCRearPauseStage IF ATCRotate_T THEN ErrorMsg_W = REAR_TURRET_ROTATE_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCRearRotateStage THEN RST ATCRotate_T ;================================================================ ATCRearPauseStage ;================================================================ IF True THEN ATCStage_W = 6, ATCPause_T = 60, SET ATCPause_T IF ATCPause_T THEN JMP ATCRearLockStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCRearPauseStage THEN RST ATCPause_T ;================================================================ ATCRearLockStage ;================================================================ IF True THEN ATCStage_W = 7, ATCLock_T = 2000, SET ATCLock_T, RST RearTurretIndexSol IF !RearTurretUnlocked THEN JMP ATCCheckStage IF ATCLock_T THEN ErrorMsg_W = REAR_TURRET_LOCK_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCRearLockStage THEN RST ATCLock_T ;================================================================ ATCCheckStage ;================================================================ ; Turret is clamped back down. If this is a programmed tool change, ; pause a moment and verify that we did clamp down at the correct ; final position. IF True THEN ATCStage_W = 8, ATCCheck_T = 500, SET ATCCheck_T IF IndexInProgress_M || ATCCheck_T THEN JMP ATCDoneStage IF M6InProgress_M && (!RearTurretActive_M && FrontTurretPosition_W != RequestedPosition_W || RearTurretActive_M && RearTurretPosition_W != RequestedPosition_W) THEN ErrorMsg_W = ATC_FINAL_POSITION_ERR, SET ErrorFlag_M, JMP ATCErrorStage IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage IF !ATCCheckStage THEN RST ATCCheck_T ;================================================================ ATCDoneStage ;================================================================ IF True THEN ATCStage_W = 9, SET ATCDone_M, ATCDone_T = 2000, SET ATCDone_T IF !M6 THEN JMP ATCResetStage IF ATCDone_T THEN ErrorMsg_W = ATC_DONE_TIMEOUT_ERR, SET ErrorFlag_M, JMP ATCResetStage IF !ATCDoneStage THEN RST ATCDone_T ;================================================================ ATCErrorStage ;================================================================ IF True THEN ATCError_W = 0, JMP ATCResetStage IF TurretPosT01 THEN ATCError_W = 1 IF TurretPosT02 THEN ATCError_W = ATCError_W + 2 IF TurretPosT03 THEN ATCError_W = ATCError_W + 4 IF TurretPosT04 THEN ATCError_W = ATCError_W + 8 IF TurretPosT05 THEN ATCError_W = ATCError_W + 16 IF TurretPosT06 THEN ATCError_W = ATCError_W + 32 IF TurretPosT07 THEN ATCError_W = ATCError_W + 64 IF TurretPosT08 THEN ATCError_W = ATCError_W + 128 IF FrontTurretUnlocked THEN ATCError_W = ATCError_W + 256 IF RearTurretUnlocked THEN ATCError_W = ATCError_W + 512 IF M6 THEN ATCError_W = ATCError_W + 1024 IF M6InProgress_M THEN ATCError_W = ATCError_W + 2048 IF IndexInProgress_M THEN ATCError_W = ATCError_W + 4096 IF FrontTurretIndexSol THEN ATCError_W = ATCError_W + 8192 IF RearTurretIndexSol THEN ATCError_W = ATCError_W + 16384 ;================================================================ ATCResetStage ;================================================================ ; Turn off all outputs and flags related to turret indexing IF True THEN RST FrontTurretIndexSol, RST RearTurretIndexSol, RST M6InProgress_M, RST IndexInProgress_M, RST ATCDone_M, RST ATCResetStage
There is, of course, a lot going on here. However, it can be broken down into some fairly clear tasks:
Note: In the PLC program I name the incoming tool-change request from the CNC program as "M6", even though on a lathe, there is no actual M6 code. The request comes from the "cnctch.mac" CNC macro, which is called whenever the CNC program calls for a T number different from the active one. "M6", in this case, is just a convenient name.
I use "BTW" to read all four turret-position switches into an integer word variable, then test the result against the valid combinations. This is a little more complex than just testing the four switches, but protects us against the possibility that one or more switches are faulty.
Each Stage in the sequence handles one operation: typically turning an output on or off, then waiting for inputs to change to show that the expected action took place. If the action completes successfully within the allowable time limit, then that stage jumps to the next stage in the sequence.
Each stage typically has an error timer, which begins running as soon as we enter the stage. If the expected action does not complete successfully in the allowed time, then the timer expires and an Error or Fault is triggered.
The error timer, and any other timers that are started within a stage, are reset by the stage whenever it exits.
Each stage also monitors to see if a Fault has occurred, or if the CNC program cycle which may have started the sequence has been cancelled. In such a situation, the stage cancels itself (typically by jumping to a "Reset" stage to turn off any related outputs and flags).
Let us look again at one of the turret operation stages to see how these actions are coded:
;================================================================ ATCRearUnlockStage ;================================================================ 1 IF True THEN ATCStage_W = 4, 2 ATCUnlock_T = 1000, SET ATCUnlock_T, SET RearTurretActive_M, SET RearTurretIndexSol 3 IF RearTurretUnlocked THEN JMP ATCRearRotateStage 4 IF ATCUnlock_T THEN ErrorMsg_W = REAR_TURRET_UNLOCK_TIMEOUT, SET ErrorFlag_M, JMP ATCErrorStage 5 IF SV_STOP || (M6InProgress_M && !M6) THEN JMP ATCResetStage 6 IF !ATCRearUnlockStage THEN RST ATCUnlock_T
When using this type of Stage structure, it is critical that no other logic, elsewhere in the program, use a RST command to turn off any of these stages. If that were to happen, the stage would not be evaluated in the scan it was turned off in, and the error timer would not get reset. The next time we called on this service and again entered the stage, the timer would long since have reached its preset, and the "Timeout" error would be reported immediately upon entry.
Many Centroid factory PLC programs use a different strategy and structure: somewhere in MainStage or ATCMainStage there may be a lengthy block of RST commands to turn off all ATC-related stages and timers in case of Fault, E-Stop or cancellation. The trouble with that approach is that the RST block needs to be updated every time a new stage or timer is introduced to the sequence. If an item is overlooked, then subtle bugs can result.
Copyright © 2015 Marc Leonard
Last updated 05-Dec-2015 MBL