• Tags
  • Documentation
  • Order
  • Register
  • Login
Duet3D Logo Duet3D
  • Tags
  • Documentation
  • Order
  • Register
  • Login

Invitation to share your conditional GCode scripts

Scheduled Pinned Locked Moved
Gcode meta commands
14
23
4.7k
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • undefined
    dc42 administrators
    last edited by Phaedrux 9 Mar 2020, 17:46 7 Feb 2020, 13:55

    We're looking for interesting ways to use the conditional GCode facility of RRF 3.01, both to look for possible enhancements to this feature and to highlight its benefits. So, if you are using conditional GCode on your printer, please share those scripts here if you are willing.

    If you are using RRF 3.01beta but you haven't yet used conditional GCode, here are a few application ideas to get you going:

    • Leadscrew bed levelling or delta printer calibration until deviation is below a certain amount
    • Homing the printer in certain contexts if and only if it hasn't been homed already
    • Taking some action (e.g. extruding) only if the extruder is hot enough
    • Repeated probing with the probe points approached from different directions, to detect backlash in the mechanics (especially useful for delta printers)
    • Adjusting the behaviour of the pause.g and resume.g file depending on whether a tool is selected, and which one
    • Doing different things depending on whether a switch is closed or not at the time
    • Lifting the head a few mm depending on whether or not the Z axis is already close to maximum
    • Changing the coordinates that pause.g moves to depending on the existing XYZ coordinates

    Please provide your own application ideas too!

    Post your examples and ideas as their own thread in the GCode Meta Commands sub-forum.

    Relevant documentation:
    https://duet3d.dozuki.com/Wiki/RepRapFirmware_3_overview
    https://duet3d.dozuki.com/Wiki/GCode_Meta_Commands
    https://duet3d.dozuki.com/Wiki/Object_Model_of_RepRapFirmware
    https://duet3d.dozuki.com/Wiki/Gcode#Section_M409_Query_object_model

    Duet WiFi hardware designer and firmware engineer
    Please do not ask me for Duet support via PM or email, use the forum
    http://www.escher3d.com, https://miscsolutions.wordpress.com

    undefined 1 Reply Last reply 5 Apr 2020, 08:12 Reply Quote 5
    • undefined
      chas2706
      last edited by 7 Feb 2020, 14:12

      @dc42 Is there a time frame when the DSF will be updated so us Duet3 + SBC users can take advantage?

      1 Reply Last reply Reply Quote 2
      • undefined
        deckingman
        last edited by 7 Feb 2020, 14:50

        I'm rather hoping that one or more of the clever people on these forums will come up with a simplified user guide for those of us who are academically challenged, when it comes to understanding such things as what an object model is. A simple list of the values that I can use would be great.

        Right now I'm recovering from surgery so am even more challenged than normal. Two things that I'd like to do but that I haven't yet looked at would be firstly to set the operation and standby temperatures for tools but only if they exist. Currently I have several configuration files for different multi-input hot ends with different numbers of tools defined. I use pre and post print macros which are called from my slicer start and end gcode but if I pick the wrong macro, it could attempt to set the temperature for a non-existent tool and throw an error. So a simple loop for say 20 tools containing "if tool n exists, set it's active and standby temperatures to xxx, yyy" else skip" would be great. Is this doable? Even better would be to have "and if filamentType = pla, set temps to xxx else if filament = PET-G set temps to yyy etc". But I've no idea if this is doable.

        Another use would be to run a purge macro on tool change but only if a certain tool hasn't been used for nnn amount of time. The usage case is that PLA will hydrolyse when held at print temperature for an extended period of time. So when using a mixing hot end, it can be be necessary to purge an unused but heated filament depending on how long it has been unused for. If the filament was last used say 20 minutes ago or less, then the purge is unnecessary and wasteful in time as well as filament. Again, no idea if this is possible.

        Ian
        https://somei3deas.wordpress.com/
        https://www.youtube.com/@deckingman

        1 Reply Last reply Reply Quote 1
        • undefined
          chas2706
          last edited by 7 Feb 2020, 17:50

          I would use this in my start.g and some other macro's to check if machine has been homed:

          M291P"Checking for homed axis!" T3
          if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed
          G28
          // rest of start code

          and this for my leadscrew levelling:

          ; If the printer hasn't been homed, home it
          if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed
          G28

          while true
          if iterations = 5
          abort "Too many auto calibration attempts"

          G30 P0 X10 Y63 Z-99999 ; probe near a leadscrew
          if result != 0
          continue

          G30 P1 X290 Y63 Z-99999 ; probe near a leadscrew
          if result != 0
          continue

          G30 P2 X150 Y290 Z-99999 S3 ; probe near a leadscrew and calibrate 3 motors
          echo result
          if result != 0
          continue

          if move.calibrationDeviation.deviation <= 0.03
          break

          echo "Repeating calibration, Deviation is " ^ move.calibrationDeviation.deviation ^ "mm"

          echo "Auto calibration successful. Deviation = " ^ move.calibrationDeviation.deviation ^ "mm"

          G28 Z ; re-home z axis in case it has shifted

          But I can't use either because they don't work with Duet3 + SBC!

          1 Reply Last reply Reply Quote 0
          • undefined
            SpoonUnit
            last edited by 2 Apr 2020, 08:56

            I'm using the following in pause.g

            ; eject
            if state.currentTool=3
            	M98 P"eject-hemera.g"
            else
            	M98 P"eject.g"
            

            and correspondingly in resume.g

            ;prime nozzle
            if state.currentTool=3
            	M98 P"prime-hemera.g"
            else
            	M98 P"prime.g"
            

            I'd really like to be able to only run G29 if that last G29 was run some length of time ago. At present, it runs every print, but could be handy to only run it if that last homing process ran over an hour ago (or some configurable time period).

            1 Reply Last reply Reply Quote 1
            • undefined
              OwenD
              last edited by 2 Apr 2020, 09:21

              Perhaps a forum section dedicated to this might be in order?

              This is my stop.g which uses several of the examples listed.
              Essentially the only thing in my slicer end code is M0 to call stop.g

              Some of the popups aren't necessary, but provide feedback.

              ; stop.g
              ; called when M0 (Stop) is run (e.g. when a print from SD card is cancelled)
              ;
              ; generated by RepRapFirmware Configuration Tool v2.1.4 on Sat Jan 04 2020 09:46:45 GMT+1000 (Australian Eastern Standard Time)
              
              ; 
              if {state.currentTool!=-1} ; check if any tools are active
              	G91 ; relative positioning
              ;check if any tools have heaters which are above cold extrude value
              	if #tools[state.currentTool].heaters > 0 & heat.heaters[tools[state.currentTool].heaters[0]].current > heat.coldRetractTemperature
              		G1 E-2 F300 ; retract the filament a bit before lifting the nozzle to release some of the pressure
              		M291 P"Retracted 2mm" R"Retracting" S0 T5
              		G4 S5 ; wait for popup
              	else
              		M291 P{"Not retracted...  Heater off or below extrude temp  " ^ heat.heaters[1].current ^ " : " ^ heat.coldRetractTemperature ^ "."} R"Retract" S0 T5
              		G4 S5 ; wait for popup
              else
              	M291 P"No active tool" R"Check tools" S0 T2
              
              if {!move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed} ; check if the machine is homed
              	M291 P"Insufficient axis homed.  Cannot raise or park" R"Parking" S0 T5
              else
              	G90 ; absolute positioning
              	if {(move.axes[2].machinePosition) < (move.axes[2].max - 10)} ; check if there's sufficient space to raise head
              		M291 P{"Raising head to...  " ^ move.axes[2].machinePosition+5}  R"Raising head" S0 T5
              		G1 Z+5 F9000 ; move Z up a bit
              	else
              		M291 P{"Cannot raise head- insufficient space  " ^ move.axes[2].machinePosition ^ " : " ^ (move.axes[2].max - 10) ^ "."} R"Raising head" S0 T5
              		G4 S5 ; wait for popup to display
              	G1 X10 Y150 ; parks X head pushes bed out to front so you can pull part
              	M400 ; wait for current moves to finish
              
              if {state.currentTool!=-1}
              	G10 S0 R0 ; Set active and standby temps to zero
              	T-1 P0 ; if any tools selected, deselect all
              else
              	T0 ; Select a tool
              	G10 S0 R0 ; Set active and standby temps to zero to ensure nothing is on standby
              	T-1 P0; deselect all tools
              M140 S0 ; heated bed heater off 
              M106 P0 S0 ; part fan off
              M84 ; steppers off
              G90 ; absolute positioning
              
              M98 P"0:/macros/songs/itchyscratchy.g" ; play finish tune
              
              Phaedruxundefined 1 Reply Last reply 3 Sept 2020, 17:47 Reply Quote 0
              • undefined
                OwenD
                last edited by 2 Apr 2020, 09:49

                Is there any documentation being prepared that explains the intent of the various object model items and when they would return a value?
                The closest I've found is the machine section of the API, but there's a lot of info in there that most don't need.
                For example when working with probe deviation, at what point should we use move.calibration.initial.deviation vs move.calibration.final.deviation?

                1 Reply Last reply Reply Quote 0
                • undefined
                  dc42 administrators
                  last edited by dc42 4 Feb 2020, 10:39 2 Apr 2020, 10:37

                  We plan to document the object model when it has settled down, after the RRF 3.01 release.

                  move.calibration.initialDeviation is the deviation reported by probing. finalDeviation is the expected deviation after the firmware had made the corrections. Both are set to zero if no auto calibration/true bed levelling has been done

                  Duet WiFi hardware designer and firmware engineer
                  Please do not ask me for Duet support via PM or email, use the forum
                  http://www.escher3d.com, https://miscsolutions.wordpress.com

                  1 Reply Last reply Reply Quote 0
                  • undefined
                    EducatingSavvas @dc42
                    last edited by 5 Apr 2020, 08:12

                    @dc42

                    Hi, I've had a couple ideas which I think might only be achieved with conditional g-code.

                    • Save waste-board location along z axis to be used when setting work-coordinate Z0 location during known stationary probe. This would be a useful for CNC router machines.
                    • Work out vector angle from x and y axis coordinates to control 5th axis motor. This could be toggled on/off in the web interface, and useful in implementing a tangential knife cutter or large scale concrete extrusion.
                    • Using switch state to control warning light system on 3D printer or CNC machine. Un-homed could be yellow, cutting or extruding will show red, and idle could be a white light.
                    • Safety enclosure door behaviour during different machine states. More specific for CNC but if cutting, pause job and display message 'enclosure has been opened,' if not cutting ignore switch state.

                    I'm not sure what is possible yet as I've only just updated to RRF3.01 RC6 but these are the type of behaviours I am interested in. Cheers.

                    1 Reply Last reply Reply Quote 1
                    • undefined
                      OwenD
                      last edited by OwenD 10 Apr 2020, 05:14

                      I did this one for calibrating the trigger height on a BL Touch
                      I tried a bunch of ways to store a fake variable, but nothing was easy enough to make this useful for a newbie, so for now you have to average the results.

                      I'm not 100% sure homing first is the best way on a brand new machine, but it can be commented out or made conditional with another M291.

                      ;Calibrate BL Touch trigger height
                      
                      ; When we get variables we can define one here
                      ; Uncomment when ready to use
                      ; var RunningTotal=0
                      ; var average=0
                      
                      
                      
                      ; If the printer hasn't been homed, home it
                      if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed
                        G28
                        
                      M564 S0 H0 ; Allow movement beyond limits
                      
                      if move.axes[2].machinePosition < 6 ; make sure we have probe clearance
                      	G1 Z6
                      M280 P0 S160 I1 ; reset BL Touch
                      G4 S0.5
                      M98 P"0:/sys/retractprobe.g" ; Ensure probe is retracted & reset
                      G4 S0.5
                      M290 R0 S0 ; clear any baby stepping
                      M561 ; clear any bed transform
                      ; Jog head to position
                      M291 P"Jog nozzle to touch bed" R"Set nozzle to zero" S3 Z1
                      G92 Z0
                      M291 P"Press OK to begin" R"Ready?" S3; 
                      ; carry out 10 probes
                      while iterations <= 9
                      	G1 Z6
                      	M400
                      	if sensors.probes[0].value[0]=1000 ; if probe is in error state
                      		echo "Probe in error state- resetting"
                      		M280 P0 S160 I1 ; reset BL Touch
                      		G4 S0.5
                      		M98 P"0:/sys/retractprobe.g" ; Ensure probe is retracted & reset
                      		G4 S0.5
                      	G30 S-1
                      	M400
                      	; Uncomment when variables allowed
                      	; RunningTotal=RunningTotal + move.axes[2].machinePosition
                      	;average=RunningTotal/(iterations+1)
                      	G4 S0.5
                      
                      ; Until variables come use this
                      M291 P"Check console for results and enter average value in G31 Z parameter of config.g"  R"Finished" S3 
                      
                      ;When variables come uncomment this
                      ;G31 Z{average}
                      ;M291 P"Trigger height set to : " ^ sensors.probes[0].triggerHeight ^ " Press OK to save to config, cancel to use until restart" R"Finished" S2 
                      ;M500
                      
                      
                      M564 S0 H1 ; Reset limits	
                      
                      PaulHewundefined 1 Reply Last reply 28 Apr 2020, 13:11 Reply Quote 1
                      • mwwhitedundefined
                        mwwhited
                        last edited by mwwhited 24 Apr 2020, 18:02

                        I was looking for a Thermostatic Fan trigger and was pointed to a post about daemon.g. Based RRF3.1-RC9 + SBC I now have my fan control for my power tied in.

                        This conditional logic is really powerful.. thanks for all the hard work.

                        daemon.g

                        M98 P"0:/macros/Special Scripts/Check Power Supply"
                        
                        G4 S10 ; wait 10 seconds
                        

                        Special Scripts/Check Power Supply

                        if fans[3].actualValue > 0.0 && sensors.analog[3].lastReading < 25
                            ;echo "fan running and temp less than 25c... stop fan"
                            M106 P3 S0.0
                        elif fans[3].actualValue < 0.5 && sensors.analog[3].lastReading > 35
                            ;echo "fan stopped and temp greater than 35c... start fan"
                            M106 P3 S1.0
                        
                        1 Reply Last reply Reply Quote 2
                        • undefined
                          OwenD
                          last edited by 28 Apr 2020, 11:43

                          Another example using daemon.g

                          I'm in the process of adding some extra safety checks.
                          This will check the heater temps when idle and initiate action such as shutting off all power, activating an alarm (probably requires a latching relay)
                          As RRF checks this when printing there's no need to run this section of the code unless idle.

                          ; daemon.g
                          ; check temps every 10 seconds when not printing (i.e. Idle) and shut down if exceed max temps.  RRF checks when printing, but not when idle.
                          ; not all commands are required.  e.g. shutting off power by dropping a relay negates need for M112, M81 - un-comment or adjust as required for your configuration
                          ; assumes that the thermistor for each heater is monitor # zero as there is no way to do nested loops using "iterations" as identifier in both loops until variables are available in the object model
                          ; no checking done for null values! - 
                          
                          if state.status="idle"
                          	while iterations < #heat.heaters ; 
                          		;if heat.heaters[iterations].current > heat.heaters[iterations].monitors[0].limit ; un-comment when ready to go live
                          		if heat.heaters[iterations].current > 50 ; uncomment for testing, comment out when going live
                          			M291 P"Heater over max temp" R"Temp Error!" S1 T0 ; Display message for testing
                          			;M112 ; Do emergency stop
                          			;M81  ; Turn PS_ON (ATX) off
                          			;M42 P5 S1 ; Set GPIO 5 (output) high to activate alarm relay. GPIO pin must be configured using M950
                          			;M42 P6 S0 ; Set GPIO 6 (output) low to cut power. GPIO pin must be configured using M950
                          
                          ;if sensors.gpIn[6].value=1 ; check state of connected smoke detector - GPIO pin must be configured using M950
                          	;M291 P"Smoke detector active!" R"I'm on fire!" S1 T0 ; Display Nikki Lauder message for testing
                          	;M112 ; Do emergency stop
                          	;M81  ; Turn PS_ON (ATX) off
                          	;M42 P5 S1 ; Set GPIO 5 (output) high to activate alarm relay
                          	;M42 P6 S0 ; Set GPIO 6 (output) low to cut power	
                          		
                          G4 S10 ; wait 10 seconds before next check	(adjust S parameter as you see fit)
                          
                          1 Reply Last reply Reply Quote 0
                          • PaulHewundefined
                            PaulHew @OwenD
                            last edited by 28 Apr 2020, 13:11

                            @OwenD Please can I make a suggestion, at the beginning, issue a

                            M290 R0 S0
                            

                            to reset baby stepping before you try to start performing jogging Z and trigger heights.

                            Just this minute made that mistake!

                            Paul

                            RailCore II - Duet Mini + 1LC, Voron V0.1 - Duet Mini
                            Voron 2.4 disassembled..... Waiting for the RailCore Mini....

                            undefined 1 Reply Last reply 28 Apr 2020, 20:08 Reply Quote 0
                            • undefined
                              OwenD @PaulHew
                              last edited by 28 Apr 2020, 20:08

                              @PaulHew said in Invitation to share your conditional GCode scripts:

                              @OwenD Please can I make a suggestion, at the beginning, issue a

                              M290 R0 S0
                              

                              to reset baby stepping before you try to start performing jogging Z and trigger heights.

                              Just this minute made that mistake!

                              Paul

                              Good idea!
                              So let it be written...

                              1 Reply Last reply Reply Quote 0
                              • undefined
                                OwenD
                                last edited by 1 May 2020, 23:44

                                Code to check if all axes are homed and optionally home them, or cancel macro.
                                It iterates across ALL axes making it more portable code (for those with >3 axis)
                                This saves manually listing them in an if || (or) statement such as

                                if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed
                                

                                I imagine this would be useful for tool changing printers where you might be doing something that may or may not require homing.
                                For the rest of us, I'd just run G28 if any are not homed.

                                ;first check if any axes are not homed and optionally home them 
                                while iterations < #move.axes
                                	if !move.axes[iterations].homed ; check if each axis is homed
                                		M291 P{"Axis " ^ move.axes[iterations].letter ^ " is not homed.  Home now?"} R"Axis un-homed" S3 ; continue or abort?
                                		M98 P{"0:/sys/home" ^ (move.axes[iterations].letter) ^ ".g"} ; home axis if answer is OK - G28 doesn't accept object variable so run macro
                                		
                                ; rest of code here
                                
                                1 Reply Last reply Reply Quote 2
                                • undefined
                                  fšk
                                  last edited by 23 May 2020, 09:58

                                  Here is what I use to choose machine type at startup depending on what tool is connected.
                                  I include a resistor connected to the sensor pin inside the tool connector. This gives a fixed temperature reading and lets the machine choose its type depending on what is connected at startup.

                                  M308 S23 P"e2temp" Y"thermistor" T100000 B3950 A"ModeSelector"   ;setup a thermistor input as config selection sensor 
                                  
                                  
                                  ;wait for the sensor to start returning meaningful values (don't know if there is a better approach for this) 
                                  while sensors.analog[23].lastReading==0||sensors.analog[23].lastReading==2000
                                    echo
                                  
                                  ;print the value detected (useful when adding a new mode)
                                  ;M117 ModeSelector value:{sensors.analog[23].lastReading}
                                  
                                  ;depending on sensor reading choose a system folder
                                  if sensors.analog[23].lastReading==-273.1
                                    M117 No Attachment Detected.
                                  elif sensors.analog[23].lastReading<155
                                    M117 Going to be a CNC.
                                    M505 P"CNC"
                                  else 
                                    M117 Going to be a 3D printer.
                                    M505 P"Printer"
                                  
                                  ;load config.g from the chosen system folder
                                  M98 P"config.g"
                                  
                                  1 Reply Last reply Reply Quote 3
                                  • mwwhitedundefined
                                    mwwhited
                                    last edited by 23 May 2020, 10:23

                                    That’s pretty cool. I’m considering my using a serial line with some tiny85 chips that I have laying around to do the same thing. For now I write out a script that I try to call from config.g that just sets up the last executed tool script.

                                    Setup 3 to 1

                                    M28 "0:/sys/lasttool.g"
                                    M98 P"0:/macros/Config Scripts/Setup 3 to 1 Hotend"
                                    M29
                                    

                                    I have a script that uses conditional code to clear out tools, fans, and heaters as well as de-energizing my relays (stepper bank switch).

                                    Change Toolhead

                                    ;echo "check temperature"
                                    while iterations < #sensors.analog
                                    	if sensors.analog[iterations] != null && sensors.analog[iterations].lastReading > 32 && sensors.analog[iterations].name != "PS"
                                    		if sensors.analog[iterations].name != "Bed"
                                    			abort "Must wait for tool head to cool down!!!"
                                    
                                    ;echo "set relays"
                                    M18 E ; Turn off Steppers for extruders
                                    G4 P100
                                    M42 P0 S0 ; Ensure relay 0 is off
                                    M42 P1 S0 ; Ensure relay 1 is off
                                    M42 P2 S0 ; Ensure relay 2 is off
                                    G4 P100
                                    
                                    ;echo "remove all tools"
                                    while iterations < #tools
                                    	;echo "Removing Tool ", tools[iterations].name, "T", iterations
                                    	M563 P{iterations} D-1 H-1
                                    
                                    ;echo "disable heaters"
                                    while iterations < #heat.heaters
                                    	if heat.bedHeaters[0] != iterations
                                    		;echo "Removing Temp Sensor and heater", sensors.analog[heat.heaters[iterations].sensor].name, "T", heat.heaters[iterations].sensor, "H", iterations
                                    		M308 S{heat.heaters[iterations].sensor} P"nil" Y"nil"
                                    		M950 H{iterations} C"nil"
                                    
                                    ;echo "remove fans"
                                    while iterations < #fans
                                    	if fans[iterations] != null && fans[iterations ].name != "Power Supply"
                                    		;echo "Removing Fan", fans[iterations].name, "F", iterations
                                    		M950 F{iterations} C"nil"
                                    
                                    M30 "0:/sys/lasttool.g"
                                    
                                    1 Reply Last reply Reply Quote 1
                                    • fmaundefined
                                      fma
                                      last edited by 23 May 2020, 10:50

                                      Once reading I²C bus is implemented (it is maybe already done in current release, I didn't check yet), using a I²C EEPROM can be a way to identify a device; this is often used in consumer products (Gopro does or did that for their accessories).

                                      Frédéric

                                      ? 1 Reply Last reply 23 May 2020, 10:56 Reply Quote 0
                                      • ?
                                        A Former User @fma
                                        last edited by 23 May 2020, 10:56

                                        @fma said in Invitation to share your conditional GCode scripts:

                                        Once reading I²C bus is implemented (it is maybe already done in current release, I didn't check yet), using a I²C EEPROM can be a way to identify a device; this is often used in consumer products (Gopro does or did that for their accessories).

                                        It also opens the possibility to store calibration data etc in the tool independent of the machine, ref IEEE1451-ish. Although Duet3d avoided using I2C for their fillament sensor (unlike Prusa) as the bus isn't intended for long runs. Maybe we'll see 1-wire or something in the future?

                                        1 Reply Last reply Reply Quote 0
                                        • fmaundefined
                                          fma
                                          last edited by 23 May 2020, 11:03

                                          Well, the filement sensor needs continuous readings, which is not the case for calibration or so.

                                          Frédéric

                                          1 Reply Last reply Reply Quote 0
                                          • First post
                                            Last post
                                          Unless otherwise noted, all forum content is licensed under CC-BY-SA