mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
Re-write Time Lapse
An update to the script. - Added insertion frequency - Added support for relative extrusion - Retract is now a boolean and the settings come from Cura. There won't be a retraction if there is already a retraction.
This commit is contained in:
parent
d842d9c139
commit
0ba72bccf9
1 changed files with 157 additions and 77 deletions
|
@ -1,17 +1,21 @@
|
||||||
# Copyright (c) 2020 Ultimaker B.V.
|
# Copyright (c) 2020 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
|
||||||
# Created by Wayne Porter
|
# Created by Wayne Porter
|
||||||
|
# Re-write April 15, 2024 by GregValiant (Greg Foresi)
|
||||||
|
# Changes:
|
||||||
|
# Added insertion frequency
|
||||||
|
# Added support for Relative Extrusion mode
|
||||||
|
# Changed Retract to a boolean and when True use the regular Cura retract settings.
|
||||||
|
# Use the regular Cura settings for Travel Speed and Speed_Z instead of asking.
|
||||||
|
# Added code to prevent retracts when parking if the filament was already retracted.
|
||||||
|
|
||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
|
from UM.Application import Application
|
||||||
|
|
||||||
class TimeLapse(Script):
|
class TimeLapse(Script):
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
def getSettingDataString(self):
|
def getSettingDataString(self):
|
||||||
return """{
|
return """{
|
||||||
"name": "Time Lapse",
|
"name": "Time Lapse Camera",
|
||||||
"key": "TimeLapse",
|
"key": "TimeLapse",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"version": 2,
|
"version": 2,
|
||||||
|
@ -19,32 +23,48 @@ class TimeLapse(Script):
|
||||||
{
|
{
|
||||||
"trigger_command":
|
"trigger_command":
|
||||||
{
|
{
|
||||||
"label": "Trigger camera command",
|
"label": "Camera Trigger Command",
|
||||||
"description": "G-code command used to trigger camera.",
|
"description": "G-code command used to trigger the camera. The command will be inserted at the ends of layers.",
|
||||||
"type": "str",
|
"type": "str",
|
||||||
"default_value": "M240"
|
"default_value": "M240"
|
||||||
},
|
},
|
||||||
|
"insert_frequency":
|
||||||
|
{
|
||||||
|
"label": "How often (layers)",
|
||||||
|
"description": "Every so many layers (always starts at the first layer whether it's the model or a raft).",
|
||||||
|
"type": "enum",
|
||||||
|
"options": {
|
||||||
|
"every_layer": "Every Layer",
|
||||||
|
"every_2nd": "Every 2nd",
|
||||||
|
"every_3rd": "Every 3rd",
|
||||||
|
"every_5th": "Every 5th",
|
||||||
|
"every_10th": "Every 10th",
|
||||||
|
"every_25th": "Every 25th",
|
||||||
|
"every_50th": "Every 50th",
|
||||||
|
"every_100th": "Every 100th"},
|
||||||
|
"default_value": "every_layer"
|
||||||
|
},
|
||||||
"pause_length":
|
"pause_length":
|
||||||
{
|
{
|
||||||
"label": "Pause length",
|
"label": "Wait for Camera",
|
||||||
"description": "How long to wait (in ms) after camera was triggered.",
|
"description": "How long to wait (in ms) after the camera was triggered before returning to the print.",
|
||||||
"type": "int",
|
"type": "int",
|
||||||
"default_value": 700,
|
"default_value": 700,
|
||||||
"minimum_value": 0,
|
"minimum_value": 0,
|
||||||
"unit": "ms"
|
"unit": "ms "
|
||||||
},
|
},
|
||||||
"park_print_head":
|
"park_print_head":
|
||||||
{
|
{
|
||||||
"label": "Park Print Head",
|
"label": "Park Print Head",
|
||||||
"description": "Park the print head out of the way. Assumes absolute positioning.",
|
"description": "Park the print head out of the way.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"default_value": true
|
"default_value": true
|
||||||
},
|
},
|
||||||
"head_park_x":
|
"head_park_x":
|
||||||
{
|
{
|
||||||
"label": "Park Print Head X",
|
"label": "Park Print Head X",
|
||||||
"description": "What X location does the head move to for photo.",
|
"description": "What X location does the head move to for the photo.",
|
||||||
"unit": "mm",
|
"unit": "mm ",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 0,
|
"default_value": 0,
|
||||||
"enabled": "park_print_head"
|
"enabled": "park_print_head"
|
||||||
|
@ -52,93 +72,153 @@ class TimeLapse(Script):
|
||||||
"head_park_y":
|
"head_park_y":
|
||||||
{
|
{
|
||||||
"label": "Park Print Head Y",
|
"label": "Park Print Head Y",
|
||||||
"description": "What Y location does the head move to for photo.",
|
"description": "What Y location does the head move to for the photo.",
|
||||||
"unit": "mm",
|
"unit": "mm ",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 190,
|
"default_value": 0,
|
||||||
"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"
|
"enabled": "park_print_head"
|
||||||
},
|
},
|
||||||
"retract":
|
"retract":
|
||||||
{
|
{
|
||||||
"label": "Retraction Distance",
|
"label": "Retract when required",
|
||||||
"description": "Filament retraction distance for camera trigger.",
|
"description": "Retract if there is not already a retraction. If unchecked then there will be no retraction even if there is none in the gcode. If retractions are not enabled in Cura there won't be a retraction regardless of this setting.",
|
||||||
"unit": "mm",
|
"type": "bool",
|
||||||
"type": "int",
|
"default_value": true
|
||||||
"default_value": 0
|
|
||||||
},
|
},
|
||||||
"zhop":
|
"zhop":
|
||||||
{
|
{
|
||||||
"label": "Z-Hop Height When Parking",
|
"label": "Z-Hop Height When Parking",
|
||||||
"description": "Z-hop length before parking",
|
"description": "The height to lift the nozzle off the print before parking.",
|
||||||
"unit": "mm",
|
"unit": "mm ",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 0
|
"default_value": 2.0,
|
||||||
|
"minimum_value": 0.0
|
||||||
|
},
|
||||||
|
"ensure_final_image":
|
||||||
|
{
|
||||||
|
"label": "Ensure Final Image",
|
||||||
|
"description": "Depending on how the layer numbers work out with the 'How Often' frequency there might not be an image taken at the end of the last layer. This will ensure that one is taken. There is no parking because the 'End Gcode' occurs immediately after.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"""
|
}"""
|
||||||
|
|
||||||
def execute(self, data):
|
def execute(self, data):
|
||||||
feed_rate = self.getSettingValueByKey("park_feed_rate")
|
# Get the settings and initialize some variables
|
||||||
|
mycura = Application.getInstance().getGlobalContainerStack()
|
||||||
|
relative_extrusion = bool(mycura.getProperty("relative_extrusion", "value"))
|
||||||
|
extruder = mycura.extruderList
|
||||||
|
retract_speed = int(extruder[0].getProperty("retraction_speed", "value"))*60
|
||||||
|
retract_dist = int(extruder[0].getProperty("retraction_amount", "value"))
|
||||||
|
retract_enabled = bool(extruder[0].getProperty("retraction_enable", "value"))
|
||||||
|
speed_z = int(extruder[0].getProperty("speed_z_hop", "value"))*60
|
||||||
|
if relative_extrusion:
|
||||||
|
rel_cmd = 83
|
||||||
|
else:
|
||||||
|
rel_cmd = 82
|
||||||
|
trav_speed = int(extruder[0].getProperty("speed_travel", "value"))*60
|
||||||
park_print_head = self.getSettingValueByKey("park_print_head")
|
park_print_head = self.getSettingValueByKey("park_print_head")
|
||||||
x_park = self.getSettingValueByKey("head_park_x")
|
x_park = self.getSettingValueByKey("head_park_x")
|
||||||
y_park = self.getSettingValueByKey("head_park_y")
|
y_park = self.getSettingValueByKey("head_park_y")
|
||||||
trigger_command = self.getSettingValueByKey("trigger_command")
|
trigger_command = self.getSettingValueByKey("trigger_command")
|
||||||
pause_length = self.getSettingValueByKey("pause_length")
|
pause_length = self.getSettingValueByKey("pause_length")
|
||||||
retract = int(self.getSettingValueByKey("retract"))
|
retract = bool(self.getSettingValueByKey("retract"))
|
||||||
zhop = self.getSettingValueByKey("zhop")
|
zhop = self.getSettingValueByKey("zhop")
|
||||||
gcode_to_append = ";TimeLapse Begin\n"
|
ensure_final_image = bool(self.getSettingValueByKey("ensure_final_image"))
|
||||||
|
when_to_insert = self.getSettingValueByKey("insert_frequency")
|
||||||
last_x = 0
|
last_x = 0
|
||||||
last_y = 0
|
last_y = 0
|
||||||
last_z = 0
|
last_z = 0
|
||||||
|
last_e = 0
|
||||||
|
prev_e = 0
|
||||||
|
is_retracted = False
|
||||||
|
gcode_to_append = ""
|
||||||
if park_print_head:
|
if park_print_head:
|
||||||
gcode_to_append += self.putValue(G=1, F=feed_rate,
|
gcode_to_append += f"G1 F{trav_speed} X{x_park} Y{y_park} ;Park print head\n"
|
||||||
X=x_park, Y=y_park) + " ;Park print head\n"
|
gcode_to_append += "M400 ;Wait for moves to finish\n"
|
||||||
gcode_to_append += self.putValue(M=400) + " ;Wait for moves to finish\n"
|
gcode_to_append += trigger_command + " ;Snap the Image\n"
|
||||||
gcode_to_append += trigger_command + " ;Snap Photo\n"
|
gcode_to_append += f"G4 P{pause_length} ;Wait for camera\n"
|
||||||
gcode_to_append += self.putValue(G=4, P=pause_length) + " ;Wait for camera\n"
|
match when_to_insert:
|
||||||
|
case "every_layer":
|
||||||
for idx, layer in enumerate(data):
|
step_freq = 1
|
||||||
for line in layer.split("\n"):
|
case "every_2nd":
|
||||||
if self.getValue(line, "G") in {0, 1}: # Track X,Y,Z location.
|
step_freq = 2
|
||||||
last_x = self.getValue(line, "X", last_x)
|
case "every_3rd":
|
||||||
last_y = self.getValue(line, "Y", last_y)
|
step_freq = 3
|
||||||
last_z = self.getValue(line, "Z", last_z)
|
case "every_5th":
|
||||||
# Check that a layer is being printed
|
step_freq = 5
|
||||||
lines = layer.split("\n")
|
case "every_10th":
|
||||||
for line in lines:
|
step_freq = 10
|
||||||
if ";LAYER:" in line:
|
case "every_25th":
|
||||||
if retract != 0: # Retract the filament so no stringing happens
|
step_freq = 25
|
||||||
layer += self.putValue(M=83) + " ;Extrude Relative\n"
|
case "every_50th":
|
||||||
layer += self.putValue(G=1, E=-retract, F=3000) + " ;Retract filament\n"
|
step_freq = 50
|
||||||
layer += self.putValue(M=82) + " ;Extrude Absolute\n"
|
case "every_100th":
|
||||||
layer += self.putValue(M=400) + " ;Wait for moves to finish\n" # Wait to fully retract before hopping
|
step_freq = 100
|
||||||
|
case _:
|
||||||
if zhop != 0:
|
step_freq = 1
|
||||||
layer += self.putValue(G=1, Z=last_z+zhop, F=3000) + " ;Z-Hop\n"
|
# Use the step_freq to index through the layers----------------------------------------
|
||||||
|
for num in range(2,len(data)-1,step_freq):
|
||||||
layer += gcode_to_append
|
layer = data[num]
|
||||||
|
try:
|
||||||
if zhop != 0:
|
# Track X,Y,Z location.--------------------------------------------------------
|
||||||
layer += self.putValue(G=0, X=last_x, Y=last_y, Z=last_z) + "; Restore position \n"
|
for line in layer.split("\n"):
|
||||||
else:
|
if self.getValue(line, "G") in {0, 1}:
|
||||||
layer += self.putValue(G=0, X=last_x, Y=last_y) + "; Restore position \n"
|
last_x = self.getValue(line, "X", last_x)
|
||||||
|
last_y = self.getValue(line, "Y", last_y)
|
||||||
if retract != 0:
|
last_z = self.getValue(line, "Z", last_z)
|
||||||
layer += self.putValue(M=400) + " ;Wait for moves to finish\n"
|
#Track the E location so that if there is already a retraction we don't double dip.
|
||||||
layer += self.putValue(M=83) + " ;Extrude Relative\n"
|
if rel_cmd == 82:
|
||||||
layer += self.putValue(G=1, E=retract, F=3000) + " ;Retract filament\n"
|
if " E" in line:
|
||||||
layer += self.putValue(M=82) + " ;Extrude Absolute\n"
|
last_e = line.split("E")[1]
|
||||||
|
if float(last_e) < float(prev_e):
|
||||||
data[idx] = layer
|
is_retracted = True
|
||||||
break
|
else:
|
||||||
|
is_retracted = False
|
||||||
|
prev_e = last_e
|
||||||
|
elif rel_cmd == 83:
|
||||||
|
if " E" in line:
|
||||||
|
last_e = line.split("E")[1]
|
||||||
|
if float(last_e) < 0:
|
||||||
|
is_retracted = True
|
||||||
|
else:
|
||||||
|
is_retracted = False
|
||||||
|
prev_e = last_e
|
||||||
|
# Insert the code----------------------------------------------------
|
||||||
|
lines = layer.split("\n")
|
||||||
|
camera_code = ""
|
||||||
|
for line in lines:
|
||||||
|
if ";LAYER:" in line:
|
||||||
|
# Retract unless already retracted
|
||||||
|
if retract and not is_retracted and retract_enabled:
|
||||||
|
camera_code += ";TYPE:CUSTOM-----------------TimeLapse Begin\n"
|
||||||
|
camera_code += "M83 ;Extrude Relative\n"
|
||||||
|
camera_code += f"G1 F{retract_speed} E-{retract_dist} ;Retract filament\n"
|
||||||
|
else:
|
||||||
|
camera_code += ";TYPE:CUSTOM-----------------TimeLapse Begin\n"
|
||||||
|
if zhop != 0:
|
||||||
|
camera_code += f"G1 F{speed_z} Z{last_z + zhop} ;Z-Hop\n"
|
||||||
|
camera_code += gcode_to_append
|
||||||
|
camera_code += self.putValue(G=0, F=trav_speed, X=last_x, Y=last_y) + " ;Restore XY position \n"
|
||||||
|
if zhop != 0:
|
||||||
|
camera_code += self.putValue(G=0, F=speed_z, Z=last_z) + " ;Restore Z position \n"
|
||||||
|
if retract and not is_retracted and retract_enabled:
|
||||||
|
camera_code += self.putValue(G=1, E=retract_dist, F=retract_speed) + " ;Un-Retract filament\n"
|
||||||
|
camera_code += self.putValue(M=rel_cmd) + " ;Extrude Mode\n"
|
||||||
|
camera_code += f";{'-' * 28}TimeLapse End"
|
||||||
|
# Format the camera code to be inserted
|
||||||
|
temp_lines = camera_code.split("\n")
|
||||||
|
for temp_index, temp_line in enumerate(temp_lines):
|
||||||
|
if ";" in temp_line and not temp_line.startswith(";"):
|
||||||
|
temp_lines[temp_index] = temp_line.replace(temp_line.split(";")[0], temp_line.split(";")[0] + str(" " * (29 - len(temp_line.split(";")[0]))),1)
|
||||||
|
temp_lines = "\n".join(temp_lines)
|
||||||
|
lines.insert(len(lines) - 2, temp_lines)
|
||||||
|
data[num] = "\n".join(lines)
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
# Take a final image if there was no camera shot at the end of the last layer.
|
||||||
|
if "TimeLapse Begin" not in data[len(data) - (3 if retract_enabled else 2)] and ensure_final_image:
|
||||||
|
data[len(data)-1] = "M400 ; Wait for all moves to finish\n" + trigger_command + " ;Snap the final Image\n" + f"G4 P{pause_length} ;Wait for camera\n" + data[len(data)-1]
|
||||||
return data
|
return data
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue