Merge branch 'master' into master-1

This commit is contained in:
Lipu Fei 2019-12-11 10:57:50 +01:00 committed by GitHub
commit 849ac3551d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2286 changed files with 195832 additions and 76181 deletions

View file

@ -162,7 +162,7 @@ class PostProcessingPlugin(QObject, Extension):
loaded_script = importlib.util.module_from_spec(spec)
if spec.loader is None:
continue
spec.loader.exec_module(loaded_script)
spec.loader.exec_module(loaded_script) # type: ignore
sys.modules[script_name] = loaded_script #TODO: This could be a security risk. Overwrite any module with a user-provided name?
loaded_class = getattr(loaded_script, script_name)
@ -219,6 +219,7 @@ class PostProcessingPlugin(QObject, Extension):
self._script_list.clear()
if not new_stack.getMetaDataEntry("post_processing_scripts"): # Missing or empty.
self.scriptListChanged.emit() # Even emit this if it didn't change. We want it to write the empty list to the stack's metadata.
self.setSelectedScriptIndex(-1)
return
self._script_list.clear()

View file

@ -2,7 +2,7 @@
"name": "Post Processing",
"author": "Ultimaker",
"version": "2.2.1",
"api": "6.0",
"api": "7.0",
"description": "Extension that allows for user created scripts for post processing",
"catalog": "cura"
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View 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

View file

@ -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"

View file

@ -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

View 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

View file

@ -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)

View 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

View file

@ -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