Improved retract handling on bowden extruders:

Separated deretract speed from a retract speed,
allowed a partial retract before wipe.
This commit is contained in:
bubnikv 2017-05-19 19:24:21 +02:00
parent 8bd3dec331
commit 70db88dd90
20 changed files with 246 additions and 108 deletions

View File

@ -1156,7 +1156,7 @@ sub build {
use_volumetric_e variable_layer_height
single_extruder_multi_material start_gcode end_gcode before_layer_gcode layer_gcode toolchange_gcode
nozzle_diameter extruder_offset
retract_length retract_lift retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe
retract_length retract_lift retract_speed deretract_speed retract_before_wipe retract_restart_extra retract_before_travel retract_layer_change wipe
retract_length_toolchange retract_restart_extra_toolchange
printer_notes
));
@ -1444,7 +1444,7 @@ sub _extruders_count_changed {
$self->_on_value_change('extruders_count', $extruders_count);
}
sub _extruder_options { qw(nozzle_diameter min_layer_height max_layer_height extruder_offset retract_length retract_lift retract_lift_above retract_lift_below retract_speed retract_restart_extra retract_before_travel wipe
sub _extruder_options { qw(nozzle_diameter min_layer_height max_layer_height extruder_offset retract_length retract_lift retract_lift_above retract_lift_below retract_speed deretract_speed retract_before_wipe retract_restart_extra retract_before_travel wipe
retract_layer_change retract_length_toolchange retract_restart_extra_toolchange) }
sub _build_extruder_pages {
@ -1497,7 +1497,7 @@ sub _build_extruder_pages {
}
$optgroup->append_single_option_line($_, $extruder_idx)
for qw(retract_speed retract_restart_extra retract_before_travel retract_layer_change wipe);
for qw(retract_speed deretract_speed retract_restart_extra retract_before_travel retract_layer_change wipe retract_before_wipe);
}
{
my $optgroup = $page->new_optgroup('Retraction when tool is disabled (advanced settings for multi-extruder setups)');
@ -1579,8 +1579,12 @@ sub _update {
# some options only apply when not using firmware retraction
$self->get_field($_, $i)->toggle($retraction && !$config->use_firmware_retraction)
for qw(retract_speed retract_restart_extra wipe);
if ($config->use_firmware_retraction && $config->get_at('wipe', $i)) {
for qw(retract_speed deretract_speed retract_before_wipe retract_restart_extra wipe);
my $wipe = $config->get_at('wipe', $i);
$self->get_field('retract_before_wipe', $i)->toggle($wipe);
if ($config->use_firmware_retraction && $wipe) {
my $dialog = Wx::MessageDialog->new($self,
"The Wipe option is not available when using the Firmware Retraction mode.\n"
. "\nShall I disable it in order to enable Firmware Retraction?",

View File

@ -376,6 +376,8 @@ DynamicConfig::optptr(const t_config_option_key &opt_key, bool create) {
opt = new ConfigOptionStrings ();
} else if (optdef->type == coPercent) {
opt = new ConfigOptionPercent ();
} else if (optdef->type == coPercents) {
opt = new ConfigOptionPercents ();
} else if (optdef->type == coFloatOrPercent) {
opt = new ConfigOptionFloatOrPercent ();
} else if (optdef->type == coPoint) {

View File

@ -57,6 +57,7 @@ class ConfigOptionSingle : public ConfigOption {
class ConfigOptionVectorBase : public ConfigOption {
public:
virtual ~ConfigOptionVectorBase() {};
// Currently used only to initialize the PlaceholderParser.
virtual std::vector<std::string> vserialize() const = 0;
};
@ -257,6 +258,46 @@ class ConfigOptionPercent : public ConfigOptionFloat
};
};
class ConfigOptionPercents : public ConfigOptionFloats
{
public:
std::string serialize() const {
std::ostringstream ss;
for (const auto &v : this->values) {
if (&v != &this->values.front()) ss << ",";
ss << v << "%";
}
std::string str = ss.str();
return str;
};
std::vector<std::string> vserialize() const {
std::vector<std::string> vv;
vv.reserve(this->values.size());
for (const auto v : this->values) {
std::ostringstream ss;
ss << v;
std::string sout = ss.str() + "%";
vv.push_back(sout);
}
return vv;
};
bool deserialize(std::string str) {
this->values.clear();
std::istringstream is(str);
std::string item_str;
while (std::getline(is, item_str, ',')) {
std::istringstream iss(item_str);
double value;
// don't try to parse the trailing % since it's optional
iss >> value;
this->values.push_back(value);
}
return true;
};
};
class ConfigOptionFloatOrPercent : public ConfigOptionPercent
{
public:
@ -488,6 +529,8 @@ enum ConfigOptionType {
coStrings,
// percent value. Currently only used for infill.
coPercent,
// percents value. Currently used for retract before wipe only.
coPercents,
// a fraction or an absolute value
coFloatOrPercent,
// single 2d point. Currently not used.

View File

@ -15,20 +15,9 @@ Extruder::Extruder(unsigned int id, GCodeConfig *config)
this->e_per_mm3 = this->extrusion_multiplier()
* (4 / ((this->filament_diameter() * this->filament_diameter()) * PI));
}
this->retract_speed_mm_min = this->retract_speed() * 60;
}
void
Extruder::reset()
{
this->E = 0;
this->absolute_E = 0;
this->retracted = 0;
this->restart_extra = 0;
}
double
Extruder::extrude(double dE)
double Extruder::extrude(double dE)
{
// in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances)
@ -46,8 +35,7 @@ Extruder::extrude(double dE)
The restart_extra argument sets the extra length to be used for
unretraction. If we're actually performing a retraction, any restart_extra
value supplied will overwrite the previous one if any. */
double
Extruder::retract(double length, double restart_extra)
double Extruder::retract(double length, double restart_extra)
{
// in case of relative E distances we always reset to 0 before any output
if (m_config->use_relative_e_distances)
@ -65,8 +53,7 @@ Extruder::retract(double length, double restart_extra)
}
}
double
Extruder::unretract()
double Extruder::unretract()
{
double dE = this->retracted + this->restart_extra;
this->extrude(dE);
@ -75,14 +62,12 @@ Extruder::unretract()
return dE;
}
double
Extruder::e_per_mm(double mm3_per_mm) const
double Extruder::e_per_mm(double mm3_per_mm) const
{
return mm3_per_mm * this->e_per_mm3;
}
double
Extruder::extruded_volume() const
double Extruder::extruded_volume() const
{
if (m_config->use_volumetric_e) {
// Any current amount of retraction should not affect used filament, since
@ -93,8 +78,7 @@ Extruder::extruded_volume() const
return this->used_filament() * (this->filament_diameter() * this->filament_diameter()) * PI/4;
}
double
Extruder::used_filament() const
double Extruder::used_filament() const
{
if (m_config->use_volumetric_e) {
return this->extruded_volume() / (this->filament_diameter() * this->filament_diameter() * PI/4);
@ -105,62 +89,64 @@ Extruder::used_filament() const
return this->absolute_E + this->retracted;
}
double
Extruder::filament_diameter() const
double Extruder::filament_diameter() const
{
return m_config->filament_diameter.get_at(this->id);
}
double
Extruder::filament_density() const
double Extruder::filament_density() const
{
return m_config->filament_density.get_at(this->id);
}
double
Extruder::filament_cost() const
double Extruder::filament_cost() const
{
return m_config->filament_cost.get_at(this->id);
}
double
Extruder::extrusion_multiplier() const
double Extruder::extrusion_multiplier() const
{
return m_config->extrusion_multiplier.get_at(this->id);
}
double
Extruder::retract_length() const
// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
double Extruder::retract_before_wipe() const
{
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(this->id) * 0.01));
}
double Extruder::retract_length() const
{
return m_config->retract_length.get_at(this->id);
}
double
Extruder::retract_lift() const
double Extruder::retract_lift() const
{
return m_config->retract_lift.get_at(this->id);
}
int
Extruder::retract_speed() const
int Extruder::retract_speed() const
{
return m_config->retract_speed.get_at(this->id);
}
double
Extruder::retract_restart_extra() const
int Extruder::deretract_speed() const
{
int speed = m_config->deretract_speed.get_at(this->id);
return (speed > 0) ? speed : this->retract_speed();
}
double Extruder::retract_restart_extra() const
{
return m_config->retract_restart_extra.get_at(this->id);
}
double
Extruder::retract_length_toolchange() const
double Extruder::retract_length_toolchange() const
{
return m_config->retract_length_toolchange.get_at(this->id);
}
double
Extruder::retract_restart_extra_toolchange() const
double Extruder::retract_restart_extra_toolchange() const
{
return m_config->retract_restart_extra_toolchange.get_at(this->id);
}

View File

@ -16,12 +16,17 @@ public:
double retracted;
double restart_extra;
double e_per_mm3;
double retract_speed_mm_min;
Extruder(unsigned int id, GCodeConfig *config);
virtual ~Extruder() {}
void reset();
void reset() {
this->E = 0;
this->absolute_E = 0;
this->retracted = 0;
this->restart_extra = 0;
}
double extrude(double dE);
double retract(double length, double restart_extra);
double unretract();
@ -33,9 +38,11 @@ public:
double filament_density() const;
double filament_cost() const;
double extrusion_multiplier() const;
double retract_before_wipe() const;
double retract_length() const;
double retract_lift() const;
int retract_speed() const;
int deretract_speed() const;
double retract_restart_extra() const;
double retract_length_toolchange() const;
double retract_restart_extra_toolchange() const;

View File

@ -159,6 +159,11 @@ WipeTowerIntegration::WipeTowerIntegration(const PrintConfig &print_config) : m_
m_impl.reset(wipe_tower);
}
static inline Point wipe_tower_point_to_object_point(GCode &gcodegen, const WipeTower::xy &wipe_tower_pt)
{
return Point(scale_(wipe_tower_pt.x - gcodegen.origin().x), scale_(wipe_tower_pt.y - gcodegen.origin().y));
}
std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer)
{
bool over_wipe_tower = false;
@ -175,6 +180,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id,
gcodegen.writer().toolchange(extruder_id);
// A phony move to the end position at the wipe tower.
gcodegen.writer().travel_to_xy(Pointf(code_and_pos.second.x, code_and_pos.second.y));
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, code_and_pos.second));
this->prepare_wipe(gcodegen, code_and_pos.second);
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
over_wipe_tower = true;
m_brim_done = true;
@ -190,6 +197,8 @@ std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id,
gcode += code_and_pos.first;
// A phony move to the end position at the wipe tower.
gcodegen.writer().travel_to_xy(Pointf(code_and_pos.second.x, code_and_pos.second.y));
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, code_and_pos.second));
this->prepare_wipe(gcodegen, code_and_pos.second);
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
}
@ -218,13 +227,26 @@ std::string WipeTowerIntegration::travel_to(GCode &gcodegen, const WipeTower::xy
std::string gcode = gcodegen.retract(true);
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
gcode += gcodegen.travel_to(
Point(scale_(dest.x - gcodegen.origin().x), scale_(dest.y - gcodegen.origin().y)),
wipe_tower_point_to_object_point(gcodegen, dest),
erMixed,
"Travel to a Wipe Tower");
gcode += gcodegen.unretract();
return gcode;
}
void WipeTowerIntegration::prepare_wipe(GCode &gcodegen, const WipeTower::xy &current_position)
{
gcodegen.m_wipe.path.points.clear();
// Start the wipe at the current position.
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, current_position));
// Wipe end point: Wipe direction away from the closer tower edge to the further tower edge.
float l = m_impl->position().x;
float r = l + m_impl->width();
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen,
WipeTower::xy((std::abs(l - current_position.x) < std::abs(r - current_position.x)) ? r : l,
current_position.y)));
}
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id)
inline void write(FILE *file, const std::string &what)
@ -577,7 +599,7 @@ bool GCode::do_export(FILE *file, Print &print)
// wher the objects are sorted by their sorted order given by object_indices.
auto it_layer_tools = std::lower_bound(tool_ordering.begin(), tool_ordering.end(), ToolOrdering::LayerTools(layer.first));
assert(it_layer_tools != tool_ordering.end() && layer.first);
if (m_wipe_tower) {
if (it_layer_tools->has_wipe_tower && m_wipe_tower) {
bool first_layer = layer.first == layers.begin()->first;
auto it_layer_tools_next = it_layer_tools;
++ it_layer_tools_next;
@ -965,7 +987,7 @@ void GCode::process_layer(
std::vector<std::unique_ptr<EdgeGrid::Grid>> lower_layer_edge_grids(layers.size());
for (unsigned int extruder_id : layer_tools.extruders)
{
gcode += m_wipe_tower ?
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
this->set_extruder(extruder_id);
@ -1923,8 +1945,10 @@ GCode::retract(bool toolchange)
return gcode;
// wipe (if it's enabled for this extruder and we have a stored wipe path)
if (EXTRUDER_CONFIG(wipe) && m_wipe.has_path())
if (EXTRUDER_CONFIG(wipe) && m_wipe.has_path()) {
gcode += toolchange ? m_writer.retract_for_toolchange(true) : m_writer.retract(true);
gcode += m_wipe.wipe(*this, toolchange);
}
/* The parent class will decide whether we need to perform an actual retraction
(the extruder might be already retracted fully or partially). We call these

View File

@ -84,6 +84,7 @@ public:
private:
std::string travel_to(GCode &codegen, const WipeTower::xy &dest);
void prepare_wipe(GCode &gcodegen, const WipeTower::xy &current_position);
std::unique_ptr<WipeTower> m_impl;
bool m_brim_done;
};

View File

@ -27,6 +27,8 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
it_layer->extruders.push_back(extruder_support);
if (has_interface)
it_layer->extruders.push_back(extruder_interface);
if (has_support || has_interface)
it_layer->has_support = true;
}
// Collect the object extruders.
for (auto layer : object.layers) {
@ -38,8 +40,10 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
if (layerm == nullptr)
continue;
const PrintRegion &region = *object.print()->regions[region_id];
if (! layerm->perimeters.entities.empty())
if (! layerm->perimeters.entities.empty()) {
it_layer->extruders.push_back(region.config.perimeter_extruder.value);
it_layer->has_object = true;
}
bool has_infill = false;
bool has_solid_infill = false;
for (const ExtrusionEntity *ee : layerm->fills.entities) {
@ -55,6 +59,8 @@ static void collect_extruders(const PrintObject &object, std::vector<LayerTools>
it_layer->extruders.push_back(region.config.solid_infill_extruder);
if (has_infill)
it_layer->extruders.push_back(region.config.infill_extruder);
if (has_solid_infill || has_infill)
it_layer->has_object = true;
}
}
@ -137,6 +143,10 @@ static void fill_wipe_tower_partitions(std::vector<LayerTools> &layers)
// Propagate the wipe tower partitions down to support the upper partitions by the lower partitions.
for (int i = int(layers.size()) - 2; i >= 0; -- i)
layers[i].wipe_tower_partitions = std::max(layers[i + 1].wipe_tower_partitions, layers[i].wipe_tower_partitions);
//FIXME this is a hack to get the ball rolling.
for (LayerTools &lt : layers)
lt.has_wipe_tower = lt.has_object;
}
// For the use case when each object is printed separately

View File

@ -11,14 +11,25 @@ namespace ToolOrdering {
struct LayerTools
{
LayerTools(const coordf_t z) : print_z(z), wipe_tower_partitions(0) {}
LayerTools(const coordf_t z) :
print_z(z),
has_object(false),
has_support(false),
has_wipe_tower(false),
wipe_tower_partitions(0) {}
bool operator< (const LayerTools &rhs) const { return print_z < rhs.print_z; }
bool operator==(const LayerTools &rhs) const { return print_z == rhs.print_z; }
coordf_t print_z;
bool has_object;
bool has_support;
// Zero based extruder IDs, ordered to minimize tool switches.
std::vector<unsigned int> extruders;
// Will there be anything extruded on this layer for the wipe tower?
// Due to the support layers possibly interleaving the object layers,
// wipe tower will be disabled for some support only layers.
bool has_wipe_tower;
// Number of wipe tower partitions to support the required number of tool switches
// and to support the wipe tower partitions above this one.
size_t wipe_tower_partitions;

View File

@ -30,6 +30,9 @@ public:
// Return the wipe tower position.
virtual const xy& position() const = 0;
// Return the wipe tower width.
virtual float width() const = 0;
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
virtual bool finished() const = 0;

View File

@ -348,11 +348,24 @@ std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::tool_change(int tool, Pu
// Wipe the newly loaded filament until the end of the assigned wipe area.
toolchange_Wipe(writer, cleaning_box);
// Draw a perimeter around cleaning_box and wipe.
toolchange_Done(writer, cleaning_box);
box_coordinates box = cleaning_box;
if (m_current_shape == SHAPE_REVERSED) {
std::swap(box.lu, box.ld);
std::swap(box.ru, box.rd);
}
// Draw a perimeter around cleaning_box.
writer.travel(box.lu, 7000)
.extrude(box.ld, 3200).extrude(box.rd)
.extrude(box.ru).extrude(box.lu);
// Wipe the nozzle.
if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE)
writer.travel(box.ru, 7200)
.travel(box.lu);
}
// Reset the extruder current to a normal value.
writer.set_extruder_trimpot(550)
.feedrate(6000)
.flush_planner_queue()
.reset_extruder()
.append("; CP TOOLCHANGE END\n"
@ -423,11 +436,15 @@ std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::toolchange_Brim(Purpose
}
}
// Move to the front left corner and wipe along the front edge.
writer.travel(wipeTower_box.ld, 7000)
.travel(wipeTower_box.rd)
.travel(wipeTower_box.ld)
.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
// Move to the front left corner.
writer.travel(wipeTower_box.ld, 7000);
if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE)
// Wipe along the front edge.
writer.travel(wipeTower_box.rd)
.travel(wipeTower_box.ld);
writer.append("; CP WIPE TOWER FIRST LAYER BRIM END\n"
";-----------------------------------\n");
// Mark the brim as extruded.
@ -616,26 +633,6 @@ void WipeTowerPrusaMM::toolchange_Wipe(
writer.set_extrusion_flow(m_extrusion_flow);
}
// Draw a perimeter around cleaning_box and wipe.
void WipeTowerPrusaMM::toolchange_Done(
PrusaMultiMaterial::Writer &writer,
const box_coordinates &cleaning_box)
{
box_coordinates box = cleaning_box;
if (m_current_shape == SHAPE_REVERSED) {
std::swap(box.lu, box.ld);
std::swap(box.ru, box.rd);
}
// Draw a perimeter around cleaning_box.
writer.travel(box.lu, 7000)
.extrude(box.ld, 3200).extrude(box.rd)
.extrude(box.ru).extrude(box.lu)
// Wipe the nozzle.
.travel(box.ru, 7200)
.travel(box.lu)
.feedrate(6000);
}
std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::finish_layer(Purpose purpose)
{
// This should only be called if the layer is not finished yet.
@ -720,11 +717,16 @@ std::pair<std::string, WipeTower::xy> WipeTowerPrusaMM::finish_layer(Purpose pur
writer.extrude(fill_box.ru + xy(- m_perimeter_width * 6, - m_perimeter_width), 2900 * speed_factor)
.extrude(fill_box.ru + xy(- m_perimeter_width * 3, - m_perimeter_width))
.extrude(fill_box.rd + xy(- m_perimeter_width * 3, m_perimeter_width))
.extrude(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width))
.extrude(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width));
if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE)
// Wipe along the front side of the current wiping box.
.travel(fill_box.ld + xy( m_perimeter_width, m_perimeter_width / 2), 7200)
.travel(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width / 2))
.append("; CP EMPTY GRID END\n"
writer.travel(fill_box.ld + xy( m_perimeter_width, m_perimeter_width / 2), 7200)
.travel(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width / 2));
else
writer.feedrate(7200);
writer.append("; CP EMPTY GRID END\n"
";------------------\n\n\n\n\n\n\n");
// Indicate that this wipe tower layer is fully covered.

View File

@ -105,6 +105,8 @@ public:
// Return the wipe tower position.
virtual const xy& position() const { return m_wipe_tower_pos; }
// Return the wipe tower width.
virtual float width() const { return m_wipe_tower_width; }
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
virtual bool finished() const { return m_max_color_changes == 0; }
@ -228,10 +230,6 @@ private:
PrusaMultiMaterial::Writer &writer,
const box_coordinates &cleaning_box);
void toolchange_Done(
PrusaMultiMaterial::Writer &writer,
const box_coordinates &cleaning_box);
void toolchange_Perimeter();
};

View File

@ -384,22 +384,24 @@ GCodeWriter::extrude_to_xyz(const Pointf3 &point, double dE, const std::string &
return gcode.str();
}
std::string
GCodeWriter::retract()
std::string GCodeWriter::retract(bool before_wipe)
{
double factor = before_wipe ? this->_extruder->retract_before_wipe() : 1.;
assert(factor >= 0. && factor <= 1. + EPSILON);
return this->_retract(
this->_extruder->retract_length(),
this->_extruder->retract_restart_extra(),
factor * this->_extruder->retract_length(),
factor * this->_extruder->retract_restart_extra(),
"retract"
);
}
std::string
GCodeWriter::retract_for_toolchange()
std::string GCodeWriter::retract_for_toolchange(bool before_wipe)
{
double factor = before_wipe ? this->_extruder->retract_before_wipe() : 1.;
assert(factor >= 0. && factor <= 1. + EPSILON);
return this->_retract(
this->_extruder->retract_length_toolchange(),
this->_extruder->retract_restart_extra_toolchange(),
factor * this->_extruder->retract_length_toolchange(),
factor * this->_extruder->retract_restart_extra_toolchange(),
"retract for toolchange"
);
}
@ -431,7 +433,7 @@ GCodeWriter::_retract(double length, double restart_extra, const std::string &co
gcode << "G10 ; retract\n";
} else {
gcode << "G1 " << this->_extrusion_axis << E_NUM(this->_extruder->E)
<< " F" << this->_extruder->retract_speed_mm_min;
<< " F" << float(this->_extruder->retract_speed() * 60.);
COMMENT(comment);
gcode << "\n";
}
@ -462,7 +464,7 @@ GCodeWriter::unretract()
} else {
// use G1 instead of G0 because G0 will blend the restart with the previous travel move
gcode << "G1 " << this->_extrusion_axis << E_NUM(this->_extruder->E)
<< " F" << this->_extruder->retract_speed_mm_min;
<< " F" << float(this->_extruder->deretract_speed() * 60.);
if (this->config.gcode_comments) gcode << " ; unretract";
gcode << "\n";
}

View File

@ -52,8 +52,8 @@ public:
bool will_move_z(double z) const;
std::string extrude_to_xy(const Pointf &point, double dE, const std::string &comment = std::string());
std::string extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment = std::string());
std::string retract();
std::string retract_for_toolchange();
std::string retract(bool before_wipe = false);
std::string retract_for_toolchange(bool before_wipe = false);
std::string unretract();
std::string lift();
std::string unlift();

View File

@ -169,6 +169,7 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|| *opt_key == "perimeter_acceleration"
|| *opt_key == "post_process"
|| *opt_key == "retract_before_travel"
|| *opt_key == "retract_before_wipe"
|| *opt_key == "retract_layer_change"
|| *opt_key == "retract_length"
|| *opt_key == "retract_length_toolchange"
@ -178,6 +179,7 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|| *opt_key == "retract_restart_extra"
|| *opt_key == "retract_restart_extra_toolchange"
|| *opt_key == "retract_speed"
|| *opt_key == "deretract_speed"
|| *opt_key == "single_extruder_multi_material"
|| *opt_key == "slowdown_below_layer_time"
|| *opt_key == "spiral_vase"

View File

@ -915,6 +915,17 @@ PrintConfigDef::PrintConfigDef()
def->default_value = opt;
}
def = this->add("retract_before_wipe", coPercents);
def->label = "Retract amount before wipe";
def->tooltip = "With bowden extruders, it may be wise to do some amount of quick retract before doing the wipe movement.";
def->sidetext = "%";
def->cli = "retract-before-wipe=s@";
{
ConfigOptionPercents* opt = new ConfigOptionPercents();
opt->values.push_back(0.f);
def->default_value = opt;
}
def = this->add("retract_layer_change", coBools);
def->label = "Retract on layer change";
def->tooltip = "This flag enforces a retraction whenever a Z move is done.";
@ -1007,7 +1018,7 @@ PrintConfigDef::PrintConfigDef()
}
def = this->add("retract_speed", coFloats);
def->label = "Speed";
def->label = "Retraction Speed";
def->full_label = "Retraction Speed";
def->tooltip = "The speed for retractions (it only applies to the extruder motor).";
def->sidetext = "mm/s";
@ -1018,6 +1029,18 @@ PrintConfigDef::PrintConfigDef()
def->default_value = opt;
}
def = this->add("deretract_speed", coFloats);
def->label = "Deretraction Speed";
def->full_label = "Deretraction Speed";
def->tooltip = "The speed for loading of a filament into extruder after retraction (it only applies to the extruder motor). If left to zero, the retraction speed is used.";
def->sidetext = "mm/s";
def->cli = "retract-speed=f@";
{
ConfigOptionFloats* opt = new ConfigOptionFloats();
opt->values.push_back(0);
def->default_value = opt;
}
def = this->add("seam_position", coEnum);
def->label = "Seam position";
def->category = "Layers and perimeters";

View File

@ -317,6 +317,7 @@ class GCodeConfig : public virtual StaticPrintConfig
{
public:
ConfigOptionString before_layer_gcode;
ConfigOptionFloats deretract_speed;
ConfigOptionString end_gcode;
ConfigOptionString extrusion_axis;
ConfigOptionFloats extrusion_multiplier;
@ -333,6 +334,7 @@ public:
ConfigOptionFloat max_volumetric_speed;
ConfigOptionFloat max_volumetric_extrusion_rate_slope_positive;
ConfigOptionFloat max_volumetric_extrusion_rate_slope_negative;
ConfigOptionPercents retract_before_wipe;
ConfigOptionFloats retract_length;
ConfigOptionFloats retract_length_toolchange;
ConfigOptionFloats retract_lift;
@ -357,6 +359,7 @@ public:
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(before_layer_gcode);
OPT_PTR(deretract_speed);
OPT_PTR(end_gcode);
OPT_PTR(extrusion_axis);
OPT_PTR(extrusion_multiplier);
@ -373,6 +376,7 @@ public:
OPT_PTR(max_volumetric_speed);
OPT_PTR(max_volumetric_extrusion_rate_slope_positive);
OPT_PTR(max_volumetric_extrusion_rate_slope_negative);
OPT_PTR(retract_before_wipe);
OPT_PTR(retract_length);
OPT_PTR(retract_length_toolchange);
OPT_PTR(retract_lift);

View File

@ -95,6 +95,13 @@ ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def) {
} else if (def.type == coPercent) {
const ConfigOptionPercent* optv = dynamic_cast<const ConfigOptionPercent*>(&opt);
return newSVnv(optv->value);
} else if (def.type == coPercents) {
const ConfigOptionPercents* optv = dynamic_cast<const ConfigOptionPercents*>(&opt);
AV* av = newAV();
av_fill(av, optv->values.size()-1);
for (const double &v : optv->values)
av_store(av, &v - &optv->values.front(), newSVnv(v));
return newRV_noinc((SV*)av);
} else if (def.type == coInt) {
const ConfigOptionInt* optv = dynamic_cast<const ConfigOptionInt*>(&opt);
return newSViv(optv->value);
@ -148,7 +155,7 @@ ConfigBase__get_at(ConfigBase* THIS, const t_config_option_key &opt_key, size_t
if (opt == NULL) return &PL_sv_undef;
const ConfigOptionDef* def = THIS->def->get(opt_key);
if (def->type == coFloats) {
if (def->type == coFloats || def->type == coPercents) {
ConfigOptionFloats* optv = dynamic_cast<ConfigOptionFloats*>(opt);
return newSVnv(optv->get_at(i));
} else if (def->type == coInts) {
@ -191,6 +198,17 @@ ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* value)
values.push_back(SvNV(*elem));
}
optv->values = values;
} else if (def->type == coPercents) {
ConfigOptionPercents* optv = dynamic_cast<ConfigOptionPercents*>(opt);
std::vector<double> values;
AV* av = (AV*)SvRV(value);
const size_t len = av_len(av)+1;
for (size_t i = 0; i < len; i++) {
SV** elem = av_fetch(av, i, 0);
if (elem == NULL || !looks_like_number(*elem)) return false;
values.push_back(SvNV(*elem));
}
optv->values = values;
} else if (def->type == coInt) {
if (!looks_like_number(value)) return false;
ConfigOptionInt* optv = dynamic_cast<ConfigOptionInt*>(opt);

View File

@ -106,7 +106,7 @@ print_config_def()
const char* opt_type;
if (optdef->type == coFloat || optdef->type == coFloats || optdef->type == coFloatOrPercent) {
opt_type = "f";
} else if (optdef->type == coPercent) {
} else if (optdef->type == coPercent || optdef->type == coPercents) {
opt_type = "percent";
} else if (optdef->type == coInt || optdef->type == coInts) {
opt_type = "i";

View File

@ -38,8 +38,6 @@
%code%{ RETVAL = THIS->restart_extra = val; %};
double e_per_mm3()
%code%{ RETVAL = THIS->e_per_mm3; %};
double retract_speed_mm_min()
%code%{ RETVAL = THIS->retract_speed_mm_min; %};
double filament_diameter();
double filament_density();