Mixing Hotend/M163 Emulation

G’day! I wanted to share my Macro and configuration for a Mixing Hotend, allowing any mix between 2 extruders.

There are some caveats to the way this is done, as it is modifying the rotation distance on the fly to change how much each extruder is extruding, it does have an affect on things like retractions, or manual extrusion distances when a mixed tool is selected.

Usage for the M163 is:
M163 Px
Where x is there percentage for extruder 0, so M163 P40 would be a 40/60 mix.
To emulate the 0-100 gradient that Marlin usually has in the menus for these mixing printers, this can be added to your “After Layer change G-code” in your slicer:

M163 P{(layer_num < 2 ? 0 : (layer_num*100 - 2) / (total_layer_count - 2))} ; Gradient 0-100

Set your rotation distances as follows:
e0rotdist = extruder 0 rotation distance
e1rotdist = extruder 1 rotation distance

[gcode_macro T0]
gcode:
    # Deactivate stepper in motion queue
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=
    SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder DISTANCE={e0rotdist}
    # Activate stepper in motion queue
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=extruder

[gcode_macro T1]
gcode:
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=
    SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder1 DISTANCE={e1rotdist}
    # Activate stepper in motion queue
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder

[gcode_macro T2]
gcode:
    SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder DISTANCE={e0rotdist *2} # 50%
    SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder1 DISTANCE={e1rotdist *2} # 50%
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=extruder # Add e0
    SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder # Add e1
    

# Usage - M163 PX (X = 0-100, indicated percentage of first extruder in the mix, so P40 will be 40/60 mix)
[gcode_macro M163]
gcode:
  {% set rot_dist0 = params.ROT_DIST_0|default(e0rotdist)|float %} # define in default the rotation distance of the extruder
  {% set rot_dist1 = params.ROT_DIST_1|default(e1rotdist)|float %} # define in default the rotation distance of the extruder
  {% if 'P' in params %}
	  {% if params.P|float == 0  %}
		#Set T0
	    SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=
	    SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder DISTANCE={rot_dist0}
	    SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=extruder
    {% elif params.P|float == 100 %}
		# Set T1
	    SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=
	    SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder1 DISTANCE={rot_dist1}
	    SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder
	  {% else %}
    # Set Mix
		  SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder DISTANCE={ rot_dist0 * 100/(100-params.P|float) }
		  SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=extruder # Add e0
		  SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder # Add e1
		  SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder1 DISTANCE={ rot_dist1 * 100/params.P|float }
	  {% endif %}
  {% else %}
      # default 50% mix
      SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder DISTANCE={rot_dist0 * 2 }
      SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=extruder # Add e0
      SYNC_EXTRUDER_MOTION EXTRUDER=extruder1 MOTION_QUEUE=extruder # Add e1
      SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder1 DISTANCE={rot_dist1 * 2 }
  {% endif %}

4 Likes

I developed this separately for my Z9V5 but I’m pretty sure you can just pull the rotation distance from each extruder.

also, your math has a few issues with it. I found that multiplication over-extruded, division is need, but you need to add a very small number to the value to prevent division by zero errors

[gcode_macro MIX]
gcode:
  {% set A = params.A|default(0.25)|float %}
  {% set B = params.B|default(0.25)|float %}
  {% set C = params.C|default(0.25)|float %}
  {% set D = params.D|default(0.25)|float %}
  {% set rot = 7.71 %}
  SYNC_EXTRUDER_MOTION EXTRUDER=extruder MOTION_QUEUE=extruder
  SYNC_EXTRUDER_MOTION EXTRUDER=extruder_1 MOTION_QUEUE=extruder
  SYNC_EXTRUDER_MOTION EXTRUDER=extruder_2 MOTION_QUEUE=extruder
  SYNC_EXTRUDER_MOTION EXTRUDER=extruder_3 MOTION_QUEUE=extruder
  SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder DISTANCE={rot/(A+0.0001)}
  SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder_1 DISTANCE={rot/(B+0.0001)}
  SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder_2 DISTANCE={rot/(C+0.0001)}
  SET_EXTRUDER_ROTATION_DISTANCE EXTRUDER=extruder_3 DISTANCE={rot/(D+0.0001)}

this is what I wrote but I still need to calibrate my bmgs on that printer and install an ssr for the new bed. rot was set of all 4 for they’re all very different it seems

1 Like

G’day! I appreciate the input and feedback!
interesting that you saw an extrusion difference, theoretically if the math is the same it should work out the same.

Rather than adding the small amount, you may notice in mine I instead catch those cases in the if statements, similar result in the end though :slight_smile:

Nice to see some others working on mixing in Klipper in the past few years I’ve had my shelved for other projects.

yeah, though zonestar’s hotends are god-awful, everything else works fine. I found a different mixing hotend that, although heavier, can be all metal.

Hi . Is this macro for a single hotend with 2 independent extruder motors for each color ?