Rectangle Pocket with radius corners and tool offset (G41) G-code Creator

Rectangle Diagram

This program will create G-code for a more complex rectangular pocket based on the parameters you input.

It uses G41 for cutter compensation, which means the tool will be compensated to the left of the programmed path. This is useful for ensuring the correct pocket dimensions when using a tool with a specific diameter. you can also specify corner radii, must be larger that the tool radius.

The generated code will have two subroutines. One for roughing out the pocket without tool compensation, and a second for finishing with G41 tool compensation on. The finish program will start and finish on one of the longer sides of the pocket.


















Generated G-code:

Disclaimer: All CNC toolpaths and G‑code generated or displayed by this tool must be reviewed and verified by the machine operator before use. TAM‑CNC and its developers accept no liability for machine damage, material loss, or personal injury resulting from improper use.

import js from pyscript import display # Global variable for decimal places, will be set by input Deci = 3 def fmt(v): # Use the global Deci variable for formatting return f"{v:.{Deci}f}" def generate_g41_rect_pocket_gcode(event): try: # --- Input Parameters --- tool_no = js.document.getElementById("rpg-tool-no").value tool_dia = float(js.document.getElementById("rpg-tool-dia").value) tool_rad = (tool_dia / 2) # Get decimal places from input and set the global variable global Deci Deci = int(js.document.getElementById("rpg-deci").value) wrk_ofset = js.document.getElementById("rpg-work-offset").value spdle_rpm = js.document.getElementById("rpg-spindle-rpm").value x_pos = float(js.document.getElementById("rpg-x-position").value) y_pos = float(js.document.getElementById("rpg-y-position").value) finish = float(js.document.getElementById("rpg-finish-cut").value) z_rapid = float(js.document.getElementById("rpg-z-rapid").value) z_start = float(js.document.getElementById("rpg-z-start").value) tz_cut = float(js.document.getElementById("rpg-tz-cut").value) z_depth = float(js.document.getElementById("rpg-z-depth").value) nosteps = int(z_depth / tz_cut) if tz_cut > 0 else 1 z_cut = z_depth / nosteps if nosteps > 0 else z_depth x_dist = float(js.document.getElementById("rpg-x-distance").value) y_dist = float(js.document.getElementById("rpg-y-distance").value) con_rad = float(js.document.getElementById("rpg-corner-radius").value) step_over = float(js.document.getElementById("rpg-step-over").value) step_over_val = (step_over / 100) * tool_dia # Renamed to avoid conflict with input name feedrate = float(js.document.getElementById("rpg-feed-rate").value) # --- Calculate Values --- x_cut = ((x_dist / 2)) y_cut = ((y_dist / 2)) # Replicating original Python logic for SideStep, Xcis, Ycis, ConStep if x_cut == y_cut: side_step = int(x_cut / step_over_val) if step_over_val > 0 else 1 xcis = (x_cut - finish - tool_rad) / side_step if side_step > 0 else 0 ycis = (y_cut - finish - tool_rad) / side_step if side_step > 0 else 0 constep = (con_rad - tool_rad) / side_step if side_step > 0 else 0 elif x_cut > y_cut: side_step = int(x_cut / step_over_val) if step_over_val > 0 else 1 xcis = (x_cut - finish - tool_rad) / side_step if side_step > 0 else 0 ycis = (y_cut - finish - tool_rad) / side_step if side_step > 0 else 0 constep = (con_rad - tool_rad) / side_step if side_step > 0 else 0 else: # y_cut > x_cut side_step = int(y_cut / step_over_val) if step_over_val > 0 else 1 ycis = (y_cut - finish - tool_rad) / side_step if side_step > 0 else 0 xcis = (x_cut - finish - tool_rad) / side_step if side_step > 0 else 0 constep = (con_rad - tool_rad) / side_step if side_step > 0 else 0 # Ensure side_step is at least 1 if dimensions are positive and calculations resulted in 0 steps if (x_cut > 0 or y_cut > 0) and side_step == 0: side_step = 1 xcis = x_cut - finish - tool_rad ycis = y_cut - finish - tool_rad constep = con_rad - tool_rad xcis = float(xcis) ycis = float(ycis) side_step = int(side_step) # --- G-Code Generation --- gcode_lines = [] gcode_lines.append("%") # Program Start gcode_lines.append("M97 P8000") gcode_lines.append("G21 (G21 for millimeters, G20 for inches)") gcode_lines.append("M05") gcode_lines.append(f"T{tool_no} M06") gcode_lines.append(f"M03 S{spdle_rpm}") gcode_lines.append(f"G{wrk_ofset}") gcode_lines.append("G40") gcode_lines.append("G98 G17") # --- Initial Rapid Move --- gcode_lines.append(f"G00 X{fmt(x_pos + step_over_val/2)} Y{fmt(y_pos)}") gcode_lines.append(f"G{wrk_ofset} G00 Z{fmt(z_rapid)} G43 H{tool_no} M08") gcode_lines.append(f"G01 Z{fmt(z_start)} F{fmt(feedrate / 2)}") gcode_lines.append(f"G91 G02 I-{fmt(step_over_val/2)} Z-{fmt(z_cut/2)} L{2*nosteps} F{fmt(feedrate / 2)}") gcode_lines.append(f"G02 I-{fmt(step_over_val/2)}") gcode_lines.append("G90 G01 X" + fmt(x_pos)) gcode_lines.append("G01 Z" + fmt(z_start) + " F" + fmt(feedrate)) gcode_lines.append(f"M97 P701 L{nosteps}") gcode_lines.append("G01 Z" + fmt(z_start)) # Conditional calls to subroutines based on pocket dimensions if y_cut > x_cut: gcode_lines.append("G01 X" + fmt(x_pos + x_cut - tool_dia) + " Y" + fmt(y_pos)) gcode_lines.append("M97 P702 L" + str(nosteps)) elif x_cut > y_cut: gcode_lines.append("G01 X" + fmt(x_pos) + " Y" + fmt(y_pos + y_cut - tool_dia)) gcode_lines.append("M97 P703 L" + str(nosteps)) else: # x_cut == y_cut gcode_lines.append("G01 X" + fmt(x_pos) + " Y" + fmt(y_pos + y_cut - tool_dia)) gcode_lines.append("M97 P703 L" + str(nosteps)) gcode_lines.append("G00 Z" + fmt(z_rapid) + " M09") gcode_lines.append("M05") gcode_lines.append("M97 P8000") gcode_lines.append("M30") # --- Pocketing Subroutine --- gcode_lines.append("\nN701") gcode_lines.append(f"G91 G01 Z-{fmt(z_cut)} F{fmt(feedrate / 2)}") gcode_lines.append(f"F{fmt(feedrate)}") gcode_lines.append("G90") gcode_lines.append(f"G01 X{fmt(x_pos + xcis)}") for i in range(2, side_step + 1): x_step = xcis * i y_step = ycis * i c_step = constep * i gcode_lines.append(f"G01 X{fmt(x_pos + x_step)}") gcode_lines.append(f"G01 Y{fmt(y_pos + y_step - c_step)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_step - c_step)} Y{fmt(y_pos + y_step)} I-{fmt(c_step)}") gcode_lines.append(f"G01 X{fmt(x_pos - x_step + c_step)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_step)} Y{fmt(y_pos + y_step - c_step)} J-{fmt(c_step)}") gcode_lines.append(f"G01 Y{fmt(y_pos - y_step + c_step)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_step + c_step)} Y{fmt(y_pos - y_step)} I+{fmt(c_step)}") gcode_lines.append(f"G01 X{fmt(x_pos + x_step - c_step)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_step)} Y{fmt(y_pos - y_step + c_step)} J+{fmt(c_step)}") gcode_lines.append(f"G01 Y{fmt(y_pos)}") gcode_lines.append("G01 X" + fmt(x_pos) + " Y" + fmt(y_pos)) gcode_lines.append("M99") #End of Subroutine # --- Corner Finishing Subroutine N702 --- if y_cut > x_cut: gcode_lines.append("\nN702") gcode_lines.append(f"G91 G01 Z-{fmt(z_cut)} F{fmt(feedrate / 2)}") gcode_lines.append(f"F{fmt(feedrate)}") gcode_lines.append("G90") gcode_lines.append(f"G41 D{tool_no} G01 Y{fmt(y_pos - tool_dia)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut)} Y{fmt(y_pos)} I0 J{fmt(tool_dia)}") gcode_lines.append(f"G01 Y{fmt(y_pos + y_cut - con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut - con_rad)} Y{fmt(y_pos + y_cut)} I-{fmt(con_rad)} J0") gcode_lines.append(f"G01 X{fmt(x_pos - x_cut + con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_cut)} Y{fmt(y_pos + y_cut - con_rad)} I0 J-{fmt(con_rad)}") gcode_lines.append(f"G01 Y{fmt(y_pos - y_cut + con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_cut + con_rad)} Y{fmt(y_pos - y_cut)} I{fmt(con_rad)} J0") gcode_lines.append(f"G01 X{fmt(x_pos + x_cut - con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut)} Y{fmt(y_pos - y_cut + con_rad)} I0 J{fmt(con_rad)}") gcode_lines.append(f"G01 Y{fmt(y_pos)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut - tool_dia)} Y{fmt(y_pos + tool_dia)} I-{fmt(tool_dia)} J0") gcode_lines.append(f"G40 G01 X{fmt(x_pos + x_cut - tool_dia)} Y{fmt(y_pos)}") gcode_lines.append("M99") #End of Subroutine # --- Corner Finishing Subroutine N703 --- if x_cut > y_cut: gcode_lines.append("\nN703") gcode_lines.append(f"G91 G01 Z-{fmt(z_cut)} F{fmt(feedrate / 2)}") gcode_lines.append(f"F{fmt(feedrate)}") gcode_lines.append("G90") gcode_lines.append(f"G41 D{tool_no} G01 X{fmt(x_pos + tool_dia)}") gcode_lines.append(f"G03 X{fmt(x_pos)} Y{fmt(y_pos + y_cut)} I-{fmt(tool_dia)} J0") gcode_lines.append(f"G01 X{fmt(x_pos - x_cut + con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_cut)} Y{fmt(y_pos + y_cut - con_rad)} I0 J-{fmt(con_rad)}") gcode_lines.append(f"G01 Y{fmt(y_pos - y_cut + con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_cut + con_rad)} Y{fmt(y_pos - y_cut)} I{fmt(con_rad)} J0") gcode_lines.append(f"G01 X{fmt(x_pos + x_cut - con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut)} Y{fmt(y_pos - y_cut + con_rad)} I0 J{fmt(con_rad)}") gcode_lines.append(f"G01 Y{fmt(y_pos + y_cut - con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut - con_rad)} Y{fmt(y_pos + y_cut)} I-{fmt(con_rad)} J0") gcode_lines.append(f"G01 X{fmt(x_pos)}") gcode_lines.append(f"G03 X{fmt(x_pos - tool_dia)} Y{fmt(y_pos + y_cut - tool_dia)} I0 J-{fmt(tool_dia)}") gcode_lines.append(f"G40 G01 X{fmt(x_pos)} Y{fmt(y_pos + y_cut - tool_dia)}") gcode_lines.append("M99") #End of Subroutine # --- Corner Finishing Subroutine N703 --- if x_cut == y_cut: gcode_lines.append("\nN703") gcode_lines.append(f"G91 G01 Z-{fmt(z_cut)} F{fmt(feedrate / 2)}") gcode_lines.append(f"F{fmt(feedrate)}") gcode_lines.append("G90") gcode_lines.append(f"G41 D{tool_no} G01 X{fmt(x_pos + tool_dia)}") gcode_lines.append(f"G03 X{fmt(x_pos)} Y{fmt(y_pos + y_cut)} I-{fmt(tool_dia)} J0") gcode_lines.append(f"G01 X{fmt(x_pos - x_cut + con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_cut)} Y{fmt(y_pos + y_cut - con_rad)} I0 J-{fmt(con_rad)}") gcode_lines.append(f"G01 Y{fmt(y_pos - y_cut + con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos - x_cut + con_rad)} Y{fmt(y_pos - y_cut)} I{fmt(con_rad)} J0") gcode_lines.append(f"G01 X{fmt(x_pos + x_cut - con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut)} Y{fmt(y_pos - y_cut + con_rad)} I0 J{fmt(con_rad)}") gcode_lines.append(f"G01 Y{fmt(y_pos + y_cut - con_rad)}") gcode_lines.append(f"G03 X{fmt(x_pos + x_cut - con_rad)} Y{fmt(y_pos + y_cut)} I-{fmt(con_rad)} J0") gcode_lines.append(f"G01 X{fmt(x_pos)}") gcode_lines.append(f"G03 X{fmt(x_pos - tool_dia)} Y{fmt(y_pos + y_cut - tool_dia)} I0 J-{fmt(tool_dia)}") gcode_lines.append(f"G40 G01 X{fmt(x_pos)} Y{fmt(y_pos + y_cut - tool_dia)}") gcode_lines.append("M99") #End of Subroutine # --- Program End Subroutine --- gcode_lines.append("\nN8000") gcode_lines.append("G00 G90 M09") gcode_lines.append("G53 G00 G40 Z0") gcode_lines.append("G53 G00 G40 X0 Y0") gcode_lines.append("M01") gcode_lines.append("M99") gcode_lines.append("%") # Program End output_element = js.document.querySelector("#rpg-gcode-output pre code") output_element.innerText = "\n".join(gcode_lines) except Exception as e: output_element = js.document.querySelector("#rpg-gcode-output pre code") output_element.innerText = f"Error generating G-code: {str(e)}\nPlease check your input values." # Placeholder for the function definition itself, as py-click handles the event. pass