diff --git a/README.md b/README.md index 8d39dbec2..4e35d5572 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,8 @@ The author of the Silk icon set is Mark James. --gcode-comments Make G-code verbose by adding comments (default: no) --vibration-limit Limit the frequency of moves on X and Y axes (Hz, set zero to disable; default: 0) + --pressure-advance Adjust pressure using the experimental advance algorithm (K constant, + set zero to disable; default: 0) Filament options: --filament-diameter Diameter in mm of your raw filament (default: 3) diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index bb3352994..d9b159118 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -51,6 +51,7 @@ use Slic3r::GCode::CoolingBuffer; use Slic3r::GCode::Layer; use Slic3r::GCode::MotionPlanner; use Slic3r::GCode::PlaceholderParser; +use Slic3r::GCode::PressureRegulator; use Slic3r::GCode::Reader; use Slic3r::GCode::SpiralVase; use Slic3r::GCode::VibrationLimit; diff --git a/lib/Slic3r/GCode/Layer.pm b/lib/Slic3r/GCode/Layer.pm index af637b167..b13eab6a0 100644 --- a/lib/Slic3r/GCode/Layer.pm +++ b/lib/Slic3r/GCode/Layer.pm @@ -11,6 +11,7 @@ has 'origin' => (is => 'ro', default => sub { Slic3r::Poi has 'spiralvase' => (is => 'lazy'); has 'vibration_limit' => (is => 'lazy'); has 'arc_fitting' => (is => 'lazy'); +has 'pressure_regulator' => (is => 'lazy'); has 'skirt_done' => (is => 'rw', default => sub { {} }); # print_z => 1 has 'brim_done' => (is => 'rw'); has 'second_layer_things_done' => (is => 'rw'); @@ -40,6 +41,14 @@ sub _build_arc_fitting { : undef; } +sub _build_pressure_regulator { + my $self = shift; + + return $self->print->config->pressure_advance > 0 + ? Slic3r::GCode::PressureRegulator->new(config => $self->print->config) + : undef; +} + sub process_layer { my $self = shift; my ($layer, $object_copies) = @_; @@ -197,6 +206,10 @@ sub process_layer { $gcode = $self->vibration_limit->process($gcode) if $self->print->config->vibration_limit != 0; + # apply pressure regulation if enabled + $gcode = $self->pressure_regulator->process($gcode) + if $self->print->config->pressure_advance > 0; + # apply arc fitting if enabled $gcode = $self->arc_fitting->process($gcode) if $self->print->config->gcode_arcs; diff --git a/lib/Slic3r/GCode/PressureRegulator.pm b/lib/Slic3r/GCode/PressureRegulator.pm new file mode 100644 index 000000000..e59e09e25 --- /dev/null +++ b/lib/Slic3r/GCode/PressureRegulator.pm @@ -0,0 +1,78 @@ +package Slic3r::GCode::PressureRegulator; +use Moo; + +has 'config' => (is => 'ro', required => 1); +has 'enable' => (is => 'rw', default => sub { 0 }); +has 'reader' => (is => 'ro', default => sub { Slic3r::GCode::Reader->new }); +has '_extrusion_axis' => (is => 'rw', default => sub { "E" }); +has '_tool' => (is => 'rw', default => sub { 0 }); +has '_advance' => (is => 'rw', default => sub { 0 }); # extra E injected + +use Slic3r::Geometry qw(epsilon); + +# Acknowledgements: +# The advance algorithm was proposed by Matthew Roberts. +# The initial work on this Slic3r feature was done by Luís Andrade (lluis) + +sub BUILD { + my ($self) = @_; + + $self->reader->apply_print_config($self->config); + $self->_extrusion_axis($self->config->get_extrusion_axis); +} + +sub process { + my $self = shift; + my ($gcode) = @_; + + my $new_gcode = ""; + + $self->reader->parse($gcode, sub { + my ($reader, $cmd, $args, $info) = @_; + + if ($cmd =~ /^T(\d+)/) { + $self->_tool($1); + } elsif ($info->{extruding} && $info->{dist_XY} > 0) { + # This is a print move. + if (exists $args->{F}) { + # We are setting a (potentially) new speed, so we calculate the new advance amount. + + # First calculate relative flow rate (mm of filament over mm of travel) + my $rel_flow_rate = $info->{dist_E} / $info->{dist_XY}; + + # Then calculate absolute flow rate (mm/sec of feedstock) + my $flow_rate = $rel_flow_rate * $args->{F} / 60; + + # And finally calculate advance by using the user-configured K factor. + my $new_advance = $self->config->pressure_advance * ($flow_rate**2); + + if (abs($new_advance - $self->_advance) > 1E-5) { + my $new_E = ($self->config->use_relative_e_distances ? 0 : $reader->E) + ($new_advance - $self->_advance); + $new_gcode .= sprintf "G1 %s%.5f F%.3f ; pressure advance\n", + $self->_extrusion_axis, $new_E, $self->unretract_speed; + $new_gcode .= sprintf "G92 %s%.5f ; restore E\n", $self->_extrusion_axis, $reader->E + if !$self->config->use_relative_e_distances; + $self->_advance($new_advance); + } + } + } elsif (($info->{retracting} || $cmd eq 'G10') && $self->_advance != 0) { + # We need to bring pressure to zero when retracting. + my $new_E = ($self->config->use_relative_e_distances ? 0 : $reader->E) - $self->_advance; + $new_gcode .= sprintf "G1 %s%.5f F%.3f ; pressure discharge\n", + $self->_extrusion_axis, $new_E, $args->{F} // $self->unretract_speed; + $new_gcode .= sprintf "G92 %s%.5f ; restore E\n", $self->_extrusion_axis, $reader->E + if !$self->config->use_relative_e_distances; + } + + $new_gcode .= "$info->{raw}\n"; + }); + + return $new_gcode; +} + +sub unretract_speed { + my ($self) = @_; + return $self->config->get_at('retract_speed', $self->_tool) * 60; +} + +1; diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index a992195b3..0121a8b20 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -894,7 +894,7 @@ sub build { $self->init_config_options(qw( bed_shape z_offset gcode_flavor use_relative_e_distances - use_firmware_retraction vibration_limit + use_firmware_retraction pressure_advance vibration_limit start_gcode end_gcode layer_gcode toolchange_gcode nozzle_diameter extruder_offset retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe @@ -970,6 +970,7 @@ sub build { { my $optgroup = $page->new_optgroup('Advanced'); $optgroup->append_single_option_line('use_firmware_retraction'); + $optgroup->append_single_option_line('pressure_advance'); $optgroup->append_single_option_line('vibration_limit'); } } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 06e66476f..dca82fc2b 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -667,7 +667,7 @@ sub write_gcode { } # write end commands to file - print $fh $gcodegen->retract; + print $fh $gcodegen->retract; # TODO: process this retract through PressureRegulator in order to discharge fully print $fh $gcodegen->writer->set_fan(0); printf $fh "%s\n", $gcodegen->placeholder_parser->process($self->config->end_gcode); print $fh $gcodegen->writer->update_progress($gcodegen->layer_count, $gcodegen->layer_count, 1); # 100% diff --git a/slic3r.pl b/slic3r.pl index 8c3a9c2ca..cd8ddd371 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -291,6 +291,8 @@ $j --gcode-comments Make G-code verbose by adding comments (default: no) --vibration-limit Limit the frequency of moves on X and Y axes (Hz, set zero to disable; default: $config->{vibration_limit}) + --pressure-advance Adjust pressure using the experimental advance algorithm (K constant, + set zero to disable; default: $config->{pressure_advance}) Filament options: --filament-diameter Diameter in mm of your raw filament (default: $config->{filament_diameter}->[0]) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 3a34c32de..0ced2c832 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -550,6 +550,12 @@ PrintConfigDef::build_def() { Options["post_process"].full_width = true; Options["post_process"].height = 60; + Options["pressure_advance"].type = coFloat; + Options["pressure_advance"].label = "Pressure advance"; + Options["pressure_advance"].tooltip = "When set to a non-zero value, this experimental option enables pressure regulation. It's the K constant for the advance algorithm that pushes more or less filament upon speed changes. It's useful for Bowden-tube extruders. Reasonable values are in range 0-10."; + Options["pressure_advance"].cli = "pressure-advance=f"; + Options["pressure_advance"].min = 0; + Options["raft_layers"].type = coInt; Options["raft_layers"].label = "Raft layers"; Options["raft_layers"].category = "Support material"; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 9a87ea884..c1e6ac69f 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -319,6 +319,7 @@ class GCodeConfig : public virtual StaticPrintConfig ConfigOptionFloats filament_diameter; ConfigOptionBool gcode_comments; ConfigOptionEnum gcode_flavor; + ConfigOptionFloat pressure_advance; ConfigOptionFloats retract_length; ConfigOptionFloats retract_length_toolchange; ConfigOptionFloats retract_lift; @@ -337,6 +338,7 @@ class GCodeConfig : public virtual StaticPrintConfig this->filament_diameter.values[0] = 3; this->gcode_comments.value = false; this->gcode_flavor.value = gcfRepRap; + this->pressure_advance.value = 0; this->retract_length.values.resize(1); this->retract_length.values[0] = 1; this->retract_length_toolchange.values.resize(1); @@ -360,6 +362,7 @@ class GCodeConfig : public virtual StaticPrintConfig if (opt_key == "filament_diameter") return &this->filament_diameter; if (opt_key == "gcode_comments") return &this->gcode_comments; if (opt_key == "gcode_flavor") return &this->gcode_flavor; + if (opt_key == "pressure_advance") return &this->pressure_advance; if (opt_key == "retract_length") return &this->retract_length; if (opt_key == "retract_length_toolchange") return &this->retract_length_toolchange; if (opt_key == "retract_lift") return &this->retract_lift;