From 70db88dd90f741b89ad8b1ded7f4448864580e09 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 19 May 2017 19:24:21 +0200 Subject: [PATCH] Improved retract handling on bowden extruders: Separated deretract speed from a retract speed, allowed a partial retract before wipe. --- lib/Slic3r/GUI/Tab.pm | 14 +++-- xs/src/libslic3r/Config.cpp | 2 + xs/src/libslic3r/Config.hpp | 43 +++++++++++++ xs/src/libslic3r/Extruder.cpp | 70 +++++++++------------ xs/src/libslic3r/Extruder.hpp | 11 +++- xs/src/libslic3r/GCode.cpp | 32 ++++++++-- xs/src/libslic3r/GCode.hpp | 1 + xs/src/libslic3r/GCode/ToolOrdering.cpp | 14 ++++- xs/src/libslic3r/GCode/ToolOrdering.hpp | 13 +++- xs/src/libslic3r/GCode/WipeTower.hpp | 3 + xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 64 ++++++++++--------- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 6 +- xs/src/libslic3r/GCodeWriter.cpp | 22 ++++--- xs/src/libslic3r/GCodeWriter.hpp | 4 +- xs/src/libslic3r/Print.cpp | 2 + xs/src/libslic3r/PrintConfig.cpp | 25 +++++++- xs/src/libslic3r/PrintConfig.hpp | 4 ++ xs/src/perlglue.cpp | 20 +++++- xs/xsp/Config.xsp | 2 +- xs/xsp/Extruder.xsp | 2 - 20 files changed, 246 insertions(+), 108 deletions(-) diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 3f246a845..995388723 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -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?", diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index a8dda7379..932e1d04f 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -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) { diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index afb0671a5..9e3a57aef 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -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 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 vserialize() const { + std::vector 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. diff --git a/xs/src/libslic3r/Extruder.cpp b/xs/src/libslic3r/Extruder.cpp index 31523cb48..19f08d907 100644 --- a/xs/src/libslic3r/Extruder.cpp +++ b/xs/src/libslic3r/Extruder.cpp @@ -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); } diff --git a/xs/src/libslic3r/Extruder.hpp b/xs/src/libslic3r/Extruder.hpp index 813623772..8569a54c0 100644 --- a/xs/src/libslic3r/Extruder.hpp +++ b/xs/src/libslic3r/Extruder.hpp @@ -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; diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 678af0ece..601293b2d 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -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 ¤t_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> 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 diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 8abbdb167..91762237c 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -84,6 +84,7 @@ public: private: std::string travel_to(GCode &codegen, const WipeTower::xy &dest); + void prepare_wipe(GCode &gcodegen, const WipeTower::xy ¤t_position); std::unique_ptr m_impl; bool m_brim_done; }; diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 54660a7fc..1eba62963 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -27,6 +27,8 @@ static void collect_extruders(const PrintObject &object, std::vector 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,9 +40,11 @@ static void collect_extruders(const PrintObject &object, std::vector if (layerm == nullptr) continue; const PrintRegion ®ion = *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); - bool has_infill = false; + it_layer->has_object = true; + } + bool has_infill = false; bool has_solid_infill = false; for (const ExtrusionEntity *ee : layerm->fills.entities) { // fill represents infill extrusions of a single island. @@ -55,6 +59,8 @@ static void collect_extruders(const PrintObject &object, std::vector 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 &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 < : layers) + lt.has_wipe_tower = lt.has_object; } // For the use case when each object is printed separately diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index 1f649b7e0..e48a578ad 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -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 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; diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp index 728ab10c5..7237be216 100644 --- a/xs/src/libslic3r/GCode/WipeTower.hpp +++ b/xs/src/libslic3r/GCode/WipeTower.hpp @@ -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; diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 262fcc75a..b82092c08 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -348,11 +348,24 @@ std::pair 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 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 WipeTowerPrusaMM::finish_layer(Purpose purpose) { // This should only be called if the layer is not finished yet. @@ -720,11 +717,16 @@ std::pair 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)) - // 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" + .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. + 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. diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index c8eb6c543..ffafb2934 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -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(); }; diff --git a/xs/src/libslic3r/GCodeWriter.cpp b/xs/src/libslic3r/GCodeWriter.cpp index 2f86f576e..cbbaeaec1 100644 --- a/xs/src/libslic3r/GCodeWriter.cpp +++ b/xs/src/libslic3r/GCodeWriter.cpp @@ -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"; } diff --git a/xs/src/libslic3r/GCodeWriter.hpp b/xs/src/libslic3r/GCodeWriter.hpp index c3c90397a..a3b88bca5 100644 --- a/xs/src/libslic3r/GCodeWriter.hpp +++ b/xs/src/libslic3r/GCodeWriter.hpp @@ -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(); diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index eb8220208..5d739d9ba 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -169,6 +169,7 @@ Print::invalidate_state_by_config_options(const std::vector || *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 || *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" diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index a7b88c992..9eb661ea2 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -914,6 +914,17 @@ PrintConfigDef::PrintConfigDef() opt->values.push_back(2); 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"; @@ -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"; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 7a826d7e8..a30d39172 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -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); diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index f814b3de3..59fb0f390 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -95,6 +95,13 @@ ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def) { } else if (def.type == coPercent) { const ConfigOptionPercent* optv = dynamic_cast(&opt); return newSVnv(optv->value); + } else if (def.type == coPercents) { + const ConfigOptionPercents* optv = dynamic_cast(&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(&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(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(opt); + std::vector 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(opt); diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp index 1add8749c..0447703ea 100644 --- a/xs/xsp/Config.xsp +++ b/xs/xsp/Config.xsp @@ -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"; diff --git a/xs/xsp/Extruder.xsp b/xs/xsp/Extruder.xsp index 36f5427c7..2031b0145 100644 --- a/xs/xsp/Extruder.xsp +++ b/xs/xsp/Extruder.xsp @@ -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();