From: Youness Alaoui Date: Tue, 2 Jun 2015 17:33:07 +0000 (-0400) Subject: Merge branch 'LulzBot-devel' into taz5-nozzle-size X-Git-Tag: lulzbot-15.02.1-1.01~4^2~5 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=b572b971043155e80ae17fe2214be4ce083861ec;hp=6239075af98d8862f729a01cb912a427c5cf2513;p=cura.git Merge branch 'LulzBot-devel' into taz5-nozzle-size --- diff --git a/Cura/gui/configWizard.py b/Cura/gui/configWizard.py index c1a91a39..7b45bf98 100644 --- a/Cura/gui/configWizard.py +++ b/Cura/gui/configWizard.py @@ -517,6 +517,12 @@ class MachineSelectPage(InfoPage): profile.putMachineSetting('machine_name', 'LulzBot Mini') profile.putMachineSetting('machine_type', 'lulzbot_mini') profile.putMachineSetting('serial_baud', '115200') + profile.putMachineSetting('extruder_head_size_min_x', '40') + profile.putMachineSetting('extruder_head_size_max_x', '75') + profile.putMachineSetting('extruder_head_size_min_y', '25') + profile.putMachineSetting('extruder_head_size_max_y', '55') + profile.putMachineSetting('extruder_head_size_height', '17') + profile.putMachineSetting('machine_center_is_zero', 'False') profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)') profile.putMachineSetting('has_heated_bed', 'True') @@ -1080,7 +1086,7 @@ class ConfigWizard(wx.wizard.Wizard): #wx.wizard.WizardPageSimple.Chain(self.ultimakerCalibrationPage, self.ultimakerCalibrateStepsPerEPage) wx.wizard.WizardPageSimple.Chain(self.printrbotSelectType, self.otherMachineInfoPage) wx.wizard.WizardPageSimple.Chain(self.otherMachineSelectPage, self.customRepRapInfoPage) - wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.taz5NozzleSelectPage) + wx.wizard.WizardPageSimple.Chain(self.machineSelectPage, self.lulzbotReadyPage) wx.wizard.WizardPageSimple.Chain(self.taz5NozzleSelectPage, self.lulzbotReadyPage) self.FitToPage(self.machineSelectPage) diff --git a/Cura/gui/mainWindow.py b/Cura/gui/mainWindow.py index 23f79c45..27223f21 100644 --- a/Cura/gui/mainWindow.py +++ b/Cura/gui/mainWindow.py @@ -384,11 +384,6 @@ class mainWindow(wx.Frame): profile.getMachineSetting('machine_type').startswith('lulzbot_'): self.bedLevelWizardMenuItem.Enable(False) self.headOffsetWizardMenuItem.Enable(False) - self.oneAtATime.Enable(False) - self.allAtOnceItem.Check(True) - # Force the gantry height to 0 so we don't get a "info: print one at a time re-enabled" - # notification since we're disabling that option - profile.putMachineSetting('extruder_head_size_height', '0.0') else: self.bedLevelWizardMenuItem.Enable(True) self.headOffsetWizardMenuItem.Enable(False) diff --git a/Cura/gui/printWindow.py b/Cura/gui/printWindow.py index c5a73f42..e3e5eadb 100644 --- a/Cura/gui/printWindow.py +++ b/Cura/gui/printWindow.py @@ -226,7 +226,10 @@ class printWindowPlugin(wx.Frame): self._printerConnection.openActiveConnection() def script_startPrint(self, data = None): - self._printerConnection.startPrint() + if self._printerConnection.isPrinting() or self._printerConnection.isPaused(): + self._printerConnection.pause(not self._printerConnection.isPaused()) + else: + self._printerConnection.startPrint() def script_cancelPrint(self, e): self._printerConnection.cancelPrint() @@ -253,7 +256,7 @@ class printWindowPlugin(wx.Frame): def OnClose(self, e): if self._printerConnection.hasActiveConnection(): - if self._printerConnection.isPrinting(): + if self._printerConnection.isPrinting() or self._printerConnection.isPaused(): pass #TODO: Give warning that the close will kill the print. self._printerConnection.closeActiveConnection() self._printerConnection.removeCallback(self._doPrinterConnectionUpdate) @@ -297,24 +300,55 @@ class printWindowPlugin(wx.Frame): self._termLog.AppendText(line.encode('utf-8', 'replace')) def _updateButtonStates(self): + hasPauseButton = False + for button in self._buttonList: + if button.command == self.script_pausePrint: + hasPauseButton = True + break + for button in self._buttonList: if button.command == self.script_connect: button.Show(self._printerConnection.hasActiveConnection()) - button.Enable(not self._printerConnection.isActiveConnectionOpen() and not self._printerConnection.isActiveConnectionOpening()) + button.Enable(not self._printerConnection.isActiveConnectionOpen() and \ + not self._printerConnection.isActiveConnectionOpening()) elif button.command == self.script_pausePrint: button.Show(self._printerConnection.hasPause()) - if not self._printerConnection.hasActiveConnection() or self._printerConnection.isActiveConnectionOpen(): - button.Enable(self._printerConnection.isPrinting() or self._printerConnection.isPaused()) + if not self._printerConnection.hasActiveConnection() or \ + self._printerConnection.isActiveConnectionOpen(): + button.Enable(self._printerConnection.isPrinting() or \ + self._printerConnection.isPaused()) + if self._printerConnection.isPaused(): + button.SetLabel(_("Resume")) + else: + button.SetLabel(_("Pause")) else: button.Enable(False) elif button.command == self.script_startPrint: - if not self._printerConnection.hasActiveConnection() or self._printerConnection.isActiveConnectionOpen(): - button.Enable(not self._printerConnection.isPrinting()) + if hasPauseButton or not self._printerConnection.hasPause(): + if not self._printerConnection.hasActiveConnection() or \ + self._printerConnection.isActiveConnectionOpen(): + button.Enable(not self._printerConnection.isPrinting() and \ + not self._printerConnection.isPaused()) + else: + button.Enable(False) else: - button.Enable(False) + if not self._printerConnection.hasActiveConnection() or \ + self._printerConnection.isActiveConnectionOpen(): + if self._printerConnection.isPrinting(): + button.SetLabel(_("Pause")) + else: + if self._printerConnection.isPaused(): + button.SetLabel(_("Resume")) + else: + button.SetLabel(_("Print")) + button.Enable(True) + else: + button.Enable(False) elif button.command == self.script_cancelPrint: - if not self._printerConnection.hasActiveConnection() or self._printerConnection.isActiveConnectionOpen(): - button.Enable(self._printerConnection.isPrinting()) + if not self._printerConnection.hasActiveConnection() or \ + self._printerConnection.isActiveConnectionOpen(): + button.Enable(self._printerConnection.isPrinting() or \ + self._printerConnection.isPaused()) else: button.Enable(False) elif button.command == self.script_showErrorLog: @@ -340,12 +374,13 @@ class printWindowPlugin(wx.Frame): return self._lastUpdateTime = t - if extraInfo is not None: + if extraInfo is not None and len(extraInfo) > 0: self._addTermLog('< %s\n' % (extraInfo)) self._updateButtonStates() + isPrinting = connection.isPrinting() or connection.isPaused() if self._progressBar is not None: - if connection.isPrinting(): + if isPrinting: self._progressBar.SetValue(connection.getPrintProgress() * 1000) else: self._progressBar.SetValue(0) @@ -359,8 +394,8 @@ class printWindowPlugin(wx.Frame): self._infoText.SetLabel(info) else: self.SetTitle(info.replace('\n', ', ')) - if connection.isPrinting() != self._isPrinting: - self._isPrinting = connection.isPrinting() + if isPrinting != self._isPrinting: + self._isPrinting = isPrinting preventComputerFromSleeping(self, self._isPrinting) class printWindowBasic(wx.Frame): @@ -450,7 +485,7 @@ class printWindowBasic(wx.Frame): def OnClose(self, e): if self._printerConnection.hasActiveConnection(): - if self._printerConnection.isPrinting(): + if self._printerConnection.isPrinting() or self._printerConnection.isPaused(): pass #TODO: Give warning that the close will kill the print. self._printerConnection.closeActiveConnection() self._printerConnection.removeCallback(self._doPrinterConnectionUpdate) @@ -487,11 +522,12 @@ class printWindowBasic(wx.Frame): return self._lastUpdateTime = t - if extraInfo is not None: + if extraInfo is not None and len(extraInfo) > 0: self._addTermLog('< %s\n' % (extraInfo)) self._updateButtonStates() - if connection.isPrinting(): + isPrinting = connection.isPrinting() or connection.isPaused() + if isPrinting: self.progress.SetValue(connection.getPrintProgress() * 1000) else: self.progress.SetValue(0) @@ -503,8 +539,8 @@ class printWindowBasic(wx.Frame): info += ' Bed: %d' % (self._printerConnection.getBedTemperature()) info += '\n\n' self.statsText.SetLabel(info) - if connection.isPrinting() != self._isPrinting: - self._isPrinting = connection.isPrinting() + if isPrinting != self._isPrinting: + self._isPrinting = isPrinting preventComputerFromSleeping(self, self._isPrinting) @@ -519,7 +555,8 @@ class printWindowBasic(wx.Frame): self.connectButton.Enable(not self._printerConnection.isActiveConnectionOpen() and not self._printerConnection.isActiveConnectionOpening()) self.pauseButton.Show(self._printerConnection.hasPause()) if not self._printerConnection.hasActiveConnection() or self._printerConnection.isActiveConnectionOpen(): - self.printButton.Enable(not self._printerConnection.isPrinting()) + self.printButton.Enable(not self._printerConnection.isPrinting() and \ + not self._printerConnection.isPaused()) self.pauseButton.Enable(self._printerConnection.isPrinting()) self.cancelButton.Enable(self._printerConnection.isPrinting()) else: diff --git a/Cura/gui/util/engineResultView.py b/Cura/gui/util/engineResultView.py index 8aeefd27..00505cc3 100644 --- a/Cura/gui/util/engineResultView.py +++ b/Cura/gui/util/engineResultView.py @@ -26,7 +26,7 @@ class engineResultView(object): self._layer20VBOs = [] self.layerSelect = openglGui.glSlider(self._parent, 10000, 1, 1, (-1,-2), lambda : self._parent.QueueRefresh()) - self.singleLayerToggle = openglGui.glButton(self._parent, 23, _("Single Layer"), (-1,-1.5), self.OnSingleLayerToggle, 0.5) #stay half size of the base size + self.singleLayerToggle = openglGui.glButton(self._parent, 27, _("Single Layer"), (-1.1,-1.4), self.OnSingleLayerToggle, 0.75) #stay at 75% size of the base size def setResult(self, result): if self._result == result: diff --git a/Cura/serialCommunication.py b/Cura/serialCommunication.py index efc6e72d..4add5f23 100644 --- a/Cura/serialCommunication.py +++ b/Cura/serialCommunication.py @@ -68,6 +68,10 @@ class serialComm(object): self._comm.sendCommand(line[1]) elif line[0] == 'START': self._comm.printGCode(self._gcodeList) + elif line[0] == 'PAUSE': + self._comm.setPause(True) + elif line[0] == 'RESUME': + self._comm.setPause(False) else: sys.stderr.write(str(line)) diff --git a/Cura/util/machineCom.py b/Cura/util/machineCom.py index 650452df..5fe86611 100644 --- a/Cura/util/machineCom.py +++ b/Cura/util/machineCom.py @@ -587,7 +587,7 @@ class MachineCom(object): line = line[0] try: if line == 'M0' or line == 'M1': - #self.setPause(True) + self.setPause(True) line = 'M105' #Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause. if self._printSection in self._feedRateModifier: line = re.sub('F([0-9]*)', lambda m: 'F' + str(int(int(m.group(1)) * self._feedRateModifier[self._printSection])), line) diff --git a/Cura/util/printerConnection/serialConnection.py b/Cura/util/printerConnection/serialConnection.py index 2495f77a..6a2c2548 100644 --- a/Cura/util/printerConnection/serialConnection.py +++ b/Cura/util/printerConnection/serialConnection.py @@ -97,7 +97,7 @@ class serialConnection(printerConnectionBase.printerConnectionBase): #Abort the previously loaded print file def cancelPrint(self): - if not self.isPrinting()or self._process is None: + if not self.isPrinting() or self._process is None: return self._process.stdin.write('STOP\n') self._printProgress = 0 @@ -105,6 +105,19 @@ class serialConnection(printerConnectionBase.printerConnectionBase): def isPrinting(self): return self._commState == machineCom.MachineCom.STATE_PRINTING + #Returns true if we have the ability to pause the file printing. + def hasPause(self): + return True + + def isPaused(self): + return self._commState == machineCom.MachineCom.STATE_PAUSED + + #Pause or unpause the printing depending on the value, if supported. + def pause(self, value): + if not (self.isPrinting() or self.isPaused) or self._process is None: + return + self._process.stdin.write('PAUSE\n' if value else "RESUME\n") + #Amount of progression of the current print file. 0.0 to 1.0 def getPrintProgress(self): if len(self._gcodeData) < 1: @@ -209,7 +222,7 @@ class serialConnection(printerConnectionBase.printerConnectionBase): line = line[1].split(':', 1) self._commState = int(line[0]) self._commStateString = line[1] - self._doCallback() + self._doCallback('') elif line[0] == 'progress': self._printProgress = int(line[1]) self._doCallback() diff --git a/Cura/util/profile.py b/Cura/util/profile.py index ef9d454b..43d54e9b 100644 --- a/Cura/util/profile.py +++ b/Cura/util/profile.py @@ -180,6 +180,7 @@ setting('wall_thickness', 0.8, float, 'basic', _('Quality')).setRa setting('retraction_enable', True, bool, 'basic', _('Quality')).setExpertSubCategory(_('Retraction')).setLabel(_("Enable retraction"), _("Retract the filament when the nozzle is moving over a none-printed area. Details about the retraction can be configured in the advanced tab.")) setting('solid_layer_thickness', 0.6, float, 'basic', _('Fill')).setRange(0).setLabel(_("Bottom/Top thickness (mm)"), _("This controls the thickness of the bottom and top layers, the amount of solid layers put down is calculated by the layer thickness and this value.\nHaving this value a multiple of the layer thickness makes sense. And keep it near your wall thickness to make an evenly strong part.")) setting('fill_density', 20, float, 'basic', _('Fill')).setExpertSubCategory(_('Infill')).setRange(0, 100).setLabel(_("Fill Density (%)"), _("This controls how densely filled the insides of your print will be. For a solid part use 100%, for an empty part use 0%. A value around 20% is usually enough.\nThis will not affect the outside of the print and only adjusts how strong the part becomes.")) +setting('perimeter_before_infill', True, bool, 'basic', _('Fill')).setLabel(_("Perimeters before Infill"), _("This controls whether the perimeters should be printed before or after the infill. Printing the perimeter after the infill may improve the quality of prints with very low layer heights, while printing the perimeters before the infill will give better results for layer height above 0.1mm")) setting('nozzle_size', 0.4, float, 'advanced', _('Machine')).setRange(0.1,10).setLabel(_("Nozzle size (mm)"), _("The nozzle size is very important, this is used to calculate the line width of the infill, and used to calculate the amount of outside wall lines and thickness for the wall thickness you entered in the print settings.")) setting('print_speed', 50, float, 'basic', _('Speed and Temperature')).setRange(1).setLabel(_("Print speed (mm/s)"), _("Speed at which printing happens. A well adjusted 3D printer can reach high speeds. However, for high quality prints slower speeds are required. Printing speed depends on a lot of factors. You will be experimenting with optimal settings for this.")) setting('print_temperature', 210, int, 'basic', _('Speed and Temperature')).setRange(0,340).setLabel(_("Printing temperature (C)"), _("Temperature used for printing. Set at 0 to pre-heat yourself.\nFor PLA 205C is recommended.\nFor ABS and HIPS 240C is recommended.")) @@ -483,7 +484,7 @@ setting('postSwitchExtruder.gcode', """;Switch between the current extruder and setting('startMode', 'Simple', ['Simple', 'Normal'], 'preference', 'hidden') setting('simpleModeProfile', '2_normal', str, 'hidden', 'hidden') setting('simpleModeMaterial', '1_pla', str, 'hidden', 'hidden') -setting('oneAtATime', 'True', bool, 'preference', 'hidden') +setting('oneAtATime', 'False', bool, 'preference', 'hidden') setting('lastFile', os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'resources', 'example', 'Rocktopus.stl')), str, 'preference', 'hidden') setting('save_profile', 'False', bool, 'preference', 'hidden').setLabel(_("Save profile on slice"), _("When slicing save the profile as [stl_file]_profile.ini next to the model.")) setting('filament_cost_kg', '0', float, 'preference', 'hidden').setLabel(_("Cost (price/kg)"), _("Cost of your filament per kg, to estimate the cost of the final print.")) diff --git a/Cura/util/sliceEngine.py b/Cura/util/sliceEngine.py index ccf90a51..5d434cf8 100644 --- a/Cura/util/sliceEngine.py +++ b/Cura/util/sliceEngine.py @@ -566,6 +566,10 @@ class Engine(object): settings['upSkinCount'] = 10000 else: settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density')) + if profile.getProfileSetting('perimeter_before_infill') == 'True': + settings['perimeterBeforeInfill'] = 1 + else: + settings['perimeterBeforeInfill'] = 0 if profile.getProfileSetting('platform_adhesion') == 'Brim': settings['skirtDistance'] = 0 settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count')) diff --git a/plugins/PronterfaceUI/script.py b/plugins/PronterfaceUI/script.py index 705c113a..eb317505 100644 --- a/plugins/PronterfaceUI/script.py +++ b/plugins/PronterfaceUI/script.py @@ -50,7 +50,7 @@ addProgressbar(255, 200, 200) addButton(0, 255, 255, 'Connect', connect) addButton(0, 240, 255, 'Print', startPrint) -addButton(0, 220, 255, 'Pause', pausePrint) +#addButton(0, 220, 255, 'Pause', pausePrint) addButton(0, 200, 255, 'Cancel', cancelPrint) addButton(0, 180, 255, 'Error log', showErrorLog) addButton(0, 160, 255, "Motors Off", sendGCode, "M18;") diff --git a/plugins/pauseAtZ.py b/plugins/pauseAtZ.py new file mode 100644 index 00000000..2991be4a --- /dev/null +++ b/plugins/pauseAtZ.py @@ -0,0 +1,125 @@ +#Name: Pause at height +#Info: Pause the printer at a certain height +#Depend: GCode +#Type: postprocess +#Param: pauseLevel(float:5.0) Pause height (mm) +#Param: parkX(float:190) Head park X (mm) +#Param: parkY(float:190) Head park Y (mm) +#Param: moveZ(float:0) Head move Z (mm) +#Param: retractAmount(float:5) Retraction amount (mm) + +__copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License" +import re +from Cura.util import profile + +def getPrintZValue(lineBlock): + ''' + look for the last z value found just before (or at the same time) G1 code in the given block + ''' + lastZ = -1 + for line in lineBlock: + lastZ = getValue(line, 'Z', lastZ) + if line.startswith('G1 ') and (getValue(line, 'X', None) is not None or getValue(line, 'Y', None) is not None): + break + + return lastZ + + +def getValue(line, key, default = None): + if not key in line or (';' in line and line.find(key) > line.find(';')): + return default + subPart = line[line.find(key) + 1:] + m = re.search('^[0-9]+\.?[0-9]*', subPart) + if m is None: + return default + try: + return float(m.group(0)) + except: + return default + +with open(filename, "r") as f: + lines = f.readlines() + +z = 0. +x = 0. +y = 0. +pauseState = 0 +#state 0 system is not active until we get to a smaller layer than the last encountered layer (default at 99999) (print one at a time support.) +#state 1 system is active and we are looking for our target layer z +#state 2 system found the layer it need to write. We will wait for the first G1 or G0 code to write the content just before. state will be set to 0 + + +with open(filename, "w") as f: + lineIndex = 0 + lastLayerIndex = 99999 + layerZ = 0 + for lIndex in xrange(len(lines)): + line = lines[lIndex] + if line.startswith(';'): + if line.startswith(';LAYER:'): + currentLayer = int(line[7:].strip()) + + if currentLayer < lastLayerIndex: + pauseState = 1 + + lastLayerIndex = currentLayer + if pauseState == 1: + layerZ = getPrintZValue(lines[lIndex:lIndex+20]) + if layerZ >= pauseLevel: + pauseState = 2 + + f.write(line) + continue + + x = getValue(line, 'X', x) + y = getValue(line, 'Y', y) + + if pauseState == 2: + g = getValue(line, 'G', None) + if g == 1 or g == 0:# We will do the pause just before printing content. We need to pause from the previous XY position. Not the current. + z = layerZ + + pauseState = 0 + f.write(";TYPE:CUSTOM\n") + #Retract + f.write("M83\n") + f.write("G1 E-%f F6000\n" % (retractAmount)) + + zChanged = False + #Change z before doing the move because the nozzle can hit the glass lock on the UM2 + if z + moveZ < 15: + zChanged = True + f.write("G1 Z15 F300\n") + + elif moveZ > 0: + newZ = z + moveZ + maxZ = profile.getMachineSettingFloat('machine_height') - 10 #For Safety Leave a 10mm space (endstop) + if maxZ < newZ: + newZ = maxZ + + if newZ > z: + zChanged = True + f.write("G1 Z%f F300\n" % (newZ)) + + #Move the head away + f.write("G1 X%f Y%f F9000\n" % (parkX, parkY)) + + #Disable the E steppers + f.write("M84 E0\n") + #Wait till the user continues printing + f.write("M0\n") + #Push the filament back, and retract again, the properly primes the nozzle when changing filament. + f.write("G1 E%f F6000\n" % (retractAmount)) + f.write("G1 E-%f F6000\n" % (retractAmount)) + + #Move the head back. Move Z at the same time to prevent hitting the glass locks on the UM2 + if zChanged : + f.write("G1 X%f Y%f Z%f F9000\n" % (x, y, z)) + else: + f.write("G1 X%f Y%f F9000\n" % (x, y)) + + f.write("G1 E%f F6000\n" % (retractAmount)) + f.write("G1 F9000\n") + f.write("M82\n") + + f.write(line) diff --git a/resources/images/glButtons.png b/resources/images/glButtons.png index 8f191279..79ba6772 100644 Binary files a/resources/images/glButtons.png and b/resources/images/glButtons.png differ diff --git a/resources/images/source/Cura_Ui_buttons.svg b/resources/images/source/Cura_Ui_buttons.svg index dd88edc6..fa3063d7 100644 --- a/resources/images/source/Cura_Ui_buttons.svg +++ b/resources/images/source/Cura_Ui_buttons.svg @@ -17,16 +17,16 @@ enable-background="new 0 0 1920 1080" xml:space="preserve" id="svg2" - inkscape:version="0.48.4 r9939" + inkscape:version="0.91 r" width="100%" height="100%" sodipodi:docname="Cura_Ui_buttons.svg" - inkscape:export-filename="/home/steven/Cura/cura-dev/resources/images/glButtons.png" + inkscape:export-filename="/home/aleph/cura-dev/resources/images/glButtons.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90">image/svg+xml