Browse Source

New experimental autospeed feature. #2810

Alessandro Ranellucci 9 years ago
parent
commit
7f70da97b4

+ 6 - 3
lib/Slic3r/GCode.pm

@@ -27,6 +27,7 @@ has '_seam_position'     => (is => 'ro', default => sub { {} });  # $object => p
 has 'first_layer'        => (is => 'rw', default => sub {0});   # this flag triggers first layer speeds
 has 'elapsed_time'       => (is => 'rw', default => sub {0} );  # seconds
 has 'last_pos'           => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } );
+has 'volumetric_speed'   => (is => 'rw', default => sub {0});
 
 sub apply_print_config {
     my ($self, $print_config) = @_;
@@ -298,11 +299,13 @@ sub _extrude_path {
             die "Invalid speed";
         }
     }
-    my $F = $speed * 60;  # convert mm/sec to mm/min
-    
     if ($self->first_layer) {
-        $F = $self->config->get_abs_value_over('first_layer_speed', $F/60) * 60;
+        $speed = $self->config->get_abs_value_over('first_layer_speed', $speed);
     }
+    if ($self->volumetric_speed != 0) {
+        $speed ||= $self->volumetric_speed / $path->mm3_per_mm;
+    }
+    my $F = $speed * 60;  # convert mm/sec to mm/min
     
     # extrude arc or line
     $gcode .= ";_BRIDGE_FAN_START\n" if $path->is_bridge && $self->enable_cooling_markers;

+ 6 - 0
lib/Slic3r/GUI/Tab.pm

@@ -450,6 +450,7 @@ sub build {
         infill_every_layers infill_only_where_needed
         solid_infill_every_layers fill_angle solid_infill_below_area 
         only_retract_when_crossing_perimeters infill_first
+        max_print_speed max_volumetric_speed
         perimeter_speed small_perimeter_speed external_perimeter_speed infill_speed 
         solid_infill_speed top_solid_infill_speed support_material_speed 
         support_material_interface_speed bridge_speed gap_fill_speed
@@ -607,6 +608,11 @@ sub build {
             $optgroup->append_single_option_line('first_layer_acceleration');
             $optgroup->append_single_option_line('default_acceleration');
         }
+        {
+            my $optgroup = $page->new_optgroup('Autospeed (advanced)');
+            $optgroup->append_single_option_line('max_print_speed');
+            $optgroup->append_single_option_line('max_volumetric_speed');
+        }
     }
     
     {

+ 53 - 2
lib/Slic3r/Print/GCode.pm

@@ -15,7 +15,7 @@ has '_brim_done'                     => (is => 'rw');
 has '_second_layer_things_done'      => (is => 'rw');
 has '_last_obj_copy'                 => (is => 'rw');
 
-use List::Util qw(first sum);
+use List::Util qw(first sum min max);
 use Slic3r::Flow ':roles';
 use Slic3r::Geometry qw(X Y scale unscale chained_path convex_hull);
 use Slic3r::Geometry::Clipper qw(JT_SQUARE union_ex offset);
@@ -40,9 +40,60 @@ sub BUILD {
             layer_count         => $layer_count,
             enable_cooling_markers => 1,
         );
+        $self->_gcodegen($gcodegen);
         $gcodegen->apply_print_config($self->config);
         $gcodegen->set_extruders($self->print->extruders);
-        $self->_gcodegen($gcodegen);
+        
+        # initialize autospeed
+        {
+            # get the minimum cross-section used in the print
+            my @mm3_per_mm = ();
+            foreach my $object (@{$self->print->objects}) {
+                foreach my $region_id (0..$#{$self->print->regions}) {
+                    my $region = $self->print->get_region($region_id);
+                    foreach my $layer (@{$object->layers}) {
+                        my $layerm = $layer->get_region($region_id);
+                        if ($region->config->get_abs_value('perimeter_speed') == 0
+                            || $region->config->get_abs_value('small_perimeter_speed') == 0
+                            || $region->config->get_abs_value('external_perimeter_speed') == 0
+                            || $region->config->get_abs_value('bridge_speed') == 0) {
+                            push @mm3_per_mm, $layerm->perimeters->min_mm3_per_mm;
+                        }
+                        if ($region->config->get_abs_value('infill_speed') == 0
+                            || $region->config->get_abs_value('solid_infill_speed') == 0
+                            || $region->config->get_abs_value('top_solid_infill_speed') == 0
+                            || $region->config->get_abs_value('bridge_speed') == 0) {
+                            push @mm3_per_mm, $layerm->fills->min_mm3_per_mm;
+                        }
+                    }
+                }
+                if ($object->config->get_abs_value('support_material_speed') == 0
+                    || $object->config->get_abs_value('support_material_interface_speed') == 0) {
+                    foreach my $layer (@{$object->support_layers}) {
+                        push @mm3_per_mm, $layer->support_fills->min_mm3_per_mm;
+                        push @mm3_per_mm, $layer->support_interface_fills->min_mm3_per_mm;
+                    }
+                }
+            }
+            my $min_mm3_per_mm = min(@mm3_per_mm);
+            if ($min_mm3_per_mm > 0) {
+                # In order to honor max_print_speed we need to find a target volumetric
+                # speed that we can use throughout the print. So we define this target 
+                # volumetric speed as the volumetric speed produced by printing the 
+                # smallest cross-section at the maximum speed: any larger cross-section
+                # will need slower feedrates.
+                my $volumetric_speed = $min_mm3_per_mm * $self->config->max_print_speed;
+                
+                # limit such volumetric speed with max_volumetric_speed if set
+                if ($self->config->max_volumetric_speed > 0) {
+                    $volumetric_speed = min(
+                        $volumetric_speed,
+                        $self->config->max_volumetric_speed,
+                    );
+                }
+                $gcodegen->volumetric_speed($volumetric_speed);
+            }
+        }
     }
     
     $self->_cooling_buffer(Slic3r::GCode::CoolingBuffer->new(

+ 17 - 3
utils/post-processing/flowrate.pl

@@ -6,17 +6,28 @@
 use strict;
 use warnings;
 
+use constant PI => 3.141592653589793238;
+my @filament_diameter = split /,/, $ENV{SLIC3R_FILAMENT_DIAMETER};
+
 my $E = 0;
-my ($X, $Y);
+my $T = 0;
+my ($X, $Y, $F);
 while (<>) {
+    if (/^G1.*? F([0-9.]+)/) {
+        $F = $1;
+    }
     if (/^G1 X([0-9.]+) Y([0-9.]+).*? E([0-9.]+)/) {
         my ($x, $y, $e) = ($1, $2, $3);
         my $e_length = $e - $E;
         if ($e_length > 0 && defined $X && defined $Y) {
             my $dist = sqrt( (($x-$X)**2) + (($y-$Y)**2) );
             if ($dist > 0) {
-                my $flowrate = sprintf '%.2f', $e_length / $dist;
-                s/(\R+)/ ; XY dist = $dist ; E dist = $e_length ; E\/XY = $flowrate mm\/mm$1/;
+                my $mm_per_mm   = $e_length / $dist;  # dE/dXY
+                my $mm3_per_mm  = ($filament_diameter[$T] ** 2) * PI/4 * $mm_per_mm;
+                my $vol_speed   = $F/60 * $mm3_per_mm;
+                my $comment = sprintf ' ; dXY = %.3fmm ; dE = %.5fmm ; dE/XY = %.5fmm/mm; volspeed = %.5fmm^3/sec',
+                    $dist, $e_length, $mm_per_mm, $vol_speed;
+                s/(\R+)/$comment$1/;
             }
         }
         $E = $e;
@@ -33,6 +44,9 @@ while (<>) {
     if (/^G92 E0/) {
         $E = 0;
     }
+    if (/^T(\d+)/) {
+        $T = $1;
+    }
     print;
 }
 

+ 15 - 0
xs/src/libslic3r/ExtrusionEntity.cpp

@@ -3,6 +3,7 @@
 #include "ExPolygonCollection.hpp"
 #include "ClipperUtils.hpp"
 #include "Extruder.hpp"
+#include <cmath>
 #include <sstream>
 
 namespace Slic3r {
@@ -375,6 +376,20 @@ ExtrusionLoop::grow() const
     return pp;
 }
 
+double
+ExtrusionLoop::min_mm3_per_mm() const
+{
+    double min_mm3_per_mm = 0;
+    for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) {
+        if (min_mm3_per_mm == 0) {
+            min_mm3_per_mm = path->mm3_per_mm;
+        } else {
+            min_mm3_per_mm = fmin(min_mm3_per_mm, path->mm3_per_mm);
+        }
+    }
+    return min_mm3_per_mm;
+}
+
 #ifdef SLIC3RXS
 REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
 #endif

+ 5 - 0
xs/src/libslic3r/ExtrusionEntity.hpp

@@ -50,6 +50,7 @@ class ExtrusionEntity
     virtual Point first_point() const = 0;
     virtual Point last_point() const = 0;
     virtual Polygons grow() const = 0;
+    virtual double min_mm3_per_mm() const = 0;
 };
 
 typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
@@ -81,6 +82,9 @@ class ExtrusionPath : public ExtrusionEntity
         double xofs, double yofs, std::string extrusion_axis,
         std::string gcode_line_suffix) const;
     Polygons grow() const;
+    double min_mm3_per_mm() const {
+        return this->mm3_per_mm;
+    };
 
     private:
     void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
@@ -117,6 +121,7 @@ class ExtrusionLoop : public ExtrusionEntity
     bool is_infill() const;
     bool is_solid_infill() const;
     Polygons grow() const;
+    double min_mm3_per_mm() const;
 };
 
 }

+ 32 - 0
xs/src/libslic3r/ExtrusionEntityCollection.cpp

@@ -1,5 +1,6 @@
 #include "ExtrusionEntityCollection.hpp"
 #include <algorithm>
+#include <cmath>
 #include <map>
 
 namespace Slic3r {
@@ -137,6 +138,37 @@ ExtrusionEntityCollection::items_count() const
     return count;
 }
 
+/* Returns a single vector of pointers to all non-collection items contained in this one */
+void
+ExtrusionEntityCollection::flatten(ExtrusionEntityCollection* retval) const
+{
+    for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+        if ((*it)->is_collection()) {
+            ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it);
+            ExtrusionEntityCollection contents;
+            collection->flatten(&contents);
+            retval->entities.insert(retval->entities.end(), contents.entities.begin(), contents.entities.end());
+        } else {
+            retval->entities.push_back((*it)->clone());
+        }
+    }
+}
+
+double
+ExtrusionEntityCollection::min_mm3_per_mm() const
+{
+    double min_mm3_per_mm = 0;
+    for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+        double mm3_per_mm = (*it)->min_mm3_per_mm();
+        if (min_mm3_per_mm == 0) {
+            min_mm3_per_mm = mm3_per_mm;
+        } else {
+            min_mm3_per_mm = fmin(min_mm3_per_mm, mm3_per_mm);
+        }
+    }
+    return min_mm3_per_mm;
+}
+
 #ifdef SLIC3RXS
 // there is no ExtrusionLoop::Collection or ExtrusionEntity::Collection
 REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");

+ 2 - 0
xs/src/libslic3r/ExtrusionEntityCollection.hpp

@@ -30,6 +30,8 @@ class ExtrusionEntityCollection : public ExtrusionEntity
     Point last_point() const;
     Polygons grow() const;
     size_t items_count() const;
+    void flatten(ExtrusionEntityCollection* retval) const;
+    double min_mm3_per_mm() const;
 };
 
 }

+ 1 - 1
xs/src/libslic3r/Print.hpp

@@ -61,7 +61,7 @@ class PrintRegion
 
     private:
     Print* _print;
-
+    
     PrintRegion(Print* print);
     ~PrintRegion();
 };

+ 16 - 0
xs/src/libslic3r/PrintConfig.cpp

@@ -501,6 +501,22 @@ PrintConfigDef::build_def() {
     Options["min_print_speed"].min = 0;
     Options["min_print_speed"].max = 1000;
 
+    Options["max_print_speed"].type = coFloat;
+    Options["max_print_speed"].label = "Max print speed";
+    Options["max_print_speed"].tooltip = "When setting other speed settings to 0 Slic3r will autocalculate the optimal speed in order to keep constant extruder pressure. This experimental setting is used to set the highest print speed you want to allow.";
+    Options["max_print_speed"].sidetext = "mm/s";
+    Options["max_print_speed"].cli = "max-print-speed=f";
+    Options["max_print_speed"].min = 1;
+    Options["max_print_speed"].max = 1000;
+
+    Options["max_volumetric_speed"].type = coFloat;
+    Options["max_volumetric_speed"].label = "Max volumetric speed";
+    Options["max_volumetric_speed"].tooltip = "When setting other speed settings to 0 Slic3r will autocalculate the optimal speed in order to keep constant extruder pressure. This experimental setting is used to set the maximum volumetric speed your extruder supports.";
+    Options["max_volumetric_speed"].sidetext = "mm³/s";
+    Options["max_volumetric_speed"].cli = "max-volumetric-speed=f";
+    Options["max_volumetric_speed"].min = 0;
+    Options["max_volumetric_speed"].max = 1000;
+
     Options["min_skirt_length"].type = coFloat;
     Options["min_skirt_length"].label = "Minimum extrusion length";
     Options["min_skirt_length"].tooltip = "Generate no less than the number of skirt loops required to consume the specified amount of filament on the bottom layer. For multi-extruder machines, this minimum applies to each extruder.";

Some files were not shown because too many files changed in this diff