From 7ab3eabe0fe228f2a833ffd5d7009bab6c99ddcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gina=20H=C3=A4u=C3=9Fge?= Date: Thu, 26 Jan 2017 13:33:42 +0100 Subject: [PATCH] Support for shared nozzle setups Support multi-extruder setups that share a single nozzle and heater, like the E3D Cyclops, Diamon hotend or probably the upcoming Prusa Mk2 multi-extruder upgrade. The Control tab will still allow tool switching and extruding for the configured extruders, the Temperature tab will only display one hotend temperature though. Printer profiles have been extended by a new option extruder.sharedNozzle that defaults to False. Extruder offsets are not displayed in the profile editor if that setting is checked and reset to (0,0). --- .../plugins/virtual_printer/virtual.py | 18 ++++++--- src/octoprint/printer/profile.py | 25 ++++++++++-- src/octoprint/settings.py | 3 +- .../static/js/app/viewmodels/gcode.js | 2 +- .../js/app/viewmodels/printerprofiles.js | 8 +++- .../static/js/app/viewmodels/temperature.js | 5 ++- .../profileEditorExtruder.jinja2 | 40 ++++++++++++------- 7 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/octoprint/plugins/virtual_printer/virtual.py b/src/octoprint/plugins/virtual_printer/virtual.py index afd4179a..ac8d7ed5 100644 --- a/src/octoprint/plugins/virtual_printer/virtual.py +++ b/src/octoprint/plugins/virtual_printer/virtual.py @@ -54,8 +54,12 @@ class VirtualPrinter(object): self._send(item) self.currentExtruder = 0 - self.temp = [0.0] * settings().getInt(["devel", "virtualPrinter", "numExtruders"]) - self.targetTemp = [0.0] * settings().getInt(["devel", "virtualPrinter", "numExtruders"]) + self.extruderCount = settings().getInt(["devel", "virtualPrinter", "numExtruders"]) + self.sharedNozzle = settings().getBoolean(["devel", "virtualPrinter", "sharedNozzle"]) + self.temperatureCount = (1 if self.sharedNozzle else self.extruderCount) + + self.temp = [0.0] * self.temperatureCount + self.targetTemp = [0.0] * self.temperatureCount self.lastTempAt = time.time() self.bedTemp = 1.0 self.bedTargetTemp = 1.0 @@ -301,8 +305,10 @@ class VirtualPrinter(object): ##~~ command implementations def _gcode_T(self, code, data): - self.currentExtruder = int(code) - self._send("Active Extruder: %d" % self.currentExtruder) + t = int(code) + if 0 <= t <= self.extruderCount: + self.currentExtruder = t + self._send("Active Extruder: %d" % self.currentExtruder) def _gcode_F(self, code, data): if self._supportF: @@ -628,7 +634,7 @@ class VirtualPrinter(object): includeOk = not self._okBeforeCommandOutput # send simulated temperature data - if settings().getInt(["devel", "virtualPrinter", "numExtruders"]) > 1: + if self.temperatureCount > 1: allTemps = [] for i in range(len(self.temp)): allTemps.append((i, self.temp[i], self.targetTemp[i])) @@ -672,7 +678,7 @@ class VirtualPrinter(object): except: pass - if tool >= settings().getInt(["devel", "virtualPrinter", "numExtruders"]): + if tool >= self.temperatureCount: return try: diff --git a/src/octoprint/printer/profile.py b/src/octoprint/printer/profile.py index 304e0c98..fb8f8980 100644 --- a/src/octoprint/printer/profile.py +++ b/src/octoprint/printer/profile.py @@ -124,7 +124,10 @@ class PrinterProfileManager(object): - Extruder offsets relative to first extruder, list of (x, y) tuples, first is always (0,0) * - ``extruder.nozzleDiameter`` - ``float`` - - Diameter of the printer nozzle + - Diameter of the printer nozzle(s) + * - ``extruder.sharedNozzle`` + - ``boolean`` + - Whether there's only one nozzle shared among all extruders (true) or one nozzle per extruder (false). * - ``axes`` - ``dict`` - Information about the printer axes @@ -185,7 +188,8 @@ class PrinterProfileManager(object): offsets = [ (0, 0) ], - nozzleDiameter = 0.4 + nozzleDiameter = 0.4, + sharedNozzle = False ), axes=dict( x = dict(speed=6000, inverted=False), @@ -390,6 +394,13 @@ class PrinterProfileManager(object): def _load_default(self): default_overrides = settings().get(["printerProfiles", "defaultProfile"]) + if self._migrate_profile(default_overrides): + try: + settings().set(["printerProfiles", "defaultProfile"], default_overrides) + settings().save() + except: + self._logger.exception("Tried to save default profile after migrating it while loading, ran into exception") + profile = self._ensure_valid_profile(dict_merge(copy.deepcopy(self.__class__.default), default_overrides)) if not profile: self._logger.warn("Invalid default profile after applying overrides") @@ -424,6 +435,14 @@ class PrinterProfileManager(object): profile["volume"]["custom_box"] = False modified = True + if "extruder" in profile and not "sharedNozzle" in profile["extruder"]: + profile["extruder"]["sharedNozzle"] = False + modified = True + + if "extruder" in profile and "sharedNozzle" in profile["extruder"] and profile["extruder"]["sharedNozzle"]: + profile["extruder"]["offsets"] = [(0.0, 0.0)] + modified = True + return modified def _ensure_valid_profile(self, profile): @@ -462,7 +481,7 @@ class PrinterProfileManager(object): return False # convert booleans - for path in (("axes", "x", "inverted"), ("axes", "y", "inverted"), ("axes", "z", "inverted")): + for path in (("axes", "x", "inverted"), ("axes", "y", "inverted"), ("axes", "z", "inverted"), ("extruder", "sharedNozzle")): try: convert_value(profile, path, bool) except Exception as e: diff --git a/src/octoprint/settings.py b/src/octoprint/settings.py index 9a80273b..7d677ac0 100644 --- a/src/octoprint/settings.py +++ b/src/octoprint/settings.py @@ -356,7 +356,8 @@ default_settings = { "echoOnM117": True, "brokenM29": True, "supportF": False, - "firmwareName": "Virtual Marlin 1.0" + "firmwareName": "Virtual Marlin 1.0", + "sharedNozzle": False } } } diff --git a/src/octoprint/static/js/app/viewmodels/gcode.js b/src/octoprint/static/js/app/viewmodels/gcode.js index d167fb14..d4ae7c31 100644 --- a/src/octoprint/static/js/app/viewmodels/gcode.js +++ b/src/octoprint/static/js/app/viewmodels/gcode.js @@ -174,7 +174,7 @@ $(function() { currentProfileData = self.settings.printerProfiles.currentProfileData(); } - if (currentProfileData && currentProfileData.extruder && currentProfileData.extruder.offsets()) { + if (currentProfileData && currentProfileData.extruder && currentProfileData.extruder.offsets() && !currentProfileData.extruder.sharedNozzle()) { var offsets = []; _.each(currentProfileData.extruder.offsets(), function(offset) { offsets.push({x: offset[0], y: offset[1]}) diff --git a/src/octoprint/static/js/app/viewmodels/printerprofiles.js b/src/octoprint/static/js/app/viewmodels/printerprofiles.js index 61ab6906..b4d76e22 100644 --- a/src/octoprint/static/js/app/viewmodels/printerprofiles.js +++ b/src/octoprint/static/js/app/viewmodels/printerprofiles.js @@ -25,7 +25,8 @@ $(function() { offsets: [ [0,0] ], - nozzleDiameter: 0.4 + nozzleDiameter: 0.4, + sharedNozzle: false } } }; @@ -63,6 +64,7 @@ $(function() { self.nozzleDiameter = ko.observable(); self.extruders = ko.observable(); self.extruderOffsets = ko.observableArray(); + self.sharedNozzle = ko.observable(); self.axisXSpeed = ko.observable(); self.axisYSpeed = ko.observable(); @@ -209,6 +211,7 @@ $(function() { self.heatedBed(data.heatedBed); self.nozzleDiameter(data.extruder.nozzleDiameter); + self.sharedNozzle(data.extruder.sharedNozzle); self.extruders(data.extruder.count); var offsets = []; if (data.extruder.count > 1) { @@ -271,7 +274,8 @@ $(function() { offsets: [ [0.0, 0.0] ], - nozzleDiameter: validFloat(self.nozzleDiameter(), defaultProfile.extruder.nozzleDiameter) + nozzleDiameter: validFloat(self.nozzleDiameter(), defaultProfile.extruder.nozzleDiameter), + sharedNozzle: self.sharedNozzle() }, axes: { x: { diff --git a/src/octoprint/static/js/app/viewmodels/temperature.js b/src/octoprint/static/js/app/viewmodels/temperature.js index 9dbd4991..e0f221c7 100644 --- a/src/octoprint/static/js/app/viewmodels/temperature.js +++ b/src/octoprint/static/js/app/viewmodels/temperature.js @@ -49,7 +49,8 @@ $(function() { // tools var currentProfileData = self.settingsViewModel.printerProfiles.currentProfileData(); var numExtruders = (currentProfileData ? currentProfileData.extruder.count() : 0); - if (numExtruders && numExtruders > 1) { + var sharedNozzle = (currentProfileData ? currentProfileData.extruder.sharedNozzle() : false); + if (numExtruders && numExtruders > 1 && !sharedNozzle) { // multiple extruders for (var extruder = 0; extruder < numExtruders; extruder++) { color = graphColors.shift(); @@ -62,7 +63,7 @@ $(function() { tools[extruder]["name"](gettext("Tool") + " " + extruder); tools[extruder]["key"]("tool" + extruder); } - } else if (numExtruders == 1) { + } else if (numExtruders == 1 || sharedNozzle) { // only one extruder, no need to add numbers color = graphColors[0]; heaterOptions["tool0"] = {name: "T", color: color}; diff --git a/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 b/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 index 2e09ad58..d509f117 100644 --- a/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 +++ b/src/octoprint/templates/snippets/settings/printerprofiles/profileEditorExtruder.jinja2 @@ -17,28 +17,38 @@
+
- {{ _('Please specify the nozzle offsets of the extruders relative to the first nozzle T0.') }} + + {{ _('Check this if your printer has a single nozzle and heater shared among its extruders instead of one nozzle and heater per extruder') }}
- -
- -
- -
- - mm -
- -
- - mm +
+
+
+ {{ _('Please specify the nozzle offsets of the extruders relative to the first nozzle T0.') }}
+ + +
+ +
+ +
+ + mm +
+ +
+ + mm +
+
+
+
-