diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fef9af6..5e466a63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ CHANGELOG for FlatCAM beta ================================================= +19.01.2022 + +- updated the header of the postprocessos with 'laser' to show essential informations like some of them do not move on the Z axis +- make sure that the laser postprocessor that do move on the Z axis (like 'GRBL_laser_Z') accept negative values for the Z focus +- fixed issue in highlighter such that the keywords that have an underscore included are highlighted +- rearranged the default keywords +- fixed the generatecncjob() method default parameters to reflect new data structure names +- in Geometry object the default self.options dictionary is updated with keys that reflect new data structure + 18.01.2022 - in the 'cutout' Tcl command made sure that when an error pop-up then it returns with a "fail" string diff --git a/appGUI/GUIElements.py b/appGUI/GUIElements.py index 924e8440..2a616758 100644 --- a/appGUI/GUIElements.py +++ b/appGUI/GUIElements.py @@ -4681,7 +4681,7 @@ class FCTextAreaLineNumber(QtWidgets.QFrame): # parameter brush = QtGui.QBrush(Qt.GlobalColor.darkBlue, Qt.BrushStyle.SolidPattern) - pattern = QtCore.QRegularExpression("\-[0-9a-zA-Z]*\s") + pattern = QtCore.QRegularExpression("\-[0-9a-zA-Z_]*\s") parameterOperator.setForeground(brush) parameterOperator.setFontWeight(QtGui.QFont.Weight.Bold) rule = (pattern, parameterOperator) diff --git a/appObjects/FlatCAMGeometry.py b/appObjects/FlatCAMGeometry.py index ad49e958..75ee79b8 100644 --- a/appObjects/FlatCAMGeometry.py +++ b/appObjects/FlatCAMGeometry.py @@ -58,34 +58,34 @@ class GeometryObject(FlatCAMObj, Geometry): "plot": True, "multicolored": False, - "cutz": -0.002, - "vtipdia": 0.1, - "vtipangle": 30, - "travelz": 0.1, - "feedrate": 5.0, - "feedrate_z": 5.0, - "feedrate_rapid": 5.0, - "spindlespeed": 0, - "dwell": True, - "dwelltime": 1000, - "multidepth": False, - "depthperpass": 0.002, - "extracut": False, - "extracut_length": 0.1, - "endz": 2.0, - "endxy": '', - "area_exclusion": False, - "area_shape": "polygon", - "area_strategy": "over", - "area_overz": 1.0, + "tools_mill_cutz": -0.002, + "tools_mill_vtipdia": 0.1, + "tools_mill_vtipangle": 30, + "tools_mill_travelz": 0.1, + "tools_mill_feedrate": 5.0, + "tools_mill_feedrate_z": 5.0, + "tools_mill_feedrate_rapid": 5.0, + "tools_mill_spindlespeed": 0, + "tools_mill_dwell": True, + "tools_mill_dwelltime": 1000, + "tools_mill_multidepth": False, + "tools_mill_depthperpass": 0.002, + "tools_mill_extracut": False, + "tools_mill_extracut_length": 0.1, + "tools_mill_endz": 2.0, + "tools_mill_endxy": '', + "tools_mill_area_exclusion": False, + "tools_mill_area_shape": "polygon", + "tools_mill_area_strategy": "over", + "tools_mill_area_overz": 1.0, - "startz": None, - "toolchange": False, - "toolchangez": 1.0, - "toolchangexy": "0.0, 0.0", - "ppname_g": 'default', - "z_pdepth": -0.02, - "feedrate_probe": 3.0, + "tools_mill_startz": None, + "tools_mill_toolchange": False, + "tools_mill_toolchangez": 1.0, + "tools_mill_toolchangexy": "0.0, 0.0", + "tools_mill_ppname_g": 'default', + "tools_mill_z_pdepth": -0.02, + "tools_mill_feedrate_probe": 3.0, }) if "tools_mill_tooldia" not in self.options: @@ -128,12 +128,12 @@ class GeometryObject(FlatCAMObj, Geometry): # flag to store if the V-Shape tool is selected in self.ui.geo_tools_table self.v_tool_type = None - # flag to store if the Geometry is type 'multi-geometry' meaning that each tool has it's own geometry + # flag to store if the Geometry is type 'multi-geometry' meaning that each tool has its own geometry # the default value is False self.multigeo = False # flag to store if the geometry is part of a special group of geometries that can't be processed by the default - # engine of FlatCAM. Most likely are generated by some of tools and are special cases of geometries. + # engine of FlatCAM. Most likely are generated by some tools and are special cases of geometries. self.special_group = None # self.old_pp_state = self.app.defaults["tools_mill_multidepth"] @@ -1011,52 +1011,56 @@ class GeometryObject(FlatCAMObj, Geometry): :return: None """ + self.app.log.debug("FlatCAMGeometry.generatecncjob()") + tooldia = dia if dia else float(self.options["tools_mill_tooldia"]) outname = outname if outname is not None else self.options["name"] - z_cut = z_cut if z_cut is not None else float(self.options["cutz"]) - z_move = z_move if z_move is not None else float(self.options["travelz"]) + z_cut = z_cut if z_cut is not None else float(self.options["tools_mill_cutz"]) + z_move = z_move if z_move is not None else float(self.options["tools_mill_travelz"]) - feedrate = feedrate if feedrate is not None else float(self.options["feedrate"]) - feedrate_z = feedrate_z if feedrate_z is not None else float(self.options["feedrate_z"]) - feedrate_rapid = feedrate_rapid if feedrate_rapid is not None else float(self.options["feedrate_rapid"]) + feedrate = feedrate if feedrate is not None else float(self.options["tools_mill_feedrate"]) + feedrate_z = feedrate_z if feedrate_z is not None else float(self.options["tools_mill_feedrate_z"]) + feedrate_rapid = feedrate_rapid if feedrate_rapid is not None else float(self.options[ + "tools_mill_feedrate_rapid"]) - multidepth = multidepth if multidepth is not None else self.options["multidepth"] - depthperpass = dpp if dpp is not None else float(self.options["depthperpass"]) + multidepth = multidepth if multidepth is not None else self.options["tools_mill_multidepth"] + depthperpass = dpp if dpp is not None else float(self.options["tools_mill_depthperpass"]) segx = segx if segx is not None else float(self.app.defaults['geometry_segx']) segy = segy if segy is not None else float(self.app.defaults['geometry_segy']) - extracut = extracut if extracut is not None else float(self.options["extracut"]) - extracut_length = extracut_length if extracut_length is not None else float(self.options["extracut_length"]) + extracut = extracut if extracut is not None else float(self.options["tools_mill_extracut"]) + extracut_length = extracut_length if extracut_length is not None else float(self.options[ + "tools_mill_extracut_length"]) - startz = startz if startz is not None else self.options["startz"] - endz = endz if endz is not None else float(self.options["endz"]) + startz = startz if startz is not None else self.options["tools_mill_startz"] + endz = endz if endz is not None else float(self.options["tools_mill_endz"]) - endxy = endxy if endxy else self.options["endxy"] + endxy = endxy if endxy else self.options["tools_mill_endxy"] if isinstance(endxy, str): endxy = re.sub('[()\[\]]', '', endxy) if endxy and endxy != '': endxy = [float(eval(a)) for a in endxy.split(",")] - toolchangez = toolchangez if toolchangez else float(self.options["toolchangez"]) + toolchangez = toolchangez if toolchangez else float(self.options["tools_mill_toolchangez"]) - toolchangexy = toolchangexy if toolchangexy else self.options["toolchangexy"] + toolchangexy = toolchangexy if toolchangexy else self.options["tools_mill_toolchangexy"] if isinstance(toolchangexy, str): toolchangexy = re.sub('[()\[\]]', '', toolchangexy) if toolchangexy and toolchangexy != '': toolchangexy = [float(eval(a)) for a in toolchangexy.split(",")] - toolchange = toolchange if toolchange else self.options["toolchange"] + toolchange = toolchange if toolchange else self.options["tools_mill_toolchange"] offset = offset if offset else 0.0 # int or None. - spindlespeed = spindlespeed if spindlespeed else self.options['spindlespeed'] - dwell = dwell if dwell else self.options["dwell"] - dwelltime = dwelltime if dwelltime else float(self.options["dwelltime"]) + spindlespeed = spindlespeed if spindlespeed else self.options['tools_mill_spindlespeed'] + dwell = dwell if dwell else self.options["tools_mill_dwell"] + dwelltime = dwelltime if dwelltime else float(self.options["tools_mill_dwelltime"]) - ppname_g = pp if pp else self.options["ppname_g"] + ppname_g = pp if pp else self.options["tools_mill_ppname_g"] # Object initialization function for app.app_obj.new_object() # RUNNING ON SEPARATE THREAD! @@ -1065,6 +1069,7 @@ class GeometryObject(FlatCAMObj, Geometry): # Propagate options job_obj.options["tooldia"] = tooldia + job_obj.options["tools_mill_tooldia"] = tooldia job_obj.coords_decimals = self.app.defaults["cncjob_coords_decimals"] job_obj.fr_decimals = self.app.defaults["cncjob_fr_decimals"] @@ -1075,8 +1080,8 @@ class GeometryObject(FlatCAMObj, Geometry): job_obj.segx = segx job_obj.segy = segy - job_obj.z_pdepth = float(self.options["z_pdepth"]) - job_obj.feedrate_probe = float(self.options["feedrate_probe"]) + job_obj.z_pdepth = float(self.options["tools_mill_z_pdepth"]) + job_obj.feedrate_probe = float(self.options["tools_mill_feedrate_probe"]) job_obj.options['xmin'] = self.options['xmin'] job_obj.options['ymin'] = self.options['ymin'] diff --git a/appPlugins/ToolMilling.py b/appPlugins/ToolMilling.py index 05f8867f..7cdbb74f 100644 --- a/appPlugins/ToolMilling.py +++ b/appPlugins/ToolMilling.py @@ -2972,6 +2972,8 @@ class ToolMilling(AppTool, Excellon): :return: None """ + self.app.log.debug("ToolMilling.mtool_gen_cncjob()") + geo_obj = geo_obj if geo_obj is not None else self.target_obj # use the name of the first tool selected in self.geo_tools_table which has the diameter passed as tool_dia diff --git a/app_Main.py b/app_Main.py index e2faa552..f51edcb6 100644 --- a/app_Main.py +++ b/app_Main.py @@ -642,17 +642,20 @@ class App(QtCore.QObject): 'version', 'write_gcode' ] - self.default_keywords = ['Desktop', 'Documents', 'FlatConfig', 'FlatPrj', 'False', 'Marius', 'My Documents', - 'Paste_1', - 'Repetier', 'Roland_MDX_20', 'Users', 'Toolchange_Custom', 'Toolchange_Probe_MACH3', - 'Toolchange_manual', 'True', 'Users', + self.default_keywords = ['Berta_CNC', 'Default_no_M6', 'Desktop', 'Documents', 'FlatConfig', 'FlatPrj', + 'False', 'GRBL_11', 'GRL_11_no_M6', 'GRBL_laser', 'grbl_laser_eleks_drd', + 'GRBL_laser_Z', 'ISEL_CNC', 'ISEL_ICP_CNC', 'Line_xyz', 'Marlin', + 'Marlin_laser_FAN_pin', 'Marlin_laser_Spindle_pin', 'NCCAD9', 'Marius', 'My Documents', + 'Paste_1', 'Repetier', 'Roland_MDX_20', 'Roland_MDX_540', + 'Users', 'Toolchange_Manual', 'Toolchange_Probe_MACH3', + 'True', 'Users', 'all', 'auto', 'axis', 'axisoffset', 'box', 'center_x', 'center_y', 'columns', 'combine', 'connect', 'contour', 'default', 'depthperpass', 'dia', 'diatol', 'dist', 'drilled_dias', 'drillz', 'dpp', 'dwelltime', 'extracut_length', 'endxy', 'enz', 'f', 'feedrate', 'feedrate_z', 'GRBL_11', 'GRBL_laser', 'gridoffsety', 'gridx', 'gridy', - 'has_offset', 'holes', 'hpgl', 'iso_type', 'Line_xyz', 'margin', 'marlin', 'method', + 'has_offset', 'holes', 'hpgl', 'iso_type', 'margin', 'marlin', 'method', 'milled_dias', 'minoffset', 'name', 'offset', 'opt_type', 'order', 'outname', 'overlap', 'obj_name', 'passes', 'postamble', 'pp', 'ppname_e', 'ppname_g', 'preamble', 'radius', 'ref', 'rest', 'rows', 'shellvar_', 'scale_factor', diff --git a/camlib.py b/camlib.py index 1da949bb..e7eae7b0 100644 --- a/camlib.py +++ b/camlib.py @@ -6037,22 +6037,23 @@ class CNCjob(Geometry): self.app.inform.emit('[ERROR_NOTCL] %s' % _("Travel Z parameter is None or zero.")) return 'fail' - if self.z_move < 0: - self.app.inform.emit('[WARNING] %s' % - _("The Travel Z parameter has negative value. " - "It is the height value to travel between cuts.\n" - "The Z Travel parameter needs to have a positive value, assuming it is a typo " - "therefore the app will convert the value to positive." - "Check the resulting CNC code (Gcode etc).")) - self.z_move = -self.z_move - elif self.z_move == 0: - self.app.inform.emit( - '[WARNING] %s: %s' % (_("The Z Travel parameter is zero. This is dangerous, skipping file"), - self.options['name']) - ) - return 'fail' + if 'laser' not in self.pp_geometry_name: + if self.z_move < 0: + self.app.inform.emit('[WARNING] %s' % + _("The Travel Z parameter has negative value. " + "It is the height value to travel between cuts.\n" + "The Z Travel parameter needs to have a positive value, assuming it is a typo " + "therefore the app will convert the value to positive." + "Check the resulting CNC code (Gcode etc).")) + self.z_move = -self.z_move + elif self.z_move == 0: + self.app.inform.emit( + '[WARNING] %s: %s' % (_("The Z Travel parameter is zero. This is dangerous, skipping file"), + self.options['name']) + ) + return 'fail' - # made sure that depth_per_cut is no more then the z_cut + # made sure that depth_per_cut is no more than the z_cut (travelz) try: if abs(self.z_cut) < self.z_depthpercut: self.z_depthpercut = abs(self.z_cut) diff --git a/preprocessors/GRBL_laser.py b/preprocessors/GRBL_laser.py index 29d9e33f..487000d4 100644 --- a/preprocessors/GRBL_laser.py +++ b/preprocessors/GRBL_laser.py @@ -21,7 +21,11 @@ class GRBL_laser(PreProc): def start_code(self, p): units = ' ' + str(p['units']).lower() gcode = '(This preprocessor is used with a motion controller loaded with GRBL firmware. )\n' - gcode += '(It is for the case when it is used together with a LASER connected on the SPINDLE connector.)\n\n' + gcode += '(It is for the case when it is used together with a LASER connected on the SPINDLE connector.)\n' \ + '(This preprocessor makes no moves on the Z axis it will only move horizontally.)\n' \ + '(The horizontal move is done with G0 - highest possible speed set in the GRBL controller.)\n' \ + '(It assumes a manually focused laser.)\n' \ + '(The laser is started with M3 command and stopped with the M5 command.)\n\n' xmin = '%.*f' % (p.coords_decimals, p['options']['xmin']) xmax = '%.*f' % (p.coords_decimals, p['options']['xmax']) @@ -29,10 +33,6 @@ class GRBL_laser(PreProc): ymax = '%.*f' % (p.coords_decimals, p['options']['ymax']) gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n' - gcode += '(Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n' - - gcode += '(Z Focus: ' + str(p['z_move']) + units + ')\n' - gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n' if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry': @@ -59,11 +59,10 @@ class GRBL_laser(PreProc): return 'M5' def down_code(self, p): - sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir] if p.spindlespeed: - return '%s S%s' % (sdir, str(p.spindlespeed)) + return '%s S%s' % ('M3', str(p.spindlespeed)) else: - return sdir + return 'M3' def toolchange_code(self, p): return '' @@ -88,32 +87,31 @@ class GRBL_laser(PreProc): (p.coords_decimals, x_pos, p.coords_decimals, y_pos) def rapid_code(self, p): - return ('G00 ' + self.position_code(p)).format(**p) + return ('G0 ' + self.position_code(p)).format(**p) def linear_code(self, p): - return ('G01 ' + self.position_code(p)).format(**p) + \ + return ('G1 ' + self.position_code(p)).format(**p) + \ ' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) def end_code(self, p): coords_xy = p['xy_end'] - gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n") + gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n") if coords_xy and coords_xy != '': - gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n" + gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n" return gcode def feedrate_code(self, p): - return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) + return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) def z_feedrate_code(self, p): - return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) + return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) def spindle_code(self, p): - sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir] if p.spindlespeed: - return '%s S%s' % (sdir, str(p.spindlespeed)) + return '%s S%s' % ('M3', str(p.spindlespeed)) else: - return sdir + return 'M3' def dwell_code(self, p): return '' diff --git a/preprocessors/Z_laser.py b/preprocessors/GRBL_laser_Z.py similarity index 80% rename from preprocessors/Z_laser.py rename to preprocessors/GRBL_laser_Z.py index 1e50adc8..6a1992fe 100644 --- a/preprocessors/Z_laser.py +++ b/preprocessors/GRBL_laser_Z.py @@ -3,6 +3,8 @@ # http://flatcam.org # # File Author: Matthieu Berthomé # # Date: 5/26/2017 # +# Modified: Marius Stanciu # +# Date: 01/19/2022 # # MIT Licence # # ########################################################## @@ -12,7 +14,7 @@ from appPreProcessor import * # is compatible with almost any version of Grbl. -class Z_laser(PreProc): +class GRBL_laser_Z(PreProc): include_header = True coordinate_format = "%.*f" @@ -30,10 +32,7 @@ class Z_laser(PreProc): ymax = '%.*f' % (p.coords_decimals, p['options']['ymax']) gcode += '(Feedrate: ' + str(p['feedrate']) + units + '/min' + ')\n' - gcode += '(Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + ')\n' + '\n' - gcode += '(Z Focus: ' + str(p['z_move']) + units + ')\n' - gcode += '(Steps per circle: ' + str(p['steps_per_circle']) + ')\n' if str(p['options']['type']) == 'Excellon' or str(p['options']['type']) == 'Excellon Geometry': @@ -54,20 +53,20 @@ class Z_laser(PreProc): return gcode def startz_code(self, p): - return '' + gcode = 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move) + return gcode def lift_code(self, p): return 'M5' def down_code(self, p): - sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir] if p.spindlespeed: - return '%s S%s' % (sdir, str(p.spindlespeed)) + return '%s S%s' % ('M3', str(p.spindlespeed)) else: - return sdir + return 'M3' def toolchange_code(self, p): - return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move) + return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move) def up_to_zero_code(self, p): return 'M5' @@ -89,32 +88,31 @@ class Z_laser(PreProc): (p.coords_decimals, x_pos, p.coords_decimals, y_pos) def rapid_code(self, p): - return ('G00 ' + self.position_code(p)).format(**p) + return ('G0 ' + self.position_code(p)).format(**p) def linear_code(self, p): - return ('G01 ' + self.position_code(p)).format(**p) + \ + return ('G1 ' + self.position_code(p)).format(**p) + \ ' F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) def end_code(self, p): coords_xy = p['xy_end'] - gcode = ('G00 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n") + gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + "\n") if coords_xy and coords_xy != '': - gcode += 'G00 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n" + gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + "\n" return gcode def feedrate_code(self, p): - return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) + return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) def z_feedrate_code(self, p): - return 'G01 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) + return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) def spindle_code(self, p): - sdir = {'CW': 'M03', 'CCW': 'M04'}[p.spindledir] if p.spindlespeed: - return '%s S%s' % (sdir, str(p.spindlespeed)) + return '%s S%s' % ('M3', str(p.spindlespeed)) else: - return sdir + return 'M3' def dwell_code(self, p): return '' diff --git a/preprocessors/grbl_laser_eleks_drd.py b/preprocessors/grbl_laser_eleks_drd.py index c6586dd4..99242cfe 100644 --- a/preprocessors/grbl_laser_eleks_drd.py +++ b/preprocessors/grbl_laser_eleks_drd.py @@ -23,7 +23,13 @@ class grbl_laser_eleks_drd(PreProc): def start_code(self, p): units = ' ' + str(p['units']).lower() gcode = '(This preprocessor is made to work with Laser cutters.)\n' - gcode += '(It allows movement on the Z axis.)\n\n' + gcode += '(This post processor is configured to output code for)\n' + gcode += '(lasers without Z Axis and to convert excellon drillcodes into arcs.)\n' + gcode += '(Therefore after etching we have small holes in the copper plane)\n' + gcode += '(which helps for centering the drill bit for manual drilling)\n' + gcode += '(The GRBL Controller has to support G2 commands)\n' + gcode += '(The moves are only on horizontal plane X-Y. There are no Z moves.)\n' + gcode += '(Assumes manual laser focussing.)\n\n' xmin = '%.*f' % (p.coords_decimals, p['options']['xmin']) xmax = '%.*f' % (p.coords_decimals, p['options']['xmax']) @@ -101,7 +107,7 @@ class grbl_laser_eleks_drd(PreProc): def toolchange_code(self, p): return ';toolchange' - def up_to_zero_code(self, p): # Only use for drilling, so no essentialy need for Laser + def up_to_zero_code(self, p): # Only use for drilling, so no essential need for Laser return ';up_to_zero' def position_code(self, p): diff --git a/tclCommands/TclCommandCncjob.py b/tclCommands/TclCommandCncjob.py index 2d7836c0..2dd70bcc 100644 --- a/tclCommands/TclCommandCncjob.py +++ b/tclCommands/TclCommandCncjob.py @@ -134,10 +134,16 @@ class TclCommandCncjob(TclCommandSignaled): args["z_move"] = args["z_move"] if "z_move" in args and args["z_move"] else \ self.app.defaults["geometry_travelz"] + args["pp"] = args["pp"] if "pp" in args and args["pp"] else self.app.defaults["tools_mill_ppname_g"] + args["feedrate"] = args["feedrate"] if "feedrate" in args and args["feedrate"] else \ self.app.defaults["tools_mill_feedrate"] - args["feedrate_z"] = args["feedrate_z"] if "feedrate_z" in args and args["feedrate_z"] else \ - self.app.defaults["tools_mill_feedrate_z"] + + if 'laser' in args["pp"] and "feedrate_z" not in args: + args["feedrate_z"] = args["feedrate"] + else: + args["feedrate_z"] = args["feedrate_z"] if "feedrate_z" in args and args["feedrate_z"] else \ + self.app.defaults["tools_mill_feedrate_z"] args["feedrate_rapid"] = args["feedrate_rapid"] if "feedrate_rapid" in args and args["feedrate_rapid"] else \ self.app.defaults["tools_mill_feedrate_rapid"] @@ -188,8 +194,6 @@ class TclCommandCncjob(TclCommandSignaled): args["dwell"] = self.app.defaults["tools_mill_dwell"] args["dwelltime"] = self.app.defaults["tools_mill_dwelltime"] - args["pp"] = args["pp"] if "pp" in args and args["pp"] else self.app.defaults["tools_mill_ppname_g"] - if "toolchangez" in args: args["toolchange"] = True if args["toolchangez"] is not None: