prusa3d / PrusaSlicer

G-code generator for 3D printers (RepRap, Makerbot, Ultimaker etc.)
https://www.prusa3d.com/prusaslicer/
GNU Affero General Public License v3.0
7.63k stars 1.92k forks source link

provide a better default extrusion width #10329

Open parabelboi opened 1 year ago

parabelboi commented 1 year ago

Problem Description

The necessity of providing (very) detailed extrusion width(s) seems unnecessary, especially in times of Arachne perimeter generator and dynamic layer heights. That is of course, because the real extrusion width is (presumably with all prints) different from what was specified.

Unfortunately, one often needs to specify concrete values, because the default values are not always suitable:

Especially the usage of a percentage value makes no sense with dynamic layer height: If layer height is between 0.05 mm and 0.25 mm, the resulting extrusion width would vary by the factor of 5. If the desired layer width is between 0.35 mm and 0.7 mm, they would only vary by factor 2. So no matter what percentage you configure, it would either not fit for thin layers or for thick layers or (more likely) for both.

So obviously a combination of both, layer height and nozzle width is needed.

Proposal

First of all, I would be more than happy, if only point 1) would be addressed:

  1. The default extrusion width should be set to (i.e. according to here): nozzle_diameter + layer_height

  2. The percentages of the Print Config should go differently into the equation. a) either like this (e.g. allowing values from -100% up to 100%): width(role_type) = nozzle_diameter + percentage(role_type) layer_height / 100 b) or if people like absolute percentages (reasonable range might be between 75% and 150%) width(role_type) = percentage(role_type) (nozzle_diameter + layer_height) / 100

2a) has the advantage, that smaller layer heights results in smaller differences between the nozzle size and the extrusion width. This is beneficial for getting high print speeds at thin layers with "auto speed". But on the other hand, one has to specify negative values if one wants to have an extrusion width that is smaller than the nozzle diameter.

In contrast to that, the solution 2b) would apply the percentage ratio also to the nozzle-diameters part of the sum. This would lead to problems with either thin layers, with thick layers or with both. So I'd clearly prefer solution 2a) over 2b).

Bonus

One does not need to maintain different print profiles anymore (at least not because of layer heights).

Details

The following change adds the needed parameter, while keeping the current behavior:

diff --git a/src/libslic3r/Flow.hpp b/src/libslic3r/Flow.hpp
index 6d999d1c5..f264284f3 100644
--- a/src/libslic3r/Flow.hpp
+++ b/src/libslic3r/Flow.hpp
@@ -107,7 +107,7 @@ public:

     // Sane extrusion width defautl based on nozzle diameter.
     // The defaults were derived from manual Prusa MK3 profiles.
-    static float auto_extrusion_width(FlowRole role, float nozzle_diameter);
+    static float auto_extrusion_width(FlowRole role, float nozzle_diameter, float height = .0f);

     // Extrusion width from full config, taking into account the defaults (when set to zero) and ratios (percentages).
     // Precise value depends on layer index (1st layer vs. other layers vs. variable layer height),
diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp
index 1084e6f10..6cc7a34c9 100644
--- a/src/libslic3r/Flow.cpp
+++ b/src/libslic3r/Flow.cpp
@@ -15,7 +15,7 @@ FlowErrorNegativeFlow::FlowErrorNegativeFlow() :
     FlowError("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?") {}

 // This static method returns a sane extrusion width default.
-float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
+float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter, float height)
 {
     switch (role) {
     case frSupportMaterial:
@@ -27,7 +27,7 @@ float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
     case frPerimeter:
     case frSolidInfill:
     case frInfill:
-        return 1.125f * nozzle_diameter;
+        return height > .0f ? height + nozzle_diameter : 1.125f * nozzle_diameter;
     }
 }

Changing also the following callers allowed a first experiment (with all extrusion width parameters set to zero): I successfully printed some object with dynamic layers between 0.05 mm and 0.45 mm (with a 0.6 mm nozzle). I also use "auto speed" which resulted in highest possible (within limits) print speed at thin layers (without visible problems) while having a reasonable slow print speed at thick layers.

@@ -98,7 +98,12 @@ double Flow::extrusion_width(const std::string& opt_key, const ConfigOptionFloat
        auto opt_nozzle_diameters = config.option<ConfigOptionFloats>("nozzle_diameter");
        if (opt_nozzle_diameters == nullptr)
                throw_on_missing_variable(opt_key, "nozzle_diameter");
-        return auto_extrusion_width(opt_key_to_flow_role(opt_key), float(opt_nozzle_diameters->get_at(first_printing_extruder)));
+        auto opt_key_layer_height = first_layer ? "first_layer_height" : "layer_height";
+        auto opt_layer_height = config.option(opt_key_layer_height);
+        if (opt_layer_height == nullptr)
+            throw_on_missing_variable(opt_key, opt_key_layer_height);
+        return auto_extrusion_width(opt_key_to_flow_role(opt_key), float(opt_nozzle_diameters->get_at(first_printing_extruder)),
+            opt->get_abs_value(opt_layer_height->getFloat()));
     }

        return opt->value;
@@ -120,7 +125,7 @@ Flow Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent
     float w;
     if (! width.percent && width.value == 0.) {
         // If user left option to 0, calculate a sane default width.
-        w = auto_extrusion_width(role, nozzle_diameter);
+        w = auto_extrusion_width(role, nozzle_diameter, height);
     } else {
         // If user set a manual value, use it.
         w = float(width.get_abs_value(height));

Possible Problems

Obviously, different extrusion widths would lead also to different infill ratios. But if one tries to keep a stable infill ratio across layers, the infill of different layers would not be aligned (which would reduce the strength of the infill). So, simply converting all callers of auto_extrusion_width() to provide a height parameter could obviously introduce problems.

parabelboi commented 1 year ago

Tests

The following tests compare 2.6.0-alpha6 against the patched version.

Summary

Print time got reduced from 96 min to 87 min (-9 min). Overall material increased from 84.3 g to 96.8 g (+12.5 g). The model weight has been increased from 73.6 g to 88.4g (+15.2g). The overall material flow changed significantly from 0.87 g/min to 1.1 g/min.

2.6.0-alpha6

image

2.6.0-alpha6 + patch

image

Checking infill

Infill layers are properly aligned (but I did not check with all infill types).

2.6.0-alpha6

Extrusion width ranges from 0.44 mm up to 1.06mm, but obviously only because of Arache perimeter generator. Almost all extrusions are between 0.6 mm and 0.7 mm.

image

2.6.0-alpha6 + patch

Please note that extrusion width ranges from 0.47mm up to 1.1 mm for infill and perimeters (but unfortunately not for support). However, the extrusion widths are distributed over the full range between 0.6 mm and 1.1 mm.

image

Checking support

Minor holes could be spotted in the areas with tall layers, with each version.

2.6.0-alpha6

image

2.6.0-alpha6 + patch

Worth to note that the width of support layers however is not changing with the layer height. So there is still room for improvement.

image

Checking speed

One would expect higher print speed because of the decreased print time, but the opposite is the case: Because of the increased extrusion width and the limited volume speed, the resulting print moves should actually be slower (at least where the print moves are long enough, so that the maximum volume speed can be reached). Only for the very few thin layers the patched version produced faster print speed. The unpatched version used extrusion width of 0.675 mm (1.125 x 0.6 mm). At layer heights below 0.075 mm, the patched version starts producing smaller extrusions (and therefore faster print moves) than the unpatched version.

2.6.0-alpha6

image

2.6.0-alpha6 + patch

image

Check resulting volume speed

Resulting volume speed stays below the upper limit (25 g/m^3) as shown below.

2.6.0-alpha6

image

2.6.0-alpha6 + patch

image

parabelboi commented 1 year ago

It seems like the support generation code does not rely on auto_extrusion_width(): The patch has been updated slightly to also enable the varying layer width for the support role. But the resulting support layers are still having the same width :-(

diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp
index 1084e6f10..5f64291dc 100644
--- a/src/libslic3r/Flow.cpp
+++ b/src/libslic3r/Flow.cpp
@@ -15,19 +15,19 @@ FlowErrorNegativeFlow::FlowErrorNegativeFlow() :
     FlowError("Flow::mm3_per_mm() produced negative flow. Did you set some extrusion width too small?") {}

 // This static method returns a sane extrusion width default.
-float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter)
+float Flow::auto_extrusion_width(FlowRole role, float nozzle_diameter, float height)
 {
     switch (role) {
-    case frSupportMaterial:
-    case frSupportMaterialInterface:
     case frTopSolidInfill:
         return nozzle_diameter;
     default:
+    case frSupportMaterial:
+    case frSupportMaterialInterface:
     case frExternalPerimeter:
     case frPerimeter:
     case frSolidInfill:
     case frInfill:
-        return 1.125f * nozzle_diameter;
+        return height > .0f ? height + nozzle_diameter : 1.125f * nozzle_diameter;
     }
 }
parabelboi commented 1 year ago

Testprint

Two cute articulated dolphins:

When looking at the infill and the inner perimeters, the one with the improved default width looks a bit stronger, but not by much.

image

When looking only at the outside perimeters, the results are not distinguishable.

image

As already stated in the issue, the instance with original defaults showed minor problems at very high print speeds, especially at solid infills. If solid infill would occur at low overhangs (not the case with the dolphin), the model would become unprintable, as the forces at the overhanging layers become too high. Usually I have to compensate this by specifying a lower extrusion width (e.g. 0.625 mm), which is not really suitable for 0.45mm layer height. Lowering the printing speed would also help, but that would hurt the print time too much, so one could also print thinner layers.

parabelboi commented 1 year ago

btw, I created a separate pull request #10340 because I did not know how to create a merge request for an existing issue. So I linked it to this issue.

parabelboi commented 1 year ago

Another benchy comparison

Two benchies, one with the extrusion width manually set to what the current defaults are (0.675 mm default extrusion width, 0.6 mm for top infill).

2.6.0-alpha6

Both benchies should be sliced with the same extrusion widths:

image

2.6.0-alpha6 + patch

Here the same 3mf file should be sliced with some improvements for the one instance, while the other should show no difference to the results that 2.6.0-alpha6 produced:

image

Because of the wider extrusion width the arachne perimeter generator gets much more active now ;-)

image

Summary

The improved defaults resulted in

image

freakydude commented 1 year ago

Sounds very logic to me.

I had some problems with the extrusion width parameters in general even before thinking about a optimum or what happens on variable layer height.

  1. The combination of percentage and absolute values
    1. In addition that the percentage are sometimes in relation to nozzle size or in contrast in relation to layer height. All in the same list of parameters ... makes it very confusing
  2. The combination with arcane (which is the good new default) - still don't know for sure what the different variants of extusion width parameters influence in this case - and how??

Where can we find answers to these questions?

And now with this issue and as you described it exemplary there are additional reasons to rethink these extrusion parameters and clarify what these really do.

Additional information: I played around with 0.6 default extrusion width (0.4 nozzle + 0.2 layer height). I saw, that bridges are influenced by this.

bridge04ew bridge06ew

While switching between default extrusion with 0.4 to 0.6 to bridges, it happens what we expect. 6x 0.4 perimeter are replaced by 4x 0.6 perimeter. But is that really right for bridges? In contrary to the example "layer on layer" the gaps between the lines will be filled ... for bridges not. They are not squeezed together, because they are in the air.

Default Extrusion Width Top: 0.4 Bottom: 0.6 Real world

Is there a solution? Do we need a extra parameter for bridges?

How can I help improving that and to be merged into the next prusa slicer version?

parabelboi commented 1 year ago

They are not squeezed together, because they are in the air.

Thanks for testing and for the very good point. Indeed, bridges are not looking any good with this change. I guess I should have printed the benchies instead of the dolphins ;-)

To compensate the wider extrusions, the bridge_flow_ratio could be reduced. But since it's a ratio, it should be applied independently from the desired extrusions width. So it would just be a workaround.

I'll check where this value is incorporated. Maybe it's applied to the (now) increased flow. I guess, it should be applied to a flow that only incorporates the nozzle_diameter.

Update: With enabled "thick bridges", the flow is only calculated on nozzle_diameter (see here). After enabling it, everything looks fine (at least in the preview). I'll be doing a testprint (hopefully by tomorrow) and report back.

freakydude commented 1 year ago

Hm. For me it's vice versa.

The screenshots were made with "Thick Bridges" enabled. If I disable the option, the gap is gone. So what remains are 4 instead of the 6 lines in this example - without a gap.

That's correct. So far so good.

Printing with 0.6 instead of 0.4 default extrusion width looks in my new print similar with and without thick bridges and where better with 0.4 + thick bridges before.

I could imagine that it is because the thicker 0.6 instead of 0.4mm extrusion sags more or got less cooled. I am not sure yet. I think it's not a bug, its a consequence of a wider extrusion

If you have time you could do some experiments your own (my used bridging test can be found here)

Additional hint, as I said before - i didn't compile your version - i just replaced the values manually ew

parabelboi commented 1 year ago

I found some more (but unrelated) problems:

  1. Although with thick_bridges the flow is looking fine (they are not hanging), the print speed (4 mm/s) dropped significantly below the specified min_print_speed of 10mm/s:
    • layer time dropped from 11s (at the last layer before the bridges) to 16 minutes (omg) at the bridge layer
    • but since 2.6.0-alpha6 shows the same behavior, I'm ignoring it for now

image

  1. The layer(s) above the bridge got printed without any slow down:
    • there was not enough stiffness to make these layers stick to the bridge (since there is no support, this can be expected)
    • also some of the (formally intact) bridge perimeters got ripped off

The image shows the ripped off layers on the bridge-test and the benchy with the way too thick bridges (when thick_bridges is off). Sorry for the mjpeg artifacts.

image

When sliced with fixed layers (i.e. 0.16mm), the resulting speed on the layer above the bridge was more reasonable:

image

So I'd say bridging (with thick_bridges=enabled) is not influenced by the changed default extrusion width. But I still need to check how the thick_bridges=disabled case can be fixed, hopefully by tomorrow.

freakydude commented 1 year ago

It's not the right issue, but I see often unrelated side effects of settings or combinations of settings of the slicer itself. Maybe it's time for general refactoring ;-) For example: If you play with the options: detect bridging perimeters, extra perimeters on overhangs, bridging angle and number of vertical shell perimeter .... do sometimes unexpected things..

I think now we got even more of these options: thick bridges and default extrusion width ;-)

In this example, there is no overhang. Its a complicated bridge ;-)

Hopefully ok - IF overhang perimeter is printed before bridge infill Extr Width: 0.4 Detect Briges: On Extra perimeter on overhangs: Off Screenshot 2023-04-18 212224

Prints in the air Extr Width: 0.4 Detect Bridges: On Extra perimeter on overhangs: On Screenshot 2023-04-18 212353

Extr Width: 0.4 Detect Bridges: Off Extra perimeter on overhangs: On Screenshot 2023-04-18 212444

Same Problem, maybe worse Extr Width: 0.6 Detect Briges: Off Extra perimeter on overhangs: On Screenshot 2023-04-18 212606

Same with "overhang" perimeters

Extr Width: 0.6 Detect Bridges: ON Extra perimeter on overhangs: Off Thick bridges: Off

Screenshot 2023-04-18 213327

This time not even close....

Extr Width: 0.6 Detect Bridges: ON Extra perimeter on overhangs: Off Thick bridges: On Screenshot 2023-04-18 213614

parabelboi commented 1 year ago

Yeah, some options definitively do not work well together. Unfortunately refactoring is way beyond my capabilities :-(

I hope that we can at least remove the need to specify extrusion width(s), as it limits the full potential of variable_layer_height (esp. if used with auto_speed).

Also I'd like to see version 2.6 being released very soon (because of organic support, Kudos for that btw). So I'd rather keep the changes as minimal and unintrusive as possible.

parabelboi commented 1 year ago

So, here is the analysis for the way-too-thick bridge on the benchy (thick_bridges=0):

So, first of all, I am glad, that my changes are not the root cause of this.

But they have triggered the problem:

Just by the tiny change of the default extrusion width from 0.675mm to 0.7mm (+3.7%), the resulting bridge flow has been more than doubled. Obviously this cannot be compensated by the bridge_flow_ratio. Because at another bridge (even at the same model), the perimeter generator might not have reduced the number of perimeters. So at that bridge, the reduction of the bridge_flow_ratio would be counter productive.

I think that this proves that: With thick_bridges=0 the resulting bridges might be much thicker than with thick_bridges=1. So the current implementation of thick_bridges=0 is broken (at least to some degree). I don't know all config options that are required to create this effect, but it would be nice, if a fix could cover ALL of them ;-)

Even if it produced better results (as it did for me at some point), it was only by chance (i.e. if users configured a extrusion width lower than the 1.125 * nozzle_size, the perimeter generator has only a smaller chance of reducing the number of perimeters).

But here is a simple fix that will just work: If thick_bridges=0, just take the minimum flow of both calculations (but of course not the other way around).

But I guess that should be a separate issue.

Anyways, regarding workarounds I just want to add:

If bridge_flow_ratio setting would be used to compensate the broken flow problem (thick_bridges=0):

parabelboi commented 1 year ago

Testing bridges

After also applying https://github.com/prusa3d/PrusaSlicer/pull/10405, I printed two more benchies:

As expected, the left benchy has indeed a slightly thicker bridge as the right one. But both bridges are acceptable (sorry again for the bad image quality).

image

freakydude commented 1 year ago

Picture Quality is really bad ... I will help you doing a test print the next days again

parabelboi commented 1 year ago

I was able to print the bridge-test using the same profile on the same printer, but with two different nozzle sizes (0.6 mm and 0.25 mm nozzles), using 2.6.0-alpha6 plus #10405 and #10340 applied.

Steps before (re-)slicing the model:

As expected, I had to enable thick_bridges. Although the bridges at 3Dbechie's roof looked better with thick_bridges=off (with #10405 applied), this bridge-test definitively requires to them to be enabled.

Additional step to disable way-to-low print speed at bridge layer:

Additional steps to allow layers on top of the bridge to be molten with the bridge layer:

I'd guess one could make bridge perimeters not taken into account when calculating enable_dynamic_overhang_speeds to have a reduced speed.

I don't know why bridge_speed is not used, if enable_dynamic_overhang_speeds is enabled. Even if an overhanging layer has 0% overlap, it is still different from a bridge: The bridge has 0% overlap over the total range, while overhanging perimeters would have at least some overlap at certain parts of the perimeter. So I'd consider it a bug.

But even if this is the intended behavior: then the bridge_speed should at least be greyed out.

Unfortunately, disabling enable_dynamic_overhang_speeds leads to the usage of bridge_speed only for bridging perimeters. The infill of the bridge layer would be printed with normal infill speed (might depend on extra_perimeters_overhangs).

So there are more conflicting configuration options. Unfortunately I have seen no feedback from developers on my current merge-requests for more than two weeks now :-( I'd like to further investigate how things can get improved. But not if the chance of a merge is near zero.

image

PS: I was too lazy to peel off the brim.