Sei sulla pagina 1di 14

Parameterized Programming: Macro Variables

Introduction to the Mini-Tutorial on G-Code Macro Programming and


Fanuc Macro B
The next several lessons in the tutorial stand together as a Mini-Tutorial on Macro
Programming and Fanuc Macro B. In many ways, Macro Programming is the highest
level of G-code Programming. It offers the most flexibility and the greatest potential
power of any of the G-Code Programming Techniques. Without Macro Programming, GCode is not really a full fledged computer language, it's more a recording of a series of
manual steps. That's useful, but computers and CNC controllers are capable of a lot
more.
A word about Fanuc Macro B
Fanuc Macro B is by far the most common Macro Programming Dialect. Not all
controllers support full Macro B, and there are variations supported by some non-Fanuc
controllers. We can't document every G-Code Dialect here, but the concepts offered in
Macro B will be similar to what you see elsewhere, and therefore applicable to those
cases with slightly different syntaxes and capabilities. If you don't have a controller with
Macro B, it's still worth checking it out. Just use a our G-Wizard CNC Simulator and
Editor to play with the Macro B capabilities.

Parameterized Programming
Until now, all of our g-coding has been done without any recourse to variables or
formulas. If we wanted to go to a particular coordinate, we had to enter that coordinate,
either absolute or relative, to get there. A tremendous amount can be accomplished in
that way, but just as algebra is more powerful than arithmetic, so parameterized
programming is more powerful than basic g-code, and for the same reasons. Once you
have variables, you can start to parameterize your programming. You'll be able to create
general purpose routines that use parameters to tie them to specific uses you want to
make. Imagine being able to create your own custom canned cycles that can do almost
anything. A custom drilling cycle, or perhaps a routine to automatically serial number
your parts. Almost anything is possible.
Covering the whole of parameterized programming will involve three chapters in our
tutorial. In this chapter, we'll be dealing with variables and formulas. The next chapter
will delve into how to divide your code up into subprograms and access the
subprograms. Lastly, we'll deal with macro control structures. Not all controls support
parameterized programming. We'll be dealing with the Fanuc Macro B dialect for it, and
we'll throw in mention where of Mach3's parameterized programming features as well.

Parameters to Customize the Machine to the Controller (aka Why


We're Going to Quit Saying "Parameters")
You may have noticed that different companies often make the CNC Controller versus
the actual machine tool. In fact, this is nearly always the case. There are a collection of
settings inside the controller that are called parameters that are used to perform that
configuration of the controller to the machine tool. For example, the travels, spindle
speed range, rapid traverse rate, and many other types of information that are critical to
making the control work right with the machine. For that reason, you don't want to go
poking around with parameters too much, or you can scramble some of those settings.
Reading a system variable is okay, but don't assign any values to them unless you know
for sure what they do. You should make sure you have a good backup of all your
parameters in case the battery fails on the controller or they get inadvertently changed.
Typically there is a procedure available for your controller to use DNC to perform a
backup.
Now here is the tricky part: Parameters and Macro Variables are Two Different
Things!
I don't know why we like to call it "Parameterized Programming" and then immediately
quit talking about Parameters, which have little to do with Parameterized Programming.
It's tempting to think Parameters are just System Variables (more on what a System
Variable is in a moment), but they're completely different. There are ways to set some
Parameters from a part program, but this is not the most common way to deal with
them--usually it's done via the control panel. Therefore, we'll be sticking to the term
"variables" and will leave "parameters" for a future chapter.

What Are Variables?


First thing is first, what are variables? Simply put, they are just like algebra variables
that you can use in your g-code. They can be assigned values, and when you refer to
them, they give back the last value they were assigned.
The syntax for a variable is the pound sign followed by a number up to however many
digits your controller supports that identifies the variable. For example, we can write "#1
= 100" to assign the value "100" to the variable "#1". There's even a special "null" value
that says the variable never had a value assigned. The variable #0 always has a null
value, and you can give any other variable a null value just by assigning #0 to it. For
example:
#100 = #0 ( Make #100's value "null" )

These variables fall into ranges that affect their meaning and how they can be used.
Here is how Fanuc thinks of these ranges, for example:
Variable
Number

Type of
Variable

#0

Null

#1 - #33

Local
Variables

#100 - # 199
#500 - #999

Common
Variables

System
#1000 and up
Variables

Function
You can never assign a value
to #0, it's value is always
"null", which means "no
value."
Local variables are used to
pass arguments to macros
and as temporary scratch
storage. Your controller won't
remember the value of any
local variables when the
power is turned off. Local
variables nest when used with
suprograms, so be sure you
understand how that works.
Common Variables are
shared by all your macro
programs. When the power is
turned off on the controller,
#100 - #199 are cleared to
null. #500 - #999 remember
their values for the next time
power is turned on.
System variables can be used
to tell things about what the
controller is doing, such as
the current position. Don't
assign anything to these
unless you know what they
do!

Fanuc Macro Variables: Note that these ranges may vary across controllers and
especially for non-Fanuc controllers!
Mach3 has 10,320 variables available, from #0 to #10320. There's not quite the variety
found in Fanuc, but still, plenty of system variables are accessible so you can get at
things like work offsets. Mach3's variables are saved from one control boot up to the
next, so be sure to reset them if you aren't expecting them to have a value.
What Are Variables Good For?

Use variables whenever you think you might want to change a value in different
situations. For example, suppose you have a macro or subprogram that cuts a square
pocket. You probably want to have variables that let you define the size of the square
and the feeds and speeds so they may vary as the material changes. Depending on the
subprogram, you might want a variable for the top left corner of the square, or you might
simply let that corner be the current position when the routine is called. You may want a
variable defining the depth of the square pocket. And lastly, you may want a variable
that defines the diameter of the tool.
Which Variables Should I Use in My Programs?
System Variables and Local Variables have some special behaviors, so steer clear of
those unless you specifically want those behaviors. System variables refer to specific
things going on in the controller, so are not usable as general purpose variables. Local
Variables exhibit "nesting" behavior with macros, so wait until you have read about
macro subprograms and understand them before deciding to use a Local Variable.
Common Variables are there for the taking, so try to stick to using those variables for
general purpose programming.
When Variables Can't Be Used
Most addresses (remember word address format?) can be variables, but not all. For
example, I can't have a sequence number that is a variable. N#10 is not allowed. Here
is a short list of the "not alloweds":
- Program Numbers: O#10 is not allowed. Neither is :#10 for controls that allow ":" for
program numbers.
- Sequence Numbers: N#10 is not allowed.
- Block Skip Address: /1 is okay but /#1 is not allowed.
- WHILE..DO..END Addresses: DO1 is allowed, DO#1 is not.

Expressions: Formulas
Formulas used in parameterized programming are called Expressions. They work pretty
much as you'd expect algebraic formulas to work with a few things to keep in mind:
- G-Code uses square brackets ("[" and "]") instead of parenthesis, since parenthesis
are used for comments. It looks kind of strange, but you get used to it pretty fast. So,
instead of:

#1 = (#2 * #3) + #4
you need to use:
#1 = [#2 * #3] + #4
- The standard operators are add ("+"), subtract ("-"), multiply ("*" asterisk and not "x"!),
and divide ("/").
- The minus sign is also used for negation. Think of it as multiplying whatever follows by
-1.
- There is a list of other operators and functions that may be somewhat controldependant. Make sure you check your manual to see if your control supports them and
if so just how they work. Here is a list of operators and functions for Fanuc and Mach3:
Operation

Fanuc Mach3
Uses
Uses

Function

Arithmetic Functions
#1 ** #2 raises #1 to the power #2.
#1 ** #2 Power takes precedence over the
other operators.

Power

Modulus divides and returns the


remainder. So 5 MOD 2 is the
remainder of 5 divided by 2, which is
MOD 1. The modules of 4 divided by 2 is 0.
Mod is a convenient way to keep a
value with a range of 0 to the MOD
divisor.

Modulus

Absolute
Value

ABS

ABS

Absolute value. ABS(1) = 1. ABS(-1)


= 1.

Rounding
Down

FIX

FIX

Rounds down to the next smaller


integer. FIX(2.8) = 2, FIX(-2.8) = -3.

Rounding Up

FUP

FUP

Rounds up to the next larger integer.


FUP(2.8) = 3. FUP(-2.8) = -2.

Rounding Off ROUND


When used in a macro function like
IF, ROUND rounds down by slicing off
the fractional decimal places.
ROUND(1.1) = 1.0. ROUND(-1.1) =
-1.0.
When used as a coordinate address,
ROUND rounds off to the least input

increment of the address = 0.001 for


mm and 0.0001for inches.
Square Root

SQRT

Natural
Logarithm

LN

Exponential

EXP

SQRT

Trig Functions
(Units are Degrees, 90 degrees 30 seconds = 90.5)
Cosine

COS

COS

Sine

SIN

SIN

Tangent

TAN

TAN

Arc Cosine

ACOS

ACOS

Arc Sine

ASIN

ASIN

Arc Tangent

ATAN

ATAN
Logical Functions

Logical OR

OR

OR

Logical AND

AND

AND

Logical XOR

XOR

XOR
Other Functions

Convert from
BCD to BIN

BIN

See your Fanuc manuals for more


details on these specialized functions.

Convert from
BIN to BCD

BCD

See your Fanuc manuals for more


details on these specialized functions.

Fanuc and Mach3 Expression Operators and Functions...

Tip: When in doubt about the order a formula will be calculated in, use extra
brackets

Most of us learned tricks in grammar school for how to remember what order to perform
arithmetic operations in. The one I learned was "My Dear Aunt Sally", which translates
to "Multiplication then Division then Addition then Subtraction." Because of that order
(called an order of precedence), these two formulas have an identical result:
#1 = [#2 * #3] + #4
#1 = #2 * #3 + #4
But this can get confusing. Always use extra brackets to make the order clearer at a
glance.

Calculating Which Variable to Access


This is kind of a trick, but you can calculate which variable to access. Instead of
retrieving #107, you could write #[100 + 7], or any other expression inside the square
brackets. This is often useful when you want to loop through variables that are grouped
together in a certain way. You can even write #[#2], which is the variable whose identity
is the value stored in variable #2. So, if the value of #2 was "10" and we write "#[#2]", it
is the same as writing "#10". Some controls will tolerate "##2", but most won't, so get in
the habit of using the square brackets.

Subprograms and Macro Calls for Code Building Blocks


In the article on Parameterized Programming, we learned how to modify g-code so it
can be used in many different situations through the use of variables. You could try
copying and pasting your code everywhere to reuse it, but that's a mess. First thing that
happens is you need to change the code, perhaps to fix a bug, but you have copies of it
scattered everywhere.
To make g-code convenient for re-use, we need some way of centralizing it and then
accessing it from the part program. The G-Code language provides two different
methods for doing this: subprogram calls and macro calls. Think of each as a way to
access code sequestered in its own little mini-program. You "call" that code, it does its
thing, and then it "returns" to your main program to continue executing right after the
call. It's kind of like delegating responsibility to that code snippet.
If you have a big library of powerful snippets, you've got the potential for some real
productivity enhancement. Even if you're not trying to reuse code, using calls can make
your existing code much smaller and easier to understand. Consider the process of
milling a pocket by stepping down several levels and cutting the same toolpath. Why
repeat the same path for each level? GibbsCAM generates g-code that generates the
path for a level once as a subprogram and then calls it multiple times after setting the zlevel deeper each time. Makes for much smaller programs. Pretty cool trick!

Subprogram Calls
Let's start out with Subprogram Calls, because they're a little simpler to understand than
Macro Calls, albeit less powerful. A subprogram call is pretty straightforward. First, stick
the g-code for the subprogram under its own subprogram number--its own "O" number.
Your program might look like this:
%
O1000
N100 (Main program)
...
N330 (Call Subprogram) M98 P2000
...
N1000 M2 (Program Stop)
O2000 (Subprogram)
N2000 ...
...
N2130 M99 (Return to Main program)
As you can see, the main program and the subprogram each have their own "O"
number. The call to the subprogram is "M98", which takes a parameter telling it the "O"
number where it can find the subprogram. When it hits M98, execution jumps over to
the subprogram. When it hits an "M99" in the subprogram, that causes it to return to the
main program right where it left off and keep going.
Subprogram Call Syntax
Depending on your controller, there are a number of different syntaxes available for
Subprogram calls. Here is G-Wizard CNC Simulator and Editor's screen for setting up
your controller's syntax:

Subprogram and Macro Call Syntax...


While there are a lot of different styles, they're mostly just slightly different ways of
saying the same things:
- Where do I find the subprogram? There is a word (most often the "P" word) that
provides the address. That address is typically an "O" word, but many controllers have
the option of looking for an "N" word if the O# is not found.
- What about a repeat? It is often convenient to code a repeat on the subprogram in the
same line using a different word. For example "L" may tell how many times to call the
subprogram before finally continuing to the next line.
- How deeply can I nest subprograms and macros? Your program can call a
subprogram, which can call another subprogram, yada, yada. How many levels deep
are allowed? Controllers have a limit to this.
- G65 is a Macro Call, whereas M98 is a Subprogram Call. More on macro calls in a
minute.
- Some controllers allow the M99 return to return to a particular line instead of just
returning to where the subprogram was called. I don't find this to be a good practice
because it is confusing. If you wanted to "goto" a line there is a macro "GOTO" for that
purpose, but not all controllers have it.
That's about it. Not so bad. For now, just focus on calling subprograms and returning
from them.

Haas Special Subprogram Goodies


It's not uncommon for a controller manufacturer to have their own "Special Sauce"
features that make their controller special. So it is with the Haas Local Subroutine, M97.
M97 is a quick and dirty subprogram because you don't have to bother setting up "O"
numbers. You can just call any "N" number with M97 and "poof" it's a subprogram.
Convenient, although other controllers have that option to look for an "N" if the "O" is
missing, which takes a little of the wind out of the quick-n-dirty M97's sails.
Note that Haas will do M98 too, it just has M97 for the quick and dirty calls.
M97 is enabled in GWE by default. If your controller doesn't support it, go to Setup Post
G/M-Codes and disable M97.

Macro Calls
A lot of cool things can be accomplished with M98-style subprogram calls. Once you
start using them, one of the first things you'll notice is you need to pass information to
the subprogram. You want to give it parameters, in other words. With what you've
learned so far, you're probably ready to do this by plugging values into Common
Variables before calling the subprogram. But, if your controller supports Macro Calls,
there is a better way.
Macro Calls are initiated with G65 instead of M98 (or M97 on a Haas). Macro Calls have
what are called "arguments". Silly word, nobody is arguing about anything, but all
programming languages that have this capability refer to it as "arguments". Arguments
let you use word address format to send information to your macro. Let's say we have a
special custom deep hole drilling cycle we have created. We want to pass it the X and Y
coordinates where the hole goes as well as a Z coordinate for how deep to drill. With a
custom Subprogram Call, it might look like this:
...
N100 (Custom Deep Hole Cycle Subprogram Call)
N110 #1 = 2.5 (Load X into #1)
N120 #2 = 3.0 (Load Y into #2)
N130 #3 = 5.4 (Load Z into #3)
N140 M98 P1000 (Call the Deep Hole Cycle)

...
As you can see, we loaded X, Y, and Z into Local Variables. The subprogram knows
which local variables contain which information and can go on about its business after
retrieving those values. Now here is what it might look like for a macro call:
...
N100 (Custom Deep Hole Cycle Macro Call)
N120 G65 X2.5 Y3.0 Z5.4
...
That's a whole lot easier on the eyes, isn't it? Easier to remember too. How does the
macro get access to X, Y, and Z?
This happens by a special process where the local variables #1..#33 are kept in what
are called "levels". When I call G65, the current values of all those locals are copied to a
level, and any words I use in calling G65 are transferred into the local variables. This
table shows how the words are mapped to local variables:
Argument Word

Local Variable

#1

#2

#3

#7

#8

#9

#11

#4

#5

#6

#13

#17

#18

#19

#20

#21

#22

#23

#24

#25

#26

Argument Words and Which Local Variable They're Transferred to in a Macro Call...
As you can see, each possible argument word has a pre-assigned local variable. If you
use X, Y, and Z as we did in our example, their values will be transferred to #24, #25,
and #26. Pretty simple to use and very convenient.
Now what about those levels?
Well, as we mentioned above, subprograms and macros can be nested. One can call
another. Each time a macro is called, its Local Variables are saved in a level. That way,
when execution returns to that macro, the local variables have been saved in a level
and they can be restored unchanged. Even though other macro calls may use the same
word arguments which map to the same local variables, they have their own copy of
those local variables in their own level, so the two don't interfere. In practice, it takes
longer to explain what's happening with levels than to just use the macro arguments and
not have to worry about whether a local variable is getting overwritten by another
macro--it's not.
But, and this is an important "but", it could be overwritten by a subprogram call. The
answer is simply to quit using subprogram calls when you have macros available, or at
the least, use variables outside the local variable range and realize they can be
overwritten.
Note: A lot of Controllers Don't Have Macro Calls
Not every controller has the convenience of macro calls. Mach3 doesn't, for example.
But, they are just that--a convenience. You can accomplish everything you really need
with ordinary subprogram calls, it'll just take a little more work is all. Sorry!

Macro and Subprogram "O" Numbers


First thing to know is that "O" numbers don't have to appear in any particular order in
your program file--they just have to be unique. You can't have two "O1000" entries.

The second thing to note is that on some controllers it is possible to provide protection
for some ranges of O numbers. This makes it possible to put standard macros onto a
machine that can't be tampered with. For example, maybe you made a big investment in
a set of probing macros and don't want them to get changed or overwritten. You'll need
to consult your controller manual to see whether it offers protection and if so how it
works. For now, just assume that protected macros have "O" numbers up in the higher
ranges. For Fanuc, O0001 to O7999 are unprotected, and that's where you should put
your macros.

A Stack Trace for Fanuc Macro Subprograms when G-Code


Programming
Recently, I was working through a complex g-code program to find and fix some bugs
in G-Wizard Editor. Trying to understand what the heck somebody else's program is
doing and whether or not my own g-code simulator was properly simulating the program
often leads to helpful ideas for tools that make G-Code programming easier for
everyone. For example, it got me to add the ability to make the simulator run until it hits
the next macro command that would cause a branch to some location other than the
next line of g-code. This is a really handy way to buzz through programs going from one
subprogram to the next, and it corresponds to similar commands in debuggers and
simulators for other computer languages.
This time around, I had a program that had lots of subprograms all madly calling around
to make a bunch of holes and then thread mill them with NPT threads using helical
interpretation. The subprograms were quite clever in how they used the "L" word to
repeat the helix 4 times for 90 degree moves to complete each turn, and then 9 more
times to get 9 threads milled. But man, there sure were a lot of different little
subprograms all calling each other, sometimes with "L" repeats and sometimes not. I
was getting lost and found myself wishing for another tool that's commonly available for
other computer languages besides g-code. That tool is called a "stack trace". It basically
shows "who called who". Here is the newly implemented stack trace for GWE:

Stack trace is underlined in red...

It's a simple little tool. The list of numbers are the line numbers of the different callers.
So we can see the following:
- At line 35, the first subprogram was called.
- Within that subprogram, at line 176, another subprogram was called.
- Within that subprogram, at line 183, a third subprogram was called, and this one has a
repeat factor of "4".
This particular g-code part program nested down 4 levels and at one point had two
different repeat counts going. I told you it was complicated. This little display made it
tremendously easier to keep track of what was going on. The "L" numbers count down
as each repeat cycle is executed as well.
If you like to write these sorts of macro subprograms in your g-code, you'll want to have
this tool in your arsenal to help you follow what the part program is doing when you
simulate it.

Conclusion
You now have some powerful tools for packing your g-code up as building blocks that
can be recombined. Think of it as the ability to create your own custom canned cycles to
perform various tasks. With our next chapter, we will introduce Conditions and Looping,
which makes it possible for the g-code to make decisions on its own about what to do,
and to execute a list of instructions a variable number of times based on those
decisions.

Potrebbero piacerti anche