mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 15:35:55 +08:00
Don't slowdown external perimeters if possible. #2796
This commit is contained in:
parent
d9a663098a
commit
f25ea9f493
18
t/cooling.t
18
t/cooling.t
@ -2,7 +2,7 @@ use Test::More;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
plan tests => 12;
|
plan tests => 13;
|
||||||
|
|
||||||
BEGIN {
|
BEGIN {
|
||||||
use FindBin;
|
use FindBin;
|
||||||
@ -10,7 +10,7 @@ BEGIN {
|
|||||||
use local::lib "$FindBin::Bin/../local-lib";
|
use local::lib "$FindBin::Bin/../local-lib";
|
||||||
}
|
}
|
||||||
|
|
||||||
use List::Util qw(first);
|
use List::Util qw(none all);
|
||||||
use Slic3r;
|
use Slic3r;
|
||||||
use Slic3r::Test;
|
use Slic3r::Test;
|
||||||
|
|
||||||
@ -141,21 +141,33 @@ $config->set('disable_fan_first_layers', 0);
|
|||||||
$config->set('slowdown_below_layer_time', 10);
|
$config->set('slowdown_below_layer_time', 10);
|
||||||
$config->set('min_print_speed', 0);
|
$config->set('min_print_speed', 0);
|
||||||
$config->set('start_gcode', '');
|
$config->set('start_gcode', '');
|
||||||
|
$config->set('first_layer_speed', '100%');
|
||||||
|
$config->set('external_perimeter_speed', 99);
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||||
my @layer_times = (0); # in seconds
|
my @layer_times = (0); # in seconds
|
||||||
|
my %layer_external = (); # z => 1
|
||||||
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
|
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
my ($self, $cmd, $args, $info) = @_;
|
||||||
|
|
||||||
if ($cmd eq 'G1') {
|
if ($cmd eq 'G1') {
|
||||||
if ($info->{dist_Z}) {
|
if ($info->{dist_Z}) {
|
||||||
push @layer_times, 0;
|
push @layer_times, 0;
|
||||||
|
$layer_external{ $args->{Z} } = 0;
|
||||||
}
|
}
|
||||||
$layer_times[-1] += abs($info->{dist_XY} || $info->{dist_E} || $info->{dist_Z} || 0) / ($args->{F} // $self->F) * 60;
|
$layer_times[-1] += abs($info->{dist_XY} || $info->{dist_E} || $info->{dist_Z} || 0) / ($args->{F} // $self->F) * 60;
|
||||||
|
if ($args->{F} && $args->{F} == $config->external_perimeter_speed*60) {
|
||||||
|
$layer_external{ $self->Z }++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
my $all_below = !defined first { $_ > 0 && $_ < $config->slowdown_below_layer_time } @layer_times;
|
@layer_times = grep $_, @layer_times;
|
||||||
|
my $all_below = none { $_ < $config->slowdown_below_layer_time } @layer_times;
|
||||||
ok $all_below, 'slowdown_below_layer_time is honored';
|
ok $all_below, 'slowdown_below_layer_time is honored';
|
||||||
|
|
||||||
|
# check that all layers have at least one unaltered external perimeter speed
|
||||||
|
my $external = all { $_ > 0 } values %layer_external;
|
||||||
|
ok $external, 'slowdown_below_layer_time does not alter external perimeters';
|
||||||
}
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
@ -201,7 +201,8 @@ Wipe::wipe(GCode &gcodegen, bool toolchange)
|
|||||||
|
|
||||||
GCode::GCode()
|
GCode::GCode()
|
||||||
: placeholder_parser(NULL), enable_loop_clipping(true), enable_cooling_markers(false), layer_count(0),
|
: placeholder_parser(NULL), enable_loop_clipping(true), enable_cooling_markers(false), layer_count(0),
|
||||||
layer_index(-1), layer(NULL), first_layer(false), elapsed_time(0.0), volumetric_speed(0),
|
layer_index(-1), layer(NULL), first_layer(false), elapsed_time(0.0),
|
||||||
|
elapsed_time_bridges(0.0), elapsed_time_external(0.0), volumetric_speed(0),
|
||||||
_last_pos_defined(false)
|
_last_pos_defined(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -575,7 +576,9 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
|
|||||||
// extrude arc or line
|
// extrude arc or line
|
||||||
if (path.is_bridge() && this->enable_cooling_markers)
|
if (path.is_bridge() && this->enable_cooling_markers)
|
||||||
gcode += ";_BRIDGE_FAN_START\n";
|
gcode += ";_BRIDGE_FAN_START\n";
|
||||||
gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : "");
|
std::string comment = ";_EXTRUDE_SET_SPEED";
|
||||||
|
if (path.role == erExternalPerimeter) comment += ";_EXTERNAL_PERIMETER";
|
||||||
|
gcode += this->writer.set_speed(F, "", this->enable_cooling_markers ? comment : "");
|
||||||
double path_length = 0;
|
double path_length = 0;
|
||||||
{
|
{
|
||||||
std::string comment = this->config.gcode_comments ? description : "";
|
std::string comment = this->config.gcode_comments ? description : "";
|
||||||
@ -600,8 +603,12 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
|
|||||||
|
|
||||||
this->set_last_pos(path.last_point());
|
this->set_last_pos(path.last_point());
|
||||||
|
|
||||||
if (this->config.cooling)
|
if (this->config.cooling) {
|
||||||
this->elapsed_time += path_length / F * 60;
|
float t = path_length / F * 60;
|
||||||
|
this->elapsed_time += t;
|
||||||
|
if (path.is_bridge()) this->elapsed_time_bridges += t;
|
||||||
|
if (path.role == erExternalPerimeter) this->elapsed_time_external += t;
|
||||||
|
}
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ class GCode {
|
|||||||
// This value is not quite precise. First it only accouts for extrusion moves and travel moves,
|
// This value is not quite precise. First it only accouts for extrusion moves and travel moves,
|
||||||
// it does not account for wipe, retract / unretract moves.
|
// it does not account for wipe, retract / unretract moves.
|
||||||
// second it does not account for the velocity profiles of the printer.
|
// second it does not account for the velocity profiles of the printer.
|
||||||
float elapsed_time; // seconds
|
float elapsed_time, elapsed_time_bridges, elapsed_time_external; // seconds
|
||||||
double volumetric_speed;
|
double volumetric_speed;
|
||||||
|
|
||||||
GCode();
|
GCode();
|
||||||
|
@ -19,8 +19,12 @@ CoolingBuffer::append(const std::string &gcode, std::string obj_id, size_t layer
|
|||||||
this->_gcode += gcode;
|
this->_gcode += gcode;
|
||||||
// This is a very rough estimate of the print time,
|
// This is a very rough estimate of the print time,
|
||||||
// not taking into account the acceleration curves generated by the printer firmware.
|
// not taking into account the acceleration curves generated by the printer firmware.
|
||||||
this->_elapsed_time += this->_gcodegen->elapsed_time;
|
this->_elapsed_time += this->_gcodegen->elapsed_time;
|
||||||
this->_gcodegen->elapsed_time = 0;
|
this->_elapsed_time_bridges += this->_gcodegen->elapsed_time_bridges;
|
||||||
|
this->_elapsed_time_external += this->_gcodegen->elapsed_time_external;
|
||||||
|
this->_gcodegen->elapsed_time = 0;
|
||||||
|
this->_gcodegen->elapsed_time_bridges = 0;
|
||||||
|
this->_gcodegen->elapsed_time_external = 0;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -55,32 +59,40 @@ std::string
|
|||||||
CoolingBuffer::flush()
|
CoolingBuffer::flush()
|
||||||
{
|
{
|
||||||
GCode &gg = *this->_gcodegen;
|
GCode &gg = *this->_gcodegen;
|
||||||
|
std::string gcode = this->_gcode;
|
||||||
|
|
||||||
std::string gcode = this->_gcode;
|
int fan_speed = gg.config.fan_always_on ? gg.config.min_fan_speed.value : 0;
|
||||||
float elapsed = this->_elapsed_time;
|
float speed_factor = 1.0;
|
||||||
this->_gcode = "";
|
bool slowdown_external = true;
|
||||||
this->_elapsed_time = 0;
|
|
||||||
this->_last_z.clear(); // reset the whole table otherwise we would compute overlapping times
|
|
||||||
|
|
||||||
int fan_speed = gg.config.fan_always_on ? gg.config.min_fan_speed.value : 0;
|
|
||||||
|
|
||||||
float speed_factor = 1.0;
|
|
||||||
|
|
||||||
if (gg.config.cooling) {
|
if (gg.config.cooling) {
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf("Layer %zu estimated printing time: %f seconds\n", this->_layer_id, elapsed);
|
printf("Layer %zu estimated printing time: %f seconds\n", this->_layer_id, this->_elapsed_time);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (elapsed < (float)gg.config.slowdown_below_layer_time) {
|
if (this->_elapsed_time < (float)gg.config.slowdown_below_layer_time) {
|
||||||
// Layer time very short. Enable the fan to a full throttle and slow down the print
|
// Layer time very short. Enable the fan to a full throttle and slow down the print
|
||||||
// (stretch the layer print time to slowdown_below_layer_time).
|
// (stretch the layer print time to slowdown_below_layer_time).
|
||||||
fan_speed = gg.config.max_fan_speed;
|
fan_speed = gg.config.max_fan_speed;
|
||||||
speed_factor = elapsed / (float)gg.config.slowdown_below_layer_time;
|
|
||||||
} else if (elapsed < (float)gg.config.fan_below_layer_time) {
|
// We are not altering speed of bridges.
|
||||||
|
float time_to_stretch = this->_elapsed_time - this->_elapsed_time_bridges;
|
||||||
|
float target_time = (float)gg.config.slowdown_below_layer_time - this->_elapsed_time_bridges;
|
||||||
|
|
||||||
|
// If we spend most of our time on external perimeters include them in the slowdown,
|
||||||
|
// otherwise only alter other extrusions.
|
||||||
|
if (this->_elapsed_time_external < time_to_stretch/2.) {
|
||||||
|
time_to_stretch -= this->_elapsed_time_external;
|
||||||
|
target_time -= this->_elapsed_time_external;
|
||||||
|
slowdown_external = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
speed_factor = time_to_stretch / target_time;
|
||||||
|
} else if (this->_elapsed_time < (float)gg.config.fan_below_layer_time) {
|
||||||
// Layer time quite short. Enable the fan proportionally according to the current layer time.
|
// Layer time quite short. Enable the fan proportionally according to the current layer time.
|
||||||
fan_speed = gg.config.max_fan_speed
|
fan_speed = gg.config.max_fan_speed
|
||||||
- (gg.config.max_fan_speed - gg.config.min_fan_speed)
|
- (gg.config.max_fan_speed - gg.config.min_fan_speed)
|
||||||
* (elapsed - (float)gg.config.slowdown_below_layer_time)
|
* (this->_elapsed_time - (float)gg.config.slowdown_below_layer_time)
|
||||||
/ (gg.config.fan_below_layer_time - gg.config.slowdown_below_layer_time);
|
/ (gg.config.fan_below_layer_time - gg.config.slowdown_below_layer_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,11 +112,12 @@ CoolingBuffer::flush()
|
|||||||
if (boost::starts_with(line, "G1")
|
if (boost::starts_with(line, "G1")
|
||||||
&& boost::contains(line, ";_EXTRUDE_SET_SPEED")
|
&& boost::contains(line, ";_EXTRUDE_SET_SPEED")
|
||||||
&& !boost::contains(line, ";_WIPE")
|
&& !boost::contains(line, ";_WIPE")
|
||||||
&& !bridge_fan_start) {
|
&& !bridge_fan_start
|
||||||
|
&& (slowdown_external || !boost::contains(line, ";_EXTERNAL_PERIMETER"))) {
|
||||||
apply_speed_factor(line, speed_factor, this->_min_print_speed);
|
apply_speed_factor(line, speed_factor, this->_min_print_speed);
|
||||||
boost::replace_first(line, ";_EXTRUDE_SET_SPEED", "");
|
boost::replace_first(line, ";_EXTRUDE_SET_SPEED", "");
|
||||||
}
|
}
|
||||||
bridge_fan_start = boost::contains(line, ";_BRIDGE_FAN_START");
|
bridge_fan_start = boost::starts_with(line, ";_BRIDGE_FAN_START");
|
||||||
new_gcode += line + '\n';
|
new_gcode += line + '\n';
|
||||||
}
|
}
|
||||||
gcode = new_gcode;
|
gcode = new_gcode;
|
||||||
@ -125,6 +138,14 @@ CoolingBuffer::flush()
|
|||||||
}
|
}
|
||||||
boost::replace_all(gcode, ";_WIPE", "");
|
boost::replace_all(gcode, ";_WIPE", "");
|
||||||
boost::replace_all(gcode, ";_EXTRUDE_SET_SPEED", "");
|
boost::replace_all(gcode, ";_EXTRUDE_SET_SPEED", "");
|
||||||
|
boost::replace_all(gcode, ";_EXTERNAL_PERIMETER", "");
|
||||||
|
|
||||||
|
// Reset the buffer.
|
||||||
|
this->_elapsed_time = 0;
|
||||||
|
this->_elapsed_time_bridges = 0;
|
||||||
|
this->_elapsed_time_external = 0;
|
||||||
|
this->_gcode = "";
|
||||||
|
this->_last_z.clear(); // reset the whole table otherwise we would compute overlapping times
|
||||||
|
|
||||||
return gcode;
|
return gcode;
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ and the print is modified to stretch over a minimum layer time.
|
|||||||
class CoolingBuffer {
|
class CoolingBuffer {
|
||||||
public:
|
public:
|
||||||
CoolingBuffer(GCode &gcodegen)
|
CoolingBuffer(GCode &gcodegen)
|
||||||
: _gcodegen(&gcodegen), _elapsed_time(0.), _layer_id(0)
|
: _gcodegen(&gcodegen), _elapsed_time(0.), _elapsed_time_bridges(0.),
|
||||||
|
_elapsed_time_external(0.), _layer_id(0)
|
||||||
{
|
{
|
||||||
this->_min_print_speed = this->_gcodegen->config.min_print_speed * 60;
|
this->_min_print_speed = this->_gcodegen->config.min_print_speed * 60;
|
||||||
};
|
};
|
||||||
@ -29,6 +30,8 @@ class CoolingBuffer {
|
|||||||
GCode* _gcodegen;
|
GCode* _gcodegen;
|
||||||
std::string _gcode;
|
std::string _gcode;
|
||||||
float _elapsed_time;
|
float _elapsed_time;
|
||||||
|
float _elapsed_time_bridges;
|
||||||
|
float _elapsed_time_external;
|
||||||
size_t _layer_id;
|
size_t _layer_id;
|
||||||
std::map<std::string,float> _last_z;
|
std::map<std::string,float> _last_z;
|
||||||
float _min_print_speed;
|
float _min_print_speed;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user