Creating vitual tools for color change



  • So all my printers have single extruder/hotend setups. With S3D I previously made a few print files (very manual process), to use different filament on the same layers, using simple M600 command to change the filament (from the video by Make Anything on YouTube).

    Most modern slicers now allow a form to create the gcode files for this (including PrusaSlicer, with its "Single extruder multi material").

    However with that setting on, it is still generating T commands (for tools that don't exist). While I can easily go through and remove them one by one (a lot less work than what I did for S3D), it is still a manual process of editing the gcode.

    I have now attempted to create a few virtual tools in RRF, but it is showing all of them on the PanelDue and DWC, which is not ideal.

    Ideally I want a message prior to any filament change specifying the tool, from the slicer, prior to me having to change the filament (using M291). So basically anytime there is a T command where it is higher than -1 (is used to deselect), simply show a message for a few seconds (non blocking, so that M600 can cause the pause, displaying the new tool number) and then run the M600, without actually going to the new tool (still use T0). How would I go about configuring this?


  • administrators

    @Jacotheron There are two general approaches to this:

    1. use a script to post process the gcode to replace the Tn commands with the M291 ... , M600 commands.

    2. Create multiple tools, using the same heater, drive etc in config.g and then use the tool change files to prompt you to change the filament. This does mean the multiple tools are visible in DWC.



  • @T3P3Tony Thank you for your reply.

    I am trying to go with option 1: creating a post process. I have a post-process that works directly in my command line, but having trouble getting it to work directly from PS (I have both a Perl and Python version). I have create support post in their support forum, as well as a issue in PS's github.

    When I get it working, I plan to post it here. My current code actually waits for a T1 (or higher tool number), before actually starting to work (this assumes the correct first filament is inserted, as I always do) which have the by-product of not doing anything unless a second tool is required.

    I also plan to use it to process a few other commands Duet have issue with (like PS's temperature setting, acceleration and other I might find later).

    Option 2 might have worked easier if the virtual tools could be hidden from DWC and PanelDue.



  • Ok my problem was solved, and I further improved my script (I called it duet-tool-change-strip.py)

    #! /usr/bin/python3-64
    # duet_toolchange-strip.py
    import fileinput
    import re
    import sys
    
    #first we define our regular expressions for a match
    extruder_0_pattern = re.compile('^T0') #the first of this is kept
    extruders_other_pattern = re.compile('^T([0-9])+') # match any extruder number (if you define 100, in PS, you can use all 100 or even more)
    empty_line = re.compile('^$') #we are stipping empty lines
    temp_set = re.compile('^M109 S([0-9]+)') #match the deprecated way to set a temperature
    temp_set_2 = re.compile('^M104 S([0-9]+)') #match second deprecated way to set temperature
    acceleration = re.compile('^M204 S([0-9]+)') #convert to Duet acceleration set
    
    #this variable to is to ensure it still work for single extruder prints
    print_have_started = 0
    for line in fileinput.input(inplace=True):
        if extruders_other_pattern.match(line):
            if (extruder_0_pattern.match(line) and print_have_started == 0):
                print(line.rstrip("\n")) #we keep the Tool as is.
                continue
            else:
                print_have_started = 1
                m = extruders_other_pattern.match(line)
                extruder_nr = m.group(1)
                print('M291 R"Tool Change" P"Tool #%s " S1 T30\nM600' % extruder_nr)
                continue
        else:
            if not empty_line.match(line):
                if temp_set.match(line):
                    m = temp_set.match(line)
                    print("G10 P0 S%s" % m.group(1))
                    continue
                if temp_set_2.match(line):
                    #void we don't want or need this line.
                    m = temp_set_2.match(line)
                    print("G10 P0 S%s" % m.group(1))
                    continue
                if acceleration.match(line):
                    m = acceleration.match(line)
                    print("M204 P%s" % m.group(1))
                    continue
                print(line.rstrip("\n")) #this is the default - we keep the line as is, if it is not empty
    

    So this script works as explained in a previous post, and now also correct the temperatures and acceleration for RRF. Note that PS adds its heatup command after your own starting Gcode, so if extruding in your starting, it is best to ensure the printer is heated before it.

    The acceleration, while PS generates the M204 commands, RRF does not know the S-parameter, here I convert the S to a P for print acceleration..

    Both 104 and 109 commands are converted to G10 commands, only setting the S (active temperature), so if you have set the standby, it is kept.

    The issue I had, was simply not calling Python directly before the script in the Print Settings > Post Processing scripts. I have used Python 3.8.5, which I placed at: C:\Python38\python.exe (if yours is installed in the default place, instead of wrapping the path in quotes, you should place a "!" before any space - https://manual.slic3r.org/advanced/post-processing). this gave me the entry in my Post-processing scripts as <path to python.exe>\python.exe <path to the script>\duet-toolchange-strip.py;

    Some people place the script in a subfolder in their PrusaSlicer installation, that can be overwritten on a new version. Place it in a safe location.

    As to a license for the above code: Public Domain. Modify, adapt, distribute as needed.
    There may be more efficient ways to do the same.



  • @Jacotheron said in Creating vitual tools for color change:

    #! /usr/bin/python3-64 # duet_toolchange-strip.py import fileinput import re import sys #first we define our regular expressions for a match extruder_0_pattern = re.compile('^T0') #the first of this is kept extruders_other_pattern = re.compile('^T([0-9])+') # match any extruder number (if you define 100, in PS, you can use all 100 or even more) empty_line = re.compile('^$') #we are stipping empty lines temp_set = re.compile('^M109 S([0-9]+)') #match the deprecated way to set a temperature temp_set_2 = re.compile('^M104 S([0-9]+)') #match second deprecated way to set temperature acceleration = re.compile('^M204 S([0-9]+)') #convert to Duet acceleration set #this variable to is to ensure it still work for single extruder prints print_have_started = 0 for line in fileinput.input(inplace=True): if extruders_other_pattern.match(line): if (extruder_0_pattern.match(line) and print_have_started == 0): print(line.rstrip("\n")) #we keep the Tool as is. continue else: print_have_started = 1 m = extruders_other_pattern.match(line) extruder_nr = m.group(1) print('M291 R"Tool Change" P"Tool #%s " S1 T30\nM600' % extruder_nr) continue else: if not empty_line.match(line): if temp_set.match(line): m = temp_set.match(line) print("G10 P0 S%s" % m.group(1)) continue if temp_set_2.match(line): #void we don't want or need this line. m = temp_set_2.match(line) print("G10 P0 S%s" % m.group(1)) continue if acceleration.match(line): m = acceleration.match(line) print("M204 P%s" % m.group(1)) continue print(line.rstrip("\n")) #this is the default - we keep the line as is, if it is not empty

    Thanks a lot, this works great. I am not very gifted in programing but was wondering if there was a way to have the script add in an automatic unload command with each pause? Also possibly a automatic hotend cool down to off (temp not cancel the print), if print is not resumed in say 5 minutes. Just in case I am not able to get to it in time to swap filament right away. This is what my Prusa Mk3s does when running manual filament changes.



  • For the Unload command (similar to the M600), you can set that in your PrusaSlicer's Tool Change gcode, the command for that would be: M702 (I guess you would want this prior to M600).

    Another option is to insert the M702 in your M600 macro (filament-change.g in /sys). This will automatically do the Unload for you.

    Regarding the the automatic cooldown, I have not seen any way to do this yet. For me, I am typically close to the printer while printing, and especially if there is a need to change filament, I am on standby for it (so the filament don't cook in the nozzle).


Log in to reply