From 8ec9521fab778ed3622327ddc69f8dff1944acd4 Mon Sep 17 00:00:00 2001 From: GregValiant <64202104+GregValiant@users.noreply.github.com> Date: Fri, 8 Sep 2023 13:00:25 -0400 Subject: [PATCH] Update MultiExtColorMix.py Add functionality for 4-in-one-out hot ends. Add an exit if the firmware is RepRap (M567 is not supported). Update MultiExtColorMix.py Change the variable names to start with lower case letter. Altered messages to include a title. Update MultiExtColorMix.py More variable name changes. Changed some string formats to templates. Update MultiExtColorMix.py merge 2 --- .../scripts/MultiExtColorMix.py | 503 +++++++++++------- 1 file changed, 300 insertions(+), 203 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/MultiExtColorMix.py b/plugins/PostProcessingPlugin/scripts/MultiExtColorMix.py index 735c7df09f7..6229edac941 100644 --- a/plugins/PostProcessingPlugin/scripts/MultiExtColorMix.py +++ b/plugins/PostProcessingPlugin/scripts/MultiExtColorMix.py @@ -1,16 +1,13 @@ -# Written by GregValiant (Greg Foresi) June of 2023 with thanks to @AHoeben and @Ghostkeeper +# Written by GregValiant (Greg Foresi) June of 2023 # Released under the terms of the AGPLv3 or higher. # -# Revised: Sept 1, 2023 -# Bug fix. -# Allow 4-in-1-out hot ends although only 3 can be used. -# -# This post processor is for machines with a 2-in-1-out or 3-in-1-out hot ends that have shared heaters and nozzles. +# This post processor is for machines with a 2-in-1-out, 3-in-1-out, or 4-in-1-out hot ends that have shared heaters and nozzles. # If 'Extruders Share Heater' and 'Extruders Share Nozzle' are not enabled in Cura - the post will exit. -# This script REQUIRES that M163 and M164 are enabled in the firmware. +# This script REQUIRES that M163 and M164 are enabled in the firmware. (RepRap uses M567 and is not compatible.) # Prime Towers are not allowed. +# 'One-at-a-Time' is not supported # 'Printer Settings / Shared Nozzle Initial Retraction Amount' and 'Dual Extrusion / Nozzle Switch Retraction Distance' will be set to "0". You will be informed of your defaults so you can reset them manually after slicing is complete. -# Options are: Constant Mix or Gradient Mix. A Range of Layers, or Entire File. 'Resume Extruder' and 'Purge'. +# Options are: Constant Mix, Gradient Mix, Range of Layers, the Entire File, the 'Resume Extruder' and whether to 'Purge' at mix change. # Additional instances of the Post Processor can be run on different layers and with different mix ratios. # All tool changes that Cura might insert will be removed from the gcode. # All M109 and M104's will be removed starting at LAYER:0. @@ -23,10 +20,10 @@ # Ex: If you are using three extruders and the first starts with 35, and 2nd with 10 then E3 must start with 55. # The same thing applies to the End numbers when you use a gradient mix. # If the Percentage Sums do not add up then the post will exit with a message. -# The virtual extruder is always Extruder_count+1 (either T2 or T3 in the gcode) +# The virtual extruder is always Extruder_count+1. (If the printer has 3 extruders then the virtual mixing extruder will be Extruder 4 (T3)). # This Post can also be used to simply set an extruder mix for an entire print. # May be used with either Absolute or Relative extrusion. -# 'One-at-a-Time' printing is a work in process. It is typically not allowed for multi-extruder printers. +# 'One-at-a-Time' printing is not supported as it isn't allowed for multi-extruder printers in Cura. from ..Script import Script from UM.Application import Application @@ -38,10 +35,17 @@ class MultiExtColorMix(Script): # Adjust Cura settings and enable the third extruder if there is one-- def initialize(self) -> None: super().initialize() + firmware_flavor = str(Application.getInstance().getGlobalContainerStack().getProperty("machine_gcode_flavor", "value")) + if firmware_flavor != "RepRap (Marlin/Sprinter)": + Message(title = "Multi-Extruder Color Mixer:", text = "This post processor is only compatible with Marlin firmware. The post processor will not run.").show() + self._instance.setProperty("enable_3rd_extruder", "value", False) + self._instance.setProperty("enable_4th_extruder", "value", False) ext_list = Application.getInstance().getGlobalContainerStack().extruderList extruder_count = Application.getInstance().getGlobalContainerStack().getProperty("machine_extruder_count", "value") enable_3rd_extruder = extruder_count > 2 + enable_4th_extruder = extruder_count > 3 self._instance.setProperty("enable_3rd_extruder", "value", enable_3rd_extruder) + self._instance.setProperty("enable_4th_extruder", "value", enable_4th_extruder) self._instance.setProperty("resume_ext_nr", "maximum_value_warning", int(extruder_count)) # Disable the Prime Tower as it interferes with the tool changes by this script if bool(Application.getInstance().getGlobalContainerStack().getProperty("prime_tower_enable", "value")): @@ -67,7 +71,8 @@ def initialize(self) -> None: ext1_default_str = "" ext2_default_str = "" ext3_default_str = "" - if extruder_count == 2: + ext4_default_str = "" + if extruder_count >= 2: ext1_default_str += "Ext 1 Nozzle Switch Retraction Distance = " + str(switch_retraction_list[0]) + "\n" ext1_default_str += "Ext 1 Shared Extruder Initial Retraction Amount = " + str(shared_retraction_list[0]) + "\n" ext2_default_str += "Ext 2 Nozzle Switch Retraction Distance = " + str(switch_retraction_list[1]) + "\n" @@ -75,16 +80,19 @@ def initialize(self) -> None: if extruder_count >= 3: ext3_default_str += "Ext 3 Nozzle Switch Retraction Distance = " + str(switch_retraction_list[2]) + "\n" ext3_default_str += "Ext 3 Shared Extruder Initial Retraction Amount = " + str(shared_retraction_list[2]) + "\n" + if extruder_count == 4: + ext3_default_str += "Ext 4 Nozzle Switch Retraction Distance = " + str(switch_retraction_list[3]) + "\n" + ext3_default_str += "Ext 4 Shared Extruder Initial Retraction Amount = " + str(shared_retraction_list[3]) + "\n" if multi_present == 1: - Message(text = "Multi-Extruder Color Mixer:" + "\n" + "You must have a Blending Hot End and 'Extruders Share Heater' and 'Extruders Share Nozzle' must be enabled in the 'Printer Settings' in Cura." + "\n" + "The 'Printer Settings / Shared Nozzle Initial Retraction Amount' will be set to '0.0' for all extruders." + "\n" + "The 'Dual Extrusion / Nozzle Switch Retraction Distance' will be set to '0.0' for all extruders." + "\n" + "Prime Tower is not allowed and will be turned off." + "\n\n" + "Note Your Default Settings:" + "\n" + ext1_default_str + ext2_default_str + ext3_default_str).show() + Message(title = "Multi-Extruder Color Mixer:", text = "You must have a Blending Hot End and 'Extruders Share Heater' and 'Extruders Share Nozzle' must be enabled in the 'Printer Settings' in Cura." + "\n" + "The 'Printer Settings / Shared Nozzle Initial Retraction Amount' will be set to '0.0' for all extruders." + "\n" + "The 'Dual Extrusion / Nozzle Switch Retraction Distance' will be set to '0.0' for all extruders." + "\n" + "Prime Tower is not allowed and will be turned off." + "\n\n" + "Note Your Default Settings:" + "\n" + ext1_default_str + ext2_default_str + ext3_default_str + ext4_default_str).show() except: - all + pass def getSettingDataString(self): return """{ - "name":"Multi-Extruder Color Mixer", - "key":"MultiExtColorMix", + "name": "Multi-Extruder Color Mixer", + "key": "MultiExtColorMix", "metadata": {}, "version": 2, "settings": @@ -123,7 +131,7 @@ def getSettingDataString(self): "maximum_value": "4", "enabled": "end_layer != -1" }, - "T0_include": + "t0_include": { "label": "Ext-1 in the Mix", "description": "Check For dual extruders. For 3-in-1-out hot end Check if you want this extruder in the Mix.", @@ -131,7 +139,7 @@ def getSettingDataString(self): "default_value": true, "enabled": true }, - "T0_mix_start": + "t0_mix_start": { "label": " Ext-1 Start mix %", "description": "First extruder percentage 0-100", @@ -139,11 +147,11 @@ def getSettingDataString(self): "unit": "%", "default_value": 100, "minimum_value": "0", - "minimum_value_warning": "0", - "maximum_value_warning": "100", - "enabled": "T0_include" + "minimum_value": "0", + "maximum_value": "100", + "enabled": "t0_include" }, - "T0_mix_end": + "t0_mix_end": { "label": " Ext-1 End mix %", "description": "First extruder percentage 0-100 to finish blend", @@ -151,11 +159,10 @@ def getSettingDataString(self): "unit": "%", "default_value": 0, "minimum_value": "0", - "minimum_value_warning": "0", - "maximum_value_warning": "100", - "enabled": "T0_include and mix_style == 'gradient'" + "maximum_value": "100", + "enabled": "t0_include and mix_style == 'gradient'" }, - "T1_include": + "t1_include": { "label": "Ext-2 in the Mix", "description": "Check For dual extruders. For 3-in-1-out hot end Check if you want this extruder included in the Mix.", @@ -163,19 +170,18 @@ def getSettingDataString(self): "default_value": true, "enabled": true }, - "T1_mix_start": + "t1_mix_start": { "label": " Ext-2 Start mix %", "description": "Second extruder percentage 0-100", "type": "int", "unit": "%", "default_value": 0, - "minimum_value": "0", - "minimum_value_warning": "0", - "maximum_value_warning": "100", - "enabled": "T1_include" + "minimum_value": "0 + "maximum_value": "100", + "enabled": "t1_include" }, - "T1_mix_end": + "t1_mix_end": { "label": " Ext-2 End mix %", "description": "Second extruder percentage 0-100 to finish blend", @@ -183,9 +189,8 @@ def getSettingDataString(self): "unit": "%", "default_value": 100, "minimum_value": "0", - "minimum_value_warning": "0", - "maximum_value_warning": "100", - "enabled": "T1_include and mix_style == 'gradient'" + "maximum_value": "100", + "enabled": "t1_include and mix_style == 'gradient'" }, "enable_3rd_extruder": { @@ -195,7 +200,7 @@ def getSettingDataString(self): "default_value": false, "enabled": false }, - "T2_include": + "t2_include": { "label": "Ext-3 in the Mix", "description": "For 3-in-1-out hot end Check if you want this extruder included in the Mix.", @@ -203,7 +208,7 @@ def getSettingDataString(self): "default_value": false, "enabled": "enable_3rd_extruder" }, - "T2_mix_start": + "t2_mix_start": { "label": " Ext-3 Start mix %", "description": "Third extruder percentage 0-100", @@ -211,11 +216,10 @@ def getSettingDataString(self): "unit": "%", "default_value": 0, "minimum_value": "0", - "minimum_value_warning": "0", - "maximum_value_warning": "100", - "enabled": "T2_include" + "maximum_value": "100", + "enabled": "t2_include" }, - "T2_mix_end": + "t2_mix_end": { "label": " Ext-3 End mix %", "description": "Third extruder percentage 0-100 to finish blend", @@ -223,9 +227,46 @@ def getSettingDataString(self): "unit": "%", "default_value": 0, "minimum_value": "0", - "minimum_value_warning": "0", - "maximum_value_warning": "100", - "enabled": "T2_include and mix_style == 'gradient'" + "maximum_value": "100", + "enabled": "t2_include and mix_style == 'gradient'" + }, + "enable_4th_extruder": + { + "label": "Enable 4th Extruder:", + "description": "Hidden from the user. Sets 'T3_enable' visibility to true if there are 4 extruders.", + "type": "bool", + "default_value": false, + "enabled": false + }, + "t3_include": + { + "label": "Ext-4 in the Mix", + "description": "For 4-in-1-out hot end Check if you want this extruder included in the Mix.", + "type": "bool", + "default_value": false, + "enabled": "enable_4th_extruder" + }, + "t3_mix_start": + { + "label": " Ext-4 Start mix %", + "description": "Fourth extruder percentage 0-100", + "type": "int", + "unit": "%", + "default_value": 0, + "minimum_value": "0", + "maximum_value": "100", + "enabled": "t3_include and enable_4th_extruder" + }, + "t3_mix_end": + { + "label": " Ext-4 End mix %", + "description": "Fourth extruder percentage 0-100 to finish blend", + "type": "int", + "unit": "%", + "default_value": 0, + "minimum_value": "0", + "maximum_value": "100", + "enabled": "t3_include and mix_style == 'gradient'" }, "park_head": { @@ -261,61 +302,79 @@ def getSettingDataString(self): "minimum_value": "1", "maximum_value": "50", "enabled": "park_head" + }, + "park_head_init_only": + { + "label": " Initial Purge only", + "description": "When enabled only the first use of the mixing extruder will Park and Purge. Any other changes will be done on-the-fly.", + "type": "bool", + "default_value": false, + "enabled": "park_head" } } }""" def execute(self, data): - MyCura = Application.getInstance().getGlobalContainerStack() - extruder_count = MyCura.getProperty("machine_extruder_count", "value") + mycura = Application.getInstance().getGlobalContainerStack() + extruder_count = mycura.getProperty("machine_extruder_count", "value") init_extruder = Application.getInstance().getExtruderManager().getInitialExtruderNr() - if extruder_count >1: - T0_include = self.getSettingValueByKey("T0_include") - T1_include = self.getSettingValueByKey("T1_include") - T2_include = False - if extruder_count >= 3: - T2_include = self.getSettingValueByKey("T2_include") + firmware_flavor = str(mycura.getProperty("machine_gcode_flavor", "value")) + if firmware_flavor != "RepRap (Marlin/Sprinter)": + Message(title = "Multi-Extruder Color Mixer:", text = "This post processor is only compatible with Marlin firmware. The post processor will exit.").show() + data[0] += "; [Multi-Extruder Color Mix] Did not run because it is only compatible with Marlin firmware\n" + return data + if extruder_count > 1: + t0_include = self.getSettingValueByKey("t0_include") + t1_include = self.getSettingValueByKey("t1_include") + t2_include = False + t3_include = False + if extruder_count >= 2: + t2_include = self.getSettingValueByKey("t2_include") + t3_include = False + if extruder_count > 3: + t3_include = self.getSettingValueByKey("t3_include") park_head = bool(self.getSettingValueByKey("park_head")) park_x = str(self.getSettingValueByKey("park_x")) park_y = str(self.getSettingValueByKey("park_y")) purge_amt = str(self.getSettingValueByKey("purge_amt")) + park_head_init_only = bool(self.getSettingValueByKey("park_head_init_only")) park_string = "" # If the Prime Tower is enabled after the script is loaded then inform the user and exit----- - if bool(MyCura.getProperty("prime_tower_enable", "value")): + if bool(mycura.getProperty("prime_tower_enable", "value")): data[0] += "; [Multi-Extruder Color Mixer] Did not run because - Prime Tower is enabled.\n" - Message(text = "[Multi-Extruder Color Mixer]: DID NOT RUN because Prime Tower is enabled.").show() - return data - + Message(title = "[Multi-Extruder Color Mixer]:", text = "DID NOT RUN because Prime Tower is enabled.").show() + return data + # If Extruder Count > 3 then inform the user that the maximum useable number is 3 extruders - if extruder_count > 3: - Message(text = "[Multi-Extruder Color Mixer]: the number of extruders is > 3 but only extruders #1, #2, and #3 can be used when mixing.").show() + if extruder_count > 4: + Message(title = "[Multi-Extruder Color Mixer]:", text = "The number of extruders is > 4 but only extruders #1, #2, #3, and #4 can be used when mixing.").show() # If it is a single extruder printer exit with a message----------- if extruder_count == 1: data[0] += "; [Multi-Extruder Color Mixer] did not run because the printer has one extruder\n" - Message(text = "Multi-Extruder Color Mixer: {}".format("The post processor exited because the printer has a single extruder.")).show() + Message(title = "Multi-Extruder Color Mixer:", text = "The post processor exited because the printer has a single extruder.").show() return data # If the printer is not equipped with Shared Heater and Shared Nozzle then exit with a message------------------ - shared_heater = bool(MyCura.getProperty("machine_extruders_share_heater", "value")) + shared_heater = bool(mycura.getProperty("machine_extruders_share_heater", "value")) try: - shared_nozzle = bool(MyCura.getProperty("machine_extruders_share_nozzle", "value")) + shared_nozzle = bool(mycura.getProperty("machine_extruders_share_nozzle", "value")) except: shared_nozzle = shared_heater if not shared_heater and not shared_nozzle: - Message(text = "Multi-Extruder Color Mixer: {}".format("This post is for machines with 'Shared Heaters' and 'Shared Nozzles'. Separate hot ends won't work. Those settings are not enabled in Cura. The Post Process will exit.")).show() + Message(title = "Multi-Extruder Color Mixer:", text = "This post is for machines with 'Shared Heaters' and 'Shared Nozzles'. Separate hot ends won't work. Those settings are not enabled in Cura. The Post Process will exit.").show() data[0] += "; [Multi-Extruder Color Mixer] did not run because - 'Shared Heaters' and/or 'Shared Nozzles' are not enabled in Cura.\n" return data - + # Set variables--------------------------------------------------------------------- start_layer = self.getSettingValueByKey("start_layer") - 1 end_layer = self.getSettingValueByKey("end_layer") resume_ext_nr = self.getSettingValueByKey("resume_ext_nr")-1 if resume_ext_nr > extruder_count + 1: resume_ext_nr = extruder_count + 1 - M164_ext_nr = extruder_count + m164_ext_nr = extruder_count mix_style = self.getSettingValueByKey("mix_style") - + # Figure out the actual End Layer------------------------------------------------------------- if end_layer == -1: end_layer = len(data)-2 @@ -324,45 +383,56 @@ def execute(self, data): layer_span = end_layer - start_layer - 1 # Calculate the 'Gradient' Indexing Factor for extruders included in the mixing------------ - if T0_include: - T0_mix_start = int(self.getSettingValueByKey("T0_mix_start")) - T0_mix_end = int(self.getSettingValueByKey("T0_mix_end")) - T0_ext_incr = (T0_mix_start - T0_mix_end) / (layer_span - 1) + if t0_include: + t0_mix_start = int(self.getSettingValueByKey("t0_mix_start")) + t0_mix_end = int(self.getSettingValueByKey("t0_mix_end")) + t0_ext_incr = (t0_mix_start - t0_mix_end) / (layer_span - 1) + else: + t0_mix_start = 0 + t0_mix_end = 0 + t0_ext_incr = 0 + if t1_include: + t1_mix_start = int(self.getSettingValueByKey("t1_mix_start")) + t1_mix_end = int(self.getSettingValueByKey("t1_mix_end")) + t1_ext_incr = (t1_mix_start - t1_mix_end) / (layer_span - 1) else: - T0_mix_start = 0 - T0_mix_end = 0 - T0_ext_incr = 0 - if T1_include: - T1_mix_start = int(self.getSettingValueByKey("T1_mix_start")) - T1_mix_end = int(self.getSettingValueByKey("T1_mix_end")) - T1_ext_incr = (T1_mix_start - T1_mix_end) / (layer_span - 1) + t1_mix_start = 0 + t1_mix_end = 0 + t1_ext_incr = 0 + if t2_include: + t2_mix_start = int(self.getSettingValueByKey("t2_mix_start")) + t2_mix_end = int(self.getSettingValueByKey("t2_mix_end")) + t2_ext_incr = (t2_mix_start - t2_mix_end) / (layer_span - 1) else: - T1_mix_start = 0 - T1_mix_end = 0 - T1_ext_incr = 0 - if T2_include: - T2_mix_start = int(self.getSettingValueByKey("T2_mix_start")) - T2_mix_end = int(self.getSettingValueByKey("T2_mix_end")) - T2_ext_incr = (T2_mix_start - T2_mix_end) / (layer_span - 1) + t2_mix_start = 0 + t2_mix_end = 0 + t2_ext_incr = 0 + if t3_include: + t3_mix_start = int(self.getSettingValueByKey("t3_mix_start")) + t3_mix_end = int(self.getSettingValueByKey("t3_mix_end")) + t3_ext_incr = (t3_mix_start - t3_mix_end) / (layer_span - 1) else: - T2_mix_start = 0 - T2_mix_end = 0 - T2_ext_incr = 0 + t3_mix_start = 0 + t3_mix_end = 0 + t3_ext_incr = 0 # Check that the Start Percentages and the End Percentages add up to 100. If not then Exit with a message---- total_start_percent = 0 total_end_percent = 0 - if T0_include: - total_start_percent += T0_mix_start - total_end_percent += T0_mix_end - if T1_include: - total_start_percent += T1_mix_start - total_end_percent += T1_mix_end - if T2_include: - total_start_percent += T2_mix_start - total_end_percent += T2_mix_end + if t0_include: + total_start_percent += t0_mix_start + total_end_percent += t0_mix_end + if t1_include: + total_start_percent += t1_mix_start + total_end_percent += t1_mix_end + if t2_include: + total_start_percent += t2_mix_start + total_end_percent += t2_mix_end + if t3_include: + total_start_percent += t3_mix_start + total_end_percent += t3_mix_end - # Remove the existing tool changes and temperature lines from the data. This is supposed to leave one G92 E0 at each previous tool change------------------ + # Remove the existing tool changes and temperature lines from the data. This leaves one G92 E0 at each previous tool change------------------ for num in range(start_layer+2,len(data)-1,1): data[num] = re.sub("G92 E0\nT(\d*)\n", "", data[num]) data[num] = re.sub("M109 S(\d.*)\n", "",data[num]) @@ -373,33 +443,39 @@ def execute(self, data): if mix_style == "constant": total_end_percent = 100 if total_start_percent != 100 or total_end_percent != 100: - textstring = "The post processor exited due to a 'Total Percentage' error. Start Total Percent = " + str(total_start_percent) + " EndTotalPercent = " + str(total_end_percent) + " Both sums must equal 100" - Message(text = "[Multi-Extruder Color Mixer]: {}".format(textstring)).show() - data[0] += "; [Multi-Extruder Color Mixer] Did not run because Start Total Percent = " + str(total_start_percent) + " EndTotalPercent = " + str(total_end_percent) + " Both sums must equal 100%\n" + textstring = "The post processor exited due to a 'Total Percentage' error. Start Total Percent = " + str(total_start_percent) + " EndTotalPercent = " + str(total_end_percent) + " Each sum must equal 100" + Message(title = "[Multi-Extruder Color Mixer]:", text = textstring).show() + data[0] += "; [Multi-Extruder Color Mixer] Did not run because Start Total Percent = " + str(total_start_percent) + " EndTotalPercent = " + str(total_end_percent) + " Each sum must equal 100%\n" return data # Put together the Reset String----------------------------------------------------------- - M163_reset = "" + m163_reset = "" if extruder_count == 2: - M163_reset = "M163 P0.50 S0" + "\nM163 P0.50 S1\n" - if extruder_count >= 3: - M163_reset = "M163 P0.33 S0" + "\nM163 P0.34 S1\n" + "M163 P0.33 S2\n" - M163_reset += "M164 S" + str(M164_ext_nr) + "\n" + m163_reset = "M163 P0.50 S0" + "\nM163 P0.50 S1\n" + if extruder_count == 3: + m163_reset = "M163 P0.33 S0" + "\nM163 P0.34 S1\n" + "M163 P0.33 S2\n" + if extruder_count == 4: + m163_reset = "M163 P0.25 S0" + "\nM163 P0.25 S1\n" + "M163 P0.25 S2\n" + "M163 P0.25 S3\n" + m163_reset += "M164 S" + str(m164_ext_nr) + "\n" # Put together the Initial Mix String----------------------------------- - if T0_include: - M163_T0 = "\nM163 P" + str(T0_mix_start/100) + " S0" + if t0_include: + m163_t0 = "\nM163 P" + str(t0_mix_start/100) + " S0" + else: + m163_t0 = "" + if t1_include: + m163_t1 = "\nM163 P" + str(t1_mix_start/100) + " S1" else: - M163_T0 = "" - if T1_include: - M163_T1 = "\nM163 P" + str(T1_mix_start/100) + " S1" + m163_t1 = "" + if t2_include: + m163_t2 = "\nM163 P" + str(t2_mix_start/100) + " S2" else: - M163_T1 = "" - if T2_include: - M163_T2 = "\nM163 P" + str(T2_mix_start/100) + " S2" + m163_t2 = "" + if t3_include: + m163_t3 = "\nM163 P" + str(t3_mix_start/100) + " S3" else: - M163_T2 = "" - M164str = M163_T0 + M163_T1 + M163_T2 + "\nM164 S" + str(M164_ext_nr) + "\nT" + str(M164_ext_nr) + m163_t3 = "" + m164str = m163_t0 + m163_t1 + m163_t2 + m163_t3 + "\nM164 S" + str(m164_ext_nr) + "\nT" + str(m164_ext_nr) # If purge is selected-------------------------------------------------------- initial_purge = "" @@ -407,11 +483,11 @@ def execute(self, data): final_string = "" if park_head: initial_purge = self.park_script(0, data, park_x, park_y, purge_amt)[1] - if park_head and M164_ext_nr != resume_ext_nr: + if park_head and m164_ext_nr != resume_ext_nr and not park_head_init_only: start_purge = self.park_script(start_layer, data, park_x, park_y, purge_amt)[1] if park_head and self.getSettingValueByKey("end_layer") != -1: final_string = self.park_script(end_layer, data, park_x, park_y, purge_amt)[0] - + # Check to see if a reset is already present (do to multiple instances of this post processor running) and if so then move on------------------------------- reset_present = False start_up_sect = data[1] @@ -422,12 +498,13 @@ def execute(self, data): reset_present = True break if not reset_present: - init_str = M163_T0 + M163_T1 + M163_T2 + "\nM164 S" + str(M164_ext_nr) + "\nT" + str(init_extruder) + init_str = m163_t0 + m163_t1 + m163_t2 + m163_t3 + "\nM164 S" + str(m164_ext_nr) + "\nT" + str(init_extruder) if start_layer > 0: init_str += initial_purge lines = data[1].split("\n") lines.insert(len(lines)-2, init_str[1:]) data[1] = "\n".join(lines) + # Constant if mix_style == "constant": self.processConstant(data, start_layer, @@ -436,8 +513,11 @@ def execute(self, data): park_x, park_y, purge_amt, - M164str, - resume_ext_nr) + m164str, + resume_ext_nr, + park_head_init_only) + + # Gradient elif mix_style == "gradient": self.processGradient(data, start_layer, @@ -446,23 +526,28 @@ def execute(self, data): park_x, park_y, purge_amt, - M164str, + m164str, resume_ext_nr, - T0_include, - T0_mix_start, - T0_ext_incr, - T1_include, - T1_mix_start, - T1_ext_incr, - T2_include, - T2_mix_start, - T2_ext_incr, - M163_T0, - M163_T1, - M163_T2, - M164_ext_nr) + t0_include, + t0_mix_start, + t0_ext_incr, + t1_include, + t1_mix_start, + t1_ext_incr, + t2_include, + t2_mix_start, + t2_ext_incr, + t3_include, + t3_mix_start, + t3_ext_incr, + m163_t0, + m163_t1, + m163_t2, + m163_t3, + m164_ext_nr, + park_head_init_only) if not reset_present: - data[len(data)-1] = M163_reset + "T" + str(resume_ext_nr) + "\n" + data[len(data)-1] + data[len(data)-1] = m163_reset + "T" + str(resume_ext_nr) + "\n" + data[len(data)-1] return data def processConstant(self, @@ -473,8 +558,9 @@ def processConstant(self, park_x: str, park_y: str, purge_amt: str, - M164str: str, - resume_ext_nr: int) -> str: + m164str: str, + resume_ext_nr: int, + park_head_init_only: bool) -> str: pre_ret = False post_prime = False for index, layer in enumerate(data): @@ -508,8 +594,9 @@ def processConstant(self, add_str = self.park_script(start_layer, data, park_x, park_y, purge_amt)[3] elif not park_head: add_str = "" - - data[index] = layer.replace(";LAYER:" + str(start_layer) + "\n", ";LAYER:" + str(start_layer) + M164str + add_str + "\n") + #if park_head_init_only: + # add_str = "" + data[index] = layer.replace(";LAYER:" + str(start_layer) + "\n", ";LAYER:" + str(start_layer) + m164str + add_str + "\n") if ";LAYER:" + str(end_layer) in layer: lines = layer.split("\n") # The last retraction and prime------------------------------------------ @@ -529,8 +616,8 @@ def processConstant(self, pre_ret = True break # Add final line depending on retraction and prime------------------------------- - if park_head: - if not pre_ret and not post_prime: + if park_head and not park_head_init_only: + if not pre_ret: final_string = self.park_script(end_layer, data, park_x, park_y, purge_amt)[0] elif not pre_ret and post_prime: final_string = self.park_script(end_layer, data, park_x, park_y, purge_amt)[1] @@ -540,6 +627,8 @@ def processConstant(self, final_string = self.park_script(end_layer, data, park_x, park_y, purge_amt)[3] elif not park_head: final_string = "" + #if park_head_init_only: + # final_string = "" data[index] = data[index].replace(";LAYER:" + str(end_layer), ";LAYER:" + str(end_layer) + "\n" + "T" + str(resume_ext_nr) + final_string) break return @@ -552,21 +641,26 @@ def processGradient(self, park_x: str, park_y: str, purge_amt: str, - M164str: str, + m164str: str, resume_ext_nr: int, - T0_include: bool, - T0_mix_start: int, - T0_ext_incr: int, - T1_include: bool, - T1_mix_start: int, - T1_ext_incr: int, - T2_include:bool, - T2_mix_start: int, - T2_ext_incr: int, - M163_T0: str, - M163_T1: str, - M163_T2: str, - M164_ext_nr: int) -> str: + t0_include: bool, + t0_mix_start: int, + t0_ext_incr: int, + t1_include: bool, + t1_mix_start: int, + t1_ext_incr: int, + t2_include:bool, + t2_mix_start: int, + t2_ext_incr: int, + t3_include:bool, + t3_mix_start: int, + t3_ext_incr: int, + m163_t0: str, + m163_t1: str, + m163_t2: str, + m163_t3: str, + m164_ext_nr: int, + park_head_init_only: bool) -> str: pre_ret = False post_prime = False for index, layer in enumerate(data): @@ -600,36 +694,44 @@ def processGradient(self, add_str = self.park_script(start_layer, data, park_x, park_y, purge_amt)[3] elif not park_head: add_str = "" - - data[index] = data[index].replace(";LAYER:" + str(start_layer) + "\n", ";LAYER:" + str(start_layer) + M164str + add_str + "\n") + + # Gradient percentages and fix rounding errors------------------------------ + data[index] = data[index].replace(";LAYER:" + str(start_layer) + "\n", ";LAYER:" + str(start_layer) + m164str + add_str + "\n") for L in range(index + 1, len(data)-2): - if T0_include: - T0_mix_start -= T0_ext_incr - if T0_mix_start > 100: T0_mix_start = 100 - if T0_mix_start < 0: T0_mix_start = 0 - M163_T0 = "\nM163 P" + str(round(T0_mix_start/100, 2)) + " S0" + if t0_include: + t0_mix_start -= t0_ext_incr + if t0_mix_start > 100: t0_mix_start = 100 + if t0_mix_start < 0: t0_mix_start = 0 + m163_t0 = "\nM163 P" + str(round(t0_mix_start/100, 2)) + " S0" + else: + m163_t0 = "" + if t1_include: + t1_mix_start -= t1_ext_incr + if t1_mix_start > 100: t1_mix_start = 100 + if t1_mix_start < 0: t1_mix_start = 0 + m163_t1 = "\nM163 P" + str(round(t1_mix_start/100, 2)) + " S1" else: - M163_T0 = "" - if T1_include: - T1_mix_start -= T1_ext_incr - if T1_mix_start > 100: T1_mix_start = 100 - if T1_mix_start < 0: T1_mix_start = 0 - M163_T1 = "\nM163 P" + str(round(T1_mix_start/100, 2)) + " S1" + m163_t1 = "" + if t2_include: + t2_mix_start -= t2_ext_incr + if t2_mix_start > 100: t2_mix_start = 100 + if t2_mix_start < 0: t2_mix_start = 0 + m163_t2 = "\nM163 P" + str(round(t2_mix_start/100, 2)) + " S2" else: - M163_T1 = "" - if T2_include: - T2_mix_start -= T2_ext_incr - if T2_mix_start > 100: T2_mix_start = 100 - if T2_mix_start < 0: T2_mix_start = 0 - M163_T2 = "\nM163 P" + str(round(T2_mix_start/100, 2)) + " S2" + m163_t2 = "" + if t3_include: + t3_mix_start -= t3_ext_incr + if t3_mix_start > 100: t3_mix_start = 100 + if t3_mix_start < 0: t3_mix_start = 0 + m163_t3 = "\nM163 P" + str(round(t3_mix_start/100, 2)) + " S3" else: - M163_T2 = "" - M164str = M163_T0 + M163_T1 + M163_T2 + "\nM164 S" + str(M164_ext_nr) + "\nT" + str(M164_ext_nr) + "\n" + m163_t3 = "" + m164str = m163_t0 + m163_t1 + m163_t2 + m163_t3 + "\nM164 S" + str(m164_ext_nr) + "\nT" + str(m164_ext_nr) + "\n" try: lines = data[L].split("\n") layer_num = int(lines[0].split(":")[1]) if layer_num < end_layer: - data[L] = data[L].replace(";LAYER:" + str(layer_num) + "\n", ";LAYER:" + str(layer_num) + M164str) + data[L] = data[L].replace(";LAYER:" + str(layer_num) + "\n", ";LAYER:" + str(layer_num) + m164str) elif layer_num == end_layer: lines = layer.split("\n") # determine retraction and prime------------------------------------ @@ -649,7 +751,7 @@ def processGradient(self, pre_ret = True break # Add the final line depending on retraction and prime - if park_head: + if park_head and not park_head_init_only: if not pre_ret and not post_prime: final_string = self.park_script(end_layer, data, park_x, park_y, purge_amt)[0] elif not pre_ret and post_prime: @@ -660,19 +762,21 @@ def processGradient(self, final_string = self.park_script(end_layer, data, park_x, park_y, purge_amt)[3] elif not park_head: final_string = "" - M164str = "\nT" + str(resume_ext_nr) - data[L] = data[L].replace(";LAYER:" + str(end_layer), ";LAYER:" + str(end_layer) + M164str + final_string) + if park_head_init_only: + final_string = "" + m164str = "\nT" + str(resume_ext_nr) + data[L] = data[L].replace(";LAYER:" + str(end_layer), ";LAYER:" + str(end_layer) + m164str + final_string) break except: - all + pass if layer_num == end_layer: break return @staticmethod def park_script(purge_layer: str, data: str, park_x: str, park_y: str, retract_amt: str) -> str: # Put together the park/purge lines to be inserted---------------------------- - MyCura = Application.getInstance().getGlobalContainerStack() - extruder = MyCura.extruderList + mycura = Application.getInstance().getGlobalContainerStack() + extruder = mycura.extruderList if int(purge_layer) < 50: zup = " Z12\n" zdn = " Z-12\n" @@ -699,38 +803,31 @@ def park_script(purge_layer: str, data: str, park_x: str, park_y: str, retract_a yloc = " Y" + str(ytemp) if xloc != "" and yloc != "": break - park_ret_prime = "\n; Multi Mix Purge\nG91\nM83\n" - park_ret = "\n; Multi Mix Purge\nG91\nM83\n" - park_prime = "\n; Multi Mix Purge\nG91\nM83\n" - park_none = "\n; Multi Mix Purge\nG91\nM83\n" - firmware_retract = bool(MyCura.getProperty("machine_firmware_retract", "value")) + park_ret_prime = "\n;TYPE:CUSTOM Multi Mix Purge\nG91\nM83\n" + park_ret = "\n;TYPE:CUSTOM Multi Mix Purge\nG91\nM83\n" + park_prime = "\n;TYPE:CUSTOM Multi Mix Purge\nG91\nM83\n" + park_none = "\n;TYPE:CUSTOM Multi Mix Purge\nG91\nM83\n" + firmware_retract = bool(mycura.getProperty("machine_firmware_retract", "value")) speed_travel = str(int(extruder[0].getProperty("speed_travel", "value")) * 60) speed_print = str(int(extruder[0].getProperty("speed_print", "value")) * 60) speed_z_hop = str(int(extruder[0].getProperty("speed_z_hop", "value")) * 60) retract_distance = str(extruder[0].getProperty("retraction_amount", "value")) speed_retract = " F" + str(int(extruder[0].getProperty("retraction_retract_speed", "value")) *60) - relative_ext = bool(MyCura.getProperty("relative_extrusion", "value")) - if relative_ext: - relative_str = "M83\n" - else: - relative_str = "M82\n" - if firmware_retract: - E_retract = "G10\n" - E_prime = "G11\n" - else: - E_retract = "G1" + speed_retract + " E-" + retract_distance + "\n" - E_prime = "G1" + speed_retract + " E" + retract_distance + "\n" + relative_ext = bool(mycura.getProperty("relative_extrusion", "value")) + relative_str = "M83\n" if relative_ext else "M82\n" + e_retract = "G10\n" if firmware_retract else f"G1{speed_retract} E-{retract_distance}\n" + e_prime = "G11\n" if firmware_retract else f"G1{speed_retract} E{retract_distance}\n" hop_str = "G1 F" + speed_z_hop + zup - park_at_str = "G0 F" + speed_travel + " X" + park_x + " Y" + park_y + "\n" - purge_str = "G1" + " F200" + " E" + retract_amt + "\n" + park_at_str = f"G0 F{speed_travel} X{park_x} Y{park_y}\n" + purge_str = f"G1 F200 E{retract_amt}\n" goto_str = "G0 F" + speed_travel + str(xloc) + str(yloc) + "\n" z_str = "G91\nG1 F" + speed_z_hop + zdn # Used when yes retraction and yes prime - park_ret_prime += E_retract + hop_str + "G90\n" + park_at_str + purge_str + E_retract + goto_str + z_str + E_prime + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" + park_ret_prime += e_retract + hop_str + "G90\n" + park_at_str + purge_str + e_retract + goto_str + z_str + e_prime + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" # Used when yes retraction and no prime - park_ret += E_retract + hop_str + "G90\n" + park_at_str + purge_str + E_retract + goto_str + z_str + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" + park_ret += e_retract + hop_str + "G90\n" + park_at_str + purge_str + e_retract + goto_str + z_str + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" # Used when no retraction and yes prime - park_prime += hop_str + "G90\n" + park_at_str + purge_str + E_retract + goto_str + z_str + E_prime + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" + park_prime += hop_str + "G90\n" + park_at_str + purge_str + e_retract + goto_str + z_str + e_prime + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" # Used when no retraction and no prime - park_none += hop_str + "G90\n" + park_at_str + purge_str + E_retract + goto_str + z_str + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" + park_none += hop_str + "G90\n" + park_at_str + purge_str + e_retract + goto_str + z_str + relative_str + "G90\nG1 F" + speed_print + "\n; End of Purge" return park_ret_prime, park_ret, park_prime, park_none \ No newline at end of file