Group macros by topic, add Blobifier, fix first tool change

- 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>
This commit is contained in:
mangavalkandClaude Opus 5.5 committed 2026-10-10 14:24:37 +02:00
1 parent 6dbb4ca3fb
commit eaf9c82617
27 files changed
+1360 -334

No files matched your search

+55 -27
View File
@@ -8,22 +8,42 @@ Installs with one script and updates through Moonraker's update manager.
## Contents ## Contents
### Macros (`macros/`, included through `klipper-macros.cfg`) ### Macros (`macros/`)
`printer.cfg` includes only `macros/klipper-macros.cfg`; that file includes
everything below, grouped by topic. Comment out what you do not use there.
| File | Macros | Needs | | File | Macros | Needs |
|---|---|---| |---|---|---|
| `macros.cfg` | `PRINT_WARMUP`, `PRINT_START`, `PRINT_END`, `SOAK_MY_BED`, `[idle_timeout]` | Beacon, AFC, Blobifier, `HEAT_SOAK`, iHeater, bdwidth, bd_pressure PA macros, soak-my-bed | | `save_variables.cfg` | the one `[save_variables]` for all macros (file `bd_pa_variables.cfg` in the config folder) | — |
| `afc_macros.cfg` | `AFC_XY_SAFETY_CHECK`, `_AFC_STORE_HOME_REFERENCE`, `AFC_XY_RESUME`, `LANE_FEED_UNTIL_HUB_OPEN`, `LANE_FEED_ABORT`, `HOME`, `SET_ACTIVE_SPOOL`, `CLEAR_ACTIVE_SPOOL` | AFC, `extras/xy_drift.py` (CoreXY) | | **blobifier/** | | |
| `blobifier.cfg` | `BLOBIFIER`, `BLOBIFIER_CLEAN`, `BLOBIFIER_PARK`, `BLOBIFIER_SHAKE_BUCKET`, ...: purge bucket and nozzle brush for AFC (Turtleblobifier, heavily modified) | Blobifier hardware, AFC |
| `blobifier_hw.cfg` | servo and bucket switch pins | — |
| **print/** | | |
| `print_start_end.cfg` | `PRINT_WARMUP`, `PRINT_START`, `PRINT_END` | Beacon, AFC, Blobifier, `HEAT_SOAK`, iHeater, bdwidth, bd_pressure PA macros |
| `pause_resume.cfg` | `PAUSE`, `RESUME`, `CANCEL_PRINT`, `M600` | — |
| `filament.cfg` | `LOAD_FILAMENT`, `UNLOAD_FILAMENT` | — |
| `homing.cfg` | `HOME` | — |
| `idle_timeout.cfg` | `[idle_timeout]`: heaters, chamber heater and motors off | iHeater macros |
| **heating/** | | |
| `heat_soak.cfg` | `HEAT_SOAK`, `STOP_HEAT_SOAK`, `CANCEL_HEAT_SOAK`, `HEAT_SOAK_RESUME`, `RESUME` | — |
| `soak_my_bed.cfg` | `SOAK_MY_BED` (homes and levels first) | soak-my-bed |
| `bed_fans.cfg` | Bed fans through `SET_HEATER_TEMPERATURE`/`M190`/`M140`/`TURN_OFF_HEATERS` overrides | `[fan_generic BedFans]` |
| `chamber_iheater.cfg` | iHeater MCU, heater and sensors, `M141`, `M191`, `iHEATER_ON`, `iHEATER_OFF` | iHeater chamber heater |
| `filament_drying.cfg` | `START_DRYING`, `STOP_DRYING`, `STATUS_DRYING` | bed fans, chamber heater (optional) |
| **afc/** | | |
| `xy_safety_check.cfg` | `AFC_XY_SAFETY_CHECK`, `_AFC_STORE_HOME_REFERENCE`, `AFC_XY_RESUME`: lost-step check around tool changes | `extras/xy_drift.py` (CoreXY) |
| `lane_tools.cfg` | `LANE_FEED_UNTIL_HUB_OPEN`, `LANE_FEED_ABORT` | AFC |
| `purge_check.cfg` | `BLOBIFIER_CHECKED`: checks every AFC purge with bd_pressure (and optionally bdwidth motion) | Blobifier, AFC, `extras/bdpressure_check.py` + bd_pressure load-check firmware, `extras/bdwidth_status.py` | | `purge_check.cfg` | `BLOBIFIER_CHECKED`: checks every AFC purge with bd_pressure (and optionally bdwidth motion) | Blobifier, AFC, `extras/bdpressure_check.py` + bd_pressure load-check firmware, `extras/bdwidth_status.py` |
| `purge_until_empty.cfg` | `PURGE_UNTIL_EMPTY`: purges a snapped filament out until there is no more nozzle pressure | same as `purge_check.cfg` | | `purge_until_empty.cfg` | `PURGE_UNTIL_EMPTY`: purges a snapped filament out until there is no more nozzle pressure | same as `purge_check.cfg` |
| `bd_pa_afc_spoolman.cfg` + `bd_pa_*.sh` | `LANE_CALIBRATE_PA`, `PA_CALIBRATE_ALL_LANES`, `LANE_RECAL_PA`, `SET_SPOOL_ID`, `PA_STATUS`: pressure advance per lane/spool with bd_pressure, cached locally and in Spoolman | bd_pressure, AFC, Spoolman, `gcode_shell_command` | | **pressure_advance/** | | |
| `motion.cfg` | PIR motion sensor (`[gcode_button am312]`) switching the case light | motion sensor on a pin, `[output_pin caselight]` | | `bd_pa_spoolman.cfg` + `bd_pa_*.sh` | `LANE_CALIBRATE_PA`, `PA_CALIBRATE_ALL_LANES`, `LANE_RECAL_PA`, `SET_SPOOL_ID`, `PA_STATUS`: pressure advance per lane/spool, cached locally and in Spoolman | bd_pressure, AFC, Spoolman, `gcode_shell_command` |
| `drying.cfg` | `START_DRYING`, `STOP_DRYING`, `STATUS_DRYING`: dry filament on the heated bed | bed fans macros, chamber heater (optional) | | **spoolman/** | | |
| `bedfans.cfg` | Bed fan control through `SET_HEATER_TEMPERATURE`/`M190`/`M140` overrides | `[fan_generic BedFans]` | | `active_spool.cfg` | `SET_ACTIVE_SPOOL`, `CLEAR_ACTIVE_SPOOL` | Spoolman in Moonraker |
| `heatsoak.cfg` | `HEAT_SOAK`, `STOP_HEAT_SOAK`, `CANCEL_HEAT_SOAK`, `HEAT_SOAK_RESUME`, `RESUME` | — | | **leds/** | | |
| `iHeater.cfg` | iHeater MCU, heater, sensors, `M141`, `M191`, `iHEATER_ON`, `iHEATER_OFF` | iHeater chamber heater | | `stealthburner_leds.cfg` | Stealthburner LED effects and `_status_*` macros | `led_effect` |
| `stealthburner_led_effects_barf.cfg` | Stealthburner LED status macros (`_status_*`) | `led_effect`, `[neopixel sb_leds]` | | **sensors/** | | |
| `macros_klipperscreen.cfg` | `PAUSE`, `RESUME`, `CANCEL_PRINT`, `LOAD_FILAMENT`, `UNLOAD_FILAMENT`, `M600` | — | | `motion_sensor.cfg` | PIR motion sensor switching the case light | sensor on a pin, `[output_pin caselight]` |
### Klipper modules (`extras/`) ### Klipper modules (`extras/`)
@@ -88,14 +108,20 @@ original printer: `Macros/*.cfg` and `bd_pa_afc_spoolman.cfg`), remove those
includes when adding `klipper-macros.cfg`, otherwise the macros are defined includes when adding `klipper-macros.cfg`, otherwise the macros are defined
twice and the old copy may win: twice and the old copy may win:
- remove `[include bd_pa_afc_spoolman.cfg]` from `printer.cfg`, - remove `[include bd_pa_afc_spoolman.cfg]` and
`[include ./blobifier/blobifier.cfg]` from `printer.cfg`,
- replace `[include ./Macros/macros.cfg]` with - replace `[include ./Macros/macros.cfg]` with
`[include klipper-macros/klipper-macros.cfg]`, `[include klipper-macros/klipper-macros.cfg]`,
- keep including what is not in this repo yourself, for example - keep including what is not in this repo yourself, for example
`[include Macros/timelapse.cfg]` and `[include Macros/TEST_SPEED.cfg]`. `[include Macros/timelapse.cfg]` and `[include Macros/TEST_SPEED.cfg]`.
`bd_pa_variables.cfg` (saved PA values) stays where it is, in the config `bd_pa_variables.cfg` (saved PA values and the Blobifier blob count) stays
folder; it is data, not part of the repo. where it is, in the config folder; it is data, not part of the repo. Before,
both `blobifier.cfg` and `bd_pa_afc_spoolman.cfg` had their own
`[save_variables]`; Klipper merged them and the last one won, so the blob
count was already stored in `bd_pa_variables.cfg` and
`blobifier/blob_vars.cfg` was no longer used. Now it is defined once, in
`save_variables.cfg`.
## Adapting to another printer ## Adapting to another printer
@@ -103,14 +129,16 @@ These are the settings of one printer. Before using a file, check:
- **Names:** `fila_width_0` (bdwidth), `bd_pa` (bd_pressure), `sb_leds`, - **Names:** `fila_width_0` (bdwidth), `bd_pa` (bd_pressure), `sb_leds`,
`caselight`, `BedFans`, `iHeater_H`, lane names `lane1..lane5`. `caselight`, `BedFans`, `iHeater_H`, lane names `lane1..lane5`.
- **Pins and serial IDs:** `motion.cfg` (`PC0`), `iHeater.cfg` (serial ID). - **Pins and serial IDs:** `blobifier/blobifier_hw.cfg` (`PC1`, `PC3`),
- **Positions:** the bed centre `X175 Y175` (350 mm bed) in `HOME` `sensors/motion_sensor.cfg` (`PC0`),
(`afc_macros.cfg`) and in `PRINT_WARMUP`/`PRINT_START` (`macros.cfg`). `heating/chamber_iheater.cfg` (serial ID).
- **Positions:** the bed centre `X175 Y175` (350 mm bed) in `print/homing.cfg`
and `print/print_start_end.cfg`.
`AFC_XY_SAFETY_CHECK` uses the axis limits from your config. `AFC_XY_SAFETY_CHECK` uses the axis limits from your config.
- **Settings at the top of a file** (`variable_...`): `purge_check.cfg` - **Settings at the top of a file** (`variable_...`): `afc/purge_check.cfg`
(`mode: "enforce"`, `motion_check: False` because this printer's bdwidth (`mode: "enforce"`, `motion_check: False` because this printer's bdwidth
motion reading is unreliable), `bd_pa_afc_spoolman.cfg` (`spoolman_url`), motion reading is unreliable), `pressure_advance/bd_pa_spoolman.cfg`
`bedfans.cfg`, `drying.cfg`. (`spoolman_url`), `heating/bed_fans.cfg`, `heating/filament_drying.cfg`.
- `xy_drift.py` is for CoreXY only. - `xy_drift.py` is for CoreXY only.
Comment out files you do not need in `klipper-macros.cfg`. Comment out files you do not need in `klipper-macros.cfg`.
@@ -132,17 +160,17 @@ original licenses apply to those parts:
| File | Based on | | File | Based on |
|---|---| |---|---|
| `stealthburner_led_effects_barf.cfg` | [tanaes/whopping_Voron_mods](https://github.com/tanaes/whopping_Voron_mods) (Rainbow Barf logo LEDs) | | `blobifier/` | [Turtleblobifier](https://github.com/ImSundee/Turtleblobifier) (AFC version of [Dendrowen/Blobifier](https://github.com/Dendrowen/Blobifier)) |
| `bedfans.cfg` | Ellis' bed fan macros ([ellis3dp.com](https://ellis3dp.com/Print-Tuning-Guide/)) | | `leds/stealthburner_leds.cfg` | [tanaes/whopping_Voron_mods](https://github.com/tanaes/whopping_Voron_mods) (Rainbow Barf logo LEDs) |
| `heatsoak.cfg` | community `HEAT_SOAK` macro | | `heating/bed_fans.cfg` | Ellis' bed fan macros ([ellis3dp.com](https://ellis3dp.com/Print-Tuning-Guide/)) |
| `iHeater.cfg` | iHeater vendor configuration | | `heating/heat_soak.cfg` | community `HEAT_SOAK` macro |
| `drying.cfg` | community filament drying macro | | `heating/chamber_iheater.cfg` | iHeater vendor configuration |
| `macros_klipperscreen.cfg` | [KlipperScreen recommended macros](https://klipperscreen.readthedocs.io/en/latest/macros/#recommended) | | `heating/filament_drying.cfg` | community filament drying macro |
| `print/pause_resume.cfg`, `print/filament.cfg` | [KlipperScreen recommended macros](https://klipperscreen.readthedocs.io/en/latest/macros/#recommended) |
| `scripts/` | [Voron docs: automating MCU updates](https://docs.vorondesign.com/community/howto/drachenkatze/automating_klipper_mcu_updates.html), [Esoterical's CANBus guide](https://canbus.esoterical.online/) | | `scripts/` | [Voron docs: automating MCU updates](https://docs.vorondesign.com/community/howto/drachenkatze/automating_klipper_mcu_updates.html), [Esoterical's CANBus guide](https://canbus.esoterical.online/) |
Uses: [Klipper](https://github.com/Klipper3d/klipper), Uses: [Klipper](https://github.com/Klipper3d/klipper),
[AFC-Klipper-Add-On](https://github.com/ArmoredTurtle/AFC-Klipper-Add-On), [AFC-Klipper-Add-On](https://github.com/ArmoredTurtle/AFC-Klipper-Add-On),
[Blobifier](https://github.com/Dendrowen/Blobifier),
[bd_pressure](https://github.com/markniu/bd_pressure), [bd_pressure](https://github.com/markniu/bd_pressure),
[bdwidth](https://github.com/markniu/bdwidth), [bdwidth](https://github.com/markniu/bdwidth),
[klipper-led_effect](https://github.com/julianschill/klipper-led_effect), [klipper-led_effect](https://github.com/julianschill/klipper-led_effect),
+2 -1
View File
@@ -69,7 +69,8 @@ ln -sfn "$REPO_DIR/macros" "$LINK_NAME"
echo "linked $LINK_NAME" echo "linked $LINK_NAME"
# 3. Scripts # 3. Scripts
chmod +x "$REPO_DIR"/macros/*.sh "$REPO_DIR"/scripts/*.sh "$REPO_DIR"/install.sh find "$REPO_DIR/macros" "$REPO_DIR/scripts" -name "*.sh" -exec chmod +x {} +
chmod +x "$REPO_DIR/install.sh"
# 4. Moonraker update manager # 4. Moonraker update manager
if [[ -f $MOONRAKER_CONF ]] && ! grep -q '^\[update_manager klipper-macros\]' "$MOONRAKER_CONF"; then if [[ -f $MOONRAKER_CONF ]] && ! grep -q '^\[update_manager klipper-macros\]' "$MOONRAKER_CONF"; then
+100
View File
@@ -0,0 +1,100 @@
# AFC lane tools: LANE_FEED_UNTIL_HUB_OPEN, LANE_FEED_ABORT
#####################################################################
## unloading help
#####################################################################
[gcode_macro LANE_FEED_UNTIL_HUB_OPEN]
variable_lane: 1
variable_step: -50
variable_max_dist: 2000
variable_moved: 0
variable_active: 0
gcode:
{% set lane = params.LANE|default(1)|int %}
{% set step = params.STEP|default(-50)|float %}
{% set max_dist = params.MAX_DIST|default(2000)|float %}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=lane VALUE={lane}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=step VALUE={step}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=max_dist VALUE={max_dist}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=moved VALUE=0
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=1
RESPOND PREFIX="info" MSG="START lane={lane} step={step} max={max_dist}"
UPDATE_DELAYED_GCODE ID=_lane_feed_loop DURATION=0.05
[delayed_gcode _lane_feed_loop]
gcode:
{% set m = printer["gcode_macro LANE_FEED_UNTIL_HUB_OPEN"] %}
{% if m.active == 1 %}
LANE_MOVE LANE=lane{m.lane} DISTANCE={m.step}
{% set new_moved = m.moved + m.step %}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=moved VALUE={new_moved}
RESPOND PREFIX="info" MSG="MOVE lane={m.lane} step={m.step} moved={new_moved}"
QUERY_ENDSTOPS
UPDATE_DELAYED_GCODE ID=_lane_eval DURATION=0.03
{% else %}
RESPOND PREFIX="info" MSG="feed_loop inactive"
{% endif %}
[delayed_gcode _lane_eval]
gcode:
{% set m = printer["gcode_macro LANE_FEED_UNTIL_HUB_OPEN"] %}
{% if m.active == 1 %}
{% set hub = printer.query_endstops.last_query.get("hub", "unknown") %}
# RESPOND PREFIX="info" MSG="QUERY hub={hub} raw={printer.query_endstops.last_query.get('hub', 'MISSING')}"
# RESPOND PREFIX="info" MSG="last_query: {printer.query_endstops.last_query}"
{% if hub == "open" or hub == 0 %}
RESPOND PREFIX="info" MSG="HUB TRIGGERED → STOP"
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=0
LANE_MOVE LANE=lane{m.lane} DISTANCE=-100
{% elif m.moved|abs >= m.max_dist %}
RESPOND PREFIX="warning" MSG="MAX DIST STOP reached={m.moved}"
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=0
{% else %}
RESPOND PREFIX="info" MSG="CONTINUE"
UPDATE_DELAYED_GCODE ID=_lane_feed_loop DURATION=0.03
{% endif %}
{% else %}
RESPOND PREFIX="info" MSG="eval inactive"
{% endif %}
[gcode_macro LANE_FEED_ABORT]
gcode:
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=0
UPDATE_DELAYED_GCODE ID=_lane_feed_loop DURATION=0
UPDATE_DELAYED_GCODE ID=_lane_eval DURATION=0
RESPOND PREFIX="warning" MSG="ABORTED"
# [gcode_macro TEST_AMS_STRESS]
# gcode:
# {% for i in range(500) %}
# T0 ; Load tool 0
# G4 P5000 ; Wait 5s
# T1 ; Unload
# G4 P3000 ; Wait 3s
# {% endfor %}
File renamed without changes.
File renamed without changes.
+70
View File
@@ -0,0 +1,70 @@
# AFC_XY_SAFETY_CHECK: lost-step check around tool changes (needs extras/xy_drift.py)
#####################################################################
## XY lost-step check (needs xy_drift.py + [xy_drift])
#####################################################################
# Homing resets the toolhead position, so the position after G28 cannot
# show lost steps. [xy_drift] compares the stepper step counts at the X and
# Y endstop triggers instead: every lost step shows up as drift.
# _AFC_STORE_HOME_REFERENCE (PRINT_START) stores the reference, every
# AFC_XY_SAFETY_CHECK compares against it and then stores a new reference,
# so each check reports the drift since the previous one.
[xy_drift]
[gcode_macro _AFC_STORE_HOME_REFERENCE]
gcode:
G28 X Y
M400
XY_DRIFT_STORE
[gcode_macro AFC_XY_SAFETY_CHECK]
description: Re-home XY and report steps lost since the last check
variable_allowed_mm: 0.1 # one motor skipping one cycle (0.4 mm) shows as 0.2 mm in X and Y; endstop noise ~0.02
variable_soft_fail: 1 # 1 = PAUSE on drift, 0 = M112
gcode:
{% set th = printer.toolhead %}
M117 AFC XY check...
SAVE_GCODE_STATE NAME=_AFC_XY_CHECK
G90
G1 Z{[th.position.z + 10, th.axis_maximum.z]|min} F3000
G28 X Y
M400
_AFC_CHECK_CAPTURE
RESTORE_GCODE_STATE NAME=_AFC_XY_CHECK
[gcode_macro _AFC_CHECK_CAPTURE]
gcode:
{% set d = printer.xy_drift %}
{% set cfg = printer["gcode_macro AFC_XY_SAFETY_CHECK"] %}
{% set th = printer.toolhead %}
{% set lim = cfg.allowed_mm|float %}
{% set drift = d.ref_set and (d.x|abs > lim or d.y|abs > lim) %}
{% if not d.ref_set %}
RESPOND PREFIX="AFC" MSG="XY check: no reference yet (Klipper restarted?), storing one now"
{% else %}
RESPOND PREFIX="AFC" MSG="XY drift since last check: X={'%.3f' % d.x} Y={'%.3f' % d.y} mm (limit {lim})"
{% endif %}
# New reference from this homing, so the next check reports only new drift
XY_DRIFT_STORE
{% if not drift %}
{% if d.ref_set %}
RESPOND PREFIX="AFC" MSG="Position OK"
{% endif %}
G1 X{th.axis_maximum.x - 10} Y{th.axis_maximum.y - 10} F5000
{% elif cfg.soft_fail|int == 1 %}
RESPOND TYPE=error MSG="AFC: XY drift detected! X={'%.3f' % d.x} Y={'%.3f' % d.y} mm. Axes are re-homed, print PAUSED. Run AFC_XY_RESUME to continue, or CANCEL_PRINT."
M117 AFC: XY drift! See console. Paused.
PAUSE
{% else %}
RESPOND TYPE=error MSG="AFC: XY drift X={'%.3f' % d.x} Y={'%.3f' % d.y} mm -> M112"
M112
{% endif %}
[gcode_macro AFC_XY_RESUME]
description: Acknowledge XY drift warning and resume print
gcode:
RESPOND PREFIX="AFC" MSG="User acknowledged drift, resuming."
# Axes were re-homed by the check, so AFC's resume returns to the
# correct print position.
RESUME
-193
View File
@@ -1,193 +0,0 @@
#####################################################################
## XY lost-step check (needs xy_drift.py + [xy_drift])
#####################################################################
# Homing resets the toolhead position, so the position after G28 cannot
# show lost steps. [xy_drift] compares the stepper step counts at the X and
# Y endstop triggers instead: every lost step shows up as drift.
# _AFC_STORE_HOME_REFERENCE (PRINT_START) stores the reference, every
# AFC_XY_SAFETY_CHECK compares against it and then stores a new reference,
# so each check reports the drift since the previous one.
[xy_drift]
[gcode_macro _AFC_STORE_HOME_REFERENCE]
gcode:
G28 X Y
M400
XY_DRIFT_STORE
[gcode_macro AFC_XY_SAFETY_CHECK]
description: Re-home XY and report steps lost since the last check
variable_allowed_mm: 0.1 # one motor skipping one cycle (0.4 mm) shows as 0.2 mm in X and Y; endstop noise ~0.02
variable_soft_fail: 1 # 1 = PAUSE on drift, 0 = M112
gcode:
{% set th = printer.toolhead %}
M117 AFC XY check...
SAVE_GCODE_STATE NAME=_AFC_XY_CHECK
G90
G1 Z{[th.position.z + 10, th.axis_maximum.z]|min} F3000
G28 X Y
M400
_AFC_CHECK_CAPTURE
RESTORE_GCODE_STATE NAME=_AFC_XY_CHECK
[gcode_macro _AFC_CHECK_CAPTURE]
gcode:
{% set d = printer.xy_drift %}
{% set cfg = printer["gcode_macro AFC_XY_SAFETY_CHECK"] %}
{% set th = printer.toolhead %}
{% set lim = cfg.allowed_mm|float %}
{% set drift = d.ref_set and (d.x|abs > lim or d.y|abs > lim) %}
{% if not d.ref_set %}
RESPOND PREFIX="AFC" MSG="XY check: no reference yet (Klipper restarted?), storing one now"
{% else %}
RESPOND PREFIX="AFC" MSG="XY drift since last check: X={'%.3f' % d.x} Y={'%.3f' % d.y} mm (limit {lim})"
{% endif %}
# New reference from this homing, so the next check reports only new drift
XY_DRIFT_STORE
{% if not drift %}
{% if d.ref_set %}
RESPOND PREFIX="AFC" MSG="Position OK"
{% endif %}
G1 X{th.axis_maximum.x - 10} Y{th.axis_maximum.y - 10} F5000
{% elif cfg.soft_fail|int == 1 %}
RESPOND TYPE=error MSG="AFC: XY drift detected! X={'%.3f' % d.x} Y={'%.3f' % d.y} mm. Axes are re-homed, print PAUSED. Run AFC_XY_RESUME to continue, or CANCEL_PRINT."
M117 AFC: XY drift! See console. Paused.
PAUSE
{% else %}
RESPOND TYPE=error MSG="AFC: XY drift X={'%.3f' % d.x} Y={'%.3f' % d.y} mm -> M112"
M112
{% endif %}
[gcode_macro AFC_XY_RESUME]
description: Acknowledge XY drift warning and resume print
gcode:
RESPOND PREFIX="AFC" MSG="User acknowledged drift, resuming."
# Axes were re-homed by the check, so AFC's resume returns to the
# correct print position.
RESUME
#####################################################################
## unloading help
#####################################################################
[gcode_macro LANE_FEED_UNTIL_HUB_OPEN]
variable_lane: 1
variable_step: -50
variable_max_dist: 2000
variable_moved: 0
variable_active: 0
gcode:
{% set lane = params.LANE|default(1)|int %}
{% set step = params.STEP|default(-50)|float %}
{% set max_dist = params.MAX_DIST|default(2000)|float %}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=lane VALUE={lane}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=step VALUE={step}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=max_dist VALUE={max_dist}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=moved VALUE=0
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=1
RESPOND PREFIX="info" MSG="START lane={lane} step={step} max={max_dist}"
UPDATE_DELAYED_GCODE ID=_lane_feed_loop DURATION=0.05
[delayed_gcode _lane_feed_loop]
gcode:
{% set m = printer["gcode_macro LANE_FEED_UNTIL_HUB_OPEN"] %}
{% if m.active == 1 %}
LANE_MOVE LANE=lane{m.lane} DISTANCE={m.step}
{% set new_moved = m.moved + m.step %}
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=moved VALUE={new_moved}
RESPOND PREFIX="info" MSG="MOVE lane={m.lane} step={m.step} moved={new_moved}"
QUERY_ENDSTOPS
UPDATE_DELAYED_GCODE ID=_lane_eval DURATION=0.03
{% else %}
RESPOND PREFIX="info" MSG="feed_loop inactive"
{% endif %}
[delayed_gcode _lane_eval]
gcode:
{% set m = printer["gcode_macro LANE_FEED_UNTIL_HUB_OPEN"] %}
{% if m.active == 1 %}
{% set hub = printer.query_endstops.last_query.get("hub", "unknown") %}
# RESPOND PREFIX="info" MSG="QUERY hub={hub} raw={printer.query_endstops.last_query.get('hub', 'MISSING')}"
# RESPOND PREFIX="info" MSG="last_query: {printer.query_endstops.last_query}"
{% if hub == "open" or hub == 0 %}
RESPOND PREFIX="info" MSG="HUB TRIGGERED → STOP"
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=0
LANE_MOVE LANE=lane{m.lane} DISTANCE=-100
{% elif m.moved|abs >= m.max_dist %}
RESPOND PREFIX="warning" MSG="MAX DIST STOP reached={m.moved}"
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=0
{% else %}
RESPOND PREFIX="info" MSG="CONTINUE"
UPDATE_DELAYED_GCODE ID=_lane_feed_loop DURATION=0.03
{% endif %}
{% else %}
RESPOND PREFIX="info" MSG="eval inactive"
{% endif %}
[gcode_macro LANE_FEED_ABORT]
gcode:
SET_GCODE_VARIABLE MACRO=LANE_FEED_UNTIL_HUB_OPEN VARIABLE=active VALUE=0
UPDATE_DELAYED_GCODE ID=_lane_feed_loop DURATION=0
UPDATE_DELAYED_GCODE ID=_lane_eval DURATION=0
RESPOND PREFIX="warning" MSG="ABORTED"
[gcode_macro HOME]
gcode:
G90
G4 P2000
G28 X0 Y0 Z0
G1 X175 Y175 Z10 F1200
[gcode_macro SET_ACTIVE_SPOOL]
gcode:
{% if params.ID %}
{% set id = params.ID|int %}
{action_call_remote_method(
"spoolman_set_active_spool",
spool_id=id
)}
{% else %}
{action_respond_info("Parameter 'ID' is required")}
{% endif %}
[gcode_macro CLEAR_ACTIVE_SPOOL]
gcode:
{action_call_remote_method(
"spoolman_set_active_spool",
spool_id=None
)}
# [gcode_macro TEST_AMS_STRESS]
# gcode:
# {% for i in range(500) %}
# T0 ; Load tool 0
# G4 P5000 ; Wait 5s
# T1 ; Unload
# G4 P3000 ; Wait 3s
# {% endfor %}
+919
View File
@@ -0,0 +1,919 @@
# Include servo hardware definition separately to allow for automatic upgrade
[include ./blobifier_hw.cfg]
##########################################################################################
# Sample config to be used in conjunction with Blobifier Purge Tray, Bucket & Nozzle
# Scrubber mod. Created by Dendrowen (dendrowen on Discord). The Macro is based on a
# version, and Nozzle Scrubber is made by Hernsl (hernsl#8860 on Discord). The device is
# designed around a Voron V2.4 300mm, but should work for 250mm and 350mm too. This
# version only supports the assembly on the rear-left of the bed. If you decide to change
# that, please consider contributing to the project by creating a pull request with the
# needed changes.
# IMPORTANT: The rear-left part of your bed becomes unusable by this mod because the
# toolhead needs to lower down to 0. Be sure not to use the left-rear 130x35mm.
# The goals of this combination of devices is to dispose of purged filament during a
# multicolored print without the need of a purge block and without the flurries of
# filament poops consuming your entire 3D printer room. The Blobifier achieves that by
# purging onto a retractable tray which causes the filament to turn into a tiny blob
# rather then a large spiral. This keeps the waste relativly small. The bucket should be
# able to account for up to 200 filament swaps (for the 300mm V2).
# The Blobifier uses some room at the back-left side of your printer, depending on your
# printer limits and positions. (usually max_pos.y - toolhead_y and brush_start +
# brush_width + toolhead_x). If you do place objects within this region, Blobifier will
# skip purging automatically. It does this by extending the EXCLUDE_OBJECT_* macro's, so
# make sure you have exclude objects enabled in your slicer.
# If your using Blobifier in conjunction with the filament cutter on the stealthburner
# toolhead, you can place the pin at max_pos.y - 7 (e.g., max pos y is 307, place it at
# 300). The pin will then poke through the cavity in your toolhead. (Be careful with
# manually moving the toolhead. I have broken many filament cutter pins)
# It is advised to use the start_gcode from Happy Hare. Then you will be able to fully
# and efficiently use this mod. Check the Happy Hare document at gcode_preprocessing.md
# in the Happy Hare github for more details.
###################################### DISCLAIMER ########################################
# You, and you alone, are responsible for the correct execution of these macros and
# gcodes. Any damage that may occur to your machine remains your responsibility.
# Especially when executing this macro for the first few times, keep an eye on your
# printer and the
# emergency stop.
##########################################################################################
##########################################################################################
# Main macro. Usually you should only need to call this one or place it in the Happy Hare
# _MMU_POST_LOAD macro using the variable_user_post_load_extension:
#
# variable_user_post_load_extension : `BLOBIFIER`
#
# Notes on parameters:
# PURGE_LENGTH=[float] (optional) The length to purge. If ommited (default) it will check
# the purge_volumes matrix or variable_purge_length. This can be used
# to override and for testing.
#
[gcode_macro BLOBIFIER]
# These parameters define your filament purging.
# Note that the control of retraction is set in 'mmu_macro_vars.cfg' which can be increased
# if you experience excessive oozing.
# variable_purge_spd: 250 #300 # Speed, in mm/min, of the purge.
variable_purge_spd: 150 # Speed, in mm/min, of the purge.
variable_purge_temp_min: 200 # Minimum nozzle purge temperature.
variable_toolhead_x: 70 # From the nozzle to the left of your toolhead
variable_toolhead_y: 50 # From the nozzle to the front of your toolhead
variable_retract_before_park: 3.0 # amount in mm. 0 to disable
variable_retract_speed: 2000 # mm/m
##custom
variable_retracted_length: 0.4 # Amount of current retraction
# This macro will prevent a gcode movement downward while 'blobbing' if there might be a
# print in the way (e.g. You print something large and need the area where Blobifier does
# its... 'business'). However, at low heights (or at print start) this might not be
# desireable. You can force a 'safe descend' with this variable. Keep in mind that the
# height of the print is an estimation based on previous heights and certain assumptions
# so it might be wise to include a safety margin of 0.2mm
variable_force_safe_descend_height_until: 2.0
# Adjust this so that your nozzle scrubs within the brush. Be careful not to go too low!
# Start out with a high value (like, 6) and go
# down from there.
variable_brush_top: -0.5
# These parameters define your scrubbing, travel speeds, safe z clearance and how many
# times you want to wipe. Update as necessary.
variable_clearance_z: 5 # When traveling, but not cleaning, the
# clearance along the z-axis between nozzle
# and brush.
variable_wipe_qty: 4 # Number of complete (A complete wipe: left,
# right, left OR right, left, right) wipes.
variable_travel_spd_xy: 25000 # Travel (not cleaning) speed along x and
# y-axis in mm/min.
variable_travel_spd_z: 2000 # Travel (not cleaning) speed along z axis
# in mm/min.
variable_wipe_spd_xy: 30000 # Nozzle wipe speed in mm/min.
# The acceleration to use when using the brush action. If set to 0, it uses the already
# set acceleration. However, in some cases this is not desirable for the last motion
# could be an 'outer contour' acceleration which is usually lower.
variable_brush_accel: 10000
# Blobifier sends the toolhead to the maximum y position during purge oeprations and
# minimum x position during shake operations. This can cause issues when skew correction
# is set up. If you have skew correction enabled and get 'move out of range' errors
# regarding blobifier while skew is enabled, try increasing this value. Keep the
# adjustments small though! (0.1mm - 0.5mm) and increase it until it works.
variable_skew_correction: 0.1
# These parameters define the size of the brush. Update as necessary. A visual reference
# is provided below.
#
# ← brush_width →
# _________________
# | | ↑ Y position is acquired from your
# brush_start (x) | | brush_depth stepper_y position_max. Adjust
# |_________________| ↓ your brush physically in Y so
# (y) that the nozzle scrubs within the
# brush_front brush.
# __________________________________________________________
# PRINTER FRONT
#
#
# Start location of the brush. Defaults for 250, 300 and 350mm are provided below.
# Uncomment as necessary
#variable_brush_start: 34 # For 250mm build
#variable_brush_start: 52 # For 300mm build
# variable_brush_start: 84 # for 350mm build
variable_brush_start: 48 # for 350mm build
# width of the brush
variable_brush_width: 45
# Location of where to purge. The tray is 15mm in length, so if you assemble it against
# the side of the bed (default), 10mm is a good location
variable_purge_x: 2
# Height of the tray. If it's below your bed, give this a negative number equal to the
# difference. If it's above your bed, give it a positive number. You can find this number
# by homing, optional QGL or equivalent, and moving you toolhead above the tray, and
# lowering it with the paper method.
variable_tray_top: 0
# Servo angles for tray positions
variable_tray_angle_out: 0
variable_tray_angle_in: 180
# ========================================================================================
# ==================== BLOB TUNING =======================================================
# ========================================================================================
# The following section defines how the purging sequence is executed. This is where you
# tune the purging to create pretty blobs. Refer to the visual reference for a better
# understanding. The visual is populated with example values. Below are some guides
# provided to help with tuning.
#
# \_____________/
# |___|___|
# \_/ ______________ < End of third iteration.
# / \ HEIGHT: 3 x iteration_z_raise - (2 + 1) x iteration_z_change (3 x 5 - 2 x 1.2 = 11.4)
# | | EXTRUDED: 3 x max_iteration_length (3 x 50 = 150)
# / \ ______________ < End of second iteration.
# | \ HEIGHT: 2 x iteration_z_raise - 1 x iteration_z_change (2 x 5 - 1 x 1.2 = 8.8)
# / | EXTRUDED: 2 x max_iteration_length (2 x 50 = 100)
# | \ ______________ < End of first iteration.
# / \ HEIGHT: 1 x iteration_z_raise (1 x 5 = 5)
# | | EXTRUDED: 1 x max_iteration_length (1 x 50 = 50)
#___________ \ / ______________ < Start height of the nozzle. default value: 1.5mm
# |_______________\___________/_ ______________ < Bottom of the tray
# |_____________________________|
# |
#
########################### BLOB TUNING ##############################
# +-------------------------------------+----------------------------+
# | Filament sticks to the nozzle at | Incr. purge start |
# | initial purge (first few mm) | |
# +-------------------------------------+----------------------------+
# | Filament scoots out from under | Incr. temperature |
# | the nozzle at the first iteration | Decr. z_raise |
# | | Incr. purge_length_maximum |
# +-------------------------------------+----------------------------+
# | Filament scoots out from under the | Decr. purge_spd |
# | the nozzle at later iterations | Decr. z_raise_exp |
# | | Decr. z_raise |
# | | Incr. purge_length_maximum |
# +-------------------------------------+----------------------------+
# | Filament sticks to the nozzle at | Incr. z_raise_exp |
# | later iterations | (Not above 1) |
# +-------------------------------------+----------------------------+
#
# The height to raise the nozzle above the tray before purging. This allows any built up
# pressure to escape before the purge.
variable_purge_start: -0.8 #0.2
# The amount to raise Z
variable_z_raise: 12 #12
# As the nozzle gets higher and the blob wider, the Z raise needs to be reduced, this
# follows the following formula:
# (extruded_amount/max_purge_length)^z_raise_exp * z_raise
# 1 is linear, below 1 will cause z to raise less quickly over time, above 1 will make it
# raise quicker over time. 0.85 is a good starting point and you should not have it above 1
variable_z_raise_exp: 0.85 #0.85
# Lift the nozzle slightly after creating the blob te release pressure on the tray.
variable_eject_hop: 6.0
# Dwell time (ms) after purging and before cleaning to relieve pressure from the nozzle.
variable_pressure_release_time: 3000 #1000
# Set the part cooling fan speed. Disabling can help prevent the nozzle from cooling down
# and stimulate flow, Enabling it can prevent blobs from sticking together. Values range
# from 0 .. 1, or -1 if you don't want it changed.
#variable_part_cooling_fan: -1 # Leave it unchanged
#variable_part_cooling_fan: 0 # Disable the fan
variable_part_cooling_fan: 1 # Run it at full speed
# ========================================================================================
# ==================== PURGE LENGTH TUNING ===============================================
# ========================================================================================
# The absolute minimum to purge, even if you don't changed tools. This is to prime the
# nozzle before printing
variable_purge_length_minimum: 35
# The maximum amount of filament (in mm¹) to purge in a single blob. Blobifier will
# automatically purge multiple blobs if the purge amount exeeds this.
variable_purge_length_maximum: 80 #120
# Default purge length to fall back on when neither the tool map purge_volumes or
# parameter PURGE_LENGTH is set.
variable_purge_length: 150
# The slicer values often are a bit too wastefull. Tune it here to get optimal values.
# 0.6 (60%) is a good starting point.
variable_purge_length_modifier: 0.5
# Fixed length of filament to add after the purge volume calculation. Happy Hare already
# shares info on the extra amount of filament to purge based on known residual filament,
# tip cutting fragment and initial retraction setting. However this setting can add a fixed
# amount on top on that if necessary although it is recommended to start with 0 and tune
# slicer purge matrix first.
# When should you alter this value:
# INCREASE: When the dark to light swaps are good, but light to dark aren't.
# DECREASE: When the light to dark swaps are good, but dark to light aren't. Don't
# forget to increase the purge_length_modifier
variable_purge_length_addition: 20 # 30
# ========================================================================================
# ==================== BUCKET ============================================================
# ========================================================================================
# Maximum number of blobs that fit in the bucket. Pauses the print if it exceeds this
# number.
variable_max_blobs: 1300
# Enable the bucket shaker. You need to have the shaker.stl installed
variable_enable_shaker: 1
# The number of back-and-forth motions of one shake
variable_bucket_shakes: 10
# During shaking acceleration can often be higher because you don't neeed to keep print
# quality in mind. Higher acceleration helps better with dispersing the blobs.
variable_shake_accel: 10000
# The frequency at which to shake the bucket. A decimal value ranging from 0 to 1, where 0
# is never, and 1 is every time. This way the shaking occurs more often as the bucket
# fills up. Sensible values range from 0.75 to 0.95
variable_bucket_shake_frequency: 0.95
# Height of the shaker arm. If your hotend hits your tray during shaking, increase.
variable_shaker_arm_z: 4
gcode:
# ======================================================================================
# ==================== RECORD STATE (INCL. FANS, SPEEDS, ETC...) =======================
# ======================================================================================
# General state
SAVE_GCODE_STATE NAME=BLOBIFIER_state
# ======================================================================================
# ==================== CHECK HOMING STATUS =============================================
# ======================================================================================
{% if "xyz" not in printer.toolhead.homed_axes %}
RESPOND MSG="BLOBIFIER: Not homed! Home xyz before blobbing"
{% elif printer.quad_gantry_level and printer.quad_gantry_level.applied == False %}
RESPOND MSG="BLOBIFIER: QGL not applied! run quad_gantry_level before blobbing"
{% else %}
# Part cooling fan
{% if part_cooling_fan >= 0 %}
# Save the part cooling fan speed to be enabled again later
{% set backup_fan_speed = printer.fan.speed %}
# Set part cooling fan speed
M106 S{part_cooling_fan * 255}
{% endif %}
# Set feedrate to 100% for correct speed purging
{% set backup_feedrate = printer.gcode_move.speed_factor %}
M220 S100
# ======================================================================================
# ==================== DEFINE BASIC VARIABLES ==========================================
# ======================================================================================
{% set park_vars = printer['gcode_macro AFC_PARK'] %}
{% set filament_diameter = printer.configfile.config.extruder.filament_diameter|float %}
{% set filament_cross_section = (filament_diameter/2) ** 2 * 3.1415 %}
{% set bl_count = printer['gcode_macro _BLOBIFIER_COUNT'] %}
{% set pos = printer.gcode_move.gcode_position %}
{% set safe = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'] %}
{% set ignore_safe = safe.print_height < force_safe_descend_height_until %}
{% set restore_z = [printer['gcode_macro BLOBIFIER_PARK'].restore_z,pos.z]|max %}
{% set pos_max = printer.toolhead.axis_maximum %}
{% set position_y = pos_max.y - skew_correction %}
{% set bl = printer['gcode_macro BLOBIFIER'] %}
# Get purge volumes from the slicer (if set up right. see
# https://github.com/moggieuk/Happy-Hare/wiki/Gcode-Preprocessing)
# {% set pv = printer.mmu.slicer_tool_map.purge_volumes %}
# ======================================================================================
# ==================== DETERMINE PURGE LENGTH ==========================================
# ======================================================================================
{% if params.PURGE_LENGTH %} # =============== PARAM PURGE LENGTH ======================
{action_respond_info("BLOBIFIER: param PURGE_LENGTH provided")}
{% set purge_len = params.PURGE_LENGTH|float %}
# {% elif from_tool == to_tool and to_tool >= 0 %} # ==== TOOL DIDN'T CHANGE =============
# {action_respond_info("BLOBIFIER: Tool didn't change (T%s > T%s), %s" % (from_tool, to_tool, "priming" if purge_length_minimum else "skipping"))}
# {% set purge_len = 0 %}
# {% elif pv %} # ============== FETCH FROM HAPPY HARE (LIKELY FROM SLICER) ==============
# {% if from_tool < 0 and to_tool >= 0%}
# {action_respond_info("BLOBIFIER: from tool unknown. Finding largest value for T? > T%d" % to_tool)}
# {% set purge_vol = pv|map(attribute=to_tool)|max %}
# {% elif to_tool < 0 %}
# {action_respond_info("BLOBIFIER: tool(s) unknown. Finding largest value")}
# {% set purge_vol = pv|map('max')|max %}
# {% else %}
# {% set purge_vol = pv[from_tool][to_tool]|float * purge_length_modifier %}
# {action_respond_info("BLOBIFIER: Swapped T%s > T%s" % (from_tool, to_tool))}
# {% endif %}
# {% set purge_len = purge_vol / filament_cross_section %}
# {% set purge_len = purge_len + printer.mmu.extruder_filament_remaining + park_vars.retracted_length + purge_length_addition %}
{% else %} # ========================= USE CONFIG VARIABLE =============================
{action_respond_info("BLOBIFIER: No toolmap or PURGE_LENGTH. Using default")}
{% set purge_len = purge_length|float + bl.retracted_length %}
{% endif %}
# # ==================================== APPLY PURGE MINIMUM =============================
{% set purge_len = [purge_len,purge_length_minimum]|max|round(0, 'ceil')|int %}
{action_respond_info("BLOBIFIER: Purging %dmm of filament" % (purge_len))}
{% if params.PURGE_LENGTH %}
{% set purge_len = params.PURGE_LENGTH|float %}
{% else %}
{% set purge_len = purge_length %}
{% endif %}
# Apply purge minimum
#{% set purge_len = [purge_len, purge_length_minimum]|max %}
{% set purge_len = [purge_len,purge_length_minimum]|max|round(0, 'ceil')|int %}
{action_respond_info("BLOBIFIER: Purging %dmm of filament" % (purge_len))}
# ======================================================================================
# ==================== PURGING SEQUENCE ================================================
# ======================================================================================
# Set to absolute positioning.
G90
# Check for purge length and purge if necessary.
{% if purge_len|float > 0 %}
# ====================================================================================
# ==================== POSITIONING ===================================================
# ====================================================================================
# Move to the assembly, first a bit more to the right (brush_start) to avoid a
# potential filametrix pin if it's not already on the same Y coordinate.
{% if printer.toolhead.position.y != position_y %}
G1 X{brush_start} Y{position_y} F{travel_spd_xy}
{% endif %}
# Move over to the tray
G1 X{purge_x} F{travel_spd_xy}
# ====================================================================================
# ==================== BUCKET SHAKE ==================================================
# ====================================================================================
{% if enable_shaker and (safe.shake or ignore_safe) %}
{% if (bl_count.current_blobs + 1) >= bl_count.next_shake %}
BLOBIFIER_SHAKE_BUCKET SHAKES={bucket_shakes}
_BLOBIFIER_CALCULATE_NEXT_SHAKE
{% endif %}
{% endif %}
# ====================================================================================
# ==================== POSITIONING ON TRAY ===========================================
# ====================================================================================
{% if safe.tray or ignore_safe %}
G1 Z{tray_top + purge_start} F{travel_spd_z}
# Extend the blobifier
BLOBIFIER_SERVO POS=out
{% endif %}
# ====================================================================================
# ==================== HEAT HOTEND ===================================================
# ====================================================================================
{% if printer.extruder.temperature < purge_temp_min %}
{% if printer.extruder.target < purge_temp_min %}
M109 S{purge_temp_min}
{% else %}
TEMPERATURE_WAIT SENSOR=extruder MINIMUM={purge_temp_min}
{% endif %}
{% endif %}
# ====================================================================================
# ==================== START ITERATING ===============================================
# ====================================================================================
# Calculate total number of iterations based on the purge length and the max_iteration
# length.
{% set blobs = (purge_len / purge_length_maximum)|round(0, 'ceil')|int %}
{% set purge_per_blob = purge_len|float / blobs %}
{% set retracts_per_blob = (purge_per_blob / 40)|round(0, 'ceil')|int %}
{% set purge_per_retract = (purge_per_blob / retracts_per_blob)|int %}
{% set pulses_per_retract = (purge_per_blob / retracts_per_blob / 5)|round(0, 'ceil')|int %}
{% set pulses_per_blob = (purge_per_blob / 5)|round(0, 'ceil')|int %}
{% set purge_per_pulse = purge_per_blob / pulses_per_blob %}
{% set pulse_time_constant = purge_per_pulse * 0.95 / purge_spd / (purge_per_pulse * 0.95 / purge_spd + purge_per_pulse * 0.05 / 50) %}
{% set pulse_duration = purge_per_pulse / purge_spd %}
# Repeat the process until purge_len is reached
{% for blob in range(blobs) %}
RESPOND MSG={"'BLOBIFIER: Blob %d of %d (%.1fmm)'" % (blob + 1, blobs, purge_per_blob)}
{% if safe.tray or ignore_safe %}
G1 Z{tray_top + purge_start} F{travel_spd_z}
{% endif %}
# relative positioning
G91
# relative extrusion
M83
# Purge filament in a pulsating motion to purge the filament quicker and better
{% for pulse in range(pulses_per_blob) %}
# Calculations to determine z-speed
{% set purged_this_blob = pulse * purge_per_pulse %}
{% set z_last_pos = purge_start + ((purged_this_blob)/purge_length_maximum)**z_raise_exp * z_raise %}
{% set z_pos = purge_start + ((purged_this_blob + purge_per_pulse)/purge_length_maximum)**z_raise_exp * z_raise %}
{% set z_up = z_pos - z_last_pos %}
{% set speed = z_up / pulse_duration %}
# Purge quickly
G1 Z{z_up * pulse_time_constant} E{purge_per_pulse * 0.95} F{speed}
# Purge a tiny bit slowly
G1 Z{z_up * (1 - pulse_time_constant)} E{purge_per_pulse * 0.05} F{speed}
# retract and unretract filament every now and then for thourough cleaning
{% if pulse % pulses_per_retract == 0 and pulse > 0 %}
G1 E-2 F1800
G1 E2 F800
{% endif %}
{% endfor %}
# Retract to match what Happy Hare is expecting
G1 E-{bl.retracted_length} F{bl.retract_speed * 60}
# ==================================================================================
# ==================== DEPOSIT BLOB ================================================
# ==================================================================================
{% if safe.tray or ignore_safe %}
# Raise z a bit to relieve pressure on the blob preventing it to go sideways
G1 Z{eject_hop} F{travel_spd_z}
# Retract the tray
BLOBIFIER_SERVO POS=in
# Move the toolhead down to purge_start height lowering the blob below the tray
G90 # absolute positioning
G1 Z{tray_top} F{travel_spd_z}
# Extend the tray to 'cut off' the blob and prepare for the next blob
BLOBIFIER_SERVO POS=out
BLOBIFIER_SERVO POS=in
BLOBIFIER_SERVO POS=out
# Keep track of the # of blobs
_BLOBIFIER_COUNT
{% endif %}
{% endfor %}
{% endif %}
{% if safe.tray or ignore_safe %}
G1 Z{tray_top + 1} F{travel_spd_z}
G4 P{pressure_release_time}
{% endif %}
{% if safe.brush or ignore_safe %}
BLOBIFIER_CLEAN
{% else %}
G1 X{brush_start} F{travel_spd_xy}
{% endif %}
# ======================================================================================
# ==================== RESTORE STATE ===================================================
# ======================================================================================
G90 # absolute positioning
G1 Z{restore_z} F{travel_spd_z}
{% if part_cooling_fan >= 0 %}
# Reset part cooling fan if it was changed
M106 S{(backup_fan_speed * 255)|int}
{% endif %}
M220 S{(backup_feedrate * 100)|int}
{% endif %}
RESTORE_GCODE_STATE NAME=BLOBIFIER_state
##########################################################################################
# Wipes the nozzle on the brass brush
#
[gcode_macro BLOBIFIER_CLEAN]
gcode:
{% set bb = printer['gcode_macro BLOBIFIER'] %}
{% set position_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
{% set original_accel = printer.toolhead.max_accel %}
{% set original_minimum_cruise_ratio = printer.toolhead.minimum_cruise_ratio %}
{% set pos = printer.gcode_move.gcode_position %}
SAVE_GCODE_STATE NAME=BLOBIFIER_CLEAN_state
G90
{% if bb.brush_accel > 0 %}
SET_VELOCITY_LIMIT ACCEL={bb.brush_accel} MINIMUM_CRUISE_RATIO=0.1
{% endif %}
{% if pos.z < bb.brush_top + bb.clearance_z %}
G1 Z{bb.brush_top + bb.clearance_z} F{bb.travel_spd_z}
{% endif %}
G1 X{bb.brush_start} F{bb.travel_spd_xy}
G1 Y{position_y}
G1 Z{bb.brush_top + bb.clearance_z} F{bb.travel_spd_z}
# Move nozzle down into brush.
G1 Z{bb.brush_top} F{bb.travel_spd_z}
SET_VELOCITY_LIMIT ACCEL={original_accel} MINIMUM_CRUISE_RATIO={original_minimum_cruise_ratio}
# Perform wipe. Wipe direction based off bucket_pos for cool random scrubby routine.
{% for wipes in range(1, (bb.wipe_qty + 1)) %}
G1 X{bb.brush_start + bb.brush_width} F{bb.wipe_spd_xy}
G1 X{bb.brush_start} F{bb.wipe_spd_xy}
{% endfor %}
{% if pos.z < 10 %}
G1 Z10
{% else %}
G1 Z{pos.z}
{% endif %}
RESTORE_GCODE_STATE NAME=BLOBIFIER_CLEAN_state
##########################################################################################
# Park the nozzle on the tray to prevent oozing during filament swaps. Place this
# extension in the post_form_tip extension in mmu_macro_vars.cfg:
# variable_user_post_form_tip_extension: "BLOBIFIER_PARK"
#
[gcode_macro BLOBIFIER_PARK]
variable_restore_z: 0
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
{% set pos = printer.gcode_move.gcode_position %}
{% set safe = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'] %}
{% set pos_max = printer.toolhead.axis_maximum %}
{% set position_y = pos_max.y - bl.skew_correction %}
SET_GCODE_VARIABLE MACRO=BLOBIFIER_PARK VARIABLE=restore_z VALUE={pos.z}
SAVE_GCODE_STATE NAME=blobifier_park_state
{% if "xyz" in printer.toolhead.homed_axes and printer.quad_gantry_level and printer.quad_gantry_level.applied %}
G90
G1 X{bl.brush_start} Y{position_y} F{bl.travel_spd_xy}
G1 X{bl.purge_x}
{% if safe.tray or ignore_safe %}
G1 Z{bl.tray_top} F{bl.travel_spd_z}
{% endif %}
{% else %}
RESPOND MSG="Please home (and QGL) before parking"
{% endif %}
RESTORE_GCODE_STATE NAME=blobifier_park_state
##########################################################################################
# Retract or extend the tray
# POS=[in|out] Retractor extend the tray
#
[gcode_macro BLOBIFIER_SERVO]
# Increase this value if the servo doesn't have enough time to fully retract or extend
# variable_dwell_time: 200
variable_dwell_time: 1000
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
{% set pos = params.POS %}
{% if pos == "in" %}
SET_SERVO SERVO=blobifier ANGLE={bl.tray_angle_in}
G4 P{dwell_time}
{% elif pos == "out" %}
SET_SERVO SERVO=blobifier ANGLE={bl.tray_angle_out}
G4 P{dwell_time}
{% else %}
{action_respond_info("BLOBIFIER: provide POS=[in|out]")}
{% endif %}
SET_SERVO SERVO=blobifier WIDTH=0
##########################################################################################
# Define exclude objects for those who haven't already
#
[exclude_object]
##########################################################################################
# Overwrite the existing EXCLUDE_OBJECT_DEFINE to also check for safe descend.
#
[gcode_macro EXCLUDE_OBJECT_DEFINE]
rename_existing: _EXCLUDE_OBJECT_DEFINE
gcode:
# only reset on the first object at the beginning of a print
{% if printer.exclude_object.objects|length < 1 %}
_BLOBIFIER_RESET_SAFE_DESCEND
{% endif %}
_EXCLUDE_OBJECT_DEFINE {rawparams}
_BLOBIFIER_SAFE_DESCEND
UPDATE_DELAYED_GCODE ID=BLOBIFIER_SHOW_SAFE_DESCEND DURATION=1
[delayed_gcode BLOBIFIER_SHOW_SAFE_DESCEND]
gcode:
{% set safe = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'] %}
{action_respond_info(
"BLOBIIER: Safe descend possible:\n - tray: %s\n - brush: %s\n - shake: %s" %
(
"yes" if safe.tray else "no",
"yes" if safe.brush else "no",
"yes" if safe.shake else "no"
)
)}
##########################################################################################
# Use the EXCLUDE_OBJECT_START gcode macro to record the current height
#
[gcode_macro EXCLUDE_OBJECT_START]
rename_existing: _EXCLUDE_OBJECT_START
gcode:
_EXCLUDE_OBJECT_START {rawparams}
{% if printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'].first_layer %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=first_layer VALUE=False
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_height VALUE={printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'].print_layer_height}
{% else %}
{% set pos = printer.gcode_move.gcode_position %}
{% set last_height = printer['gcode_macro _BLOBIFIER_SAFE_DESCEND'].print_previous_height|float %}
{% if pos.z > last_height %}
{% set last_layer = (pos.z - last_height)|round(2) %}
{% set print_height = (pos.z + last_layer)|round(2) %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_previous_height VALUE={pos.z}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_height VALUE={print_height}
{% endif %}
{% endif %}
##########################################################################################
# Reset the safe descend variables.
#
[gcode_macro _BLOBIFIER_RESET_SAFE_DESCEND]
gcode:
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=tray VALUE=True
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=brush VALUE=True
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=shake VALUE=True
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=first_layer VALUE=True
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_height VALUE=0
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=print_previous_height VALUE=0
##########################################################################################
# Determine if it is safe to drop the toolhead (e.g. not hit a print)
#
[gcode_macro _BLOBIFIER_SAFE_DESCEND]
variable_tray: True # Assume it is safe
variable_brush: True
variable_shake: True
variable_first_layer: True
variable_print_height: 0
variable_print_previous_height: 0
variable_print_layer_height: 0.3
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
{% set pos_max = printer.toolhead.axis_maximum %}
{% set position_y = pos_max.y - bl.skew_correction %}
{% set tray = [bl.purge_x + bl.toolhead_x, position_y - bl.toolhead_y] %}
{% set brush = [bl.brush_start + bl.brush_width + bl.toolhead_x, position_y - bl.toolhead_y] %}
{% set shake = [bl.purge_x + bl.toolhead_x, position_y - bl.toolhead_y - 4] %}
{% set objects = printer.exclude_object.objects | map(attribute='polygon') %}
{% for polygon in objects %}
{% for point in polygon %}
{% if point[0] < tray[0] and point[1] > tray[1] %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=tray VALUE=False
{% endif %}
{% if point[0] < brush[0] and point[1] > brush[1] %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=brush VALUE=False
{% endif %}
{% if point[0] < shake[0] and point[1] > shake[1] %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_SAFE_DESCEND VARIABLE=shake VALUE=False
{% endif %}
{% endfor %}
{% endfor %}
##########################################################################################
# Increment the blob count with 1 and check if the bucket is full. Pause
# the printer if it is.
#
[gcode_macro _BLOBIFIER_COUNT]
# Don't change these variables
variable_current_blobs: 0
variable_last_shake: 0
variable_next_shake: 0
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
{% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %}
{% if current_blobs >= bl.max_blobs %}
{action_respond_info("BLOBIFIER: Empty purge bucket!")}
M117 Empty purge bucket!
PAUSE
{% else %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=current_blobs VALUE={current_blobs + 1}
_BLOBIFIER_SAVE_STATE
{action_respond_info(
"BLOBIFIER: Blobs in bucket: %s/%s. Next shake @ %s"
% (current_blobs + 1, bl.max_blobs, next_shake)
)}
{% endif %}
##########################################################################################
# Reset the blob count to 0
#
[gcode_macro _BLOBIFIER_COUNT_RESET]
gcode:
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=current_blobs VALUE=0
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE=0
_BLOBIFIER_SAVE_STATE
_BLOBIFIER_CALCULATE_NEXT_SHAKE
##########################################################################################
# Shake the blob bucket to disperse the blobs
#
[gcode_macro BLOBIFIER_SHAKE_BUCKET]
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
{% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %}
{% set original_accel = printer.toolhead.max_accel %}
{% set original_minimum_cruise_ratio = printer.toolhead.minimum_cruise_ratio %}
{% set position_x = bl.skew_correction %}
{% if "xyz" not in printer.toolhead.homed_axes %}
{action_raise_error("BLOBIFIER: Not homed. Home xyz first")}
{% endif %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE={count.current_blobs}
_BLOBIFIER_SAVE_STATE
SAVE_GCODE_STATE NAME=shake_bucket
M400
M117 (^_^)
G90
{% set shakes = params.SHAKES|default(10)|int %}
{% set position_y = printer.configfile.config["stepper_y"]["position_max"]|float %}
# move to save y if not already there
{% if printer.toolhead.position.y != position_y %}
G1 X{bl.brush_start} Y{position_y} F{bl.travel_spd_xy}
{% endif %}
# move up a bit to prevent oozing on base
G1 Z{bl.shaker_arm_z} F{bl.travel_spd_z}
# slide into the slot
# G1 X{position_x} F{bl.travel_spd_xy}
G1 X4
M400
M117 (+(+_+)+)
SET_VELOCITY_LIMIT ACCEL={bl.shake_accel} MINIMUM_CRUISE_RATIO=0.1
# Shake away!
{% for shake in range(1, shakes) %}
G1 Y{position_y - 10} F3600
G1 Y{position_y} F30000
{% endfor %}
SET_VELOCITY_LIMIT ACCEL={original_accel} MINIMUM_CRUISE_RATIO={original_minimum_cruise_ratio}
# move out of slot
G1 X{bl.purge_x}
M400
M117 (X_x)
RESTORE_GCODE_STATE NAME=shake_bucket
##########################################################################################
# Calculate when the bucket should be shaken.
#
[gcode_macro _BLOBIFIER_CALCULATE_NEXT_SHAKE]
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
{% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %}
{% set remaining_blobs = bl.max_blobs - count.last_shake %}
{% set next_shake = (1 - bl.bucket_shake_frequency) * remaining_blobs + count.last_shake %}
_BLOBIFIER_SAVE_STATE
_BLOBIFIER_SET_NEXT_SHAKE VALUE={next_shake|int}
##########################################################################################
# Set when the bucket should be shaken next
# VALUE=[int] At what amount of blobs should it be shaken
#
[gcode_macro _BLOBIFIER_SET_NEXT_SHAKE]
gcode:
{% if params.VALUE %}
{% set next_shake = params.VALUE %}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=next_shake VALUE={next_shake}
_BLOBIFIER_SAVE_STATE
{% else %}
{action_respond_info("BLOBIFIER: Provide parameter VALUE=")}
{% endif %}
##########################################################################################
# Some sanity checks
#
[delayed_gcode BLOBIFIER_INIT]
initial_duration: 5.0
gcode:
_BLOBIFIER_INIT
BLOBIFIER_SERVO POS=out
[gcode_macro _BLOBIFIER_INIT]
gcode:
{% set bl = printer['gcode_macro BLOBIFIER'] %}
# Valid part cooling fan setting
{% if bl.part_cooling_fan != -1 and (bl.part_cooling_fan < 0 or bl.part_cooling_fan > 1) %}
{action_emergency_stop("BLOBIFIER: Value %f is invalid for variable part_cooling_fan. Either -1 or a value from 0 .. 1 is valid." % (bl.part_cooling_fan))}
{% endif %}
# Valid bucket shake frequency
{% if bl.bucket_shake_frequency < 0 or bl.bucket_shake_frequency > 1 %}
{action_emergency_stop("BLOBIFIER: Value %f is invalid for variable bucket_shake_frequency. Change it to a value between 0 .. 1" % (bl.bucket_shake_frequency))}
{% endif %}
# Check if position is on 'next'
{% if printer.mmu %}
{% if printer['gcode_macro _MMU_SEQUENCE_VARS'].restore_xy_pos != 'next' %}
{action_respond_info("BLOBIFIER: If not using a wipe tower, consider setting restore_xy_pos: 'next' in mmu_macro_vars.cfg")}
{% endif %}
{% endif %}
# Check the z_raise variable for normal values
{% if bl.z_raise < 3 %}
{action_respond_info("BLOBIFIER: variable_z_raise: %f is very low. This is the value z raises in total on a single blob. Make sure the value is correct before continuing." % (bl.z_raise))}
{% endif %}
# Z raise exponent
{% if bl.z_raise_exp > 1 or bl.z_raise_exp < 0.5 %}
{action_respond_info("BLOBIFIER: variable_z_raise_exp has value: %f. This value is out of spec (0.5 ... 1.0)." % (bl.z_raise))}
{% endif %}
[delayed_gcode BLOBIFIER_LOAD_STATE]
initial_duration: 2.0 # Give it some time to boot up
gcode:
{% set sv = printer.save_variables.variables.blobifier %}
{% if sv %}
# Restore state
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=last_shake VALUE={sv.last_shake}
SET_GCODE_VARIABLE MACRO=_BLOBIFIER_COUNT VARIABLE=current_blobs VALUE={sv.current_blobs}
{% endif %}
_BLOBIFIER_CALCULATE_NEXT_SHAKE
[gcode_macro _BLOBIFIER_SAVE_STATE]
gcode:
{% set count = printer['gcode_macro _BLOBIFIER_COUNT'] %}
{% set sv = {'current_blobs': count.current_blobs, 'last_shake': count.last_shake} %}
SAVE_VARIABLE VARIABLE=blobifier VALUE="{sv}"
[respond]
# [save_variables] is defined once in ../save_variables.cfg (shared with the PA macros)
+26
View File
@@ -0,0 +1,26 @@
##########################################################################################
# The servo hardware configuration. Change the values to your needs.
#
[servo blobifier]
# Pin for the servo.
pin: PC1
# Adjust this value until a 'BLOBIFIER_SERVO POS=in' retracts the tray fully without a
# buzzing sound
minimum_pulse_width: 0.00053
# Adjust this value until a 'BLOBIFIER_SERVO POS=out' extends the tray fully without a
# buzzing sound
maximum_pulse_width: 0.0023
# Leave this value at 180
maximum_servo_angle: 180
##########################################################################################
# The bucket hardware configuration. Change the pin to whatever pin you've connected the
# switch to.
#
[gcode_button bucket]
pin: ^PC3 # The pullup ( ^ ) is important here.
press_gcode:
M117 bucket installed
release_gcode:
M117 bucket removed
_BLOBIFIER_COUNT_RESET
@@ -1,3 +1,5 @@
# Bed fans driven by the bed heater (based on Ellis' bed fan macros)
############### Config options ################## ############### Config options ##################
[gcode_macro _BEDFANVARS] [gcode_macro _BEDFANVARS]
@@ -1,3 +1,5 @@
# iHeater chamber heater: MCU, heater, sensors and M141/M191
#======================================================== #========================================================
#=====================iHeater cfg======================== #=====================iHeater cfg========================
#======================================================== #========================================================
@@ -1,3 +1,5 @@
# Filament drying on the heated bed: START_DRYING, STOP_DRYING, STATUS_DRYING
########################################################### ###########################################################
# Filament Drying # # Filament Drying #
########################################################### ###########################################################
@@ -1,3 +1,5 @@
# HEAT_SOAK: wait for a sensor to reach thermal equilibrium (community macro)
## ##
## HEAT_SOAK HEATER=<heater_name> TARGET=<target_heater_temperature> SOAKER=<heat_soak_temp_sensor_name> [RATE=<heat_soak_temp_rate_of_change>] [TIMEOUT=<time_to_abort_heat_soak>] ## HEAT_SOAK HEATER=<heater_name> TARGET=<target_heater_temperature> SOAKER=<heat_soak_temp_sensor_name> [RATE=<heat_soak_temp_rate_of_change>] [TIMEOUT=<time_to_abort_heat_soak>]
## ##
+22
View File
@@ -0,0 +1,22 @@
# SOAK_MY_BED wrapper (soak-my-bed plugin): home and QGL first
# [gcode_macro QUAD_GANTRY_LEVEL]
# rename_existing: _QUAD_GANTRY_LEVEL
# gcode:
# _QUAD_GANTRY_LEVEL
# _QUAD_GANTRY_LEVEL PROBE_METHOD=contact
### bed warp visualizer
[gcode_macro SOAK_MY_BED]
description: Heat soak bed and live meassure
rename_existing: SOAK_MY_BED_BASE
gcode:
{% set temp = params.TEMPERATURE|default(60) %}
{% set duration = params.DURATION|default(10) %}
{% set heater = params.HEATER|default("heater_bed") %}
{% set mesh = params.MESH_COMMAND|default("BED_MESH_CALIBRATE METHOD=beacon") %}
G28
QUAD_GANTRY_LEVEL
SOAK_MY_BED_BASE TEMPERATURE={temp} DURATION={duration} HEATER={heater} MESH_COMMAND="{mesh}"
+40 -20
View File
@@ -1,26 +1,46 @@
##################################################################### #####################################################################
# klipper-macros: include this one file from printer.cfg # klipper-macros: include this one file from printer.cfg, after
# [include mainsail.cfg] (it needs [pause_resume], [virtual_sdcard] and
# [respond] from there, and replaces Mainsail's PAUSE/RESUME/CANCEL_PRINT):
# #
# [include klipper-macros/klipper-macros.cfg] # [include klipper-macros/klipper-macros.cfg]
# #
# The order below matters: several files rename PAUSE/RESUME/CANCEL_PRINT # Comment out what you do not use. Keep the order where noted: some
# (rename_existing), and the last definition wins. It is the order these # macros (PAUSE, RESUME, CANCEL_PRINT) are defined in more than one file
# files had on the original printer. Comment out what you do not use. # and the last definition wins.
#
# Not part of this repo, include them yourself if you use them:
# timelapse.cfg (moonraker-timelapse), TEST_SPEED.cfg (Ellis),
# mainsail.cfg (before this file), blobifier, AFC, KAMP
##################################################################### #####################################################################
[include bedfans.cfg] [include save_variables.cfg] # the one [save_variables] for all macros
[include stealthburner_led_effects_barf.cfg]
[include macros_klipperscreen.cfg] # Blobifier purge bucket (Turtleblobifier for AFC, modified)
[include iHeater.cfg] [include blobifier/blobifier.cfg]
[include drying.cfg]
[include afc_macros.cfg] # Printing
[include motion.cfg] [include print/pause_resume.cfg] # before heating/heat_soak.cfg
[include heatsoak.cfg] [include print/filament.cfg]
[include purge_until_empty.cfg] [include print/homing.cfg]
[include purge_check.cfg] [include print/idle_timeout.cfg]
[include macros.cfg] [include print/print_start_end.cfg]
[include bd_pa_afc_spoolman.cfg]
# Heating
[include heating/bed_fans.cfg]
[include heating/chamber_iheater.cfg]
[include heating/heat_soak.cfg] # its RESUME wraps the one above
[include heating/soak_my_bed.cfg]
[include heating/filament_drying.cfg]
# AFC (Box Turtle)
[include afc/xy_safety_check.cfg]
[include afc/lane_tools.cfg]
[include afc/purge_check.cfg]
[include afc/purge_until_empty.cfg]
# Pressure advance per lane/spool (bd_pressure + Spoolman)
[include pressure_advance/bd_pa_spoolman.cfg]
# Spoolman
[include spoolman/active_spool.cfg]
# LEDs and sensors
[include leds/stealthburner_leds.cfg]
[include sensors/motion_sensor.cfg]
File renamed without changes.
@@ -129,16 +129,9 @@
# REQUIRED SETUP # REQUIRED SETUP
# --------------------------------------------------------------------- # ---------------------------------------------------------------------
# 1) [save_variables] is declared below in this same file (see the # 1) [save_variables] is declared once for the whole repo in
# [save_variables] section right after this header) -- you do NOT # save_variables.cfg (klipper-macros.cfg includes it). It stores the
# need to add it to printer.cfg separately. # variables of all macros (this file and Blobifier) in one file.
# IMPORTANT: if you already have a [save_variables] section
# somewhere else in your config (printer.cfg or another include),
# DELETE the one below -- Klipper will error on a duplicate section
# if it appears twice anywhere in your merged config. Only one
# [save_variables] section is allowed printer-wide, but it stores
# ALL variables from ALL macros in one shared file, so having it
# declared once, here, works fine for everything in your setup.
# #
# 2) Make sure moonraker.conf has [spoolman] configured so AFC can pull # 2) Make sure moonraker.conf has [spoolman] configured so AFC can pull
# nozzle_temp/material from Spoolman when a lane is loaded: # nozzle_temp/material from Spoolman when a lane is loaded:
@@ -180,14 +173,7 @@
# PA_STATUS # PA_STATUS
######################################################################## ########################################################################
# --------------------------------------------------------------------------- # [save_variables] is defined once in ../save_variables.cfg (shared with Blobifier)
# Persistent variable storage -- required by SAVE_VARIABLE/printer.save_variables
# used throughout this file for the PA cache and lane->spool_id tracking.
# DELETE THIS SECTION if you already have a [save_variables] section
# defined anywhere else in your config (only one is allowed printer-wide).
# ---------------------------------------------------------------------------
[save_variables]
filename: ~/printer_data/config/bd_pa_variables.cfg
# The file above does not need to exist yet -- Klipper creates it on # The file above does not need to exist yet -- Klipper creates it on
# first SAVE_VARIABLE call and reloads it on every restart. # first SAVE_VARIABLE call and reloads it on every restart.
@@ -261,9 +247,9 @@ gcode: # intentionally empty -- variables only
# file sidesteps this entirely, since that file is never touched by # file sidesteps this entirely, since that file is never touched by
# Klipper's config parser. # Klipper's config parser.
# #
# The script ships in this folder (klipper-macros/bd_pa_write_spoolman.sh); # The script ships in this folder (klipper-macros/pressure_advance/bd_pa_write_spoolman.sh);
# install.sh makes it executable. # install.sh makes it executable.
command: bash ~/printer_data/config/klipper-macros/bd_pa_write_spoolman.sh command: bash ~/printer_data/config/klipper-macros/pressure_advance/bd_pa_write_spoolman.sh
verbose: False verbose: False
@@ -274,7 +260,7 @@ verbose: False
# (un-indented), which is also a config parsing error in Klipper's # (un-indented), which is also a config parsing error in Klipper's
# parser -- every line of a multi-line value must be indented, # parser -- every line of a multi-line value must be indented,
# including the very last line. # including the very last line.
command: bash ~/printer_data/config/klipper-macros/bd_pa_create_spoolman_field.sh command: bash ~/printer_data/config/klipper-macros/pressure_advance/bd_pa_create_spoolman_field.sh
verbose: False verbose: False
@@ -368,7 +354,7 @@ gcode:
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# PA cache, keyed by spool_id, stored via Klipper's own save_variables. # PA cache, keyed by spool_id, stored via Klipper's own save_variables.
# Requires a [save_variables] section in printer.cfg (see header notes). # Requires [save_variables] (save_variables.cfg, see header notes).
# #
# IMPORTANT: printer.save_variables.variables is read DIRECTLY inline in # IMPORTANT: printer.save_variables.variables is read DIRECTLY inline in
# each macro below (not via a helper sub-macro + SET_GCODE_VARIABLE # each macro below (not via a helper sub-macro + SET_GCODE_VARIABLE
+28
View File
@@ -0,0 +1,28 @@
# LOAD_FILAMENT, UNLOAD_FILAMENT (based on the KlipperScreen recommended macros)
[gcode_macro LOAD_FILAMENT]
variable_load_distance: 60
variable_purge_distance: 20
gcode:
{% set speed = params.SPEED|default(15) %}
{% set max_velocity = printer.configfile.settings['extruder'].max_extrude_only_velocity * 15 %}
SAVE_GCODE_STATE NAME=load_state
G91
G92 E0
G1 E{load_distance} F{max_velocity} # fast-load
G1 E{purge_distance} F{speed} # purge
RESTORE_GCODE_STATE NAME=load_state
[gcode_macro UNLOAD_FILAMENT]
variable_unload_distance: 100
variable_purge_distance: 0
gcode:
{% set speed = params.SPEED|default(15) %}
{% set max_velocity = printer.configfile.settings['extruder'].max_extrude_only_velocity * 30 %}
SAVE_GCODE_STATE NAME=unload_state
G91
G92 E0
G1 E{purge_distance} F{speed} # purge
G1 E-20 F100# unload
G1 E-{unload_distance} F{max_velocity} # fast-unload
RESTORE_GCODE_STATE NAME=unload_state
+8
View File
@@ -0,0 +1,8 @@
# HOME: home all axes and move to the bed centre
[gcode_macro HOME]
gcode:
G90
G4 P2000
G28 X0 Y0 Z0
G1 X175 Y175 Z10 F1200
+23
View File
@@ -0,0 +1,23 @@
# Idle timeout: heaters and motors off when the printer is idle
# [dynamicmacros]
# configs: Macros/dynamicmacros.cfg
# [gcode_button kill_switch]
# pin: gpio7
# press_gcode: M112
[idle_timeout]
gcode:
TURN_OFF_HEATERS
iHEATER_OFF ; Turns off the chamber heater
M84
# reset paused flag
{% if printer.pause_resume.is_paused|lower == 'false' and park|lower == 'true'%}
_TOOLHEAD_PARK_PAUSE_CANCEL
{% endif %}
_status_ready
# A list of G-Code commands to execute on an idle timeout. See
# docs/Command_Templates.md for G-Code format. The default is to run
# "TURN_OFF_HEATERS" and "M84".
timeout: 85400 # 24 hours
@@ -1,3 +1,5 @@
# PAUSE, RESUME, CANCEL_PRINT, M600 (based on the KlipperScreen recommended macros)
# https://klipperscreen.readthedocs.io/en/latest/macros/#recommended # https://klipperscreen.readthedocs.io/en/latest/macros/#recommended
[gcode_macro PAUSE] [gcode_macro PAUSE]
description: Pause the actual running print description: Pause the actual running print
@@ -132,33 +134,6 @@ gcode:
TURN_OFF_HEATERS TURN_OFF_HEATERS
CANCEL_PRINT_BASE_KLIPPERSCREEN CANCEL_PRINT_BASE_KLIPPERSCREEN
[gcode_macro LOAD_FILAMENT]
variable_load_distance: 60
variable_purge_distance: 20
gcode:
{% set speed = params.SPEED|default(15) %}
{% set max_velocity = printer.configfile.settings['extruder'].max_extrude_only_velocity * 15 %}
SAVE_GCODE_STATE NAME=load_state
G91
G92 E0
G1 E{load_distance} F{max_velocity} # fast-load
G1 E{purge_distance} F{speed} # purge
RESTORE_GCODE_STATE NAME=load_state
[gcode_macro UNLOAD_FILAMENT]
variable_unload_distance: 100
variable_purge_distance: 0
gcode:
{% set speed = params.SPEED|default(15) %}
{% set max_velocity = printer.configfile.settings['extruder'].max_extrude_only_velocity * 30 %}
SAVE_GCODE_STATE NAME=unload_state
G91
G92 E0
G1 E{purge_distance} F{speed} # purge
G1 E-20 F100# unload
G1 E-{unload_distance} F{max_velocity} # fast-unload
RESTORE_GCODE_STATE NAME=unload_state
[gcode_macro M600] [gcode_macro M600]
@@ -1,26 +1,5 @@
# Print start/end macros. Included by klipper-macros.cfg. # Print start and end: PRINT_WARMUP, PRINT_START, PRINT_END
# [dynamicmacros]
# configs: Macros/dynamicmacros.cfg
# [gcode_button kill_switch]
# pin: gpio7
# press_gcode: M112
[idle_timeout]
gcode:
TURN_OFF_HEATERS
iHEATER_OFF ; Turns off the chamber heater
M84
# reset paused flag
{% if printer.pause_resume.is_paused|lower == 'false' and park|lower == 'true'%}
_TOOLHEAD_PARK_PAUSE_CANCEL
{% endif %}
_status_ready
# A list of G-Code commands to execute on an idle timeout. See
# docs/Command_Templates.md for G-Code format. The default is to run
# "TURN_OFF_HEATERS" and "M84".
timeout: 85400 # 24 hours
# Idle time (in seconds) to wait before running the above G-Code # Idle time (in seconds) to wait before running the above G-Code
# commands. The default is 600 seconds. # commands. The default is 600 seconds.
@@ -96,6 +75,7 @@ gcode:
BLOBIFIER_CLEAN ; call another macro to wipe nozzle if available BLOBIFIER_CLEAN ; call another macro to wipe nozzle if available
G1 X175 Y175 Z5 F1200 G1 X175 Y175 Z5 F1200
_HEAT_FOR_LOADED_LANE TOOL={initial_tool} ; unload needs the loaded filament's temperature
T{initial_tool} #PURGE_LENGTH=100 #Load Initial Tool T{initial_tool} #PURGE_LENGTH=100 #Load Initial Tool
M104 S{target_extruder} ; set extruder to print temp M104 S{target_extruder} ; set extruder to print temp
M109 S{target_extruder} ; wait for extruder temp M109 S{target_extruder} ; wait for extruder temp
@@ -124,6 +104,25 @@ gcode:
# (CANCEL='_NOTHING') and having unreachable SOAK_TEMP makes it run till the TIMEOUT and continue without canceling the print. # (CANCEL='_NOTHING') and having unreachable SOAK_TEMP makes it run till the TIMEOUT and continue without canceling the print.
{% endif %} {% endif %}
# AFC heats for a tool change from the print file's per-tool temperatures.
# When the loaded lane's tool number is not in that list (for example lane5 =
# T4 loaded, single-colour print with only T0), AFC does not heat at all and
# the unload fails below min_extrude_temp. Heat for the loaded filament first.
[gcode_macro _HEAT_FOR_LOADED_LANE]
description: Heat to the loaded lane's filament temperature before changing to another tool
gcode:
{% set tool = 'T' ~ params.TOOL|default(0)|int %}
{% set cur = printer.AFC.current_load %}
{% if cur and ('AFC_stepper ' ~ cur) in printer %}
{% set lane = printer['AFC_stepper ' ~ cur] %}
{% if lane.map != tool %}
{% set min_temp = printer.configfile.settings.extruder.min_extrude_temp|int + 20 %}
{% set temp = [lane.extruder_temp|default(0, true)|int, min_temp]|max %}
RESPOND MSG="Heating to {temp}C to unload {cur} ({lane.material}) before {tool}"
M109 S{temp}
{% endif %}
{% endif %}
[gcode_macro _NOTHING] [gcode_macro _NOTHING]
gcode: gcode:
_HEAT_SOAK__BASE_RESUME _HEAT_SOAK__BASE_RESUME
@@ -254,25 +253,3 @@ gcode:
[delayed_gcode _delayed_motors_off] [delayed_gcode _delayed_motors_off]
gcode: gcode:
M84 M84
# [gcode_macro QUAD_GANTRY_LEVEL]
# rename_existing: _QUAD_GANTRY_LEVEL
# gcode:
# _QUAD_GANTRY_LEVEL
# _QUAD_GANTRY_LEVEL PROBE_METHOD=contact
### bed warp visualizer
[gcode_macro SOAK_MY_BED]
description: Heat soak bed and live meassure
rename_existing: SOAK_MY_BED_BASE
gcode:
{% set temp = params.TEMPERATURE|default(60) %}
{% set duration = params.DURATION|default(10) %}
{% set heater = params.HEATER|default("heater_bed") %}
{% set mesh = params.MESH_COMMAND|default("BED_MESH_CALIBRATE METHOD=beacon") %}
G28
QUAD_GANTRY_LEVEL
SOAK_MY_BED_BASE TEMPERATURE={temp} DURATION={duration} HEATER={heater} MESH_COMMAND="{mesh}"
+6
View File
@@ -0,0 +1,6 @@
# Klipper allows one [save_variables] section; every SAVE_VARIABLE goes to
# this one file. Used by the PA cache (pressure_advance/) and the Blobifier
# blob counter (blobifier/). The file stays in the config folder: it is data,
# not part of the repo.
[save_variables]
filename: ~/printer_data/config/bd_pa_variables.cfg
@@ -1,3 +1,5 @@
# PIR motion sensor: case light on when someone is near the printer
[gcode_button am312] [gcode_button am312]
pin: !PC0 pin: !PC0
press_gcode: press_gcode:
+20
View File
@@ -0,0 +1,20 @@
# Spoolman: SET_ACTIVE_SPOOL, CLEAR_ACTIVE_SPOOL
[gcode_macro SET_ACTIVE_SPOOL]
gcode:
{% if params.ID %}
{% set id = params.ID|int %}
{action_call_remote_method(
"spoolman_set_active_spool",
spool_id=id
)}
{% else %}
{action_respond_info("Parameter 'ID' is required")}
{% endif %}
[gcode_macro CLEAR_ACTIVE_SPOOL]
gcode:
{action_call_remote_method(
"spoolman_set_active_spool",
spool_id=None
)}