mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-22 05:39:37 +08:00
500 lines
25 KiB
Python
500 lines
25 KiB
Python
# ChangeAtZ script - Change printing parameters at a given height
|
|
# This script is the successor of the TweakAtZ plugin for legacy Cura.
|
|
# It contains code from the TweakAtZ plugin V1.0-V4.x and from the ExampleScript by Jaime van Kessel, Ultimaker B.V.
|
|
# It runs with the PostProcessingPlugin which is released under the terms of the AGPLv3 or higher.
|
|
# This script is licensed under the Creative Commons - Attribution - Share Alike (CC BY-SA) terms
|
|
|
|
#Authors of the ChangeAtZ plugin / script:
|
|
# Written by Steven Morlock, smorloc@gmail.com
|
|
# Modified by Ricardo Gomez, ricardoga@otulook.com, to add Bed Temperature and make it work with Cura_13.06.04+
|
|
# Modified by Stefan Heule, Dim3nsioneer@gmx.ch since V3.0 (see changelog below)
|
|
# Modified by Jaime van Kessel (Ultimaker), j.vankessel@ultimaker.com to make it work for 15.10 / 2.x
|
|
# Modified by Ruben Dulek (Ultimaker), r.dulek@ultimaker.com, to debug.
|
|
|
|
##history / changelog:
|
|
##V3.0.1: TweakAtZ-state default 1 (i.e. the plugin works without any TweakAtZ comment)
|
|
##V3.1: Recognizes UltiGCode and deactivates value reset, fan speed added, alternatively layer no. to tweak at,
|
|
## extruder three temperature disabled by "#Ex3"
|
|
##V3.1.1: Bugfix reset flow rate
|
|
##V3.1.2: Bugfix disable TweakAtZ on Cool Head Lift
|
|
##V3.2: Flow rate for specific extruder added (only for 2 extruders), bugfix parser,
|
|
## added speed reset at the end of the print
|
|
##V4.0: Progress bar, tweaking over multiple layers, M605&M606 implemented, reset after one layer option,
|
|
## extruder three code removed, tweaking print speed, save call of Publisher class,
|
|
## uses previous value from other plugins also on UltiGCode
|
|
##V4.0.1: Bugfix for doubled G1 commands
|
|
##V4.0.2: uses Cura progress bar instead of its own
|
|
##V4.0.3: Bugfix for cool head lift (contributed by luisonoff)
|
|
##V4.9.91: First version for Cura 15.06.x and PostProcessingPlugin
|
|
##V4.9.92: Modifications for Cura 15.10
|
|
##V4.9.93: Minor bugfixes (input settings) / documentation
|
|
##V4.9.94: Bugfix Combobox-selection; remove logger
|
|
##V5.0: Bugfix for fall back after one layer and doubled G0 commands when using print speed tweak, Initial version for Cura 2.x
|
|
##V5.0.1: Bugfix for calling unknown property 'bedTemp' of previous settings storage and unkown variable 'speed'
|
|
##V5.1: API Changes included for use with Cura 2.2
|
|
|
|
## Uses -
|
|
## M220 S<factor in percent> - set speed factor override percentage
|
|
## M221 S<factor in percent> - set flow factor override percentage
|
|
## M221 S<factor in percent> T<0-#toolheads> - set flow factor override percentage for single extruder
|
|
## M104 S<temp> T<0-#toolheads> - set extruder <T> to target temperature <S>
|
|
## M140 S<temp> - set bed target temperature
|
|
## M106 S<PWM> - set fan speed to target speed <S>
|
|
## M605/606 to save and recall material settings on the UM2
|
|
|
|
from ..Script import Script
|
|
#from UM.Logger import Logger
|
|
import re
|
|
|
|
class ChangeAtZ(Script):
|
|
version = "5.1.1"
|
|
def __init__(self):
|
|
super().__init__()
|
|
|
|
def getSettingDataString(self):
|
|
return """{
|
|
"name":"ChangeAtZ """ + self.version + """ (Experimental)",
|
|
"key":"ChangeAtZ",
|
|
"metadata": {},
|
|
"version": 2,
|
|
"settings":
|
|
{
|
|
"a_trigger":
|
|
{
|
|
"label": "Trigger",
|
|
"description": "Trigger at height or at layer no.",
|
|
"type": "enum",
|
|
"options": {"height":"Height","layer_no":"Layer No."},
|
|
"default_value": "height"
|
|
},
|
|
"b_targetZ":
|
|
{
|
|
"label": "Change Height",
|
|
"description": "Z height to change at",
|
|
"unit": "mm",
|
|
"type": "float",
|
|
"default_value": 5.0,
|
|
"minimum_value": "0",
|
|
"minimum_value_warning": "0.1",
|
|
"maximum_value_warning": "230",
|
|
"enabled": "a_trigger == 'height'"
|
|
},
|
|
"b_targetL":
|
|
{
|
|
"label": "Change Layer",
|
|
"description": "Layer no. to change at",
|
|
"unit": "",
|
|
"type": "int",
|
|
"default_value": 1,
|
|
"minimum_value": "-100",
|
|
"minimum_value_warning": "-1",
|
|
"enabled": "a_trigger == 'layer_no'"
|
|
},
|
|
"c_behavior":
|
|
{
|
|
"label": "Behavior",
|
|
"description": "Select behavior: Change value and keep it for the rest, Change value for single layer only",
|
|
"type": "enum",
|
|
"options": {"keep_value":"Keep value","single_layer":"Single Layer"},
|
|
"default_value": "keep_value"
|
|
},
|
|
"d_twLayers":
|
|
{
|
|
"label": "Layer Spread",
|
|
"description": "The change will be gradual over this many layers. Enter 1 to make the change immediate.",
|
|
"unit": "",
|
|
"type": "int",
|
|
"default_value": 1,
|
|
"minimum_value": "1",
|
|
"maximum_value_warning": "50",
|
|
"enabled": "c_behavior == 'keep_value'"
|
|
},
|
|
"e1_Change_speed":
|
|
{
|
|
"label": "Change Speed",
|
|
"description": "Select if total speed (print and travel) has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"e2_speed":
|
|
{
|
|
"label": "Speed",
|
|
"description": "New total speed (print and travel)",
|
|
"unit": "%",
|
|
"type": "int",
|
|
"default_value": 100,
|
|
"minimum_value": "1",
|
|
"minimum_value_warning": "10",
|
|
"maximum_value_warning": "200",
|
|
"enabled": "e1_Change_speed"
|
|
},
|
|
"f1_Change_printspeed":
|
|
{
|
|
"label": "Change Print Speed",
|
|
"description": "Select if print speed has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"f2_printspeed":
|
|
{
|
|
"label": "Print Speed",
|
|
"description": "New print speed",
|
|
"unit": "%",
|
|
"type": "int",
|
|
"default_value": 100,
|
|
"minimum_value": "1",
|
|
"minimum_value_warning": "10",
|
|
"maximum_value_warning": "200",
|
|
"enabled": "f1_Change_printspeed"
|
|
},
|
|
"g1_Change_flowrate":
|
|
{
|
|
"label": "Change Flow Rate",
|
|
"description": "Select if flow rate has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"g2_flowrate":
|
|
{
|
|
"label": "Flow Rate",
|
|
"description": "New Flow rate",
|
|
"unit": "%",
|
|
"type": "int",
|
|
"default_value": 100,
|
|
"minimum_value": "1",
|
|
"minimum_value_warning": "10",
|
|
"maximum_value_warning": "200",
|
|
"enabled": "g1_Change_flowrate"
|
|
},
|
|
"g3_Change_flowrateOne":
|
|
{
|
|
"label": "Change Flow Rate 1",
|
|
"description": "Select if first extruder flow rate has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"g4_flowrateOne":
|
|
{
|
|
"label": "Flow Rate One",
|
|
"description": "New Flow rate Extruder 1",
|
|
"unit": "%",
|
|
"type": "int",
|
|
"default_value": 100,
|
|
"minimum_value": "1",
|
|
"minimum_value_warning": "10",
|
|
"maximum_value_warning": "200",
|
|
"enabled": "g3_Change_flowrateOne"
|
|
},
|
|
"g5_Change_flowrateTwo":
|
|
{
|
|
"label": "Change Flow Rate 2",
|
|
"description": "Select if second extruder flow rate has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"g6_flowrateTwo":
|
|
{
|
|
"label": "Flow Rate two",
|
|
"description": "New Flow rate Extruder 2",
|
|
"unit": "%",
|
|
"type": "int",
|
|
"default_value": 100,
|
|
"minimum_value": "1",
|
|
"minimum_value_warning": "10",
|
|
"maximum_value_warning": "200",
|
|
"enabled": "g5_Change_flowrateTwo"
|
|
},
|
|
"h1_Change_bedTemp":
|
|
{
|
|
"label": "Change Bed Temp",
|
|
"description": "Select if Bed Temperature has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"h2_bedTemp":
|
|
{
|
|
"label": "Bed Temp",
|
|
"description": "New Bed Temperature",
|
|
"unit": "C",
|
|
"type": "float",
|
|
"default_value": 60,
|
|
"minimum_value": "0",
|
|
"minimum_value_warning": "30",
|
|
"maximum_value_warning": "120",
|
|
"enabled": "h1_Change_bedTemp"
|
|
},
|
|
"i1_Change_extruderOne":
|
|
{
|
|
"label": "Change Extruder 1 Temp",
|
|
"description": "Select if First Extruder Temperature has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"i2_extruderOne":
|
|
{
|
|
"label": "Extruder 1 Temp",
|
|
"description": "New First Extruder Temperature",
|
|
"unit": "C",
|
|
"type": "float",
|
|
"default_value": 190,
|
|
"minimum_value": "0",
|
|
"minimum_value_warning": "160",
|
|
"maximum_value_warning": "250",
|
|
"enabled": "i1_Change_extruderOne"
|
|
},
|
|
"i3_Change_extruderTwo":
|
|
{
|
|
"label": "Change Extruder 2 Temp",
|
|
"description": "Select if Second Extruder Temperature has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"i4_extruderTwo":
|
|
{
|
|
"label": "Extruder 2 Temp",
|
|
"description": "New Second Extruder Temperature",
|
|
"unit": "C",
|
|
"type": "float",
|
|
"default_value": 190,
|
|
"minimum_value": "0",
|
|
"minimum_value_warning": "160",
|
|
"maximum_value_warning": "250",
|
|
"enabled": "i3_Change_extruderTwo"
|
|
},
|
|
"j1_Change_fanSpeed":
|
|
{
|
|
"label": "Change Fan Speed",
|
|
"description": "Select if Fan Speed has to be changed",
|
|
"type": "bool",
|
|
"default_value": false
|
|
},
|
|
"j2_fanSpeed":
|
|
{
|
|
"label": "Fan Speed",
|
|
"description": "New Fan Speed (0-255)",
|
|
"unit": "PWM",
|
|
"type": "int",
|
|
"default_value": 255,
|
|
"minimum_value": "0",
|
|
"minimum_value_warning": "15",
|
|
"maximum_value_warning": "255",
|
|
"enabled": "j1_Change_fanSpeed"
|
|
}
|
|
}
|
|
}"""
|
|
|
|
def getValue(self, line, key, default = None): #replace default getvalue due to comment-reading feature
|
|
if not key in line or (";" in line and line.find(key) > line.find(";") and
|
|
not ";ChangeAtZ" in key and not ";LAYER:" in key):
|
|
return default
|
|
subPart = line[line.find(key) + len(key):] #allows for string lengths larger than 1
|
|
if ";ChangeAtZ" in key:
|
|
m = re.search("^[0-4]", subPart)
|
|
elif ";LAYER:" in key:
|
|
m = re.search("^[+-]?[0-9]*", subPart)
|
|
else:
|
|
#the minus at the beginning allows for negative values, e.g. for delta printers
|
|
m = re.search("^[-]?[0-9]*\.?[0-9]*", subPart)
|
|
if m == None:
|
|
return default
|
|
try:
|
|
return float(m.group(0))
|
|
except:
|
|
return default
|
|
|
|
def execute(self, data):
|
|
#Check which changes should apply
|
|
ChangeProp = {"speed": self.getSettingValueByKey("e1_Change_speed"),
|
|
"flowrate": self.getSettingValueByKey("g1_Change_flowrate"),
|
|
"flowrateOne": self.getSettingValueByKey("g3_Change_flowrateOne"),
|
|
"flowrateTwo": self.getSettingValueByKey("g5_Change_flowrateTwo"),
|
|
"bedTemp": self.getSettingValueByKey("h1_Change_bedTemp"),
|
|
"extruderOne": self.getSettingValueByKey("i1_Change_extruderOne"),
|
|
"extruderTwo": self.getSettingValueByKey("i3_Change_extruderTwo"),
|
|
"fanSpeed": self.getSettingValueByKey("j1_Change_fanSpeed")}
|
|
ChangePrintSpeed = self.getSettingValueByKey("f1_Change_printspeed")
|
|
ChangeStrings = {"speed": "M220 S%f\n",
|
|
"flowrate": "M221 S%f\n",
|
|
"flowrateOne": "M221 T0 S%f\n",
|
|
"flowrateTwo": "M221 T1 S%f\n",
|
|
"bedTemp": "M140 S%f\n",
|
|
"extruderOne": "M104 S%f T0\n",
|
|
"extruderTwo": "M104 S%f T1\n",
|
|
"fanSpeed": "M106 S%d\n"}
|
|
target_values = {"speed": self.getSettingValueByKey("e2_speed"),
|
|
"printspeed": self.getSettingValueByKey("f2_printspeed"),
|
|
"flowrate": self.getSettingValueByKey("g2_flowrate"),
|
|
"flowrateOne": self.getSettingValueByKey("g4_flowrateOne"),
|
|
"flowrateTwo": self.getSettingValueByKey("g6_flowrateTwo"),
|
|
"bedTemp": self.getSettingValueByKey("h2_bedTemp"),
|
|
"extruderOne": self.getSettingValueByKey("i2_extruderOne"),
|
|
"extruderTwo": self.getSettingValueByKey("i4_extruderTwo"),
|
|
"fanSpeed": self.getSettingValueByKey("j2_fanSpeed")}
|
|
old = {"speed": -1, "flowrate": 100, "flowrateOne": -1, "flowrateTwo": -1, "platformTemp": -1, "extruderOne": -1,
|
|
"extruderTwo": -1, "bedTemp": -1, "fanSpeed": -1, "state": -1}
|
|
twLayers = self.getSettingValueByKey("d_twLayers")
|
|
if self.getSettingValueByKey("c_behavior") == "single_layer":
|
|
behavior = 1
|
|
else:
|
|
behavior = 0
|
|
try:
|
|
twLayers = max(int(twLayers),1) #for the case someone entered something as "funny" as -1
|
|
except:
|
|
twLayers = 1
|
|
pres_ext = 0
|
|
done_layers = 0
|
|
z = 0
|
|
x = None
|
|
y = None
|
|
layer = -100000 #layer no. may be negative (raft) but never that low
|
|
# state 0: deactivated, state 1: activated, state 2: active, but below z,
|
|
# state 3: active and partially executed (multi layer), state 4: active and passed z
|
|
state = 1
|
|
# IsUM2: Used for reset of values (ok for Marlin/Sprinter),
|
|
# has to be set to 1 for UltiGCode (work-around for missing default values)
|
|
IsUM2 = False
|
|
oldValueUnknown = False
|
|
TWinstances = 0
|
|
|
|
if self.getSettingValueByKey("a_trigger") == "layer_no":
|
|
targetL_i = int(self.getSettingValueByKey("b_targetL"))
|
|
targetZ = 100000
|
|
else:
|
|
targetL_i = -100000
|
|
targetZ = self.getSettingValueByKey("b_targetZ")
|
|
index = 0
|
|
for active_layer in data:
|
|
modified_gcode = ""
|
|
lines = active_layer.split("\n")
|
|
for line in lines:
|
|
if line.strip() == "":
|
|
continue
|
|
if ";Generated with Cura_SteamEngine" in line:
|
|
TWinstances += 1
|
|
modified_gcode += ";ChangeAtZ instances: %d\n" % TWinstances
|
|
if not ("M84" in line or "M25" in line or ("G1" in line and ChangePrintSpeed and (state==3 or state==4)) or
|
|
";ChangeAtZ instances:" in line):
|
|
modified_gcode += line + "\n"
|
|
IsUM2 = ("FLAVOR:UltiGCode" in line) or IsUM2 #Flavor is UltiGCode!
|
|
if ";ChangeAtZ-state" in line: #checks for state change comment
|
|
state = self.getValue(line, ";ChangeAtZ-state", state)
|
|
if ";ChangeAtZ instances:" in line:
|
|
try:
|
|
tempTWi = int(line[20:])
|
|
except:
|
|
tempTWi = TWinstances
|
|
TWinstances = tempTWi
|
|
if ";Small layer" in line: #checks for begin of Cool Head Lift
|
|
old["state"] = state
|
|
state = 0
|
|
if ";LAYER:" in line: #new layer no. found
|
|
if state == 0:
|
|
state = old["state"]
|
|
layer = self.getValue(line, ";LAYER:", layer)
|
|
if targetL_i > -100000: #target selected by layer no.
|
|
if (state == 2 or targetL_i == 0) and layer == targetL_i: #determine targetZ from layer no.; checks for change on layer 0
|
|
state = 2
|
|
targetZ = z + 0.001
|
|
if (self.getValue(line, "T", None) is not None) and (self.getValue(line, "M", None) is None): #looking for single T-cmd
|
|
pres_ext = self.getValue(line, "T", pres_ext)
|
|
if "M190" in line or "M140" in line and state < 3: #looking for bed temp, stops after target z is passed
|
|
old["bedTemp"] = self.getValue(line, "S", old["bedTemp"])
|
|
if "M109" in line or "M104" in line and state < 3: #looking for extruder temp, stops after target z is passed
|
|
if self.getValue(line, "T", pres_ext) == 0:
|
|
old["extruderOne"] = self.getValue(line, "S", old["extruderOne"])
|
|
elif self.getValue(line, "T", pres_ext) == 1:
|
|
old["extruderTwo"] = self.getValue(line, "S", old["extruderTwo"])
|
|
if "M107" in line: #fan is stopped; is always updated in order not to miss switch off for next object
|
|
old["fanSpeed"] = 0
|
|
if "M106" in line and state < 3: #looking for fan speed
|
|
old["fanSpeed"] = self.getValue(line, "S", old["fanSpeed"])
|
|
if "M221" in line and state < 3: #looking for flow rate
|
|
tmp_extruder = self.getValue(line, "T", None)
|
|
if tmp_extruder == None: #check if extruder is specified
|
|
old["flowrate"] = self.getValue(line, "S", old["flowrate"])
|
|
if old["flowrate"] == -1:
|
|
old["flowrate"] = 100.0
|
|
elif tmp_extruder == 0: #first extruder
|
|
old["flowrateOne"] = self.getValue(line, "S", old["flowrateOne"])
|
|
elif tmp_extruder == 1: #second extruder
|
|
old["flowrateTwo"] = self.getValue(line, "S", old["flowrateTwo"])
|
|
if ("M84" in line or "M25" in line):
|
|
if state>0 and ChangeProp["speed"]: #"finish" commands for UM Original and UM2
|
|
modified_gcode += "M220 S100 ; speed reset to 100% at the end of print\n"
|
|
modified_gcode += "M117 \n"
|
|
modified_gcode += line + "\n"
|
|
if "G1" in line or "G0" in line:
|
|
newZ = self.getValue(line, "Z", z)
|
|
x = self.getValue(line, "X", None)
|
|
y = self.getValue(line, "Y", None)
|
|
e = self.getValue(line, "E", None)
|
|
f = self.getValue(line, "F", None)
|
|
if 'G1' in line and ChangePrintSpeed and (state==3 or state==4):
|
|
# check for pure print movement in target range:
|
|
if x != None and y != None and f != None and e != None and newZ==z:
|
|
modified_gcode += "G1 F%d X%1.3f Y%1.3f E%1.5f\n" % (int(f / 100.0 * float(target_values["printspeed"])), self.getValue(line, "X"),
|
|
self.getValue(line, "Y"), self.getValue(line, "E"))
|
|
else: #G1 command but not a print movement
|
|
modified_gcode += line + "\n"
|
|
# no changing on retraction hops which have no x and y coordinate:
|
|
if (newZ != z) and (x is not None) and (y is not None):
|
|
z = newZ
|
|
if z < targetZ and state == 1:
|
|
state = 2
|
|
if z >= targetZ and state == 2:
|
|
state = 3
|
|
done_layers = 0
|
|
for key in ChangeProp:
|
|
if ChangeProp[key] and old[key]==-1: #old value is not known
|
|
oldValueUnknown = True
|
|
if oldValueUnknown: #the changing has to happen within one layer
|
|
twLayers = 1
|
|
if IsUM2: #Parameters have to be stored in the printer (UltiGCode=UM2)
|
|
modified_gcode += "M605 S%d;stores parameters before changing\n" % (TWinstances-1)
|
|
if behavior == 1: #single layer change only and then reset
|
|
twLayers = 1
|
|
if ChangePrintSpeed and behavior == 0:
|
|
twLayers = done_layers + 1
|
|
if state==3:
|
|
if twLayers-done_layers>0: #still layers to go?
|
|
if targetL_i > -100000:
|
|
modified_gcode += ";ChangeAtZ V%s: executed at Layer %d\n" % (self.version,layer)
|
|
modified_gcode += "M117 Printing... ch@L%4d\n" % layer
|
|
else:
|
|
modified_gcode += (";ChangeAtZ V%s: executed at %1.2f mm\n" % (self.version,z))
|
|
modified_gcode += "M117 Printing... ch@%5.1f\n" % z
|
|
for key in ChangeProp:
|
|
if ChangeProp[key]:
|
|
modified_gcode += ChangeStrings[key] % float(old[key]+(float(target_values[key])-float(old[key]))/float(twLayers)*float(done_layers+1))
|
|
done_layers += 1
|
|
else:
|
|
state = 4
|
|
if behavior == 1: #reset values after one layer
|
|
if targetL_i > -100000:
|
|
modified_gcode += ";ChangeAtZ V%s: reset on Layer %d\n" % (self.version,layer)
|
|
else:
|
|
modified_gcode += ";ChangeAtZ V%s: reset at %1.2f mm\n" % (self.version,z)
|
|
if IsUM2 and oldValueUnknown: #executes on UM2 with Ultigcode and machine setting
|
|
modified_gcode += "M606 S%d;recalls saved settings\n" % (TWinstances-1)
|
|
else: #executes on RepRap, UM2 with Ultigcode and Cura setting
|
|
for key in ChangeProp:
|
|
if ChangeProp[key]:
|
|
modified_gcode += ChangeStrings[key] % float(old[key])
|
|
# re-activates the plugin if executed by pre-print G-command, resets settings:
|
|
if (z < targetZ or layer == 0) and state >= 3: #resets if below change level or at level 0
|
|
state = 2
|
|
done_layers = 0
|
|
if targetL_i > -100000:
|
|
modified_gcode += ";ChangeAtZ V%s: reset below Layer %d\n" % (self.version, targetL_i)
|
|
else:
|
|
modified_gcode += ";ChangeAtZ V%s: reset below %1.2f mm\n" % (self.version, targetZ)
|
|
if IsUM2 and oldValueUnknown: #executes on UM2 with Ultigcode and machine setting
|
|
modified_gcode += "M606 S%d;recalls saved settings\n" % (TWinstances-1)
|
|
else: #executes on RepRap, UM2 with Ultigcode and Cura setting
|
|
for key in ChangeProp:
|
|
if ChangeProp[key]:
|
|
modified_gcode += ChangeStrings[key] % float(old[key])
|
|
data[index] = modified_gcode
|
|
index += 1
|
|
return data
|