diff --git a/README.markdown b/README.markdown index 3d708d722..4fa28d7a3 100644 --- a/README.markdown +++ b/README.markdown @@ -263,7 +263,8 @@ The author of the Silk icon set is Mark James. --support-material-extrusion-width Set a different extrusion width for support material --bridge-flow-ratio Multiplier for extrusion when bridging (> 0, default: 1) - + --vibration-limit Experimental frequency limit to avoid resonance (Hz, default: 15) + Multiple extruder options: --extruder-offset Offset of each extruder, if firmware doesn't handle the displacement (can be specified multiple times, default: 0x0) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 6969633f8..49542067b 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -412,7 +412,7 @@ our $Options = { }, 'vibration_limit' => { label => 'Vibration limit', - tooltip => 'This experimental option will slow down those parts hitting the configured frequency limit. The purpose of limiting vibrations is to avoid mechanical resonance.', + tooltip => 'This experimental option will slow down those moves hitting the configured frequency limit. The purpose of limiting vibrations is to avoid mechanical resonance. Set zero to disable.', sidetext => 'Hz', cli => 'vibration-limit=f', type => 'f', diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index f725ee79d..8be61946d 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -180,23 +180,55 @@ sub extrude_path { $self->speed( $role_speeds{$path->role} || die "Unknown role: " . $path->role ); my $path_length = 0; if ($path->isa('Slic3r::ExtrusionPath::Arc')) { - $path_length = $path->length; + $path_length = unscale $path->length; $gcode .= $self->G2_G3($path->points->[-1], $path->orientation, $path->center, $e * unscale $path_length, $description); } else { + my @moves = (); + my @last_moves = (); + my $speed_mms = $self->speeds->{$self->speed} / 60; foreach my $line ($path->lines) { - my $line_length = $line->length; + my $line_length = unscale $line->length; $path_length += $line_length; - $gcode .= $self->G1($line->[B], undef, $e * unscale $line_length, $description); + + # apply frequency limit + # http://hydraraptor.blogspot.it/2010/12/frequency-limit.html + if ($Slic3r::Config->vibration_limit && @{ $path->polyline } >= 4) { # optimization: resonance isn't triggered with less than three moves + my $freq = $speed_mms / $line_length; + if ($freq >= $Slic3r::Config->vibration_limit) { + my $vector = $line->vector; + if (@last_moves >= 1) { + if ($vector->[B][X] * $last_moves[-1][B][X] > 0 && $vector->[B][Y] * $last_moves[-1][B][Y] > 0) { + # if both X and Y have the same direction (sign), reset the buffer as there's no shaking + @last_moves = (); + } + } + push @last_moves, $vector; + if (@last_moves >= 3) { + my ($shortest_length) = reverse sort map $_->length, @last_moves; + my $speed = $Slic3r::Config->vibration_limit * unscale $shortest_length; + ###Slic3r::debugf "Reducing speed to %s mm/s (%s Hz vibration detected)\n", $speed, $freq; + $self->speed($speed * 60); + } + } else { + @last_moves = (); + } + } + + push @moves, [ $line->[B], $e * unscale $line_length ]; + } + + foreach my $move (@moves) { + $gcode .= $self->G1($move->[0], undef, $move->[1], $description); } } if ($Slic3r::Config->cooling) { - my $path_time = unscale($path_length) / $self->speeds->{$self->last_speed} * 60; + my $path_time = $path_length / $self->speeds->{$self->last_speed} * 60; if ($self->layer->id == 0) { $path_time = $Slic3r::Config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ ? $path_time / ($1/100) - : unscale($path_length) / $Slic3r::Config->first_layer_speed * 60; + : $path_length / $Slic3r::Config->first_layer_speed * 60; } $self->elapsed_time($self->elapsed_time + $path_time); } @@ -366,7 +398,7 @@ sub _Gx { # apply the speed reduction for print moves on bottom layer my $speed_f = $speed eq 'retract' ? ($self->extruder->retract_speed_mm_min) - : $self->speeds->{$speed}; + : $self->speeds->{$speed} // $speed; if ($e && $self->layer && $self->layer->id == 0 && $comment !~ /retract/) { $speed_f = $Slic3r::Config->first_layer_speed =~ /^(\d+(?:\.\d+)?)%$/ ? ($speed_f * $1/100) diff --git a/lib/Slic3r/Line.pm b/lib/Slic3r/Line.pm index 58c9479d3..d0d0a3da7 100644 --- a/lib/Slic3r/Line.pm +++ b/lib/Slic3r/Line.pm @@ -32,6 +32,11 @@ sub length { return Slic3r::Geometry::line_length($self); } +sub vector { + my $self = shift; + return (ref $self)->new([0,0], [map $self->[B][$_] - $self->[A][$_], X,Y]); +} + sub atan { my $self = shift; return Slic3r::Geometry::line_atan($self); diff --git a/slic3r.pl b/slic3r.pl index d540fcae4..6e011ec88 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -311,6 +311,7 @@ $j --support-material-extrusion-width Set a different extrusion width for support material --bridge-flow-ratio Multiplier for extrusion when bridging (> 0, default: $config->{bridge_flow_ratio}) + --vibration-limit Experimental frequency limit to avoid resonance (Hz, default: $config->{vibration_limit}) Multiple extruder options: --extruder-offset Offset of each extruder, if firmware doesn't handle the displacement