Rewrite frequency limiting code
This commit is contained in:
parent
600e951fd8
commit
72007c4f6a
2 changed files with 104 additions and 34 deletions
|
@ -184,42 +184,10 @@ sub extrude_path {
|
|||
$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 = unscale $line->length;
|
||||
$path_length += $line_length;
|
||||
|
||||
# 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);
|
||||
$gcode .= $self->G1($line->[B], undef, $e * $line_length, $description);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,4 +468,104 @@ sub set_bed_temperature {
|
|||
return $gcode;
|
||||
}
|
||||
|
||||
# http://hydraraptor.blogspot.it/2010/12/frequency-limit.html
|
||||
sub limit_frequency {
|
||||
my $self = shift;
|
||||
my ($gcode) = @_;
|
||||
|
||||
return $gcode if $Slic3r::Config->vibration_limit == 0;
|
||||
|
||||
my $current_gcode = $gcode;
|
||||
$gcode = '';
|
||||
my ($X, $Y, $F);
|
||||
my @last_moves = ();
|
||||
my $longest_move;
|
||||
my $buffer = '';
|
||||
my $vibration_limit_min = $Slic3r::Config->vibration_limit * 60;
|
||||
|
||||
my $flush_buffer = sub {
|
||||
my ($line) = @_;
|
||||
|
||||
if (@last_moves >= 3) {
|
||||
$buffer =~ s/ F[0-9.]+//g;
|
||||
my $new_speed = $vibration_limit_min * $longest_move;
|
||||
$gcode .= "G1 F$new_speed ; limit vibrations\n";
|
||||
$gcode .= $buffer;
|
||||
$gcode .= "G1 F$F; restore previous speed\n";
|
||||
} else {
|
||||
$gcode .= $buffer;
|
||||
}
|
||||
$gcode .= "$line\n";
|
||||
@last_moves = ();
|
||||
$buffer = '';
|
||||
};
|
||||
|
||||
my $append_to_buffer = sub {
|
||||
my ($line, $move, $freq) = @_;
|
||||
|
||||
###printf "move x = %s, y = %s\n", map $_ // '/', @$move[X,Y];
|
||||
###printf " freq x = %s, y = %s\n", map $_ // '/', @$freq[X,Y];
|
||||
|
||||
$buffer .= "$line\n";
|
||||
push @last_moves, [ map $freq->[$_] ? $_ : undef, @$move ];
|
||||
for (grep defined $freq->[$_], X,Y) {
|
||||
$longest_move = abs($move->[$_]) if $move->[$_] && (!defined $longest_move || abs($move->[$_]) > $longest_move);
|
||||
}
|
||||
};
|
||||
|
||||
foreach my $line (split /\n/, $current_gcode) {
|
||||
if ($line =~ /^G[01] /) {
|
||||
my ($x, $y, $f);
|
||||
$x = $1 if $line =~ /X([0-9.]+)/;
|
||||
$y = $1 if $line =~ /Y([0-9.]+)/;
|
||||
$f = $1 if $line =~ /F([0-9.]+)/;
|
||||
|
||||
# calculate the move vector
|
||||
my @move = (
|
||||
(defined $x && $X) ? ($x - $X) : 0,
|
||||
(defined $y && $Y) ? ($x - $Y) : 0,
|
||||
);
|
||||
|
||||
# calculate the frequency (how many times the move can happen in one minute) for each axis
|
||||
# and only keep it for the axes exceeding the configured limit.
|
||||
# (undef = infinite)
|
||||
my @freq = ();
|
||||
for (X,Y) {
|
||||
next if !$move[$_];
|
||||
my $freq = ($f // $F) / abs($move[$_]);
|
||||
$freq[$_] = $freq if $freq >= $vibration_limit_min;
|
||||
}
|
||||
|
||||
# does our move exceed the limit?
|
||||
if (grep defined $_, @freq) {
|
||||
# if so, do we have a buffer already?
|
||||
if (@last_moves) {
|
||||
# if we have a buffer, compare the direction (for each axis) with the previous one.
|
||||
if (($move[X] // 0) * ($last_moves[-1][X] // 0) < 0 || ($move[Y] // 0) * ($last_moves[-1][Y] // 0) < 0 && ($f // $F) == $F) {
|
||||
# this move has opposite direction on at least one axis, and has also same speed:
|
||||
# we can add it to the buffer
|
||||
$append_to_buffer->($line, \@move, \@freq);
|
||||
} else {
|
||||
$flush_buffer->($line);
|
||||
}
|
||||
} else {
|
||||
# if we have no buffer, store this move inside it
|
||||
$append_to_buffer->($line, \@move, \@freq);
|
||||
}
|
||||
} else {
|
||||
# if the move does not exceed any limit, flush the buffer and output this line
|
||||
$flush_buffer->($line);
|
||||
}
|
||||
|
||||
$X = $x if defined $x;
|
||||
$Y = $y if defined $y;
|
||||
$F = $f if defined $f;
|
||||
} else {
|
||||
$gcode .= "$line\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $gcode;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -3,7 +3,7 @@ use Moo;
|
|||
|
||||
use File::Basename qw(basename fileparse);
|
||||
use File::Spec;
|
||||
use List::Util qw(max first);
|
||||
use List::Util qw(min max first);
|
||||
use Math::ConvexHull::MonotoneChain qw(convex_hull);
|
||||
use Slic3r::ExtrusionPath ':roles';
|
||||
use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN PI scale unscale move_points nearest_point);
|
||||
|
@ -851,6 +851,8 @@ sub write_gcode {
|
|||
$gcode =~ s/^;_BRIDGE_FAN_END\n/ $gcodegen->set_fan($fan_speed, 1) /gmex;
|
||||
}
|
||||
|
||||
$gcode = $gcodegen->limit_frequency($gcode);
|
||||
|
||||
return $gcode;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue