This problem occurs only with more than one extruder configuration.
I write a custom start code for my dual extrusion machine and want to set the
_material_print_temperature_ or _material_standby_temperature_ to the first hotend
like:
"machine_start_gcode": { "default_value": ";
in the gcode: the hotend temperatures are from the definition file or default, not from the materials or gui config.
Is it possible to differ whitch extruders are used in the job and preheat only this.
eg. with a machine_extruder_init_code
in cura 14.12 it was differd by start.gcode and start2.gcode
There is machine_extruder_start_code
, which is the g-code to use when switching to a certain extruder. But that would get executed at every extruder switch, not just at the start of the print. It's good enough to do things like setting the bed temperature but not priming since that only needs to be done once.
This sort of thing is really not supported yet at the moment by the engine. We haven't run into this problem ourselves since for the Ultimaker 3 (our only multi-extrusion printer) the default procedure is enough.
What I understand here is that you want to start your print with extruder_1 and not with extruder_0. But your start.gcode will only let you set the temp for extruder_0.
This is very difficult and tricky and I have no answer for it(yet).
I do have a lot of experience in this and the next paragraph will discuss but 1 problem, so feel free to skip to the next paragraph with a possible solution :)
I used to use Slic3r and there are some features there to make things better, but it is far from perfect.
1 of them was setting the variable from M104 S{material_print_temperature} to M104 S{material_standby_temperature_0} making sure that the temperature was the correct temp for the material being used in the appropriate extruder and not some default temp.
So you could say:
T1
M104 S{material_print_temperature_1}
to preheat Extruder_1 with the correct temp
But then you would have a start.gcode which will only work for extruder_1 and not extruder_0
So for a global start.gcode file you would want:
M104 S{material_print_temperature_0} T0
M104 S{material_print_temperature_1} T1
But then both(or more, if you have them) extruders would be heated and only one of them will be used and the others will be oozing.
So you need to heat the temps of the unused extruders to the material_standby_temperature.
In any case:
The problem is that you (the author of the start.gcode) does not know which extruder is going to be used 1st. (and neither does the slicing program when inserting the start.gcode)
One way of going about it is to not put any M104 or M109 codes in the start.gcode. Then Cura will put some temps in before the start.gcode.
The flaw I see here:
All extruders are heated to print temp and then are drawing power for no reason to the unused extruders.
You do want to heat your extruders at beginning as you want to clean all your nozzles in start.gcode. But it needs to be material_standby_temperature for the unused extruders, otherwise you will be oozing.
A solution to the "drawing power for no reason to unused extruders" would be to generate a code after the start.gcode with "M104 S0 Txxx" , cooling the unused extruders down.
As told before: this is a very tricky subject and up for a lot of debate :)
The flaw I see here:
All extruders are heated to print temp and then are drawing power for no reason to the unused extruders.
Cura should not attempt to heat up extruders that it doesn't use. We've made specific checks for that. Because it's hella annoying to test a print when it needs to heat up both extruders every time ;)
strange, when UM3 is selected it only heats up the extruder it is going to use
with my Cartesio it does:
;FLAVOR:RepRap
;TIME:285
;Filament used: 0.0913444m
;Layer height: 0.2
;Generated with Cura_SteamEngine master
M190 S50
M104 S205
M104 T1 S235
M104 T2 S245
M104 T3 S250
M109 S205
M109 T1 S235
M109 T2 S245
M109 T3 S250
So it heats up all extruders to " printing temperature initial layer"
Maybe I need to set variants?
Update: variants make no diference
@Ghostkeeper, au contraire mon amis...
[...]the Ultimaker 3 (our only multi-extrusion printer) [...] is not correct. There are a few UMO with official dual upgrade in the feld, so sorry to correct this :-)
So same issue there... (ref. to https://github.com/Ultimaker/Cura/issues/1128)
Any info, when this bug will be killed?
Side question: [...]machine_extruder_start_code, which is the g-code to use when switching to a certain extruder.[...] could be used to let the extruder every time switched e.g. run to a defined point similar to the nozzle lift at UM3 - correct?
Correct on the machine_extruder_start_code (and end).
There is a little issue open on #1225 about this.
Thanks @maukcc, already implemented this fix.
@maukcc , @Ghostkeeper,
... but seems not to work - tried with M190 S{material_standby_temperature} in my machine_extruder_start_code
it just displays the line in the gcode but does not substitute "material_standby_temperature" by the defined temp.
Tried also with other variables but without the expected behavior.
Wouldn`t it be better if these start and end codes, both for machine and extruder, would be "profile" dependent and not "printer" dependent?
@Drayson80 The fix for processing start/end extruder code was only recently committed to master, so unless you are working with a recent build of master that bug will still be there.
@maukcc What do you mean with "profile dependent"? We have quite a few things that are called "profile".
When you start a slice job you choose a "profile", in this profile you have the sections: Quality,Infill,...,...,Experimental
After Experimental you could have a section
Custom Gcodes
I did some further testing and it does do good things :)
If you put in temps in the start gcode, it will lower the unused temps to "standby temperature" after the start gcode.
But it will only do this if there is X amount of seconds between that code and the time it will use the next extruder.
It does not seem to be affected by "machine_nozzle_heat_up_speed"
Update: this is caused by "machine_min_cool_heat_time_window"
Strange things are happening since a few days
when I Have M109 S{material_print_temperature} in the start gcode, I ALWAYS get M109 S210. No matter what material I select.
I am guessing 210 is some default value?
when I put in M109 S{material_print_temperature_layer_0} I always get M109 S215. That "default value" +5, which is correct(ish)
But because it does not see {material_print_temperature} in the start gcode, you also get the temps before the start gcode which are the correct temps for the specific material.
Ah, I think it could be filling in the global material temperature rather than the material temperature of the extruder it starts with.
The start and end g-codes can technically be modified in a profile (you can set them by modifying the .cfg files). But we have no interface elements for them yet because you'd require a multi-line text box. And you would need to specify some way that this is different from single-line string settings.
I can not get that global material temperature out of there.
Any hints on where to seek?
I am using the Cartesio printer profile. With custom FDM printer it works fine.
The "global material temperature" is an artefact of our implementation.
When you have multiple extruders, there is a global set of settings as well as a set of settings for each of the extruders. Some settings are only specified in the global set, such as heated bed temperature. Some settings, such as extruder temperature, are settable per extruder and while they have some default value in the global set, you don't see that because the value for the extruder overrides it. The setting you see in the Cura GUI is the setting for one of the extruders (depending on which extruder tab you have selected).
The start g-code is not applicable to one or the other extruder. It just looks at the global setting values. It doesn't know which extruder the temperature must be set for in your custom start g-code.
We could let this always resolve to the first extruder. Perhaps that is the easiest solution.
Thanks for the update. The easiest solution for now is to always use extruder_0, but people need to know that they have to consider that.
I like it when we can leave the users in the dark :) and let us worry about what extruder will be used 1st.
For that to happen, the program needs to slice everything first and then look for which extruder is going to be used 1st and set that temp accordingly. I do not know what sequence is being used now in slicing.
for instance if extruder_1 is going to be used first the gcode would look like:
T1
start gcode
rest of the gcode
I do not know what sequence is being used now in slicing.
The front-end fills in the setting values first, then sends it over to CuraEngine. CuraEngine analyses the start g-code to see if there are any temperatures in there. If there are, it writes the start g-code to its output and then the actual g-code. If there aren't any temperature codes, it writes temperature codes first (with the correct extruder), then the start g-code and then the actual g-code. This g-code output is then sent back to the front-end so that it can send it over via wifi or save it on USB or whatever.
For that to happen, the program needs to slice everything first and then look for which extruder is going to be used 1st and set that temp accordingly.
This is a bit of a problem because the setting values are filled in with Python's formatting. If slicing needs to happen first you'd need to apply this formatting to all of the g-code output (where the start g-code is placed somewhere in between), which is prohibitively expensive. Or you'd need to implement our own formatting engine in C++ to interpret these settings. The last one is a better option but it's also more work and needs some refactoring because not all settings are sent to the engine.
A workaround for now is:
get the M109 S{material_print-temperature} out of your start gcode
put this in your "definition".def.json file:
"material_print_temp_wait": { "default_value": false },
"material_bed_temp_wait": { "default_value": false },
this way it will heat up the correct temps on the correct nozzles, but it will not wait for it(nozzles that are not being used or are not present at the time)
then before it does anything with the extruders add a
M104 T1 S21
M104 T2 S21
M104 T3 S21
G4 S50
so it will cool down unused extruders and wait 50 sec.(or whatever you need) to get to the correct temperature
This will need to assume that T0 always starts, which is absolutely not a good solution, but best for now.
Now lets see what to do with the extruder_start_gcode, as that really needs to be put after the heating commands and not before. Does any one know where I can look for that?
Cura should not attempt to heat up extruders that it doesn't use. We've made specific checks for that. Because it's hella annoying to test a print when it needs to heat up both extruders every time ;)
still I would like to know why this works correct for UM3 and not for all others.
I am new to Cura. I made json files to try to work with a Monoprice Dual Extruder. Cura recognizes the printer now. I would suggest a checkbox for each extruder to indicate if it's active for the particular print. I would suggest allowing separate "machine_start_gcodes" for each extruder in the ..def.json file. these would be included only if the extruder is active.
There are extruder start g-codes but they are inserted every time the extruder is switched.
Thanks for replying. I read that about independent tool gcode, and the problem of head switching. My thought was to add individual tool gcode to the machine definitions. This gcode is inserted if an extruder is explicitly selected to be used. I see the problem of when where and how to preheat and prime an extruder is complex. I use Slic3r and try to teach people in our makerspace to use it. People are often forgetting to pick the right profile. As a result, the extruders don't preheat properly.
On Apr 10, 2017, at 12:36 AM, Ghostkeeper notifications@github.com wrote:
There are extruder start g-codes but they are inserted every time the extruder is switched.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or mute the thread.
There's the settings machine_extruder_start_code
and machine_extruder_end_code
. The start code is inserted after every Tx
, where x
is the position of the extruder with that setting. The end code is inserted before switching away from the extruder with Ty
. The intent of these settings is to allow an extruder to do stuff like wiping off the nozzle after switching, or perhaps perform a nozzle switching movement.
The temperatures are regulated by Cura separately, as it needs to start pre-heating in time before the switch. Priming is also done separately on the first layer just before the extruder is used. It doesn't all happen at the start of the print. Cura ensures that the nozzle is hot by the time it needs to start printing.
This just got removed from our planning because it's older than 12 weeks.
Are you kidding? sorry... but older than 12 weeks means not important enough to fix... - right...? Really sorry to hear that...
No, just that it isn't likely that we will.
I'm not kidding. Our project manager shelves bugs and feature requests that are older than 12 weeks. He then allows 4 weeks for developers to comment on the ones that we find important and if it's not considered important the bug or feature gets deleted permanently.
The 4 weeks are going on now. I'm trying to get this one through.
@Ghostkeeper, thank you for supporting this fix... I think it´s important to safeguard and bugfix basic things like this to make a reliable software more reliable and trustworth.
See https://github.com/Ultimaker/Cura/issues/2971#issuecomment-351449419
It's definitely back on the urgent to fix list as well.
Just fixed this (hopefully) in 57651e837fd549c6531416450113a9addb43aab2.
@ChrisTerBeke : While you are at it :) could you also have a look at #1338
Basically the same point, not at machine_start_gcode, but at extruder_start_gcode
That's an engine issue, completely different code source than this issue.
This issue just passed internal QA, which means it'll be fixed in the next release.
Thanks! I’d like to try it, but I am having permission problems with git. Do I need to be in a development group?
You can always clone the repository as it is public. Please check the readme for details about pulling in the dependencies and building Cura.
If I'm reading this right, 57651e8 doesn't look like a fix for any extruders beyond extruder 0. It seems to me that what'd really be necessary to resolve this issue for dual-extruder printers is access to settings for all extruders, ie. extruder0_material_print_temperature
(Slic3r, if I'm not mistaken, just calls it extruder0_temperature
). Is there already an issue open for tracking this as a feature?
It seems to me that what'd really be necessary to resolve this issue for dual-extruder printers is access to settings for all extruders
I agree. Here's how I would propose to tackle this:
{setting_key, extruder_nr}
Omitting the extruder_nr
would result in the same way as it currently does, getting the value from the same stack as always. extruder_nr
could be specified as either a numeric value or as an setting, eg:
{material_standby_temperature}
in start gcode would get the (resolved) setting value from the global stack{material_standby_temperature, 1}
would get the value from the 2nd extruder{material_standby_temperature, support_extruder_nr}
would get the value from whatever extruder is set as support extruderAs a bonus an additional gcode replacement variable could be added named "initial_extruder_nr", pointing to the extruder that is the first extruder that will be active.
I will see if I can do the legwork for this. GcodeStartEndFormatter would need to detect the comma, and would need to get access to all stack setting values. Should not be too complicated (famous last words...)
The current implementation is a fix for the issue where the temperatures weren't applied at all (single extruder and multi-extrusion on ext. 0, which is like 99% of use cases). Having the ability to specify an extruder for settings that have multi-extrusion support would be nice, but I don't think it's a must have that the core team will work on anytime soon.
That’s why I suggested I do the legwork. I’m just looking for feedback on the above proposal before I start.
I think the core idea of @fieldOfView's proposal (being able to not only reference explicit extruders, but variable extruders) is good, but I think the implementation would be easier, and less likely to break other tools, if it were in the form of compound variable names that don't change the fundamental syntax of variable replacement (ie. {support_extruder_material_standby_temperature}
instead of {material_standby_temperature, support_extruder_nr}
) - for instance, I've seen at least one tool that parses commas as a G-code separator (so multi-line commands can be put on one line, in a context where each line defines a rule), meaning that it can't handle producing G-code containing commas.
Note that the commas will not appear in gcode exported by Cura; before it is exported these replacement tokens will have been... replaced (comma and all).
Knowing the codebase, having compound variable names will be a lot more complicated to implement and a lot less flexible.
I am open for suggestions for other separators (/, |, %, you name it) between the setting key and the extruder key, but "_" will not work because it is used in the setting key names.
Sure, but that's only not a problem if the tool in question comes after Cura - it's still a problem for processors that come before it (such as a toolchain that produces definition files for multiple frontends).
To be clear, the pseudocode for the implementation I'm describing here would be something like this:
map replacementVariables;
for {key, value} of machineSettings:
replacementVariables[key] = value;
for {number, settings} of extruderTrains:
for {key, value} of settings:
replacementVariables["extruder$number_$key"] = value;
for spec of ["support", "adhesion", "initial"]:
for {key, value} of specExtruders[spec].settings:
replacementVariables["${spec}_extruder_$key"] = value;
addOtherVariablesLikeDate(replacementVariables);
processedStartCode = processCustomGcode(startCode, replacementVariables);
processedEndCode = processCustomGcode(endCode, replacementVariables);
So, what tool do you know that processes gcode directly from the cura configuration files? Because that's the only way a tool could access the gcode snippets containing the replacement patterns.
Your pseudocode would not really work inside the current implementation of Cura (because that uses a Python string formatter), and is a lot slower and less flexible than what I propose (because with my proposal you are not limited to support, adhesion and initial extruder nrs, but you can also go much more specific and ask for support interface extruder, inner and outer wall extruder, support infill extruder etc.
Thanks for the feedback though.
Also, resolving this bug properly would yield a significantly more appealing workaround to #1128.
I was going to ask if it's possible for the frontend to replace start_extruder_nr
, but I guess that's not as pressing of a need post Ultimaker/CuraEngine#640 where every print is initially set to the initial extruder before running the start G-code. (Something like that would still be nice, though, as it would allow for start scripts to (a) do something with a different tool within the startup procedure, then switch back to the initial tool, and (b) include the start code for the appropriate extruder, provided that variable extruder settings are available.)
EDIT: oh hey there it is
As I just alluded to over in https://github.com/Ultimaker/Cura/pull/3068#issuecomment-354694897, if you're going to alter the behavior of _expandGcodeTokens
, what'd really be extensible (and structurally-compatible with Slic3r) would be to make the extruder train stacks available with suffixes like _t0
, and apply the replacement recursively so that, say, the retraction amount for outer walls could be queried as {retraction_amount_t{outer_wall_extruder_nr}}
.
Nesting variable replacement in this fashion also introduces the capability to do other kinds of meta-variables for free: for instance, if variables were to be introduced to quantify speeds for brims and skirts (instead of just rafts, as appears to be the case today), you could reference the adhesion speed as a general variable with {{adhesion_type}_speed}
.
Also, provided that you allow definitions to define custom variables, what would be devastatingly useful in this recursive-replacement paradigm would be to add a line for result["extruders_in_use"] = sorted(Application.getInstance().getExtruderManager().getUsedExtruderStacks()).join('_')
, as this would allow for printers to define custom G-code snippets (eg. priming ooze paths) for every active combination of extruders, like so (using YAML to represent the .def.json structure here for clarity):
settings:
machine_settings:
# description, icon, yadda yadda yadda
children:
machine_start_gcode:
default_value: |
G90
M140 S{print_bed_temperature}
{prime_using_{extruders_in_use}}
M73 P1
gcode_snippets: # or maybe these could just be siblings of machine_start_gcode, whatever
label: G-Code Snippets
type: category
description: Conditional G-codes for use in start and end routines
children:
prime_using_0:
label: Left Extruder Startup G-Code
description: G-Code that runs for left-extruder prints
type: str
default_value: |
T0
G92 E0
G1 X-70 Y-70 Z0.2 F2400.0 ; move to left edge
G1 X-70 Y70 E15 F1200.000 ; extrude left filament along edge
G92 E0
prime_using_1:
label: Right Extruder Startup G-Code
description: G-Code that runs for right-extruder prints
type: str
default_value: |
T1
G92 E0
G1 X70 Y-70 Z0.2 F2400.0 ; move to right edge
G1 X70 Y70 E15 F1200.000 ; extrude right filament along edge
G92 E0
prime_using_0_1:
label: Dual Extruder Startup G-Code
description: G-Code that runs for dual-extruder prints
type: str
default_value: |
T1
G92 E0
G1 X70 Y-70 Z0.2 F2400.0 ; move to right edge
G1 X70 Y70 E15 F1200.000 ; extrude right filament along edge
G92 E0
T0
G92 E0
G1 X-70 Y70 E15 F1200.000 ; extrude left filament along bottom edge
G92 E0
Thanks for your enthusiasm and ideas. I saw an opportunity to solve most of the issues with multi-extruder replacement patterns with fairly little changes (and fairly little chances of breaking stuff), and took some time to implement that.
Most of your suggestions are a lot more complex to implement with higher chances to screw things up and/or perform quite a bit worse. I am not saying (all of) your suggestions are bad, but the complexity of implementing it like that and associated risk is one of the reasons this issue has been open for so long without a fix.
I do agree there is still something that is not covered by my fix: There’s no way to affect only the used extruders, eg when heating up. I have not yet come up with a way to fix this that does not involve creating either conditional patterns (IF) or a loop (FOR).
Perhaps a solution would be to always only expose the used extruders to the setting replacement keys. Like, don't just allow the setting functions to select a subset of the extruders, but always provide that subset. I don't see a use case for requesting settings from extruders that aren't used.
So if you had
M104 S{material_standby_temperature, 0} T0
M104 S{material_standby_temperature, 1} T1
M104 S{material_standby_temperature, 2} T2
M104 S{material_standby_temperature, 3} T3
in a quad extruder machine, and only extruders 0 and 1 are used, this would result in
M104 S175 T0
M104 S175 T1
M104 S0 T2
M104 S0 T3
That would work with temperatures, but would it work with other settings, or would setting eg an accelleration value of an unused extruder to 0 break things?
I don't think acceleration is a problem since that is only output by the engine just before a line is drawn with a different acceleration than the previous line (iirc). The same goes for speed and jerk. But there are probably some things that we didn't think of.
But where would the software get that "0" fallback for when an extruder is disabled?
Most helpful comment
I agree. Here's how I would propose to tackle this:
{setting_key, extruder_nr}
Omitting the
extruder_nr
would result in the same way as it currently does, getting the value from the same stack as always.extruder_nr
could be specified as either a numeric value or as an setting, eg:{material_standby_temperature}
in start gcode would get the (resolved) setting value from the global stack{material_standby_temperature, 1}
would get the value from the 2nd extruder{material_standby_temperature, support_extruder_nr}
would get the value from whatever extruder is set as support extruderAs a bonus an additional gcode replacement variable could be added named "initial_extruder_nr", pointing to the extruder that is the first extruder that will be active.
I will see if I can do the legwork for this. GcodeStartEndFormatter would need to detect the comma, and would need to get access to all stack setting values. Should not be too complicated (famous last words...)