Clean Code

We’ve all been there: asked to work on a project where some or all of
the programming has already been done. You pick up the teach pendant
to find a program called MAIN which contains 1000 LOC with a mess of
labels, old sections of code that are jumped out and may even be
controlling other parts of the machine at the same time. If you’re
lucky, there might be some comments or thoughtfully-labeled sections,
but it’s still going to be a nightmare to work on. If only the original
programmer had put some more thought into the architecture of his
programming you wouldn’t have to sift through 1000 lines to fix a bug.

Naming

There are only two hard things in Computer Science: cache
invalidation and naming things.Phil Karlton

Luckily we don’t really have to deal with cache invalidation when
programming robots, but we do have to name things: programs, macros,
I/O, registers, positions, position registers, etc. Name things such
that their intent is clear, so that anyone who sees the program,
subroutine, etc. can intuitively understand its purpose.

How often have you seen a set of macros called GRIP_OPEN and
GRIP_CLOSE? What does that mean? You might assume that GRIP_CLOSE
would grip the part and GRIP_OPEN would release it, but what if the
gripper expands within the part to grip it? GRIP_ON and GRIP_OFF are
a little more clear, but I typically use GRIP and UNGRIP.

FANUC doesn’t gives us very many options to organize our code. There’s
no concept of directories for your programs; the best you get are
sub-types for macros, condition handlers, KAREL programs, etc. Since
everything is ordered alphabetically by default, I generally preface
my programs in a way to keep related programs together. At the very
least, I usually prefix all of my TP programs with some letter and an
underscore (e.g. J_) and all KAREL programs with a K_ to easily
distinguish between the two. Beyond that, I’ll try to simply extend
a given operation into more detail:

J_UNLOAD

J_UNLOAD_CONVEYOR

J_UNLOAD_BUFFER

J_LOAD

J_LOAD_CONVEYOR

J_LOAD_BUFFER

This helps me quickly scroll through the SELECT menu to find the
program I’m looking for.

Single Responsibility Principle

If you’ve ever done any object-oriented programming, you’ve probably
heard of this before. If you haven’t, it means that any class (think
of a program or subroutine) should have a single responsibility; it
shouldn’t be doing many different things.

Let’s look at our earlier example. We had one program, MAIN, that did
the entire operation. Assuming the operation is more than just a move
from A to B, we can probably do a better job of communicating intent.

If it’s a pick and place operation, your main program might look like
this:

The programs are about the same length, but we’ve reduced duplication
significantly. If you wanted to change a segment speed or an approach
offset, you only have to change it in one place. Yes, we’ve added one
level of indirection here, but it’s not hard to follow. The tradeoff
in clarity and reduced duplication makes it easy to justify.

Don’t Repeat Yourself (DRY)

I believe this may be the most important programming principle I
follow. Any time I see code that looks similar in two places, I try
and think of a way to refactor it so that the code is not repeated.
It’s much easier to fix a bug in one place than many places. A smaller
code-base is much easier to maintain than a large one.

Small Bites

What is it people say about eating elephants? Big problems are much
easier when you break them down into smallerchunks.

Try and reduce your problem into its main operations, then break those
operations into even smaller subroutines. I had a project recently
where the robot had to be ready to perform any given operation depending
on the current state of the cell. I broke the requirement down into its
two main parts and then broke those parts down into smaller chunks:

J_HANDLE_UNFINISHED

J_PICK_STA9

J_PLACE_STA10

J_HANDLE_FINISHED

J_PICK_FINISHED

J_PICK_STA19

J_PICK_BUFFER

J_PICK_INSPECT

J_PLACE_FINISHED

J_PLACE_DUNNAGE

J_PLACE_BUFFER

J_PLACE_INSPECT

J_PLACE_REJECT

This could have gotten messy real fast if it had all been one giant
program jumping around to many different labels.

I’d argue that your main routine should probably have only a couple of
labels at most, with the only jumps being in and out of the main loop.
Anyone should be able to look at your main routine and clearly
understand what the robot’s operation is.

There you have it:

Name things accurately to communicate intent

Organize your programs by name to save time

Your programs should only do one thing (Single Responsibility
Principle (SRP)

Don’t Repeat Yourself (DRY)

Break things down into small chunks

Your MAIN program should be simple

If you follow these guidelines, you and the other programmers who
end up having to support your code will have an easier time and thank
you for it.