Intelligent Traversing

Filed under: FANUC TP Programming

I’ve been working on several machine-tending applications lately. These projects tend to get complicated quickly as the robot decides where to go next based on the state of the peripheral equipment. The decision-making logic is hard enough, but getting the robot to and from each station safely can be tricky. This is how I handle it.

I start off by defining a list of stations:

  1. Home
  2. Inbound parts
  3. Regrip station
  4. Machine 1
  5. Machine 2
  6. Reject station
  7. Inspection station
  8. Outbound parts

I then define a register for saving the robot’s current location. I’ll typically also add another register for saving the previous station, just in case I need it.


  R[50:current station]
  R[51:previous station]

Let’s create a simple macro for saving the robot’s current station and previous station:


  ! SAVE_STATION.LS ;
  ! =============== ;
  ! Saves the robot's current location and ;
  ! previous station based on AR[1]. ;
  !  ;
  ! 1. Home ;
  ! 2. Inbound parts ;
  ! 3. Regrip station ;
  ! 4. Machine 1 ;
  ! 5. Machine 2 ;
  ! 6. Reject station ;
  ! 7. Inspect station ;
  ! 8. Outbound parts ;
    ;
  ! shift current station into previous station ;
  R[51:previous station]=R[50:current station] ;
    ;
  ! save current station ;
  R[50:current station]=AR[1] ;

It would be nice to be able to use String Registers for this, but until FANUC beefs up String Register comparison and assignment, simple integer constants are going to have to do.

I use this macro whenever the robot actually gets to a given station.


  ! HOME.LS ;
  ! ======= ;
  ! Move home ;
   ;
  UFRAME_NUM=0 ;
  UTOOL_NUM=0 ;
   ;
  J PR[1:HOME] 10% CNT0 ;
   ;
  ! save current station as home ;
  CALL SAVE_STATION(1) ;

Saving your current location is only half the battle. The next step is creating a routine that gets the robot from A to B, or C, or D, etc.

Let’s create a new routine called TRAVERSE. It takes a single argument, the target station, and simply acts as a man-in-the-middle, inserting any necessary points between stations.


  ! TRAVERSE.LS ;
  ! =========== ;
  ! Inserts points as necessary to get ;
  ! the robot from its current station ;
  ! to the target station in AR[1].    ;
  !  ;
  ! 1. Home ;
  ! 2. Inbound parts ;
  ! 3. Regrip station ;
  ! 4. Machine 1 ;
  ! 5. Machine 2 ;
  ! 6. Reject station ;
  ! 7. Inspect station ;
  ! 8. Outbound parts ;
    ;
  ! prevent all traversals for now ;
  UALM[1] ;

The TRAVERSE program doesn’t do anything right now. It just prevents us from accidentally crashing the robot into something when moving from station to station. This is how I might use this routine:


  ! UNLOAD_MACHINE_1.LS ;
  ! =================== ;
   ;
  CALL TRAVERSE(4) ;
  UFRAME_NUM=1 ;
  UTOOL_NUM=1 ;
  J PR[2:Machine 1 approach] 100% CNT100 ;
  CALL SAVE_STATION(4) ;

There are a couple things to notice here:

  1. Despite calling TRAVERSE, I still include a motion statement that actually approaches the station in the operation routine. The TRAVERSE routine should only be used to add extra points between the last station’s exit point and this station’s approach.
  2. I don’t CALL SAVE_STATION(4) until I know for sure the robot has actually made it to this station. I don’t want to preemtively save the current station and potentially have the robot thinking it’s somewhere it’s not.

With the current implementation of TRAVERSE, you’ll simply get a user alarm as soon as the robot starts executing UNLOAD_MACHINE_1. Let’s assume that the robot is supposed to move from the regrip station to machine 1 and add a valid traversal for this case:


  ! TRAVERSE.LS ;
  ! =========== ;
  ! Inserts points as necessary to get ;
  ! the robot from its current station ;
  ! to the target station in AR[1].    ;
  !  ;
  ! 1. Home ;
  ! 2. Inbound parts ;
  ! 3. Regrip station ;
  ! 4. Machine 1 ;
  ! 5. Machine 2 ;
  ! 6. Reject station ;
  ! 7. Inspect station ;
  ! 8. Outbound parts ;
    ;
  LBL[1] ;
  SELECT R[50:current station]=3,JMP LBL[30] ;
         ELSE,JMP LBL[500] ;
    ;
  LBL[500] ;
  ! invalid traversal ;
  UALM[1] ;
  JMP LBL[1] ;
   ;
  LBL[30] ;
  ! traversals from regrip station ;
  IF (AR[1]=4),JMP LBL[304] ;
  JMP LBL[500] ;
   ;
  LBL[304] ;
  ! regrip to machine 1 ;
  UFRAME_NUM=0 ;
  UTOOL_NUM=1 ;
  J P[1:regrip to machine 1] 100% CNT100 ;
  JMP LBL[999] ;
   ;
  LBL[999] ;

The first thing the program does is see if there are any valid traversals from the current station stored in R[50]. It then jumps down and checks to see if there are any valid traversals to the target station in AR[1]. If everything looks good, it executes the motion statement or two required to get from A to B, otherwise it catches the error and potentially saves the robot from crashing.

It’s pretty common for the robot to have to traverse to and from itself, so I’ll typically add one simple line to the top of TRAVERSE to allow this:


  ! TRAVERSE.LS ;
  ! =========== ;
  ! Inserts points as necessary to get ;
  ! the robot from its current station ;
  ! to the target station in AR[1].    ;
  !  ;
  ! 1. Home ;
  ! 2. Inbound parts ;
  ! 3. Regrip station ;
  ! 4. Machine 1 ;
  ! 5. Machine 2 ;
  ! 6. Reject station ;
  ! 7. Inspect station ;
  ! 8. Outbound parts ;
    ;
  ! always safe to move to current station ;
  IF (AR[1]=R[50:current station]),JMP LBL[999] ;
    ;
  LBL[1] ;
  SELECT R[50:current station]=3,JMP LBL[30] ;
         ELSE,JMP LBL[500] ;


It’s also pretty common for no extra motion to be necessary, so I’ll usually have a NOOP (no operation) label to handle this case.


  LBL[1001:NOOP] ;
  ! no additional points necessary ;
  JMP LBL[999] ;

I purposefully jump here instead of the end of the program just in case I want to do any logging, etc.

As you add more and more traversals, the TRAVERSE routine starts to get pretty large. At this point, it probably makes sense to separate each station’s traversals into their own routines:


  ! TRAVERSE_TO_MACHINE_1.LS ;
  ! =========== ;
  ! Inserts points as necessary to get ;
  ! the robot from its current station ;
  ! to machine 1.
  !  ;
  ! 1. Home ;
  ! 2. Inbound parts ;
  ! 3. Regrip station ;
  ! 4. Machine 1 ;
  ! 5. Machine 2 ;
  ! 6. Reject station ;
  ! 7. Inspect station ;
  ! 8. Outbound parts ;
    ;
  LBL[1] ;
  SELECT R[50:current station]=3,JMP LBL[30] ;
         =4,JMP LBL[1001] ;
   ;
  ! invalid traversal ;
  UALM[1] ;
  JMP LBL[1] ;
   ;
  LBL[30] ;
  ! regrip to machine 1 ;
  UFRAME_NUM=0 ;
  UTOOL_NUM=1 ;
  J P[1:regrip to machine 1] 100% CNT100 ;
  JMP LBL[999] ;
   ;
  LBL[1001:NOOP] ;
  ! no points necessary ;
  JMP LBL[999] ;
   ;
  LBL[999] ;

This is the cleanest way I’ve found to get the robot from station to station, protect us both from programming errors and keep our actual operation programs clean. How do you handle this problem? Let me know if you have any alternative ideas or ways to improve how I currently handle this.


Want posts like this delivered right to your inbox?

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