What's new
What's new

Macro Programming Fundamentals


Dec 23, 2007
Southeastern US
Macro programming is a useful tool for most any CNC machine shop, whether a one man garage or an international conglomerate. Macro programming provides a means of shortening code and doing repetitive tasks easily and quickly. All of your canned cycles in a control are nothing but a macro. Macro is also extremely useful for families of parts.
All computer programming is on a fundamental level, very similar. The syntax of the commands, and purpose of the programming may change, but the fundamentals of how to approach it, how logic works, and program flow are pretty much the same.

The first step to any programming is to define the _functionality_ required of the program. Functionality is defined as the end result(s) and abilities expected of the computer code. In other words, what is it supposed to do.

When we write a macro, we have a desired result in mind. Write down the broad-based result you are looking for from the program. A broad-based result would be something like: Bolt circle drilling, rectangular pocketing, block facing, slotting, etc.
For an example, lets use bolt circle drilling.
After we have defined the broad-based functionality, we need to narrow down the specifics of what we desire from the program. We must set limits to the functionality we want to achieve. If no limits are set, then the program becomes too large, cumbersome and time consuming.
In our example, one of the main limits we need to set is the maximum number of holes we will be allowed to drill in the macro. For the sake of brevity, lets limit ourselves to 10 holes (We have another question coming up that, in reality, allows unlimited holes using only 10 as a maximum here)
So: Max Holes in pattern == 10.
Next up on the functionality list regarding hole drilling: Do we have a drilling cycle in the machine control or not? Most of the time, this is going to be a yes, so we will go with that.
So: Have drilling cycle in control == Yes
Next up on the functionality list: Do we want the ability to start the hole pattern at some angle other than directly along one of the major machine axis (X,Y,Z), this is seen often in parts, so yes, we want this functionality.
So: Ability to start holes at operator input angle == Yes
Next: Do we want the macro to call the tool, or will you already have the tool in the spindle when you call the macro? Lets do macro does not call tool. This is really a programmers preference as to which way to go, but since the possibility exists that we could do multiple bolt patterns with the same tool, we wouldn't want to go to tool change position each time between patterns.
So: Macro calls tool == No
Next: Do we want to induce multiples of our max holes? This would allow you to drill more than our stated maximum number of holes. I think we can implement this in a short manner, so we will do this.
So: Macro allows multiples == Yes
What other functionality should we define?......hrm.....for now I can't think of anything, so onward we go with the functionality described above.
Programing standards for Variables

Now that we have defined functionality, we need to set some standards with regards to the macro programming. The first thing to consider is the variable table. You have four (4) types of variables:

Local Variables: These variables are local to the program. Normally used to transfer values to a cycle call, or as intermediate mathematical value holders. I hate using local variables because of one major issue with them. They are reset to null (not 0) when the control is reset or the program ends. While perfectly fine for use in transferring variables to canned cycles, etc. They can get you in trouble if you use them for other things. I, just by policy, never use them for anything. In Fanucese, these are typically #100-#499 (if you have that many available). Local variables are only available to the program in which they are used.

Global Variables: These variables, once set, remain set unless you change or reset them via macro or the control keyboard. Unlike local variables, global variables are available to any program in the control. I use gobal variables because they are retained, can be used in any program, and you can track what's going on if you have an issue. In Fanucese, these are typically #500-#999

System Variables: These variables are available to use in macro programming and allow you to write and retrieve information from the control itself, such as tool in the spindle, tool offset active, write and read offsets, check active codes, etc. Very handy indeed, BUT, these are _NOT_ standardized to a great extent. You will have to consult the macro programming portion of your control manuals to determine what these are.

String Variables: String variables are a group of characters interpreted as a single value. Typically defined with a $ symbol. String variables allow you to manipulate text and phrases etc. Not all controls support string functions.

I typically define my variable fields along the following lines:
#500-599 : Input variables to the macro
#600-799 : Mathmatical functions of the macro
#800-899 : Variables needed with regard to tooling, offsets and system variables.
#900-999 : Logic keep bits, counters, etc
Define Inputs

After we have defined our functionality and standardized our variable table usage, we now need to define the inputs to our program that are needed to generate the functionality results we desire. My method is to put the inputs in a separate subprogram from the actual working program. This helps to prevent editing errors from curiosity and just oops in the main macro.
The inputs we need to do our drilling are the following:
#500 = Number of holes to be drilled
#501 = Bolt circle diameter
#502 = Angle of first hole along the X axis at machine coordinate 0° angle. Typically this is the X+ direction.
#503 = X axis absolute position for bolt circle center
#504 = Y axis absolute position for bolt circle center
#505 = Hole Depth
#507 = Pecking Depth
#507 = R plane clearance
#508 = Feedrate for drilling
#509 = Clearance height (above part Z0) for rapid movements between holes
#510 = Spindle speed for drilling
#511 = W function of the G82 drill cycle
#512 = E function of the G82 drill cycle
#513 = V function of the G82 drill cycle
#514 = L function of the G82 drill cycle

That's all I can think of right now that we would need to achieve our stated functionality. If anyone sees something missing, let me know, as I'm writing this and thinking it through as I go. - Btw, I'm writing this based on the Brother B00 implementation of fanucese. More to come later.....
Nice Job Tony!

Couple o' things...

I worked with a machine tool builder once, that had a bolt circle drilling canned cycle. Either a degree spacing, or a # of holes equally spaced could be programmed. Also, there was a "word" somewhere to skip one or more of specific holes in the array.

I like to use pass-through variables. The ones between 1 and 26, inclusive. #500+ can be set from within a program if you don't want to have them be as volatile as you have described.
Nice Job Tony!

Couple o' things...

I worked with a machine tool builder once, that had a bolt circle drilling canned cycle. Either a degree spacing, or a # of holes equally spaced could be programmed. Also, there was a "word" somewhere to skip one or more of specific holes in the array.

I like to use pass-through variables. The ones between 1 and 26, inclusive. #500+ can be set from within a program if you don't want to have them be as volatile as you have described.

Yes, I've worked with a few controls that had a bolt circle cycle. Handy they are. I'm just using this as an example of how to lay out a program, and some of the basic functionality available with macro programming.
Program flow functions

We need to understand some program flow (control) functions before we do our mathematics because we need some of these functions to quickly perform the mathematics.

These are the 3 most commonly used:

IF [compare1 {function} compare2]- GOTO[block]: The if-then statement is a conditional jump. If the statement is true then the GOTO command is executed and a program jump is performed. If the statement is false, then program flow continues with the next block. There are numerous functions available, the most common are:
EQ - (==) - Equals
NE - (<>) - Not Equal
LT - (<) - Less than
GT - (>) - Greater than
(Consult your manuals for the full list of supported functions and the symbols, fanucese uses letters, Siemens uses symbols, this varies by mfg)
N40 IF [#500 EQ 0] GOTO 900 - If variable #500 equals 0 then jump to block 900.

WHILE [compare1 {function} compare2] DO END: While the comparison is true, the blocks between DO and END are repeated, with the comparison checked each time it loops through.
N10 WHILE [#530 LT 8] DO
N80 .......
So long as #530 is less than 8, blocks N40-N70 are executed repeatedly. When #530 is no longer less than 8, program execution jumps to block N80 and continues.

GOTO {block or label}: This is an absolute jump to a different block. In the Siemens controls the commands are GOTOF and GOTOB depending on which way you want the control to search for the block. (F = Forward, B = Backwards) Siemens also supports labels, while fanuc style does not.
Be careful using the EQ - (==) - Equals comparison. Depending on the variable type, esp. floating point, they might not compare, even though you know they should, due to rounding errors.
Good call 3t3d it is floating point math. I spent about 4 days pounding my head against the wall :wall:. Trying to figure out why when I had IF[#23GE#17] GOTO1 and I would look at the variables and the were both be .400 but would not jump to 1. I had to end up using the rounding function to fix it. IF[ROUND[#23*10000/10000]]GE[ROUND[#17*10000/10000]]GOTO1

Tonytn36 Nice work :smoking:.
I just wanted to throw my 2 cents in. I know that it is the programmer’s decision if the tool call is in the macro. I use this in the macro to keep less data out of the main program with the macro call. I don’t believe that you should limit yourself to 10 holes for the fact that what happens when you have to do 11 holes? Now the macro has to be changed. I like to look at it as the fact the only thing that can cause the macro to not machine what you want is the few variables that you set in the macro call. There should also be specified a bolt circle diameter. I also like to use the Local variable assignments #1-#33 because if a macro call is written and a variable is forgotten then the old variable from the previous program. I know code can be written to check this but that gets into longer macros and more calculations. My macro calls cosist of 6-8 variables on average.

Nice catch on the EQ 3t3d. I should mention that most controllers with macro ability also support RND, FIX and INT functions.
On the hole limit of 10..... I chose 10 because from the values 0 - 10, you can achieve all other values needed for number of holes and it can limit the number of calculations you need to do in the macro, by adding just a few.
As mentioned, and of note many things when macro programming are "programmer preference", including whether to use local variables or not. I just prefer to not use them and that decision is based on the fact that one man was killed because of ill-advised local variable use (3t3d and SwissPro should remember this incident from a.m.c). The biggest key is to be _consistent_ with how you program.
You should _always_ have variable range checks in your macro. This is akin to shutting the door on the mill before you plow into a piece of aluminum at 10K and 200 IPM. It's a safety issue, both for the machine and the operator. Yup, it takes a few minutes to write, and eats up a little memory, but if it saves your machine just once....it's paid for all of that time and effort.
Kudos Tony for starting an "Education Thread" Like to see more of this, along with fixturing tips & tricks, machine specific tips like the Haas thread. Perhaps the mods could start a new 'Training Forum' or sub forum in each forum (lots of 'how to' questions that pop up in the gunsmith forum) where threads like this can be cataloged & locked to serve as reference material instead of getting buried in the archives.
Tony I agree with you 100%. Most of my programs that actually run and loop the part are 10 lines of code but I have 30 lines of calculations that check and alarm in case someone fat fingered a number ect. I was more referring to it is hard to catch a clearance plane for example as you were describing for #509. If you use for example #1 for your clearance at the beginning of the macro you can have IF[#1EQ[#[0]]]GOTO1000(alarm). Which means if you forgot to set #1 all together it will be equal to null and the calculation will catch that it was never set. However if you run 1 macro setting #509=3 then run another macro when you need a clearance of #509=5 and you forget to include #509 in your program all together it is going to use 3. It’s just a bit harder to catch that in a calculation without making the macro part specific.

As you said it is programmer preference. However I do like to have my clearance planes in the #500 that way there is always something for clearance as long as you’re using #500 in all of your macros.
The way I like to put in safe calculations is take each variable that is being set and 1 at a time run it through every scenario that an operator can change it to and what the outcome would be. Then combine 1 and 2 for outcomes ect.

There is no limit to macros except imagination. Great work on breaking down the systematic process for developing a macro. I look forward to seeing your code :drool5:. Just when you think you know all the tricks someone shows you something you didn’t think was possible :eek:.

Fanuc / Okuma Converter

Just a side note ... Kentech Inc. has released a new option for our CNC XChange software that can auto-convert Fanuc Macro B code to Okuma User Task and reverse. So, for users familiar with one but not the other and may either have both controls on the floor or are wishing to purchase one or the other, CNC XChange can save a lot of work and still allow you to utilize your previous, tested and proven macro programs.

Info and demos at www.KentechInc.com
Thanks for the sticky, WILLE. I won't have to go surfing for the great info from Tony.

Bluechip, are you saying that the converter changes the Fanuc macro into a common variable program for the Okuma?
Hrm..... Why can I not edit my previous posts on this thread now?

Anyway... appreciate the sticky Willie. Maybe someone will find something useful in the thread.

and now....
Last edited:
Mathematical Functions Available to Us

There are quite a few mathematical functions available to us for macro programming. Some controls offer more extensive operation sets, but I'll stick with the Fanucese standard set for now.

All Fanucese and fanucese compatible variables begin with a pound (#) sign (#500). Siemens variables are preceded by an R (R500). I am not sure what other controls use.

In a macro logical or mathematical statement, the variable to be written is to the left of the operator sign, while the function (equation) is written to the right of the operator sign.
N30 #500=500+#502 (The results of the equation 500+#502 is written to #500)

NOTE 3: For NESTED equations, brackets [] must be used to delineate the order of operations, if they must differ from the standard order of operations supported by the control.
The standard operational order of equations for Fanucese is:
First: Functions (Trig Functions, etc)
Second: Multiplication, Division, AND
Third: Addition, Subtraction, OR,XOR

Check your controller manuals for this, as it *does* differ from control to control.

Mathematical Functions:
Definition (=)
Addition (+)
Subtraction (-)
Multiplication (*)
Division (/)
Sine (SIN)
Arcsine (ASINE)
Cosine (COS)
Arccosine (ACOS)
Tangent (TAN)
Arctangent (ATAN)
Square Root (SQRT)
Absolute Value (ABS)
Rounding Off (ROUND)
Rounding Down (FIX)
Rounding Up (FUP)
Natural Logarithm (LN)
Expotential (EXP)
Logical addition (AND)
Logical or (OR)
Logical xor (XOR)
Conversion BCD to BIN (BIN)
Conversion BIN to BCD (BCD)
Our Bolt Circle Example

We have four distinct possibilities that could occur with our bolt circle example.
#1. There is an even number of holes, one of which starts on a Major axis.
#2. There is an odd number of holes, one of which starts on a Major axis
#3. There is an even number of holes that do not start on a Major axis.
#4. There is an odd number of holes that do not start on a Major axis.

Now, we could write one macro that would ignore the differences of the four possibilities listed above and programmers preference abodes here. However, in the spirit of this thread, and to show some programming possibilities, we will handle some of these differently.

The differences in the above statements are even vs odd and hole aligned or hole not aligned.
Lets look at the even/odd thing first.
How are we going to determine if the number of holes the operator has given us in #500 is even or odd, given the limited mathematical functions available to us in the control?
The rule to determine if a number is even or odd is: Is the number divisible by 2 with no remainder.
If we take
#600 = #500/2
#600 will now be the result.
Now if we take #600 and do a little work with it, we can determine if the value is even or not.
#601 = FIX(#600)
#602 = FUP(#600)
What we have done here, is both round UP and round DOWN to the integer.
With the FIX command, if the value of #600 was 3.33 the FIX command will round the value to 3.0.
With the FUP command, the value will be rounded to 4.0
If you use the ROUND command, it will be rounded to the first decimal, based on normal rounding rules.
Now we can compare our original value, to the rounded values. If the number was evenly divisible, all 3 values should be identical. If the value was not evenly divisible by 2, then the FIX and FUP will return different values and our logic statements will not be true.
IF [#600 NE #601] GOTO 400 (Non even number)
IF [#600 NE #602] GOTO 400 (Non even number)
If they are equal, we keep going.....in the next post....
CNC XChange

QUOTE : "Bluechip, are you saying that the converter changes the Fanuc macro into a common variable program for the Okuma? "

Yes ... CNC XChange will auto-convert all areas of the Fanuc Macro B language including Common Variables, System Variables, Arithematic Operations, Control Commands ( While / Do loops, If, etc., Conditional Expressions ( EQ, LT, etc. ) ... into the compatible Okuma User Task commands / variables ... and REVERSE.

CNC XChange also has an unlimited user defined area where users can set-up their own "what-to-convert-into-what" in case their control does some specific functions not covered in the hard-coding.

Of course .. our standard version of CNC XChange will also convert standard Fanuc G code to Okuma OSP code ... and REVERSE.

Again ... info and video presentations at www.KentechInc.com