Subroutine G-Code

Offsets G52 and Subroutine M98 and M99

There are a number of ways to use free or inexpensive 2D or 2.5D software to cut deeper or thicker stock than would be allowed with the single pass that is generated with the software.
Mach3 has a Z offset function that lowers the Z axis on each successive pass.
This function is straightforward and is described in the Mach3 manual.
A simple way to lower the Z on each pass is to move the Z axis to a lower level by hand, and to then repeat the cut.
The router's software does not know that the Z's height was changed, so the router cuts at a deeper level while thinking that it is at the original level.
A similar method is to jog the Z axis lower and to re-zero the software to the new position before each new pass.
Like the previous method, this also requires that the operator be available to reset the table at the end of each pass.
Another way to lower the Z on each pass is the subroutine below. It requires editing the g-code, but once edited the entire cutting process is automatic. There is no need to manually set the Z to a new depth at the end of every run.
Note: With any of these methods it is important for the original clearance plane to be high enough to prevent the router from cutting into the stock as it is offset downward. Offsets require careful attention.
This subroutine g-code can also be used to repeat any section of the g-code. Therefore, it is not limited to just the Z axis.

This is very handy for making a set of identical parts without having to code each component for a specific location in the stock.

In the right image, one part was designed to be milled from flat bar. The subroutine was used to duplicate this single pattern.
The cuts in the spoil board show the repeating pattern.

Note that this shape was also designed to interlock with its neighbor, so one cut could define two edges. This saves lots of mill time and stock.

Repeating one pattern.
The following description is based on the triangle pattern shown here.
This is a simple subroutine that offsets the Z axis 1/10 inch deeper on each repeat, from 0.1 to 0.5 inches below the surface plane which is 0.

The original 2D or 2.5D g-code for one layer of the triangle is in the bottom section of the g-code below. It is in this color  in the left column. This original g-code becomes the subroutine that is to be repeated.

The g-codes' background colors match the descriptions on the right.

Triangles for g-code.
G00 Z1
Rapid move of Z to 1
Rapid of X to zero and Y to zero
M3 M7 F50 Spindle ON clockwise, coolant (or vacuum etc) ON, feed-rate of 50 inches (mm) per minute
All of the above is the standard beginning of a simple run.
The following is the Offset g-code
G52 Z -0.1

Offset Z by negative 1/10 inch
The axis will not move but the DRO (Digital Read-Out)
will advance from 
Z of 1. (from Z position moved to above)  to 1.1
 See Note 1 at page bottom.
M98 P1

Call subroutine named "1"   This is the original g-code; it is in this color below
The router cuts the triangle and the controlling software returns to the following line;
the process is repeated.
G52 Z -.2 Offset Z by negative 2/10 inch
M98 P1

Call subroutine named "1"
The router cuts again and repeats the process after each M98 below
G52 Z -.3 Offset Z by negative 3/10 inch
M98 P1 Call subroutine named "1"
G52 Z -.4 Offset Z by negative 4/10 inch
M98 P1 Call subroutine named "1"
G52 Z -.5 Offset Z by negative 5/10 inch
M98 P1 Call subroutine named "1"
G52 Z0 Offset Z by 0 ( that is, clear the offset; set things back to normal ) see Note 2
G00 Z1 Rapid to Z 1
M30 End and rewind
O1 Letter "O" defines the beginning of subroutine"1" is the label or name of the subroutine.
The following is the triangle's g-code that is to be repeated.
G01 Z0   go to Z0
G01  Y3  go to Y3  this is the vertical leg of the triangle
G01 X2 Y0 go to 2,0  this is the diagonal leg of the triangle
G01 X0 Y0 go to 0,0  this is the bottom leg of the triangle

End Subroutine and return to the line following the M98 that called it.
This will repeat until there are no more M98s; the controller will read the remaining code until reaching M30.

Note 1) Though it may seem counter intuitive, when the offset is negative the DRO gains the amount, and when the offset is positive the DRO loses the offset's amount.
It may help to envision the process as tricking the software into thinking that the router is higher (or lower) than it really is.

Note 2) It is important to clear the offsets at the end of a run, otherwise the software will retain the offsets until they are manually cleared. (Which I remember to do just as the mill plows the table bed.)

The following is the g-code described above.
It can be copied and pasted into Notepad and then opened and run with Mach3. Watching it run line by line will add clarity.

G00 Z1
G00 X0 Y0
M3 M7 F50
G52 Z -0.1
M98 P1
G52 Z -.2
M98 P1
G52 Z -.3
M98 P1
G52 Z -.4
M98 P1
G52 Z -.5
M98 P1
G52 Z0
G00 Z1
G01 Z0
G01 Y3
G01 X2 Y0
G01 X0 Y0

Make sure to hit the Enter key after the M99 when the code is pasted into Notepad. Without that keystroke Mach3 will not read the M99 line.