Fanuc Turning System Variables (Fanuc-T)
A Fanuc lathe control (Fanuc-T: 0i-T, 30i-T and kin) runs the same custom-macro machinery as the mill controls — the same #-variables, the same IF/GOTO/WHILE, the same read-into-a-variable, do-arithmetic, write-it-back pattern covered in the Fanuc System Variables reference. What changes is the tool-offset map, and it changes completely: a lathe offset station is not one length and one radius, it is X geometry, Z geometry, nose radius, and tip direction — each (except tip direction) with a separate geometry and wear value. That is up to seven numbers per station, and they live in variable blocks a mill programmer has never touched. This article maps them, then works the two problems every lathe macro runs into: diameter mode, and writing wear offsets from measured parts.
How the Lathe Numbering Is Organized
Same skeleton as the mill map — the number tells you the family. The two lathe-specific entries are the tool-offset block (same #2001 neighborhood as a mill, completely different interior) and the work shift:
| Range | Family |
|---|---|
#1–#33 | Local variables & macro call arguments |
#100–#999 | Common (general-purpose) variables |
#2001–#2964 | Tool offsets — wear and geometry blocks for X, Z, nose radius, tip direction, Y (the lathe-specific map below), with the work shift embedded at #2501/#2601 |
#3000–#3902 | Alarms, timers, control switches, part counters |
#4001–#4130 | Modal information (active G-codes, T, S, F…) |
#5001–#5106 | Positions (previous block, machine, work, skip, deviation) |
#5201–#5208 | External workpiece zero-point offset (needs the workpiece-coordinate-system option on older T controls; not the Work Shift screen — that is #2501/#2601) |
#5221–#5328 | Work offsets G54–G59 |
#10001+ | Five-digit tool-offset map for high offset counts (documented since the 16i/18i era; table below) |
The Lathe Tool-Offset Map
The layout below is the standard Fanuc-T map for controls with geometry/wear offset memory, and it is printed identically in the 0i-B (B-63834EN), 16i/18i-B (B-63524EN), and 30i-B Plus (B-64724EN) custom-macro chapters — these bases are stable across generations. Variable = block base + offset number, so X wear for offset 07 is #2007 and X geometry for offset 07 is #2707. One asymmetry to respect: the wear blocks and the nose-radius geometry block cover offsets 1–64, but the X and Z geometry blocks stop at offset 49 (the Y-axis blocks occupy the room above them) — offsets past those limits are reached through the five-digit map below.
| Variable | Usage | R/W |
|---|---|---|
| Wear Offsets (base + offset number 1–64) | ||
#2001–#2064 | X-axis wear offset | R/W |
#2101–#2164 | Z-axis wear offset | R/W |
#2201–#2264 | Tool-nose radius wear offset | R/W |
#2301–#2364 | Tip direction (imaginary tool-nose number T, integer 0–9 — a code, not a dimension; one value per offset, shared by geometry and wear) | R/W |
#2401–#2449 | Y-axis wear offset (mill-turn lathes with a Y axis) | R/W |
| Geometry Offsets (base + offset number — note the 49 limit on X/Z) | ||
#2701–#2749 | X-axis geometry offset (offsets 1–49 only) | R/W |
#2801–#2849 | Z-axis geometry offset (offsets 1–49 only) | R/W |
#2901–#2964 | Tool-nose radius geometry offset (1–64) | R/W |
#2451–#2499 | Y-axis geometry offset (1–49) | R/W |
| Work Shift | ||
#2501 / #2601 | Workpiece coordinate system shift amount, X / Z — the value on the lathe’s Work Shift screen, applied on top of every coordinate system. (The similarly-purposed #5201+ block is the external workpiece zero-point offset — a different register.) | R/W |
| Five-Digit Map (base + offset number; same fields, no 49/64 ceilings) | ||
#10001+ / #15001+ | X-axis wear / geometry | R/W |
#11001+ / #16001+ | Z-axis wear / geometry | R/W |
#12001+ / #17001+ | Nose-radius wear / geometry | R/W |
#13001+ | Tip direction (one value, as in the four-digit map) | R/W |
#14001+ / #19001+ | Y-axis wear / geometry | R/W |
The five-digit map is not a 30i invention — the 16i/18i-B manual documents it for 99-set configurations and the 0i-B for 64 — but on the 30i series it reaches offset 999 and is the safer base to program against: it is valid even for low offset numbers, and it has no 49-offset cliff on X/Z geometry. (30i controls also expose named aliases like [#_OFSXW[n]] and [#_OFSXG[n]] for the same registers.) Two configuration departures to know about: a control without the geometry/wear memory option keeps one combined value per field at the wear bases (#2001/#2101/#2201/#2301), and a machine with more offset sets than the four-digit blocks hold simply has no four-digit address for the excess — use the five-digit one. An MDI read compared against the offset screen still settles any doubt in thirty seconds.
Two consequences of this layout worth internalizing. First, updating a lathe tool after a measured drift is usually two writes, not one (X wear and Z wear move independently). Second, tip direction sits in the middle of the dimensional blocks but is an integer code — writing a length into #2301+ corrupts nose-radius compensation quietly.
Indirect addressing (#[expression]) works exactly as on the mill, and on a lathe it earns its keep immediately — one macro can pull every field of a station whose number arrives as an argument. A useful pattern is a pre-flight check that reads the whole station and alarms out before a finish pass runs with an unset nose radius:
(O8090 - SANITY-CHECK ONE OFFSET STATION, CALL: G65 P8090 A3.)
(#1 = OFFSET NUMBER)
#11 = #[2000 + #1] (X WEAR)
#12 = #[2100 + #1] (Z WEAR)
#13 = #[2200 + #1] (NOSE RADIUS WEAR)
#14 = #[2700 + #1] (X GEOMETRY)
#15 = #[2800 + #1] (Z GEOMETRY)
#16 = #[2900 + #1] (NOSE RADIUS GEOMETRY)
#17 = #[2300 + #1] (TIP DIRECTION, INTEGER 0-9)
IF [[#16 + #13] LE 0] GOTO 90 (NO NOSE RADIUS - G41/G42 WOULD BE WRONG)
IF [#17 LT 0] GOTO 91
IF [#17 GT 9] GOTO 91 (TIP DIRECTION OUT OF RANGE)
GOTO 99
N90 #3000 = 102 (NOSE RADIUS NOT SET FOR THIS OFFSET)
N91 #3000 = 103 (TIP DIRECTION INVALID FOR THIS OFFSET)
N99 M99
Named Tool-Offset Variables (30i / Plus)
On a 30i-family lathe every register in the map above also has a name, written with the whole reference in brackets: [#_OFSXW[7]] is X wear for offset 7, unambiguously — where #2007 needs the map (and a check of the geometry/wear memory option) to decode. The mechanism — the [#_NAME[n]] syntax, expression subscripts, and the PS1098/PS1099 alarms for a misspelled name or bad index — is covered in the mill article’s named-variables section; the table below is the lathe-specific offset vocabulary. Note how the memory option is spelled out in the name: with geometry/wear memory the …W/…G forms address the two blocks separately, while a control without that option uses the plain #_OFSX-style names for its single combined values — at the same wear-block numbers.
| Name | Number equivalent | Index | R/W | Meaning |
|---|---|---|---|---|
| Wear Offsets (with geometry/wear offset memory) | ||||
#_OFSXW[n] | #2001–#2064; #10001–#10999 | n = offset number (1–64 / 1–999) | R/W | X-axis wear offset |
#_OFSZW[n] | #2101–#2164; #11001–#11999 | n = offset number (1–64 / 1–999) | R/W | Z-axis wear offset |
#_OFSRW[n] | #2201–#2264; #12001–#12999 | n = offset number (1–64 / 1–999) | R/W | Tool-nose radius wear offset |
#_OFSYW[n] | #2401–#2449; #14001–#14999 | n = offset number (1–49 / 1–999) | R/W | Y-axis wear offset |
| Geometry Offsets | ||||
#_OFSXG[n] | #2701–#2749; #15001–#15999 | n = offset number (1–49 / 1–999) | R/W | X-axis geometry offset |
#_OFSZG[n] | #2801–#2849; #16001–#16999 | n = offset number (1–49 / 1–999) | R/W | Z-axis geometry offset |
#_OFSRG[n] | #2901–#2964; #17001–#17999 | n = offset number (1–64 / 1–999) | R/W | Tool-nose radius geometry offset |
#_OFSYG[n] | #2451–#2499; #19001–#19999 | n = offset number (1–49 / 1–999) | R/W | Y-axis geometry offset |
| Tip Direction | ||||
#_OFST[n] | #2301–#2364; #13001–#13999 | n = offset number (1–64 / 1–999) | R/W | Virtual tool tip T position (the integer 0–9 tip-direction code) |
| Without Geometry/Wear Offset Memory (single combined value per field) | ||||
#_OFSX[n] | #2001–#2064; #10001–#10999 | n = offset number (1–64 / 1–999) | R/W | X-axis compensation value |
#_OFSZ[n] | #2101–#2164; #11001–#11999 | n = offset number (1–64 / 1–999) | R/W | Z-axis compensation value |
#_OFSR[n] | #2201–#2264; #12001–#12999 | n = offset number (1–64 / 1–999) | R/W | Tool-nose radius compensation value |
#_OFSY[n] | #2401–#2449; #14001–#14999 | n = offset number (1–49 / 1–999) | R/W | Y-axis compensation value |
| Second Geometry Tool Offsets | ||||
#_OFSX2G[n] | #5801–#5832; #27001–#27999 | n = offset number (1–32 / 1–999) | R/W | Second geometry tool offset, X axis |
#_OFSZ2G[n] | #5833–#5864; #28001–#28999 | n = offset number (1–32 / 1–999) | R/W | Second geometry tool offset, Z axis |
#_OFSY2G[n] | #5865–#5896; #29001–#29999 | n = offset number (1–32 / 1–999) | R/W | Second geometry tool offset, Y axis |
| Workpiece Shift | ||||
#_WKSFTX (the manual’s explanation pages also spell it #_WZ_SFTX) | #2501 | — (scalar) | R/W | X-axis workpiece coordinate system shift amount |
#_WKSFTZ (also spelled #_WZ_SFTZ) | #2601 | — (scalar) | R/W | Z-axis workpiece coordinate system shift amount |
#_WZ_SFT[n] | #100751–#100800 | n = axis number (1–50) | R/W | nth-axis workpiece shift amount |
| Active Tool Offset (what is applied to the tool right now — read-only reporters, not the offset table) | ||||
#_TOFSWX / #_TOFSWZ / #_TOFSWY | #5081, #100201 / #5082, #100202 / #5083, #100203 | — (scalar) | R | X- / Z- / Y-axis tool offset (wear) of the active tool |
#_TOFS[n] | #5084–#5100 (n = 4–20); #100204–#100250 (n = 4–50) | n = axis number | R | Tool offset (wear) for an arbitrary axis |
#_TOFSGX / #_TOFSGZ / #_TOFSGY | #5121, #100901 / #5122, #100902 / #5123, #100903 | — (scalar) | R | X- / Z- / Y-axis tool offset (geometry) of the active tool |
#_TOFSG[n] | #5124–#5140 (n = 4–20); #100904–#100950 (n = 4–50) | n = axis number | R | Tool offset (geometry) for an arbitrary axis |
Where the numbers make you memorize that #2007 is wear and #2707 is geometry — and remember the 49-offset cliff — the names carry both facts in the token and accept the full 1–999 subscript wherever the expanded ranges exist. The tip-direction trap flagged above reads even louder in named form: #_OFST is visibly not a dimension field.
Everything That’s the Same as the Mill
Outside the tool-offset blocks, the map matches the mill reference — see Fanuc System Variables for the full table with R/W flags. The short version, with the one lathe-specific trap flagged:
| Family | Variables | Lathe note |
|---|---|---|
| Positions | #5001+ (previous block end), #5021+ (machine), #5041+ (work) | Axis order is X, Z, … per the machine’s axis configuration — and X reads come back as a diameter on a diameter-programmed lathe (next section) |
| Skip / probe | #5061+ (position where G31 tripped, work coordinates) | Same diameter caveat on the X value |
| Modal data | #4001+ G-code groups, #4120 modal T | #4120 returns the whole T word (T0312 → 312): station and offset number packed together |
| Common variables | #100–#199 (volatile), #500–#999 (retained) | Identical |
| Alarms & stops | #3000 (alarm), #3006 (stop with message) | Identical |
| Part counters | #3901 (machined parts), #3902 (required parts) | Identical — the usual home of bar-feeder “count and stop” logic |
| Timers & clock | #3001/#3002 (timers), #3011/#3012 (date/time) | Identical |
| Work offsets | #5221+ (G54) … #5321+ (G59) | Identical numbering (option-gated on older T controls, along with the external offset #5201+); many lathes run everything from the work shift (#2501/#2601) plus geometry offsets instead |
Read-Only vs Read/Write at a Glance
The mill rule of thumb carries over unchanged: variables that report state are read-only, variables that hold setup data are writable. On a lathe the practically important consequence is that the entire offset map above — all seven fields per station, plus the work shift — is writable, which is exactly what makes in-process wear compensation a macro-sized job.
| Read-only (report state) | Read/write (you can assign to them) |
|---|---|
Positions #5001–#5106 (previous-block end, machine, work, skip, deviation) | Tool offsets #2001–#2964 and #10001+ (wear + geometry, X/Z/R/T/Y) |
Modal codes #4001–#4130 (incl. #4120 modal T) | Work shift #2501/#2601, external offset #5201+, work offsets #5221–#5328 |
Clock #3011/#3012, null #0 | Commons #100–#199, #500–#999; counters #3901/#3902; timers #3001/#3002; alarm/stop #3000/#3006 (write-only) |
Diameter Mode Bites Macros
Almost every lathe is diameter-programmed: X50. means a 50 mm diameter, not 50 mm from centerline. The control extends that convention into the system variables — #5041 (and #5021, #5061) return the X axis as a diameter value. Any macro doing real geometry — trigonometry on a taper, comparing a probe trip to a radial clearance — must halve the X read first:
#101 = #5041 / 2 (CURRENT X AS A RADIUS - #5041 IS DIAMETER)
#102 = #5061 / 2 (SKIP X AS A RADIUS)
The same ambiguity hits writes — and here the manual is explicit. Suppose a post-process gauge says the finished part is 0.04 mm big on diameter. The physical correction is to bring the tool 0.02 mm closer to centerline — but what number goes into the X wear variable depends on how the control stores X offsets, and that is a documented parameter: the operator’s manual’s diameter-programming table says the tool-offset component follows bit 1 (ORC) of parameter No. 5004 — 0 (the factory default) stores offsets for a diameter-programmed axis as diameter values, 1 as radius values. So on a standard diameter-mode lathe the write is -0.04, matching what the operator would key into the offset screen. Two footnotes: ORC only applies to diameter-programmed axes (a radius-programmed axis always takes radius values), and on an ORC=1 machine, bit 0 (OWD) of parameter No. 5040 can put wear offsets back on diameter while geometry stays radius. A test cut remains the right acceptance check of the whole chain — cut, measure, write a known correction, cut again, and confirm the diameter moved by the full amount you wrote (diameter storage) or twice it (radius) — but you are verifying a parameter setting now, not guessing at one.
(PART MEASURED 0.04 MM OVERSIZE ON DIAMETER, TOOL OFFSET 3)
#[2000 + 3] = #[2000 + 3] - 0.04 (ORC=0, THE DEFAULT: X WEAR IS A DIAMETER VALUE)
(OR - 0.02 ON AN ORC=1 RADIUS-ENTRY MACHINE - PARAM 5004#1)
Worked Example: In-Process Gauging Loop
The bread-and-butter lathe macro: after a finish pass, a measured diameter (from an in-process gauge, a probe routine, or the operator keying it into a retained common variable) is compared to target, and the X wear offset for the active tool drifts to compensate. The offset number is resolved from the modal T word (#4120), the correction is clamped so one bad reading cannot crash the next part, and anything outside the scrap band raises #3000 instead of “correcting” it. Assumes a 2+2 T format (T0303) and the default diameter-value offset storage (ORC=0) — adjust if your machine is set to radius entry.
(O8100 - UPDATE X WEAR FROM MEASURED DIAMETER)
(#510 = MEASURED DIAMETER - GAUGE OR OPERATOR ENTRY)
(#511 = TARGET DIAMETER)
#1 = #510 - #511 (DIAMETER ERROR, + = OVERSIZE)
IF [ABS[#1] GT 0.25] GOTO 90 (OUTSIDE SCRAP BAND - DO NOT CORRECT)
IF [ABS[#1] LE 0.005] GOTO 99 (INSIDE DEADBAND - LEAVE OFFSET ALONE)
IF [#1 GT 0.06] THEN #1 = 0.06 (CLAMP CORRECTION PER CYCLE)
IF [#1 LT -0.06] THEN #1 = -0.06
#2 = #4120 - [FIX[#4120 / 100] * 100] (WEAR OFFSET NO. = LOW 2 DIGITS OF T)
IF [#2 LT 1] GOTO 91 (NO OFFSET ACTIVE - T??00)
#[2000 + #2] = #[2000 + #2] - #1 (SHIFT X WEAR, DIAMETRAL STORAGE)
GOTO 99
N90 #3000 = 100 (PART OUT OF TOLERANCE - CHECK TOOL AND GAUGE)
N91 #3000 = 101 (NO WEAR OFFSET ACTIVE - CHECK T WORD)
N99 M99
On a 30i control the X-wear write reads better in the named form — the name carries the axis and the wear/geometry meaning, the subscript carries the offset number, and the same pattern works on the read side (#5 = [#_OFSZG[#2]] pulls Z geometry for the same station):
[#_OFSXW[#2]] = [#_OFSXW[#2]] - #1 (SAME X-WEAR WRITE AS #[2000 + #2] ABOVE, NAMED FORM)
Getting the measurement in. Where #510 comes from depends on the shop. The zero-hardware version pauses the cycle and asks the operator to key the gauge reading into a retained common variable before pressing cycle start:
(OPERATOR-ENTRY VARIANT)
#3006 = 1 (MIC THE PART - PUT DIAMETER IN NO. 510 - CYCLE START)
G65 P8100 (RUN THE WEAR-UPDATE MACRO ABOVE)
With a spindle probe, a G31 skip move onto the turned diameter captures the trip position instead — and because the X read is diametral (previous section), a probe touching a centerline-symmetric OD hands you a diameter-mode value directly. Probe radius and trigger calibration still have to be folded in (that is what the stylus-calibration constant in a retained variable is for):
(PROBE-CAPTURE VARIANT)
G00 X[#511 + 4.] Z-10. (CLEAR OF THE TURNED DIAMETER)
G31 X[#511 - 2.] F100. (SKIP MOVE ONTO THE OD)
#510 = #5061 + #520 (SKIP X, DIAMETRAL + STYLUS CAL FROM #520)
G00 X[#511 + 4.] (RETRACT)
G65 P8100 (RUN THE WEAR-UPDATE MACRO ABOVE)
One timing note: a wear value written mid-program is stored immediately, but the axis does not move — the new value takes effect when the offset is next applied (the next T call, in the next part cycle). That is exactly what you want for drift compensation.
Gotchas Worth Knowing
- Diameter vs radius, everywhere. X position reads (
#5021/#5041/#5061) are diametral on a diameter-programmed lathe; X offsets are diameter values by default and radius values if bit 1 (ORC) of parameter No. 5004 is set. Halve for geometry, and confirm the offset-storage chain with a test cut before trusting a correction macro. - Write wear for drift, geometry for setup. Geometry offsets describe where the tool is (set at touch-off); wear offsets absorb how it changes (insert wear, thermal growth). An in-process loop should only ever touch the wear blocks — a macro that “corrects” geometry destroys the setup reference and hides how much the insert has actually worn.
- Tip direction (
#2301+) is an integer, not a dimension. It selects the imaginary tool-nose quadrant (0–9) for nose-radius compensation. Indirect-addressing loops that sweep “all offset variables” must skip this block, or they will write fractional lengths into a code field. - The T word maps to offsets differently across machines. The example above assumes T0303-style 2+2 format where the low two digits are the offset number — but some builders use 1+2 or 2+1 formats, and turret station and offset number need not match (T0315 runs station 3 with offset 15). Gang-tool and multi-turret lathes complicate it further. Resolve the offset number from
#4120the way your T format packs it, and never assume station = offset. - Skip moves want comp cancelled. Run
G31inG40— a skip move under active nose-radius compensation is either rejected or hands you a trip position skewed by the comp vector. Cancel, probe, re-apply. - Look-ahead buffering applies here too. A block already read into the buffer keeps the old value of an offset you just wrote, and position reads can be evaluated before the preceding motion finishes. Where a read or write must line up with motion, drain the buffer first (
G04dwell is the common idiom) — same rules as the mill article details. - Check units before writing corrections. A gauge reading keyed in millimeters against a program running
G20writes a 25× oversized correction. If the macro can be run in either mode, read#4006(20 = inch, 21 = metric) and convert — or alarm out. - Mind the edges of the four-digit map. The bases themselves are stable from 0i-B through 30i-B Plus, but the X/Z geometry blocks (
#2701/#2801) end at offset 49 and the wear blocks at 64 — a loop that walks offsets 1–80 through four-digit addresses walks off the map. Use the five-digit bases (#10001+) for anything general, and remember that a control without geometry/wear offset memory collapses each field to a single value at the wear bases. One MDI read against the offset screen settles any residual doubt in thirty seconds.
▶ Try these in the Macro Playground — pick the Fanuc control, paste the gauging loop, set #510/#511 and #4120 as inputs, and watch the wear-offset write happen live.
See also: Fanuc Turning Programming for the lathe G-code context these macros live in, Fanuc System Variables for the full mill-side #-number map shared by both control families, and Reading & Writing System Variables for the same read/compute/write pattern across every control.
References
- FANUC, Series 30i/31i/32i-MODEL B Plus Operator’s Manual (Common), B-64724EN/01, ch. 16 (system variables, lathe tool-compensation and work-shift tables) and §8.4 (diameter/radius programming).
- FANUC, Series 16i/18i-TB Operator’s Manual, B-63524EN/01, ch. 15, and Series 0i-TB Operator’s Manual, B-63834EN/01, ch. 15 (legacy-generation variable tables).
- FANUC, Series 30i/31i/32i-MODEL B Plus Parameter Manual, B-64730EN/01 (Nos. 5004 ORC, 5040 OWD).
- Peter Smid, Fanuc CNC Custom Macros, Industrial Press, 2004.
Have a question or want to contribute?
Contact us with corrections, additions, or topics you'd like covered.
Get in Touch