-
Notifications
You must be signed in to change notification settings - Fork 0
/
flow_calibrate.cfg
289 lines (244 loc) · 16.4 KB
/
flow_calibrate.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
#########################################
###### FLOW MULTIPLIER CALIBRATION ######
#########################################
# Written by Frix_x#0161 #
# @version: 1.4
# CHANGELOG:
# v1.4: fix issue when extrude_factor is != 1
# v1.3: fix the logging
# v1.2: fix for those using absolute extrusion that leads to an error
# v1.1: added part cooling fan control and some speed optimizations
# v1.0: first flow calibration macro
### What is it ? ###
# The main reason for this set of macros is to get a filament and slicer agnostic way to calibrate the flow extrusion multiplier.
# The goal is to make it easy to set, share and use it.
# This macro is parametric and most of the values can be adjusted with their respective input parameters.
# It can be called without any parameters - in which case the default values would be used - or with any combination of parameters as desired.
# Installation:
# 1. Copy this file and include it in your Klipper config
# 2. Add and activate the [gcode_arcs] section as it's used for the round corners ! Don't hesitate to change the resolution to something better like 0.1 or 0.2
# Usage:
# 1. Make sure your axis are homed, your bed mesh is loaded (if you are using one), both the hotend and the bed are at the temperature required for your filament
# and the machine ready to print something (be sure to also do the QGL, Z-tilt, set your Z offset correctly, ...).
# 2. Print the shell by typing in the klipper console (using Mainsail/Fluidd/Octoprint):
# FLOW_MULTIPLIER_CALIBRATION [args... like RAFT=1]
# 3. Measure the shell thickness using a caliper (or better using a micrometer) and call the computation macro with it:
# COMPUTE_FLOW_MULTIPLIER MEASURED_THICKNESS=xxx.xxx
# -> You will see the new computed flow printed in the console. You can then copy and paste it in your prefered slicer.
# Available input parameters for FLOW_MULTIPLIER_CALIBRATION :
# DO_RAFT : default(1) print a "base" to support the shell (better bed adhesion and easier to remove at the end)
# DO_RETRACT : default(0) enable/disable retraction. Disabled by default to try to keep a constant flow, but can be enabled in case of problems on the print
# SIZE : default(40) size in mm, that the test will use on the bed. The model will be printed in the middle of the bed
# HEIGHT : default(15) height in mm of the printed shell
# CORNER_RADIUS : default(8) external radius used in the corners of the shell to smooth the velocity and try to keep a constant flow over the print
# PERIMETERS : default(2) number of perimeters used to print the shell. If using 1 perim, it's mandatory to use a micrometer to measure: best is to use >=2
# FAN_SPEED : default(20) percentage of part cooling fan to use for the print (applied after the raft)
# EXTRUSION_MULTIPLIER: default(0.93) extrusion multiplier to apply to the print (use something close to the real one)
# FILAMENT_DIAMETER : default(1.75) diameter of the filament currently loaded in the machine
# EXTRUSION_WIDTH : default(0.4) width of an extrusion line (used as a goal). Using 0.4 for a 0.4mm diameter nozzle is a safe bet
# LAYER_HEIGHT : default(0.2) layer height of the print. Avoid too small layer height and try to be close to 0.5 * nozzle diameter
# CONTROL_SPEED : default(100) feedrate (in mm/s) for printing the shell
# RAFT_SPEED : default(60) feedrate (in mm/s) for printing the raft
# TRAVEL_SPEED : default(200) feedrate (in mm/s) for fast travel moves
# Z_LIFT_SPEED : default(20) feedrate (in mm/s) for z lift moves (basically Z-hop and Z alignement)
# RETRACT_SPEED : default(50) feedrate (in mm/s) for retract and unretract filament moves
# RETRACT_LENGTH : default(0.5) retraction length in mm (use your own retraction value for the filament)
# PURGE_MM : default(1) amount of filament pushed to initiate pressure before printing the prime line (can be 0 to disable)
# ================================================================================================================================================
# DO NOT MODIFY THOSE VARIABLES (they are used internaly by the flow calibration macro)
[gcode_macro _FLOW_CALIB_VARIABLES]
variable_last_shell_thickness: 0.0
variable_last_evalue: 0.0
gcode:
[gcode_macro FLOW_MULTIPLIER_CALIBRATION]
description: Print a small tower to calibrate the extrusion flow multiplier by measuring the shell
gcode:
#
# PARAMETERS
#
{% set do_raft = params.DO_RAFT|default(1)|int %} # whether to print a raft or not
{% set do_retract = params.DO_RECTRACT|default(0)|int %} # whether to enable retract/unrectract on travel moves
{% set print_size = params.SIZE|default(40)|int %} # size of the printed object on the build plate
{% set print_height = params.HEIGHT|default(15)|int %} # height of the printed object
{% set corner_radius = params.CORNER_RADIUS|default(8)|int %} # radius of the corners to smooth the shell and toolpath
{% set number_of_perimeters = params.PERIMETERS|default(2)|int %} # number of perimeters to print the shell
{% set fan_speed = params.FAN_SPEED|default(20)|int %} # part cooling fan speed in percent (0-100)
{% set e_multiplier = params.EXTRUSION_MULTIPLIER|default(0.93)|float %} # extrusion multiplier for the shell
{% set filament_diameter = params.FILAMENT_DIAMETER|default(1.75)|float %} # filament diameter
{% set extrusion_width = params.EXTRUSION_WIDTH|default(0.4)|float %} # extrusion width goal for one line
{% set layer_height = params.LAYER_HEIGHT|default(0.2)|float %} # layer height for the print
{% set retract_length = params.RETRACT_LENGTH|default(0.5)|float %} # how much to retract when traveling between print moves
{% set initial_purge = params.PURGE_MM|default(1)|int %} # mm of filament to purge before printing. set to 0 to disable
{% set z_hop_height = 2 * layer_height %}
{% set feedrate_print = params.CONTROL_SPEED|default(100)|int * 60 %} # print feedrate
{% set feedrate_travel = params.TRAVEL_SPEED|default(200)|int * 60 %} # travel feedrate between print moves
{% set feedrate_raft = params.RAFT_SPEED|default(60)|int * 60 %} # print feedrate for printing raft
{% set feedrate_z = params.Z_LIFT_SPEED|default(20)|int * 60 %} # z axis travel feedrate
{% set feedrate_retract = params.RETRACT_SPEED|default(50)|int * 60 %} # retract and deretract feedrate
#
# COMPUTED VALUES
#
{% set e_per_mm = ((extrusion_width - layer_height) * layer_height + 3.14159 * (layer_height / 2)**2) / (3.14159 * (filament_diameter / 2)**2) %} # computed E factor (similar to Slic3r/PrusaSlicer/SuperSlicer)
{% set spacing = extrusion_width - layer_height * (1 - 3.14159 / 4) %} # line spacing during the print
{% set shell_thickness = extrusion_width + (number_of_perimeters|float - 1) * spacing %} # theoric shell thickness
{% set max_x = printer.toolhead.axis_maximum.x|float %}
{% set max_y = printer.toolhead.axis_maximum.y|float %}
{% set x_start = max_x / 2 - print_size / 2 %}
{% set y_start = max_y / 2 - print_size / 2 %}
{% set x_end = x_start + print_size %}
{% set y_end = y_start + print_size %}
{% set num_raft_lines = ([print_size, max_x]|min / spacing)|round(0, 'floor')|int %}
{% set raft_size = num_raft_lines * spacing %}
#
# STARTING...
#
{action_respond_info("")}
{action_respond_info("Starting extrusion flow calibration print")}
{action_respond_info("This operation can not be interrupted by normal means. Hit the \"emergency stop\" button to stop it if needed")}
{action_respond_info("")}
{action_respond_info("Exrusion multiplier used: %.4f" % e_multiplier)}
{action_respond_info("Number of perimeters to print: %d" % number_of_perimeters)}
{action_respond_info("THEORIC SHELL THICKNESS: %.4f" % shell_thickness)}
{action_respond_info("")}
{action_respond_info("Measure the shell thickness using a caliper or micrometer. Then call the computation macro with the measured value:")}
{action_respond_info("COMPUTE_FLOW_MULTIPLIER MEASURED_THICKNESS=xxx.xxx")}
{action_respond_info("")}
SAVE_GCODE_STATE NAME=STATE_FLOW_MULTIPLIER_CALIBRATION
#
# set variables for later computation
#
SET_GCODE_VARIABLE MACRO=_FLOW_CALIB_VARIABLES VARIABLE=last_shell_thickness VALUE={shell_thickness}
SET_GCODE_VARIABLE MACRO=_FLOW_CALIB_VARIABLES VARIABLE=last_evalue VALUE={e_multiplier}
#
# purging before raft
#
G90
M83
G92 E0.0
G0 X{x_start} Y{y_start - 5} Z{layer_height} F{feedrate_travel} # move at the start position to do a purge line
G91 # use relative coordinates for the prime line
G1 E{initial_purge} F{5 * 60}
G1 X{raft_size} E{raft_size * e_per_mm * 1.5} F{feedrate_raft / 2} # print prime line
G1 Y-{extrusion_width} E{extrusion_width * e_per_mm} F{feedrate_raft / 2} # move to next line
G1 X-{raft_size} E{raft_size * e_per_mm} F{feedrate_raft / 2} # print second prime line
G1 E-{retract_length} F{feedrate_retract} # retract
G0 Z{z_hop_height} F{feedrate_z} # z-hop
G90 # back to absolute coordinates
G0 X{x_start} Y{y_start} F{feedrate_travel} # move to start position
G1 Z{layer_height} F{feedrate_z} # move to print height
G1 E{retract_length} F{feedrate_retract} # unretract
# set extrude_factor
M221 S{e_multiplier * 100}
#
# print the raft
#
{% if do_raft == 1 %}
G91 # use relative coordinates for the raft
{% for curr_raft_line in range(1, num_raft_lines + 2) %}
# print a raft line with alternating direction
G1 Y{loop.cycle(1.0, -1.0) * raft_size} E{raft_size * e_per_mm} F{feedrate_raft}
# spacing move
{% if not loop.last %}
G1 X{spacing} E{spacing * e_per_mm} F{feedrate_raft}
{% endif %}
{% endfor %}
G1 E-{retract_length} F{feedrate_retract} # retract
G0 Z{z_hop_height} F{feedrate_z} # z-hop
G90 # back to absolute coordinates
{% endif %}
#
# print the shell
#
G90
M106 S{fan_speed * 255 / 100}
# for each layer
{% for curr_layer in range(1, (print_height / layer_height)|round|int) %}
G0 X{x_start + corner_radius} Y{y_start} F{feedrate_travel} # move to XY start position
G1 Z{(curr_layer * layer_height) + (layer_height if do_raft == 1 else 0)} F{feedrate_z} # move to Z start position
# print one layer of the shell (in a for loop to do all the perimeters of one layer)
{% for perim_num in range(number_of_perimeters) %}
# compute values for the current perimeter (offset and radius)
{% set perim_offset = perim_num * spacing %}
{% set perim_radius = corner_radius - (perim_num * spacing) %}
# start position of the current perimeter
G1 X{x_start + corner_radius} Y{y_start + perim_offset} F{feedrate_travel}
{% if do_retract == 1 %}
G1 E{retract_length} F{feedrate_retract} # unretract
{% endif %}
# print the perimeter using the offset and radius computed
G1 X{x_end - corner_radius} Y{y_start + perim_offset} E{(print_size - (2 * corner_radius)) * e_per_mm} F{feedrate_print}
G3 X{x_end - perim_offset} Y{y_start + corner_radius} J{perim_radius} E{(3.14159 / 2) * perim_radius * e_per_mm} F{feedrate_print}
G1 X{x_end - perim_offset} Y{y_end - corner_radius} E{(print_size - (2 * corner_radius)) * e_per_mm} F{feedrate_print}
G3 X{x_end - corner_radius} Y{y_end - perim_offset} I-{perim_radius} E{(3.14159 / 2) * perim_radius * e_per_mm} F{feedrate_print}
G1 X{x_start + corner_radius} Y{y_end - perim_offset} E{(print_size - (2 * corner_radius)) * e_per_mm} F{feedrate_print}
G3 X{x_start + perim_offset} Y{y_end - corner_radius} J-{perim_radius} E{(3.14159 / 2) * perim_radius * e_per_mm} F{feedrate_print}
G1 X{x_start + perim_offset} Y{y_start + corner_radius} E{(print_size - (2 * corner_radius)) * e_per_mm} F{feedrate_print}
G3 X{x_start + corner_radius} Y{y_start + perim_offset} I{perim_radius} E{(3.14159 / 2) * perim_radius * e_per_mm} F{feedrate_print}
{% if do_retract == 1 %}
G1 E-{retract_length} F{feedrate_retract} # retract
{% endif %}
{% endfor %}
{% if do_retract == 1 %}
G91
G0 Z{z_hop_height} F{feedrate_z}
G90
{% endif %}
{% endfor %}
#
# retract and move away
#
G1 E-{retract_length} F{feedrate_retract}
G91
G0 Z20 F{feedrate_travel}
RESTORE_GCODE_STATE NAME=STATE_FLOW_MULTIPLIER_CALIBRATION
[gcode_macro COMPUTE_FLOW_MULTIPLIER]
description: Compute a new flow multiplier by using the measured shell thickness on the calibration print
gcode:
{% set evalue = params.OLD_EXTRUSION_MULTIPLIER|default(0.0)|float %} # extrusion multiplier used for the calibration print
{% set theorical_thickness = params.THEORICAL_THICKNESS|default(0.0)|float %} # theorical shell thickness
{% set measured_thickness = params.MEASURED_THICKNESS|default(0.0)|float %} # measured shell thickness on the calibration print
# if there is no OLD_EXTRUSION_MULTIPLIER passed as param, get the one from the last print calib run
{% if evalue == 0.0 %}
{% set last_evalue = printer["gcode_macro _FLOW_CALIB_VARIABLES"].last_evalue %}
# then, if there is also no evalue saved from the last run, alert user
{% if last_evalue == 0.0 %}
{action_respond_info("It seems that no calibration print was run prior to this (or a restart of Klipper occured).")}
{action_respond_info("You can still manually use it by calling again this macro like that:")}
{action_respond_info("COMPUTE_FLOW_MULTIPLIER OLD_EXTRUSION_MULTIPLIER=xxx.xxx THEORICAL_THICKNESS=xxx.xxx MEASURED_THICKNESS=xxx.xxx")}
{action_raise_error("not enough data to perform the computation of the new flow !")}
{% else %}
{% set final_evalue = last_evalue %}
{action_respond_info("Using OLD_EXTRUSION_MULTIPLIER: %.3f" % final_evalue)}
{% endif %}
{% else %}
{% set final_evalue = evalue %}
{action_respond_info("Using OLD_EXTRUSION_MULTIPLIER: %.3f" % final_evalue)}
{% endif %}
# similarly, if there is no THEORICAL_THICKNESS passed as param, get the one from the last print calib run
{% if theorical_thickness == 0.0 %}
{% set last_shell_thickness = printer["gcode_macro _FLOW_CALIB_VARIABLES"].last_shell_thickness %}
# then, if there is also no evalue saved from the last run, alert user
{% if last_shell_thickness == 0.0 %}
{action_respond_info("It seems that no calibration print was run prior to this (or a restart of Klipper occured).")}
{action_respond_info("You can still manually use it by calling again this macro like that:")}
{action_respond_info("COMPUTE_FLOW_MULTIPLIER OLD_EXTRUSION_MULTIPLIER=xxx.xxx THEORICAL_THICKNESS=xxx.xxx MEASURED_THICKNESS=xxx.xxx")}
{action_raise_error("not enough data to perform the computation of the new flow !")}
{% else %}
{% set final_theorical_thickness = last_shell_thickness %}
{action_respond_info("Using THEORICAL_THICKNESS: %.3f" % final_theorical_thickness)}
{% endif %}
{% else %}
{% set final_theorical_thickness = theorical_thickness %}
{action_respond_info("Using THEORICAL_THICKNESS: %.3f" % final_theorical_thickness)}
{% endif %}
# use the measured thickness from the user to compute a new flow value
{% if measured_thickness == 0.0 %}
{action_respond_info("You must use a caliper or micrometer to measure the calibration print shell thickness and call this macro with the measured value !!!")}
{action_respond_info("COMPUTE_FLOW_MULTIPLIER MEASURED_THICKNESS=xxx.xxx")}
{action_raise_error("not enough data to perform the computation of the new flow !")}
{% else %}
{% set new_evalue = final_theorical_thickness * final_evalue / measured_thickness %}
{action_respond_info("NEW COMPUTED FLOW VALUE: %.3f" % new_evalue)}
{action_respond_info("Use this new value as extrusion multiplier in your slicer of choice")}
{action_respond_info("")}
{% endif %}