Skip to content

Commit

Permalink
start_end: Add randomized XY print position on bed
Browse files Browse the repository at this point in the history
  • Loading branch information
jschuh committed May 22, 2023
1 parent 15b4903 commit fc6672e
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 4 deletions.
32 changes: 29 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,17 @@ _PRINT_START_PHASE_PURGE
; to generate the purge).
```

#### Additional SuperSlicer Start G-code

If you're using SuperSlicer you can add the following immediately before the
`PRINT_START` line from above. This will perform some added bounds checking and
will allow you to use the random print relocation feature without requiring
`exclude_object` entries in the print file.

```
PRINT_START_SET MODEL_MIN={bounding_box[0]},{bounding_box[1]} MODEL_MAX={bounding_box[3]},{bounding_box[4]}
```

#### End G-code

```
Expand Down Expand Up @@ -922,22 +933,37 @@ These are the customization options you can add to your
adjustments after the print completes or is cancelled (e.g. feedrate,
flow percentage).

* `variable_start_purge_clearance` *(default: 5.0)* Distance (in millimeters)
* `variable_start_purge_clearance` *(default: 5.0)* - Distance (in millimeters)
between the purge lines and the print area (if a `start_purge_length` is
provided).

* `variable_start_purge_length` *(default: 0.0)* - Length of filament (in
millimeters) to purge after the extruder finishes heating and prior to
starting the print. For most setups `30` is a good starting point.

* `variable_start_purge_prime_length` *(default: 10.0)* Length of filament (in
* `variable_start_purge_prime_length` *(default: 10.0)* - Length of filament (in
millimeters) to prime the extruder before drawing the purge lines.

* `variable_start_quad_gantry_level_at_temp` *(default: True if
`quad_gantry_level` configured)* - If true the `PRINT_START` macro will run
`QUAD_GANTRY_LEVEL` after the bed has stabilized at its target temperature.

* `variable_start_try_saved_surface_mesh` *(default: False)* If enabled and
* `variable_start_random_placement_max` *(default: 0)* - A positive value
specifies the +/- distance in the XY axes that the print can be randomly
relocated (assuming the bed has sufficient space). This can help reduce bed
wear from repeatedly printing in the same spot. Note that this feature
requires additional information to determine the proper bounds of the
relocated print. As such, `START_PRINT` must have valid `MESH_MIN`/`MESH_MAX`
parameters, and either `MODEL_MIN`/`MODEL_MAX` must be set or the print file
must include `EXCLUDE_OBJECT_DEFINE` statements with `POLYGON` lists that
define the bounds of the objects ([see `exclude_object` for more information](
https://www.klipper3d.org/Exclude_Object.html)).

* `variable_start_random_placement_padding` *(default: 10.0)* - The minimum
distance the relocated print will be placed from the printable edge of the
bed.

* `variable_start_try_saved_surface_mesh` *(default: False)* - If enabled and
`bed_mesh.profiles` contains a matching mesh for the currently select bed
surface, then the mesh will be loaded from the saved profile (and
[`BED_MESH_CALIBRATE_FAST`](#bed-mesh-improvements) will be skipped if
Expand Down
4 changes: 4 additions & 0 deletions globals.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ variable_start_purge_length: 0.0 # 30 is a good starting point.
variable_start_purge_prime_length: 12.0
# Level gantry in PRINT_START after bed temp stabilizes; False to disable.
variable_start_quad_gantry_level_at_temp: True
# Maximum distance to relocate print in random XY location to reduce bed wear.
variable_start_random_placement_max: 0
# The relocation will be at least this far from the printable edge of the bed.
variable_start_random_placement_padding: 10.0
# Skip level and load saved mesh for current sheet (if found); False to disable.
variable_start_try_saved_surface_mesh: False
# Adjust Z tilt in PRINT_START after bed temp stabilizes; False to disable.
Expand Down
1 change: 1 addition & 0 deletions pause_resume_cancel.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ gcode:
RESTORE_GCODE_STATE NAME=_KM_PAUSE_OVERRIDE_STATE MOVE=0
{% endif %}
CLEAR_PAUSE
_KM_APPLY_PRINT_OFFSET RESET=1
{% if 'virtual_sdcard' in printer and not printer.virtual_sdcard.is_active %}
SDCARD_RESET_FILE
{% endif %}
Expand Down
58 changes: 57 additions & 1 deletion start_end.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ description: Inserted by slicer at start of print. Initializes PRINT_START
gcode:
CHECK_KM_CONFIG # Need this in case startup errors were missed.
SET_GCODE_VARIABLE MACRO=_print_end_inner VARIABLE=cancelled VALUE="{False}"
_KM_APPLY_PRINT_OFFSET RESET=1
{% set settings = printer["gcode_macro print_start_set"].settings %}
{% if 'PRINT_START_PHASE' in settings %}
{ action_raise_error("Error in PRINT_START_PHASE: init") }
Expand Down Expand Up @@ -134,12 +135,46 @@ description: Inserted by slicer at start of print. Performs probing (including
Usage: See PRINT_START.
gcode:
{% set settings = printer["gcode_macro print_start_set"].settings %}
{% set km = printer["gcode_macro _km_globals"] %}
{% if settings.PRINT_START_PHASE != "probing" %}
{ action_raise_error("Error in PRINT_START_PHASE: %s" %
(settings.PRINT_START_PHASE,)) }
{% endif %}

{% set MESH_MIN = settings.MESH_MIN|default(None) %}
{% set MESH_MAX = settings.MESH_MAX|default(None) %}
# Randomize the placement of the print on the bed.
{% if km.start_random_placement_max > 0 and settings.PRINT_MIN and MESH_MIN %}
{% set PRINT_MIN = settings.PRINT_MIN.split(",")|map('float')|list %}
{% set PRINT_MAX = settings.PRINT_MAX.split(",")|map('float')|list %}
{% set x_offset = (((km.print_max[0] - km.print_min[0] - PRINT_MAX[0] +
PRINT_MIN[0] - 2 * km.start_random_placement_padding)|int,
km.start_random_placement_max * 2)|min, 0)|max %}
{% set y_offset = (((km.print_max[1] - km.print_min[1] - PRINT_MAX[1] +
PRINT_MIN[1] - 2 * km.start_random_placement_padding)|int,
km.start_random_placement_max * 2)|min, 0)|max %}
{% if x_offset > 0 %}
{% set x_offset = range(x_offset)|random + km.print_min[0] -
PRINT_MIN[0] + km.start_random_placement_padding %}
{% endif %}
{% if y_offset > 0 %}
{% set y_offset = range(y_offset)|random + km.print_min[1] -
PRINT_MIN[1] + km.start_random_placement_padding %}
{% endif %}
# This MESH_MIN/MESH_MAX gets passed to BED_MESH_CALIBRATE below, but the
# rest of the macros rely on SET_GCODE_OFFSET performing the adjustment.
{% set MESH_MIN = MESH_MIN.split(",")|map('float')|list %}
{% set MESH_MAX = MESH_MAX.split(",")|map('float')|list %}
{% set MESH_MIN_NEW = (MESH_MIN[0] + x_offset, MESH_MIN[1] + y_offset) %}
{% set MESH_MAX_NEW = (MESH_MAX[0] + x_offset, MESH_MAX[1] + y_offset) %}
{action_respond_info(
"Relocating print origin from (%.3f,%.3f) "|format(*MESH_MIN) +
"to (%.3f,%.3f)"|format(*MESH_MIN_NEW))}
{% set MESH_MIN = (MESH_MIN_NEW[0], MESH_MIN_NEW[1])|join(',') %}
{% set MESH_MAX = (MESH_MAX_NEW[0], MESH_MAX_NEW[1])|join(',') %}
PRINT_START_SET PRINT_OFFSET={"%d,%d" % (x_offset,y_offset)}
{% endif %}

{% set EXTRUDER = settings.EXTRUDER|int %}
{% set km = printer["gcode_macro _km_globals"] %}
{% set start_level_bed_at_temp = km.start_level_bed_at_temp and
Expand Down Expand Up @@ -188,6 +223,8 @@ gcode:
# Wait for extruder to reach temperature
_KM_PARK_IF_NEEDED HEATER={printer.toolhead.extruder} RANGE=ABOVE
M109 S{EXTRUDER}
# Apply the offset for bed placement randomization.
_KM_APPLY_PRINT_OFFSET
# apply Z offset for bed surface (just in case it was reset).
_APPLY_BED_SURFACE_OFFSET
PRINT_START_SET PRINT_START_PHASE="purge"
Expand Down Expand Up @@ -239,6 +276,24 @@ gcode:
{% endif %}
{% endif %}

[gcode_macro _km_apply_print_offset]
variable_offset: []
gcode:
{% set settings = printer["gcode_macro print_start_set"].settings %}
{% if params.RESET|default(0)|int and offset and
not printer["gcode_macro _km_save_state"].is_ephemeral%}
{% set PRINT_OFFSET = [offset.pop(0) * -1, offset.pop() * -1] %}
{% elif settings.PRINT_OFFSET and not offset and
not printer["gcode_macro _km_save_state"].is_ephemeral %}
{% set PRINT_OFFSET = settings.PRINT_OFFSET.split(",")|map('float')|list %}
{% set dummy = offset.extend(PRINT_OFFSET) %}
{% endif %}

{% if PRINT_OFFSET %}
_KM_SET_GCODE_OFFSET_BASE {"X_ADJUST=%.2f Y_ADJUST=%.2f"|
format(*PRINT_OFFSET)}
{% endif %}

[gcode_macro _km_mesh_if_needed]
gcode:
# TODO: Instead of blindly using the loaded mesh we could probe a few key
Expand Down Expand Up @@ -274,7 +329,6 @@ gcode:
M220 S100
M221 S100
{% endif %}
_KM_APPLY_PRINT_OFFSET INVERT=1
_RESET_LAYER_GCODE
_RESET_VELOCITY_LIMITS
TURN_OFF_HEATERS
Expand Down Expand Up @@ -308,6 +362,8 @@ gcode:
G91
G0 Z{z_safe} E-1.0 F{km.travel_speed_z * 2} ; move nozzle up
G0 X{x_safe} Y{y_safe} E-1.0 F{km.travel_speed_xy} ; remove stringing
# Remove the offset now that we're done.
_KM_APPLY_PRINT_OFFSET RESET=1
{% endif %}

# Small retract to prevent ooze
Expand Down
8 changes: 8 additions & 0 deletions state.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ gcode:
_KM_RESTORE_GCODE_STATE {rawparams}
{% set NAME = params.NAME|default("default") %}
_km_save_state NAME={NAME} SAVE=0

[gcode_macro _abort_on_gcode_state]
gcode:
{% set save_state = printer["gcode_macro _km_save_state"] %}
{% if save_state.is_ephemeral %}
{action_raise_error("Encountered unexpected save state " +
save_state.state_set|list|sort|string)}
{% endif %}

0 comments on commit fc6672e

Please sign in to comment.