Download src/Mod/CAM/Path/Post/scripts/grbl_legacy_post.py from AbdulElahGwaith/FreeCAD: direct link, hf CLI and curl.
- Browser
- Download file 26.2 kB
-
https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/CAM/Path/Post/scripts/grbl_legacy_post.py
- Command line
-
hf download hf://AbdulElahGwaith/FreeCAD/src/Mod/CAM/Path/Post/scripts/grbl_legacy_post.py
-
curl -L -o grbl_legacy_post.py https://huggingface.co/AbdulElahGwaith/FreeCAD/resolve/main/src/Mod/CAM/Path/Post/scripts/grbl_legacy_post.py
26.2 kB
| # *************************************************************************** | |
| # * Copyright (c) 2014 sliptonic <shopinthewoods@gmail.com> * | |
| # * Copyright (c) 2018, 2019 Gauthier Briere * | |
| # * Copyright (c) 2019, 2020 Schildkroet * | |
| # * * | |
| # * This file is part of the FreeCAD CAx development system. * | |
| # * * | |
| # * This program is free software; you can redistribute it and/or modify * | |
| # * it under the terms of the GNU Lesser General Public License (LGPL) * | |
| # * as published by the Free Software Foundation; either version 2 of * | |
| # * the License, or (at your option) any later version. * | |
| # * for detail see the LICENCE text file. * | |
| # * * | |
| # * FreeCAD is distributed in the hope that it will be useful, * | |
| # * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
| # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
| # * GNU Lesser General Public License for more details. * | |
| # * * | |
| # * You should have received a copy of the GNU Library General Public * | |
| # * License along with FreeCAD; if not, write to the Free Software * | |
| # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * | |
| # * USA * | |
| # * * | |
| # *************************************************************************** | |
| import FreeCAD | |
| from FreeCAD import Units | |
| import Path | |
| import Path.Base.Util as PathUtil | |
| import Path.Post.Utils as PostUtils | |
| import PathScripts.PathUtils as PathUtils | |
| import argparse | |
| import datetime | |
| import shlex | |
| import re | |
| from builtins import open as pyopen | |
| TOOLTIP = """ | |
| Generate g-code from a Path that is compatible with the grbl controller. | |
| import grbl_legacy_post | |
| grbl_legacy_post.export(object, "/path/to/file.ncc") | |
| """ | |
| # *************************************************************************** | |
| # * Globals set customization preferences | |
| # *************************************************************************** | |
| # Default values for command line arguments: | |
| OUTPUT_COMMENTS = True # default output of comments in output gCode file | |
| OUTPUT_HEADER = True # default output header in output gCode file | |
| OUTPUT_LINE_NUMBERS = False # default doesn't output line numbers in output gCode file | |
| OUTPUT_BCNC = False # default doesn't add bCNC operation block headers in output gCode file | |
| SHOW_EDITOR = True # default show the resulting file dialog output in GUI | |
| PRECISION = 3 # Default precision for metric (see http://linuxcnc.org/docs/2.7/html/gcode/overview.html#_g_code_best_practices) | |
| TRANSLATE_DRILL_CYCLES = True # If true, G81, G82 & G83 are translated in G0/G1 moves | |
| PREAMBLE = """G17 G90 | |
| """ # default preamble text will appear at the beginning of the gCode output file. | |
| POSTAMBLE = """M5 | |
| G17 G90 | |
| M2 | |
| """ # default postamble text will appear following the last operation. | |
| SPINDLE_WAIT = 0 # no waiting after M3 / M4 by default | |
| RETURN_TO = None # no movements after end of program | |
| # Customisation with no command line argument | |
| MODAL = False # if true commands are suppressed if the same as previous line. | |
| LINENR = 100 # line number starting value | |
| LINEINCR = 10 # line number increment | |
| OUTPUT_TOOL_CHANGE = ( | |
| False # default don't output M6 tool changes (comment it) as grbl currently does not handle it | |
| ) | |
| DRILL_RETRACT_MODE = ( | |
| "G98" # Default value of drill retractations (CURRENT_Z) other possible value is G99 | |
| ) | |
| MOTION_MODE = "G90" # G90 for absolute moves, G91 for relative | |
| UNITS = "G21" # G21 for metric, G20 for us standard | |
| UNIT_FORMAT = "mm" | |
| UNIT_SPEED_FORMAT = "mm/min" | |
| PRE_OPERATION = """""" # Pre operation text will be inserted before every operation | |
| POST_OPERATION = """""" # Post operation text will be inserted after every operation | |
| TOOL_CHANGE = """""" # Tool Change commands will be inserted before a tool change | |
| # *************************************************************************** | |
| # * End of customization | |
| # *************************************************************************** | |
| # Parser arguments list & definition | |
| parser = argparse.ArgumentParser(prog="grbl", add_help=False) | |
| parser.add_argument("--comments", action="store_true", help="output comment (default)") | |
| parser.add_argument("--no-comments", action="store_true", help="suppress comment output") | |
| parser.add_argument("--header", action="store_true", help="output headers (default)") | |
| parser.add_argument("--no-header", action="store_true", help="suppress header output") | |
| parser.add_argument("--line-numbers", action="store_true", help="prefix with line numbers") | |
| parser.add_argument( | |
| "--no-line-numbers", | |
| action="store_true", | |
| help="don't prefix with line numbers (default)", | |
| ) | |
| parser.add_argument( | |
| "--show-editor", | |
| action="store_true", | |
| help="pop up editor before writing output (default)", | |
| ) | |
| parser.add_argument( | |
| "--no-show-editor", | |
| action="store_true", | |
| help="don't pop up editor before writing output", | |
| ) | |
| parser.add_argument("--precision", default="3", help="number of digits of precision, default=3") | |
| parser.add_argument( | |
| "--translate_drill", | |
| action="store_true", | |
| help="translate drill cycles G81, G82 & G83 in G0/G1 movements", | |
| ) | |
| parser.add_argument( | |
| "--no-translate_drill", | |
| action="store_true", | |
| help="don't translate drill cycles G81, G82 & G83 in G0/G1 movements (default)", | |
| ) | |
| parser.add_argument( | |
| "--preamble", | |
| help='set commands to be issued before the first command, default="G17 G90\\n"', | |
| ) | |
| parser.add_argument( | |
| "--postamble", | |
| help='set commands to be issued after the last command, default="M5\\nG17 G90\\nM2\\n"', | |
| ) | |
| parser.add_argument( | |
| "--inches", action="store_true", help="Convert output for US imperial mode (G20)" | |
| ) | |
| parser.add_argument("--tool-change", action="store_true", help="Insert M6 for all tool changes") | |
| parser.add_argument( | |
| "--wait-for-spindle", | |
| type=int, | |
| default=0, | |
| help="Wait for spindle to reach desired speed after M3 / M4, default=0", | |
| ) | |
| parser.add_argument( | |
| "--return-to", | |
| default="", | |
| help="Move to the specified coordinates at the end, e.g. --return-to=0,0", | |
| ) | |
| parser.add_argument( | |
| "--bcnc", | |
| action="store_true", | |
| help="Add Job operations as bCNC block headers. Consider suppressing existing comments: Add argument --no-comments", | |
| ) | |
| parser.add_argument( | |
| "--no-bcnc", action="store_true", help="suppress bCNC block header output (default)" | |
| ) | |
| TOOLTIP_ARGS = parser.format_help() | |
| # *************************************************************************** | |
| # * Internal global variables | |
| # *************************************************************************** | |
| MOTION_COMMANDS = [ | |
| "G0", | |
| "G00", | |
| "G1", | |
| "G01", | |
| "G2", | |
| "G02", | |
| "G3", | |
| "G03", | |
| ] # Motion gCode commands definition | |
| RAPID_MOVES = ["G0", "G00"] # Rapid moves gCode commands definition | |
| SUPPRESS_COMMANDS = [] # These commands are ignored by commenting them out | |
| COMMAND_SPACE = " " | |
| # Global variables storing current position | |
| CURRENT_X = 0 | |
| CURRENT_Y = 0 | |
| CURRENT_Z = 0 | |
| def processArguments(argstring): | |
| global OUTPUT_HEADER | |
| global OUTPUT_COMMENTS | |
| global OUTPUT_LINE_NUMBERS | |
| global SHOW_EDITOR | |
| global PRECISION | |
| global PREAMBLE | |
| global POSTAMBLE | |
| global UNITS | |
| global UNIT_SPEED_FORMAT | |
| global UNIT_FORMAT | |
| global TRANSLATE_DRILL_CYCLES | |
| global OUTPUT_TOOL_CHANGE | |
| global SPINDLE_WAIT | |
| global RETURN_TO | |
| global OUTPUT_BCNC | |
| try: | |
| args = parser.parse_args(shlex.split(argstring)) | |
| if args.no_header: | |
| OUTPUT_HEADER = False | |
| if args.header: | |
| OUTPUT_HEADER = True | |
| if args.no_comments: | |
| OUTPUT_COMMENTS = False | |
| if args.comments: | |
| OUTPUT_COMMENTS = True | |
| if args.no_line_numbers: | |
| OUTPUT_LINE_NUMBERS = False | |
| if args.line_numbers: | |
| OUTPUT_LINE_NUMBERS = True | |
| if args.no_show_editor: | |
| SHOW_EDITOR = False | |
| if args.show_editor: | |
| SHOW_EDITOR = True | |
| PRECISION = args.precision | |
| if args.preamble is not None: | |
| PREAMBLE = args.preamble.replace("\\n", "\n") | |
| if args.postamble is not None: | |
| POSTAMBLE = args.postamble.replace("\\n", "\n") | |
| if args.no_translate_drill: | |
| TRANSLATE_DRILL_CYCLES = False | |
| if args.translate_drill: | |
| TRANSLATE_DRILL_CYCLES = True | |
| if args.inches: | |
| UNITS = "G20" | |
| UNIT_SPEED_FORMAT = "in/min" | |
| UNIT_FORMAT = "in" | |
| PRECISION = 4 | |
| if args.tool_change: | |
| OUTPUT_TOOL_CHANGE = True | |
| if args.wait_for_spindle > 0: | |
| SPINDLE_WAIT = args.wait_for_spindle | |
| if args.return_to != "": | |
| RETURN_TO = [int(v) for v in args.return_to.split(",")] | |
| if len(RETURN_TO) != 2: | |
| RETURN_TO = None | |
| print("--return-to coordinates must be specified as <x>,<y>, ignoring") | |
| if args.bcnc: | |
| OUTPUT_BCNC = True | |
| if args.no_bcnc: | |
| OUTPUT_BCNC = False | |
| except Exception as e: | |
| return False | |
| return True | |
| # For debug... | |
| def dump(obj): | |
| for attr in dir(obj): | |
| print("obj.%s = %s" % (attr, getattr(obj, attr))) | |
| def export(objectslist, filename, argstring): | |
| if not processArguments(argstring): | |
| return None | |
| global UNITS | |
| global UNIT_FORMAT | |
| global UNIT_SPEED_FORMAT | |
| global MOTION_MODE | |
| global SUPPRESS_COMMANDS | |
| print("Post Processor: " + __name__ + " postprocessing...") | |
| gcode = "" | |
| # write header | |
| if OUTPUT_HEADER: | |
| gcode += linenumber() + "(Exported by FreeCAD)\n" | |
| gcode += linenumber() + "(Post Processor: " + __name__ + ")\n" | |
| gcode += linenumber() + "(Output Time:" + str(datetime.datetime.now()) + ")\n" | |
| # Check canned cycles for drilling | |
| if TRANSLATE_DRILL_CYCLES: | |
| if len(SUPPRESS_COMMANDS) == 0: | |
| SUPPRESS_COMMANDS = ["G99", "G98", "G80"] | |
| else: | |
| SUPPRESS_COMMANDS += ["G99", "G98", "G80"] | |
| # Write the preamble | |
| if OUTPUT_COMMENTS: | |
| gcode += linenumber() + "(Begin preamble)\n" | |
| for line in PREAMBLE.splitlines(): | |
| gcode += linenumber() + line + "\n" | |
| # verify if PREAMBLE have changed MOTION_MODE or UNITS | |
| if "G90" in PREAMBLE: | |
| MOTION_MODE = "G90" | |
| elif "G91" in PREAMBLE: | |
| MOTION_MODE = "G91" | |
| else: | |
| gcode += linenumber() + MOTION_MODE + "\n" | |
| if "G21" in PREAMBLE: | |
| UNITS = "G21" | |
| UNIT_FORMAT = "mm" | |
| UNIT_SPEED_FORMAT = "mm/min" | |
| elif "G20" in PREAMBLE: | |
| UNITS = "G20" | |
| UNIT_FORMAT = "in" | |
| UNIT_SPEED_FORMAT = "in/min" | |
| else: | |
| gcode += linenumber() + UNITS + "\n" | |
| for obj in objectslist: | |
| # Debug... | |
| # print("\n" + "*"*70) | |
| # dump(obj) | |
| # print("*"*70 + "\n") | |
| if not hasattr(obj, "Path"): | |
| print( | |
| "The object " + obj.Name + " is not a path. Please select only path and Compounds." | |
| ) | |
| return | |
| # Skip inactive operations | |
| if not PathUtil.activeForOp(obj): | |
| continue | |
| # do the pre_op | |
| if OUTPUT_BCNC: | |
| gcode += linenumber() + "(Block-name: " + obj.Label + ")\n" | |
| gcode += linenumber() + "(Block-expand: 0)\n" | |
| gcode += linenumber() + "(Block-enable: 1)\n" | |
| if OUTPUT_COMMENTS: | |
| gcode += linenumber() + "(Begin operation: " + obj.Label + ")\n" | |
| for line in PRE_OPERATION.splitlines(True): | |
| gcode += linenumber() + line | |
| # get coolant mode | |
| coolantMode = PathUtil.coolantModeForOp(obj) | |
| # turn coolant on if required | |
| if OUTPUT_COMMENTS: | |
| if not coolantMode == "None": | |
| gcode += linenumber() + "(Coolant On:" + coolantMode + ")\n" | |
| if coolantMode == "Flood": | |
| gcode += linenumber() + "M8" + "\n" | |
| if coolantMode == "Mist": | |
| gcode += linenumber() + "M7" + "\n" | |
| # Parse the op | |
| gcode += parse(obj) | |
| # do the post_op | |
| if OUTPUT_COMMENTS: | |
| gcode += linenumber() + "(Finish operation: " + obj.Label + ")\n" | |
| for line in POST_OPERATION.splitlines(True): | |
| gcode += linenumber() + line | |
| # turn coolant off if required | |
| if not coolantMode == "None": | |
| if OUTPUT_COMMENTS: | |
| gcode += linenumber() + "(Coolant Off:" + coolantMode + ")\n" | |
| gcode += linenumber() + "M9" + "\n" | |
| if RETURN_TO: | |
| gcode += linenumber() + "G0 X%s Y%s\n" % tuple(RETURN_TO) | |
| # do the post_amble | |
| if OUTPUT_BCNC: | |
| gcode += linenumber() + "(Block-name: post_amble)\n" | |
| gcode += linenumber() + "(Block-expand: 0)\n" | |
| gcode += linenumber() + "(Block-enable: 1)\n" | |
| if OUTPUT_COMMENTS: | |
| gcode += linenumber() + "(Begin postamble)\n" | |
| for line in POSTAMBLE.splitlines(): | |
| gcode += linenumber() + line + "\n" | |
| # show the gCode result dialog | |
| if FreeCAD.GuiUp and SHOW_EDITOR: | |
| dia = PostUtils.GCodeEditorDialog() | |
| dia.editor.setPlainText(gcode) | |
| result = dia.exec_() | |
| if result: | |
| final = dia.editor.toPlainText() | |
| else: | |
| final = gcode | |
| else: | |
| final = gcode | |
| print("Done postprocessing.") | |
| # write the file | |
| if filename != "-": | |
| with pyopen(filename, "w") as gfile: | |
| gfile.write(final) | |
| return final | |
| def linenumber(): | |
| if not OUTPUT_LINE_NUMBERS: | |
| return "" | |
| global LINENR | |
| global LINEINCR | |
| s = "N" + str(LINENR) + " " | |
| LINENR += LINEINCR | |
| return s | |
| def format_outstring(strTable): | |
| global COMMAND_SPACE | |
| # construct the line for the final output | |
| s = "" | |
| for w in strTable: | |
| s += w + COMMAND_SPACE | |
| s = s.strip() | |
| return s | |
| def parse(pathobj): | |
| global DRILL_RETRACT_MODE | |
| global MOTION_MODE | |
| global CURRENT_X | |
| global CURRENT_Y | |
| global CURRENT_Z | |
| out = "" | |
| lastcommand = None | |
| precision_string = "." + str(PRECISION) + "f" | |
| params = [ | |
| "X", | |
| "Y", | |
| "Z", | |
| "A", | |
| "B", | |
| "C", | |
| "U", | |
| "V", | |
| "W", | |
| "I", | |
| "J", | |
| "K", | |
| "F", | |
| "S", | |
| "T", | |
| "Q", | |
| "R", | |
| "L", | |
| "P", | |
| ] | |
| if hasattr(pathobj, "Group"): # We have a compound or project. | |
| if OUTPUT_COMMENTS: | |
| out += linenumber() + "(Compound: " + pathobj.Label + ")\n" | |
| for p in pathobj.Group: | |
| out += parse(p) | |
| return out | |
| else: # parsing simple path | |
| if not hasattr(pathobj, "Path"): # groups might contain non-path things like stock. | |
| return out | |
| if OUTPUT_COMMENTS: | |
| out += linenumber() + "(Path: " + pathobj.Label + ")\n" | |
| for c in PathUtils.getPathWithPlacement(pathobj).Commands: | |
| outstring = [] | |
| command = c.Name | |
| outstring.append(command) | |
| # if modal: only print the command if it is not the same as the last one | |
| if MODAL: | |
| if command == lastcommand: | |
| outstring.pop(0) | |
| # Now add the remaining parameters in order | |
| for param in params: | |
| if param in c.Parameters: | |
| if param == "F": | |
| if command not in RAPID_MOVES: | |
| speed = Units.Quantity(c.Parameters["F"], FreeCAD.Units.Velocity) | |
| if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0: | |
| outstring.append( | |
| param | |
| + format( | |
| float(speed.getValueAs(UNIT_SPEED_FORMAT)), | |
| precision_string, | |
| ) | |
| ) | |
| elif param in ["T", "H", "S"]: | |
| outstring.append(param + str(int(c.Parameters[param]))) | |
| elif param in ["D", "P", "L"]: | |
| outstring.append(param + str(c.Parameters[param])) | |
| elif param in ["A", "B", "C"]: | |
| outstring.append(param + format(c.Parameters[param], precision_string)) | |
| else: # [X, Y, Z, U, V, W, I, J, K, R, Q] (Conversion eventuelle mm/inches) | |
| pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length) | |
| outstring.append( | |
| param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string) | |
| ) | |
| # store the latest command | |
| lastcommand = command | |
| # Memorizes the current position for calculating the related movements and the withdrawal plan | |
| if command in MOTION_COMMANDS: | |
| if "X" in c.Parameters: | |
| CURRENT_X = Units.Quantity(c.Parameters["X"], FreeCAD.Units.Length) | |
| if "Y" in c.Parameters: | |
| CURRENT_Y = Units.Quantity(c.Parameters["Y"], FreeCAD.Units.Length) | |
| if "Z" in c.Parameters: | |
| CURRENT_Z = Units.Quantity(c.Parameters["Z"], FreeCAD.Units.Length) | |
| if command in ("G98", "G99"): | |
| DRILL_RETRACT_MODE = command | |
| if command in ("G90", "G91"): | |
| MOTION_MODE = command | |
| if TRANSLATE_DRILL_CYCLES: | |
| if command in ("G81", "G82", "G83"): | |
| out += drill_translate(outstring, command, c.Parameters) | |
| # Erase the line we just translated | |
| outstring = [] | |
| if SPINDLE_WAIT > 0: | |
| if command in ("M3", "M03", "M4", "M04"): | |
| out += linenumber() + format_outstring(outstring) + "\n" | |
| out += linenumber() + format_outstring(["G4", "P%s" % SPINDLE_WAIT]) + "\n" | |
| outstring = [] | |
| # Check for Tool Change: | |
| if command in ("M6", "M06"): | |
| if OUTPUT_COMMENTS: | |
| out += linenumber() + "(Begin toolchange)\n" | |
| if not OUTPUT_TOOL_CHANGE: | |
| outstring.insert(0, "(") | |
| outstring.append(")") | |
| else: | |
| for line in TOOL_CHANGE.splitlines(True): | |
| out += linenumber() + line | |
| if command == "message": | |
| if OUTPUT_COMMENTS is False: | |
| out = [] | |
| else: | |
| outstring.pop(0) # remove the command | |
| if command in SUPPRESS_COMMANDS: | |
| outstring.insert(0, "(") | |
| outstring.append(")") | |
| # prepend a line number and append a newline | |
| if len(outstring) >= 1: | |
| out += linenumber() + format_outstring(outstring) + "\n" | |
| # Check for comments containing machine-specific commands to pass literally to the controller | |
| m = re.match(r"^\(MC_RUN_COMMAND: ([^)]+)\)$", command) | |
| if m: | |
| raw_command = m.group(1) | |
| out += linenumber() + raw_command + "\n" | |
| return out | |
| def drill_translate(outstring, cmd, params): | |
| global DRILL_RETRACT_MODE | |
| global MOTION_MODE | |
| global CURRENT_X | |
| global CURRENT_Y | |
| global CURRENT_Z | |
| global UNITS | |
| global UNIT_FORMAT | |
| global UNIT_SPEED_FORMAT | |
| strFormat = "." + str(PRECISION) + "f" | |
| trBuff = "" | |
| if OUTPUT_COMMENTS: # Comment the original command | |
| outstring[0] = "(" + outstring[0] | |
| outstring[-1] = outstring[-1] + ")" | |
| trBuff += linenumber() + format_outstring(outstring) + "\n" | |
| # cycle conversion | |
| # currently only cycles in XY are provided (G17) | |
| # other plains ZX (G18) and YZ (G19) are not dealt with : Z drilling only. | |
| param_X = Units.Quantity(params["X"], FreeCAD.Units.Length) | |
| param_Y = Units.Quantity(params["Y"], FreeCAD.Units.Length) | |
| param_Z = Units.Quantity(params["Z"], FreeCAD.Units.Length) | |
| param_R = Units.Quantity(params["R"], FreeCAD.Units.Length) | |
| # R less than Z is error | |
| if param_R < param_Z: | |
| trBuff += linenumber() + "(drill cycle error: R less than Z )\n" | |
| return trBuff | |
| if MOTION_MODE == "G91": # G91 relative movements, (not generated by CAM WB drilling) | |
| param_X += CURRENT_X | |
| param_Y += CURRENT_Y | |
| param_Z += CURRENT_Z | |
| param_R += param_Z | |
| # NIST-RS274 | |
| # 3.5.20 Set Canned Cycle Return Level — G98 and G99 | |
| # When the spindle retracts during canned cycles, there is a choice of how far it retracts: (1) retract | |
| # perpendicular to the selected plane to the position indicated by the R word, or (2) retract | |
| # perpendicular to the selected plane to the position that axis was in just before the canned cycle | |
| # started (unless that position is lower than the position indicated by the R word, in which case use | |
| # the R word position). | |
| # To use option (1), program G99. To use option (2), program G98. Remember that the R word has | |
| # different meanings in absolute distance mode and incremental distance mode. | |
| # """ | |
| if DRILL_RETRACT_MODE == "G99": | |
| clear_Z = param_R | |
| if DRILL_RETRACT_MODE == "G98" and CURRENT_Z >= param_R: | |
| clear_Z = CURRENT_Z | |
| else: | |
| clear_Z = param_R | |
| strG0_clear_Z = "G0 Z" + format(float(clear_Z.getValueAs(UNIT_FORMAT)), strFormat) + "\n" | |
| strG0_param_R = "G0 Z" + format(float(param_R.getValueAs(UNIT_FORMAT)), strFormat) + "\n" | |
| # get the other parameters | |
| drill_feedrate = Units.Quantity(params["F"], FreeCAD.Units.Velocity) | |
| strF_Feedrate = " F" + format(float(drill_feedrate.getValueAs(UNIT_SPEED_FORMAT)), ".2f") + "\n" | |
| if cmd == "G83": | |
| drill_Step = Units.Quantity(params["Q"], FreeCAD.Units.Length) | |
| a_bit = ( | |
| drill_Step * 0.05 | |
| ) # NIST 3.5.16.4 G83 Cycle: "current hole bottom, backed off a bit." | |
| elif cmd == "G82": | |
| drill_DwellTime = params["P"] | |
| # wrap this block to ensure machine MOTION_MODE is restored in case of error | |
| try: | |
| if MOTION_MODE == "G91": | |
| trBuff += linenumber() + "G90\n" # force absolute coordinates during cycles | |
| # NIST-RS274 | |
| # 3.5.16.1 Preliminary and In-Between Motion | |
| # At the very beginning of the execution of any of the canned cycles, with the XY-plane selected, if | |
| # the current Z position is below the R position, the Z-axis is traversed to the R position. This | |
| # happens only once, regardless of the value of L. | |
| # In addition, at the beginning of the first cycle and each repeat, the following one or two moves are | |
| # made: | |
| # 1. a straight traverse parallel to the XY-plane to the given XY-position, | |
| # 2. a straight traverse of the Z-axis only to the R position, if it is not already at the R position. | |
| if CURRENT_Z < param_R: | |
| trBuff += linenumber() + strG0_param_R | |
| trBuff += ( | |
| linenumber() | |
| + "G0 X" | |
| + format(float(param_X.getValueAs(UNIT_FORMAT)), strFormat) | |
| + " Y" | |
| + format(float(param_Y.getValueAs(UNIT_FORMAT)), strFormat) | |
| + "\n" | |
| ) | |
| if CURRENT_Z > param_R: | |
| trBuff += linenumber() + strG0_param_R | |
| last_Stop_Z = param_R | |
| # drill moves | |
| if cmd in ("G81", "G82"): | |
| trBuff += ( | |
| linenumber() | |
| + "G1 Z" | |
| + format(float(param_Z.getValueAs(UNIT_FORMAT)), strFormat) | |
| + strF_Feedrate | |
| ) | |
| # pause where applicable | |
| if cmd == "G82": | |
| trBuff += linenumber() + "G4 P" + str(drill_DwellTime) + "\n" | |
| trBuff += linenumber() + strG0_clear_Z | |
| else: # 'G83' | |
| if params["Q"] != 0: | |
| while 1: | |
| if last_Stop_Z != clear_Z: | |
| clearance_depth = ( | |
| last_Stop_Z + a_bit | |
| ) # rapid move to just short of last drilling depth | |
| trBuff += ( | |
| linenumber() | |
| + "G0 Z" | |
| + format( | |
| float(clearance_depth.getValueAs(UNIT_FORMAT)), | |
| strFormat, | |
| ) | |
| + "\n" | |
| ) | |
| next_Stop_Z = last_Stop_Z - drill_Step | |
| if next_Stop_Z > param_Z: | |
| trBuff += ( | |
| linenumber() | |
| + "G1 Z" | |
| + format(float(next_Stop_Z.getValueAs(UNIT_FORMAT)), strFormat) | |
| + strF_Feedrate | |
| ) | |
| trBuff += linenumber() + strG0_clear_Z | |
| last_Stop_Z = next_Stop_Z | |
| else: | |
| trBuff += ( | |
| linenumber() | |
| + "G1 Z" | |
| + format(float(param_Z.getValueAs(UNIT_FORMAT)), strFormat) | |
| + strF_Feedrate | |
| ) | |
| trBuff += linenumber() + strG0_clear_Z | |
| break | |
| except Exception as e: | |
| pass | |
| if MOTION_MODE == "G91": | |
| trBuff += linenumber() + "G91" # Restore if changed | |
| return trBuff | |
| # print(__name__ + ": GCode postprocessor loaded.") | |