CNC ProgrammingG-code (Macro B)FANUC control (or builder supporting Macro B) · G65 custom macroMIT licenseAdvanced
Bolt-circle drilling in FANUC Macro B (G65 custom macro)
The Python bolt-circle generator writes a finished program; this is the same drilling pattern living inside the control as a callable custom macro — G65 P2000 A40. B8 Z-12. F120. S2400 D0. E0. and the control computes every hole itself. Same math, same G81/G83 modal trick, FANUC's own control flow instead of a Python for loop — and it validates its arguments before cutting anything.
Before you run it
- A FANUC control (or Haas/other builder supporting Macro B custom macros) with custom macro B enabled
- Loaded as its own subprogram (
O2000), called viaG65 P2000with the arguments shown - A dry run above the part before the first real cut — every time, no exceptions
The code
O2000 (BOLT CIRCLE - MACRO B)
(CALL: G65 P2000 A40. B8 Z-12. F120. S2400 D0. E0.)
(A=RADIUS B=HOLE COUNT Z=DEPTH(NEGATIVE) F=FEED S=RPM)
(D=PECK INCREMENT, 0 OR OMITTED = PLAIN G81 E=START ANGLE, DEG, DEFAULT 0)
IF[#1 NE #0]GOTO10
#3000=1(BOLT CIRCLE: A/RADIUS REQUIRED)
N10
IF[#2 NE #0]GOTO20
#3000=1(BOLT CIRCLE: B/HOLE COUNT REQUIRED)
N20
IF[#26 NE #0]GOTO30
#3000=1(BOLT CIRCLE: Z/DEPTH REQUIRED)
N30
IF[#8 NE #0]GOTO40
#8=0
N40
#101=#8
#102=0
G90 G94 G17 G21
S#19 M3
G43 H01 Z25.
WHILE[#102 LT #2]DO1
#110=#1*COS[#101]
#111=#1*SIN[#101]
IF[#102 EQ 0]GOTO50
X#110 Y#111
GOTO70
N50
IF[#7 EQ #0]GOTO60
G98 G83 X#110 Y#111 Z#26 R2. Q#7 F#9
GOTO70
N60
G98 G81 X#110 Y#111 Z#26 R2. F#9
N70
#101=#101+360/#2
#102=#102+1
END1
G80
G0 Z25.
M5
M99What you get
What you get
Call: G65 P2000 A40. B8 Z-12. F120. S2400 D0. E0.
The control moves through the same 8-hole bolt circle as the
Python generator (radius 40, holes 8) - only here every X/Y/Z
motion happens live, computed by the control itself. Nothing to
copy into a program: G65 IS the program.How it works
- Argument letters map to fixed variable numbers under FANUC's Argument Specification I —
A→#1,B→#2,Z→#26,F→#9,S→#19— which is why the call line and the variable numbers inside the macro don't visually match up. That mapping is the first thing to memorize.L6–17 COS[#101]/SIN[#101]take degrees, matching#101's own units — Macro B trig is degrees-native, the opposite of nearly every general-purpose language.L27–28WHILE[#102 LT #2]DO1 ... END1is the loop; theIF[#102 EQ 0]inside it is exactly the same "first hole gets the cycle, the rest are modal X Y" logic as the Python generator — same idea, FANUC's own control flow instead of aforloop.L26–41#3000=1(...)is FANUC's built-in way to fail loud: it raises a custom alarm with the parenthetical text as the message, so a missing required argument stops the program with a readable reason instead of cutting air at X0 Y0.
Gotchas & honest limits
- COS/SIN take degrees in Macro B, unlike most languages that expect radians — that's the reason this reads naturally as
360/#2instead of needing a manual conversion. #3000=1(MESSAGE)raises a custom alarm (3001, with the message shown) and stops execution — the FANUC-native way to fail loud on a bad call, instead of silently cutting air at X0 Y0.- Argument letters map to fixed variable numbers by control design, not by choice — getting a letter wrong silently reads the wrong variable rather than erroring.
- This is Macro B, the common FANUC/Haas dialect; Siemens/Heidenhain custom-cycle syntax is completely different. The shape of the logic (loop, first-hole-gets-cycle) transfers; the syntax doesn't.
Goes deeper
Want this adapted to your shop — or built into a real tool?
Samples are the free 80%. The last 20% is the part I do for a living.