Assigning a Filament (aka Thermal Preset) to an Extruder

I want to stop having to pedantically explain to klipper that I have ASA filament in the extruder on my printer. Like other machines, I’d like to tell klipper that information once and have it remembered across restarts. Then I’d like to make use of that information when performing common tasks, like loading/unloading filament or running a test print.

So here is a macro package that does this, for both single extruder and multi-extruder machines:

You create filaments like this:

SETUP_FILAMENT NAME=PLA EXTRUDER=215 BED=60

And set the filament like this

SET_FILAMENT NAME=PLA

The win is getting macros to heat things up that don’t take any parameters:

PREHEAT_EXTRUDER
PREHEAT_BED
PREHEAT
HEAT_EXTRUDER_AND_WAIT
HEAT_BED_AND_WAIT
HEAT_AND_WAIT

If you have a multi-tool printer these macros all take a TOOL_INDEX argument with the index of the extruder. So to set up a test print with PLA supports and PETG you might do this:

SET_FILAMENT NAME=PLA TOOL_INDEX=0
SET_FILAMENT NAME=PETG TOOL_INDEX=1
PREHEAT_EXTRUDER TOOL_INDEX=0
PREHEAT_EXTRUDER TOOL_INDEX=1
PREHEAT_BED TOOL_INDEX=1

In this case the bed is preheated with the bed temperature for the PETG in tool 1.

So, this is cool, but I hated every minute of programming it in Jinja. With enough hacking I can get Fluidd and KlipperScreen to use this instead of their own thermal preset tools but it wont be pretty. I wont get them to add buttons to call the PREHEAT* macros or to display the filament assigned to each extruder. The front ends wont evolve to take advantage of this unless I put out a klipper extension and eventually get it merged into klipper mainline.

So who would like this in Python and an installable extension? Is there value in this for you? Just like the post (or comment) if you are interested.

2 Likes

I agree it would be useful to have a mechanism to specify the filament type. I run into similar issues swapping filament on my printers. Alas, I have no suggestions on a good way to implement that.

-Kevin

1 Like

I was tumbling over a similar idea/issue to be able controlling chamber filters and fans.

Lets say you print with ABS or ASA and want to turn on carbon and HEPA filters during the print or at its end to clean and evacuate the printer/chamber.

My idea was to extend the parameter set of PRINT_START and PRINT_END macro with filament type and pass this via the slicer along with bed and hotend temps.
Then you only select for instance in Cura the filament type and the rest is handled via macros:

Then depending on the filament type one could control fans and stuff.

To get Mainsail properly showing additional information my start code in Cura looks like follows:

;Filament weight = {filament_weight}
;Nozzle diameter = {machine_nozzle_size}
;Filament type = {material_type}
;Filament name = {material_name}
PRINT_START BED_TEMP={material_bed_temperature_layer_0} HOTEND_TEMP={material_print_temperature_layer_0}

Meaning those parameters are already available and can be passed to Klipper.
Due to other topics I was not yet able to check if it is feasible…

1 Like

Klipper Screen is the only front end that I’m aware of that has this feature: Preheat Options. It stores additional fields. I think they exclusively mean “heaters” but I like the idea of arbitrarily settings stored with a preset. Some use-cases that come to mind:

  • Is the chamber fan/filter required for this filament type? What fan speed?
  • Does this filament need to hit a chamber temperature before printing? (PLA=False, ABS=True)
  • What temp should the Extruder be during the homing & probing phase (e.g. Voron Tap hit the bed so you are limited to 170C max, PETG likes to ooze so maybe that’s different)
  • Storing a retraction setting for the filament type to be used in test prints
  • Storing a generic pressure advance value to be used in test prints
  • In your multi-tool printer, do you want different tool parking and purging behavior based on filament type?

I don’t think we need to solve all of these things. We just need a way to store the data associated with the preset. I think we have some options:

  1. You could DIY this with [save_variables] by keeping all this data in some other place and looking it up based on the name of the filament preset.
  2. The Filament system could store all of this for you as fields on the preset

I’m going to look into how practical the second option is to do well.

Another feature that the front ends have is running some gcode after the preset is clicked.

I think the best way we can handle that is by invoking a macro. Pass in the preset, extruder name and extruder index to the macro, which is something none of the front ends do. That way you don’t have to write a new macro for each filament, you can just write 1 macro and vary its behavior based on the extruder and preset. This is something that I think can be set up from the klipper config. If you need a whole block of gcode you can put that in your macro.

Ok, here is my very specific suggestion-as-code: GitHub - garethky/filaments-klipper-extra: A Klipper plugin that does basic filament management for extruders in the printer

I’ll take feedback and suggestions here or on github. I haven’t had a chance to run the multi-tool code paths as I don’t have that printer running right now. Ive tried all of he single-tool code paths, I think.

If you generally like what you see I’ll reach out to the front ends and see what they think.

I set up some macros and Fluidd makes them into buttons that make this easy to live with:

Clicking a filament button does not heat anything up, it just set that as the current filament.
It would be pretty easy to do something similar in Klipper Screen. the only thing the both cant do it display a value from Moonraker in a label, so I cant see what the current filament is.

I worked out where the spare pins are on my SKR 1.4s so I could squeeze one more extruder config out of them. Here is what I got up to:

  • multi-tool testing
  • Use EXTRUDER=[name] rather than tool index in arguments, more like SET_PRESSURE_ADVANCE
  • Use the active extruder on the toolhead if no extruder argument is given. This means 99% of people wont ever need that EXTRUDER argument.
  • Switch to register_mux_command to avoid handling invalid extruder names
  • Merged LIST_FILAMENTS and SHOW_FILAMENT into a single QUERY_FILAMENTS command. QUERY_* naming convention is used on other modules to print state to the console.
  • Extruder objects (printer.extruder*) now contain the filament key that has the preset assignment. This should make integration with front ends much easier as they already iterate the extruder objects. I’m sure we can find a clean way to do this if its integrated into klipper directly, but for now its done by wrapping the get_status method on PrinterExtruder.
  • Renamed UNSET_FILAMENT to CLEAR_FILAMENT. UNSET didn’t have a naming precedent but CLEAR did.
  • SET_FILAMENT and CLEAR_FILAMENT now print a message about what just happened
  • readme updated

Some minimal edits to Fluidd’s code and it displays Filament Preset, nozzle diameter and an Active Extruder marker in the Thermals panel. Its looping over the “Heater” objects but these are really extruder objects so its an easy thing to drop in with this extension.

2 Likes

I read this thread with interest because it seems like your project might have some application for something I’m about to work on. I’ve got a 6-in-1-out setup. Right now, when I slice a model I have to make sure the slicer’s filament-to-extruder settings match what’s actually loaded in the printer. While that’s certainly not too much to ask, what I’d really like to be able to do is tell Klipper which filament is loaded in which extruder, and then make the slicer extruder-agnostic so at tool changes the gcode just identifies what filament to use, and Klipper selects whatever extruder that filament is actually loaded in. I’d even like it to be able to warn at print start if the gcode calls for a filament that’s not currently loaded.

I think I can implement this entirely in jinja via macros, but this thread has me enamored by the idea of having GUI controls. Do you think this use case is within the scope of your project?

What do you mean by “6 in 1 out? Is that like MMU/ERCF? My understanding of those setups is limited. If this is the case do you have a sample config I could look at?

Functionally yes, it’s very similar to MMU/ERCF in that there’s one hotend with one nozzle and a direct-drive extruder (pancake stepper + BMG clone), and filament is loaded into and out of it during the print as necessary. But the mechanism is (in my opinion) much simpler than the MMU/ERCF approach. I have a 6-to-1 splitter that feeds into the hotend. “Upstream” of the splitter are 6 extruders each with its own stepper.

In Klipper parlance, the direct-drive extruder on the hotend is the only “extruder,” and each of the six upstream steppers is an “extruder stepper.” The filament-loading procedure consists of syncing the appropriate extruder stepper with the extruder and then advancing the loaded filament through the splitter into the hotend, and then purging out the previous filament before proceeding with the print. Unloading the filament consists of withdrawing the loaded filament to a position just “upstream” of the splitter to clear the path for whatever filament gets loaded next.

My config file is an unholy mess at the moment, as it (like my printer) seems to be in a never-ending state of experimentation/evolution. (I’m using three different control boards in addition to the Pi). But here are some decluttered excerpts related to filament handling:

[EDIT: Deleted macros because they were untested and full of bugs at the time.]

As you can see, I’m already doing some storing of filament data, both to variables and to disk, to keep track of relevant properties of whatever filament is loaded in the hotend (extruder). Eventually I want to do something similar to track what’s loaded in the upstream extruder steppers.

1 Like

Ok, in that case this should work. The filament is assigned to an extruder object. I had thought about MMU type configs but generally they don’t have different filament types (e.h. they run all PLA). And they also only have 1 extruder object form what I can see. So I’m not sure how to really support those configs. Maybe there is someone that has made a “Virtual Extruder” extra that will represent each filament as an extruder without having a stepper. Anyway, that’s not your setup!

This extra should let you assign a filament to the main extruder on tool change. You can assign a filament to each of the sub-extruders and then copy that on filament change. You can store the type, color, and purge volume in the extra data of the filament:

SETUP_FILAMENT NAME='Prusament Carmine Red' EXTRUDER=250 BED=85 COLOR='#8B0000' TYPE='PETG' PURGE_VOLUME=15.0

(Python Literal rules apply, so strings need quotes)

What are you using the color for? I think that the rest of the params make sense but color sort of implies that you have several filament of the same “Type” each with a different color. I’ve been considering this something that I’ll leave up to the slicer. Same for pressure advance.

I’d be super happy to get some feedback if you use it!

Color discussion here: Macro snippet to calculate the Euclidean distance between filament colors

In short, I’m trying to work out some math that will optimize purge volumes on material changes based on the colors of the filaments being switched.

I get it. That’s interesting.

This system only has 1 filament object per preset. So you cant create a “PETG” preset and then assign it to 2 extruders and have each with a different color. You would have to make “PETG Red” and “PETG Blue” and assign accordingly.

I don’t want this to turn into Ocroprint’s filament manager (FilamentManager). That’s kind of where color probably belongs, associated with a Spool rather than a filament type. Maybe that would be a good app built on top of Moonraker.

Maybe there is a point to merge this idea with the similar approach to save pressure advance settings in Klipper:

https://github.com/zellneralex/klipper_config/blob/master/pressure_advance.cfg

I think there is also point to store pressure advance settings as well, as those may vary across filaments. :slight_smile:

You can do this. The PA value can be stored as a custom variable when you configure the filament:

SETUP_FILAMENT NAME=PLA NOZZLE=240 BED=60 PRESSURE_ADVANCE=0.3

The you can access this value from the extruder object and use it to set PA, maybe in your PRINT_START macro:

SET_PRESSURE_ADVANCE ADVANCE={printer.extruder.filament.pressure_advance}

Personally I’m not happy with this solution. I find that PA is impacted by many factors:

  • Nozzle size
  • Brand
  • Printing Temp
  • Flow Rate/Extrusion Multiplier

So I’m not trying to solve all of that in Klipper. I keep the info in Prusa Slicer as Filaments. I didn’t want to make a filament for every nozzle size x brand combination so I’m doing this in my filament custom gcode:

SET_EXTRUDER_PA NOZZLE=0.25 ADVANCE=0.060 EXTRUDER={filament_extruder_id}
SET_EXTRUDER_PA NOZZLE=0.4  ADVANCE=0.045 EXTRUDER={filament_extruder_id}
SET_EXTRUDER_PA NOZZLE=0.6  ADVANCE=0.040 EXTRUDER={filament_extruder_id}
SET_EXTRUDER_PA NOZZLE=0.8  ADVANCE=0.030 EXTRUDER={filament_extruder_id}

And the SET_EXTRUDER_PA macro will only apply the PA setting if that nozzle is installed in that extruder. I updated it to incorporate your idea, so if you don’t specify PA it will default to a value from the filament object first (still needs more testing though!):

[gcode_macro SET_EXTRUDER_PA]
gcode:
    #{% set flow = (params.FLOW | float) | default(100.0) %}
    {% set extruder = 'extruder' + (params.EXTRUDER | default('')) %}
    {% if extruder == 'extruder0' %}
        {% set extruder = 'extruder' %}
    {% endif %}
    {% set extruder_nozzle_diameter = (printer[extruder]).nozzle_diameter %}
    {% set nozzle = (params.NOZZLE | default(extruder_nozzle_diameter) | float) %}
    # option 1, get the default PA value from the current filament
    {% set advance = params.ADVANCE | default((printer[extruder]).filament.pressure_advance) | float %}
    # option 2, fall back to the default PA value from the config file
    {% if not advance %}
        {% set advance = printer.configfile.config[extruder].pressure_advance %}
    {% endif %}

    {% if nozzle == extruder_nozzle_diameter %}
        SET_PRESSURE_ADVANCE EXTRUDER={extruder} ADVANCE={advance}
        {action_respond_info("Pressure Advance Set: Extruder: %s Nozzle: %f Pressure Advance: %f" % (extruder, nozzle, advance))}
        # TODO: How do we handle per-extruder flow rate?
        #M221 S{flow}
    {% endif %}

I still don’t have per-extruder flow rate compensation solved yet but that’s a level of tweaking I very rarely need.

this works really well but lately, the custom properties for the presets completely broke for me. it just errors on my end for some reason

Thanks for reporting, I see your comment in git hub as well: unknown config object 'save_variables' when including filaments into the config · Issue #2 · garethky/filaments-klipper-extra · GitHub

Can you post the output of the QUERY_FILAMENTS command. It should show which filament is currently assigned to the extruder.

// Current Filaments:
14:46:48
// extruder: pla - 215/60
14:46:48
// Filament Presets:
14:46:48
// pla - 215/60
// ASA - 250/100
// PBT - 260/75
// HDPE - 230/110

I do have a peram called PA set on those btw. I can give you my variable file if need be