Coordinate Systems & Work Offsets

Every reference article on this site — Fanuc #5221, Siemens $P_UIFR, Okuma VZOFX, Heidenhain preset tables — assumes you already understand what a work offset is and why a part program never talks to the machine in raw machine coordinates. This page teaches that foundation once, in control-neutral terms, then hands you the map back to each control’s specific registers. If you have ever touched off an edge finder, typed a number into a G54 screen, or wondered why your part machined 3 inches from where you expected, this is the concept underneath it.

Two Coordinate Systems: Machine and Work

A CNC machine actually has two coordinate systems running at all times, and confusing them is the single most common cause of a scrapped part or a crash.

The Machine Coordinate System (MCS) is fixed to the machine itself. Its origin — machine zero (machine home) — is a physical point the control finds every power-up by driving each axis to its reference point (the home switch plus the encoder grid/marker pulse). Machine zero never moves. On most vertical machining centers it sits at a corner of travel with all axes fully retracted, so machine coordinates are typically all-negative numbers. The MCS is the machine’s ground truth: it is where limit switches, tool-change positions, and pallet locations are measured from.

The Work Coordinate System (WCS) is fixed to your part. Its origin — part zero or program zero — is wherever you decide to program from: a corner of the vise, the center of a bore, the top of the stock. CAM posts everything relative to this point. The whole reason we don’t program in machine coordinates is portability: a fixture that sits at a slightly different spot tomorrow, a second part in the other vise, or the same program run on a different machine would all need every coordinate rewritten. Instead, the program stays put and only one number set — the offset — changes.

The relationship is exactly this:

Work position (what you program)  =  Machine position  −  Work offset

… or rearranged, the offset IS the vector from machine zero to part zero:

Work offset  =  Machine position of part zero  −  Machine zero (0)

So the work offset is nothing more than the machine coordinates of your part zero. When you “set G54,” you are telling the control: “my part’s origin lives here, at this spot in the machine.” Everything the program commands is then measured from that spot. To move in raw machine coordinates for a single block — a safe retract to a fixed clearance, a move to a tool-change position — use G53, which is a one-shot, non-modal command that ignores all work offsets for that block only.

Here is that chain in one picture — the same offset values as the G10 example later on this page:

Machine home G53 X0 Y0 G54 offset X-450.0 Y-375.0 Part zero G54 Programmed point X1.0 Y2.0 Tool position +X +Y Machine home G54 offset X-450.0 Y-375.0 machine table Part +X +Y Part zero (G54)

The work-offset stack: the G54 offset is the vector from machine home to part zero, and every programmed coordinate is measured from part zero.

The Standard Work Offsets

A control does not store just one work offset — it stores a table of them, so one program can address several fixtures, a tombstone’s faces, or multiple parts without changing a coordinate. These are the ISO/Fanuc-standard members of the family, and the same G-codes appear on Haas, Mazak, Mitsubishi, and Siemens ISO mode.

Code Name What it does
Settable work offsets
G54G59Work coordinate systems 1–6The six standard part-zero registers. Modal — once selected, it stays active until another is chosen. G54 is the everyday default.
G54.1 P1P48Extended (additional) work offsetsAn optional bank of 48 more (Fanuc/Haas write it G54.1 Pn or G54 Pn; Mazak extends to P300). Essential for horizontal machines and multi-part tombstones. Same idea as G54, just addressed by a P number.
Shifts stacked on top
G52Local coordinate systemA temporary shift added on top of the active work offset — move the origin to a sub-feature (a bolt-circle center, one pocket of a repeated pattern) without disturbing G54. Cancel with G52 X0 Y0 Z0.
G92Coordinate system settingSets the WCS by declaring the tool’s current position to be a given coordinate. Older technique, still common on lathes. It works by computing a shift — see the gotchas below.
External / CommonExternal (common) work offsetRegister “00” on the offset screen (marked EXT or COM). Not selectable by any G-code — it is always added to whichever work offset is active, so nudging it shifts every G54–G59 at once. Handy for a global fixture-plate or thermal correction.
Escape hatch to the machine
G53Machine coordinate systemOne-shot, non-modal move in raw machine coordinates. Ignores all offsets for that block. Use for safe retracts and fixed positions.

These stack. On a Fanuc-family control the effective part zero is the sum of every layer that is active:

Work position  =  Machine position
− External(common) offset
− Active work offset (G54 … G59, or G54.1 Pn)
− G52 local offset
− G92 shift

Read it top to bottom as layers of shift: the external offset moves everything, the selected G54–G59 sets the part, G52 nudges to a local feature, and G92 (if used) adds one more shift. Most jobs use exactly one layer — a single G54 — and that is the healthy default. Siemens organizes the same idea as frames rather than stacked G-codes: a base frame, the settable frame (G54–G59), and a programmable frame (TRANS/ROT, the G52/G68 analog) chain together into the total active frame. See the Sinumerik Programming Basics article for how TRANS and G500 map to G52 and offset cancel.

How Each Control Names the Offset Registers

This is the payoff. The concept above is universal; the register you read or write is control-specific. Every offset lives at an addressable location, and once you know the address you can read it, log it, or overwrite it from a macro. Each row links to that control’s full reference on this site.

Control G54 register (X…C = 1–6) Extended / other offsets Reference article
Fanuc#5221#5226 (G55 = #5241+, G56 = #5261+ … G59 = #5321+)#5201#5206 external; #7001+ for G54.1 P1, stride 20 per P (P48 = #7941+)Fanuc System Variables
Haas#5221#5226 (same map as Fanuc)#5201#5206 = G52 shift on Haas (not external); #7001+ for G154 P1 (a.k.a. G110) extended offsetsHaas System Variables
Mazak (EIA/ISO)#5221#5226 (same numbers as Fanuc)#5201+ external; #7001+ for G54.1; G54.1 extends to P300 with the optionMazak EIA/ISO Programming
Mitsubishi (M700/M70)#5221#5226 (“same numbers as Fanuc”)#5201+ external; #7001+ for G54.1 P1, stride 20 (P48 = #7941+)Mitsubishi Programming & Macros
Siemens SINUMERIK$P_UIFR[1] (G54 frame; G55 = $P_UIFR[2] …)Indexed by axis & component: $P_UIFR[1,Z,TR] = G54 Z translation. G505–G599 = $P_UIFR[5]+; programmable frame = $P_PFRAMESinumerik System Variables
Heidenhain TNC 640Preset table PRESET.PR (row = preset number; row 0 = last manual preset)Datum tables *.D (activated by TRANS DATUM TABLE / Cycle 7); read live with FN 18: SYSREAD ID507/508, active preset = ID530 NR1Heidenhain TNC 640 Tables & System Data
Okuma OSPVZOFX[n] / VZOFY[n] / VZOFZ[n] (work-zero offset, set n)Common shift added to every offset: VZSFTX / VZSFTY / VZSFTZ (the external-offset analog)Okuma Variable Types

Two things to notice. First, the Fanuc-family controls (Fanuc, Haas, Mazak, Mitsubishi) deliberately share the #5221#5226 map for G54 and #7001+ for the extended set — a macro that touches offsets is largely portable among them. The one trap: #5201#5206 is the external offset on Fanuc/Mazak/Mitsubishi but the G52 shift on Haas. Second, Siemens, Heidenhain, and Okuma abandon numbered registers for named ones — a frame, a table row, a function-and-axis name — but the underlying quantity is identical: the vector from machine zero to part zero.

Setting a Work Offset

There are three ways the number gets into the register, from most manual to most automated.

1. At the machine (touch-off). The everyday method. Put an edge finder, dowel, or spindle probe against a known feature, read the machine position, and store it into the offset. Most controls have a “set” softkey on the offset page that captures the current axis position for you (jog-and-set); for Z you typically touch the tool or a gauge block to the top of the part. A wireless or wired touch probe automates the touch-off with a cycle — probe two edges for X / Y, a bore for a center, or a boss for a datum — and writes the result directly into G54 without arithmetic. The key idea is unchanged: whatever the method, you are measuring where part zero sits in machine coordinates and storing that vector.

2. From the program with G10. The G10 command (programmable data input) writes offset registers straight from NC code — no macro option required. For work offsets the format is G10 L2 P__, where P1P6 select G54–G59 and P0 selects the external offset; the extended offsets use L20 with P1P48. The active G90/G91 mode matters: G90 writes an absolute value, G91 adds to whatever is already there.

G90 G10 L2 P0 X-10.0             ; external offset X = -10 (shifts ALL offsets)
G90 G10 L2 P1 X-450.0 Y-375.0 Z0 ; set G54 absolutely (P1 = G54)
G90 G10 L2 P3 X-630.0 Y-408.0    ; set G56; Z omitted, so G56 Z is left unchanged
G91 G10 L2 P1 X5.0               ; ADD 5 mm to the current G54 X (incremental)
G10 L20 P1 X-200.0 Y-150.0 Z0    ; set the first EXTENDED offset (G54.1 P1)

A common pattern: an operator measures a fixture once, then a short G10 preamble at the top of the program stamps every offset for the tombstone so nothing depends on stale screen values.

3. From a macro (probe → write the register). Because the offset registers are ordinary system variables, a probing routine can capture a measured position and write it back. This is the heart of in-process probing: trip the probe with a G31 skip move, read the trigger position out of the skip variables (#5061#5063 on Fanuc), and store the result into the active offset. For example, adding a probed correction to G54 X is a single line:

#5221 = #5221 + #500   ; add the probing result (#500) to G54 X

The same move on a Siemens control writes the frame — $P_UIFR[1,X,TR] = $P_UIFR[1,X,TR] + R1 — and on Okuma writes the named variable, VZOFX[1] = VZOFX[1] + VC1. For the mechanics of reading skip positions and writing offset variables safely (save/restore modal state, absolute vs incremental), see Modal & Position Data, which walks through the #5061/#5221 pairing used by every probing macro.

Tool Length vs. Work Offset — Don’t Confuse Them

These are the two offsets people mix up, and they answer two different questions. The work offset (G54) answers “where is the part?” — it is one vector per fixture, shared by every tool. The tool length offset (called with G43 H__ on Fanuc-style controls, automatic via the D-edge on Siemens) answers “how far does this particular tool stick out of the spindle?” — it is one value per tool. In the Z axis both stack up: the machine drops the spindle to work-offset Z plus the active tool length so that Z0 in the program lands on the part top no matter which tool is loaded.

Getting the split wrong is a classic error: bake a tool’s stick-out into the G54 Z and every other tool cuts at the wrong depth; conversely, set part location in a tool offset and only one tool finds the part. The clean rule is part geometry goes in the work offset, tool geometry goes in the tool offset. For how each control stores tool length and radius — geometry vs. wear, memory types A/B/C, the #2001/#2401 registers — see Tool Offset Variables.

Common Gotchas & Crashes

Symptom Cause Fix
Part machines in the wrong spot, often far from the fixtureNo WCS selected, so the last active one (or the machine’s default) is in force — forgetting the G54Always command the work offset in the safe startup line, e.g. G90 G54 G17 G40 G80, before the first positioning move.
The right offset is set but the wrong one is activeA previous tool or subprogram left G55 (or a stray G54.1 P_) modal; the new part runs on itRe-assert the intended offset per tool/operation. Verify the active WCS on screen (Fanuc #4014 tells a macro which one is live).
Everything is off by a constant amount, on every offset at onceA nonzero external/common offset (register 00, EXT) is quietly adding to all of themCheck the external offset line first when all parts shift together. It is invisible if you only look at the G54 page.
G92 shift lingers and corrupts a later G54G92 creates a shift that stays until cleared or overwritten; mixing G92 and G54G59 stacks them unexpectedlyPrefer G54–G59 for fixturing. If you must use G92, cancel it (G92.1/G50 per control) and avoid combining it with settable offsets.
A move goes the opposite way or double the expected distanceIncremental (G91) left active when absolute (G90) was intended — especially after a G91 G10 or G91 G28 lineReturn to G90 explicitly after any incremental block. In macros, save #4003 and restore it.
Rapid into the fixture during a “safe” retractA G53 machine-coordinate move assumed the wrong sign, or a work-coordinate Z retract was shorter than the tool lengthRetract with G53 to a known machine Z (usually near 0), and remember G53 ignores offsets — the number is raw machine position.

The through-line for all of these: know which coordinate system a number lives in before you trust it. A value that is correct in machine coordinates is a crash in work coordinates, and vice versa. When in doubt, single-block the first moves and watch the position display switch between machine and work readouts.

References

  • Peter Smid, Fanuc CNC Custom Macros, Industrial Press, 2004 — Chapter 5 (Data Setting / G10) and the work-offset concept chapters.
  • Fanuc, Operator’s Manual / Parameter Manual, FANUC Corporation.

Have a question or want to contribute?

Contact us with corrections, additions, or topics you'd like covered.

Get in Touch