mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
Merge branch 'master' into master-1
This commit is contained in:
commit
849ac3551d
2286 changed files with 195832 additions and 76181 deletions
|
@ -100,8 +100,8 @@ class ChangeAtZ(Script):
|
|||
},
|
||||
"d_twLayers":
|
||||
{
|
||||
"label": "No. Layers",
|
||||
"description": "No. of layers used to change",
|
||||
"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,
|
||||
|
@ -330,7 +330,7 @@ class ChangeAtZ(Script):
|
|||
"extruderOne": self.getSettingValueByKey("i2_extruderOne"),
|
||||
"extruderTwo": self.getSettingValueByKey("i4_extruderTwo"),
|
||||
"fanSpeed": self.getSettingValueByKey("j2_fanSpeed")}
|
||||
old = {"speed": -1, "flowrate": -1, "flowrateOne": -1, "flowrateTwo": -1, "platformTemp": -1, "extruderOne": -1,
|
||||
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":
|
||||
|
@ -367,6 +367,8 @@ class ChangeAtZ(Script):
|
|||
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
|
||||
|
@ -410,6 +412,8 @@ class ChangeAtZ(Script):
|
|||
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
|
||||
|
@ -481,9 +485,9 @@ class ChangeAtZ(Script):
|
|||
state = 2
|
||||
done_layers = 0
|
||||
if targetL_i > -100000:
|
||||
modified_gcode += ";ChangeAtZ V%s: reset below Layer %d\n" % (self.version,targetL_i)
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
# Cura PostProcessingPlugin
|
||||
# Author: Amanda de Castilho
|
||||
# Date: August 28, 2018
|
||||
# Modified: November 16, 2018 by Joshua Pope-Lewis
|
||||
|
||||
# Description: This plugin inserts a line at the start of each layer,
|
||||
# M117 - displays the filename and layer height to the LCD
|
||||
# Alternatively, user can override the filename to display alt text + layer height
|
||||
# Description: This plugin shows custom messages about your print on the Status bar...
|
||||
# Please look at the 3 options
|
||||
# - Scolling (SCROLL_LONG_FILENAMES) if enabled in Marlin and you arent printing a small item select this option.
|
||||
# - Name: By default it will use the name generated by Cura (EG: TT_Test_Cube) - Type a custom name in here
|
||||
# - Max Layer: Enabling this will show how many layers are in the entire print (EG: Layer 1 of 265!)
|
||||
|
||||
from ..Script import Script
|
||||
from UM.Application import Application
|
||||
|
@ -15,35 +18,72 @@ class DisplayFilenameAndLayerOnLCD(Script):
|
|||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Display filename and layer on LCD",
|
||||
"name": "Display Filename And Layer On LCD",
|
||||
"key": "DisplayFilenameAndLayerOnLCD",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"scroll":
|
||||
{
|
||||
"label": "Scroll enabled/Small layers?",
|
||||
"description": "If SCROLL_LONG_FILENAMES is enabled select this setting however, if the model is small disable this setting!",
|
||||
"type": "bool",
|
||||
"default_value": false
|
||||
},
|
||||
"name":
|
||||
{
|
||||
"label": "text to display:",
|
||||
"label": "Text to display:",
|
||||
"description": "By default the current filename will be displayed on the LCD. Enter text here to override the filename and display something else.",
|
||||
"type": "str",
|
||||
"default_value": ""
|
||||
},
|
||||
"startNum":
|
||||
{
|
||||
"label": "Initial layer number:",
|
||||
"description": "Choose which number you prefer for the initial layer, 0 or 1",
|
||||
"type": "int",
|
||||
"default_value": 0,
|
||||
"minimum_value": 0,
|
||||
"maximum_value": 1
|
||||
},
|
||||
"maxlayer":
|
||||
{
|
||||
"label": "Display max layer?:",
|
||||
"description": "Display how many layers are in the entire print on status bar?",
|
||||
"type": "bool",
|
||||
"default_value": true
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
max_layer = 0
|
||||
if self.getSettingValueByKey("name") != "":
|
||||
name = self.getSettingValueByKey("name")
|
||||
else:
|
||||
name = Application.getInstance().getPrintInformation().jobName
|
||||
lcd_text = "M117 " + name + " layer: "
|
||||
i = 0
|
||||
name = Application.getInstance().getPrintInformation().jobName
|
||||
if not self.getSettingValueByKey("scroll"):
|
||||
if self.getSettingValueByKey("maxlayer"):
|
||||
lcd_text = "M117 Layer "
|
||||
else:
|
||||
lcd_text = "M117 Printing Layer "
|
||||
else:
|
||||
lcd_text = "M117 Printing " + name + " - Layer "
|
||||
i = self.getSettingValueByKey("startNum")
|
||||
for layer in data:
|
||||
display_text = lcd_text + str(i)
|
||||
display_text = lcd_text + str(i) + " " + name
|
||||
layer_index = data.index(layer)
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if line.startswith(";LAYER_COUNT:"):
|
||||
max_layer = line
|
||||
max_layer = max_layer.split(":")[1]
|
||||
if line.startswith(";LAYER:"):
|
||||
if self.getSettingValueByKey("maxlayer"):
|
||||
display_text = display_text + " of " + max_layer
|
||||
else:
|
||||
display_text = display_text + "!"
|
||||
line_index = lines.index(line)
|
||||
lines.insert(line_index + 1, display_text)
|
||||
i += 1
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
# Cura PostProcessingPlugin
|
||||
# Author: Mathias Lyngklip Kjeldgaard
|
||||
# Date: July 31, 2019
|
||||
# Modified: November 26, 2019
|
||||
|
||||
# Description: This plugin displayes the remaining time on the LCD of the printer
|
||||
# using the estimated print-time generated by Cura.
|
||||
|
||||
|
||||
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
import re
|
||||
import datetime
|
||||
|
||||
|
||||
class DisplayRemainingTimeOnLCD(Script):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name":"Display Remaining Time on LCD",
|
||||
"key":"DisplayRemainingTimeOnLCD",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"TurnOn":
|
||||
{
|
||||
"label": "Enable",
|
||||
"description": "When enabled, It will write Time Left: HHMMSS on the display. This is updated every layer.",
|
||||
"type": "bool",
|
||||
"default_value": false
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
if self.getSettingValueByKey("TurnOn"):
|
||||
total_time = 0
|
||||
total_time_string = ""
|
||||
for layer in data:
|
||||
layer_index = data.index(layer)
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if line.startswith(";TIME:"):
|
||||
# At this point, we have found a line in the GCODE with ";TIME:"
|
||||
# which is the indication of total_time. Looks like: ";TIME:1337", where
|
||||
# 1337 is the total print time in seconds.
|
||||
line_index = lines.index(line) # We take a hold of that line
|
||||
split_string = re.split(":", line) # Then we split it, so we can get the number
|
||||
|
||||
string_with_numbers = "{}".format(split_string[1]) # Here we insert that number from the
|
||||
# list into a string.
|
||||
total_time = int(string_with_numbers) # Only to contert it to a int.
|
||||
|
||||
m, s = divmod(total_time, 60) # Math to calculate
|
||||
h, m = divmod(m, 60) # hours, minutes and seconds.
|
||||
total_time_string = "{:d}h{:02d}m{:02d}s".format(h, m, s) # Now we put it into the string
|
||||
lines[line_index] = "M117 Time Left {}".format(total_time_string) # And print that string instead of the original one
|
||||
|
||||
|
||||
|
||||
|
||||
elif line.startswith(";TIME_ELAPSED:"):
|
||||
|
||||
# As we didnt find the total time (";TIME:"), we have found a elapsed time mark
|
||||
# This time represents the time the printer have printed. So with some math;
|
||||
# totalTime - printTime = RemainingTime.
|
||||
line_index = lines.index(line) # We get a hold of the line
|
||||
list_split = re.split(":", line) # Again, we split at ":" so we can get the number
|
||||
string_with_numbers = "{}".format(list_split[1]) # Then we put that number from the list, into a string
|
||||
|
||||
current_time = float(string_with_numbers) # This time we convert to a float, as the line looks something like:
|
||||
# ;TIME_ELAPSED:1234.6789
|
||||
# which is total time in seconds
|
||||
|
||||
time_left = total_time - current_time # Here we calculate remaining time
|
||||
m1, s1 = divmod(time_left, 60) # And some math to get the total time in seconds into
|
||||
h1, m1 = divmod(m1, 60) # the right format. (HH,MM,SS)
|
||||
current_time_string = "{:d}h{:2d}m{:2d}s".format(int(h1), int(m1), int(s1)) # Here we create the string holding our time
|
||||
lines[line_index] = "M117 Time Left {}".format(current_time_string) # And now insert that into the GCODE
|
||||
|
||||
|
||||
# Here we are OUT of the second for-loop
|
||||
# Which means we have found and replaces all the occurences.
|
||||
# Which also means we are ready to join the lines for that section of the GCODE file.
|
||||
final_lines = "\n".join(lines)
|
||||
data[layer_index] = final_lines
|
||||
return data
|
|
@ -1,9 +1,7 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from UM.Logger import Logger
|
||||
from typing import List
|
||||
from ..Script import Script
|
||||
|
||||
class FilamentChange(Script):
|
||||
|
@ -65,9 +63,10 @@ class FilamentChange(Script):
|
|||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data: list):
|
||||
|
||||
"""data is a list. Each index contains a layer"""
|
||||
## Inserts the filament change g-code at specific layer numbers.
|
||||
# \param data A list of layers of g-code.
|
||||
# \return A similar list, with filament change commands inserted.
|
||||
def execute(self, data: List[str]):
|
||||
layer_nums = self.getSettingValueByKey("layer_number")
|
||||
initial_retract = self.getSettingValueByKey("initial_retract")
|
||||
later_retract = self.getSettingValueByKey("later_retract")
|
||||
|
@ -88,32 +87,16 @@ class FilamentChange(Script):
|
|||
if y_pos is not None:
|
||||
color_change = color_change + (" Y%.2f" % y_pos)
|
||||
|
||||
color_change = color_change + " ; Generated by FilamentChange plugin"
|
||||
color_change = color_change + " ; Generated by FilamentChange plugin\n"
|
||||
|
||||
layer_targets = layer_nums.split(",")
|
||||
if len(layer_targets) > 0:
|
||||
for layer_num in layer_targets:
|
||||
layer_num = int(layer_num.strip())
|
||||
if layer_num <= len(data):
|
||||
index, layer_data = self._searchLayerData(data, layer_num - 1)
|
||||
if layer_data is None:
|
||||
Logger.log("e", "Could not found the layer")
|
||||
continue
|
||||
lines = layer_data.split("\n")
|
||||
lines.insert(2, color_change)
|
||||
final_line = "\n".join(lines)
|
||||
data[index] = final_line
|
||||
try:
|
||||
layer_num = int(layer_num.strip()) + 1 #Needs +1 because the 1st layer is reserved for start g-code.
|
||||
except ValueError: #Layer number is not an integer.
|
||||
continue
|
||||
if 0 < layer_num < len(data):
|
||||
data[layer_num] = color_change + data[layer_num]
|
||||
|
||||
return data
|
||||
|
||||
## This method returns the data corresponding with the indicated layer number, looking in the gcode for
|
||||
# the occurrence of this layer number.
|
||||
def _searchLayerData(self, data: list, layer_num: int) -> Tuple[int, Optional[str]]:
|
||||
for index, layer_data in enumerate(data):
|
||||
first_line = layer_data.split("\n")[0]
|
||||
# The first line should contain the layer number at the beginning.
|
||||
if first_line[:len(self._layer_keyword)] == self._layer_keyword:
|
||||
# If found the layer that we are looking for, then return the data
|
||||
if first_line[len(self._layer_keyword):] == str(layer_num):
|
||||
return index, layer_data
|
||||
return 0, None
|
||||
return data
|
50
plugins/PostProcessingPlugin/scripts/InsertAtLayerChange.py
Normal file
50
plugins/PostProcessingPlugin/scripts/InsertAtLayerChange.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
# Created by Wayne Porter
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
class InsertAtLayerChange(Script):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Insert at layer change",
|
||||
"key": "InsertAtLayerChange",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"insert_location":
|
||||
{
|
||||
"label": "When to insert",
|
||||
"description": "Whether to insert code before or after layer change.",
|
||||
"type": "enum",
|
||||
"options": {"before": "Before", "after": "After"},
|
||||
"default_value": "before"
|
||||
},
|
||||
"gcode_to_add":
|
||||
{
|
||||
"label": "GCODE to insert.",
|
||||
"description": "GCODE to add before or after layer change.",
|
||||
"type": "str",
|
||||
"default_value": ""
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
gcode_to_add = self.getSettingValueByKey("gcode_to_add") + "\n"
|
||||
for layer in data:
|
||||
# Check that a layer is being printed
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if ";LAYER:" in line:
|
||||
index = data.index(layer)
|
||||
if self.getSettingValueByKey("insert_location") == "before":
|
||||
layer = gcode_to_add + layer
|
||||
else:
|
||||
layer = layer + gcode_to_add
|
||||
|
||||
data[index] = layer
|
||||
break
|
||||
return data
|
|
@ -1,15 +1,18 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
from UM.Application import Application #To get the current printer's settings.
|
||||
from UM.Logger import Logger
|
||||
|
||||
from typing import List, Tuple
|
||||
|
||||
class PauseAtHeight(Script):
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
|
||||
def getSettingDataString(self):
|
||||
def getSettingDataString(self) -> str:
|
||||
return """{
|
||||
"name": "Pause at height",
|
||||
"key": "PauseAtHeight",
|
||||
|
@ -105,19 +108,24 @@ class PauseAtHeight(Script):
|
|||
"standby_temperature":
|
||||
{
|
||||
"label": "Standby Temperature",
|
||||
"description": "Change the temperature during the pause",
|
||||
"description": "Change the temperature during the pause.",
|
||||
"unit": "°C",
|
||||
"type": "int",
|
||||
"default_value": 0
|
||||
},
|
||||
"display_text":
|
||||
{
|
||||
"label": "Display Text",
|
||||
"description": "Text that should appear on the display while paused. If left empty, there will not be any message.",
|
||||
"type": "str",
|
||||
"default_value": ""
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def getNextXY(self, layer: str):
|
||||
"""
|
||||
Get the X and Y values for a layer (will be used to get X and Y of
|
||||
the layer after the pause
|
||||
"""
|
||||
## Get the X and Y values for a layer (will be used to get X and Y of the
|
||||
# layer after the pause).
|
||||
def getNextXY(self, layer: str) -> Tuple[float, float]:
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if self.getValue(line, "X") is not None and self.getValue(line, "Y") is not None:
|
||||
|
@ -126,8 +134,10 @@ class PauseAtHeight(Script):
|
|||
return x, y
|
||||
return 0, 0
|
||||
|
||||
def execute(self, data: list):
|
||||
"""data is a list. Each index contains a layer"""
|
||||
## Inserts the pause commands.
|
||||
# \param data: List of layers.
|
||||
# \return New list of layers.
|
||||
def execute(self, data: List[str]) -> List[str]:
|
||||
pause_at = self.getSettingValueByKey("pause_at")
|
||||
pause_height = self.getSettingValueByKey("pause_height")
|
||||
pause_layer = self.getSettingValueByKey("pause_layer")
|
||||
|
@ -143,6 +153,7 @@ class PauseAtHeight(Script):
|
|||
firmware_retract = Application.getInstance().getGlobalContainerStack().getProperty("machine_firmware_retract", "value")
|
||||
control_temperatures = Application.getInstance().getGlobalContainerStack().getProperty("machine_nozzle_temp_enabled", "value")
|
||||
initial_layer_height = Application.getInstance().getGlobalContainerStack().getProperty("layer_height_0", "value")
|
||||
display_text = self.getSettingValueByKey("display_text")
|
||||
|
||||
is_griffin = False
|
||||
|
||||
|
@ -151,6 +162,9 @@ class PauseAtHeight(Script):
|
|||
# use offset to calculate the current height: <current_height> = <current_z> - <layer_0_z>
|
||||
layer_0_z = 0
|
||||
current_z = 0
|
||||
current_height = 0
|
||||
current_layer = 0
|
||||
current_extrusion_f = 0
|
||||
got_first_g_cmd_on_layer_0 = False
|
||||
current_t = 0 #Tracks the current extruder for tracking the target temperature.
|
||||
target_temperature = {} #Tracks the current target temperature for each extruder.
|
||||
|
@ -184,6 +198,10 @@ class PauseAtHeight(Script):
|
|||
if not layers_started:
|
||||
continue
|
||||
|
||||
# Look for the feed rate of an extrusion instruction
|
||||
if self.getValue(line, "F") is not None and self.getValue(line, "E") is not None:
|
||||
current_extrusion_f = self.getValue(line, "F")
|
||||
|
||||
# If a Z instruction is in the line, read the current Z
|
||||
if self.getValue(line, "Z") is not None:
|
||||
current_z = self.getValue(line, "Z")
|
||||
|
@ -201,7 +219,7 @@ class PauseAtHeight(Script):
|
|||
|
||||
current_height = current_z - layer_0_z
|
||||
if current_height < pause_height:
|
||||
break # Try the next layer.
|
||||
continue # Scan the enitre layer, z-changes are not always on the same/first line.
|
||||
|
||||
# Pause at layer
|
||||
else:
|
||||
|
@ -247,8 +265,8 @@ class PauseAtHeight(Script):
|
|||
# the nozzle)
|
||||
x, y = self.getNextXY(layer)
|
||||
prev_lines = prev_layer.split("\n")
|
||||
for line in prev_lines:
|
||||
new_e = self.getValue(line, 'E', current_e)
|
||||
for lin in prev_lines:
|
||||
new_e = self.getValue(lin, "E", current_e)
|
||||
if new_e != current_e:
|
||||
current_e = new_e
|
||||
break
|
||||
|
@ -264,7 +282,7 @@ class PauseAtHeight(Script):
|
|||
|
||||
if not is_griffin:
|
||||
# Retraction
|
||||
prepend_gcode += self.putValue(M = 83) + "\n"
|
||||
prepend_gcode += self.putValue(M = 83) + " ; switch to relative E values for any needed retraction\n"
|
||||
if retraction_amount != 0:
|
||||
if firmware_retract: #Can't set the distance directly to what the user wants. We have to choose ourselves.
|
||||
retraction_count = 1 if control_temperatures else 3 #Retract more if we don't control the temperature.
|
||||
|
@ -274,25 +292,28 @@ class PauseAtHeight(Script):
|
|||
prepend_gcode += self.putValue(G = 1, E = -retraction_amount, F = retraction_speed * 60) + "\n"
|
||||
|
||||
# Move the head away
|
||||
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + "\n"
|
||||
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + " ; move up a millimeter to get out of the way\n"
|
||||
|
||||
# This line should be ok
|
||||
prepend_gcode += self.putValue(G = 1, X = park_x, Y = park_y, F = 9000) + "\n"
|
||||
|
||||
if current_z < 15:
|
||||
prepend_gcode += self.putValue(G = 1, Z = 15, F = 300) + "\n"
|
||||
prepend_gcode += self.putValue(G = 1, Z = 15, F = 300) + " ; too close to bed--move to at least 15mm\n"
|
||||
|
||||
if control_temperatures:
|
||||
# Set extruder standby temperature
|
||||
prepend_gcode += self.putValue(M = 104, S = standby_temperature) + "; standby temperature\n"
|
||||
prepend_gcode += self.putValue(M = 104, S = standby_temperature) + " ; standby temperature\n"
|
||||
|
||||
if display_text:
|
||||
prepend_gcode += "M117 " + display_text + "\n"
|
||||
|
||||
# Wait till the user continues printing
|
||||
prepend_gcode += self.putValue(M = 0) + ";Do the actual pause\n"
|
||||
prepend_gcode += self.putValue(M = 0) + " ; Do the actual pause\n"
|
||||
|
||||
if not is_griffin:
|
||||
if control_temperatures:
|
||||
# Set extruder resume temperature
|
||||
prepend_gcode += self.putValue(M = 109, S = int(target_temperature.get(current_t, 0))) + "; resume temperature\n"
|
||||
prepend_gcode += self.putValue(M = 109, S = int(target_temperature.get(current_t, 0))) + " ; resume temperature\n"
|
||||
|
||||
# Push the filament back,
|
||||
if retraction_amount != 0:
|
||||
|
@ -308,8 +329,10 @@ class PauseAtHeight(Script):
|
|||
prepend_gcode += self.putValue(G = 1, E = -retraction_amount, F = retraction_speed * 60) + "\n"
|
||||
|
||||
# Move the head back
|
||||
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + "\n"
|
||||
if current_z < 15:
|
||||
prepend_gcode += self.putValue(G = 1, Z = current_z + 1, F = 300) + "\n"
|
||||
prepend_gcode += self.putValue(G = 1, X = x, Y = y, F = 9000) + "\n"
|
||||
prepend_gcode += self.putValue(G = 1, Z = current_z, F = 300) + " ; move back down to resume height\n"
|
||||
if retraction_amount != 0:
|
||||
if firmware_retract: #Can't set the distance directly to what the user wants. We have to choose ourselves.
|
||||
retraction_count = 1 if control_temperatures else 3 #Retract more if we don't control the temperature.
|
||||
|
@ -317,8 +340,13 @@ class PauseAtHeight(Script):
|
|||
prepend_gcode += self.putValue(G = 11) + "\n"
|
||||
else:
|
||||
prepend_gcode += self.putValue(G = 1, E = retraction_amount, F = retraction_speed * 60) + "\n"
|
||||
prepend_gcode += self.putValue(G = 1, F = 9000) + "\n"
|
||||
prepend_gcode += self.putValue(M = 82) + "\n"
|
||||
|
||||
if current_extrusion_f != 0:
|
||||
prepend_gcode += self.putValue(G = 1, F = current_extrusion_f) + " ; restore extrusion feedrate\n"
|
||||
else:
|
||||
Logger.log("w", "No previous feedrate found in gcode, feedrate for next layer(s) might be incorrect")
|
||||
|
||||
prepend_gcode += self.putValue(M = 82) + " ; switch back to absolute E values\n"
|
||||
|
||||
# reset extrude value to pre pause value
|
||||
prepend_gcode += self.putValue(G = 92, E = current_e) + "\n"
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from UM.Logger import Logger
|
||||
from ..Script import Script
|
||||
class PauseAtHeightforRepetier(Script):
|
||||
def __init__(self):
|
||||
|
@ -73,6 +74,7 @@ class PauseAtHeightforRepetier(Script):
|
|||
def execute(self, data):
|
||||
x = 0.
|
||||
y = 0.
|
||||
current_extrusion_f = 0
|
||||
current_z = 0.
|
||||
pause_z = self.getSettingValueByKey("pause_height")
|
||||
retraction_amount = self.getSettingValueByKey("retraction_amount")
|
||||
|
@ -94,9 +96,11 @@ class PauseAtHeightforRepetier(Script):
|
|||
|
||||
if self.getValue(line, 'G') == 1 or self.getValue(line, 'G') == 0:
|
||||
current_z = self.getValue(line, 'Z')
|
||||
if self.getValue(line, 'F') is not None and self.getValue(line, 'E') is not None:
|
||||
current_extrusion_f = self.getValue(line, 'F', current_extrusion_f)
|
||||
x = self.getValue(line, 'X', x)
|
||||
y = self.getValue(line, 'Y', y)
|
||||
if current_z != None:
|
||||
if current_z is not None:
|
||||
if current_z >= pause_z:
|
||||
|
||||
index = data.index(layer)
|
||||
|
@ -150,7 +154,12 @@ class PauseAtHeightforRepetier(Script):
|
|||
prepend_gcode +="G1 X%f Y%f F9000\n" % (x, y)
|
||||
if retraction_amount != 0:
|
||||
prepend_gcode +="G1 E%f F6000\n" % (retraction_amount)
|
||||
prepend_gcode +="G1 F9000\n"
|
||||
|
||||
if current_extrusion_f != 0:
|
||||
prepend_gcode += self.putValue(G=1, F=current_extrusion_f) + " ; restore extrusion feedrate\n"
|
||||
else:
|
||||
Logger.log("w", "No previous feedrate found in gcode, feedrate for next layer(s) might be incorrect")
|
||||
|
||||
prepend_gcode +="M82\n"
|
||||
|
||||
# reset extrude value to pre pause value
|
||||
|
|
75
plugins/PostProcessingPlugin/scripts/RetractContinue.py
Normal file
75
plugins/PostProcessingPlugin/scripts/RetractContinue.py
Normal file
|
@ -0,0 +1,75 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# The PostProcessingPlugin is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import math
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
## Continues retracting during all travel moves.
|
||||
class RetractContinue(Script):
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Retract Continue",
|
||||
"key": "RetractContinue",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"extra_retraction_speed":
|
||||
{
|
||||
"label": "Extra Retraction Ratio",
|
||||
"description": "How much does it retract during the travel move, by ratio of the travel length.",
|
||||
"type": "float",
|
||||
"default_value": 0.05
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
current_e = 0
|
||||
current_x = 0
|
||||
current_y = 0
|
||||
extra_retraction_speed = self.getSettingValueByKey("extra_retraction_speed")
|
||||
|
||||
for layer_number, layer in enumerate(data):
|
||||
lines = layer.split("\n")
|
||||
for line_number, line in enumerate(lines):
|
||||
if self.getValue(line, "G") in {0, 1}: # Track X,Y location.
|
||||
current_x = self.getValue(line, "X", current_x)
|
||||
current_y = self.getValue(line, "Y", current_y)
|
||||
if self.getValue(line, "G") == 1:
|
||||
if self.getValue(line, "E"):
|
||||
new_e = self.getValue(line, "E")
|
||||
if new_e >= current_e: # Not a retraction.
|
||||
continue
|
||||
# A retracted travel move may consist of multiple commands, due to combing.
|
||||
# This continues retracting over all of these moves and only unretracts at the end.
|
||||
delta_line = 1
|
||||
dx = current_x # Track the difference in X for this move only to compute the length of the travel.
|
||||
dy = current_y
|
||||
while line_number + delta_line < len(lines) and self.getValue(lines[line_number + delta_line], "G") != 1:
|
||||
travel_move = lines[line_number + delta_line]
|
||||
if self.getValue(travel_move, "G") != 0:
|
||||
delta_line += 1
|
||||
continue
|
||||
travel_x = self.getValue(travel_move, "X", dx)
|
||||
travel_y = self.getValue(travel_move, "Y", dy)
|
||||
f = self.getValue(travel_move, "F", "no f")
|
||||
length = math.sqrt((travel_x - dx) * (travel_x - dx) + (travel_y - dy) * (travel_y - dy)) # Length of the travel move.
|
||||
new_e -= length * extra_retraction_speed # New retraction is by ratio of this travel move.
|
||||
if f == "no f":
|
||||
new_travel_move = "G1 X{travel_x} Y{travel_y} E{new_e}".format(travel_x = travel_x, travel_y = travel_y, new_e = new_e)
|
||||
else:
|
||||
new_travel_move = "G1 F{f} X{travel_x} Y{travel_y} E{new_e}".format(f = f, travel_x = travel_x, travel_y = travel_y, new_e = new_e)
|
||||
lines[line_number + delta_line] = new_travel_move
|
||||
|
||||
delta_line += 1
|
||||
dx = travel_x
|
||||
dy = travel_y
|
||||
|
||||
current_e = new_e
|
||||
|
||||
new_layer = "\n".join(lines)
|
||||
data[layer_number] = new_layer
|
||||
|
||||
return data
|
|
@ -128,9 +128,26 @@ class Stretcher():
|
|||
onestep = GCodeStep(0, in_relative_movement)
|
||||
onestep.copyPosFrom(current)
|
||||
elif _getValue(line, "G") == 1:
|
||||
last_x = current.step_x
|
||||
last_y = current.step_y
|
||||
last_z = current.step_z
|
||||
last_e = current.step_e
|
||||
current.readStep(line)
|
||||
onestep = GCodeStep(1, in_relative_movement)
|
||||
onestep.copyPosFrom(current)
|
||||
if (current.step_x == last_x and current.step_y == last_y and
|
||||
current.step_z == last_z and current.step_e != last_e
|
||||
):
|
||||
# It's an extruder only move. Preserve it rather than process it as an
|
||||
# extruded move. Otherwise, the stretched output might contain slight
|
||||
# motion in X and Y in addition to E. This can cause problems with
|
||||
# firmwares that implement pressure advance.
|
||||
onestep = GCodeStep(-1, in_relative_movement)
|
||||
onestep.copyPosFrom(current)
|
||||
# Rather than copy the original line, write a new one with consistent
|
||||
# extruder coordinates
|
||||
onestep.comment = "G1 F{} E{}".format(onestep.step_f, onestep.step_e)
|
||||
else:
|
||||
onestep = GCodeStep(1, in_relative_movement)
|
||||
onestep.copyPosFrom(current)
|
||||
|
||||
# end of relative movement
|
||||
elif _getValue(line, "G") == 90:
|
||||
|
@ -145,6 +162,7 @@ class Stretcher():
|
|||
current.readStep(line)
|
||||
onestep = GCodeStep(-1, in_relative_movement)
|
||||
onestep.copyPosFrom(current)
|
||||
onestep.comment = line
|
||||
else:
|
||||
onestep = GCodeStep(-1, in_relative_movement)
|
||||
onestep.copyPosFrom(current)
|
||||
|
|
95
plugins/PostProcessingPlugin/scripts/TimeLapse.py
Normal file
95
plugins/PostProcessingPlugin/scripts/TimeLapse.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
# Created by Wayne Porter
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
class TimeLapse(Script):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Time Lapse",
|
||||
"key": "TimeLapse",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"trigger_command":
|
||||
{
|
||||
"label": "Trigger camera command",
|
||||
"description": "Gcode command used to trigger camera.",
|
||||
"type": "str",
|
||||
"default_value": "M240"
|
||||
},
|
||||
"pause_length":
|
||||
{
|
||||
"label": "Pause length",
|
||||
"description": "How long to wait (in ms) after camera was triggered.",
|
||||
"type": "int",
|
||||
"default_value": 700,
|
||||
"minimum_value": 0,
|
||||
"unit": "ms"
|
||||
},
|
||||
"park_print_head":
|
||||
{
|
||||
"label": "Park Print Head",
|
||||
"description": "Park the print head out of the way. Assumes absolute positioning.",
|
||||
"type": "bool",
|
||||
"default_value": true
|
||||
},
|
||||
"head_park_x":
|
||||
{
|
||||
"label": "Park Print Head X",
|
||||
"description": "What X location does the head move to for photo.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0,
|
||||
"enabled": "park_print_head"
|
||||
},
|
||||
"head_park_y":
|
||||
{
|
||||
"label": "Park Print Head Y",
|
||||
"description": "What Y location does the head move to for photo.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 190,
|
||||
"enabled": "park_print_head"
|
||||
},
|
||||
"park_feed_rate":
|
||||
{
|
||||
"label": "Park Feed Rate",
|
||||
"description": "How fast does the head move to the park coordinates.",
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"default_value": 9000,
|
||||
"enabled": "park_print_head"
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
feed_rate = self.getSettingValueByKey("park_feed_rate")
|
||||
park_print_head = self.getSettingValueByKey("park_print_head")
|
||||
x_park = self.getSettingValueByKey("head_park_x")
|
||||
y_park = self.getSettingValueByKey("head_park_y")
|
||||
trigger_command = self.getSettingValueByKey("trigger_command")
|
||||
pause_length = self.getSettingValueByKey("pause_length")
|
||||
gcode_to_append = ";TimeLapse Begin\n"
|
||||
|
||||
if park_print_head:
|
||||
gcode_to_append += self.putValue(G = 1, F = feed_rate, X = x_park, Y = y_park) + " ;Park print head\n"
|
||||
gcode_to_append += self.putValue(M = 400) + " ;Wait for moves to finish\n"
|
||||
gcode_to_append += trigger_command + " ;Snap Photo\n"
|
||||
gcode_to_append += self.putValue(G = 4, P = pause_length) + " ;Wait for camera\n"
|
||||
gcode_to_append += ";TimeLapse End\n"
|
||||
for layer in data:
|
||||
# Check that a layer is being printed
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if ";LAYER:" in line:
|
||||
index = data.index(layer)
|
||||
layer += gcode_to_append
|
||||
|
||||
data[index] = layer
|
||||
break
|
||||
return data
|
|
@ -0,0 +1,46 @@
|
|||
# Cura PostProcessingPlugin
|
||||
# Author: Amanda de Castilho
|
||||
# Date: January 5,2019
|
||||
|
||||
# Description: This plugin overrides probing command and inserts code to ensure
|
||||
# previous probe measurements are loaded and bed leveling enabled
|
||||
# (searches for G29 and replaces it with M501 & M420 S1)
|
||||
# *** Assumes G29 is in the start code, will do nothing if it isn't ***
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
class UsePreviousProbeMeasurements(Script):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Use Previous Probe Measurements",
|
||||
"key": "UsePreviousProbeMeasurements",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"use_previous_measurements":
|
||||
{
|
||||
"label": "Use last measurement?",
|
||||
"description": "Selecting this will remove the G29 probing command and instead ensure previous measurements are loaded and enabled",
|
||||
"type": "bool",
|
||||
"default_value": false
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
text = "M501 ;load bed level data\nM420 S1 ;enable bed leveling"
|
||||
if self.getSettingValueByKey("use_previous_measurements"):
|
||||
for layer in data:
|
||||
layer_index = data.index(layer)
|
||||
lines = layer.split("\n")
|
||||
for line in lines:
|
||||
if line.startswith("G29"):
|
||||
line_index = lines.index(line)
|
||||
lines[line_index] = text
|
||||
final_lines = "\n".join(lines)
|
||||
data[layer_index] = final_lines
|
||||
return data
|
Loading…
Add table
Add a link
Reference in a new issue