From 9911402c959ef16e41ff834112766bb04ac213a9 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Sat, 8 Feb 2020 18:01:32 +0200 Subject: [PATCH] - added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser' - modified the Geometry UI when using laser preprocessors --- FlatCAMApp.py | 4 +- FlatCAMObj.py | 123 +++++++++++++++++++++++-- README.md | 7 +- camlib.py | 75 +++++++-------- flatcamGUI/ObjectUI.py | 80 ++++++++-------- flatcamGUI/PreferencesUI.py | 20 ++-- preprocessors/{marlin.py => Marlin.py} | 4 +- preprocessors/Marlin_laser.py | 122 ++++++++++++++++++++++++ preprocessors/grbl_laser.py | 8 +- 9 files changed, 336 insertions(+), 107 deletions(-) rename preprocessors/{marlin.py => Marlin.py} (98%) create mode 100644 preprocessors/Marlin_laser.py diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 3f0d9086..9189e8f8 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -1291,7 +1291,7 @@ class App(QtCore.QObject): "excellon_drillz": self.ui.excellon_defaults_form.excellon_opt_group.cutz_entry, "excellon_travelz": self.ui.excellon_defaults_form.excellon_opt_group.travelz_entry, "excellon_endz": self.ui.excellon_defaults_form.excellon_opt_group.eendz_entry, - "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_entry, + "excellon_feedrate": self.ui.excellon_defaults_form.excellon_opt_group.feedrate_z_entry, "excellon_spindlespeed": self.ui.excellon_defaults_form.excellon_opt_group.spindlespeed_entry, "excellon_dwell": self.ui.excellon_defaults_form.excellon_opt_group.dwell_cb, "excellon_dwelltime": self.ui.excellon_defaults_form.excellon_opt_group.dwelltime_entry, @@ -1361,7 +1361,7 @@ class App(QtCore.QObject): "geometry_cutz": self.ui.geometry_defaults_form.geometry_opt_group.cutz_entry, "geometry_travelz": self.ui.geometry_defaults_form.geometry_opt_group.travelz_entry, "geometry_feedrate": self.ui.geometry_defaults_form.geometry_opt_group.cncfeedrate_entry, - "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.cncplunge_entry, + "geometry_feedrate_z": self.ui.geometry_defaults_form.geometry_opt_group.feedrate_z_entry, "geometry_spindlespeed": self.ui.geometry_defaults_form.geometry_opt_group.cncspindlespeed_entry, "geometry_dwell": self.ui.geometry_defaults_form.geometry_opt_group.dwell_cb, "geometry_dwelltime": self.ui.geometry_defaults_form.geometry_opt_group.dwelltime_entry, diff --git a/FlatCAMObj.py b/FlatCAMObj.py index e9982564..fdc45475 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -2804,7 +2804,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): "solid": self.ui.solid_cb, "drillz": self.ui.cutz_entry, "travelz": self.ui.travelz_entry, - "feedrate": self.ui.feedrate_entry, + "feedrate": self.ui.feedrate_z_entry, "feedrate_rapid": self.ui.feedrate_rapid_entry, "tooldia": self.ui.tooldia_entry, "slot_tooldia": self.ui.slot_tooldia_entry, @@ -2978,12 +2978,14 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): self.ui.mill_type_radio.show() self.ui.mill_dia_label.show() self.ui.mill_dia_entry.show() - self.ui.mpass_cb.show() - self.ui.maxdepth_entry.show() self.ui.frxylabel.show() self.ui.xyfeedrate_entry.show() self.ui.extracut_cb.show() self.ui.e_cut_entry.show() + + if 'laser' not in self.ui.pp_excellon_name_cb.get_value().lower(): + self.ui.mpass_cb.show() + self.ui.maxdepth_entry.show() else: self.ui.mill_type_label.hide() self.ui.mill_type_radio.hide() @@ -3464,6 +3466,59 @@ class FlatCAMExcellon(FlatCAMObj, Excellon): self.ui.feedrate_rapid_label.hide() self.ui.feedrate_rapid_entry.hide() + if 'laser' in current_pp.lower(): + self.ui.cutzlabel.hide() + self.ui.cutz_entry.hide() + try: + self.ui.mpass_cb.hide() + self.ui.maxdepth_entry.hide() + except AttributeError: + pass + + self.ui.travelzlabel.setText('%s:' % _("Focus Z")) + + try: + self.ui.frzlabel.hide() + self.ui.feedrate_z_entry.hide() + except AttributeError: + pass + self.ui.dwell_cb.hide() + self.ui.dwelltime_entry.hide() + + self.ui.spindle_label.setText('%s:' % _("Laser Power")) + + try: + self.ui.tool_offset_label.hide() + self.ui.offset_entry.hide() + except AttributeError: + pass + else: + self.ui.cutzlabel.show() + self.ui.cutz_entry.show() + try: + self.ui.mpass_cb.show() + self.ui.maxdepth_entry.show() + except AttributeError: + pass + + self.ui.travelzlabel.setText('%s:' % _('Travel Z')) + + try: + self.ui.frzlabel.show() + self.ui.feedrate_z_entry.show() + except AttributeError: + pass + self.ui.dwell_cb.show() + self.ui.dwelltime_entry.show() + + self.ui.spindle_label.setText('%s:' % _('Spindle speed')) + + try: + self.ui.tool_offset_lbl.show() + self.ui.offset_entry.show() + except AttributeError: + pass + def on_create_cncjob_button_click(self, *args): self.app.report_usage("excellon_on_create_cncjob_button") self.read_form() @@ -4026,7 +4081,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): "vtipangle": self.ui.tipangle_entry, "travelz": self.ui.travelz_entry, "feedrate": self.ui.cncfeedrate_entry, - "feedrate_z": self.ui.cncplunge_entry, + "feedrate_z": self.ui.feedrate_z_entry, "feedrate_rapid": self.ui.cncfeedrate_rapid_entry, "spindlespeed": self.ui.cncspindlespeed_entry, "dwell": self.ui.dwell_cb, @@ -5178,6 +5233,59 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): self.ui.fr_rapidlabel.hide() self.ui.cncfeedrate_rapid_entry.hide() + if 'laser' in current_pp.lower(): + self.ui.cutzlabel.hide() + self.ui.cutz_entry.hide() + try: + self.ui.mpass_cb.hide() + self.ui.maxdepth_entry.hide() + except AttributeError: + pass + + self.ui.travelzlabel.setText('%s:' % _("Focus Z")) + + try: + self.ui.frzlabel.hide() + self.ui.feedrate_z_entry.hide() + except AttributeError: + pass + self.ui.dwell_cb.hide() + self.ui.dwelltime_entry.hide() + + self.ui.spindle_label.setText('%s:' % _("Laser Power")) + + try: + self.ui.tool_offset_label.hide() + self.ui.offset_entry.hide() + except AttributeError: + pass + else: + self.ui.cutzlabel.show() + self.ui.cutz_entry.show() + try: + self.ui.mpass_cb.show() + self.ui.maxdepth_entry.show() + except AttributeError: + pass + + self.ui.travelzlabel.setText('%s:' % _('Travel Z')) + + try: + self.ui.frzlabel.show() + self.ui.feedrate_z_entry.show() + except AttributeError: + pass + self.ui.dwell_cb.show() + self.ui.dwelltime_entry.show() + + self.ui.spindle_label.setText('%s:' % _('Spindle speed')) + + try: + self.ui.tool_offset_lbl.show() + self.ui.offset_entry.show() + except AttributeError: + pass + def on_generatecnc_button_click(self, *args): log.debug("Generating CNCJob from Geometry ...") self.app.report_usage("geometry_on_generatecnc_button") @@ -6783,7 +6891,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): try: for key in self.cnc_tools: ppg = self.cnc_tools[key]['data']['ppname_g'] - if ppg == 'marlin' or ppg == 'Repetier': + if 'marlin' in ppg.lower() or 'repetier' in ppg.lower() : marlin = True break if ppg == 'hpgl': @@ -6797,7 +6905,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): pass try: - if self.options['ppname_e'] == 'marlin' or self.options['ppname_e'] == 'Repetier': + if 'marlin' in self.options['ppname_e'].lower() or 'repetier' in self.options['ppname_e'].lower(): marlin = True except KeyError: # log.debug("FlatCAMCNCJob.gcode_header(): --> There is no such self.option: %s" % str(e)) @@ -7150,8 +7258,7 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): _("The used preprocessor file has to have in it's name: " "'toolchange_custom'")) except KeyError: - self.app.inform.emit('[ERROR] %s' % - _("There is no preprocessor file.")) + self.app.inform.emit('[ERROR] %s' % _("There is no preprocessor file.")) def get_gcode(self, preamble='', postamble=''): # we need this to be able get_gcode separatelly for shell command export_gcode diff --git a/README.md b/README.md index 2728cc8b..38b752bc 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing. ================================================= +8.02.2020 + +- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser' +- modified the Geometry UI when using laser preprocessors + 5.02.2020 - Modified the Distance Tool such that the Measure button can't be clicked while measuring is in progress @@ -583,7 +588,7 @@ CAD program, and create G-Code for Isolation routing. 16.11.2019 -- fixed issue #341 that affected both postprocessors that have inlined feedrate: marlin and repetier. THe used feedrate was the Feedrate X-Y and instead had to be Feedrate Z. +- fixed issue #341 that affected both postprocessors that have inlined feedrate: marlin and repetier. The used feedrate was the Feedrate X-Y and instead had to be Feedrate Z. 15.11.2019 diff --git a/camlib.py b/camlib.py index 9eaa8ab8..217e3ef5 100644 --- a/camlib.py +++ b/camlib.py @@ -3299,7 +3299,7 @@ class CNCjob(Geometry): # ## Iterate over geometry paths getting the nearest each time. log.debug("Starting G-Code...") - self.app.inform.emit(_("Starting G-Code...")) + self.app.inform.emit('%s...' % _("Starting G-Code")) path_count = 0 current_pt = (0, 0) @@ -3381,12 +3381,9 @@ class CNCjob(Geometry): self.gcode += self.doformat(p.spindle_stop_code) self.gcode += self.doformat(p.lift_code, x=current_pt[0], y=current_pt[1]) self.gcode += self.doformat(p.end_code, x=0, y=0) - self.app.inform.emit('%s... %s %s.' % - (_("Finished G-Code generation"), - str(path_count), - _("paths traced") - ) - ) + self.app.inform.emit( + '%s... %s %s.' % (_("Finished G-Code generation"), str(path_count), _("paths traced")) + ) return self.gcode def generate_from_geometry_2( @@ -3418,8 +3415,7 @@ class CNCjob(Geometry): """ if not isinstance(geometry, Geometry): - self.app.inform.emit('[ERROR] %s: %s' % - (_("Expected a Geometry, got"), type(geometry))) + self.app.inform.emit('[ERROR] %s: %s' % (_("Expected a Geometry, got"), type(geometry))) return 'fail' log.debug("Executing camlib.CNCJob.generate_from_geometry_2()") @@ -3465,10 +3461,11 @@ class CNCjob(Geometry): # if the offset is less than half of the total length or less than half of the total width of the # solid geometry it's obvious we can't do the offset if -offset > ((c - a) / 2) or -offset > ((d - b) / 2): - self.app.inform.emit('[ERROR_NOTCL] %s' % _( - "The Tool Offset value is too negative to use " - "for the current_geometry.\n" - "Raise the value (in module) and try again.")) + self.app.inform.emit( + '[ERROR_NOTCL] %s' % + _("The Tool Offset value is too negative to use for the current_geometry.\n" + "Raise the value (in module) and try again.") + ) return 'fail' # hack: make offset smaller by 0.0000000001 which is insignificant difference but allow the job # to continue @@ -3532,9 +3529,11 @@ class CNCjob(Geometry): else: self.xy_toolchange = [float(eval(a)) for a in toolchangexy.split(",")] if len(self.xy_toolchange) < 2: - self.app.inform.emit('[ERROR] %s' % - _("The Toolchange X,Y field in Edit -> Preferences has to be " - "in the format (x, y) \nbut now there is only one value, not two. ")) + self.app.inform.emit( + '[ERROR] %s' % + _("The Toolchange X,Y field in Edit -> Preferences has to be in the format (x, y) \n" + "but now there is only one value, not two. ") + ) return 'fail' except Exception as e: log.debug("camlib.CNCJob.generate_from_geometry_2() --> %s" % str(e)) @@ -3545,9 +3544,10 @@ class CNCjob(Geometry): if self.machinist_setting == 0: if self.z_cut is None: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("Cut_Z parameter is None or zero. Most likely a bad combinations of " - "other parameters.")) + self.app.inform.emit( + '[ERROR_NOTCL] %s' % _("Cut_Z parameter is None or zero. Most likely a bad combinations of " + "other parameters.") + ) return 'fail' if self.z_cut > 0: @@ -3559,14 +3559,14 @@ class CNCjob(Geometry): "Check the resulting CNC code (Gcode etc).")) self.z_cut = -self.z_cut elif self.z_cut == 0: - self.app.inform.emit('[WARNING] %s: %s' % - (_("The Cut Z parameter is zero. There will be no cut, skipping file"), - geometry.options['name'])) + self.app.inform.emit( + '[WARNING] %s: %s' % (_("The Cut Z parameter is zero. There will be no cut, skipping file"), + geometry.options['name']) + ) return 'fail' if self.z_move is None: - self.app.inform.emit('[ERROR_NOTCL] %s' % - _("Travel Z parameter is None or zero.")) + self.app.inform.emit('[ERROR_NOTCL] %s' % _("Travel Z parameter is None or zero.")) return 'fail' if self.z_move < 0: @@ -3578,9 +3578,10 @@ class CNCjob(Geometry): "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'])) + 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 @@ -3663,7 +3664,7 @@ class CNCjob(Geometry): # Iterate over geometry paths getting the nearest each time. log.debug("Starting G-Code...") - self.app.inform.emit(_("Starting G-Code...")) + self.app.inform.emit('%s...' % _("Starting G-Code")) # variables to display the percentage of work done geo_len = len(flat_geometry) @@ -3674,9 +3675,7 @@ class CNCjob(Geometry): current_tooldia = float('%.*f' % (self.decimals, float(self.tooldia))) self.app.inform.emit( - '%s: %s%s.' % (_("Starting G-Code for tool with diameter"), - str(current_tooldia), - str(self.units)) + '%s: %s%s.' % (_("Starting G-Code for tool with diameter"), str(current_tooldia), str(self.units)) ) path_count = 0 @@ -3859,13 +3858,9 @@ class CNCjob(Geometry): pass log.debug("Finishing SolderPste G-Code... %s paths traced." % path_count) - self.app.inform.emit('%s... %s %s' % - (_("Finished SolderPste G-Code generation"), - str(path_count), - _("paths traced.") - ) - ) - + self.app.inform.emit( + '%s... %s %s' % (_("Finished SolderPste G-Code generation"), str(path_count), _("paths traced.")) + ) # Finish self.gcode += self.doformat(p.lift_code) @@ -4064,9 +4059,9 @@ class CNCjob(Geometry): command['X'] = float(match_lsr.group(1).replace(" ", "")) command['Y'] = float(match_lsr.group(2).replace(" ", "")) - match_lsr_pos = re.search(r"^(M0[3-5])", gline) + match_lsr_pos = re.search(r"^(M0?[3-5])", gline) if match_lsr_pos: - if 'M05' in match_lsr_pos.group(1): + if 'M05' in match_lsr_pos.group(1) or 'M5' in match_lsr_pos.group(1): # the value does not matter, only that it is positive so the gcode_parse() know it is > 0, # therefore the move is of kind T (travel) command['Z'] = 1 diff --git a/flatcamGUI/ObjectUI.py b/flatcamGUI/ObjectUI.py index ed9863ae..0a08d60b 100644 --- a/flatcamGUI/ObjectUI.py +++ b/flatcamGUI/ObjectUI.py @@ -895,8 +895,8 @@ class ExcellonObjectUI(ObjectUI): self.grid3.addWidget(self.mill_dia_entry, 3, 1) # Cut Z - cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) - cutzlabel.setToolTip( + self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) + self.cutzlabel.setToolTip( _("Drill depth (negative)\n" "below the copper surface.") ) @@ -911,7 +911,7 @@ class ExcellonObjectUI(ObjectUI): self.cutz_entry.setSingleStep(0.1) - self.grid3.addWidget(cutzlabel, 4, 0) + self.grid3.addWidget(self.cutzlabel, 4, 0) self.grid3.addWidget(self.cutz_entry, 4, 1) # Multi-Depth @@ -930,19 +930,15 @@ class ExcellonObjectUI(ObjectUI): self.maxdepth_entry.set_range(0, 9999.9999) self.maxdepth_entry.setSingleStep(0.1) - self.maxdepth_entry.setToolTip( - _( - "Depth of each pass (positive)." - ) - ) + self.maxdepth_entry.setToolTip(_("Depth of each pass (positive).")) self.mis_mpass_geo = OptionalInputSection(self.mpass_cb, [self.maxdepth_entry]) self.grid3.addWidget(self.mpass_cb, 5, 0) self.grid3.addWidget(self.maxdepth_entry, 5, 1) # Travel Z (z_move) - travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) - travelzlabel.setToolTip( + self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) + self.travelzlabel.setToolTip( _("Tool height when travelling\n" "across the XY plane.") ) @@ -957,7 +953,7 @@ class ExcellonObjectUI(ObjectUI): self.travelz_entry.setSingleStep(0.1) - self.grid3.addWidget(travelzlabel, 6, 0) + self.grid3.addWidget(self.travelzlabel, 6, 0) self.grid3.addWidget(self.travelz_entry, 6, 1) # Tool change: @@ -1029,20 +1025,20 @@ class ExcellonObjectUI(ObjectUI): self.grid3.addWidget(self.xyfeedrate_entry, 12, 1) # Excellon Feedrate Z - frlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) - frlabel.setToolTip( + self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) + self.frzlabel.setToolTip( _("Tool speed while drilling\n" "(in units per minute).\n" "So called 'Plunge' feedrate.\n" "This is for linear move G01.") ) - self.feedrate_entry = FCDoubleSpinner(callback=self.confirmation_message) - self.feedrate_entry.set_precision(self.decimals) - self.feedrate_entry.set_range(0.0, 99999.9999) - self.feedrate_entry.setSingleStep(0.1) + self.feedrate_z_entry = FCDoubleSpinner(callback=self.confirmation_message) + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.set_range(0.0, 99999.9999) + self.feedrate_z_entry.setSingleStep(0.1) - self.grid3.addWidget(frlabel, 14, 0) - self.grid3.addWidget(self.feedrate_entry, 14, 1) + self.grid3.addWidget(self.frzlabel, 14, 0) + self.grid3.addWidget(self.feedrate_z_entry, 14, 1) # Excellon Rapid Feedrate self.feedrate_rapid_label = QtWidgets.QLabel('%s:' % _('Feedrate Rapids')) @@ -1092,8 +1088,8 @@ class ExcellonObjectUI(ObjectUI): self.grid3.addWidget(self.e_cut_entry, 17, 1) # Spindlespeed - spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed')) - spdlabel.setToolTip( + self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed')) + self.spindle_label.setToolTip( _("Speed of the spindle\n" "in RPM (optional)") ) @@ -1102,7 +1098,7 @@ class ExcellonObjectUI(ObjectUI): self.spindlespeed_entry.set_range(0, 1000000) self.spindlespeed_entry.setSingleStep(100) - self.grid3.addWidget(spdlabel, 19, 0) + self.grid3.addWidget(self.spindle_label, 19, 0) self.grid3.addWidget(self.spindlespeed_entry, 19, 1) # Dwell @@ -1647,8 +1643,8 @@ class GeometryObjectUI(ObjectUI): self.grid3.addWidget(self.tipangle_entry, 2, 1) # Cut Z - cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) - cutzlabel.setToolTip( + self.cutzlabel = QtWidgets.QLabel('%s:' % _('Cut Z')) + self.cutzlabel.setToolTip( _( "Cutting depth (negative)\n" "below the copper surface." @@ -1664,7 +1660,7 @@ class GeometryObjectUI(ObjectUI): self.cutz_entry.setSingleStep(0.1) - self.grid3.addWidget(cutzlabel, 3, 0) + self.grid3.addWidget(self.cutzlabel, 3, 0) self.grid3.addWidget(self.cutz_entry, 3, 1) # Multi-pass @@ -1694,8 +1690,8 @@ class GeometryObjectUI(ObjectUI): self.grid3.addWidget(self.maxdepth_entry, 4, 1) # Travel Z - travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) - travelzlabel.setToolTip( + self.travelzlabel = QtWidgets.QLabel('%s:' % _('Travel Z')) + self.travelzlabel.setToolTip( _("Height of the tool when\n" "moving without cutting.") ) @@ -1709,7 +1705,7 @@ class GeometryObjectUI(ObjectUI): self.travelz_entry.setSingleStep(0.1) - self.grid3.addWidget(travelzlabel, 5, 0) + self.grid3.addWidget(self.travelzlabel, 5, 0) self.grid3.addWidget(self.travelz_entry, 5, 1) # Tool change @@ -1771,8 +1767,8 @@ class GeometryObjectUI(ObjectUI): self.grid3.addWidget(self.gendz_entry, 9, 1) # Feedrate X-Y - frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y')) - frlabel.setToolTip( + self.frlabel = QtWidgets.QLabel('%s:' % _('Feedrate X-Y')) + self.frlabel.setToolTip( _("Cutting speed in the XY\n" "plane in units per minute") ) @@ -1781,23 +1777,23 @@ class GeometryObjectUI(ObjectUI): self.cncfeedrate_entry.set_range(0, 99999.9999) self.cncfeedrate_entry.setSingleStep(0.1) - self.grid3.addWidget(frlabel, 10, 0) + self.grid3.addWidget(self.frlabel, 10, 0) self.grid3.addWidget(self.cncfeedrate_entry, 10, 1) # Feedrate Z (Plunge) - frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) - frzlabel.setToolTip( + self.frzlabel = QtWidgets.QLabel('%s:' % _('Feedrate Z')) + self.frzlabel.setToolTip( _("Cutting speed in the XY\n" "plane in units per minute.\n" "It is called also Plunge.") ) - self.cncplunge_entry = FCDoubleSpinner(callback=self.confirmation_message) - self.cncplunge_entry.set_precision(self.decimals) - self.cncplunge_entry.set_range(0, 99999.9999) - self.cncplunge_entry.setSingleStep(0.1) + self.feedrate_z_entry = FCDoubleSpinner(callback=self.confirmation_message) + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.set_range(0, 99999.9999) + self.feedrate_z_entry.setSingleStep(0.1) - self.grid3.addWidget(frzlabel, 11, 0) - self.grid3.addWidget(self.cncplunge_entry, 11, 1) + self.grid3.addWidget(self.frzlabel, 11, 0) + self.grid3.addWidget(self.feedrate_z_entry, 11, 1) # Feedrate rapids self.fr_rapidlabel = QtWidgets.QLabel('%s:' % _('Feedrate Rapids')) @@ -1843,8 +1839,8 @@ class GeometryObjectUI(ObjectUI): self.grid3.addWidget(self.e_cut_entry, 13, 1) # Spindlespeed - spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed')) - spdlabel.setToolTip( + self.spindle_label = QtWidgets.QLabel('%s:' % _('Spindle speed')) + self.spindle_label.setToolTip( _( "Speed of the spindle in RPM (optional).\n" "If LASER preprocessor is used,\n" @@ -1855,7 +1851,7 @@ class GeometryObjectUI(ObjectUI): self.cncspindlespeed_entry.set_range(0, 1000000) self.cncspindlespeed_entry.setSingleStep(100) - self.grid3.addWidget(spdlabel, 14, 0) + self.grid3.addWidget(self.spindle_label, 14, 0) self.grid3.addWidget(self.cncspindlespeed_entry, 14, 1) # Dwell diff --git a/flatcamGUI/PreferencesUI.py b/flatcamGUI/PreferencesUI.py index cde679cf..92e06f69 100644 --- a/flatcamGUI/PreferencesUI.py +++ b/flatcamGUI/PreferencesUI.py @@ -3152,12 +3152,12 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI): "So called 'Plunge' feedrate.\n" "This is for linear move G01.") ) - self.feedrate_entry = FCDoubleSpinner() - self.feedrate_entry.set_precision(self.decimals) - self.feedrate_entry.set_range(0, 99999.9999) + self.feedrate_z_entry = FCDoubleSpinner() + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.set_range(0, 99999.9999) grid2.addWidget(frlabel, 5, 0) - grid2.addWidget(self.feedrate_entry, 5, 1) + grid2.addWidget(self.feedrate_z_entry, 5, 1) # Spindle speed spdlabel = QtWidgets.QLabel('%s:' % _('Spindle Speed')) @@ -4096,14 +4096,14 @@ class GeometryOptPrefGroupUI(OptionsGroupUI): "plane in units per minute.\n" "It is called also Plunge.") ) - self.cncplunge_entry = FCDoubleSpinner() - self.cncplunge_entry.set_range(0, 99999.9999) - self.cncplunge_entry.set_precision(self.decimals) - self.cncplunge_entry.setSingleStep(0.1) - self.cncplunge_entry.setWrapping(True) + self.feedrate_z_entry = FCDoubleSpinner() + self.feedrate_z_entry.set_range(0, 99999.9999) + self.feedrate_z_entry.set_precision(self.decimals) + self.feedrate_z_entry.setSingleStep(0.1) + self.feedrate_z_entry.setWrapping(True) grid1.addWidget(frz_label, 8, 0) - grid1.addWidget(self.cncplunge_entry, 8, 1) + grid1.addWidget(self.feedrate_z_entry, 8, 1) # Spindle Speed spdlabel = QtWidgets.QLabel('%s:' % _('Spindle speed')) diff --git a/preprocessors/marlin.py b/preprocessors/Marlin.py similarity index 98% rename from preprocessors/marlin.py rename to preprocessors/Marlin.py index 5eafd92d..65428e8f 100644 --- a/preprocessors/marlin.py +++ b/preprocessors/Marlin.py @@ -9,7 +9,7 @@ from FlatCAMPostProc import * -class marlin(FlatCAMPostProc): +class Marlin(FlatCAMPostProc): include_header = True coordinate_format = "%.*f" @@ -34,7 +34,7 @@ class marlin(FlatCAMPostProc): if str(p['options']['type']) == 'Geometry': gcode += ';Feedrate_Z: ' + str(p['z_feedrate']) + units + '/min' + '\n' - gcode += ';Feedrate rapids ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n' + gcode += ';Feedrate rapids: ' + str(p['feedrate_rapid']) + units + '/min' + '\n' + '\n' gcode += ';Z_Cut: ' + str(p['z_cut']) + units + '\n' if str(p['options']['type']) == 'Geometry': diff --git a/preprocessors/Marlin_laser.py b/preprocessors/Marlin_laser.py new file mode 100644 index 00000000..e67e9bb5 --- /dev/null +++ b/preprocessors/Marlin_laser.py @@ -0,0 +1,122 @@ +# ########################################################## +# FlatCAM: 2D Post-processing for Manufacturing # +# Website: http://flatcam.org # +# File Author: Marius Adrian Stanciu (c) # +# Date: 8-Feb-2020 # +# License: MIT Licence # +# ########################################################## + +from FlatCAMPostProc import * + + +class Marlin_laser(FlatCAMPostProc): + + include_header = True + coordinate_format = "%.*f" + feedrate_format = '%.*f' + feedrate_rapid_format = feedrate_format + + def start_code(self, p): + units = ' ' + str(p['units']).lower() + coords_xy = p['xy_toolchange'] + gcode = '' + + xmin = '%.*f' % (p.coords_decimals, p['options']['xmin']) + xmax = '%.*f' % (p.coords_decimals, p['options']['xmax']) + ymin = '%.*f' % (p.coords_decimals, p['options']['ymin']) + 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': + gcode += ';Preprocessor Excellon: ' + str(p['pp_excellon_name']) + '\n' + else: + gcode += ';Preprocessor Geometry: ' + str(p['pp_geometry_name']) + '\n' + '\n' + + gcode += ';X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + '\n' + gcode += ';Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + '\n\n' + + gcode += ';Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + '\n' + '\n' + + gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n" + gcode += 'G90\n' + gcode += 'G94' + + return gcode + + def startz_code(self, p): + if p.startz is not None: + return 'G0 Z' + self.coordinate_format % (p.coords_decimals, p.z_move) + else: + return '' + + def lift_code(self, p): + gcode = 'M400\n' + gcode += 'M5 S0' + return gcode + + def down_code(self, p): + sdir = {'CW': 'M3', 'CCW': 'M4'}[p.spindledir] + if p.spindlespeed: + return '%s S%s' % (sdir, str(p.spindlespeed)) + else: + return sdir + + def toolchange_code(self, p): + return '' + + def up_to_zero_code(self, p): + gcode = 'M400\n' + gcode += 'M5' + return gcode + + def position_code(self, p): + return ('X' + self.coordinate_format + ' Y' + self.coordinate_format) % \ + (p.coords_decimals, p.x, p.coords_decimals, p.y) + + def rapid_code(self, p): + return ('G0 ' + self.position_code(p)).format(**p) + " " + self.feedrate_rapid_code(p) + + def linear_code(self, p): + return ('G1 ' + self.position_code(p)).format(**p) + " " + self.inline_feedrate_code(p) + + def end_code(self, p): + coords_xy = p['xy_toolchange'] + gcode = ('G0 Z' + self.feedrate_format % (p.fr_decimals, p.z_end) + " " + self.feedrate_rapid_code(p) + "\n") + + if coords_xy is not None: + gcode += 'G0 X{x} Y{y}'.format(x=coords_xy[0], y=coords_xy[1]) + " " + self.feedrate_rapid_code(p) + "\n" + + return gcode + + def feedrate_code(self, p): + return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.feedrate)) + + def z_feedrate_code(self, p): + return 'G1 F' + str(self.feedrate_format % (p.fr_decimals, p.z_feedrate)) + + def inline_feedrate_code(self, p): + return 'F' + self.feedrate_format % (p.fr_decimals, p.feedrate) + + def feedrate_rapid_code(self, p): + return 'F' + self.feedrate_rapid_format % (p.fr_decimals, p.feedrate_rapid) + + def spindle_code(self, p): + sdir = {'CW': 'M3', 'CCW': 'M4'}[p.spindledir] + if p.spindlespeed: + return '%s S%s' % (sdir, str(p.spindlespeed)) + else: + return sdir + + def dwell_code(self, p): + return '' + + def spindle_stop_code(self, p): + gcode = 'M400\n' + gcode += 'M5' + return gcode diff --git a/preprocessors/grbl_laser.py b/preprocessors/grbl_laser.py index e975a703..a3f4da7d 100644 --- a/preprocessors/grbl_laser.py +++ b/preprocessors/grbl_laser.py @@ -28,7 +28,9 @@ class grbl_laser(FlatCAMPostProc): 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 += '(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' @@ -40,10 +42,12 @@ class grbl_laser(FlatCAMPostProc): gcode += '(X range: ' + '{: >9s}'.format(xmin) + ' ... ' + '{: >9s}'.format(xmax) + ' ' + units + ')\n' gcode += '(Y range: ' + '{: >9s}'.format(ymin) + ' ... ' + '{: >9s}'.format(ymax) + ' ' + units + ')\n\n' + gcode += '(Laser Power (Spindle Speed): ' + str(p['spindlespeed']) + ')\n\n' + gcode += ('G20' if p.units.upper() == 'IN' else 'G21') + "\n" gcode += 'G90\n' gcode += 'G17\n' - gcode += 'G94\n' + gcode += 'G94' return gcode