New option to print each object completely before moving onto next one (watch out for extruder collisions, Slic3r isn't doing any check since it doesn't know its shape)
This commit is contained in:
parent
0a5cf4ba90
commit
ce6b4aeaee
@ -35,11 +35,12 @@ Slic3r current key features are:
|
||||
* save configuration profiles;
|
||||
* center print around bed center point;
|
||||
* multiple solid layers near horizontal external surfaces;
|
||||
* ability to scale, rotate and duplicate input object;
|
||||
* ability to scale, rotate and duplicate input objects;
|
||||
* customizable initial and final G-code;
|
||||
* support material;
|
||||
* cooling and fan control;
|
||||
* use different speed for bottom layer and perimeters.
|
||||
* use different speed for bottom layer, perimeters, small perimeters, bridges, solid infill;
|
||||
* ability to print complete objects before moving onto next one.
|
||||
|
||||
Experimental features include:
|
||||
|
||||
@ -51,28 +52,24 @@ Roadmap includes the following goals:
|
||||
* output some statistics;
|
||||
* support material for internal perimeters;
|
||||
* more GUI work;
|
||||
* more fill patterns.
|
||||
|
||||
## Is it usable already? Any known limitation?
|
||||
|
||||
Sure, it's very usable. Remember that:
|
||||
|
||||
* it only works well with manifold and clean models (check them with Meshlab or Netfabb or http://cloud.netfabb.com/).
|
||||
* more fill patterns;
|
||||
* a more complete roadmap is needed too ;-)
|
||||
|
||||
## How to install?
|
||||
|
||||
It's very easy. See the [project homepage](http://slic3r.org/)
|
||||
for instructions and links to the precompiled packages.
|
||||
for instructions and links to the precompiled packages that you can just
|
||||
download and run, with no dependencies required.
|
||||
|
||||
## Can I help?
|
||||
|
||||
Sure! Send patches and/or drop me a line at aar@cpan.org. You can also
|
||||
find me in #reprap on FreeNode with the nickname _Sound_.
|
||||
find me in #reprap and in #slic3r on FreeNode with the nickname _Sound_.
|
||||
|
||||
## What's Slic3r license?
|
||||
|
||||
Slic3r is licensed under the _GNU Affero General Public License, version 3_.
|
||||
The author is Alessandro Ranellucci (me).
|
||||
The author is Alessandro Ranellucci.
|
||||
|
||||
## How can I invoke slic3r.pl using the command line?
|
||||
|
||||
@ -162,6 +159,8 @@ The author is Alessandro Ranellucci (me).
|
||||
--layer-gcode Load layer-change G-code from the supplied file (default: nothing).
|
||||
--support-material Generate support material for overhangs
|
||||
--randomize-start Randomize starting point across layers (default: yes)
|
||||
--complete-objects When printing multiple objects and/or copies, complete each one before
|
||||
starting the next one; watch out for extruder collisions (default: no)
|
||||
|
||||
Retraction options:
|
||||
--retract-length Length of retraction in mm when pausing extrusion
|
||||
|
@ -109,6 +109,7 @@ our $fill_angle = 45;
|
||||
our $randomize_start = 1;
|
||||
our $support_material = 0;
|
||||
our $support_material_tool = 0;
|
||||
our $complete_objects = 0;
|
||||
our $start_gcode = "G28 ; home all axes";
|
||||
our $end_gcode = <<"END";
|
||||
M104 S0 ; turn off temperature
|
||||
|
@ -262,6 +262,11 @@ our $Options = {
|
||||
values => [0,1],
|
||||
labels => [qw(Primary Secondary)],
|
||||
},
|
||||
'complete_objects' => {
|
||||
label => 'Complete individual objects (watch out for extruder collisions if you enable this)',
|
||||
cli => 'complete-objects',
|
||||
type => 'bool',
|
||||
},
|
||||
'start_gcode' => {
|
||||
label => 'Start G-code',
|
||||
cli => 'start-gcode=s',
|
||||
|
@ -377,4 +377,28 @@ sub set_fan {
|
||||
return "";
|
||||
}
|
||||
|
||||
sub set_temperature {
|
||||
my $self = shift;
|
||||
my ($temperature, $wait) = @_;
|
||||
|
||||
return "" if $wait && $Slic3r::gcode_flavor eq 'makerbot';
|
||||
|
||||
my ($code, $comment) = $wait
|
||||
? ('M109', 'wait for temperature to be reached')
|
||||
: ('M104', 'set temperature');
|
||||
return sprintf "$code %s%d ; $comment\n",
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature;
|
||||
}
|
||||
|
||||
sub set_bed_temperature {
|
||||
my $self = shift;
|
||||
my ($temperature, $wait) = @_;
|
||||
|
||||
my ($code, $comment) = $wait
|
||||
? (($Slic3r::gcode_flavor eq 'makerbot' ? '109' : '190'), 'wait for bed temperature to be reached')
|
||||
: ('M40', 'set bed temperature');
|
||||
return sprintf "$code %s%d ; $comment\n",
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -61,7 +61,8 @@ sub new {
|
||||
},
|
||||
gcode => {
|
||||
title => 'G-code',
|
||||
options => [qw(start_gcode end_gcode layer_gcode gcode_comments post_process)],
|
||||
options => [qw(start_gcode end_gcode layer_gcode complete_objects gcode_comments post_process)],
|
||||
label_width => 260,
|
||||
},
|
||||
extrusion => {
|
||||
title => 'Extrusion',
|
||||
|
@ -398,19 +398,23 @@ sub write_gcode {
|
||||
printf $fh "; single wall width = %.2fmm\n", $Slic3r::flow_width;
|
||||
print $fh "\n";
|
||||
|
||||
# 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);
|
||||
}
|
||||
print $fh $extruder->set_fan(0, 1) if $Slic3r::cooling && $Slic3r::disable_fan_first_layers;
|
||||
|
||||
# write start commands to file
|
||||
printf $fh "M%s %s%d ; set bed temperature\n",
|
||||
($Slic3r::gcode_flavor eq 'makerbot' ? '109' : '190'),
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $Slic3r::first_layer_bed_temperature
|
||||
printf $fh $extruder->set_bed_temperature($Slic3r::first_layer_bed_temperature, 1),
|
||||
if $Slic3r::first_layer_bed_temperature && $Slic3r::start_gcode !~ /M190/i;
|
||||
printf $fh "M104 %s%d ; set temperature\n",
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $Slic3r::first_layer_temperature
|
||||
if $Slic3r::first_layer_temperature;
|
||||
printf $fh $extruder->set_temperature($Slic3r::first_layer_temperature)
|
||||
if $Slic3r::first_layer_temperature;
|
||||
printf $fh "%s\n", Slic3r::Config->replace_options($Slic3r::start_gcode);
|
||||
printf $fh "M109 %s%d ; wait for temperature to be reached\n",
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $Slic3r::first_layer_temperature
|
||||
if $Slic3r::first_layer_temperature && $Slic3r::gcode_flavor ne 'makerbot'
|
||||
&& $Slic3r::start_gcode !~ /M109/i;
|
||||
printf $fh $extruder->set_temperature($Slic3r::first_layer_temperature, 1)
|
||||
if $Slic3r::first_layer_temperature && $Slic3r::start_gcode !~ /M109/i;
|
||||
print $fh "G90 ; use absolute coordinates\n";
|
||||
print $fh "G21 ; set units to millimeters\n";
|
||||
if ($Slic3r::gcode_flavor =~ /^(?:reprap|teacup)$/) {
|
||||
@ -432,72 +436,66 @@ sub write_gcode {
|
||||
$Slic3r::print_center->[Y] - (unscale ($print_bb[Y2] - $print_bb[Y1]) / 2) - unscale $print_bb[Y1],
|
||||
);
|
||||
|
||||
# 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);
|
||||
}
|
||||
print $fh $extruder->set_fan(0, 1) if $Slic3r::cooling && $Slic3r::disable_fan_first_layers;
|
||||
# prepare the logic to print one layer
|
||||
my $skirt_done = 0;
|
||||
my $extrude_layer = sub {
|
||||
my ($layer_id, $object_copies) = @_;
|
||||
my $gcode = "";
|
||||
|
||||
# write gcode commands layer by layer
|
||||
for my $layer_id (0..$self->layer_count-1) {
|
||||
my @obj_idx = grep $self->objects->[$_]->layers->[$layer_id], 0..$#{$self->objects};
|
||||
my @obj_layers = map $self->objects->[$_]->layers->[$layer_id], @obj_idx;
|
||||
if ($layer_id == 1) {
|
||||
printf $fh "M104 %s%d ; set temperature\n",
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $Slic3r::temperature
|
||||
$gcode .= $extruder->set_temperature($Slic3r::temperature)
|
||||
if $Slic3r::temperature && $Slic3r::temperature != $Slic3r::first_layer_temperature;
|
||||
printf $fh "M140 %s%d ; set bed temperature\n",
|
||||
($Slic3r::gcode_flavor eq 'mach3' ? 'P' : 'S'), $Slic3r::bed_temperature
|
||||
$gcode .= $extruder->set_bed_temperature($Slic3r::bed_temperature)
|
||||
if $Slic3r::bed_temperature && $Slic3r::bed_temperature != $Slic3r::first_layer_bed_temperature;
|
||||
}
|
||||
|
||||
# go to layer
|
||||
my $layer_gcode = $extruder->change_layer($obj_layers[0]);
|
||||
# go to layer (just use the first one, we only need Z from it)
|
||||
$gcode .= $extruder->change_layer($self->objects->[$object_copies->[0][0]]->layers->[$layer_id]);
|
||||
$extruder->elapsed_time(0);
|
||||
|
||||
# extrude skirt
|
||||
$extruder->shift_x($shift[X]);
|
||||
$extruder->shift_y($shift[Y]);
|
||||
$layer_gcode .= $extruder->set_acceleration($Slic3r::perimeter_acceleration);
|
||||
if ($layer_id < $Slic3r::skirt_height) {
|
||||
$layer_gcode .= $extruder->extrude_loop($_, 'skirt') for @{$self->skirt};
|
||||
if (!$skirt_done) {
|
||||
$extruder->shift_x($shift[X]);
|
||||
$extruder->shift_y($shift[Y]);
|
||||
$gcode .= $extruder->set_acceleration($Slic3r::perimeter_acceleration);
|
||||
if ($layer_id < $Slic3r::skirt_height) {
|
||||
$gcode .= $extruder->extrude_loop($_, 'skirt') for @{$self->skirt};
|
||||
}
|
||||
$skirt_done = 1;
|
||||
}
|
||||
|
||||
for my $obj_idx (@obj_idx) {
|
||||
for my $obj_copy (@$object_copies) {
|
||||
my ($obj_idx, $copy) = @$obj_copy;
|
||||
my $layer = $self->objects->[$obj_idx]->layers->[$layer_id];
|
||||
for my $copy (@{ $self->copies->[$obj_idx] }) {
|
||||
# retract explicitely because changing the shift_[xy] properties below
|
||||
# won't always trigger the automatic retraction
|
||||
$layer_gcode .= $extruder->retract;
|
||||
|
||||
$extruder->shift_x($shift[X] + unscale $copy->[X]);
|
||||
$extruder->shift_y($shift[Y] + unscale $copy->[Y]);
|
||||
# retract explicitely because changing the shift_[xy] properties below
|
||||
# won't always trigger the automatic retraction
|
||||
$gcode .= $extruder->retract;
|
||||
|
||||
# extrude perimeters
|
||||
$layer_gcode .= $extruder->extrude($_, 'perimeter') for @{ $layer->perimeters };
|
||||
$extruder->shift_x($shift[X] + unscale $copy->[X]);
|
||||
$extruder->shift_y($shift[Y] + unscale $copy->[Y]);
|
||||
|
||||
# extrude fills
|
||||
$layer_gcode .= $extruder->set_acceleration($Slic3r::infill_acceleration);
|
||||
for my $fill (@{ $layer->fills }) {
|
||||
$layer_gcode .= $extruder->extrude_path($_, 'fill')
|
||||
for $fill->shortest_path($extruder->last_pos);
|
||||
}
|
||||
# extrude perimeters
|
||||
$gcode .= $extruder->extrude($_, 'perimeter') for @{ $layer->perimeters };
|
||||
|
||||
# extrude support material
|
||||
if ($layer->support_fills) {
|
||||
$layer_gcode .= $extruder->set_tool($Slic3r::support_material_tool)
|
||||
if $Slic3r::support_material_tool > 0;
|
||||
$layer_gcode .= $extruder->extrude_path($_, 'support material')
|
||||
for $layer->support_fills->shortest_path($extruder->last_pos);
|
||||
$layer_gcode .= $extruder->set_tool(0)
|
||||
if $Slic3r::support_material_tool > 0;
|
||||
}
|
||||
# extrude fills
|
||||
$gcode .= $extruder->set_acceleration($Slic3r::infill_acceleration);
|
||||
for my $fill (@{ $layer->fills }) {
|
||||
$gcode .= $extruder->extrude_path($_, 'fill')
|
||||
for $fill->shortest_path($extruder->last_pos);
|
||||
}
|
||||
|
||||
# extrude support material
|
||||
if ($layer->support_fills) {
|
||||
$gcode .= $extruder->set_tool($Slic3r::support_material_tool)
|
||||
if $Slic3r::support_material_tool > 0;
|
||||
$gcode .= $extruder->extrude_path($_, 'support material')
|
||||
for $layer->support_fills->shortest_path($extruder->last_pos);
|
||||
$gcode .= $extruder->set_tool(0)
|
||||
if $Slic3r::support_material_tool > 0;
|
||||
}
|
||||
}
|
||||
last if !$layer_gcode;
|
||||
last if !$gcode;
|
||||
|
||||
my $fan_speed = $Slic3r::fan_always_on ? $Slic3r::min_fan_speed : 0;
|
||||
my $speed_factor = 1;
|
||||
@ -515,24 +513,77 @@ sub write_gcode {
|
||||
Slic3r::debugf " fan = %d%%, speed = %d%%\n", $fan_speed, $speed_factor * 100;
|
||||
|
||||
if ($speed_factor < 1) {
|
||||
$layer_gcode =~ s/^(?=.*? [XY])(?=.*? E)(G1 .*?F)(\d+(?:\.\d+)?)/
|
||||
$gcode =~ s/^(?=.*? [XY])(?=.*? E)(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;
|
||||
$gcode = $extruder->set_fan($fan_speed) . $gcode;
|
||||
|
||||
# bridge fan speed
|
||||
if (!$Slic3r::cooling || $Slic3r::bridge_fan_speed == 0 || $layer_id < $Slic3r::disable_fan_first_layers) {
|
||||
$layer_gcode =~ s/^;_BRIDGE_FAN_(?:START|END)\n//gm;
|
||||
$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;
|
||||
$gcode =~ s/^;_BRIDGE_FAN_START\n/ $extruder->set_fan($Slic3r::bridge_fan_speed, 1) /gmex;
|
||||
$gcode =~ s/^;_BRIDGE_FAN_END\n/ $extruder->set_fan($fan_speed, 1) /gmex;
|
||||
}
|
||||
|
||||
print $fh $layer_gcode;
|
||||
return $gcode;
|
||||
};
|
||||
|
||||
# do all objects for each layer
|
||||
if ($Slic3r::complete_objects) {
|
||||
|
||||
# get the height of the tallest object
|
||||
my $max_z;
|
||||
{
|
||||
my @last_layers = sort { $a->layer_id <=> $b->layer_id } map $_->layers->[-1], @{$self->objects};
|
||||
$max_z = $Slic3r::z_offset + unscale $last_layers[-1]->print_z;
|
||||
}
|
||||
|
||||
my $finished_objects = 0;
|
||||
for my $obj_idx (0..$#{$self->objects}) {
|
||||
for my $copy (@{ $self->copies->[$obj_idx] }) {
|
||||
# move to the origin position for the copy we're going to print.
|
||||
# this happens before Z goes down to layer 0 again, so that
|
||||
# no collision happens hopefully.
|
||||
# if our current Z is lower than the tallest object in the print,
|
||||
# raise our Z to that one + a little clearance before doing the
|
||||
# horizontal move
|
||||
if ($finished_objects > 0) {
|
||||
$extruder->shift_x($shift[X] + unscale $copy->[X]);
|
||||
$extruder->shift_y($shift[Y] + unscale $copy->[Y]);
|
||||
print $fh $extruder->retract;
|
||||
print $fh $extruder->G0(undef, $max_z + 1, 0, 'move up to avoid collisions')
|
||||
if $extruder->z < $max_z;
|
||||
print $fh $extruder->G0(Slic3r::Point->new(0,0), undef, 0, 'move to origin position for next object');
|
||||
}
|
||||
|
||||
for my $layer_id (0..$#{$self->objects->[$obj_idx]->layers}) {
|
||||
# if we are printing the bottom layer of an object, and we have already finished
|
||||
# another one, set first layer temperatures. this happens before the Z move
|
||||
# is triggered, so machine has more time to reach such temperatures
|
||||
if ($layer_id == 0 && $finished_objects > 0) {
|
||||
printf $fh $extruder->set_bed_temperature($Slic3r::first_layer_bed_temperature),
|
||||
if $Slic3r::first_layer_bed_temperature;
|
||||
printf $fh $extruder->set_temperature($Slic3r::first_layer_temperature)
|
||||
if $Slic3r::first_layer_temperature;
|
||||
}
|
||||
print $fh $extrude_layer->($layer_id, [[ $obj_idx, $copy ]]);
|
||||
}
|
||||
$finished_objects++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for my $layer_id (0..$self->layer_count-1) {
|
||||
my @object_copies = ();
|
||||
for my $obj_idx (grep $self->objects->[$_]->layers->[$layer_id], 0..$#{$self->objects}) {
|
||||
push @object_copies, map [ $obj_idx, $_ ], @{ $self->copies->[$obj_idx] };
|
||||
}
|
||||
print $fh $extrude_layer->($layer_id, \@object_copies);
|
||||
}
|
||||
}
|
||||
|
||||
# save statistic data
|
||||
|
@ -202,6 +202,8 @@ $j
|
||||
--layer-gcode Load layer-change G-code from the supplied file (default: nothing).
|
||||
--support-material Generate support material for overhangs
|
||||
--randomize-start Randomize starting point across layers (default: yes)
|
||||
--complete-objects When printing multiple objects and/or copies, complete each one before
|
||||
starting the next one; watch out for extruder collisions (default: no)
|
||||
|
||||
Retraction options:
|
||||
--retract-length Length of retraction in mm when pausing extrusion
|
||||
|
Loading…
Reference in New Issue
Block a user