Cooling and fan control. #110

This commit is contained in:
Alessandro Ranellucci 2012-02-25 21:01:00 +01:00
parent f4fde54bf3
commit 1d0a852679
8 changed files with 205 additions and 68 deletions

View File

@ -38,6 +38,7 @@ Slic3r current key features are:
* ability to scale, rotate and duplicate input object;
* customizable initial and final GCODE;
* support material;
* cooling and fan control;
* use different speed for bottom layer and perimeters.
Experimental features include:
@ -50,7 +51,6 @@ Roadmap includes the following goals:
* output some statistics;
* support material for internal perimeters;
* new and better GUI;
* cool;
* more fill patterns.
## Is it usable already? Any known limitation?
@ -91,6 +91,8 @@ The author is Alessandro Ranellucci (me).
Output file name format; all config options enclosed in brackets
will be replaced by their values, as well as [input_filename_base]
and [input_filename] (default: [input_filename_base].gcode)
--post-process Generated G-code will be processed with the supplied script;
call this more than once to process through multiple scripts.
Printer options:
--nozzle-diameter Diameter of nozzle in mm (default: 0.5)
@ -161,6 +163,17 @@ The author is Alessandro Ranellucci (me).
Only retract before travel moves of this length in mm (default: 2)
--retract-lift Lift Z by the given distance in mm when retracting (default: 0)
Cooling options:
--min-fan-speed Minimum fan speed (default: 35%)
--max-fan-speed Maximum fan speed (default: 100%)
--bridge-fan-speed Fan speed to use when bridging (default: 100%)
--fan-below-layer-time Enable fan if layer print time is below this approximate number
of seconds (default: 60)
--slowdown-below-layer-time Slow down if layer print time is below this approximate number
of seconds (default: 15)
--min-print-speed Minimum print speed speed (mm/s, default: 10)
--disable-fan-first-layers Disable fan for the first N layers (default: 1)
Skirt options:
--skirts Number of skirts to draw (0+, default: 1)
--skirt-distance Distance in mm between innermost skirt and object

View File

@ -114,6 +114,15 @@ our $retract_speed = 30; # mm/s
our $retract_before_travel = 2; # mm
our $retract_lift = 0; # mm
# cooling options
our $min_fan_speed = 35;
our $max_fan_speed = 100;
our $bridge_fan_speed = 100;
our $fan_below_layer_time = 60;
our $slowdown_below_layer_time = 15;
our $min_print_speed = 10;
our $disable_fan_first_layers = 1;
# skirt options
our $skirts = 1;
our $skirt_distance = 6; # mm

View File

@ -292,6 +292,43 @@ our $Options = {
type => 'f',
},
# cooling options
'min_fan_speed' => {
label => 'Min fan speed (%)',
cli => 'min-fan-speed=i',
type => 'i',
},
'max_fan_speed' => {
label => 'Max fan speed (%)',
cli => 'max-fan-speed=i',
type => 'i',
},
'bridge_fan_speed' => {
label => 'Bridge fan speed (%)',
cli => 'bridge-fan-speed=i',
type => 'i',
},
'fan_below_layer_time' => {
label => 'Enable fan if layer print time is below (approximate seconds)',
cli => 'fan-below-layer-time=i',
type => 'i',
},
'slowdown_below_layer_time' => {
label => 'Slow down if layer print time is below (approximate seconds)',
cli => 'slowdown-below-layer-time=i',
type => 'i',
},
'min_print_speed' => {
label => 'Min print speed (mm/s)',
cli => 'min-print-speed=i',
type => 'i',
},
'disable_fan_first_layers' => {
label => 'Disable fan for the first N layers',
cli => 'disable-fan-first-layers=i',
type => 'i',
},
# skirt options
'skirts' => {
label => 'Loops',

View File

@ -1,50 +1,36 @@
package Slic3r::Extruder;
use Moo;
use Slic3r::Geometry qw(scale);
use Slic3r::Geometry qw(scale unscale);
has 'layer' => (is => 'rw');
has 'shift_x' => (is => 'rw', default => sub {0} );
has 'shift_y' => (is => 'rw', default => sub {0} );
has 'z' => (is => 'rw', default => sub {0} );
has 'print_feed_rate' => (is => 'rw');
has 'speed' => (is => 'rw');
has 'extrusion_distance' => (is => 'rw', default => sub {0} );
has 'elapsed_time' => (is => 'rw', default => sub {0} ); # seconds
has 'total_extrusion_length' => (is => 'rw', default => sub {0} );
has 'retracted' => (is => 'rw', default => sub {1} ); # this spits out some plastic at start
has 'lifted' => (is => 'rw', default => sub {0} );
has 'last_pos' => (is => 'rw', default => sub { Slic3r::Point->new(0,0) } );
has 'last_f' => (is => 'rw', default => sub {0});
has 'last_speed' => (is => 'rw', default => sub {""});
has 'last_fan_speed' => (is => 'rw', default => sub {0});
has 'dec' => (is => 'ro', default => sub { 3 } );
# calculate speeds
has 'travel_speed' => (
# calculate speeds (mm/min)
has 'speeds' => (
is => 'ro',
default => sub { $Slic3r::travel_speed * 60 }, # mm/min
);
has 'perimeter_speed' => (
is => 'ro',
default => sub { $Slic3r::perimeter_speed * 60 }, # mm/min
);
has 'small_perimeter_speed' => (
is => 'ro',
default => sub { $Slic3r::small_perimeter_speed * 60 }, # mm/min
);
has 'infill_speed' => (
is => 'ro',
default => sub { $Slic3r::infill_speed * 60 }, # mm/min
);
has 'solid_infill_speed' => (
is => 'ro',
default => sub { $Slic3r::solid_infill_speed * 60 }, # mm/min
);
has 'bridge_speed' => (
is => 'ro',
default => sub { $Slic3r::bridge_speed * 60 }, # mm/min
);
has 'retract_speed' => (
is => 'ro',
default => sub { $Slic3r::retract_speed * 60 }, # mm/min
default => sub {{
travel => 60 * $Slic3r::travel_speed,
perimeter => 60 * $Slic3r::perimeter_speed,
small_perimeter => 60 * $Slic3r::small_perimeter_speed,
infill => 60 * $Slic3r::infill_speed,
solid_infill => 60 * $Slic3r::solid_infill_speed,
bridge => 60 * $Slic3r::bridge_speed,
retract => 60 * $Slic3r::retract_speed,
}},
);
use Slic3r::Geometry qw(points_coincide PI X Y);
@ -151,23 +137,32 @@ sub extrude_path {
* (4 / (($Slic3r::filament_diameter ** 2) * PI));
# extrude arc or line
$self->print_feed_rate(
$path->role =~ /^(perimeter|skirt|support-material)$/o ? $self->perimeter_speed
: $path->role eq 'small-perimeter' ? $self->small_perimeter_speed
: $path->role eq 'fill' ? $self->infill_speed
: $path->role eq 'solid-fill' ? $self->solid_infill_speed
: $path->role eq 'bridge' ? $self->bridge_speed
$self->speed(
$path->role =~ /^(perimeter|skirt|support-material)$/o ? 'perimeter'
: $path->role eq 'small-perimeter' ? 'small_perimeter'
: $path->role eq 'fill' ? 'infill'
: $path->role eq 'solid-fill' ? 'solid_infill'
: $path->role eq 'bridge' ? 'bridge'
: die "Unknown role: " . $path->role
);
my $path_length = 0;
if ($path->isa('Slic3r::ExtrusionPath::Arc')) {
$path_length = $path->length;
$gcode .= $self->G2_G3($path->points->[-1], $path->orientation,
$path->center, $e * $path->length, $description);
$path->center, $e * $path_length, $description);
} else {
foreach my $line ($path->lines) {
$gcode .= $self->G1($line->b, undef, $e * $line->length, $description);
my $line_length = $line->length;
$path_length += $line_length;
$gcode .= $self->G1($line->b, undef, $e * $line_length, $description);
}
}
# TODO: optimize: avoid calculation if cooling is disabled
if (1) {
$self->elapsed_time($self->elapsed_time + (unscale($path_length) / $self->speeds->{$self->last_speed} * 60));
}
return $gcode;
}
@ -179,7 +174,7 @@ sub retract {
&& !$self->retracted;
# prepare moves
$self->print_feed_rate($self->retract_speed);
$self->speed('retract');
my $retract = [undef, undef, -$Slic3r::retract_length, "retract"];
my $lift = ($Slic3r::retract_lift == 0 || defined $params{move_z})
? undef
@ -229,7 +224,7 @@ sub unretract {
$self->lifted(0);
}
$self->print_feed_rate($self->retract_speed);
$self->speed('retract');
$gcode .= $self->G0(undef, undef, ($Slic3r::retract_length + $Slic3r::retract_restart_extra),
"compensate retraction");
@ -239,7 +234,7 @@ sub unretract {
sub set_acceleration {
my $self = shift;
my ($acceleration) = @_;
return unless $Slic3r::acceleration;
return "" unless $Slic3r::acceleration;
return sprintf "M201 E%s%s\n",
$acceleration, ($Slic3r::gcode_comments ? ' ; adjust acceleration' : '');
@ -248,21 +243,19 @@ sub set_acceleration {
sub G0 {
my $self = shift;
return $self->G1(@_) if !$Slic3r::g0;
return "G0" . $self->G0_G1(@_);
return $self->_G0_G1("G0", @_);
}
sub G1 {
my $self = shift;
return "G1" . $self->G0_G1(@_);
return $self->_G0_G1("G1", @_);
}
sub G0_G1 {
sub _G0_G1 {
my $self = shift;
my ($point, $z, $e, $comment) = @_;
my ($gcode, $point, $z, $e, $comment) = @_;
my $dec = $self->dec;
my $gcode = "";
if ($point) {
$gcode .= sprintf " X%.${dec}f Y%.${dec}f",
($point->x * $Slic3r::resolution) + $self->shift_x,
@ -308,13 +301,19 @@ sub _Gx {
: 1;
# determine speed
my $speed = ($e ? $self->print_feed_rate : $self->travel_speed) * $speed_multiplier;
my $speed = ($e ? $self->speed : 'travel');
# output speed if it's different from last one used
# (goal: reduce gcode size)
if ($speed != $self->last_f) {
$gcode .= sprintf " F%.${dec}f", $speed;
$self->last_f($speed);
my $append_bridge_off = 0;
if ($speed ne $self->last_speed) {
if ($speed eq 'bridge') {
$gcode = "_BRIDGE_FAN_START\n$gcode";
} elsif ($self->last_speed eq 'bridge') {
$append_bridge_off = 1;
}
$gcode .= sprintf " F%.${dec}f", $self->speeds->{$speed} * $speed_multiplier;
$self->last_speed($speed);
}
# output extrusion distance
@ -326,6 +325,9 @@ sub _Gx {
}
$gcode .= sprintf " ; %s", $comment if $comment && $Slic3r::gcode_comments;
if ($append_bridge_off) {
$gcode .= "\n_BRIDGE_FAN_END";
}
return "$gcode\n";
}
@ -336,4 +338,19 @@ sub set_tool {
return sprintf "T%d%s\n", $tool, ($Slic3r::gcode_comments ? ' ; change tool' : '');
}
sub set_fan {
my $self = shift;
my ($speed, $dont_save) = @_;
if ($self->last_fan_speed != $speed || $dont_save) {
$self->last_fan_speed($speed) if !$dont_save;
if ($speed == 0) {
return sprintf "M107%s\n", ($Slic3r::gcode_comments ? ' ; disable fan' : '');
} else {
return sprintf "M106 S%d%s\n", (255 * $speed / 100), ($Slic3r::gcode_comments ? ' ; enable fan' : '');
}
}
return "";
}
1;

View File

@ -26,8 +26,9 @@ sub new {
foreach my $opt_key (@{$p{options}}) {
my $opt = $Slic3r::Config::Options->{$opt_key};
my $label = Wx::StaticText->new($parent, -1, "$opt->{label}:", Wx::wxDefaultPosition, [180,-1]);
$label->Wrap(180); # needed to avoid Linux/GTK bug
my $label = Wx::StaticText->new($parent, -1, "$opt->{label}:", Wx::wxDefaultPosition,
[$p{label_width} || 180, -1]);
$label->Wrap($p{label_width} || 180); # needed to avoid Linux/GTK bug
#set the bold font point size to the same size as all the other labels (for consistency)
$bold_font->SetPointSize($label->GetFont()->GetPointSize());

View File

@ -47,6 +47,11 @@ sub new {
title => 'Retraction',
options => [qw(retract_length retract_lift retract_speed retract_restart_extra retract_before_travel)],
},
cooling => {
title => 'Cooling',
options => [qw(min_fan_speed max_fan_speed bridge_fan_speed fan_below_layer_time slowdown_below_layer_time min_print_speed disable_fan_first_layers)],
label_width => 300,
},
skirt => {
title => 'Skirt',
options => [qw(skirts skirt_distance skirt_height)],
@ -101,6 +106,7 @@ sub new {
my @tabs = (
$make_tab->([qw(transform accuracy skirt)], [qw(print retract)]),
$make_tab->([qw(cooling)]),
$make_tab->([qw(printer filament)], [qw(print_speed speed)]),
$make_tab->([qw(gcode)]),
$make_tab->([qw(notes)]),
@ -108,10 +114,11 @@ sub new {
);
$tabpanel->AddPage($tabs[0], "Print Settings");
$tabpanel->AddPage($tabs[1], "Printer and Filament");
$tabpanel->AddPage($tabs[2], "Start/End GCODE");
$tabpanel->AddPage($tabs[3], "Notes");
$tabpanel->AddPage($tabs[4], "Advanced");
$tabpanel->AddPage($tabs[1], "Cooling");
$tabpanel->AddPage($tabs[2], "Printer and Filament");
$tabpanel->AddPage($tabs[3], "Start/End GCODE");
$tabpanel->AddPage($tabs[4], "Notes");
$tabpanel->AddPage($tabs[5], "Advanced");
my $buttons_sizer;
{

View File

@ -612,6 +612,8 @@ sub export_gcode {
# set up our extruder object
my $extruder = Slic3r::Extruder->new;
my $min_print_speed = 60 * $Slic3r::min_print_speed;
my $dec = $extruder->dec;
if ($Slic3r::support_material && $Slic3r::support_material_tool > 0) {
print $fh $extruder->set_tool(0);
}
@ -621,36 +623,75 @@ sub export_gcode {
# go to layer
print $fh $extruder->change_layer($layer);
my $layer_gcode = "";
$extruder->elapsed_time(0);
# extrude skirts
$extruder->shift_x($shift[X]);
$extruder->shift_y($shift[Y]);
print $fh $extruder->set_acceleration($Slic3r::perimeter_acceleration);
print $fh $extruder->extrude_loop($_, 'skirt') for @{ $layer->skirts };
$layer_gcode .= $extruder->set_acceleration($Slic3r::perimeter_acceleration);
$layer_gcode .= $extruder->extrude_loop($_, 'skirt') for @{ $layer->skirts };
foreach my $copy (@{$self->copies}) {
$extruder->shift_x($shift[X] + unscale $copy->[X]);
$extruder->shift_y($shift[Y] + unscale $copy->[Y]);
# extrude perimeters
print $fh $extruder->extrude($_, 'perimeter') for @{ $layer->perimeters };
$layer_gcode .= $extruder->extrude($_, 'perimeter') for @{ $layer->perimeters };
# extrude fills
print $fh $extruder->set_acceleration($Slic3r::infill_acceleration);
$layer_gcode .= $extruder->set_acceleration($Slic3r::infill_acceleration);
for my $fill (@{ $layer->fills }) {
print $fh $extruder->extrude_path($_, 'fill')
$layer_gcode .= $extruder->extrude_path($_, 'fill')
for $fill->shortest_path($extruder->last_pos);
}
# extrude support material
if ($layer->support_fills) {
print $fh $extruder->set_tool($Slic3r::support_material_tool)
$layer_gcode .= $extruder->set_tool($Slic3r::support_material_tool)
if $Slic3r::support_material_tool > 0;
print $fh $extruder->extrude_path($_, 'support material')
$layer_gcode .= $extruder->extrude_path($_, 'support material')
for $layer->support_fills->shortest_path($extruder->last_pos);
print $fh $extruder->set_tool(0)
$layer_gcode .= $extruder->set_tool(0)
if $Slic3r::support_material_tool > 0;
}
}
last if !$layer_gcode;
my $layer_time = $extruder->elapsed_time;
my $fan_speed = 0;
my $speed_factor = 1;
Slic3r::debugf "Layer %d estimated printing time: %d seconds\n", $layer->id, $layer_time;
if ($layer_time < $Slic3r::fan_below_layer_time) {
if ($layer_time < $Slic3r::slowdown_below_layer_time) {
$fan_speed = $Slic3r::max_fan_speed;
$speed_factor = $layer_time / $Slic3r::slowdown_below_layer_time;
} else {
$fan_speed = $Slic3r::max_fan_speed - ($Slic3r::max_fan_speed - $Slic3r::min_fan_speed)
* ($layer_time - $Slic3r::slowdown_below_layer_time)
/ ($Slic3r::fan_below_layer_time - $Slic3r::slowdown_below_layer_time); #/
}
}
Slic3r::debugf " fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100;
if ($speed_factor < 1) {
$layer_gcode =~ s/^(?=.*? [XY])(G1 .*?F)(\d+(?:\.\d+)?)/
my $new_speed = $2 * $speed_factor;
$1 . sprintf("%.${dec}f", $new_speed < $min_print_speed ? $min_print_speed : $new_speed)
/gexm;
}
$fan_speed = 0 if $layer->id < $Slic3r::disable_fan_first_layers;
$layer_gcode = $extruder->set_fan($fan_speed) . $layer_gcode;
# bridge fan speed
if ($Slic3r::bridge_fan_speed == 0 || $layer->id < $Slic3r::disable_fan_first_layers) {
$layer_gcode =~ s/^_BRIDGE_FAN_(?:START|END)\n//gm;
} else {
$layer_gcode =~ s/^_BRIDGE_FAN_START\n/ $extruder->set_fan($Slic3r::bridge_fan_speed, 1) /gmex;
$layer_gcode =~ s/^_BRIDGE_FAN_END\n/ $extruder->set_fan($fan_speed, 1) /gmex;
}
print $fh $layer_gcode;
}
# save statistic data
@ -658,6 +699,7 @@ sub export_gcode {
# write end commands to file
print $fh $extruder->retract;
print $fh $extruder->set_fan(0);
print $fh "M501 ; reset acceleration\n" if $Slic3r::acceleration;
print $fh "$Slic3r::end_gcode\n";

View File

@ -181,6 +181,17 @@ Usage: slic3r.pl [ OPTIONS ] file.stl
Only retract before travel moves of this length in mm (default: $Slic3r::retract_before_travel)
--retract-lift Lift Z by the given distance in mm when retracting (default: $Slic3r::retract_lift)
Cooling options:
--min-fan-speed Minimum fan speed (default: $Slic3r::min_fan_speed%)
--max-fan-speed Maximum fan speed (default: $Slic3r::max_fan_speed%)
--bridge-fan-speed Fan speed to use when bridging (default: $Slic3r::bridge_fan_speed%)
--fan-below-layer-time Enable fan if layer print time is below this approximate number
of seconds (default: $Slic3r::fan_below_layer_time)
--slowdown-below-layer-time Slow down if layer print time is below this approximate number
of seconds (default: $Slic3r::slowdown_below_layer_time)
--min-print-speed Minimum print speed speed (mm/s, default: $Slic3r::min_print_speed)
--disable-fan-first-layers Disable fan for the first N layers (default: $Slic3r::disable_fan_first_layers)
Skirt options:
--skirts Number of skirts to draw (0+, default: $Slic3r::skirts)
--skirt-distance Distance in mm between innermost skirt and object