Pepperoni Bot

From Industrial Robotics & Automation - Fanuc Teach Pendant Programming

Making pizza is a process that requires many steps and different tools. The stretching of dough, the application of sauce and cheese, and the addition of various layers of toppings are usually performed manually by an employee, but can be automated quite easily.

This example details an automated placement of pepperoni on a square sheet pizza.

Reasoning & Prerequisites

Prerequisite Knowledge

  • Safety
  • Teach Pendant Navigation
  • Jogging and Clearing Alarms
  • Creating Programs
  • Motion Instructions
  • Tool and User Frame
  • Non-Motion Instructions

Required Preliminary Setup

  • A stack of poker chips representing pepperoni.
  • A Box
  • Robot at HOME Position

Reinforced Concepts

  • Counters and Register Instructions
  • User Frame Use
  • Offsets
  • Palletizing (Stack Tracking)

All labs assume HandlingTool software.

Planning Your Cell

Program Requirements Program Name
The robot will need to pick up a pepperoni piece from the pepperoni stack Pick_Pepperoni
The robot will need to place the pepperoni at the next available space on the pizza. Place_Pepperoni
The robot will need to reconfigure the position registers so the offsets reflect the reducing height of the pepperoni stack, as well as the next location for placement on the pizza. Pepperoni_Bot

We have determined the main motion tasks required for the robot’s function. This is picking up the pepperoni, and then placing the pepperoni. These will be separate programs, to make our process easier to manage and understand.

We have added a main program as well that will do all the math and set up all the registers for us, before calling each of the motion programs.


Requirement Frame Type Name
The robot will need to know where the center of the vacuum gripper tool is, relative to TCP. Tool VacuumTool
The robot will need to know where the pizza is placed to properly determine rows and columns for the intended pepperoni. User PizzaFrame

Tool Frame

Since we will be using a tool on the robot, we will need to tell the robot exactly where the tool’s effective end is. Due to the fact we will be working entirely within X, Y, and Z (no rotations needed) the tool frame 3-point method will suffice. Set up your tool frame with the 3-point method, name it VacuumTool, then change your selected frame to the number of the frame you made.

*SHIFT+COORD, select Tool, type your tool frame number.

User Frame

The pizza could be placed anywhere within the robot’s work envelope. We need to create a user frame that is aligned with the first pizza we will be teaching, so any new ones can simply be adjusted later. Again, since we will just be working in X,Y,Z with no need of precision, you can use the 3 point method for the user frame you create. Create your user frame for the box. Use the name PizzaFrame. Make the Y axis align with pepperoni rows and the X axis align with pepperoni columns.

Before you begin programming, change your coordinate system to the user frame you created.

*SHIFT+COORD, select User, type your user frame number.

Just in case the robot was left in a state where it is locked by another task, go ahead and hit FCTN and select Abort All.


Motion Program: Pick_Pepperoni

Point Description
P[1:Above_Stack] A point above the stack, allowing for XY travel without interacting with the stack.
P[2:At_Piece] A point touching the topmost piece.
Our first motion program will be Pick_Pepperoni. It includes the instructions needed to go to the pepperoni stack and grab a piece.

While there only actually needs to be one point taught, as the “Above_Stack” height could just be an offset of the “At_Piece” position, it’s just simpler to use the two. We will have to organize our motion and IO instructions to move above the stack, then move down to the current height of the top pepperoni, turn the vacuum on, then move back above the stack.

J P[1:Above_Stack] 100% FINE

L P[2:At_Piece] 100mm/s FINE Offset PR[17:Stack_Height]

RO[1:Vacuum] = ON

L P[1:Above_Stack] 100mm/s FINE

Note: The choice of motion types is important. The Joint motion to get to the stack will ensure the robot can get from the stack to the pizza, regardless of position. The linear moves down to/up from the stack ensure the stack won’t be disturbed in the XY directions.

Motion Program: Place_Pepperoni

Point Description
P[1:Above_Pizza] This point is above, but not touching the pizza. This allows XY motion without crashing into the existing pepperoni pieces. Figure 15 mm above.
P[2:At_Pizza] This point is at the placement height.
Our other motion program is Place_Pepperoni. This will include all the instructions required to deposit the pepperoni the robot is currently holding (from the Pick_Pepperoni program) at the desired position on the pizza.

We will be using the position register PR[18:Pizza] to offset our destination positions. The contents of PR[18:Pizza] will be written ahead of time in the Pepperoni_Bot program.

J P[1:Above_Pizza] 100% FINE OFFSET PR[18:Pizza]

L P[2:At_Pizza] 100mm/s FINE OFFSET PR[18:Pizza]

RO[1:Vacuum] = OFF

L P[1:Above_Pizza] 100mm/s FINE OFFSET PR[18:Pizza]


Main Program: Pepperoni_Bot

PR[17:Stack_Height] Keeps track of pepperoni stack height.
PR[18:Pizza] Keeps track of where to place the next pepperoni piece on the pizza.
R[70:Row_Pieces] Keeps track of how many pieces have been placed in our current row.
R[71:Row_Select] Keeps track of how many rows we have placed on the pizza so far.
The beginning of your Pepperoni_Bot program should set registers and IO you use to known values. Typically, this means setting them to zero, but you can start at any number that makes sense to your program. In this program, we will set everything up as zero and OFF.

PR[17:Stack_Height] = PR[17:Stack_Height] - PR[17:Stack_Height]

PR[18:Pizza] = PR[18:Pizza] - PR[18:Pizza]

RO[1:Vacuum] = OFF

Note: You may not know all the registers and position registers you will use in programs you create before you start writing them. This is fine, as you can always add more to your setup section later. Keep track of them on paper as you use new ones.

Additionally: The robot could be in any position when the program first starts. Many of these positions could cause issue if care is not taken before running. To ensure the trajectory of the first motion is always consistent, we add an instruction to go home at the start:

J PR[1:Home] 100% FINE

The above instructions so far won’t be part of our main loop, so it will only run through them once, when the program is first started. Everything we want as part of the main loop will have to be below the label chosen to mark the main loop’s beginning:

LBL [1:Loop]

The rest of this program will exist within the loop, except for our program END and an instruction to go HOME.

Requirement Action
Pick Up a Pepperoni Call Pick_Pepperoni
Consider the stack is now lower Reduce Z in PR[17:Stack_Height] by 3.3mm
Place a Pepperoni Call Place_Pepperoni
Consider the next row position. Add 45mm to the Y element of PR[18:Pizza]
Check to see if the row is done IF conditional to see if the Y element of PR[18:Pizza] is now outside our pizza
Check to see if the pizza is done (repeat if not) IF conditional to see if the X element of PR[18:Pizza] is now outside our pizza
This program exists to run the other programs and configure the offsets for each loop. Since we taught the points for Pick_Pepperoni at the first location, it will first run it with zero in the offset register:

CALL Pick_Pepperoni

Every time this is called, we need to reconfigure the offset register to reflect that the stack is a bit lower now. We’ve chosen 3.3mm as the height of the pepperoni because that’s the height of our poker chips, so the stack is reduced in height by 3.3mm each time:

PR[17,3: Stack_Height] = PR[17,3: Stack_Height] – 3.3

Now it is time to place the pepperoni. Since nothing has yet been written to PR[18:Pizza], nothing will be added to the placement position and it will place it at our originally taught first position.

Call Place_Pepperoni

Every time this is called, we need to reconfigure the offset register to reflect the next desired placement position. This is +45mm in the Y axis.

PR[18,2: Pizza] = PR[18,2: Pizza] + 45

After it has placed 5 pepperonis, we don’t want it to place another in that row or it will be outside the pizza crust, so we’ll add a conditional to check the position and alternatively start a new row entirely. This means starting from the original 0mm Y position but 45mm further in the X axis

IF PR[18,2: Pizza] < 181 JMP LBL [2: SKIP]

PR[18,2: Pizza] = 0

PR[18,1: Pizza] = PR[18,1: Pizza] + 45


Now we have it making new rows every time one is finished, but there’s nothing yet stopping it after it makes all 5 rows. We add another conditional to check this and keep looping if it isn’t outside the limit we set. Once it is outside this limit, it will go home and END.

IF PR[18,1: Pizza] < 181 JMP LBL [1:Loop]

J PR[1:HOME] 100% FINE


Going Further

This program is just an introduction to what the robot would be capable of. The sections below are overviews of what additional features could be added to our system.

Application of Sauce

The robot is capable of moving around an applicator for pouring sauce on the pizza. With the rate of flow regulated, the robot would only need to move in a back-and-forth sweeping pattern so the whole area becomes covered in a uniform layer of sauce. A circular instruction with points that increase in distance from the center every 360 degrees would be ideal.

Resume Function

If the robot is rebooted halfway through a pizza and the program were to start again, it would start to lay pepperoni over the pizza from the beginning. Consider how a digital input may used to disable the lines of code that set offsets back to zero at the beginning. In reality, this would be triggered by a connected PLC or HMI, where an operator is prompted with the choice to resume where it left off.

Additionally, if power was lost mid-pizza, it is likely the air was shut off (which is often tied to the master control relay) and the pepperoni it was holding has fallen off. It would need to resume from the beginning of the pick operation!

Pepperoni Error Correction

This program works in concept but relies entirely on perfectly uniform food products. In reality, this doesn't happen and you will need sensors to adjust for errors. On your own, think about how you could add these error correcting features:

  • Pepperoni Height Adjust - We used 1.8mm as a constant but it could instead be taken from a laser distance sensor above the stack.
  • Gripper Error - A fiber optic reflective photoelectric sensor can be placed inside the vacuum cup brass piece to sense if a pepperoni is loaded, to "redo" a pickup when a piece is dropped. A vacuum pressure sensor can also be used, although a clogged cup will trigger it.
  • Stack Empty - Multiple stacks can be used, letting the cell run longer without human intervention. In industry, a feeder system is often established to allow production operators to refill empty stacks of consumables while the robot works on others, so the robot never has to wait for a stack to be replenished. A door interlock would prevent it from switching stacks while an operator is working on it and prevent an operator from beginning work while stacks are switching.