155 lines
7.4 KiB
INI
155 lines
7.4 KiB
INI
#####################################################################
|
|||
|
|
# Purge check - did the filament really reach the nozzle during the
|
||
|
|
# Blobifier purge after a tool change?
|
||
|
|
#
|
||
|
|
# Two independent checks around the purge AFC runs after every load:
|
||
|
|
# 1. bdwidth motion: extruded mm vs mm the sensor saw moving past it.
|
||
|
|
# Catches a grinding extruder, a tangle or a snapped filament.
|
||
|
|
# 2. bd_pressure (needs the load-check firmware extension): how long
|
||
|
|
# the nozzle pressure stayed above the threshold. Catches filament
|
||
|
|
# that never reached the melt zone. Skipped automatically on stock
|
||
|
|
# firmware or when bdpressure_check.py is not installed.
|
||
|
|
#
|
||
|
|
# Needs: bdwidth_status.py in ~/klipper/klippy/extras/
|
||
|
|
# bdpressure_check.py in ~/klipper/klippy/extras/ (optional)
|
||
|
|
# (klipper/install.sh links both; guide: klipper/load_check/afc_blobifier/README.md)
|
||
|
|
# Hook: in [AFC] (AFC/AFC.cfg) change poop_cmd: BLOBIFIER
|
||
|
|
# to poop_cmd: BLOBIFIER_CHECKED
|
||
|
|
#
|
||
|
|
# Rollout:
|
||
|
|
# Phase 1 mode "report": only prints the results after every purge.
|
||
|
|
# Collect a few days of values, then set min_ratio and
|
||
|
|
# pressure_min_ms well below the lowest good ones.
|
||
|
|
# Phase 2 mode "enforce": pauses when a check fails.
|
||
|
|
#
|
||
|
|
# Costs about 2 x (sample_time + 0.5 s) per swap, 5 s at sample_time 2,
|
||
|
|
# so the sensors are quiet and up to date before and after the purge.
|
||
|
|
# When bdwidth is not reading, add bdwidth_warmup_ms: it is switched on for
|
||
|
|
# the check (motion only, SET_BDWIDTH ENABLE_MOTION) with its runout pause
|
||
|
|
# off meanwhile (SET_FILAMENT_SENSOR), and outside a print off again after.
|
||
|
|
#####################################################################
|
||
|
|
|
||
|
|
[bdwidth_status]
|
||
|
|
sensor: fila_width_0
|
||
|
|
|
||
|
|
# Remove this section if bdpressure_check.py is not installed
|
||
|
|
[bdpressure_check]
|
||
|
|
sensor: bd_pa
|
||
|
|
|
||
|
|
[gcode_macro _PURGE_CHECK_CFG]
|
||
|
|
variable_mode: "enforce" # report | enforce | off
|
||
|
|
variable_motion_check: False # False: skip the bdwidth motion check, pressure only
|
||
|
|
variable_min_ratio: 0.4 # placeholder: sensed mm / extruded mm below this = not feeding
|
||
|
|
variable_min_extrude: 20 # skip the checks for purges shorter than this (mm)
|
||
|
|
variable_pressure_min_ms: 5000 # placeholder: longest continuous pressure needed (ms)
|
||
|
|
# bdwidth is not reading after SET_BDWIDTH ... COMMAND=DISABLE and after
|
||
|
|
# every Klipper restart until an ENABLE (outside a print, often early in a
|
||
|
|
# print start). The check then switches it on and waits this long for the
|
||
|
|
# first readings (its first read often fails and it retries after 10 s).
|
||
|
|
variable_bdwidth_warmup_ms: 15000
|
||
|
|
variable_start_counts: 0
|
||
|
|
variable_start_e: 0.0
|
||
|
|
gcode:
|
||
|
|
|
||
|
|
[gcode_macro BLOBIFIER_CHECKED]
|
||
|
|
description: Blobifier purge with bdwidth motion and bd_pressure checks (use as poop_cmd in [AFC])
|
||
|
|
gcode:
|
||
|
|
{% set cfg = printer["gcode_macro _PURGE_CHECK_CFG"] %}
|
||
|
|
{% set wait = (printer.bdwidth_status.sample_time * 1000 + 500)|int %}
|
||
|
|
{% set pressure = 'bdpressure_check' in printer %}
|
||
|
|
{% set bdw = printer.bdwidth_status.name %}
|
||
|
|
# If bdwidth is not reading (outside a print, early in a print start,
|
||
|
|
# after a Klipper restart) it is switched on for the check, with its
|
||
|
|
# runout response off meanwhile, so an empty lane does not make bdwidth
|
||
|
|
# pause the printer (the check reports it instead). Afterwards the
|
||
|
|
# runout response is restored; bdwidth itself is only switched off
|
||
|
|
# again outside a print, so a print never loses it.
|
||
|
|
{% set bdw_on = cfg.motion_check and not printer.bdwidth_status.reading|default(false) %}
|
||
|
|
{% set bdw_off = bdw_on and printer.print_stats.state not in ["printing", "paused"] %}
|
||
|
|
{% set runout_was = 1 if printer.bdwidth_status.enabled else 0 %}
|
||
|
|
# Without the motion check, bdwidth's own runout response is off during
|
||
|
|
# the purge too, so a bdwidth that does not see the movement cannot
|
||
|
|
# pause the printer here; the pressure check judges the purge.
|
||
|
|
{% set runout_off = bdw_on or not cfg.motion_check %}
|
||
|
|
{% if cfg.mode == "off" %}
|
||
|
|
BLOBIFIER {rawparams}
|
||
|
|
{% else %}
|
||
|
|
M400
|
||
|
|
{% if runout_off %}
|
||
|
|
SET_FILAMENT_SENSOR SENSOR={bdw} ENABLE=0
|
||
|
|
{% endif %}
|
||
|
|
{% if bdw_on %}
|
||
|
|
SET_BDWIDTH NAME={bdw} COMMAND=ENABLE_MOTION
|
||
|
|
G4 P{cfg.bdwidth_warmup_ms}
|
||
|
|
{% endif %}
|
||
|
|
G4 P{wait}
|
||
|
|
_PURGE_CHECK_START
|
||
|
|
{% if pressure %}
|
||
|
|
BDP_CHECK_START
|
||
|
|
{% endif %}
|
||
|
|
BLOBIFIER {rawparams}
|
||
|
|
M400
|
||
|
|
{% if pressure %}
|
||
|
|
BDP_CHECK_STOP
|
||
|
|
{% endif %}
|
||
|
|
G4 P{wait}
|
||
|
|
_PURGE_CHECK_END
|
||
|
|
{% if bdw_off %}
|
||
|
|
SET_BDWIDTH NAME={bdw} COMMAND=DISABLE
|
||
|
|
{% endif %}
|
||
|
|
{% if runout_off %}
|
||
|
|
SET_FILAMENT_SENSOR SENSOR={bdw} ENABLE={runout_was}
|
||
|
|
{% endif %}
|
||
|
|
{% endif %}
|
||
|
|
|
||
|
|
# Separate macros so the status is read when they run, not when
|
||
|
|
# BLOBIFIER_CHECKED is rendered
|
||
|
|
[gcode_macro _PURGE_CHECK_START]
|
||
|
|
gcode:
|
||
|
|
SET_GCODE_VARIABLE MACRO=_PURGE_CHECK_CFG VARIABLE=start_counts VALUE={printer.bdwidth_status.total_move}
|
||
|
|
SET_GCODE_VARIABLE MACRO=_PURGE_CHECK_CFG VARIABLE=start_e VALUE={printer.toolhead.position.e}
|
||
|
|
|
||
|
|
[gcode_macro _PURGE_CHECK_END]
|
||
|
|
gcode:
|
||
|
|
{% set cfg = printer["gcode_macro _PURGE_CHECK_CFG"] %}
|
||
|
|
{% set s = printer.bdwidth_status %}
|
||
|
|
{% set lane = printer.AFC.current_load|default("?", true) %}
|
||
|
|
{% set extruded = printer.toolhead.position.e - cfg.start_e %}
|
||
|
|
{% set failed = [] %}
|
||
|
|
{% if extruded < cfg.min_extrude %}
|
||
|
|
RESPOND MSG="PURGE_CHECK {lane}: only {'%.1f' % extruded} mm extruded, skipped"
|
||
|
|
{% else %}
|
||
|
|
{% set motion_on = cfg.motion_check and s.active != "disable" %}
|
||
|
|
{% if not cfg.motion_check %}
|
||
|
|
{% set motion = "motion check off" %}
|
||
|
|
{% elif not motion_on %}
|
||
|
|
{% set motion = "motion skipped (bdwidth disabled)" %}
|
||
|
|
{% else %}
|
||
|
|
{% set sensed = (s.total_move - cfg.start_counts)|abs / s.linear_motion %}
|
||
|
|
{% set ratio = sensed / extruded %}
|
||
|
|
{% set motion = "motion %.1f/%.1f mm ratio %.2f, width %.2f" % (sensed, extruded, ratio, s.diameter) %}
|
||
|
|
{% if ratio < cfg.min_ratio %}
|
||
|
|
{% if s.total_move == 0 and s.diameter == 0 %}
|
||
|
|
{% set _ = failed.append("no data from bdwidth since Klipper start (sensor connected?)") %}
|
||
|
|
{% else %}
|
||
|
|
{% set _ = failed.append("filament not moving past bdwidth") %}
|
||
|
|
{% endif %}
|
||
|
|
{% endif %}
|
||
|
|
{% endif %}
|
||
|
|
{% if 'bdpressure_check' in printer and printer.bdpressure_check.available %}
|
||
|
|
{% set p = printer.bdpressure_check %}
|
||
|
|
{% set press = "pressure longest %d ms, total %d ms, peak %d" % (p.longest_ms, p.above_ms, p.peak) %}
|
||
|
|
{% if p.longest_ms < cfg.pressure_min_ms %}
|
||
|
|
{% set _ = failed.append("no sustained nozzle pressure") %}
|
||
|
|
{% endif %}
|
||
|
|
{% else %}
|
||
|
|
{% set press = "pressure skipped (no check firmware)" %}
|
||
|
|
{% endif %}
|
||
|
|
{% set checked = motion_on or 'bdpressure_check' in printer and printer.bdpressure_check.available %}
|
||
|
|
{% set verdict = 'FAIL: ' ~ failed|join(', ') if failed else ('OK' if checked else 'NOTHING CHECKED') %}
|
||
|
|
RESPOND MSG="PURGE_CHECK {lane}: {motion}; {press} -> {verdict}"
|
||
|
|
{% if failed and cfg.mode == "enforce" %}
|
||
|
|
RESPOND TYPE=error MSG="PURGE_CHECK: {lane} {failed|join(', ')} - check extruder and lane"
|
||
|
|
PAUSE
|
||
|
|
{% endif %}
|
||
|
|
{% endif %}
|