Fanuc Macro B: variables, IF, WHILE and G65 explained

Fanuc Custom Macro B for machinists: variable types, calculations, IF and WHILE, macro calls with G65 and G66, argument letters, system variables and a complete bolt circle cycle.

Fanuc Custom Macro B, usually just called Macro B, is the macro language of Fanuc controls and of many controls that copy the Fanuc dialect. This page explains the parts you need for everyday work. The general ideas behind variables, conditions and loops are explained in Control flow basics.

Is Macro B available?

On older controls Macro B is an option. If the offset screen shows a page for macro variables, the function is installed. The available variable ranges and some details depend on the control generation and the machine builder’s settings. When in doubt, test with harmless values in MDI first.

Variables

A variable is written as # followed by a number. The number decides what kind of variable it is.

NumberTypeBehavior
#0Always emptyCan be read, never written. Used to check whether another variable is empty
#1 to #33LocalBelong to one macro call. Arguments of a G65 call land here. Empty at the start of every call
#100 to #199Common, volatileShared by all programs. Cleared when the control is switched off
#500 to #999Common, retainedShared by all programs. Keep their value after power-off
#1000 and higherSystemAccess to machine data: offsets, positions, modal states, alarms, timers

On older or smaller controls only part of the common ranges may exist, for example #100 to #149 and #500 to #531. Common variables can be viewed and edited on the macro variable page of the offset screen.

Empty and zero

An empty variable (null) and a variable with the value 0 behave differently in some places.

Situation#1 empty#1 = 0
G01 X50. Y#1Y is left out, only X movesY moves to 0
#2=#1#2 becomes empty#2 becomes 0
#2=#1+5#2 becomes 5 (empty counts as 0 in calculations)#2 becomes 5
IF[#1 EQ #0]truefalse
IF[#1 EQ 0]falsetrue
IF[#1 GT 0]falsefalse

Only EQ and NE tell empty and zero apart. All other comparisons treat empty as zero. To check that an argument was given, compare it with #0.

Variables in NC words

Most addresses accept a variable instead of a number. A minus sign in front of the # negates the value.

#24=35.5
#26=12.
G01 X#24 Z-#26 F#9
G#10 X[#24+5.]

Rules to know:

  • A calculation inside an address needs square brackets: X[#24+5.].
  • O, N and the block skip number after / cannot be variables.
  • The control rounds the value to the resolution of the address. With 0.001 mm resolution, 12.34567 becomes 12.346.
  • A variable number can be calculated: #[100+#1] is the variable whose number is 100 plus the value of #1.

Calculating

An assignment has the form #i=<expression>. Constants without a decimal point are treated as whole numbers with a decimal point, so #1=12 is the same as #1=12.0.

OperationExampleNote
Add, subtract#3=#1+#2, #3=#1-#2
Multiply, divide#3=#1*#2, #3=#1/#2Division by zero stops with an alarm
Remainder#3=#1 MOD #2Both values are rounded to whole numbers first
Sine, cosine, tangentSIN[#1], COS[#1], TAN[#1]Angle in degrees, 30’ = 0.5°
Inverse functionsASIN[#1], ACOS[#1], ATAN[#1]Result in degrees
Angle from two valuesATAN[#2]/[#1]Like ATAN2: Y value first, X value second
Square rootSQRT[#1]
Absolute valueABS[#1]
RoundROUND[#1]Nearest whole number in calculations
Cut off decimalsFIX[#1]Towards zero: 1.7 gives 1, −1.7 gives −1
Round upFUP[#1]Away from zero: 1.2 gives 2, −1.2 gives −2
Power, logarithmPOW[#1,#2], LN[#1], EXP[#1]Newer controls
Bitwise logicAND, OR, XORFor PLC signals and bit patterns

Functions are calculated first, then multiplication and division, then addition and subtraction. Square brackets change the order and can be nested up to five levels. Round brackets are comments.

#5=#1+#2*SIN[#3]       (SINE FIRST, THEN *, THEN +)
#6=[#1+#2]*SIN[#3]     (BRACKET FIRST)

Precision traps

The control calculates with binary numbers. Results that should be whole can come out a tiny bit too small. FIX then cuts off a whole unit. Two habits avoid most problems:

#3=FIX[#2+0.0001]          (SAFETY MARGIN BEFORE CUTTING OFF)
IF[ABS[#1-#2] LT 0.001] GOTO 20   (EQUAL WITHIN 0.001 MM)

Inside an NC address the control rounds to the resolution of the axis. If a program adds rounded and unrounded values, the tool can end up a few thousandths away from where it started. Round each value with ROUND before adding when exact return positions matter.

Jumps and conditions

GOTO

GOTO n continues the program at the block with sequence number Nn. The number can also come from a variable: GOTO #10.

  • The N number must stand at the start of the target block.
  • Each N number may exist only once in a program. With duplicates the jump target is undefined.
  • Jumping backwards takes longer than jumping forwards, because the control searches the program. For repetitions use WHILE.

IF with GOTO

IF[#26 LE 0] GOTO 900

If the condition is true, the program jumps to N900. Otherwise it continues with the next block.

IF with THEN

IF[#11 EQ #0] THEN #11=4

If the condition is true, the single macro statement after THEN is executed. THEN cannot be followed by a move or a list of several statements.

Comparison operators

OperatorMeaning
EQequal
NEnot equal
GTgreater than
GEgreater than or equal
LTless than
LEless than or equal

Conditions can be combined with AND, OR and XOR. Each single condition gets its own brackets:

IF[[#24 GT 0] AND [#24 LT 100]] GOTO 10

ELSE with jumps

Macro B has no ELSE. A two-way decision uses two jumps:

IF[#17 GT 3.] GOTO 10
#30=200. (FEED FOR SMALL PECK)
GOTO 20
N10 #30=140. (FEED FOR LARGE PECK)
N20 (BOTH CASES CONTINUE HERE)

WHILE loops

WHILE[<condition>] DO1
(BLOCKS TO REPEAT)
END1

While the condition is true, the blocks between DO and END repeat. When it becomes false, the program continues after END.

  • The loop number after DO and END is 1, 2 or 3. It pairs each DO with its END.
  • Loops can be nested three levels deep. The inner loop needs a different number than the outer one.
  • The same number can be used again for a later loop that does not overlap.
  • Two loops must not cross each other: the inner END must come before the outer END.
  • A GOTO may jump out of a loop, never into one.
  • DO without WHILE runs forever. This is only useful together with a GOTO that leaves the loop.
#20=0 (ROW COUNTER)
WHILE[#20 LT 3] DO1
#21=0 (COLUMN COUNTER)
WHILE[#21 LT 5] DO2
X[#21*15.] Y[#20*10.] (ACTIVE DRILL CYCLE DRILLS HERE)
#21=#21+1
END2
#20=#20+1
END1

This drills a grid of 3 rows and 5 columns with 15 mm and 10 mm spacing, using a drilling cycle that was activated before.

Calling macros

M98 or G65

M98 PxxxxG65 Pxxxx
TypeSubprogram callMacro call
ArgumentsNoYes, with letters
Local variables #1 to #33Shared with the calling programNew, empty set for each call
Other commands in the same blockAllowed, executed firstNot allowed, alarm
Single block stop at the callYesNo

Both end with M99, which returns to the block after the call.

G65 with arguments

G65 P9100 L1 X0 Y0 R40. H6. A15.

P is the program number, L the number of repetitions (default 1). All other letters are arguments. Each letter writes its value into a fixed local variable:

LetterVariableLetterVariableLetterVariable
A#1I#4T#20
B#2J#5U#21
C#3K#6V#22
D#7M#13W#23
E#8Q#17X#24
F#9R#18Y#25
H#11S#19Z#26

G, L, N, O and P cannot be used as arguments. Letters that are not given leave their variable empty. A second assignment scheme allows I, J and K up to ten times for passing several points, it is used rarely.

Always write arguments with a decimal point. Depending on the settings, X10 without a point can arrive in the macro as 0.01 or as 10, while X10. always arrives as 10.

G66 P9200 Z-8. R2. F120.
G00 X20. Y10.
X50.
X80. Y30.
G67

After G66 the macro runs after every block with an axis move, with the arguments from the G66 block. G67 ends the modal call. This is how you build your own drilling-type cycles.

Own G and M codes

Parameters can link a G or M code to a macro program. Parameters 6050 to 6059 assign G codes to programs O9010 to O9019. Parameters 6080 to 6089 assign M codes to programs O9020 to O9029. With 6050 set to 130, the block G130 X0 Y0 R40. H6. calls O9010 with these arguments, exactly like G65 P9010. Changing parameters is a job for someone who knows the machine; check with the machine builder first.

Macro calls can be nested up to four or five levels deep, depending on the control. Each level has its own set of local variables.

Protecting macro programs

Programs O9000 to O9999 can be protected against editing with bit 4 (NE9) of parameter 3202. Finished cycles are usually stored there so that nobody changes them by accident.

Macro blocks and single block

Blocks with a calculation, a jump, a loop or a macro call are macro statements. All other blocks are NC statements. In single block mode the machine stops after each NC statement, but by default it runs through macro statements without stopping. Bit 5 (SBM) of parameter 6000 makes the control stop after macro statements as well, which helps when testing a new macro step by step.

The control also reads macro statements ahead while the machine is still moving. A calculation can therefore be done before the move above it has finished. When a value from the machine must be read after a move, for example a position or a probe result, the read has to wait until the move is done. A dwell or a block that stops read-ahead in between solves this.

System variables

System variables connect the macro to the machine. The tables show the most used ones on Fanuc milling controls. Some numbers differ between control generations and between milling and turning, so check them on your machine before writing to them.

Alarms and messages

VariableUse
#3000#3000=n (TEXT) stops the program with a macro alarm and shows the text. On many controls the alarm number is 3000 plus n
#3006#3006=1 (TEXT) stops the program and shows the text as a message. Cycle start continues
IF[#18 LE 0] THEN #3000=1 (RADIUS R MUST BE POSITIVE)
#3006=1 (CHECK CLAMPING THEN CYCLE START)

The text should be short, about 26 characters fit on older screens.

Time, counters and run control

VariableUse
#3001Millisecond timer. Starts at 0 at power-on and can be set to 0 by the program
#3002Hour counter that runs while cycle start is active. Survives power-off
#3011Date as a number, for example 20261013
#3012Time as a number, for example 143005 for 14:30:05
#3003Single block and waiting for M/S/T completion on or off
#3004Feed hold, feed override and exact stop check on or off
#3901Parts counter (machined parts)
#3902Required number of parts
#3001=0
M98 P2000 (MACHINING)
#510=#3001/1000 (CYCLE TIME IN SECONDS)

#3003 and #3004 switch off operator functions such as single block or feed hold. Use them only in short sections like tapping, and switch them back on right after.

VariableContent
#4001 to #4030Active G code of each group. #4001 is group 1 (G00, G01, …), #4003 group 3 (G90 or G91), #4014 group 14 (work offset 54 to 59)
#4107Active D number
#4109Active feed F
#4111Active H number
#4119Programmed spindle speed S
#4120Active tool number T

These values are read-only. A typical use is to save a state at the start of a macro and restore it at the end:

#30=#4003 (SAVE G90 OR G91)
G91
(INCREMENTAL MOVES)
G#30 (RESTORE)

Positions

VariableContent
#5001 to #5005End point of the last block, workpiece coordinates (axes 1 to 5)
#5021 to #5025Current position in machine coordinates
#5041 to #5045Current position in workpiece coordinates
#5061 to #5065Position where the skip signal (probe) switched with G31

Axis 1 is usually X, axis 2 Y, axis 3 Z. #5003 is therefore the Z end point of the last block.

Work offsets

VariableOffset
#5201 to #5205External (common) offset
#5221 to #5225G54
#5241 to #5245G55
#5261 to #5265G56
#5281 to #5285G57
#5301 to #5305G58
#5321 to #5325G59
#7001 to #7005G54.1 P1
#7021 to #7025G54.1 P2, and so on in steps of 20

Each offset starts 20 numbers after the previous one. More on this topic, including a calculated address for G54 to G59, is on the page Fanuc work offset parameters.

Tool offsets

The variable numbers depend on the offset memory type of the control. On most machining centers with separate values for length and radius and for geometry and wear (memory type C):

VariablesContent
#11001 and upLength geometry (H)
#10001 and upLength wear (H)
#13001 and upRadius geometry (D)
#12001 and upRadius wear (D)

The last digits are the offset number: #11005 is the length geometry of H5. Controls with up to 200 offsets also accept the older numbers starting at #2001.

#1=#4120 (ACTIVE TOOL)
#2=#[11000+#1] (ITS LENGTH, IF H NUMBER = T NUMBER)
IF[#2 GT 50.] GOTO 10
#3000=2 (TOOL LENGTH TOO SHORT)
N10

Example: bolt circle cycle with input check

The macro drills a bolt circle with the drilling cycle that is active when it is called. It checks the inputs first and leaves the machine in the same state it found it.

O1000 (MAIN PROGRAM)
G90 G54 G17
T5 M06
G43 H5 Z50.
S1800 M03
G98 G81 Z-12. R2. F160 K0 (STORE CYCLE, NO HOLE)
G65 P9100 X60. Y40. R35. H8. A22.5
G65 P9100 X160. Y40. R20. H4.
G80
G28 G91 Z0
M30
O9100 (BOLT CIRCLE)
(X=#24 Y=#25 CENTER, R=#18 RADIUS)
(H=#11 HOLES, A=#1 START ANGLE)
IF[#24 EQ #0] GOTO 900
IF[#25 EQ #0] GOTO 900
IF[#18 LE 0] GOTO 910
IF[#11 LT 1] GOTO 920
IF[#1 EQ #0] THEN #1=0
#30=#4003 (SAVE G90/G91)
#10=360./#11 (ANGLE STEP)
#12=0 (COUNTER)
G90
WHILE[#12 LT #11] DO1
#13=#1+#12*#10
X[#24+#18*COS[#13]] Y[#25+#18*SIN[#13]]
#12=#12+1
END1
G#30 (RESTORE G90/G91)
M99
N900 #3000=1 (CENTER X Y MISSING)
N910 #3000=2 (RADIUS R MISSING)
N920 #3000=3 (HOLES H MISSING)

What happens:

  • The first checks stop the program with a clear alarm if an argument is missing. An empty H also stops at N920, because empty counts as 0 in the LT comparison.
  • A missing start angle is not an error, it is set to 0.
  • The macro saves G90 or G91, switches to absolute and restores the old state at the end.
  • Each X/Y block triggers the drilling cycle that is still active from the main program.
  • The alarm blocks sit after M99 and are only reached by the jumps.

Tips for the shop

  • Keep a list of every common variable you use and what it means. Write the meaning as a comment in the program where the variable is set.
  • Use the retained range #500 and up only for values that must survive power-off, and back them up with the other machine data.
  • Check all arguments at the start of a macro. A clear alarm costs nothing, a wrong position costs a part or a spindle.
  • Test new macros with the feed override at a low value and with single block, and with parameter 6000 bit 5 set if you need to stop at macro blocks.
  • Write arguments and constants with a decimal point.
  • Store finished cycles in the O9000 range and protect them.

A practical application of Macro B with system variables and a little geometry is shown in Building your own tilt cycle.