; This macro generates a test print to determine the best pressure advance factor (M572 S-parameter) ; It uses the test print described in this forum post: ; https://forum.duet3d.com/topic/6698/pressure-advance-calibration ; Author: Schmart ; WARNING: all dimensions, size units and speeds are in mm and mm/s ; Reference for conditional G-code: ; - https://duet3d.dozuki.com/Wiki/GCode_Meta_Commands ; Wishes for conditional G-code: ; - Canceling or stopping running conditional G-code ; - Simulation; logging what commands would be executed/generated without actually executing them ; - Dumping the variables (names and values) in a macro, perhaps also treating variable in a meta-way, e.g. {#var} for count, {var[0].name} and {var['layer_height'].value} ; - Assigning an object or array to a variable. E.g. var axis = move.axes[0]; echo {var.axis.letter} ; - Custom subroutine/function definition, e.g. def print_line(var a, var b) ; - ceiling(), pow() and sq() functions ; TODO: ; - Many optimizations still remaining ; - Perhaps the most important variables (bed and print temperature, filament diameter, extrusion multiplier, PA stepping) ; can be made into macro parameters, e.g. M98 P"0:/macros/4 - Print Tuning/Pressure Advance" B40 P204 D1.75 X0.95 S0.02 P0.002 ; Starting value for pressure advance var pa_start = 0.0 ; Pressure advance increment for each (whole) millimeter print height ; e.g. if var.height = 20, var.pa_start = 0.1 and var.pa_stepping = 0.004, then ; the PA test range is from 0.1 to (0.1 + 20 * 0.004) => 0.1 to 0.18. var pa_stepping = 0.005 ; The extruder to apply the pressure advance factor to var pa_extruder = 0 ; These values specify the center of the print bed ; The default bed center is at (0,0) var x_center = 100 var y_center = 100 ; Print temperatures var print_temperature = 260 var standby_temperature = 120 var bed_temperature = 95 ; Height of the test print var height = 20 var layer_height = 0.20 ; Number of fast segments var fast_segments = 3 ; Slow segments are at the beginning and the end, and in between fast segments, e.g. SLOW FAST SLOW FAST SLOW var slow_segment_length = 10 var fast_segment_length = 20 ; Definition of speeds var first_layer_speed = 20 var travel_speed = 150 var fast_segment_speed = 80 var slow_segment_speed = 20 ; Number of perimeters around the object as a stable base var skirt_loops = 6 ; Height of the skirt in layers var skirt_layers = 2 ; The tool number to print with var tool_number = 0 ; Extrusion width is calculated here, but can also be set with a literal value ; Note that 1.05 and 1.125 are common factors that result in 0.42mm or 0.45mm width respectively var nozzle_bore_diameter = 0.40 var extrusion_width = {var.nozzle_bore_diameter * 1.125} var filament_diameter = 1.75 var extrusion_multiplier = 0.93 ; Firmware retraction settings var retract_length = 0.4 var retract_restart_length = 0 var retract_speed = 40 var deretract_speed = 40 var retract_z_lift = 0 ; Flow math var filament_flow = {pi * var.filament_diameter * var.filament_diameter / 4} var regular_flow = {(var.extrusion_width - var.layer_height) * var.layer_height + pi * var.layer_height * var.layer_height / 4} var bridge_flow = {pi * var.nozzle_bore_diameter * var.nozzle_bore_diameter / 4} var line_spacing = {var.extrusion_width - var.layer_height * (1 - pi / 4)} var regular_flow_ratio = { var.extrusion_multiplier * var.regular_flow / var.filament_flow} var purge_line_flow_ratio = { 2.0 * var.regular_flow_ratio } echo "extrusion_width: " ^ var.extrusion_width echo "layer_height: " ^ var.layer_height echo "filament_flow: " ^ var.filament_flow echo "bridge_flow: " ^ var.bridge_flow echo "regular_flow: " ^ var.regular_flow echo "line_spacing: " ^ var.line_spacing echo "regular_flow_ratio: " ^ var.regular_flow_ratio ;M37 S1 ; Enter simulation mode ; Set firmware retraction M207 S{var.retract_length} R{var.retract_restart_length} F{60 * var.retract_speed} T{60 * var.deretract_speed} Z{var.retract_z_lift} T{var.tool_number} ; Select tool M106 S0 ; Turn off part cooling fan M568 P{var.tool_number} S{var.print_temperature} R{var.standby_temperature} A1 ; Set tool to standby temperature M190 S{var.bed_temperature} ; Wait for bed temperature to reach setpoint M116 P{var.tool_number} ; Wait for temperatures associated with the selected tool to be reached ; Make an inventory of axes that have not yet been homed var axes = "" echo "Total number of axes: " ^ {#move.axes} while {iterations < #move.axes} if {!move.axes[iterations].homed} set var.axes = {var.axes ^ move.axes[iterations].letter} ; Home applicable axes echo "Axes to be homed: " ^ var.axes G32 ;G28 XYZ ; Home the X, Y and Z axes ;G28 XY ; Home the X and Y axes ;G28 Z ; Home the Z axis G21 ; Set units to millimeters M83 ; Use relative distances for extrusion ; Calculate object width var width = {var.fast_segments * var.fast_segment_length + (1 + var.fast_segments) * var.slow_segment_length} ; Calculate starting coordinates and other constant(s) var x_start = {var.x_center - 0.5 * var.width + var.skirt_loops * var.line_spacing} var y_start = {var.y_center - 0.5 * var.line_spacing + var.skirt_loops * var.line_spacing} var travel_feedrate = {60 * var.travel_speed} var first_layer_feedrate = {60 * var.first_layer_speed} ; Absolute position for purge line in X and Y space, 50 mm behind model G90 ; Use absolute coordinates G1 X{var.x_start} Y{var.y_start + 50} F{var.travel_feedrate} ; Set heater to final temperature and wait M568 A2 M116 P{var.tool_number} ; Absolute position of nozzle at first layer height G1 Z{var.layer_height} F{var.travel_feedrate} ; Relatively print two fat purge lines G91 ; Switch to relative coordinates G1 X{var.width} E{var.width * var.purge_line_flow_ratio} F{var.first_layer_feedrate} G1 Y{-(2 * var.line_spacing)} F{var.travel_feedrate} G1 X{-var.width} E{var.width * var.purge_line_flow_ratio} F{var.first_layer_feedrate} G10 ; Retract to prevent oozing ; Move to the start of the model in X, Y and Z space ; The skirt code also moves to the start, but the skirt can be disabled. ; Also, the skirt code does not set Z, and there may be no purge line for which Z is set. Safety first. G90 ; Use absolute coordinates G1 X{var.x_start} Y{var.y_start} Z{var.layer_height} F{var.travel_feedrate} G91 ; Switch to relative coordinates G11 ; Advance/unretract/deretract in preparation to print ; Routine for printing the test object var layers = {floor(var.height / var.layer_height)} echo "Total number of layers: " ^ var.layers while {iterations < var.layers} ; Track current layer var layer = {iterations + 1} ; Current height in mm var z = {var.layer * var.layer_height} ; Calculate pressure advance factor var pa = {var.pa_start + floor(var.z) * var.pa_stepping} ; Set pressure advance M572 D{var.pa_extruder} S{var.pa} ; Output some statistics while printing echo "Layer " ^ iterations ^ " (" ^ {iterations + 1} ^ " of " ^ {var.layers} ^ " at " ^ {var.z} ^ "mm)" echo "Pressure advance: " ^ {var.pa} ; Pre-calculate feedrates for first layer and other layers var slow_segment_feedrate = {60 * (var.layer == 1 ? var.first_layer_speed : var.slow_segment_speed)} var fast_segment_feedrate = {60 * (var.layer == 1 ? var.first_layer_speed : var.fast_segment_speed)} ; Print skirt if {iterations < var.skirt_layers} G90 ; Use absolute coordinates ; Move to absolute XY start coordinates G1 X{var.x_start} Y{var.y_start} F{var.travel_feedrate} G91 ; Switch to relative coordinates ; Print all loops of the skirt while {iterations < var.skirt_loops} var skirt_loop = {var.skirt_loops - iterations} var x = {var.width + 2 * var.skirt_loop * var.line_spacing} var y = {var.line_spacing + 2 * var.skirt_loop * var.line_spacing} ; Print one full skirt loop while iterations < 2 var direction = {iterations == 0 ? 1 : -1} G1 X{var.direction * var.x} E{var.x * var.regular_flow_ratio} F{var.fast_segment_feedrate} G1 Y{var.direction * var.y} E{var.y * var.regular_flow_ratio} F{var.fast_segment_feedrate} ; Travel to the start of the next skirt loop G1 X{var.line_spacing} Y{var.line_spacing} F{var.travel_feedrate} ; Print two perimeters back and forth of alternating slow and fast segments while iterations < 2 var direction = {iterations == 0 ? 1 : -1} ; Slow starting segment (X) G1 X{var.direction * var.slow_segment_length} E{var.slow_segment_length * var.regular_flow_ratio} F{var.slow_segment_feedrate} ; Remaining fast and slow segments (X) while iterations < var.fast_segments G1 X{var.direction * var.fast_segment_length} E{var.fast_segment_length * var.regular_flow_ratio} F{var.fast_segment_feedrate} G1 X{var.direction * var.slow_segment_length} E{var.slow_segment_length * var.regular_flow_ratio} F{var.slow_segment_feedrate} ; Print the side perimeter (Y) G1 Y{var.direction * var.line_spacing} E{var.line_spacing * var.regular_flow_ratio} F{var.slow_segment_feedrate} ; Move one layer up G1 Z{var.layer_height} F{var.travel_feedrate} G10 ; Retract G91 ; Relative positioning G1 F3000 Z20 ; Move gantry up 20mm G90 ; Absolute positioning ;M104 S0 ; Turn off nozzle heat block M568 P{var.tool_number} S0 R0 A2 ; Set required heater temperature off M140 S0 ; Turn off bed M106 S0 ; Turn off part cooling fan M18 ; Disable stepper motors ; Simulated print time: 671