As a contract programmer, it’s important for me to be as efficient as possible. Coding faster saves my clients money and allows me to move on to the next project quicker. Over the years I’ve developed quite a few tools and habits that help me do more work faster.
I picked up Ruby on Rails back in 2007. One of the things I really like about it is its liberal use of convention over configuration. By defining conventions for things that always come up, you don’t have to waste any time or energy developing solutions for them.
Almost every application requires registers for the following:
- Numeric Registers
- Position Registers
- Cartesian Zero
- Joint Zero
Defining these before you even start coding helps, but it will take you even less brain-power to decide where they’re going to be once and for all. Why not use these?
- PR[3:C ZERO]
- PR[4:J ZERO]
How many times do you need to use a temp register for a calculation? If it’s always R, you’ll never have to pull out your register definition spreadsheet to find out where it is.
It’s very easy for a clean program to become nasty quickly once error handling and conditionals start getting included. My thoughts on good labeling are enough for another post, but I do use a couple of labeling conventions that keep my programs consistent/readable and save my brain from reinventing the wheel.
Some people use LBL or LBL, but jumping to the end of a subroutine is so common that you should probably standardize it.
Error: LBL not found
I come from a web programming background. The HTTP response code that indicates a “Not Found” condition is 404. It’s generally displayed when the user follows a broken or dead link. How does this relate to FANUC TPE programming?
My programs will never actually feature a LBL definition, but I’ll probably have JMP LBL sprinkled throughout my code. I use it to prevent the program from doing something stupid such as setting a PR Z-value to a value beneath the floor. For example:
IF R[10:Pick position]<1,JMP LBL ; IF R[10:Pick Position]>10,JMP LBL ; L PR[R[10:pick position]] 1000mm/sec CNT0 ;
If everything has been implemented correctly, R[10:Pick position] should always be within 1 and 10, but on the off-chance that someone gets things into a bad state, we won’t accidentally move to PR.
I usually use the 500 range of labels for different error conditions. Borrowing again from the HTTP status codes, 5XX response codes indicate that “the server is aware that it has encountered an error or is otherwise incapable for performing the request.” Wikipedia
LBL ; IF DI[1:Part present]=OFF,JMP LBL ; IF RI[1:Gripper overtravel]=ON,JMP LBL ; JMP LBL ; ; LBL ; ! Show HMI screen indicating part presence error ; UALM ; JMP LBL ; : LBL ; ! Show HMI screen indicating gripper overtravel ; UALM ; JMP LBL ; ; LBL ;
Thing * 100
You’ll see stuff like this all over my code:
SELECT R[1:Product ID]=1,JMP LBL ; =2,JMP LBL ; =3,JMP LBL ; ELSE,JMP LBL ;
Why not just use labels 1-3 and do something like this:
JMP LBL[R[1:Product ID]] ;
Or if you really wanted the -hundred range:
R[2:Temp]=R[1:Product ID]*100 ; JMP LBL[R[2:Temp]] ;
First of all, no error checking outside of jumping to a missing label (that you didn’t purposefully fail to include). You definitely could do this, but I just find it much explicit and readable. Even if you included error checking, it’s still not terribly clear which Product IDs are actually valid:
IF R[1:Product ID]<1,JMP LBL ; IF R[1:Product ID]>3,JMP LBL ; JMP LBL[R[1:Product ID]] ;
Maybe it’s just the second-line indent of the SELECT statement, but it just looks much more readable to me. The intent is clear and it includes error checking for free with the ELSE block. There’s obviously a point where the SELECT gets ridiculous (e.g. 15 or 20 cases), but it works well for the majority of situations.
There you have it
Don’t underestimate how important a good workflow is in being productive. Saving yourself a minute or two every time you have to do a repetitive task adds up to serious time in the long run.