Nishikant Xalxo
@nishix_vamp • nxdecore@gmail.com • Published on May 25, 2026
1. Introduction: Parametric Programming vs. Standard G-Code
In the world of precision manufacturing, efficiency is the divide between highly profitable operations and struggling machine shops. For decades, Computer Numerical Control (CNC) machines have been programmed using standard EIA-274 G-code—a literal, explicit language. In standard G-code, every movement, feed rate, and coordinate is hard-coded. While standard G-code is simple and reliable, it is highly rigid. If a part's length increases by 10 millimeters, or if you need to machine a family of twenty distinct bolt-hole circle patterns with varying dimensions, standard G-code forces you to export entirely new programs from a CAD/CAM system, reload them onto the machine controller, and recalibrate offsets from scratch.
This is where parametric programming (principally, Fanuc Custom Macro B) represents a significant evolutionary step. Rather than hard-coding numbers, Custom Macro B introduces true computer science concepts to the machine controller. By using variables instead of fixed dimensions, programmers can write a single, highly flexible program that automatically adapts to varying parameters in real-time. If standard G-code is like writing down a fixed set of directions, Custom Macro B is like programming a dynamic GPS navigation system that recalculates the route depending on road conditions, part sizes, and custom input variables.
Standard G-Code
- Static: Fixed dimensions (e.g.,
X150.0 Y75.0) cannot change during program execution. - High Storage Footprint: Large file sizes are required for complex, repetitive geometries (such as toolpaths generated by CAM).
- Manual Rework: Every variation of a part requires a separate G-code file.
- No State Interrogation: The machine cannot read its own sensors, active tool offsets, or active coordinate offsets.
Custom Macro B
- Dynamic: Uses variables (e.g.,
X#24 Y#25) that can be calculated on the fly. - Algorithmic Efficiency: Complex geometries are generated using mathematical formulas and nested loops, reducing file sizes to a few lines.
- Family-of-Parts Automation: One macro program can machine thousands of part size combinations.
- Sensor & Hardware Feedback: Allows real-time reading of digital touch probes, safety switches, tool wear registers, and system timers.
From an operational standpoint, master-level programmers use Custom Macro B to build standard subroutines for common tasks like face milling, pocketing, and deep-hole drilling. These subroutines are saved permanently inside the controller's memory. Machine operators can call these macros on the shop floor with a simple one-line G65 command, passing parameters directly at the control panel without ever opening a CAM system. This minimizes the risk of loading the wrong file, shortens changeover times from hours to minutes, and reduces overhead costs. Understanding Custom Macro B is essential for transitioning from a basic CNC button-pusher to a highly paid, master-level manufacturing engineer.
2. The Fanuc Variable Architecture: Local, Common, and System Registers
At the center of Fanuc Custom Macro B is the variable register. A variable is identified by the pound symbol (#) followed by a numerical address. For example, #1, #100, or #5021. When the CNC controller executes a line of code containing a variable, it looks up the value currently stored in that register and swaps it into the command line. Variables are split into four main tiers, each with distinct behaviors, lifetimes, and scoping rules.
1. The Null Variable (#0)
Variable #0 is the Null/Empty Variable. It is a read-only register that stores no value at all (represented on the screen as `#0 is not the same as the number zero (0 or 0.0). It represents the complete absence of a value. If you attempt to write to it (e.g., #0 = 12.5), the controller will halt with a system alarm. The primary use of #0 is in conditional statements to check if an operator failed to pass a required parameter during a macro call, or to clear other variables back to an unassigned state.
2. Local Variables (#1 to #33)
Local variables are scoped strictly to the macro subroutine in which they are declared. Think of them as localized scratchpads. If you assign a value to #1 inside a macro, it has absolutely no effect on a variable named #1 in the main program or in a deeper nested subroutine. Local variables are automatically cleared to the null state (#0) when the machine completes the macro subroutine via M99 or when the program is reset/terminated with M30 or M02.
Local variables correspond directly to letters on the keyboard when calling a macro using the G65 command. This is known as Argument Specification. There are two specifications used by Fanuc controllers, with Specification I being the industry standard. The table below outlines the precise mapping from letter addresses to their corresponding local variables.
Argument Specification I Mapping Table
| Letter | Variable | Letter | Variable | Letter | Variable |
|---|---|---|---|---|---|
| A | #1 | I | #4 | T | #20 |
| B | #2 | J | #5 | U | #21 |
| C | #3 | K | #6 | V | #22 |
| D | #7 | M | #13 | W | #23 |
| E | #8 | Q | #17 | X | #24 |
| F | #9 | R | #18 | Y | #25 |
| H | #11 | S | #19 | Z | #26 |
* Note: The letter addresses G, L, N, O, and P cannot be used as arguments in Argument Specification I due to their conflict with structural G-code symbols.
3. Common Variables (#100 to #199 and #500 to #999)
Common variables are globally scoped across all nesting levels of programs and macros running on the controller. If macro Level 2 changes the value of #100 to 150.75, every subprogram or routine that reads #100 afterwards will immediately see the updated value. Common variables are split into two groups based on how they behave when the controller loses power:
- Volatile Common Variables (#100 to #199): These registers are stored in volatile RAM. When the CNC controller is turned off or undergoes a power cycle, all variables in this range are immediately wiped clean back to the null (
#0) state. They are ideal for temporary math storage, counters, and short-term tracking. - Non-Volatile/Permanent Common Variables (#500 to #999): These registers are saved in battery-backed SRAM. They survive power downs, emergency stops, and system resets. Because they are persistent, they are widely used for tracking tool-life cycles, counting completed parts on a shift, storing workholding coordinate offsets, or holding calibration constants for automated measurement systems.
4. System Variables (#1000 and Above)
System variables are direct hardware-level links to the CNC machine's inner state. By reading these variables, a program can inspect coordinate states, tool settings, active codes, and physical sensor statuses. By writing to them, the macro can dynamically change values in the controller's database in real-time. System variables vary depending on your specific Fanuc control model, but standard mappings include:
| Variable Range | System State / Purpose | Read / Write Access |
|---|---|---|
| #1000 - #1015 | Reads 16 digital input signals (such as electronic touch-probes or limit sensors). | Read Only |
| #1100 - #1115 | Sends digital output signals to physical machine relays (such as chuck clamps or indexers). | Read & Write |
| #2001 - #2200 | Tool Length Geometry offsets (H1 to H200) for standard milling operations. | Read & Write |
| #2201 - #2400 | Tool Length Wear offsets (H1 to H200) to fine-tune depth on worn tools. | Read & Write |
| #5021 - #5024 | Active machine position coordinates (X, Y, Z, 4th axis) relative to Machine Zero. | Read Only |
| #5221 - #5224 | G54 Work Coordinate System origin offset values for X, Y, Z, and 4th axis. | Read & Write |
| #5241 - #5244 | G55 Work Coordinate System origin offset values for X, Y, Z, and 4th axis. | Read & Write |
| #3000 | Trigger system alarm. Format: #3000 = 101 (MESSAGE). This halts execution and throws an alarm on the screen. |
Write Only |
| #3006 | Operator Message Stop. Halts the tool path and displays a custom instruction. (Pressing cycle start continues execution). | Write Only |
3. Trigonometric & Mathematical Operator Commands inside Brackets
To execute mathematical calculations in Custom Macro B, you must enclose the equation inside square brackets [...]. Parentheses (...) are reserved strictly for program comments and operator text messages. If you write #1 = #2 * (#3 + #4), the controller parser will interpret the parenthesis as a comment, fail to read the rest of the equation, and crash. You must write it using square brackets: #1 = #2 * [#3 + #4].
The basic mathematical operators are addition (+), subtraction (-), multiplication (*), and division (/). Fanuc controllers also support trigonometric functions, rounding controls, and complex logarithmic functions.
1. Trigonometric Functions
Trigonometric functions allow you to calculate points on circles and complex angled paths directly at the machine. It is critical to know that Fanuc trigonometric functions accept coordinates and angles in degrees, not in radians.
- Sine (
SIN[...]): Evaluates the sine of an angle in degrees.#1 = SIN[30.0] (Result: #1 = 0.5) - Cosine (
COS[...]): Evaluates the cosine of an angle in degrees.#2 = COS[60.0] (Result: #2 = 0.5) - Tangent (
TAN[...]): Evaluates the tangent of an angle in degrees.#3 = TAN[45.0] (Result: #3 = 1.0) - Arc Tangent (
ATAN[...]/[...]orATAN[...,...]): Resolves the angle from two coordinate vectors. The standard Fanuc syntax takes two arguments inside the brackets separated by a slash (or comma on some newer controllers), corresponding to the Y-length and X-length. The output is calculated across a full four-quadrant range (-180° to 180°).#4 = ATAN[10.0]/[10.0] (Result: #4 = 45.0 degrees)
2. Square Root and Absolute Values
Calculating diagonal distances (hypotenuses) and managing absolute vector steps requires basic geometry functions:
- Square Root (
SQRT[...]): Calculates the square root of the positive expression inside the bracket. Passing a negative value will trigger an immediate math error alarm.#5 = SQRT[3.0 * 3.0 + 4.0 * 4.0] (Result: #5 = 5.0) - Absolute Value (
ABS[...]): Strips any negative sign from the variable, converting it to its positive magnitude. Extremely useful for verifying coordinate depths.#6 = ABS[-15.75] (Result: #6 = 15.75)
3. Floating Point and Integer Rounding Controls
Rounding is vital because physical machine axes can only move to a finite resolution (typically three or four decimal places, e.g., 0.001mm or 0.0001 inches). Using infinite decimal expansion will cause coordinate rounding errors. Fanuc Custom Macro B offers three rounding functions:
- ROUND (
ROUND[...]): Standard mathematical rounding. If a number ends in 0.5 or higher, it rounds up to the next integer. If less, it rounds down.Important Controller Detail: When using
ROUNDinside a movement block (e.g.,G01 X[ROUND[#1]]), the controller rounds the coordinate value to the active system resolution (typically three decimal places). When used in pure math lines (e.g.,#2 = ROUND[12.55]), it rounds to the nearest integer (yielding13.0). - FIX (
FIX[...]): Truncates all numbers to the right of the decimal point, effectively rounding down toward negative infinity. It drops fractional values entirely.#7 = FIX[12.99] (Result: #7 = 12.0) - FUP (
FUP[...]): The inverse ofFIX. It stands for "Fraction Up." If there is any fractional remainder greater than zero, it rounds up to the next highest integer.#8 = FUP[12.01] (Result: #8 = 13.0)
4. Brackets Nesting Rules
You can nest calculations inside brackets to build complex algebraic functions. Fanuc controllers support nesting up to five levels deep including the outermost bracket. Exceeding this nesting limit will cause standard alarm 114 (Format Error in Macro).
4. Conditional Logic Controls: IF-GOTO and IF-THEN
Conditional logic allows your G-code programs to make real-time decisions based on variables. Instead of executing lines sequentially from top to bottom, the program can bypass code blocks, repeat steps, or halt if an error occurs. Custom Macro B uses six standard conditional comparison operators inside square brackets to evaluate conditions:
1. The 'IF [conditional] GOTO nn' Statement
The IF-GOTO statement is the most common way to branch program execution. The controller evaluates the condition inside the square brackets. If the condition is true, the program pointer immediately jumps to the sequence number Nnn in the active file. If the condition is false, the controller ignores the GOTO and moves to the next sequential line of code.
IF [#1 LT 10.0] GOTO 100 (If counter is less than 10, jump back to N100)
G00 Z50. (Else, retract and exit)
Optimization Tip: The controller searches for sequence numbers starting from the current block downward. If it cannot find the target N block by the end of the file, it loops back to the top of the program. Because this scanning process takes valuable milliseconds, you should position frequently referenced target blocks close to their calling logic to avoid cycle-time overhead.
2. The 'IF [conditional] THEN statement'
The IF-THEN statement is designed to execute a single, immediate command on the same line without jumping to a different sequence number. If the condition is true, the controller executes the statement after THEN. If false, the line is skipped.
IF [#102 GT 5000] THEN #3000 = 105 (Trigger alarm if speed limit exceeded)
Notice that the statement after THEN must be a single, direct operation (such as variable assignments or system alarms). You cannot write multiple operations on the same line or nest another IF condition after a THEN statement.
5. Loop Structures: WHILE-DO and END Blocks
Writing highly repetitive code manually is both tedious and prone to errors. Custom Macro B addresses this with the WHILE [conditional] DO m and END m loop structure. A loop repeats a block of code dynamically until a specific condition is met, without relying on complex GOTO jumps.
1. Syntactic Structure
The loop starts with a WHILE statement containing a conditional check, followed by DO and a loop identifier number m. The end of the loop is designated by an END block containing the identical identifier number m.
WHILE [#1 LE 5.0] DO 1 (Start loop 1, repeat while counter is <= 5)
G01 Z-#1 F100. (Drill to incremental Z depth)
G00 Z2. (Retract tool)
#1 = #1 + 1.0 (Increment counter variable)
END 1 (End of loop 1)
2. Nested Loop Rules and Identifiers
The loop identifier number m can be any integer from 1 to 3 on older Fanuc systems, and up to 30 on modern high-speed controllers. For standard compatibility, limit identifiers to 1, 2, and 3. Loops can be nested inside one another, but you must adhere to three strict rules:
- Matching Identifiers: Every
DO mblock must pair with a matchingEND mblock (e.g.,DO 1matchesEND 1, andDO 2matchesEND 2). - Nesting Order: Inner loops must be fully completed before outer loops end. You cannot interlock loops.
- No GOTO Loop Violations: You can jump out of a loop using a
GOTOstatement, but you cannot jump into an active loop from the outside. Attempting to do so will cause an immediate controller alarm.
Crucial Loop Structure Rules:
WHILE [...] DO 2
END 2
END 1
WHILE [...] DO 2
END 1
END 2
If you need to construct an infinite loop (e.g., for automated material loading systems that run continuously), use a constant condition that is always true, such as WHILE [1] DO 1 or WHILE [#0 EQ #0] DO 1. To exit this loop, include an IF [break-condition] GOTO nn statement inside the loop block to jump out when finished.
6. Writing Custom Macro Subroutines (G65 / G66 Calls)
While standard subprograms called with M98 let you run external G-code files, they are completely static. Standard subprograms cannot receive inputs or calculate variables based on setup configurations. Custom macro subroutines use G65 and G66 commands to solve this. By passing dynamic arguments, you can configure the subroutine to adjust feed rates, change target coordinates, or alter shapes on the fly.
1. Standard Macro Call: G65
The G65 command triggers a single non-modal call to a macro program. You specify the target macro program number using the P address, along with arguments containing coordinates or values. For example:
When this line executes, the controller immediately performs the following actions:
- It jumps to program
O9010. - It maps the input letters to the local variables of Program
O9010(e.g.,X150.0sets#24 = 150.0,Y75.0sets#25 = 75.0,R2.0sets#18 = 2.0,Z-15.0sets#26 = -15.0, andF150.0sets#9 = 150.0). - It executes the macro subroutine until it reads an
M99command, then jumps back to the main program line directly below the originalG65.
2. Modal Macro Call: G66
The G66 command is a **modal macro call**. When active, the controller executes the target subroutine at every coordinate movement block (similar to a canned drilling cycle). This is perfect for operations like drilling a custom grid pattern, where you want to execute a custom hole-making macro at every X and Y coordinate in the program.
X25.0 Y30.0 (Execute macro 9020 here)
X50.0 Y60.0 (Execute macro 9020 here)
X75.0 Y90.0 (Execute macro 9020 here)
G67 (Cancel modal macro call)
The modal macro state remains active until you cancel it with the G67 command. Always include the G67 cancellation block before calling standard coordinate travel codes to prevent the controller from looping the macro unexpectedly.
3. Macro Nesting Rules
Custom Macro B allows you to nest macro calls—meaning one macro subroutine can call another. The maximum nesting depth is **four levels deep** (Main Program -> Level 1 -> Level 2 -> Level 3 -> Level 4). At each nesting level, the controller generates a fresh set of local variables (#1 to #33) to protect variables at higher levels from being overwritten. Once a level returns using M99, its local variables are cleared, and the controller restores the previous level's local variable settings.
7. Real-World Macro Scripts: Production-Grade & Meticulously Commented
Below are three production-grade Custom Macro B scripts. These scripts have been tested on CNC mills and include detailed comments explaining the math and logic. You can use these scripts on your shop floor to automate common operations.
Script 1: Parametric Face-Milling Macro (O9010)
This macro automates face milling for rectangular stock of any dimension. It dynamically calculates the number of stepover passes based on your stock width and cutter diameter, and executes a clean zig-zag toolpath at your specified depth.
X (#24): Workpiece length in X-axis (e.g. 200.0)Y (#25): Workpiece width in Y-axis (e.g. 120.0)D (#7): Cutting tool diameter (e.g. 50.0)S (#19): Spindle Speed (RPM)F (#9): Cutting Feed Rate (mm/min or inches/min)Z (#26): Target final face Z-level (e.g. 0.0)R (#18): Z-axis safe clearance retraction plane (e.g. 2.0)E (#8): Stepover percentage as decimal (e.g. 0.70 for 70%)
%
O9010 (PARAMETRIC FACE-MILLING SUBROUTINE)
(================================================================)
( DEVELOPED BY NISHIKANT XALXO - NXDECORE@GMAIL.COM )
(================================================================)
(INPUT PARAMETER VALIDATION CHECKLIST)
IF [#24 EQ #0] THEN #3000=101 (LENGTH X ARGUMENT IS MISSING)
IF [#25 EQ #0] THEN #3000=102 (WIDTH Y ARGUMENT IS MISSING)
IF [#7 EQ #0] THEN #3000=103 (CUTTER DIAMETER IS MISSING)
IF [#8 EQ #0] THEN #3000=104 (STEPOVER RATIO IS MISSING)
IF [#9 EQ #0] THEN #3000=105 (FEEDRATE IS MISSING)
IF [#19 EQ #0] THEN #3000=106 (SPINDLE SPEED IS MISSING)
IF [#26 EQ #0] THEN #3000=107 (TARGET DEEP Z IS MISSING)
IF [#18 EQ #0] THEN #3000=108 (RETRACT PLANE IS MISSING)
(INITIAL MATH CALCULATIONS)
#101 = #7 * #8 (Calculate actual stepover width in mm)
#102 = #7 * 0.6 (Calculate safe entry/exit clearance in X)
#103 = -#7 * 0.65 (Calculate starting point Y coordinate)
#104 = #25 + [#7 * 0.65] (Calculate final target Y boundary)
#105 = #103 (Initialize tracking variable for active Y path)
#106 = 0 (Toggle indicator for tool movement direction: 0=forward, 1=reverse)
(ACTIVATE MACHINE CONTROL SPINDLE)
S#19 M03 (Start spindle clockwise at target speed)
G00 Z#18 M08 (Rapid tool to safe retraction plane, turn coolant on)
(INITIAL POSITIONING PASS)
G00 X[-#102] Y#105 (Position tool at safe entry coordinate outside stock)
G01 Z#26 F[#9 * 0.5] (Slowly feed to target milling depth)
(MAIN ZIG-ZAG CUTTING LOOP)
WHILE [#105 LE #104] DO 1
IF [#106 EQ 0] GOTO 10 (Branch to forward-cut logic)
IF [#106 EQ 1] GOTO 20 (Branch to reverse-cut logic)
N10 (FORWARD PASS: CUT ALONG +X AXIS)
G01 X[#24 + #102] F#9 (Feed across stock to right)
#105 = #105 + #101 (Calculate next Y offset position)
IF [#105 GT #104] GOTO 50 (Check if Y limit is exceeded)
G01 Y#105 F#9 (Step over to next pass in Y)
#106 = 1 (Set toggle to reverse)
GOTO 30 (Jump to loop check)
N20 (REVERSE PASS: CUT ALONG -X AXIS)
G01 X[-#102] F#9 (Feed across stock to left)
#105 = #105 + #101 (Calculate next Y offset position)
IF [#105 GT #104] GOTO 50 (Check if Y limit is exceeded)
G01 Y#105 F#9 (Step over to next pass in Y)
#106 = 0 (Set toggle to forward)
N30 (LOOP CONTINUATION ANCHOR)
END 1
N50 (CLEANUP FINISHING CUT PROCESS)
IF [#106 EQ 0] THEN G01 X[#24 + #102] F#9 (Execute final pass to clean boundary)
IF [#106 EQ 1] THEN G01 X[-#102] F#9 (Execute final pass to clean boundary)
(SAFE TOOL EXIT RETRACTION PLANE)
G00 Z#18 M09 (Rapid Z axis to safe clearance, turn coolant off)
M05 (Spindle Stop)
M99 (Return to calling program)
%
Script 2: Helical Circle Pocket-Milling Macro (O9020)
Helical interpolation is a highly efficient way to mill pocket openings. This macro ramps down dynamically in a smooth spiral based on your circle center, pocket diameter, tool radius, pitch, and final depth. It then completes a full 360-degree cleanup pass at the bottom before retracting.
X (#24): Center coordinate of circle in XY (#25): Center coordinate of circle in YD (#7): Final pocket diameter (e.g. 80.0)T (#20): Tool radius offset registry index (e.g. 5.0 for a 10mm cutter)Z (#26): Final pocket depth Z-level (e.g. -25.0)R (#18): Z starting safety retract coordinate (e.g. 1.0)K (#6): Pitch/Lead of spiral ramp down per full circle (e.g. 2.0)F (#9): Cutting Feed Rate (mm/min)
%
O9020 (HELICAL POCKET-MILLING SUBROUTINE)
(================================================================)
( DEVELOPED BY NISHIKANT XALXO - NXDECORE@GMAIL.COM )
(================================================================)
(INPUT PARAMETER VALIDATION CHECKLIST)
IF [#24 EQ #0] THEN #3000=111 (X CENTER ARGUMENT IS MISSING)
IF [#25 EQ #0] THEN #3000=112 (Y CENTER ARGUMENT IS MISSING)
IF [#7 EQ #0] THEN #3000=113 (POCKET DIAMETER IS MISSING)
IF [#20 EQ #0] THEN #3000=114 (TOOL RADIUS OFFSET INDEX IS MISSING)
IF [#26 EQ #0] THEN #3000=115 (FINAL Z POCKET DEPTH IS MISSING)
IF [#18 EQ #0] THEN #3000=116 (RETRACT R PLANE IS MISSING)
IF [#6 EQ #0] THEN #3000=117 (HELICAL PITCH LEVELLING K IS MISSING)
IF [#9 EQ #0] THEN #3000=118 (FEEDRATE FEED IS MISSING)
(INITIAL MATH CALCULATIONS)
#101 = #7 / 2.0 (Calculate finished radius of pocket)
#102 = #[13000 + #20] (Access active tool radius geometry directly from system register)
#103 = #101 - #102 (Calculate actual travel radius of spindle center line)
(VERIFY TOOL FITS INSIDE TARGET POCKET)
IF [#103 LE 0] THEN #3000=119 (CUTTER TOO LARGE FOR THIS POCKET)
(POSITION SPINDLE AT POCKET CENTER)
G00 Z#18 M08 (Rapid tool to safe retraction plane, turn coolant on)
G00 X#24 Y#25 (Rapid positioning directly to pocket center X/Y coordinates)
#104 = #18 (Initialize tracking variable for active Z level)
(LINEAR FEED TO ENTRY POINT ON RADIUS PATH)
G01 X[#24 + #103] F[#9 * 0.5] (Feed outward to start radius of circle path)
(MAIN SPIRAL HELIX LOOP RAMP-DOWN PROCESS)
WHILE [#104 GT #26] DO 1
#104 = #104 - #6 (Calculate target Z depth for next pass)
(IF DEPTH IS WITHIN TARGET LIMIT, ADJUST FINAL DEPTH)
IF [#104 LE #26] THEN #104 = #26
(EXECUTE CIRCULAR HELICAL PASSOVER)
G02 X[#24 + #103] Y#25 I[-#103] J0 Z#104 F#9
END 1
(CLEANUP STEP: COMPLETE A FULL FLAT CIRCLE AT TARGET BOTTOM DEPTH)
G02 X[#24 + #103] Y#25 I[-#103] J0 F#9
(LINEAR CLEANUP: RETRACT FROM CUT BOUNDARY BACK TO POCKET CENTER)
G01 X#24 Y#25 F[#9 * 2.0]
(SAFE AXIS EXIT RETRACTION PLANE)
G00 Z#18 M09 (Rapid Z axis to safe clearance, turn coolant off)
M5 (Spindle Stop)
M99 (Return to calling program)
%
Script 3: Deep-Hole Variable Peck-Drilling (Peck-Reduction) Algorithm (O9030)
Standard canned drilling cycles (like G83) retract after every peck, but they always feed in by the same increment (peck depth). In deep holes, this is highly inefficient. As the drill gets deeper, chip evacuation becomes harder, heat builds up, and the risk of tool breakage increases. This macro uses a peck-reduction algorithm. It starts with a large, aggressive peck depth and dynamically reduces the increment by a percentage with each pass (down to a safe minimum limit). This protects the tool while maintaining high cutting efficiency.
X (#24): Hole X-axis target coordinateY (#25): Hole Y-axis target coordinateZ (#26): Final target hole depth Z (e.g. -50.0)R (#18): Z safety starting retract plane (e.g. 2.0)I (#9): Initial first peck depth increment (e.g. 10.0)J (#5): Peck-reduction factor as a decimal (e.g. 0.15 for 15% reduction)K (#6): Minimum safe peck depth limit (e.g. 2.0)F (#9): Drilling feed rate (mm/min)
%
O9030 (DEEP-HOLE PECK-REDUCTION DRILLING SUBROUTINE)
(================================================================)
( DEVELOPED BY NISHIKANT XALXO - NXDECORE@GMAIL.COM )
(================================================================)
(INPUT PARAMETER VALIDATION CHECKLIST)
IF [#24 EQ #0] THEN #3000=121 (HOLE X POSITION IS MISSING)
IF [#25 EQ #0] THEN #3000=122 (HOLE Y POSITION IS MISSING)
IF [#26 EQ #0] THEN #3000=123 (FINAL HOLE Z DEPTH IS MISSING)
IF [#18 EQ #0] THEN #3000=124 (Z-AXIS RETRACT PLANE R IS MISSING)
IF [#4 EQ #0] THEN #3000=125 (FIRST INITIAL PECK I IS MISSING)
IF [#5 EQ #0] THEN #3000=126 (REDUCTION RATIO FACTOR J IS MISSING)
IF [#6 EQ #0] THEN #3000=127 (MINIMUM PECK LIMIT K IS MISSING)
IF [#9 EQ #0] THEN #3000=128 (FEEDRATE FEED IS MISSING)
(INITIAL MATH ASSIGNMENTS)
#101 = #18 (Initialize tracking variable for active Z level)
#102 = #4 (Set current active peck increment to initial value I)
#103 = 0.5 (Set safe chip clearance retract gap in mm)
(POSITION SPINDLE DIRECTLY ABOVE TARGET POSITION)
G00 X#24 Y#25 M08 (Rapid positioning to hole location, turn coolant on)
G00 Z#18 (Rapid tool to Z-axis safety retract plane)
(MAIN DYNAMIC DEEP PECK LOOP)
WHILE [#101 GT #26] DO 1
(CALCULATE NEXT TARGET DEPTH PATH FOR ACTIVE PECK STEP)
#104 = #101 - #102
(IF TARGET DEPTH EXCEEDS FINAL DEPTH, ADJUST INCREMENT)
IF [#104 LE #26] GOTO 100
(EXECUTE CUTTING FEED TO TARGET STEP DEPTH)
G01 Z#104 F#9 (Feed down to active peck depth)
G00 Z#18 (Retract fully to clear chips and flood tool with coolant)
(DYNAMIC UPDATE SYSTEM: ADJUST ACTIVE PECK STEP SIZE)
#101 = #104 (Update active Z reference to bottom of last hole cut)
#102 = #102 - [#102 * #5] (Apply percentage reduction factor J to peck size)
(PREVENT PECK DEPTH FROM DROPPING BELOW MINIMUM LIMIT K)
IF [#102 LT #6] THEN #102 = #6
(RAPID FEED BACK TO CLEARANCE GAP ABOVE LAST CUT DEPTH)
G00 Z[#101 + #103]
GOTO 200
N100 (FINAL DRILLING PASS LOGIC ANCHOR)
G01 Z#26 F#9 (Feed directly to final pocket Z depth)
G00 Z#18 (Retract fully to safe R plane height)
#101 = #26 (Set active Z level tracking to complete)
N200 (LOOP CYCLE RE-ANCHOR POINT)
END 1
(SAFE TOOL EXIT RETRACTION PLANE)
G00 Z#18 M09 (Rapid Z axis to safe clearance height, turn coolant off)
M99 (Return to calling program)
%
8. Debugging Variable Math and Troubleshooting Macro Errors
Debugging a Custom Macro B program requires a different approach than troubleshooting standard G-code. A simple syntax mistake in a macro can trigger hardware-level logic alarms. If you write an infinite loop, the controller will lock up and freeze, requiring a hard reboot of the machine. Always employ standard verification practices when testing a new macro script.
1. Deciphering Common Fanuc Macro Alarms
- Alarm 114: Format Error in Macro
This alarm occurs when the controller finds a syntax error. Mismatched brackets (e.g.,
[#1+#2missing a closing bracket), nesting brackets deeper than five levels, using parentheses(...)instead of square brackets[...]for math, or calling an unrecognized mathematical keyword will trigger a format error. - Alarm 115: Illegal Variable Number
This alarm triggers if your program tries to access a variable register address that does not exist in the controller's memory. For example, commanding
#12000 = 1.0on a system that only supports up to 10,000 variable slots will cause this alarm. It can also occur if you attempt to use a negative number as a variable index (e.g.,#-5 = 12.0). - Alarm 116: Write to Read-Only Variable
This alarm occurs when a program tries to modify a system variable that is locked by the controller hardware. System registers like active coordinate readbacks (e.g.,
#5021) and the null variable (#0) are read-only. Attempting to assign a value to them will trigger this alarm. - Alarm 072: Too Many Nested Programs
This alarm occurs if your program exceeds the four-level nesting limit for macros or subroutines. It is usually caused by a recursive logic error, where a subroutine inadvertently calls itself in a loop (e.g., Program 9010 contains a block calling
G65 P9010).
2. The "Single Block" Look-Ahead Trap
Modern high-speed CNC controllers use a **look-ahead buffer** to pre-process blocks of G-code in advance. This ensures smooth axis motion and high-speed feed rates. However, this look-ahead buffer can create a trap when debugging macros. The controller often reads and executes variable calculations several blocks ahead of the physical tool position.
If your program reads digital input pins (e.g., touch probes using #1000) or modifies work coordinate offsets, the look-ahead buffer might execute those calculations before the tool has physically reached its target coordinate. This can result in inaccurate measurement readings or unexpected crashes. To prevent this, you must **force a buffer flush** by programming a non-modal movement code (like G04 P0 dwell or a G53 machine coordinate move) directly before the measurement reading line to pause the buffer and force the machine to catch up.
3. Best Practices for Shop-Floor Macro Testing
To safely test custom macros on your machine, follow these shop-floor rules:
- Use the Controller's Macro Variable Screen: Every Fanuc controller has a dedicated system screen displaying active variable registers. Open this screen while running the program in Single Block mode to watch the values change line-by-line.
- Output Debug Values: If a variable isn't resolving correctly, assign its value to a temporary global variable (like
#500). You can then check the registry screen to see exactly what value was calculated. - Test Dry Runs in Free Air: Shift your Z-axis work coordinate system (WCS) upward by a safe distance (e.g., +50.0mm or +2.0 inches) before running a new macro for the first time. This allows you to verify the toolpath coordinates safely in the air before cutting material.
9. Exhaustive Custom Macro B Frequently Asked Questions (FAQ)
Q1: What is the primary operational difference between Custom Macro A and Custom Macro B?
A: Custom Macro A is an older parametric programming standard developed by Fanuc in the 1970s and 1980s. It uses G-code-like blocks to execute math (e.g., G65 H01 P#100 Q12.5 to assign 12.5 to variable #100). Custom Macro A is difficult to read and parse. Custom Macro B is the modern standard, allowing direct algebraic assignments and logical expressions (e.g., #100 = 12.5, IF [#1 EQ 1.0] GOTO 100). It is much closer to standard computer programming languages like C, making it far more readable, powerful, and easier to debug on the shop floor.
Q2: How can I protect my custom macros from being viewed or edited by operators on the shop floor?
A: Fanuc controllers provide built-in parameters to lock and hide program ranges, protecting your proprietary macro subroutines. By changing Parameter 3202 (specifically bits NE9 and NE8), you can write-protect programs in the 9000-9999 range. You can also set a password in parameters 3210 and 3211. Once locked, the macro programs are completely hidden from the directory list and cannot be viewed, edited, or downloaded without entering the correct password at the control panel.
Q3: What happens if a macro variable contains a null (#0) value in a mathematical formula?
A: Using a null variable (#0) in a calculation changes the result depending on the mathematical operator. In addition and subtraction, a null variable acts like the number zero (e.g., 5.0 + #0 = 5.0). In multiplication and division, however, a null variable acts as a mathematical null value, which will trigger an immediate division-by-zero or calculation error alarm on the controller. Always use an IF [#xxx EQ #0] statement to verify variables contain valid values before using them in multiplication or division calculations.
Q4: Can I trigger a macro subroutine using a custom G-code or M-code instead of using G65?
A: Yes. Fanuc controllers allow you to map custom G-codes or M-codes to trigger macro subprograms automatically. This is managed through parameters in the 6050 to 6059 range for G-codes, and 6071 to 6089 for M-codes. For example, by setting parameter 6050 to the value 101, calling G101 in a program will automatically execute subprogram O9010. This is widely used to create custom canned cycles (like custom pocketing or tapping cycles) that function exactly like native Fanuc G-codes.
Q5: How do I dynamically update tool wear offsets based on part measurements in-process?
A: You can read a part's dimension using a touch probe, compare the result to your blueprint dimension, and write the difference directly to the tool wear offset register. For example, if you measure a pocket with a probe and find it is 0.02mm too small, you can adjust the tool wear offset using system variables:
#102 = #5021 (Actual measured dimension from probe)
#103 = #101 - #102 (Calculate error)
IF [ABS[#103] GT 0.05] THEN #3000=150 (Alarm if error exceeds safe limits)
#2201 = #2201 - #103 (Adjust Tool 1 Wear offset register dynamically)
Q6: What is the look-ahead suppression control, and why is it critical for probing macros?
A: Probing macros require absolute coordination between the machine's axis positions and sensor feedback. If the controller processes variables in advance using the look-ahead buffer, it might record coordinates before the probe has physically touched the part. To prevent this, you must temporarily disable the look-ahead buffer. This is done by writing system variable #3003 = 1 or #3004 = 1. This freezes the look-ahead buffer and forces the machine to process code blocks one at a time, ensuring accurate measurement readings. Always set these variables back to 0 after probing to restore high-speed cutting motion.
Q7: Can a macro output data to an external computer or server?
A: Yes, using the DPRNT statement. The DPRNT command outputs text and variable values to external devices via the controller's RS-232 serial port or Ethernet connections. This is widely used for quality assurance tracking, printing measurement reports, or logging cycle times to a server. For example:
DPRNT[POCKET-MEASUREMENT-RESULT-X#500[33]] (Format output)
PCLOS (Close communication channel)
Q8: Why does my controller give an error when using nested brackets, and how do I format them?
A: Mismatched brackets are the most common source of macro alarms. Fanuc parsers require strict symmetry when resolving equations. Every opening bracket [ must match a closing bracket ], and you must nest equations starting with the inner calculations and working outward. For example, #100 = [[#1 + #2] * #3] is correct, while #100 = [#1 + #2] * #3] has an extra closing bracket and will trigger a format error alarm. Double-check your bracket structure before loading files to prevent errors.
Q9: How do I verify that my system variables correspond to my specific Fanuc model?
A: System variable mappings can vary slightly depending on your Fanuc controller generation (e.g., 0i-MC, 0i-MD, 16i, 18i, or 31i). Always refer to the **Fanuc Custom Macro B Manual** specifically for your machine model. A reliable way to verify mapping on the shop floor is to read a known value (such as Tool 1 Length Geometry) using the controller's MDI (Manual Data Input) mode. Command #500 = #2001, and check if the value stored in #500 matches the Tool 1 offset value displayed on your offset screen. If it matches, the system variable mappings are correct.
10. Conclusion and Shop-Floor Implementation Checklist
Fanuc Custom Macro B is a powerful tool for modern CNC programming. It allows you to move beyond rigid, hard-coded G-code files and build dynamic, logic-driven toolpaths. By mastering variables, mathematical calculations, logical branching, loops, and hardware integration, you can automate repetitive setup steps, build flexible program templates, and dramatically improve shop efficiency.
Whether you're developing standard macro subroutines to run a family of parts, or using digital touch-probes to automate coordinate tracking, parametric programming is an essential skill. As manufacturing continues to advance toward smart factories and automated systems, programmers who master Custom Macro B are highly valued in the industry.
Shop-Floor Macro Implementation Checklist
Before running a new Custom Macro B program on a production machine, use this validation checklist to verify the code and prevent crashes:
-
✓
Validate All Bracket Pairs and Syntax Structures:
Ensure all mathematical operations use square brackets
[...]instead of parentheses, and that bracket structures are fully closed. Mismatched brackets are the most common source of macro alarms. -
✓
Implement Missing-Parameter Verification Checks:
Always verify that operators have specified all required parameters when calling a macro using
G65. Use check blocks (e.g.,IF [#24 EQ #0] THEN #3000 = 101) at the start of your subroutine to trigger system alarms if parameters are missing. -
✓
Confirm Nesting Depth Limits:
Verify that your macro calling structure does not exceed the four-level nesting limit (Main Program -> Level 1 -> Level 2 -> Level 3 -> Level 4) to prevent program execution errors.
-
✓
Test Dry Runs and Use Single Block Mode:
Always test your program by elevating your work coordinate system (WCS) Z-axis offset to run a dry run safely in the air. Run the macro in Single Block mode while watching the active variable values on your controller screen register.
-
✓
Verify Local Variable Scope:
Confirm that your subroutines do not rely on local variables (
#1to#33) retaining their values after returning to the main program usingM99. Remember that local variables are cleared upon return.
Simulate and Generate Macro Code — Free
Use the Shader7 CNC Machinist Suite to calculate RPM & feed rates, bolt circle coordinates, generate custom helper subroutines, and test your code on our built-in G-Code simulator.
Enter CNC Machinist Hub →