- Split the macro files into folders by topic (print, heating, afc, pressure_advance, spoolman, leds, sensors); klipper-macros.cfg is the one file printer.cfg includes. Macros moved unchanged; the effective config is identical apart from the paths of the PA shell scripts. - Add the modified Blobifier (Turtleblobifier for AFC) and define [save_variables] once in save_variables.cfg instead of in both blobifier.cfg and the PA macros (same file, bd_pa_variables.cfg). - PRINT_WARMUP: heat to the loaded lane's temperature before the first tool change. AFC skips heating when the loaded lane's tool number is not in the print file's temperature list, and the unload then failed below min_extrude_temp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
156 lines
7.4 KiB
INI
156 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 %}
|