Klipper Config shared_heater Deprecated

A while back I upgraded my Ender 5 Pro with a BigTreeTech Octopus V1.1 and added four extruders to utilize all eight stepper drivers available. The extruders are attached with a 5-in-1-out PTFE tube adapter so they all feed into a single nozzle. When I installed the new control board, I also switched to the Klipper firmware. I already had an OctoPi and continued running that for a bit.

Well, the other day I finally took the plunge and gave Fluidd a try. Once I got it up and running, I was greeted with a whole bunch of errors — one of them being that the shared_heater option is deprecated and will be removed soon.

The shared_heater Method

We’ll start with a little background info on how it was configured before. Skip down a bit if you just want to see the new working config.

In my Klipper configuration (printer.cfg) I had defined the first extruder section as usual with the stepper and heater values.

# Driver3 - Extruder #1 (T0)
[extruder]
step_pin: PG4
dir_pin: !PC1
enable_pin: !PA0
microsteps: 16
rotation_distance: 32.68
nozzle_diameter: 0.400
filament_diameter: 1.750
heater_pin: PA2 # HE0
sensor_pin:  PF4 # T0
sensor_type: EPCOS 100K B57560G104F
control: pid
pid_Kp: 21.527
pid_Ki: 1.063
pid_Kd: 108.982
min_temp: 0
max_temp: 260
min_extrude_temp: 180
max_extrude_only_distance: 150
pressure_advance: 0.60
pressure_advance_smooth_time: 0.080

The additional four extruders were configured using the shared_heater parameter as shown below.

# Driver4 - Extruder #2 (T1)
[extruder1]
step_pin: PF9
dir_pin: !PF10
enable_pin: !PG2
microsteps: 16
rotation_distance: 32.68
nozzle_diameter: 0.400
filament_diameter: 1.750
shared_heater: extruder
max_extrude_only_distance: 150
pressure_advance: 0.60
pressure_advance_smooth_time: 0.080

My tool change gcode macros looked like this.

[gcode_macro T0]
gcode:
	ACTIVATE_EXTRUDER EXTRUDER=extruder
	SAVE_VARIABLE VARIABLE=currentextruder VALUE='"extruder"'

[gcode_macro T1]
gcode:
	ACTIVATE_EXTRUDER EXTRUDER=extruder1
	SAVE_VARIABLE VARIABLE=currentextruder VALUE='"extruder1"'
# ...and so on...

Finally, I had a startup gcode macro that would activate the last used extruder after a reboot. That way it can still retract the filament before switching to another extruder and loading its filament.

[delayed_gcode STARTUP_GCODE]
initial_duration: 0.1
gcode:
	{% set svv = printer.save_variables.variables %}
	ACTIVATE_EXTRUDER extruder={svv.currentextruder}
	{ action_respond_info("Current extruder: " + svv.currentextruder) }

This method worked great while I was still running OctoPrint on my Pi.

The extruder_stepper Method

The Klipper configuration documentation recommends replacing any shared_heater extruder with an [extruder_stepper] section.

It took me a bit of trial and error to figure out what options were needed and in what sections. Maybe it’s just me, but I found the Klipper documentation to be a little confusing… perhaps it was because I had a solid mental image of how the shared_heater works and the new method approaches the problem from a different angle.

In this new approach, only one “real” [extruder] needs to be defined (including all the heater, sensor, pressure advance, etc. definitions). The other extruders are defined in an [extruder_stepper] section and then those are either synchronized (or not synchronized to) to the “real” extruder. Hopefully this makes more sense in a minute. My extruder #1 configuration is shown below.

# Driver3 (Extruder 1 / T0)
[extruder]
step_pin: PG4
dir_pin: !PC1
enable_pin: !PA0
full_steps_per_rotation: 200
microsteps: 16
rotation_distance: 32.68
nozzle_diameter: 0.400
filament_diameter: 1.750
heater_pin: PA2 # HE0
sensor_pin:  PF4 # T0
sensor_type: EPCOS 100K B57560G104F
control: pid
pid_Kp: 21.527
pid_Ki: 1.063
pid_Kd: 108.982
min_temp: 0
max_temp: 260
min_extrude_temp: 180
max_extrude_only_distance: 150
pressure_advance: 0.60
pressure_advance_smooth_time: 0.080

The [extruder_stepper] section defines a stepper motor and nothing else — no heater or sensor, no nozzle size, no pressure advance value. The only new option is extruder to specify another extruder to synchronize this stepper to. I left these empty in the config file so that at startup none of the extra steppers are synchronized. Extruders #2 through #4 are shown below.

# Driver4 (Extruder 2 / T1)
[extruder_stepper extruder1]
extruder: 
step_pin: PF9
dir_pin: !PF10
enable_pin: !PG2
full_steps_per_rotation: 200
microsteps: 16
rotation_distance: 32.68

# Driver5 (Extruder 3 / T2)
[extruder_stepper extruder2]
extruder: 
step_pin: PC13
dir_pin: !PF0
enable_pin: !PF1
full_steps_per_rotation: 200
microsteps: 16
rotation_distance: 32.68

# ...and so on...

If I command the extruder to move at this point (G1 E5), only extruder #1 (extruder) will move. The next step is to add the tool change macros to switch which extruder is active (synchronized). I defined my T0/T1/T2/T3/T4 macros as shown below. Basically each macro synchronizes the desired extruder (or extruder_stepper) to extruder (extruder #1, the “real” extruder) and sets all other extruders to synchronize to nothing. Finally each Tn macro saves the tool to a variable named active_tool (I renamed it from currentextruder before).

[gcode_macro T0]
gcode:
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder" MOTION_QUEUE="extruder"
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder1" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder2" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder3" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder4" MOTION_QUEUE=""
	SAVE_VARIABLE VARIABLE=active_tool VALUE='"T0"'

[gcode_macro T1]
gcode:
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder1" MOTION_QUEUE="extruder"
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder2" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder3" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder4" MOTION_QUEUE=""
	SAVE_VARIABLE VARIABLE=active_tool VALUE='"T1"'

[gcode_macro T2]
gcode:
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder1" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder2" MOTION_QUEUE="extruder"
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder3" MOTION_QUEUE=""
	SYNC_EXTRUDER_MOTION EXTRUDER="extruder4" MOTION_QUEUE=""
	SAVE_VARIABLE VARIABLE=active_tool VALUE='"T2"'

# ...and so on...

Now my STARTUP_GCODE macro looks like this. It is also where I set the pressure advance of each extruder since the pressure_advance definition is not valid in extruder_stepper sections.

[delayed_gcode STARTUP_GCODE]
initial_duration: 0.1
gcode:
	{% set svv = printer.save_variables.variables %}
	{% if svv.active_tool != "" %}
	{ svv.active_tool }
	{% else %}
	T0
	{% endif %}
	{ action_respond_info("Active Tool: " + svv.active_tool) }
	set_pressure_advance extruder=extruder advance=0.60 smooth_time=0.08
	set_pressure_advance extruder=extruder1 advance=0.60 smooth_time=0.08
	set_pressure_advance extruder=extruder2 advance=0.60 smooth_time=0.08
	set_pressure_advance extruder=extruder3 advance=0.60 smooth_time=0.08
	set_pressure_advance extruder=extruder4 advance=0.60 smooth_time=0.08

Just for completeness, below is my configuration for the TMC2209 drivers when using extruder_stepper sections.

[tmc2209 extruder]
uart_pin: PC7
run_current: 0.750

[tmc2209 extruder_stepper extruder1]
uart_pin: PF2
run_current: 0.750

[tmc2209 extruder_stepper extruder2]
uart_pin: PE4
run_current: 0.750

# ...and so on...

With all of that in place I was finally able to programmatically switch between extruders. Of course there are additional macros for loading and unloading filament and everything else, but regarding the shared_heater to extruder_stepper migration, I hope this helps!