Просмотр исходного кода

- added a new preprocessor for using laser on a Marlin 3D printer named 'Marlin_laser'
- modified the Geometry UI when using laser preprocessors

Marius Stanciu 6 лет назад
Родитель
Сommit
9911402c95
9 измененных файлов с 336 добавлено и 107 удалено
  1. 2 2
      FlatCAMApp.py
  2. 115 8
      FlatCAMObj.py
  3. 6 1
      README.md
  4. 35 40
      camlib.py
  5. 38 42
      flatcamGUI/ObjectUI.py
  6. 10 10
      flatcamGUI/PreferencesUI.py
  7. 2 2
      preprocessors/Marlin.py
  8. 122 0
      preprocessors/Marlin_laser.py
  9. 6 2
      preprocessors/grbl_laser.py

+ 2 - 2
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,

+ 115 - 8
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

+ 6 - 1
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
 

+ 35 - 40
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

+ 38 - 42
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

+ 10 - 10
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'))

+ 2 - 2
preprocessors/marlin.py → 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':

+ 122 - 0
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

+ 6 - 2
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