load unload macro with endless loop and cancel condition



  • Hi there,
    mighty duet-folks,

    has anybody played around in the new RRF3.x with loops and the corresponding break-out-conditions?

    Would like to make a filament load and unload where the process of the actual e-movements for e.g. 5 seconds is repeated endless with a small pause of around 2 seconds between each un-/load. The reason for it is
    a) when changing colours to use the load already as purge to wait as long until happy with the filamentcolour
    b) when tightening the "tension-screw" for a BMG (double-gear-extruder) to have some time to play around

    cancel/break-out could be via a user-interaction via the duet-display or DWC (and of course for security reasons after an absurd high number of loops like 25 or so)...

    Ideas are heartly welcomed - somebody please help me where to start...


  • administrators

    So you could try using a combination for M291 and M292 within the loop (I have not tried this. basically the idea would be to prompt the user to cancel, using M291, if the user does not press the cancel button within a set dwell time (defined by G4) then you use M292 to cancel the message and repeat.

    The "iterations" counter can be used for the >25 loops test.

    https://duet3d.dozuki.com/Wiki/GCode_Meta_Commands#Section_Named_constants



  • It doesn't fit exactly your criteria as I've used distance rather than time, but I have just started using the filaments macros and have this far done this for each filament type. The move code is used for all filaments.
    A couple of bits of code may be redundant because RRF already seems to checks the condition, but I was playing it safe.

    Typical filament files.

    load.g (Filaments Directory)

    ;; load.g
    ;;
    M291 R"Loading ABS" P"Loading config and heating" S1 T3
    G4 S3
    M703 ; load config.g of this filament
    
    ; only run if not in a job
    if job.file.fileName!=null
    	M291 R"Cancel loading" P"Print job in progress. Skipping load moves" S1 T5
    	M99;
        
    ;check if ABS is already loaded   
    if move.extruders[state.currentTool].filament="ABS"
    	M291 R"Cancel loading" P"Filament already loaded.  Skipping load moves" S1 T5
    	M99;
    ;we know ABS isn't loaded, but if something else is, we need to unload it first
    ; this part of the code is untested!!
    if move.extruders[state.currentTool].filament!=null
    	M98 P"0:/filaments/" ^ {move.extruders[state.currentTool].filament} ^ "/unload.g"
            M291 R"Unload finished" P"Press OK when ready to load new filament" S3 
        
    M291 R"Loading ABS" P"Waiting for nozzle loading temperature..." S1 T0
    M98 P"0:/macros/heating/preheat_ABS.g"
    M116                            ; Wait for temperature
    M291 R"Loading ABS" P"Feeding and priming..." S1 T0
    M98 P"/macros/filament/do_moves_for_load.g"
    M292                            ; Clear messages
    

    "do moves for load.g"
    Does max five loops and prompts to feed 120mm on each loop.
    I have a bowden, so this equates to longer than the bowden tube if needed.

    do_moves_for_load.g (/macros/filaments/ directory)

    ;do moves for load.g - run when filament change is required.
    M291 P"loading do_moves_for_load.g" S1 T0
    M400 ; wait for any moves
    if (state.currentTool=-1) || ({heat.heaters[tools[state.currentTool].heaters[0]].current < heat.coldExtrudeTemperature})
        M291 P"No tool active or temp to low for loading" R"Can't proceed" S1 T10
        abort;
    M83 ; set relative extrusion
    while true
        if iterations = 5
           break
        M291 P"Press OK to feed 120mm of filament or CANCEL to abort" R"Ready"  S3
        M291 P"Feeding filament..  Please wait" R"Feeding"  S1 T45
        G1 E120 F180 ; feed 120mm to load filament
        G1 E-2 ; Retract 2mm to reduce pressure
        M400 ; wait for moves to finish
        M292 ; Clear messages
        
    M400 ; wait for moves to finish
    M291 R"Done" P{move.extruders[state.currentTool].filament} ^  " Filament loaded.  Clear nozzle to proceed" S3  
    

    config.g (filaments/ABS directory)

    ; Used to set parameters for filament such as retracts, temperatures etc
    M291 P"loading config.g for ABS" R"Loading config" S1 T5
    M302 S200 R120 ; set cold extrude and retract temperatures
    ;M592 D0:1 A0.012 B0 ; Set non linear extrusion
    M572 D0 S0.08 ;Set pressure advance
    M207 S0.7 F2400  Z0	; Set retraction
    ;M593 F25  ; cancel ringing at 25Hz
    

    preheat_ABS.g (macros/heating directory)

    M291 R"Preheating" P"Setting preheat temperatures" S1 T0
    if state.currentTool=-1
    	T0
    M140 S90 R50               ; set bed temp
    M703 ; load config.g for this filament
    G10 P0 S{heat.coldExtrudeTemperature+10} R{heat.coldRetractTemperature+5}        ; set tool temps
    M116 ; wait for temps
    M291 R"Preheating" P"Preheating... Done" S1 T5
    

    In Prusa Slicer I have this in the start code.
    This will load all the specific temp and other settings in the filament config.g like retraction etc for the specified filament.
    It can be tricky using meta commands because Prusa Slicer has its own conditional code which can confuse thing, but between the two you can have very powerful and prtable code..

    T[current_extruder] ; select tool 
    M104 S0 R0 T[current_extruder] ; Set temps to zero to stop slicer adding them
    M106 P[current_extruder] S0 ;Start with fan off
    M701 S"[filament_type]"; define filament 
    ; All retraction and temp settings done in 0:/filaments/[filament_type]/config.g
    M703 ; load config file for [filament_type]
    M291 S0 T3  P"Homing..."
    G32 ; Level bed & home
    M400 ; wait for last move
    M83 ; Set relative extrusion
    ;G4 S4 ; Wait 4 Seconds for PanelDue only required if M80 is used
    M98 P"0:/macros/songs/charge.g" ; play start tune
    G4 S4 ; Wait 4 Seconds for song
    G21 ;metric values
    G90 ; Switch to using Absolute Coordinates
    G4 S1 ; Wait 1 Second
    M280 P0 S160 I1 ; Reset BL Touch
    M280 P3 S90 I1 ; Retract proibe
    M140 S[first_layer_bed_temperature_0]  R{first_layer_bed_temperature[0] /2 }; Set fast bed temp & standby - Standby is half first layer temp.
    M116 ; Wait for bed before doing mesh probe.
    M561 ; clear any bed transform
    M557 TBD  ; parameters will be set automatically to suit size of printed area
    G29 S0  ; do mesh for printed area
    G29 S1  ; load small mesh
    G01 X{"{move.axes[0].min }"} Y{"{move.axes[1].max}"} Z0.6  F1500 ; Move to back corner while heating
    G10 P0 R{"{heat.coldExtrudeTemperature+5}"} S[first_layer_temperature_0] T[current_extruder] ; (set standby and active temperatures for active tool.  Standby is 5 degrees above cold extrude temp )
    M118 P3 S" Waiting for temps..."
    G4 S1 ; Wait 1 Second
    M116 ; Wait for all temps to stabilise
    G1 X1 Y{"{move.axes[1].max -10 }"} Z0.4 F1200 ; move to edge to wipe any oozed filament
    G1 X1 Y{"{move.axes[1].min +10 }"}  F600 E15; move and extrude
    G1 X{"{move.axes[0].min +1}"}
    G1  Y{"{move.axes[1].max -10 }"}  F600 E15; move and extrude
    G10 ; Retract
    G1 X{"{move.axes[0].min +50}"} F1200 ; wipe
    M118 P3 S" Printing..."        ;Put printing message on screen
    


  • @OwenD said in load unload macro with endless loop and cancel condition:

    > M98 P"0:/filaments/" ^ {move.extruders[state.currentTool].filament} ^ "/unload.g"
    

    @LB

    The above code in load.g is wrong.
    It should be
    Also filaments doesn't return null if there isn't one loaded, it returns an empty string""

    M98 P{"0:/filaments/" ^ {move.extruders[state.currentTool].filament} ^ "/unload.g"}
    

    The extra curly braces are required to form a proper filename parameter.

    Note that RRF doesn't allow you to change filaments from within a print file using M701.

    It returns an error, however it does not cancel the print!

    You can call the macro using M98, but that's kind of working against the checks RRF has in place, which is that you would manually unload an existing filament before trying to load a new one.
    I can see a case for both methods. With enough sensors etc, fully automated loading would be possible.

    Following more testing I have settled on this (for now 😁 )

    ;; load.g
    M291 R"Loading ABS" P"Loading config and heating" S1 T3
    M302 S210 R120 ; set cold extrude and retract temperatures
    
    ;check if no tool selected or if heater is off
    if state.currentTool=-1
    	T0 P0
    if heat.heaters[state.currentTool].state="off"
    	T0 P0
    	G10 P{state.currentTool} R0 S0
        
    M291 R"Loading ABS" P"Waiting for nozzle loading temperature..." S1 T0
    M98 P"0:/macros/heating/preheat_ABS.g"
    M116                            ; Wait for temperature
    
    ;check if ABS is already loaded   
    if move.extruders[state.currentTool].filament="ABS"
    	M291 R"Cancel loading" P"Filament already loaded.  Skipping load moves" S1 T5
    	M99 ; cancel macro but not print
    
    
    ; only run if not in a job (M701 won't allow this, but manually calling this macro is possible)
    ;if we want to auto load/unload at the start of a print we'd have to remove this
    
    if job.file.fileName!=null
    	M291 R"Cancel loading" P"Print job in progress. Skipping load moves" S1 T5
    	G4 S3
    	M99 ;cancel macro but not print
    
    ;we know ABS isn't loaded, but if something else is, we need to unload it first
    if move.extruders[state.currentTool].filament!=""
    	if move.extruders[state.currentTool].filament!="ABS"
    		M702 S{"{move.extruders[state.currentTool].filament}"}
    		M291 R"Unload finished" P"Press OK when ready to load new filament" S3
    		M701 S"ABS" ; this seems to be needed to update DWC if we unload first
     
    
    
    ; we check filament loaded again in case this is a second loop from an unload/reload above.
    if move.extruders[state.currentTool].filament!="ABS"
    	M291 R"Loading ABS" P"Feeding and priming..." S1 T0
    	M98 P"/macros/filament/do_moves_for_load.g"
    
    M292                            ; Clear messages
    

    I have also added M703 to 0:/sys/config.g to load any settings if a filament is already loaded for the active tool.



  • @T3P3Tony

    Thanks for the hint!

    @OwenD

    Impressive - to say the least..., will take a bit till I understand fully...



  • @OwenD

    M106 P[current_extruder] S0 ;Start with fan off
    -> Is P within M106 not the fan but the extruder?

    Do you have defined these variables like in "G10 P0 S{heat.coldExtrudeTemperature+10} R{heat.coldRetractTemperature+5}" or if not where can I find a "reference" about all predefined variables like these?

    And why do you specify [current_extruder] within M104 as T but not within G10 as P, since in the G-Code-Reference of duet both are the "tool number"?



  • @LB said in load unload macro with endless loop and cancel condition:

    @OwenD

    M106 P[current_extruder] S0 ;Start with fan off
    -> Is P within M106 not the fan but the extruder?
    M106
    Pnnn Fan number (optional, defaults to 0). (In RRF_3 relates to the fan number created by M950, NOT the fan pin number on the board)

    In my case the part fan is F0

    M950 F0 C"fan0" Q500                                        ; create fan 0 on pin fan0 and set its frequency
    M106 P0 C"Part_Fan" S0 B2.0 H-1
    

    However I also use a post processing script in Prusa Slicer to try to ensure that if there were multiple tools, the correct fan is selected (see below)

    Do you have defined these variables like in "G10 P0 S{heat.coldExtrudeTemperature+10} R{heat.coldRetractTemperature+5}" or if not where can I find a "reference" about all predefined variables like these?

    These are object model meta commands which refer to the values you set in M302.
    You woud typically set these in config.g , but it would be more accurate to have them in each filament config.g
    I found that the filament config.g isn't loaded until after the load.g is complete so in order to reference these values I had to put the M302 in the preheat macro for each filament.
    It would be nice if M703 accepted parameters so you could load the correct values at the start of a filament change.

    And why do you specify [current_extruder] within M104 as T but not within G10 as P, since in the G-Code-Reference of duet both are the "tool number"?

    Probably laziness 🙄
    At present I only use a single extruder, so it's not really an issue for me.
    I try to make everything I do as portable as possible, so that any hardware changes take as little re-writing of individual macros etc as possible.
    For accuracy and completeness it should be as you say.

    I should point out that I also have post processors in Prusa Slicer which adjust the code to suit RRF flavour better.
    In the case of G10 temps this will soon be possible within Prusa Slicer.
    At present M104 is used and will set both active and standby temps to whatever is in the slicer at every temp change

    #RRF-fixes.py
    # Save in Prusa Slicer Scripts folder
    # Add to Prusa Slicer post processing scripts
    
    import sys
    #open G Code fand store in memory "filedata"
    f = open(sys.argv[1],"r")
    filedata = f.read()
    f.close()
    # search filedata and put the results into newdata
    newdata = filedata.replace("M104 S","G10 S") # replace all M104 with G10
    # now we keep searching newdata
    newdata = newdata.replace("M109 S","G10 S") # replace all M104 with G10
    newdata = newdata.replace("M204 S","M204 P")  # replace all M204 S parameters with Parameter
    newdata = newdata.replace("M106 S","M106 P{tools[state.currentTool].fans[0]} S") # replace all M106 with code to select tool
    newdata = newdata.replace("M107","M106 P{tools[state.currentTool].fans[0]} S0") # replace all M107 with M1106 to turn off heater
    
    f = open(sys.argv[1],"w")
    f.write(newdata) # write info back to G Code file
    f.close()
    

    .
    I should also point out that my day job is making sparks and smoke (welding)
    I try not to bring that to coding, but "caveat emptor" applies if you use any of my code.
    😁



  • @OwenD
    AAHHH sorry bout the Fan-question with m106 - seems I mixed that up...

    "It would be nice if M703 accepted parameters so you could load the correct values at the start of a filament change." +1 here!

    Where did you pick up the
    M104 S0 R0
    Why do they have to be "zeroed", couldn´t just the filament-config.g temps get loaded instead?
    Doesn´t work yet I guess...?

    (Not your dayjob - woah, 💪 don´t make me fear my image in the mirror 😩 ...)



  • @LB said in load unload macro with endless loop and cancel condition:

    @OwenD

    Where did you pick up the
    M104 S0 R0
    Why do they have to be "zeroed", couldn´t just the filament-config.g temps get loaded instead?

    If there is no M104 in your start Gcode, prusa slicer (and others) will add it automatically.
    This just tricks the slicer into not doing that, so that all temps are as we intended.



  • This post is deleted!


  • @OwenD

    for some sort of end.g for the print files, I do not even get this to work:

    G1 X{"{move.axes[0].min+5}"} Y{"{move.axes[1].max-5}"} F500 ; position for easy part removal
    

    edit: seems to work with:

    G1 X{move.axes[0].min+5} Y{move.axes[1].max-5} F500 ; position for easy part removal
    

    yeah! juhuu my first conditional g-code... 😊

    O.K. next:

    ;set temps for all heaters to have time to cool down below 60°C touch-safe temp with an additional -5°C for safety to account for measurement-tolerances, what gives then 55°C
    ;make conditional: only if S>55 do the following, else skip:
    ;M104 S55				; turn extruder-heater off -> DEPRACTED in RRF>=3.x
    ;if T0 > S55
    ;G10 S55					; turn extruder-heater to a touch-safe temperature
    ;if P0 > S55
    ;M140 S55				; turn print-heat-plate to a touch-safe temperature
    

    Nobody here to know what the variable for the current heater0 & heater1 is or where I find an overview how these variables are called/named?



  • @LB said in load unload macro with endless loop and cancel condition:

    @OwenD

    for some sort of end.g for the print files, I do not even get this to work:

    G1 X{"{move.axes[0].min+5}"} Y{"{move.axes[1].max-5}"} F500 ; position for easy part removal
    

    edit: seems to work with:

    G1 X{move.axes[0].min+5} Y{move.axes[1].max-5} F500 ; position for easy part removal
    

    yeah! juhuu my first conditional g-code... 😊

    Yes, by using quotes you turned it into a string instead of a meta command

    You need to study this
    https://duet3d.dozuki.com/Wiki/GCode_Meta_Commands

    O.K. next:

    ;set temps for all heaters to have time to cool down below 60°C touch-safe temp with an additional -5°C for safety to account for measurement-tolerances, what gives then 55°C
    ;make conditional: only if S>55 do the following, else skip:
    ;M104 S55				; turn extruder-heater off -> DEPRACTED in RRF>=3.x
    ;if T0 > S55
    ;G10 S55					; turn extruder-heater to a touch-safe temperature
    ;if P0 > S55
    ;M140 S55				; turn print-heat-plate to a touch-safe temperature
    

    Nobody here to know what the variable for the current heater0 & heater1 is or where I find an overview how these variables are called/named?

    In DWC go to the settings section and select "Object Model"
    You can drill down to find what you want.
    You may have to update RRF & DWC to see it.
    You can also use M409 but it can't return the entire model.



  • @OwenD said in load unload macro with endless loop and cancel condition:

    In DWC go to the settings section and select "Object Model"
    You can drill down to find what you want.
    You may have to update RRF & DWC to see it.
    You can also use M409 but it can't return the entire model.

    Thanks so much!

    Where do I find the "settings" section for DWC -> on the project hosting page? At least I could not find anything in the webbrowser that´s named like this...


  • Moderator

    @LB I'm guessing you're not running the 3.2 beta, so if you're still on 3.1.1 you wouldn't see the object model browser.



  • @OwenD
    @Phaedrux
    Ah! Thanks -> have so much work with setting up the stuff, will wait for 3.2-alpha I guess...

    For now this should be enough: https://duet3d.dozuki.com/Wiki/Object_Model_of_RepRapFirmware#Section_Uses
    Combining with the
    https://duet3d.dozuki.com/Wiki/GCode_Meta_Commands#Section_Object_model_properties
    should work...
    (Saw that tree-structure in the first place but didn´t know what to do but reading slowly in I think I get the hold somehwere there 🙂 )



  • @OwenD
    @Phaedrux
    @T3P3Tony

    Thanks everybody,
    because of the code-snippets posted by you I was able to implement it in a way I am happy for now:

    duet2ethernet1.0.4 with RRF3.1.1

    load:

    ; https://duet3d.dozuki.com/Wiki/Filaments
    
    ; load.g
    
    
    
    if (state.currentTool=-1)
        M291 P"No tool active" R"Can't proceed" S1 T10
        abort;
    
    M703								;load from filament-config.g:
    G10 S235 							; Set current tool temperature S___ ,for PETG 230-255°C
    ;G10 S___							; get from filament-config.g
    
    M291 R"...heating up hotend..." P"...for loading filament..." S0 T100 				; Display message P=main-message R=secondary-message T=timer in sec
    
    ;https://duet3d.dozuki.com/Wiki/Gcode#Section_M116_Wait
    ;M116																			; Wait for ALL temperatures to be reached (if no secondary parameters like H, C or S are defined)
    M116 P0																			; Wait for P0=Tool0 to reach temp
    ;M116 P_			; make automatic for tool selected
    
    M292 ; Clear messages
    
    
    
    ; reliable max speed for extrusion seems to be below 10mm/s for PETG, retract can be higher
    M83 																			; Extruder to relative mode
    
    ;old style fix:
    ;G1 E50 F200 												; Feed+/Retract- E__mm of filament at F___mm/min
    ;G1 E250 F500 												; Feed+/Retract- E__mm of filament at F___mm/min
    ;M400 														; Wait for moves to complete
    ;G4 P5 														; Wait/Dwell P___ MILLIsecond(s), S___ second(s)
    ;G1 E-2 F1000 												; Feed+/Retract- E__mm of filament at F___mm/min
    
    ;new style interactive:
    M400 ; wait for moves to finish
    while true
        if iterations = 25
           break
        ;M292 ; Clear messages
        M291 P"Press OK to feed 50mm of filament (or CANCEL to abort)" R"Extrude?"  S3
        M291 P"...moving the filament..." R"...wait..."  S0 T50		; make long enough to be displayed longer then it takes to extrude
        G1 E50 F250 												; Feed+/Retract- E__mm of filament at F___mm/min
        G1 E-2 														; Feed+/Retract- E__mm of filament at F___mm/min
        M400 ; wait for moves to finish
        ;M292 ; Clear messages
    M400 ; wait for moves to finish
    
    
    
    M291 R"Done loading" P{move.extruders[state.currentTool].filament ^  " Filament"} S1			; Display new message
    ; set all back
    G10 S0 																			; Set current tool temperature S___
    ;M292 																			; Hide message
    

    unload:

    ; https://duet3d.dozuki.com/Wiki/Filaments
    
    ; unload.g
    
    
    if (state.currentTool=-1)
        M291 P"No tool active" R"Can't proceed" S1 T10
        abort;
    
    M703								;load from filament-config.g:
    G10 S220 							; Set current tool temperature S___ ,for PETG 230-255°C
    ;G10 S___							; get from filament-config.g
    
    M291 R"...heating up hotend..." P"...to unload filament..." S0 T100 				; Display message P=main-message R=secondary-message T=timer in sec
    
    ;https://duet3d.dozuki.com/Wiki/Gcode#Section_M116_Wait
    ;M116																			; Wait for ALL temperatures to be reached (if no secondary parameters like H, C or S are defined)
    M116 P0																			; Wait for P0=Tool0 to reach temp
    ;M116 P_			; make automatic for tool selected
    
    M292 ; Clear messages
    
    
    
    ; reliable max speed for extrusion seems to be below 10mm/s for PETG, retract can be higher
    M83 																			; Extruder to relative mode
    
    ;old style fix:
    ;G1 E50 F200 												; Feed+/Retract- E__mm of filament at F___mm/min
    ;G1 E250 F500 												; Feed+/Retract- E__mm of filament at F___mm/min
    ;M400 														; Wait for moves to complete
    ;G4 P5 														; Wait/Dwell P___ MILLIsecond(s), S___ second(s)
    ;G1 E-2 F1000 												; Feed+/Retract- E__mm of filament at F___mm/min
    
    ;new style interactive:
    M400 ; wait for moves to finish
    while true
        if iterations = 25
           break
    	;M292 ; Clear messages
    	M291 P"Press OK to un-feed 50mm of filament (or CANCEL to abort)" R"Un-load?"  S3
    	M291 P"...moving the filament..." R"...wait..."  S0 T50		        ; make long enough to be displayed longer then it takes to extrude
    	G1 E-47 F500 																	; Feed+/Retract- E__mm of filament at F___mm/min
    	G1 E-3 F300 																	; Feed+/Retract- E__mm of filament at F___mm/min
    	M400 ; wait for moves to finish
    	;M292 ; Clear messages
    M400 ; wait for moves to finish
    
    
    
    M291 R"Done unloading" P{move.extruders[state.currentTool].filament ^  " Filament"} S1			; Display new message
    ; set all back
    G10 S0 																			; Set current tool temperature S___
    ;M292 																			; Hide message
    

    Thanks!

    Please close as "solved"



  • @LB Do you ever have the message done loading/unloading ? I tried your solution but as soon as i cancel the purge, it kills the macro and don't finish it.



  • @Krohm-Koala said in load unload macro with endless loop and cancel condition:

    @LB Do you ever have the message done loading/unloading ? I tried your solution but as soon as i cancel the purge, it kills the macro and won't finish it.
    likewise in the above case, abort would kill the macro (and print)

    At present if you hit cancel in an M291 S3 dialog it will cancel the macro, so no, you would never get the finished message in that instance.

    There was discussion about adding a third option to M291, but it doesn't seem to be on the current list for implementation.
    Perhaps some some time after 3.2 is finalized.



  • @OwenD said in load unload macro with endless loop and cancel condition:

    @Krohm-Koala said in load unload macro with endless loop and cancel condition:

    @LB Do you ever have the message done loading/unloading ? I tried your solution but as soon as i cancel the purge, it kills the macro and won't finish it.
    likewise in the above case, abort would kill the macro (and print)

    At present if you hit cancel in an M291 S3 dialog it will cancel the macro, so no, you would never get the finished message in that instance.

    There was discussion about adding a third option to M291, but it doesn't seem to be on the current list for implementation.
    Perhaps some some time after 3.2 is finalized.

    @OwenD
    Thanks for pointing this out! That is what I assumed! Conditional G-code is pretty new, so not everything can be there from the start. But over time I guess there will be an option so I just let the code there to change it whenever the solution arrives...
    @Krohm-Koala
    To be honest I feel settled with the no "final" message since anyway in DWC it shows you that it has loaded everything -> since I currently only work with printers with only 1 extruder (and no colourchanger or stuff like that) the filamentchange-code posted is good enough for me now... hope you understand 🙂



  • @LB Totally understand 😄 it's just me who want too much 😂


Log in to reply