FilamentChange.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. # Copyright (c) 2023 Ultimaker B.V.
  2. # The PostProcessingPlugin is released under the terms of the LGPLv3 or higher.
  3. # Modification 06.09.2020
  4. # add checkbox, now you can choose and use configuration from the firmware itself.
  5. from typing import List
  6. from ..Script import Script
  7. from UM.Application import Application # To get the current printer's settings.
  8. class FilamentChange(Script):
  9. _layer_keyword = ";LAYER:"
  10. def __init__(self):
  11. super().__init__()
  12. def getSettingDataString(self):
  13. return """{
  14. "name": "Filament Change",
  15. "key": "FilamentChange",
  16. "metadata": {},
  17. "version": 2,
  18. "settings":
  19. {
  20. "enabled":
  21. {
  22. "label": "Enable",
  23. "description": "Uncheck to temporarily disable this feature.",
  24. "type": "bool",
  25. "default_value": true
  26. },
  27. "layer_number":
  28. {
  29. "label": "Layer",
  30. "description": "At what layer should color change occur. This will be before the layer starts printing. Specify multiple color changes with a comma.",
  31. "unit": "",
  32. "type": "str",
  33. "default_value": "1",
  34. "enabled": "enabled"
  35. },
  36. "firmware_config":
  37. {
  38. "label": "Use Firmware Configuration",
  39. "description": "Use the settings in your firmware, or customise the parameters of the filament change here.",
  40. "type": "bool",
  41. "default_value": false,
  42. "enabled": "enabled"
  43. },
  44. "initial_retract":
  45. {
  46. "label": "Initial Retraction",
  47. "description": "Initial filament retraction distance. The filament will be retracted with this amount before moving the nozzle away from the ongoing print.",
  48. "unit": "mm",
  49. "type": "float",
  50. "default_value": 30.0,
  51. "enabled": "enabled and not firmware_config"
  52. },
  53. "later_retract":
  54. {
  55. "label": "Later Retraction Distance",
  56. "description": "Later filament retraction distance for removal. The filament will be retracted all the way out of the printer so that you can change the filament.",
  57. "unit": "mm",
  58. "type": "float",
  59. "default_value": 300.0,
  60. "enabled": "enabled and not firmware_config"
  61. },
  62. "x_position":
  63. {
  64. "label": "X Position",
  65. "description": "Extruder X position. The print head will move here for filament change.",
  66. "unit": "mm",
  67. "type": "float",
  68. "default_value": 0,
  69. "enabled": "enabled and not firmware_config"
  70. },
  71. "y_position":
  72. {
  73. "label": "Y Position",
  74. "description": "Extruder Y position. The print head will move here for filament change.",
  75. "unit": "mm",
  76. "type": "float",
  77. "default_value": 0,
  78. "enabled": "enabled and not firmware_config"
  79. },
  80. "z_position":
  81. {
  82. "label": "Z Position (relative)",
  83. "description": "Extruder relative Z position. Move the print head up for filament change.",
  84. "unit": "mm",
  85. "type": "float",
  86. "default_value": 0,
  87. "minimum_value": 0,
  88. "enabled": "enabled"
  89. },
  90. "retract_method":
  91. {
  92. "label": "Retract method",
  93. "description": "The gcode variant to use for retract.",
  94. "type": "enum",
  95. "options": {"U": "Marlin (M600 U)", "L": "Reprap (M600 L)"},
  96. "default_value": "U",
  97. "value": "\\\"L\\\" if machine_gcode_flavor==\\\"RepRap (RepRap)\\\" else \\\"U\\\"",
  98. "enabled": "enabled and not firmware_config"
  99. },
  100. "machine_gcode_flavor":
  101. {
  102. "label": "G-code flavor",
  103. "description": "The type of g-code to be generated. This setting is controlled by the script and will not be visible.",
  104. "type": "enum",
  105. "options":
  106. {
  107. "RepRap (Marlin/Sprinter)": "Marlin",
  108. "RepRap (Volumetric)": "Marlin (Volumetric)",
  109. "RepRap (RepRap)": "RepRap",
  110. "UltiGCode": "Ultimaker 2",
  111. "Griffin": "Griffin",
  112. "Makerbot": "Makerbot",
  113. "BFB": "Bits from Bytes",
  114. "MACH3": "Mach3",
  115. "Repetier": "Repetier"
  116. },
  117. "default_value": "RepRap (Marlin/Sprinter)",
  118. "enabled": "false"
  119. },
  120. "enable_before_macro":
  121. {
  122. "label": "Enable G-code Before",
  123. "description": "Use this to insert a custom G-code macro before the filament change happens",
  124. "type": "bool",
  125. "default_value": false,
  126. "enabled": "enabled"
  127. },
  128. "before_macro":
  129. {
  130. "label": "G-code Before",
  131. "description": "Any custom G-code to run before the filament change happens, for example, M300 S1000 P10000 for a long beep.",
  132. "unit": "",
  133. "type": "str",
  134. "default_value": "M300 S1000 P10000",
  135. "enabled": "enabled and enable_before_macro"
  136. },
  137. "enable_after_macro":
  138. {
  139. "label": "Enable G-code After",
  140. "description": "Use this to insert a custom G-code macro after the filament change",
  141. "type": "bool",
  142. "default_value": false,
  143. "enabled": "enabled"
  144. },
  145. "after_macro":
  146. {
  147. "label": "G-code After",
  148. "description": "Any custom G-code to run after the filament has been changed right before continuing the print, for example, you can add a sequence to purge filament and wipe the nozzle.",
  149. "unit": "",
  150. "type": "str",
  151. "default_value": "M300 S440 P500",
  152. "enabled": "enabled and enable_after_macro"
  153. }
  154. }
  155. }"""
  156. ## Copy machine name and gcode flavor from global stack so we can use their value in the script stack
  157. def initialize(self) -> None:
  158. super().initialize()
  159. global_container_stack = Application.getInstance().getGlobalContainerStack()
  160. if global_container_stack is None or self._instance is None:
  161. return
  162. for key in ["machine_gcode_flavor"]:
  163. self._instance.setProperty(key, "value", global_container_stack.getProperty(key, "value"))
  164. def execute(self, data: List[str]):
  165. """Inserts the filament change g-code at specific layer numbers.
  166. :param data: A list of layers of g-code.
  167. :return: A similar list, with filament change commands inserted.
  168. """
  169. enabled = self.getSettingValueByKey("enabled")
  170. layer_nums = self.getSettingValueByKey("layer_number")
  171. initial_retract = self.getSettingValueByKey("initial_retract")
  172. later_retract = self.getSettingValueByKey("later_retract")
  173. x_pos = self.getSettingValueByKey("x_position")
  174. y_pos = self.getSettingValueByKey("y_position")
  175. z_pos = self.getSettingValueByKey("z_position")
  176. firmware_config = self.getSettingValueByKey("firmware_config")
  177. enable_before_macro = self.getSettingValueByKey("enable_before_macro")
  178. before_macro = self.getSettingValueByKey("before_macro")
  179. enable_after_macro = self.getSettingValueByKey("enable_after_macro")
  180. after_macro = self.getSettingValueByKey("after_macro")
  181. if not enabled:
  182. return data
  183. color_change = ";BEGIN FilamentChange plugin\n"
  184. if enable_before_macro:
  185. color_change = color_change + before_macro + "\n"
  186. color_change = color_change + "M600"
  187. if not firmware_config:
  188. if initial_retract is not None and initial_retract > 0.:
  189. color_change = color_change + (" E%.2f" % initial_retract)
  190. if later_retract is not None and later_retract > 0.:
  191. # Reprap uses 'L': https://reprap.org/wiki/G-code#M600:_Filament_change_pause
  192. # Marlin uses 'U' https://marlinfw.org/docs/gcode/M600.html
  193. retract_method = self.getSettingValueByKey("retract_method")
  194. color_change = color_change + (" %s%.2f" % (retract_method, later_retract))
  195. if x_pos is not None:
  196. color_change = color_change + (" X%.2f" % x_pos)
  197. if y_pos is not None:
  198. color_change = color_change + (" Y%.2f" % y_pos)
  199. if z_pos is not None and z_pos > 0.:
  200. color_change = color_change + (" Z%.2f" % z_pos)
  201. color_change = color_change + "\n"
  202. if enable_after_macro:
  203. color_change = color_change + after_macro + "\n"
  204. color_change = color_change + ";END FilamentChange plugin\n"
  205. layer_targets = layer_nums.split(",")
  206. if len(layer_targets) > 0:
  207. for layer_num in layer_targets:
  208. try:
  209. layer_num = int(layer_num.strip()) + 1 #Needs +1 because the 1st layer is reserved for start g-code.
  210. except ValueError: #Layer number is not an integer.
  211. continue
  212. if 0 < layer_num < len(data):
  213. data[layer_num] = color_change + data[layer_num]
  214. return data