Reading & Writing System Variables (Every Control)
Every CNC control keeps a live picture of itself in memory — where each axis is, which work and tool offsets are active, what the probe just touched, which G-codes are modal, how many parts have run, which alarms are set. System variables are the named or numbered handles a part program uses to reach that data: read one into a scratch variable, do arithmetic, and (where the variable allows it) write a new value back. This one mechanism is behind every probing routine, tool-breakage check, adaptive-feed macro, and part-family program ever written. The idea is universal; only the spelling changes from control to control. This article puts the seven common dialects side by side so you can translate a pattern you know into one you don't — and links each control’s own reference for the full list.
Read-Only vs Read/Write — the Universal Caveat
Reading is almost always allowed. Writing is gated. Variables that report machine state — live positions, modal codes, the clock, probe-trigger positions — are read-only on every control; assigning to them is either ignored or throws an error. Variables that hold a stored value — work offsets, tool offsets, general-purpose commons, part counters — are read/write. On top of that split, some writes are locked behind an option or by the machine builder (OEM/PLC territory). Getting this wrong is the most common source of “why won’t it write?” confusion.
| Control | Read-only (report state) | Read/write (you can assign) | The catch |
|---|---|---|---|
| Fanuc / Haas | Positions #5001–#5108, modal codes #4000–#4130, clock #3011/#3012 | Work offsets #5201–#5328/#7001+, tool offsets #2001–#2800/#10001+, commons #100–#199/#500–#999 | Probe/parameter ranges only present if the option is installed; Haas Settings #20000+ and Parameters #30000+ are read-only |
| Mitsubishi | Positions #5001–#510n, PLC inputs #1000–#1035, modal #4001–#4021 | Work offsets #5221+, tool offsets #10001+/#2001+, commons, date/time #3011/#3012 (writable here) | Common-variable count is option-dependent; PLC outputs #1100+ writable |
| Mazak (EIA) | Positions #5001–#5116, modal #4001–#4227, interface inputs #1000+ | Work offsets #5221+, tool data #40001+ (by tool-data index), interface outputs #1100+ | No fixed #2001 tool block — resolve the tool-data index via #3020 first |
| Siemens | $AA_IM/$AA_IW positions, $P_ modal data, $VA_ servo data | $P_UIFR[] frames, $TC_DP tool data, R-parameters, $AC_ timers/counters | Writability varies per $-variable; the System Variables manual marks each. Reading a $A_/$V_ runtime var forces a preprocessing stop |
| Heidenhain | All FN 18: SYSREAD system data; preassigned Q100–Q199 (probe results, tool data) | Q/QL/QR/QS parameters; tables via FN 27/TABDATA WRITE/SQL UPDATE | FN 17: SYSWRITE is OEM/PLC-locked — you never write a live datum directly. Writes go through tables, the preset table, or a probing cycle |
| Okuma | Spindle speed VSPS; Renishaw cycle results in VS75–VS89 | Work offsets VZOFX/Y/Z[n], zero shift VZSFTx, tool offsets VTOFH/D[n], commons VC1–VC200 | VS system variables reset to null at program end; index ranges depend on OSP version and offset-set option |
Three per-control notes worth memorizing. Fanuc/Haas: positions are read-only, offsets are writable — the whole probing workflow depends on that asymmetry. Siemens: read/write status is per-$-variable and documented in the System Variables manual (in synchronized actions, an “SA” column marks read/write eligibility). Heidenhain: the direct write path FN 17: SYSWRITE is machine-builder territory, so a normal NC program changes offsets by writing a table (FN 27, TABDATA WRITE, or SQL) or by letting a touch-probe cycle write the preset table.
The Rosetta Stone — One Task, Seven Dialects
Each row is a job a machinist actually asks of a macro; each column is how that control spells it. Axis suffixes shown are for Z on a typical 3-axis mill (X = first, Y = second, Z = third). Verify against the linked per-control article before you run converted code — option gates and index ranges differ.
| Task | Fanuc / Haas | Mitsubishi | Mazak (EIA) | Siemens | Heidenhain | Okuma |
|---|---|---|---|---|---|---|
| Read current machine position (Z) | #5023 | #5023 | #5023 | $AA_IM[Z] | FN 18: SYSREAD Q1 = ID240 NR1 IDX3 | — (see note) |
| Read current work position (Z) | #5043 | #5043 | #5043 | $AA_IW[Z] | FN 18: SYSREAD Q1 = ID270 NR1 IDX3 | — (see note) |
| Read a probe / skip result (Z) | #5063 | #5063 | #5063 | $AA_MW[Z] | Q117 (Q115–Q119 = X,Y,Z,4,5) | VS77 (Renishaw cycle Z) |
| Read active tool offset (length) | #5083 (active) / #2001+ (stored) | #5083 / #10001+n | #5083 / #40001+n | $TC_DP3[t,d] | Q114 (active) / ID50 NR1 (table L) | VTOFH[n] |
| Read active work offset / modal WCS | #4014 | #4012 | #4012 | $P_UIFRNUM | FN 18: SYSREAD Q1 = ID530 NR1 | — (see note) |
| Writes (gated — see caveats above) | ||||||
| Write a work offset (G54 Z) | #5223 = … | #5223 = … | #5223 = … | $P_UIFR[1,Z,TR] = … | FN 27 datum / preset cycle (Q303/Q305) | VZOFZ[n] = … |
| Write a tool offset (length) | #2001 = … / #[11000+H] = … | #10001+n = … / G10 L10 | #40001+n = … / G10 | $TC_DP3[t,d] = … | TABDATA WRITE CORR-TCS / SQL on TOOL.T | VTOFH[n] = … |
Okuma note: the OSP references in this wiki document the named offset variables (VZOFx, VTOFx) and Renishaw probe outputs (VS75–VS89), but do not document a bare numbered current-position or skip-position system variable equivalent to Fanuc’s #5041/#5063. On an Okuma the read-and-write pattern is normally driven off the probing-cycle outputs (below), not a raw position variable. Heidenhain note: FN 18: SYSREAD always returns metric values regardless of program units, and a real-time read should be preceded by FN 20: WAIT FOR SYNC to flush look-ahead.
The Canonical Task in Every Dialect
Here is the same job — probe the top of a part and store the measured height into the active work offset so the touched face becomes Z0 — written seven ways. It is the “touch off and set zero” pattern that underpins in-process setup. Read the skip/probe position, add it to the stored work offset, retract.
Fanuc / Haas
Feed down with G31 until the probe trips; #5063 latches the Z skip position in work coordinates; shift the G54 Z offset #5223.
(TOUCH TOP OF PART, SET IT AS G54 Z0)
G90 G31 Z-25. F50. (feed down until the probe trips)
#5223 = #5223 + #5063 (shift G54 Z so the touched face = Z0)
G00 Z25. (retract)
The G31 skip sequence: the control feeds until the probe trips, latches the contact position into #5061–#5068, then stops motion and ends the block.
Mitsubishi (M700/M70)
Near-identical to Fanuc — same G31, same #5063 skip variable, same #5221–#522n work-offset block. Only the block terminator (;) and the millisecond timers differ from Fanuc habits.
(TOUCH TOP OF PART, SET G54 Z0)
G90 G31 Z-25. F200 ; (feed until the skip signal comes in)
#5223 = #5223 + #5063 ; (#5063 = Z skip position, workpiece coords)
G00 Z25. ; (retract)
Mazak (EIA/ISO)
Mazak’s EIA macro language reads captured positions from the same numbers (#5061–#5076 skip, #5221+ work offsets share Fanuc’s numbering). Real Mazak Renishaw programs read #5041/#5043 the same way.
(TOUCH TOP OF PART, SET G54 Z0)
G90 G31 Z-25. F50 ; skip move down until the probe input fires
#5223 = #5223 + #5063 ; #5063 = present skip-signal Z
G00 Z25. ; retract
Siemens (SINUMERIK)
A measuring move captures the trigger position into $AA_MW[Z] (workpiece coords); write it into the G54 frame $P_UIFR[1,Z,TR] and re-select G54 to activate the change. STOPRE ensures the measured value is available before the write.
MEAS=+1 G01 Z-25 F300 ; probe down, trigger on probe 1
STOPRE ; make the measured value current
$P_UIFR[1,Z,TR] = $P_UIFR[1,Z,TR] + $AA_MW[Z] ; shift G54 Z to the face
G54 ; re-select G54 to apply the new frame
G0 Z25 ; retract
Heidenhain (TNC 640)
There is no FN 17 write to a live datum — a touch-probe cycle does the write itself, straight into the preset table. Q305 selects the preset-table row, Q303 selects transfer of the measured value into the preset table. (To store into a datum table instead, probe first, then push the value with FN 27: TABWRITE or SQL UPDATE.)
; Probe the top face in the tool axis and set it as the datum.
; The cycle writes PRESET.PR directly - no FN 17 SYSWRITE (OEM-locked).
5 TCH PROBE 417 DATUM IN TS AXIS ~
Q305=+0 ; preset-table row to update (0 = active preset)
Q303=+1 ; transfer the measured value into the preset table
6 CYCL CALL
; To verify afterward, read the active preset row back:
7 FN 18: SYSREAD Q1 = ID530 NR1 ; number of the active preset
Okuma (OSP)
A Renishaw single-surface cycle (O9811) probes the face and stores the measured Z in VS77; add that to the work-zero offset for offset set 1, VZOFZ[1]. (The protected cycle can also update the offset for you when given a work-offset argument; the manual read-then-write below shows the mechanism.)
(PROBE TOP FACE WITH RENISHAW SINGLE-SURFACE CYCLE)
CALL O9811 (measured Z surface lands in VS77)
VZOFZ[1] = VZOFZ[1] + VS77 (shift work-offset set 1 in Z to the face)
Indirect & Computed Access
The real power of system variables is reaching one whose number or index is computed at run time — e.g. “the length offset for whatever tool is active” without hard-coding the tool.
| Control | Indirect form | Example |
|---|---|---|
| Fanuc / Haas | #[ expression ] | #104 = #[11000 + #4111] — geometry length offset for the active H number |
| Mitsubishi | #[ expression ] | #104 = #[10000 + #11] — tool length offset indexed by an argument |
| Mazak | #[ expression ], tool data by index | #104 = #[40000 + #3020] — length for the spindle tool’s data index |
| Siemens | bracket index, R[R n], $AC_PARAM[$AC_MARKER[n]] | R[R2] = 1; $P_UIFR[$P_UIFRNUM, Z, TR] — the active frame |
| Heidenhain | IDX index on SYSREAD; QS-driven KEY / labels | FN 18: SYSREAD Q5 = ID50 NR1 IDX+Q10; TABDATA READ Q1 = … KEY "Q10" |
| Okuma | variable index in brackets | VZOFZ[VC1] — offset set chosen by a common variable |
Argument Passing — Getting Data Into a Macro
The flip side of reading control data is handing your own values to a subprogram. Each dialect does it differently:
- Fanuc / Haas / Mitsubishi / Mazak —
G65letter→variable. A macro call maps address letters to local variables:A→#1 B→#2 C→#3 D→#7 F→#9 H→#11 I→#4 R→#18 X→#24 Y→#25 Z→#26….G65 P8010 A15. B40. H6lands 15 in#1, 40 in#2, 6 in#11. A fresh local set is created per call level. See the Fanuc, Mitsubishi, and Mazak articles. - Siemens —
PROCwith typed parameters. A subprogram declares its own signature:PROC DRILL(REAL DEPTH, INT COUNT), called asDRILL(-12.5, 6). R-parameters and GUD provide the shared, named alternative. See SINUMERIK R-Parameters & System Variables. - Heidenhain — no positional arguments; Q parameters are global.
CALL LBL "UP1"andCALL PGM …pass nothing directly —Qparameters remain globally effective across program calls, so you setQ1…before the call and the subprogram reads them. Local scratch usesQLparameters. See Klartext & Q-Parameters. - Okuma — named local variables on
CALL.CALL O1234 AA11=1.234 BB22=BB22 PC33=1creates named locals in the subprogram; a leadingP(PC33) marks an optional argument testable withEMPTY. See Okuma Argument & Local Variables.
Each Control’s Full Reference
- Fanuc System Variables & Modal & Position Data — the
#-number reference the others map to. - Haas System Variables — NGC and legacy variable mappings, with an explicit read/write column.
- Mitsubishi M700/M70 Programming & Macros — ~95% Fanuc Macro B, with the millisecond-timer gotcha.
- Mazak EIA/ISO Programming — Fanuc-like
#-variables, but tool data by index and Mazak-specific numbers. - SINUMERIK R-Parameters & System Variables & Synchronized Actions — the
$-prefix decode and real-time reads/writes. - Heidenhain TNC 640 Tables & System Data (FN 18 SYSREAD, FN 27, TABDATA) & Klartext & Q-Parameters.
- Okuma Variable Types (VS / VC / VZOF / VTOF) & Okuma Argument & Local Variables.
▶ Open the Macro Playground — read and write system variables interactively across seven controls.
References
- Fanuc, Operator’s Manual / Parameter Manual, FANUC Corporation.
- Haas, Operator’s Manual / NGC Programming Guide, Haas Automation, Inc.
- Mitsubishi Electric, CNC 700/70 Series Programming Manual (Machining Center System), IB-1500072.
- Yamazaki Mazak, Programming Manual (Machining Centers) — EIA/ISO, MAZATROL SmoothAi, H747PB1000E.
- Siemens, SINUMERIK System Variables Parameter Manual and Programming Guide: Job Planning, Siemens AG.
- HEIDENHAIN, TNC 640 Klartext Programming User’s Manual, NC software 34059x-11.
- Okuma, OSP Programming Manual, Okuma Corporation; Renishaw, Inspection Plus Programming Manual, Renishaw plc.
Have a question or want to contribute?
Contact us with corrections, additions, or topics you'd like covered.
Get in Touch