diff --git a/FlatCAMApp.py b/FlatCAMApp.py index c2391181..028fbfd3 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -245,7 +245,9 @@ class App(QtCore.QObject): "cncjob_plot": self.defaults_form.cncjob_group.plot_cb, "cncjob_tooldia": self.defaults_form.cncjob_group.tooldia_entry, "cncjob_prepend": self.defaults_form.cncjob_group.prepend_text, - "cncjob_append": self.defaults_form.cncjob_group.append_text + "cncjob_append": self.defaults_form.cncjob_group.append_text, + "cncjob_dwell": self.defaults_form.cncjob_group.dwell_cb, + "cncjob_dwelltime": self.defaults_form.cncjob_group.dwelltime_cb } self.defaults = LoudDict() @@ -289,8 +291,13 @@ class App(QtCore.QObject): "cncjob_tooldia": 0.016, "cncjob_prepend": "", "cncjob_append": "", - "background_timeout": 300000, #default value is 5 minutes - "verbose_error_level": 0, # shell verbosity 0 = default(python trace only for unknown errors), 1 = show trace(show trace allways), 2 = (For the future). + "cncjob_dwell": True, + "cncjob_dwelltime": 1, + "background_timeout": 300000, # Default value is 5 minutes + "verbose_error_level": 0, # Shell verbosity 0 = default + # (python trace only for unknown errors), + # 1 = show trace(show trace allways), + # 2 = (For the future). # Persistence "last_folder": None, diff --git a/FlatCAMGUI.py b/FlatCAMGUI.py index 2ec95ac3..9f22faa5 100644 --- a/FlatCAMGUI.py +++ b/FlatCAMGUI.py @@ -806,6 +806,26 @@ class CNCJobOptionsGroupUI(OptionsGroupUI): self.append_text = FCTextArea() self.layout.addWidget(self.append_text) + # Dwell + grid1 = QtGui.QGridLayout() + self.layout.addLayout(grid1) + + dwelllabel = QtGui.QLabel('Dwell:') + dwelllabel.setToolTip( + "Pause to allow the spindle to reach its\n" + "speed before cutting." + ) + dwelltime = QtGui.QLabel('Duration [sec.]:') + dwelltime.setToolTip( + "Number of second to dwell." + ) + self.dwell_cb = FCCheckBox() + self.dwelltime_cb = FCEntry() + grid1.addWidget(dwelllabel, 0, 0) + grid1.addWidget(self.dwell_cb, 0, 1) + grid1.addWidget(dwelltime, 1, 0) + grid1.addWidget(self.dwelltime_cb, 1, 1) + class GlobalOptionsUI(QtGui.QWidget): """ diff --git a/FlatCAMObj.py b/FlatCAMObj.py index 722e9c4a..199c63f3 100644 --- a/FlatCAMObj.py +++ b/FlatCAMObj.py @@ -1,3 +1,4 @@ +from cStringIO import StringIO from PyQt4 import QtCore from copy import copy from ObjectUI import * @@ -981,7 +982,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): "plot": True, "tooldia": 0.4 / 25.4, # 0.4mm in inches "append": "", - "prepend": "" + "prepend": "", + "dwell": False, + "dwelltime": 1 }) # Attributes to be included in serialization @@ -1001,7 +1004,9 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): "plot": self.ui.plot_cb, "tooldia": self.ui.tooldia_entry, "append": self.ui.append_text, - "prepend": self.ui.prepend_text + "prepend": self.ui.prepend_text, + "dwell": self.ui.dwell_cb, + "dwelltime": self.ui.dwelltime_entry }) self.ui.plot_cb.stateChanged.connect(self.on_plot_cb_click) @@ -1019,6 +1024,8 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): def on_exportgcode_button_click(self, *args): self.app.report_usage("cncjob_on_exportgcode_button") + self.read_form() + try: filename = QtGui.QFileDialog.getSaveFileName(caption="Export G-Code ...", directory=self.app.defaults["last_folder"]) @@ -1030,10 +1037,51 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob): self.export_gcode(filename, preamble=preamble, postamble=postamble) + def dwell_generator(self, lines): + + log.debug("dwell_generator()...") + + m3m4re = re.compile(r'^\s*[mM]0[34]') + g4re = re.compile(r'^\s*[gG]4\s+([\d\.\+\-e]+)') + bufline = None + + for line in lines: + # If the buffer contains a G4, yield that. + # If current line is a G4, discard it. + if bufline is not None: + yield bufline + bufline = None + + if not g4re.search(line): + yield line + + continue + + # If start spindle, buffer a G4. + if m3m4re.search(line): + log.debug("Found M03/4") + bufline = "G4 {}\n".format(self.options['dwelltime']) + + yield line + + raise StopIteration + def export_gcode(self, filename, preamble='', postamble=''): - f = open(filename, 'w') - f.write(preamble + '\n' + self.gcode + "\n" + postamble) - f.close() + + lines = StringIO(self.gcode) + + if self.options['dwell']: + log.debug("Will add G04!") + lines = self.dwell_generator(lines) + + with open(filename, 'w') as f: + f.write(preamble + "\n") + + for line in lines: + + f.write(line) + + f.write(postamble) # Just for adding it to the recent files list. self.app.file_opened.emit("cncjob", filename) @@ -1309,8 +1357,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry): app_obj.progress.emit(80) - - if use_thread: + if use_thread: # To be run in separate thread def job_thread(app_obj): with self.app.proc_container.new("Generating CNC Job."): diff --git a/ObjectUI.py b/ObjectUI.py index f54f1c3b..61b4b009 100644 --- a/ObjectUI.py +++ b/ObjectUI.py @@ -163,7 +163,9 @@ class CNCObjectUI(ObjectUI): ) self.custom_box.addWidget(self.updateplot_button) + ################## ## Export G-Code + ################## self.export_gcode_label = QtGui.QLabel("Export G-Code:") self.export_gcode_label.setToolTip( "Export and save G-Code to\n" @@ -194,6 +196,26 @@ class CNCObjectUI(ObjectUI): self.append_text = FCTextArea() self.custom_box.addWidget(self.append_text) + # Dwell + grid1 = QtGui.QGridLayout() + self.custom_box.addLayout(grid1) + + dwelllabel = QtGui.QLabel('Dwell:') + dwelllabel.setToolTip( + "Pause to allow the spindle to reach its\n" + "speed before cutting." + ) + dwelltime = QtGui.QLabel('Duration [sec.]:') + dwelltime.setToolTip( + "Number of second to dwell." + ) + self.dwell_cb = FCCheckBox() + self.dwelltime_entry = FCEntry() + grid1.addWidget(dwelllabel, 0, 0) + grid1.addWidget(self.dwell_cb, 0, 1) + grid1.addWidget(dwelltime, 1, 0) + grid1.addWidget(self.dwelltime_entry, 1, 1) + # GO Button self.export_gcode_button = QtGui.QPushButton('Export G-Code') self.export_gcode_button.setToolTip( diff --git a/camlib.py b/camlib.py index d66a71fd..9b4f02f3 100644 --- a/camlib.py +++ b/camlib.py @@ -2720,7 +2720,8 @@ class CNCjob(Geometry): self.feedrate = feedrate self.tooldia = tooldia self.unitcode = {"IN": "G20", "MM": "G21"} - self.pausecode = "G04 P1" + # TODO: G04 Does not exist. It's G4 and now we are handling in postprocessing. + #self.pausecode = "G04 P1" self.feedminutecode = "G94" self.absolutecode = "G90" self.gcode = "" @@ -2818,7 +2819,7 @@ class CNCjob(Geometry): else: gcode += "M03\n" # Spindle start - gcode += self.pausecode + "\n" + #gcode += self.pausecode + "\n" for tool in tools: @@ -2915,7 +2916,7 @@ class CNCjob(Geometry): self.gcode += "M03 S%d\n" % int(self.spindlespeed) # Spindle start with configured speed else: self.gcode += "M03\n" # Spindle start - self.gcode += self.pausecode + "\n" + #self.gcode += self.pausecode + "\n" ## Iterate over geometry paths getting the nearest each time. log.debug("Starting G-Code...") @@ -3031,6 +3032,8 @@ class CNCjob(Geometry): :param gtext: A single string with g-code """ + log.debug("pre_parse()") + # Units: G20-inches, G21-mm units_re = re.compile(r'^G2([01])') @@ -3097,7 +3100,8 @@ class CNCjob(Geometry): # TODO: Merge into single parser? gobjs = self.pre_parse(self.gcode) - + + log.debug("gcode_parse(): pre_parse() done.") # Last known instruction current = {'X': 0.0, 'Y': 0.0, 'Z': 0.0, 'G': 0}