FANUC Robot Programming
Last updated: 7/2/2026
Whether you're programming your first FANUC robot or tightening up your approach, here's how I think about it after ~20 years.
I remember being nervous while making changes to a production cell when I first started working at FANUC.
Will this crash the robot?
Will this brick the controller?
I mostly learned through experiencing pain. One of my first tasks in 2008 was to put together a demo of an M-420iB case-packing some random boxes that were coming in on a conveyor. Vision and line tracking... not the easiest first project.
I think this was the first time I ever saw the TP programming language syntax, and I was immediately struck by how easy it was to read. The language is simple and hasn't changed much in decades.
I'm sure I crashed the robot a couple of times while working on this cell. In fact, I definitely remember breaking some sort of pressure gauge off of an M-410 while doing the PalletTool training class (you have to watch everything while moving the robot), but there was a saying at the time: "If you've never crashed a robot, you've never driven a robot."
I'd been programming since I was a little kid, so the case-packing program immediately showed me some pain. Do I really need to teach a unique point for each of these drops? Does TP have arrays or something? There must be a better way.
I asked around, and sure enough, someone showed me the Position Register screen. This wasn't exactly what I was looking for, but it would definitely help. With Position Registers I could teach one point and generate subsequent positions relative to that point. I could also use Frame Offsets and Tool Offsets to get a nice motion profile without repeating myself.
I guess my point is this: you can't really fully understand what programming a FANUC robot actually involves until you do it. You need someone to show you the basics and then let you loose on a project. Use your brain, try your best, experience some pain and then see if there's a better way.
That's what I tried to do with my book, Robot Whispering: the Unofficial Guide to Programming FANUC Robots. We start with the basics, and then we build up a simple application from scratch, sometimes doing things the hard way before refactoring into something better. I think this is the best way to really learn how and why to do things a certain way.
I think program architecture and efficient motion are probably the two hardest concepts for new robot programmers to get. Here's my mental model for both:
99% of the time I start with a main program where the cell controller (PLC or PC) calls the shots. The shots are high-level tasks that the robot must perform: e.g. pick a part, place a part, go home, go to maintenance, etc.
From there, the structure of any given task is basically this:
- Move safely to the target station
- Make sure my gripper is ready (e.g. open + empty or closed + full)
- Wait for the station to be ready/Request access to the station
- Move to the operation position
- Do the thing (pick, drop, etc.)
- Update our payload
- Retreat
- Double-check station part-presence
- Double-check gripper part-presence
- Exit the station and say we're clear
That's it. Of course there are some finer details (e.g. there's probably a lot of logic within the "Move safely to the target station" step), but that's the recipe for most tasks.
For efficient motion, I always try to think about trying to get from A to B with as
few points as possible, as fast as possible, using CNT100 as much as possible.
Joint moves are ideal if you can swing it. Your robot can easily get wrapped up
with lots of linear moves and never using a joint move to force the correct joint configuration.
TP Programming vs. KAREL Programming
FANUC robots are programmed in two languages: TP (the teach pendant language) and KAREL. 99% of time you're going to be writing TP. KAREL is used for more complex tasks that TP cannot do: reading and writing files (see also this post on writing a logging utility), socket messaging, position transformations, monitoring, custom user interfaces with the FANUC form manager, complex multi-tasking, etc.
For an experienced programmer, KAREL is nice because it gives you typed variables, custom data structures, routines with variables that can be passed by reference, return values, etc. It's easy to test, particularly because we are generally not doing any MOTION with KAREL. FANUC removed motion support from KAREL a long time ago, so you'll have to shell out to a TP program if you want to move the robot.
The Teach Pendant
I love the teach pendant and FANUC operating system. Maybe it's just because I've been using it for so long, but I honestly think it's pretty easy to use.
Programs? Press SELECT. Maybe filter by TYPE with F1.
Select with ENTER, and your editor is right there.
Data? Press DATA. Use that F1 [TYPE] filter again to get to Numeric
Registers, Position Registers, etc.
Status? Press STATUS. Again, use F1 [TYPE] to see all the available
Status options.
I/O? Press I/O. Pretty intuitive, right? Our friend F1 [TYPE] lets you choose what type of I/O you want to look at.
Lots of good stuff under SETUP. F1 [TYPE] will get you to the right place: Frames,
Host Comm (for IP address settings), BG Logic (background logic), User Alarms, etc.
These are all just shortcuts. Similar to the Windows start menu, you can get anywhere by pressing
MENU. You just need to get familiar with the tree structure.
Alarms (see How to Diagnose FANUC Alarm Codes and Error Codes), File and System are probably the only other top-level
items I use on a day-to-day basis.
It takes a little time to get comfortable with where everything is and how to get deeper into each screen,
but you generally get there via the shortcut or MENU button and then use the F1-F5 keys
(and maybe Prev/Next) to operate the screen.
Running and Controlling Programs
As I mentioned earlier, 99% of the time some cell controller (likely a PLC) will be in charge. I wrote a long article on Starting FANUC Robots in Auto that pretty much covers everything.
For controlling the program, the main thing is the UOP signals (covered in the post above), and controlling the robot's speed override. I wrote about several ways to do that.
Generally you'll map I/O between the PLC and the robot and either use a Group Input to pass a tasks number to the robot, or maybe just a DI if that's easier.
Your MAIN program structure is then something like this:
LBL[1] ;
CALL GET_TASK_ID_FROM_PLC ;
SELECT R[1:TaskID]=1,CALL TASK_001 ;
=2,CALL TASK_002 ;
=3,CALL TASK_003 ;
ELSE,JMP LBL[501] ;
JMP LBL[1] ;
Where GET_TASK_ID_FROM_PLC might be something like:
LBL[1] ;
WAIT (GI[1:TaskID]<>0) TIMEOUT,LBL[501] ;
R[1:TaskID]=GI[1:TaskID] ;
GO[1:TaskID]=R[1:TaskID] ;
WAIT (GI[1:TaskID]=0) TIMEOUT,LBL[502] ;
END ;
;
LBL[501] ;
! timeout waiting for task ;
! TODO: alarm? ;
JMP LBL[1] ;
;
LBL[502] ;
! timeout waiting for task ack ;
! TODO: alarm? ;
JMP LBL[1] ;
Or if you're just using DIs:
LBL[1] ;
R[1:TaskID]=0 ;
IF (DI[1:Run Task001]),R[1:TaskID]=(1) ;
IF R[1:TaskID]<>0,JMP LBL[999] ;
;
IF (DI[2:Run Task002]),R[1:TaskID]=(2) ;
IF R[1:TaskID]<>0,JMP LBL[999] ;
;
IF (DI[3:Run Task003]),R[1:TaskID]=(3) ;
IF R[1:TaskID]<>0,JMP LBL[999] ;
;
! no task given ;
! maybe add a short wait ;
WAIT 0.01(sec) ;
JMP LBL[1] ;
;
LBL[999] ;
END ;
You basically want to write clean code that's easy to maintain.
Working with Variables and Data
Writing complex TP programs isn't a fun time. Most of the data you'll be using is global (e.g. Numeric Registers and Position Registers), and because these are referenced by index (e.g. memory location) instead of name, you'll have to map out this memory by hand using a spreadsheet or something. (NOTE: You can use Fexcel to automatically label your data from Excel and even use names in your programs intead of raw indices.)
For anyone who's used to just declaring named local variables or passing values to functions, this is a bit of a rude awakening.
I hated this so much that I wrote my own programming language called TP+ back in 2014. It was a fun project that helped me learn about how programming languages and compilers work, but I found it a little cumbersome to use in production -- keeping my high-level TP+ source code in sync with any small changes made on the teach pendant was difficult, and I never solved this workflow problem. I'm glad that Matt over at Group Six Technologies took over the project and continues to maintain it.
I had another go at this problem in 2021 and released the Fexcel "compiler" which keeps your code a little closer to the "metal." The source code is the same line-for-line, but any registers, position registers, I/O, etc. are replaced by variable names that correspond to definitions in your Excel spreadsheet.
Fexcel is great when I remember to use it, but I experience the same problem I did with TP+: it's difficult to keep my PC's high-level source code in sync with any changes on the robot.
I've written some tooling to compare my local binaries to what's on the robot, but that's not ready for general release yet. I think the next step is to write something that will convert a standard FANUC LS file into a Fexcel file so I don't have to... stay tuned.
Testing and Best Practices
Testing TP Programs
Projects go way more smoothly when you get them 99% of the way there in ROBOGUIDE first. Trying to figure out your motion on a real robot is painful. Do it in ROBOGUIDE first -- trust me.
That means getting CAD from your mechanical engineers. ROBOGUIDE tends to choke on large files, so it's best to simplify (if possible) and send different stations separately.
A good trick when exporting from SolidWORKS is to define a new coordinate system, perhaps one at the robot origin, and then use that coordinate system when exporting your IGES or STL files.
When exporting part and gripper CAD, make sure the coordinate system makes sense. Teach your mechanical engineers how the robot faceplate coordinate system works (+Z out, +X up when at zero) so you don't have to painfully move the CAD around after importing.
ROBOGUIDE v10 is a little better at importing CAD, but as of 7/2/2026 I have found v10 Classic to be more stable for v9.40 projects.
A lot of times I will have a register or flag bit in my TP programs to bypass certain programs or
checks while running in ROBOGUIDE. (e.g. IF (R[x:SIM]=1),JMP LBL[y].) It can be painful
to have to manually toggle I/O all the time to get through your routines.
The biggest pieces you need to get mostly figured out in ROBOGUIDE are 1) your large moves
from station to station and eventual wrist orientation at each station (e.g. are you running
NUT or FUT? J4/J6 turn counts 0, -1 or 1?) and 2) DCS.
If you don't know what I'm talking about with this NUT/FUT or turncounts stuff,
you can read more in my post about The Perils of Six Axis Robots.
For DCS, it's important to make sure your mechanical engineers gave you enough room to keep the robot, the End-of-arm-Tool (EOAT) and part safely away from the fence. You'll have to do your own safety analysis, but a good rule of thumb is a 50mm gap between DCS and your fence at payloads <10kg, 150mm if <150kg, 500mm if < 300kg and 700mm+ for higher payloads. I'm not a safety expert. Take these values with a grain of salt and do your own safety analysis. Also, mechanical engineers: just because the rule-of-thumb is 150mm doesn't mean to give the robot guys exactly 150mm. Keep in mind that the robot needs to get in and out of stations and our DCS user models don't match the CAD exactly. Leave some room.
It's best to verify there's a big enough gap EARLY in the project, so the engineers can make adjustments to the layout/guarding if necessary.
Once the big motion decisions and DCS are out of the way, it's good to get a head start on homing the robot. I like to use the exact same retreat routines for my main high-speed production routines as I do for homing -- this way I know these routines have a lot of runtime on them and don't only get run once in a blue moon. I also don't have to write essentially the same logic/motion twice.
To test homing, I generally just run a routine and stop the robot at various points throughout the motion. Then I abort and run the homing routine. The robot should home just fine. If it faults or does something weird, fix the homing routine. When homing from a station, I write code starting from the assumption that the robot is the furthest it can get into a station (i.e. at the pick or drop point) and write retreat code from there e.g.
CALL PROGRAM_TO_VERIFY_ROBOT_IS_AT_STATION ;
;
UFRAME_NUM=1 ;
UTOOL_NUM=1 ;
PR[x:LPOS]=LPOS ;
;
! assume robot is at pick position at this point ;
! and write a check to falsify that assumption ;
! e.g. the robot is above the point of the first retreat ;
IF (PR[x,3:LPOS]>a),JMP LBL[1] ;
! robot is probably at pick ;
! move to first retreat ;
! or maybe just straight up ;
PR[x,3:LPOS]=a ;
L PR[x] 500mm/sec CNTx ;
;
LBL[1] ;
! ok we are at least at Z=a ;
! do another check if necessary ;
IF (PR[x,1:LPOS]<b),JMP LBL[2] ;
! need to move back to b ;
! move to position or just adjust x ;
PR[x,1:LPOS]=b ;
L PR[x] 500mm/sec CNTx ;
;
LBL[2] ;
! ok we're at at least Z=a and ;
! X=b... do another check or maybe just move ;
! to the station perch ;
J PR[y:perch] 100% CNT100 ;
Testing KAREL Programs
As I mentioned earlier, testing KAREL programs is easy to do. It's also pretty important because you're probably doing some complex stuff.
It's not necessary, but I wrote KUnit back in 2014 to help with some simple assertions
while testing KAREL. I run a cygwin console environment and use curl to hit KUNIT and
run all my tests right from my console (e.g. make test.)
If I have a KAREL library called lib, I'll probably have a program called test_lib.kl.
(I guess you could also have lib_test.kl, whatever looks good to you.)
Then in test_lib, I usually have a routine to test routine I need to test e.g.
PROGRAM test_lib
...
ROUTINE test_add
VAR
result : INTEGER
BEGIN
kunit_test('1+1=2', kunit_eq_int(2, add(1,1)))
kunit_test('2+2=4', kunit_eq_int(4, add(2,2)))
kunit_test('4+1=5', kunit_eq_int(5, add(4,1)))
END test_add
BEGIN
kunit_init
test_add
kunit_done
END test_lib
My Makefile might look something like this:
HOST ?= 127.0.0.2
test:
curl -m 5 http://$(HOST)/karel/kunit?filenames=test_lib
curl -m 5 http://$(HOST)/karel/kunit?filenames=test_lib2
KUnit supports passing multiple filenames at once, but it does those in parallel which may not work if your code is not threadsafe. I usually just test each file with it's own HTTP call... should probably update KUnit to be able to opt out of this...
Backing Up Your Robots
You can use a USB stick to back up your robots, but it's easier to use FTP. BackupTool can backup all your robots at the same time with one command.
Where to go deeper
This is really just the beginning of all there is to FANUC robot programming. If you want to go deeper, I wrote a book that covers everything I think someone would need to know to get up and running and productive on FANUC robots. Check out Robot Whispering: the Unofficial Guide to Programming FANUC robots.
