Why are "custom GCodes" only for non implemended GCodes?
-
Seems like most needs can be handled with a macro that is called via M98. You can even name your macro "M3_custom.g" or whatever to make it close to the Gcode it's derived from.
Having the firmware re-direct execution from a known g-code to a macro (with a name that looks like a gcode). Seems only important if the system is calling a g-code internally and you want to change the behavior. This is risky because you would need to know every place in the fw that calls the GCode of interest. Feels like editing the source might be the way to go.
-
@t3p3tony said in Why are "custom GCodes" only for non implemended GCodes?:
So you want to run a macro as well as have the normal behaviour happen? At the same time? in what order?
Please excuse me if I am unclear about what I am trying to archive. I am still trying to wrap my mind around how standard Codes and macros could work together.
I see two possible Solutions:
- Call the custom G Code macro (if present) after the standard G Code is called. This way values like spindle speed are already available in the object model.
But what if I want to do something before the standard GCode is executed? Then we would need something like a Gcode override like @alankilian suggested:
- If a custom Gcode macro is present in the /sys folder, it is executed instead of the standard Gcode. The question is how to hand over the values like spindle speed when the macro is called...
To give a practival example:
I would like to execute some commands before and after turning on the spindle of my CNC-Maschine:;M3.g ;this is run whenever M3 is called ;check if enclosure door is closed if var global door=open M291 P"Door open! Please close the door and press "OK" to continue" R"Attention!" S2 else M80 ; turn on power M3 P0 S{spindles[0].active} ;turn on spindle to desired RPM G4 S3 ; wait for spindle to spin up
-
@maxgyver Isn't this easier done by modifying your CAM postprocessor? You could create a custom M3.1.g in \sys with all the commands you require, then modify your postprocessor to insert M3.1 before M3 in your gcode. Granted, this requires an understanding of how your postprocessor works, but I find it easier to implement than what you're suggesting.
-
The Spindle speed was only one of many many usecases I have at hand. I am also using a bunch of Duet3 based 3D printers and hopefully soon a CNC lathe. So most probably I would need to make adjustments on two post processors and a slicer...
My printers for example all use a central CPAP blower instead of fans. The airflow is controlled by opening an closing valves with stepper motors. Right now I have a deamon.g constantly running in the back converting the desired fan speed of M106 in an axis position for the motor valves.
A custom M106.g would allow me to only run the macro whenever M106 is changed. Now I run it every 0.5 seconds in deamon.g in oder to have a relatively fast fan response.
-
@maxgyver
I also think what you want can relatively easily be achieved with some post processing.
Most slivers have a search and replace.
So replace all M106 commands with M106.1
In your M106.1.g macro you can do whatever you want and use the parameters passed by the slicer to finally call M106 with those parameters. -
For some slicers, this is true. But for the sake of simplicity, I would very much prefer to make these adjustments in one place. Like mentioned earlier, I would have to add scripts to the slicer, which have their own "flavor" of gcode placeholders, plus different post processor I use on my CNC machines. And editing a post processor definitively requires a lot more work and skill than adding a simple macro in the duet environment. I know this because I have tried and failed miserably
This brings me back to my original question:
Since we arlready have standard Gcodes that trigger custom macros (G29->mesh.g, G32-> bed.g, G28 -> homeall.g e.t.c)
,why not extend the list of custom Gcodes and make the system as a whole so much more flexible and user-friendly?I absolutely love the Duet products. But I am exhausted of finding workarounds for workarounds to implement simple functions...
And I am absolutely certain that a lot of future requests could be solved by just adding the desired function in form of a custom Gcode macro. -
@maxgyver
I guess the trick is how do you do it so that all use cases are met.
i.e. do you run the custom code before are after the standard one, or instead of ?Is the answer to check for say M106pre.g and M106post.g ?
Could cause quite a performance hit though. -
@owend said in Why are "custom GCodes" only for non implemended GCodes?:
In your M106.1.g macro you can do whatever you want and use the parameters passed by the slicer to finally call M106 with those parameters.
The passing of parameters is not so easy.
Of course I can just call a macro whenever M106 is called from the slicer.
The slicer calls the macro like you discribed...but the S-Value is not handed over correctly. So in my Gcode M106 looks like this:
G98 P"0:/macros/m106.g" S89.25
As a workaround I can call my motor valve Axis "S"
Then this:
Would result in the desired output whenever M106 is called:
G0 F6000 S252.45
But here is the thing. I have two extruders, both with their respective valves... So I need a workaround for my workaround to make this work.
With a custom GCode I could just grab the values from the object model and do whatever I want with them.
Furthermore, the upcoming RRF 3.5 release will allow for multiple GCode streams. Meaning that custom GCodes could be executed in the back without influencing the part being printed. Right now, whenever the fan value changes, I have a small pause in the print because the valve motors need some time to reach the new position. This means that I am unable to use automatic fan controll since with every change in M106 I the printhead stops until the valve position is reached creating an awfull lot of blobs.
-
@maxgyver
You misunderstood what I meant.In your search and replace simply search for M106 and replace it with M106.1
So
M106 P0 S180 would become M106.1 P0 S180
Then create an M106.1.g
In that haveM42 P{param.P} S{param.S) ; or whaever it is you need to do M106 P{param.P} S{param.S}
-
@owend said in Why are "custom GCodes" only for non implemended GCodes?:
@maxgyver
I guess the trick is how do you do it so that all use cases are met.
i.e. do you run the custom code before are after the standard one, or instead of ?By running the custom GCode instead.
So my logic would be like this: When a GCode is called, check if there is a file with the same name in the sys/ folder. If yes, push the values of the standard GCode to the object model and run this macro instead. If no macro is present, run the standard GCode.
This way I could grab the desired values from the object model and set the order of things to do in my macro file.
@owend said in Why are "custom GCodes" only for non implemended GCodes?:
Could cause quite a performance hit though.
I am not a programmer, but I recon checking if a file is present in sys/ should not take so many resources?
Maybe checking all GCodes is too much to ask. But maybe we can add a handful of customizable GCodes?
-
Thanks! I was unaware of this! I just noticed Macro parameters are supported from RRF 3.3
I am not at work right now, so I can test this on my printers tomorrow. On one hand I would still prefer not to use the slicers find and replace feature and just have custom GCodes. But on the other hand it will use a little less resources on the board.
This solves it for the slicer part... But the issue with post processors for CNC remain...
-
@maxgyver said in Why are "custom GCodes" only for non implemended GCodes?:
This solves it for the slicer part... But the issue with post processors for CNC remain...
A python script can do the search and replace.
It's what I use in Prusa Slicer rather than individual search and replace.
This should give you an idea.You would call it with
RRF-fixes.py "path_to_your_gcode.g"#RRF-fixes.py # Save in Prusa Slicer Scripts folder # Add to Prusa Slicer post processing scripts import sys import fileinput X = sys.argv[1] # this is the output gcode file name #search for M109 calls and add M116 after because we will replace M109 with M568 for line in fileinput.FileInput(X,inplace=1): if "M109" in line: line=line.replace(line,line + "M116 ; wait for heaters. Added by script") line=line.rstrip('\n') print (line) #open G Code fand store in memory "filedata" f = open(X,"r") filedata = f.read() f.close() # search filedata and put the results into newdata newdata = filedata.replace("M104 S","M568 S") # replace all M104 with G10 # now we keep searching newdata newdata = newdata.replace("M109 S","M568 S") # replace all M109 with M568 to set temps 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 S0") # replace all M107 with M1106 to turn off fan f = open(X,"w") f.write(newdata) # write info back to G Code file f.close()
-
While the search and replace approach works for Gcode files, it will not work for commands send from the Duet Web Control. So starting the Spindle or adjusting fan speeds from the Web interface will only work with standard GCodes.
-
@maxgyver said in Why are "custom GCodes" only for non implemended GCodes?:
Is there a reason why "custom GCodes" are only available for GCodes that are not implemented?
The current mechanism works by trying to open a macro file on the SD card to see if the macro exists, but only for codes that are not implemented. The overhead for looking for a file for every GCode command executed would be too great. So in order to allow macro replacement for any GCode, we would have to maintain a bitmap with one bit per possible G- or M-code, or a table or replaced G- and M-codes, so that RRF could quickly determine whether to look for a file or not. That bitmap could be constructed either by scanning /sys for relevant macro files at startup, or by requiring a new M-code to be used to specify that the implementation of a code is replaced by a macro.
You might want to be able to call the "native" version of a command from the macro, so we would need to provide a way to do that too.
-
@dc42 Thank you for clarifying. It sounds like there is more than one possible solution.
If the overhead is the bottleneck, maybe it can be reduced by only looking for Non-implemented and custom Gcodes if they are defined by the user, rather than always look for the complete list of non-implemented + custom Gcodes.@dc42 said in Why are "custom GCodes" only for non implemended GCodes?:
You might want to be able to call the "native" version of a command from the macro, so we would need to provide a way to do that too.
Indeed, this would massively simplify the use of custom Geodes on the user side.
-
@dc42
Sounds easy if you say it fast
I think substituting already defined G/M codes probably opens up Pandora's box in terms of being able to support RFF.
There are a lot of codes that are interdependent on other codes.
Support would no longer be a "post your config" scenario, it'd be "upload your SD contents"Post processing achieves the desired results without affecting the vast majority that don't need this option.
Plus it's easy to see a custom code when doing support.
It appears DWC doesn't support custom G codes.
My vote would be to correct that so it matches RRF behaviour rather that introduce so much complexity into RRF -
@owend amen.
-
@owend said in Why are "custom GCodes" only for non implemended GCodes?:
I think substituting already defined G/M codes probably opens up Pandora's box in terms of being able to support RFF.
Is it really substituting? In my understanding, it is rather a redirection to call a macro rather than executing the native Gcode directly
@owend said in Why are "custom GCodes" only for non implemended GCodes?:
There are a lot of codes that are interdependent on other codes.
I understand, but what I am proposing would not touch the "native" Gcode. On one Hand, I agree that customization does not make sense for all available Gcodes. On the other hand, it can be an incredibly powerful tool for adding custom behaviors and routines to our machines by giving users the option of combining Gcodes that are already there in a simple manner, Inside RRF and without the need for slicer scripts or custom post processors.
@owend said in Why are "custom GCodes" only for non implemended GCodes?:
Support would no longer be a "post your config" scenario, it'd be "upload your SD contents"
The same is true right now when you are using macros, Mesh.g, Bed.g, daemon.g e.t.c, which we basically all do. It really depends on where the problem is coming from.
@owend said in Why are "custom GCodes" only for non-implemented GCodes?:
Post processing achieves the desired results without affecting the vast majority that don't need this option.
No it does not, otherwise we would not have this discussion. Furthermore, I see a lot of feature requests that can be simply solved with custom Gcodes. The thing is that this is already working for a list of non-implemented and some native Gcodes like G32, G29 and so on. Furthermore, the "vast majority" does also not use CNC-specific Gcodes either, but a whole list of non-implemented CNC-Gcodes is checked when called. So my proposal to only check for custom and non-Implemented Gcodes ,that are for example defined in config.g, will probably even reduce the overhead.
-
Thanks for the suggestions.
-
@maxgyver I'm struggling to understand...........In your OP you stated........
For me, it would be a huge deal to be able to adjust the behavior of standard G codes by simply adding the desired function via a macro file.
and......
For example, I would like to check if the enclosure door of my CNC is closed, move the Z-axis to a safe hight and set the Spindle speed using a separate macro whenever M3 is called.
And from what I can gather, you want to do this by modifying the behaviour of the gcode rather than use a stand alone macro. So taking your example of modifying the behaviour of M3, you want to check the enclosure door first, then move the Z axis, then set the spindle speed. But if you modify the behaviour of M3, to do all that, how are you going to set the spindle speed? You can't call/use M3 from within the macro because you've changed the behaviour such that it will check the door and move the Z axis which will just end up with a recursive call. By modifying the behaviour of the standard gcode, you no longer have any means of just setting the spindle speed. So you'd need to define another gcode to do that which you can then use with the macro that runs whenever M3 is encountered. Am I being thick? Have I misunderstood? I don't get why you can't just use a macro and how or why modifying the behaviour of existing gcode commands is going to be better.