Control flow basics: how a program makes decisions
Variables, conditions, IF/ELSE, loops and subprograms explained for machinists with a simple made-up language, independent of any CNC control.
A G-code program runs from top to bottom, block by block. Every value is written in the program: X50, Z-12, F200. If the part changes, the program has to be changed.
A macro program can do more. It stores values under a name, calculates new values from them, checks conditions and jumps to another part of the program depending on the result. These tools are called control flow, because they control in which order the blocks are executed.
This page explains control flow with a made-up language that looks like plain English. It does not run on any machine. The goal is to understand the ideas first. The real syntax for each control comes later in the series and only changes the spelling.
Variables
A variable is a storage place with a name and a value. Think of a labeled drawer: the label says DEPTH, inside lies the number 12.
SET depth = 12
SET feed = 250
SET diameter = 8
Wherever the program needs the value, it uses the name. When the drawer gets a new value, every line that uses the name works with the new value.
MOVE_FEED Z = -depth F = feed
On most CNC controls a variable has a number instead of a name, for example #100. The idea stays the same.
Calculating
Variables can be combined with arithmetic. The result goes into a variable again.
SET radius = diameter / 2
SET depth_per_pass = depth / 4
SET hole_angle = 360 / number_of_holes
A line like SET count = count + 1 looks strange at first. Read it from right to left: take the current value of count, add 1, put the result back into count. This is how a program counts.
Typical functions are available as well: square root, sine and cosine for bolt circles, rounding, absolute value.
Conditions
A condition is a question with the answer yes or no. It compares two values.
| Comparison | Meaning |
|---|---|
| a = b | a is equal to b |
| a <> b | a is not equal to b |
| a > b | a is greater than b |
| a >= b | a is greater than or equal to b |
| a < b | a is smaller than b |
| a <= b | a is smaller than or equal to b |
Two conditions can be linked. AND means both must be true. OR means at least one must be true.
diameter > 6 AND diameter < 12
tool_length < 50 OR tool_length > 250
IF and THEN: do something only when needed
The simplest decision: when the condition is true, the lines between IF and END IF run. Otherwise the program skips them.
IF depth > 30 THEN
SET peck = 3
END IF
Deep holes get a peck depth of 3 mm. For shallow holes nothing changes.
IF, THEN and ELSE: choose between two ways
With ELSE the program always does one of two things.
IF material = STEEL THEN
SET speed = 1200
ELSE
SET speed = 3500
END IF
More than two cases are handled by putting decisions one after the other, or one inside the other:
IF diameter <= 6 THEN
SET feed = 120
ELSE IF diameter <= 12 THEN
SET feed = 180
ELSE
SET feed = 220
END IF
The program checks from top to bottom and takes the first case that fits.
Checking inputs and stopping with a message
Conditions are the main safety tool in macros. Before a cycle moves the machine, it checks that the values make sense.
IF depth <= 0 THEN
ALARM "DEPTH MUST BE POSITIVE"
END IF
An alarm stops the machine and shows the text to the operator. It is much better to stop here than to find out after the tool has crashed.
WHILE: repeat as long as a condition is true
A loop repeats a group of lines. The WHILE loop checks its condition before every round. As soon as the condition is false, the program continues after END WHILE.
SET current_depth = 0
WHILE current_depth < depth DO
SET current_depth = current_depth + peck
IF current_depth > depth THEN
SET current_depth = depth
END IF
MOVE_FEED Z = -current_depth
MOVE_RAPID Z = 2
END WHILE
This is a peck drilling cycle: drill one peck deeper, retract, repeat until the final depth is reached. The IF inside the loop makes sure the last peck does not go below the final depth.
A loop needs something inside that changes the condition. If current_depth never grew, the loop would run forever. On a machine this means a program that never ends or a tool that keeps moving. Check every loop for this before running it.
FOR: repeat a fixed number of times
When the number of repetitions is known, a counting loop is easier to read. The counter starts at the first value, goes up by one each round and stops after the last value.
FOR hole = 1 TO 6
SET angle = start_angle + (hole - 1) * 60
SET x = center_x + radius * COS(angle)
SET y = center_y + radius * SIN(angle)
DRILL_AT x, y
END FOR
Six holes on a bolt circle, one every 60°. Many CNC controls have no FOR loop. You then build it from a WHILE loop and a counter:
SET hole = 1
WHILE hole <= 6 DO
...
SET hole = hole + 1
END WHILE
Both versions do exactly the same.
GOTO: jump to a label
Older NC macro languages have no END IF and no ELSE. They use jumps instead. A label marks a line, GOTO continues the program at that label.
IF depth <= 30 THEN GOTO no_peck
SET peck = 3
LABEL no_peck
This does the same as the first IF example. Jumps work, but many of them make a program hard to follow, because the reader has to look up and down for the labels. Use structured loops and IF blocks when the control offers them, and keep jumps short and simple.
Subprograms with parameters
A subprogram is a piece of program with its own name that can be called from anywhere. Parameters are values handed over at the call. Inside the subprogram they work like normal variables.
SUBPROGRAM bolt_circle(center_x, center_y, radius, holes, start_angle)
SET angle_step = 360 / holes
SET hole = 1
WHILE hole <= holes DO
SET angle = start_angle + (hole - 1) * angle_step
DRILL_AT center_x + radius * COS(angle), center_y + radius * SIN(angle)
SET hole = hole + 1
END WHILE
END SUBPROGRAM
CALL bolt_circle(0, 0, 40, 6, 0)
CALL bolt_circle(150, 0, 25, 4, 45)
The main program now only says what it wants: a bolt circle here, another one there. How the holes are calculated sits in one place. A fix in the subprogram fixes every call. This is exactly what a custom cycle on a CNC control is.
Local and shared variables
A variable that only exists inside a subprogram is local. When the subprogram ends, it disappears, and it cannot disturb variables of the same name elsewhere. A shared (global) variable is visible everywhere and keeps its value between calls. Shared variables are useful for values that several programs need, such as a part counter. They are also a common source of errors, because any program can overwrite them.
Summary of the building blocks
| Building block | Use in the shop |
|---|---|
| Variable | Dimensions, feeds and counters that change between parts |
| Arithmetic | Positions on a bolt circle, depth per pass, speed from cutting speed |
| IF / ELSE | Different values for different sizes or materials, input checks |
| Alarm | Stop with a clear message when a value is wrong |
| WHILE | Repeat until a depth or a size is reached |
| FOR / counter | Fixed number of holes, passes or parts |
| GOTO | Jumps in controls without structured IF blocks |
| Subprogram | Own cycles that work for many parts |
The next page, Macros and computer code, shows the same building blocks in Python and in NC macro syntax side by side.