Since I can't do any printing at the moment (printer is broken), I have put together a bit of a tutorial on "best practice" when creating conditional G code.
There will be many far more qualified people than I on the forum to do this, and I'm sure that there is better and more concise documentation coming, but some may find it useful.
It is far from a complete or even comprehensive treatise on the subject, nor is it meant to be.
Feel free to correct, disagree or ignore as you see fit.
Especially since the code therein is untested (printer broken remember)
Conditional G Code best practice.pdf
Best posts made by OwenD
-
Conditional G Code introduction "tutorial" (PDF)
-
RE: Baby Stepping.. can it, or can it not be permanent?
just run a macro. (assuming you're running RRF3)
You could either do it manually or put it in the stop gcode of your slicer;save_babystep.g ; Add babystep to Z offset and make "persistant" if move.axes[2].babystep !=0 echo {"Z trigger height altered by " ^ move.axes[2].babystep ^ "mm"} echo {"OLD: " ^ sensors.probes[0].triggerHeight ^ " new: " ^ sensors.probes[0].triggerHeight - move.axes[2].babystep} G31 Z{sensors.probes[0].triggerHeight - move.axes[2].babystep} M500 P10:31 ; save settings to config-overide.g - Must have M501 in config.g else echo "No babystepping set. Nothing to save"
EDIT: Original post incorrectly added baby steps to trigger height. It should subtract.
-
Pressure Advance Tuning file generator
Hi All,
In my quest to tune my various settings I decided I needed to be able to automatically generate a test file that would change the pressure advance at set intervals.
The only programming language I know is Delphi/Lazarus, so I created a windows application to carry out the task.Essentially that application creates a square box with two wall perimeters.
The inner wall prints at a constant speed and acts merely for support.
The outer wall alternates between a high and low speed with the transition point being mid way along the wall.
At the end of each layer a retraction is added.This allows you to see how the PA adjustments are affecting corners at the two speeds and how it is affecting the retraction settings.
A start and end G code section takes care of temps etc.
Here are some pics of tests starting a PA of zero and increasing by 0.05 every 5mm in height.
My printer runs about a 350mm bowden tube.Pic 1: PA range 0-0.35
Note the distinct thickness variations at the speed change point and the blobbing at the retraction/layer change point.
Pic2: PA Range 0.4-0.75
Transition line still faintly visible and some issues around retraction area
Pic3: PA range 0.8-1.15
Looks pretty good at about mid way
Pic4: PA range 1.2-1.55
Here we can see that pressure advance is starting to cause too much retraction.
I'd either have to reduce PA or try again with less retraction.
If anyone would like to try the application and provide feedback , I have put a link to my dropbox.
Download link:
https://www.dropbox.com/s/nolo5aca26e7fni/PaAdvanceTestInstall_v1-0.zip?dl=0BE WARNED!!
This should be considered very much beta software.
Use at your own risk.
I've only tested on Windows 10.I'm not sure my extrusion volume calculations are 100% accurate.
They seem close, but not identical to Cura's values.
At any rate it seems good enough for the test purposes. -
Macro for "automatic" calibration of BL Touch
This macro uses variables so needs RRF3.3b2 or later.
EDIT: Object model values for M558 are now stored in mm/min so no conversion necessary. - please used amended macro below which includes improvements and corrects some errors pointed out in this thread by other users.
It prompts you to jog the nozzle to the bed and then runs 10 probe offset tests (this number is configurable as a variable)
At the end, it discards the highest and lowest reading and averages the rest.
You can then choose to save the result in config-overide.g;Calibrate BL Touch ; Reprap firmware version 3.3b2 or later required! ; if two speed probing is configured in M558,we probably want to reduce the speed for this test var ProbeSpeedHigh = sensors.probes[0].speeds[0]*60 ; Speeds are saved in mm/sec in the object model but M558 uses mm/min var ProbeSpeedLow = sensors.probes[0].speeds[1]*60 M558 F60 ; reduce probe speed to 60mm/min for accuracy - adjust F parameter as required ;define some variables to store readings var NumTests=10 ; modify this value to define number of tests ; Do not change below this line var RunningTotal=0 var Average=0 var Lowest=0 var Highest=0 ; If the printer hasn't been homed, home it if !move.axes[0].homed || !move.axes[1].homed || !move.axes[2].homed G28 else G1 Z{sensors.probes[0].diveHeight} F360 ; if axes homed move to dive height M561 ; clear any bed transform M290 R0 S0 ; clear babystepping ; move nozzle to centre of bed G1 X{(move.axes[0].min + move.axes[0].max)/2} Y{(move.axes[1].min + move.axes[1].max)/2} M564 S0 H0 ; Allow movement beyond limits ;ensure you have room for the probe if move.axes[2].machinePosition < sensors.probes[0].diveHeight G1 Z{sensors.probes[0].diveHeight} M280 P0 S160 I1 ; reset BL Touch G4 S0.5 M98 P"0:/sys/retractprobe.g" ; Ensure probe is retracted & reset G4 S0.5 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 ; set Z position to zero M291 P"Press OK to begin" R"Ready?" S3; ; Move probe over top of same point that nozzle was when zero was set G1 Z{sensors.probes[0].diveHeight}; lift head G1 X{move.axes[0].machinePosition - sensors.probes[0].offsets[0]} Y{move.axes[1].machinePosition - sensors.probes[0].offsets[1]} F1800 echo "Current probe offset = " ^ sensors.probes[0].triggerHeight ^ "mm" ; carry out 10 probes (or what is set in NumTests variable) while iterations < var.NumTests G1 Z{sensors.probes[0].diveHeight} ; move to dive height 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 M118 P2 S{"Test # " ^ (iterations+1) ^ " Triggered @ " ^ move.axes[2].machinePosition ^ "mm"} ; send trigger height to Paneldue console M118 P3 S{"Test # " ^ (iterations+1) ^ " Triggered @ " ^ move.axes[2].machinePosition ^ "mm"} ; send trigger height to DWC console if iterations == 0 set var.Lowest={move.axes[2].machinePosition} ; set the new lowest reading to first probe height set var.Highest={move.axes[2].machinePosition} ; set the new highest reading to first probe height if move.axes[2].machinePosition < var.Lowest set var.Lowest={move.axes[2].machinePosition} ; set the new lowest reading ;M118 P3 S{"new low reading = " ^ move.axes[2].machinePosition} ; send trigger height to DWC console G4 S0.3 if move.axes[2].machinePosition > var.Highest set var.Highest={move.axes[2].machinePosition} ; set the new highest reading ;M118 P3 S{"new high reading = " ^ move.axes[2].machinePosition} ; send trigger height to DWC console G4 S0.3 set var.RunningTotal={var.RunningTotal + move.axes[2].machinePosition} ; set new running total ;M118 P3 S{"running total = " ^ var.RunningTotal} ; send running total to DWC console G4 S0.5 set var.Average = {(var.RunningTotal - var.Highest - var.Lowest) / (var.NumTests - 2)} ; calculate the average after discarding th ehigh & low reading ;M118 P3 S{"running total = " ^ var.RunningTotal} ; send running total to DWC console ;M118 P3 S{"low reading = " ^ var.Lowest} ; send low reading to DWC console ;M118 P3 S{"high reading = " ^ var.Highest} ; send high reading to DWC console M118 P2 S{"Average excluding high and low reading = " ^ var.Average} ; send average to PanelDue console M118 P3 S{"Average excluding high and low reading = " ^ var.Average} ; send average to DWC console G31 P500 Z{var.Average} ; set Z probe offset to the average reading M564 S0 H1 ; Reset limits M558 F{var.ProbeSpeedHigh}:{var.ProbeSpeedLow} ; reset probe speed to original G1 Z{sensors.probes[0].diveHeight} F360 ; move head back to dive height M291 P{"Trigger height set to : " ^ sensors.probes[0].triggerHeight ^ " OK to save to config-overide.g, cancel to use until next restart"} R"Finished" S3 M500 P31 ; optionally save result to config-overide.g
-
RE: oibject model "status" dcos.
@Tinchus
Political correctness has spread even to RRF.
In the spirit of inclusiveness , you must now use "processing" in deference to those machines that do not identify as "printers" -
RE: Reprap G-Code syntax now part of RJ TextEd text editor
I have updated the syntax file for RJ TextEd to include more object model items.
I have also included a suggested colour format file.
You will need to update RJ TextEd to the latest version in order to take advantage of hints etc.Replace the existing files (reprap.syx, reprap.ini) in C:\Users"yourname"\AppData\Roaming\RJ TextEd\Syntax
Copy the file "Reprap Dark.xml" to C:\Users"yourname"\AppData\Roaming\RJ TextEd\Syntax color themes\To install.
1: Go to ENVIRONMENT > THEMES > CUSTOMISE
2: Select "Reprap G Code" from the drop down list of highlighters
3: Click the button, and select import colors from file
4: Select the "Reprap Dark.xml" file previously copied.
You can customize the colours to suit yourself.
Different G Code parameters such as X, Y, Z , E, F, G etc can be coloured to make individually.
Likewise, comments and other items can be individually coloured.
-
Forum categories for conditional Gcode & macros
Now that 3.1 is released, I think it would be beneficial to have a forum category dedicated to conditional gcode & macros.
This should probably be broken down into various kinematic types.
Furthermore it may be good to have some sort of āduet approvedā marker like the āsolvedā marker, once the macros have been peer reviewed and improved where necessary.
I usually try to make macros āportableā by not hard coding anything, but the very fact that certain parts of the object model are not visible if you donāt run that type of configuration, probably makes putting them in the categories for which they were designed beneficial and will reduce angst and support time.
(Yes, I know we should be checking for null objects and kinematic types as a matter of course in every macro)
Which leads to my final point, which is once we have some documentation on the object model, perhaps someone could do a small tutorial on best practice when writing macros.
My programming background is not in C or its variants so I admit Iām constantly searching for proper syntax etc.
To a non-programmer it is just gobbledygook.
If thereās going to be dozens of people learning to do it, they may as well learn to do it in a way that ensure portability and reduces the chance of unexpected issues.
Iāve always found it usually takes 10 lines of code to do the job, the another 50 lines of code to stop people trying to do it out of order or in a way you never imagined -
RE: Conditional G Code - RJ TextEd Syntax file.
For those using RJ Text Editor, I have posted an updated syntax file that includes the new object model items and G Codes contained in RRF3.5.0 b2
It can be downloaded here
https://www.rj-texted.se/Forum/viewtopic.php?p=18659#p18659It includes mouse over hints for G Code commands and auto-complete
The program comes with the RRF syntax file as standard but you may need to update it as new firmware versions come out. -
Heater fault checking routine to be run in daemon.g
This is a routine I run in daemon.g to check for heater faults.
It is mainly aimed at covering the time when the printer is idle as RRF already checks when a print is running.
I have excluded heaters that are currently being PID auto tuned
It does not take action if the heater temp is < 45 degrees but will shut down if temp is < zero as that would indicate a thermistor fault.
If the temperature is over 45 degrees it will only fault if the current temp is > 15 degrees from the set active temp AND the temperature is rising by > 0.5 degrees over 3 seconds.
This is to avoid activating when the temp is deliberately lowered.
NOTE: I have used a dummy tool to store variables which allow me to have this routine run only at intervals greater than 10 seconds whilst allowing the rest of daemon.g to run at normal intervals. Without this (and until we get variables) you will need to modify the code and use G4 to set the timing
For the timing I have used state.upTime. which will probably roll over at some point if the printer is left on long enough (I'm guessing it's a 16 bit signed integer?), so I have a check for that.
I have tested it in both idle and printing states and it seems to work as expected but have not confirmed the upTime rollover works as expected.; 0:/sys/daemon.g ; runs continually in background at approximately 1Hz if not delayed internally ;HEATER CHECKS ; this section of daemon.g checks for heater faults ; RRF doesn't currently check for faults when idle but by default will shutdown during printing if temperature excursion is > 15 degrees. ; Note: temp excursion value and time may be manually set using M570 ; checking if temp is rising requires a variable. I have used a dummy tool offset (Tool2) for this and to do elapsed time since last check ; G4 could be used but would also delay anything else in daemon.g ; this way allows other checks to run more frequently if needed however the G4 delays inside the loop will affect the frequency of daemon.g ; will be updated when variables are available in RRF. while iterations < #heat.heaters ; loop through all configured heaters if ((tools[2].offsets[1]+10) > state.upTime) ; if checked in last 10 seconds escape loop and go to rest of daemon.g if present. offset will be zero at startup via config.g ;echo "skipping loop " ^ " " ^ state.upTime ^ " " ^ tools[2].offsets[1]+10 if tools[2].offsets[1] - state.upTime > 60 ; uptime must have rolled over so reset off set to zero G10 P2 Y0 echo "upTime has rolled over. Heater checking reset" break ;echo "checking heater " ^ iterations ^ " " ^ state.upTime ^ " " ^ tools[2].offsets[1]+10 if heat.heaters[iterations].state="tuning" ;echo "heater " ^ iterations ^ " is tuning - no check carried out" continue ; don't check this heater as it is PID auto tuning if (heat.heaters[iterations].current) > (heat.heaters[iterations].max) ; temp is over max so emergency shutdown required ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm echo "heater over max temp fault detected in daemon.g. - shutting down" M112; emergency shutdown M81 S1 ; turn off power when fans have turned off if (heat.heaters[iterations].current > 45) ; no real danger at below this temp as ambient may be close to this ;echo "heater " ^ iterations ^ " is above 45 degrees" if (heat.heaters[iterations].state!="off") && (heat.heaters[iterations].current > heat.heaters[iterations].active + 15) ; temp is > 15 degrees above target. ;echo "heater " ^ iterations ^ " is on or in standby - checking if temp is rising" G10 P2 X{heat.heaters[iterations].current} ; set dummy tool X offset to current temp of heater G4 S3 ; wait 3 seconds if (heat.heaters[iterations].current > tools[2].offsets[0] + 0.5) ; heat is rising by more than 0.5 degrees in 3 seconds echo "heater runaway fault detected in daemon.g. - shutting down" if (state.status=="processing") M25 ; pause print so you might be able to save it using M119 ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm M0 ; unconditional stop. If axes are homed and a print is being canceled will run cancel.g otherwise will run stop.g M81 S1 ; turn off power when fans have turned off else ;echo "heater is on or standby but temp is falling on heater " ^ iterations ^ " - no action needed" elif (heat.heaters[iterations].state="off") && (heat.heaters[iterations].current >= 45) ; if heater is off and temp is greater than 45 there could be an issue ;echo "heater " ^ iterations ^ " is off but checking if temp is rising" G10 P2 X{heat.heaters[iterations].current} ; set dummy tool X offset to current temp of heater G4 S3 ; wait 3 seconds if (heat.heaters[iterations].current > tools[2].offsets[0] + 0.5) ; heat is rising by more than 0.5 degrees in 3 seconds ;echo "heater is off but temp is rising on heater " ^ iterations ^ "emergency shutdown" ;M41 P5 S1 ; activate output connected to externally powered latching relay here to sound alarm echo "heater runaway fault detected in daemon.g. - shutting down" M112; emergency shutdown M81 S1 ; turn off power when fans have turned off else ;echo "heater is off & temp is falling or stable on heater " ^ iterations ^ " - no action needed" else ;heater is below 45 degrees so only other fault may be an open circuit thermistor which should show -275 degrees if heat.heaters[iterations].current < -0 ; we probably have a thermistor fault if heater is less than 0 degrees M112 ; emergency shutdown M81 S1 ; turn off power when fans have turned off if iterations == #heat.heaters-1 ; all heaters have been checked G10 P2 Y{state.upTime} ; set the new time to check again ; END HEATER CHECKS ; run other checks ;G4 S10 ; pause daemon.g for 10 seconds before next run - required if not using variables
-
RE: How can I create a toggle macro?
@paulhew said in How can I create a toggle macro?:
@dc42 said in How can I create a toggle macro?:
state.gpout
Appreciate the input you have given, maybe I need to start at the beginning.
This is my config for my Lights;Lights M950 F10 C"out1" M106 P10 S0 H-1 C"Front Lights" M106 P10 S1
It looks correct, it works. Personally it would be better if it was an on/off and not PWM'd, Do not think I require mood lighting on my chamber lights
So after enabling Object Model Browser, I found F10 under Fans and it shows the correct info as in my config.
I change the lights on and off and it changes 'actualValue'Not being as clever as you guys but willing to learn, how do I query 'Fan.10' actualValue'?
I sort of understand the 'if' part
if 'actualValue' = 1
then set to 0
Elif 'actualValue' = 0
set to 1Personally, it would be handy if there were some basic 'Meta Guides' to help us understand how to write queries and some simple ones we could implement to advance our learning.
try here
https://duet3d.dozuki.com/Wiki/GCode_Meta_CommandsLike if the printer is not homed, then home it and how to turn on /off lights with a one button macro!
If you look through the meta commands topic section of the forum there are many examples which should help you understand.
https://forum.duet3d.com/category/34/gcode-meta-commandsMuch like you have done with the RRF configurator, it explains the function which has helped me learn a lot.
I did search for the "state.gpout[n].pwm" and variations in the dozuki and could not find any reference to it.
Again, Thanks in advance.
You have to use the object model to reference the proper name & syntax for the GPIO output, fan or whatever.
In our case, you're using a fan output, not a GPIO pin.
So you need to look in the fans section of the object browser.
Fan outputs are PWM capable, so that you can set a fan to any speed.
In your case, you can just set it to 0 or 1 using M106.
A GPIO output would be set by M42in terms of code you could have something like
if fans[10].actualValue = 1 M106 P10 S0 else M106 P10 S1
This example is only meant for an LED connected to a fan ouput that is only ever set full on, or full off.
Latest posts made by OwenD
-
RE: how to setup a hotend for directly printing metal and ceramic.
@lynnmt
Those examples are using the current to melt the wire (akin to MIG welding), so they are nothing like TIG hot wire.
In hot wire TIG, the current through the wire is much lower and used only to aid melting the wire by getting it hot.
The main heat source is external. In TIG it's a high current arc carried via a tungsten electrode, but a heating cartridge would equally work.
Naturally it wouldn't work with non conductive materials.
Anyway, just a thought. -
RE: zone heated bed
I would probably treat them as two different heaters.
Create a macro to define Zone 1 as you would any heated bed.
i.e. in M950 choose your output and sensor for that section.Then have a macro that frees the pin and sensor used for zone one and redefines the entire bed (Zone 2) using two outputs and the sensor mounted to zone two.
You could define the sensor used on zone one and have max temps etc as well for added protection.I think that should allow PID tuning as per normal for each zone, but of course zone 1 is going to "bleed" heat into zone 2, so overall accuracy will be reduced I guess.
I'm sure it's been done many times, so someone may have more info based on actual experience.
-
RE: how to setup a hotend for directly printing metal and ceramic.
Unrelated to the tuning, but I wonder if adopting a setup similar to hot wire tig welding would be beneficial in this application ?
Essentially the wire has a current applied by an external DC power source (sometimes AC), with the bed being the ground.
When a connection occurs during feeding, the wire is "pre heated" allowing for faster melting & higher deposition rates.
The current used isn't enough that the wire can create an arc on its own. -
RE: [3.5.0-rc.3] Conditional 'abort' command called unexpectedly
@gloomyandy said in [3.5.0-rc.3] Conditional 'abort' command called unexpectedly:
@OwenD Could be SBC or could be related to the multiple gcode stream feature, so you may not see it on a Duet2.
Very true.
If it's multiple stream issue the perhaps a G4 P100 before the if and abort commands would be a work around? -
RE: [3.5.0-rc.3] Conditional 'abort' command called unexpectedly
@lycean
Looks like it might be an SBC thing?
I ran it on my Duet 2 stand alone mo problems (had to change IO); Use probe 1 as a dummy source for values M558 K1 P8 C"exp.e6_stop" H2 F1000 ; Center the head before we start G0 X{(move.axes[0].max - move.axes[0].min) / 2} Y{(move.axes[1].max - move.axes[1].min) / 2} Z50 F10000 M400 ; ; First test block ; echo "1.0 Starting test" G91 echo "1.1 Commanding move" G0 X50 F1000 ; ** Need to command a move for the problem to occur. G90 G31 K1 P2000 ; ** Need to set threshold so the 'if' statement below will evaluate to true before the pause. echo "1.2 Pausing" G4 P1 ; ** Need a delay after the move. echo "1.3 Setting threshold to 500" G31 K1 P500 ; Set threshold to 500 so the 'if' statement below should be false and the 'abort' shouldn't be executed. echo "1.4 Testing to see if probe speed "^sensors.probes[1].speeds[0]^" is less than threshold "^sensors.probes[1].threshold if sensors.probes[1].speeds[0] < sensors.probes[1].threshold abort "1.5 SHOULD NEVER FIRE: Probe speed "^sensors.probes[1].speeds[0]^" is less than threshold "^sensors.probes[1].threshold echo "1.6 Finished test"
-
RE: [3.5.0-rc.3] Conditional 'abort' command called unexpectedly
@lycean
It seems to be failing at the G31 command
You can check each command using resultG31 K1 P500 if result = 0 echo "G31 OK" else echo "G31 failed"
If you see the failed message, or no message then you have your culprit.
Not sure if it makes a difference calling G31 in a print job vs a macro
It's probably failing in both, but RRF sees it as a fatal failure when you're printing -
RE: [3.5.0-rc.3] Conditional 'abort' command called unexpectedly
@lycean said in [3.5.0-rc.3] Conditional 'abort' command called unexpectedly:
if sensors. Probes[1].speeds[0] < sensors. Probes[1].threshold
Your if statement has syntax errors, whereas your echo statement is correct.
Try
if sensors.probes[1].speeds[0] < sensors.probes[1].threshold
-
RE: Multiple motion system homing malfunction
You have no indentation in your second while statement.
-
Options for print monitoring
I have been using an old notebook running mjpg-streamer & ffmpeg for years to monitor my prints.
Recently it died, so I'm looking for an alternative.
I have a raspberry pi 4 on hand and a pi camera.
I originally thought I might use it for RRF, but really haven't seen enough benefit to warrant the change.
I tried installing "motion" on it and whilst I can get it to run, I can't for the life of me get it to boot as a service due to permission errors.
A google search shows this to be common, but after a day of trying every "solution" provided, I'm over it.Can anyone recommend either a pi image or a definite working setup?
Or an alternative?