Isolate Your Wait Statements

Filed under: FANUC TP Programming Workflow

Have you ever looked at a TP program and gotten lost following all the LBLs and JMPs? Have you ever gotten lazy handling your WAIT-statement TIMEOUTs because you didn’t want to bother adding the extra stuff to your main routine?

If you’re nodding “yes” right now, you should try isolating your WAIT-statements into their own small programs.

In my eight-plus years of programming robots and troubleshooting other people’s code, I’ve found that a mess of labels and lack of refactoring large programs into smaller routines is the single biggest cause of issues.

Here’s an example of how you might code a machine unload program:

! unload_machine.ls
LBL[1] ;
WAIT (DI[1:machine ready]) TIMEOUT,LBL[500] ;
 ;
! go ahead and unload the machine ;
! grip part ;
LBL[2] ;
WAIT (RI[1:part gripped]) TIMEOUT,LBL[501] ;
! ok part is gripped, retreat and end the routine ;
END ;
 ;
LBL[500] ;
! machine not ready timeout ;
UALM[1] ;
JMP LBL[1] ;
 ;
LBL[501] ;
! grip fail ;
UALM[2] ;
JMP LBL[2] ;

Among other things, I see two glaring problems here:

  1. There are FOUR labels in this program. I would argue that unless you’re handling a large SELECT conditional, you should probably have two or fewer.
  2. The error handling parts of the program are far removed from the actual errors themselves, and they have to remember where to jump back to once the error has been acknowledged and (hopefully) fixed.

Here’s how I would fix the issue:

! machine_unload.ls ;
CALL WAIT_MACHINE_READY ;
! go ahead and unload the machine ;
! grip part ;
CALL WAIT_PART_GRIPPED ;
! ok part is gripped, retreat and end the routine ;
! wait_machine_ready.ls ;
LBL[1] ;
WAIT (DI[1:machine ready]) TIMEOUT,LBL[500] ;
END ;
 ;
LBL[500] ;
! machine ready timeout ;
UALM[1] ;
JMP LBL[1] ;
! wait_part_gripped.ls ;
LBL[1] ;
WAIT (RI[1:part gripped]) TIMEOUT,LBL[500] ;
END ;
 ;
LBL[500] ;
! grip fail ;
UALM[2] ;
JMP LBL[1] ;

We’ve made a number of improvements:

  1. The main routine now has zero labels. In my opinion, the fewer the better.
  2. The main routine is highly readable and has nothing unrelated to the actual function to the routine (e.g. gripper error handling).
  3. The wait_* utility routines have only 7 lines of code and contain only 2 labels.
  4. Since the different error conditions are isolated to their own unique TP programs, we can re-use LBL[1] for the top of the program and LBL[500] for the error itself– no cognitive overhead there.

In the first version it would be very easy to accidently jump to the wrong part of the program when an error is acknowledged or lose track of why that LBL[2] even exists. Do you think you’d make the same mistake if you could see the entire program in your editor at once?

Give it a try. Start isolating your WAIT-statements into tiny programs and see how you like it. I bet you’ll get hooked and start thinking about all the other logic you can extract from your main routines.


Want posts like this delivered right to your inbox?

If you liked this post, please sign up for my mailing list!