There have been a lot of redundant questions about Interrupt handling lately, so I decided to make a heavily-commented example file that should (Hopefully!) point people with the same questions to as a starting point.
I don't have a KRC handy to test this on, though, so I can't guarantee I haven't missed something subtle here.
Code
&ACCESS RVO1
&COMMENT
DEF InterruptExample ( )
;FOLD INI
;FOLD BASISTECH INI
GLOBAL INTERRUPT DECL 3 WHEN $STOPMESS==TRUE DO IR_STOPM ( )
INTERRUPT ON 3
BAS (#INITMOV,0 )
;ENDFOLD (BASISTECH INI)
;FOLD USER INI
;Make your modifications here
;ENDFOLD (USER INI)
;ENDFOLD (INI)
;FOLD PTP HOME Vel= 100 % DEFAULT;%{PE}%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:HOME, 3:, 5:100, 7:DEFAULT
$BWDSTART = FALSE
PDAT_ACT=PDEFAULT
FDAT_ACT=FHOME
BAS (#PTP_PARAMS,100 )
$H_POS=XHOME
PTP XHOME
;ENDFOLD
;=============================================================================
; First example: Perform search motion and stop when the interrupt is tripped
; Set up Interrupt condition
; Interrupt will only fire when $IN[1] changes from False to True
INTERRUPT DECL 10 WHEN $IN[1] DO SearchAndStopISR()
;FOLD PTP StartSearch Vel=100 % PDAT1 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:StartSearch, 3:, 5:100, 7:PDAT1
$BWDSTART=FALSE
PDAT_ACT=PPDAT1
FDAT_ACT=FStartSearch
BAS(#PTP_PARAMS,100)
PTP XStartSearch
;ENDFOLD
; execute motion during which Interrupt is expected
SearchAndStop()
; The program pointer will jump back to this line
;when the RESUME command in SearchAndStopISR executes
; That is because the INTERRUPT DECL is in this subroutine
; Move to where the robot was when the Interrupt fired
; This can be used to "fix" the robot's stopping distance
IF Interrupted THEN
LIN $POS_INT
ELSE
MsgNotify("No Interrupt during Search motion")
ENDIF
;============================================================================
; Second Example: Multiple interrupts WITHOUT stopping motion
; This could be used to measure a hole with a laser sensor by
;"dragging" the laser across the hole
; Set up Interrupt -- 10 on the False-to-True change of $IN[1],
; 11 on the True-to-False transition
; Note the re-use of Interrupt 10 -- an interrupt number can be "recycled" by
;re-DECLing it
INTERRUPT DECL 10 WHEN $IN[1] DO RecordFirstEdgeISR() ; when laser "falls into" hole
INTERRUPT DECL 11 WHEN NOT $IN[1] DO RecordSecondEdgeISR() ; when laser "climbs out" of hole
; position to start "dragging" the laser across the hole
;FOLD PTP HoleMeasureStart Vel=100 % PDAT2 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:HoleMeasureStart, 3:, 5:100, 7:PDAT2
$BWDSTART=FALSE
PDAT_ACT=PPDAT2
FDAT_ACT=FHoleMeasureStart
BAS(#PTP_PARAMS,100)
PTP XHoleMeasureStart
;ENDFOLD
; Call the subroutine that will be interrupted
SearchWithoutStopping()
;===============================================================================
; Third example: Stop and continue
; In this example, the Interrupt *pauses* the motion, but does not cancel it
; This example also uses a $CYCFLAG to allow the Interrupt to be fired
;by a complex Boolean expression
; CYCFLAG updates "live" in the background
$CYCFLAG[1] = ($IN[1] AND NOT $IN[2]) OR $IN[3]
; Interrupt condition and action
INTERRUPT DECL 10 WHEN $CYCFLAG[1] DO StopAndGoISR()
;FOLD PTP StopAndGoStart Vel=100 % PDAT3 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:StopAndGoStart, 3:, 5:100, 7:PDAT3
$BWDSTART=FALSE
PDAT_ACT=PPDAT3
FDAT_ACT=FStopAndGoStart
BAS(#PTP_PARAMS,100)
PTP XStopAndGoStart
;ENDFOLD
; Subroutine to be interrupted
StopAndGoMove()
;FOLD PTP HOME Vel= 100 % DEFAULT;%{PE}%MKUKATPBASIS,%CMOVE,%VPTP,%P 1:PTP, 2:HOME, 3:, 5:100, 7:DEFAULT
$BWDSTART = FALSE
PDAT_ACT=PDEFAULT
FDAT_ACT=FHOME
BAS (#PTP_PARAMS,100 )
$H_POS=XHOME
PTP XHOME
;ENDFOLD
END
DEF SearchAndStop()
; This subroutine should only contain the motion that is expected to be interrupted
; arm the interrupt
; receiving the input before this will have no effect
INTERRUPT ON 10
; .DAT file variable to indicate if interrupt fired
; not necessary, but handy
Interrupted = FALSE
;FOLD LIN SearchEnd Vel=2 m/s CPDAT1 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VLIN,%P 1:LIN, 2:SearchEnd, 3:, 5:2, 7:CPDAT1
$BWDSTART=FALSE
LDAT_ACT=LCPDAT1
FDAT_ACT=FSearchEnd
BAS(#CP_PARAMS,2)
LIN XSearchEnd
;ENDFOLD
; If the interrupt fires, no code below this line will execute
; due to the RESUME command in the ISR
; Instead, the RESUME command will "cancel" the rest of this subroutine
; and jump the program pointer back to one line after where this subroutine was called
INTERRUPT OFF 10 ; always turn off the Interrupt as soon as it's no longer needed
MsgNotify("Reached SearchEnd without triggering Interrupt")
; break Advance Run Pointer.
; This is needed to ensure the ARP does not
;get back to the top level program before the interrupt fires
WAIT SEC 0
END
DEF SearchAndStopISR()
; This routine is only called when the Interrupt fires
; this should always be first in any Interrupt Service Routine (ISR)
; to protect against double-firing the interrupt
INTERRUPT OFF 10
Interrupted = TRUE
; Stops the robot physical motion.
; The 'F' is optional, but makes the robot stop faster
BRAKE F ;
; cancel the motion that was active when the Interrupt fired
RESUME
END
DEF SearchWithoutStopping()
; Arm interrupts
INTERRUPT ON 10
INTERRUPT ON 11
; use these to check if edges were found
FoundFirstEdge = FALSE
FoundSecondEdge = FALSE
; move to be interrupted
;FOLD LIN HoleMeasureEnd Vel=2 m/s CPDAT2 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VLIN,%P 1:LIN, 2:HoleMeasureEnd, 3:, 5:2, 7:CPDAT2
$BWDSTART=FALSE
LDAT_ACT=LCPDAT2
FDAT_ACT=FHoleMeasureEnd
BAS(#CP_PARAMS,2)
LIN XHoleMeasureEnd
;ENDFOLD
; in case the ISRs did not fire
; this is an important safety net
INTERRUPT OFF 10
INTERRUPT OFF 11
; Check if both edges were found
IF NOT FoundFirstEdge THEN
MsgNotify("Did not find first edge!")
ENDIF
IF NOT FoundSecondEdge THEN
MsgNotify("Did NOT find second edge!")
ENDIF
; break Advance Run Pointer.
; This is needed to ensure the ARP does not
;get back to the top level program before the interrupt fires
WAIT SEC 0
END
DEF RecordFirstEdgeISR()
; This routine is only called when the Interrupt fires
; without a BRAKE command, the robot will not stop!
; without a RESUME command, the active motion will complete normally!
; this should always be first in any Interrupt Service Routine (ISR)
; to protect against double-firing the interrupt
INTERRUPT OFF 10
; Record TCP position when iterrupt fired
; Robot DOES NOT STOP!
FirstEdgePos = $POS_INT
; flag that edge was found
FoundFirstEdge = TRUE ;
END
DEF RecoredPos2()
; This routine is only called when the Interrupt fires
; without a BRAKE command, the robot will not stop!
; without a RESUME command, the active motion will complete normally!
; this should always be first in any Interrupt Service Routine (ISR)
; to protect against double-firing the interrupt
INTERRUPT OFF 11
; Record TCP position when iterrupt fired
; Robot DOES NOT STOP!
SecondEdgePos = $POS_INT
; flag that edge was found
FoundSecondEdge = TRUE
END
DEF StopAndGoMove()
; arm the interrupt
; receiving the input before this will have no effect
INTERRUPT ON 10
; record if Interrupt fired
Interrupted = FALSE
; An interrupt can be active for more than one motion, if need be
;FOLD LIN StopAndGoMid CONT Vel=2 m/s CPDAT4 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VLIN,%P 1:LIN, 2:StopAndGoMid, 3:C_DIS C_DIS, 5:2, 7:CPDAT4
$BWDSTART=FALSE
LDAT_ACT=LCPDAT4
FDAT_ACT=FStopAndGoMid
BAS(#CP_PARAMS,2)
LIN XStopAndGoMid C_DIS C_DIS
;ENDFOLD
;FOLD LIN StopAndGoEnd Vel=2 m/s CPDAT3 Tool[0] Base[0];%{PE}%R 8.3.22,%MKUKATPBASIS,%CMOVE,%VLIN,%P 1:LIN, 2:StopAndGoEnd, 3:, 5:2, 7:CPDAT3
$BWDSTART=FALSE
LDAT_ACT=LCPDAT3
FDAT_ACT=FStopAndGoEnd
BAS(#CP_PARAMS,2)
LIN XStopAndGoEnd
;ENDFOLD
; always make sure to disarm the interrupt after it's no longer needed
INTERRUPT OFF 10
IF NOT Interrupted THEN
MsgNotify("No Interrupt during StopAndGo motion!")
ENDIF
; break Advance Run Pointer.
; This is needed to ensure the ARP does not
;get back to the top level program before the interrupt fires
WAIT SEC 0
END
DEF StopAndGoISR()
; Interrupt Service Routine
; This ISR simply stops the robot temporarily,
;then lets the interrupted motion continue
INTERRUPT OFF 10 ; disarm interrupt
$OUT[1] = TRUE ; turn on output while motion is paused
BRAKE ; bring the robot to a halt
WAIT SEC 5 ; wait for 5 seconds
$OUT[1] = FALSE ; turn output off as motion continues
; Re-arm interrupt
; This will allow the robot to be paused at multiple
;times during the StopAndGo motion
INTERRUPT ON 10
END
Display More
Code
;&ACCESS RVO1
&COMMENT
DEFDAT InterruptExample PUBLIC
;FOLD EXTERNAL DECLARATIONS;%{PE}%MKUKATPBASIS,%CEXT,%VCOMMON,%P
;FOLD BASISTECH EXT;%{PE}%MKUKATPBASIS,%CEXT,%VEXT,%P
EXT BAS (BAS_COMMAND :IN,REAL :IN )
DECL INT SUCCESS
;ENDFOLD (BASISTECH EXT)
;FOLD USER EXT;%{E}%MKUKATPUSER,%CEXT,%VEXT,%P
;Make here your modifications
;ENDFOLD (USER EXT)
;ENDFOLD (EXTERNAL DECLERATIONS)
DECL BOOL Interrupted = FALSE
DECL BOOL FoundFirstEdge = FALSE
DECL BOOL FoundSecondEdge = FALSE
DECL E6POS FirstEdgePos = {X 0}
DECL E6POS SecondEdgePos = {X 0}
DECL BASIS_SUGG_T LAST_BASIS={POINT1[] "StopAndGoMid",POINT2[] "StopAndGoMid",CP_PARAMS[] "CPDAT4",PTP_PARAMS[] "PDAT3",CONT[] " ",CP_VEL[] "2",PTP_VEL[] "100",SYNC_PARAMS[] " ",SPL_NAME[] " "}
DECL E6POS XStartSearch={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FStartSearch={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL PDAT PPDAT1={VEL 100,ACC 100,APO_DIST 100,APO_MODE #CPTP,GEAR_JERK 50}
DECL E6POS XSearchEnd={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FSearchEnd={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL LDAT LCPDAT1={VEL 2,ACC 100,APO_DIST 100,APO_FAC 50,AXIS_VEL 100.0,AXIS_ACC 100.0,ORI_TYP #VAR,CIRC_TYP #BASE,JERK_FAC 50.0,GEAR_JERK 50.0,EXAX_IGN 0}
DECL E6POS XHoleMeasureStart={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FHoleMeasureStart={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL PDAT PPDAT2={VEL 100,ACC 100,APO_DIST 100,APO_MODE #CPTP,GEAR_JERK 50}
DECL E6POS XHoleMeasureE nd={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FHoleMeasureE nd={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL LDAT LCPDAT2={VEL 2,ACC 100,APO_DIST 100,APO_FAC 50,AXIS_VEL 100.0,AXIS_ACC 100.0,ORI_TYP #VAR,CIRC_TYP #BASE,JERK_FAC 50.0,GEAR_JERK 50.0,EXAX_IGN 0}
DECL E6POS XHoleMeasureEnd={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FHoleMeasureEnd={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL E6POS XStopAndGoStart={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FStopAndGoStart={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL PDAT PPDAT3={VEL 100,ACC 100,APO_DIST 100,APO_MODE #CPTP,GEAR_JERK 50}
DECL E6POS XStopAndGoEnd={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FStopAndGoEnd={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL LDAT LCPDAT3={VEL 2,ACC 100,APO_DIST 100,APO_FAC 50,AXIS_VEL 100.0,AXIS_ACC 100.0,ORI_TYP #VAR,CIRC_TYP #BASE,JERK_FAC 50.0,GEAR_JERK 50.0,EXAX_IGN 0}
DECL E6POS XStopAndGoMid={X 0,Y 0,Z 0,A 0,B 0,C 0,S 0,T 0,E1 0,E2 0,E3 0,E4 0,E5 0,E6 0}
DECL FDAT FStopAndGoMid={TOOL_NO 0,BASE_NO 0,IPO_FRAME #BASE,POINT2[] " ",TQ_STATE FALSE}
DECL LDAT LCPDAT4={VEL 2,ACC 100,APO_DIST 100,APO_FAC 50,AXIS_VEL 100.0,AXIS_ACC 100.0,ORI_TYP #VAR,CIRC_TYP #BASE,JERK_FAC 50.0,GEAR_JERK 50.0,EXAX_IGN 0}
ENDDAT
Display More