From b08d6f1969f237432cd18c15ad6432e5b95fb640 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 12 Sep 2017 15:55:38 +0200 Subject: [PATCH] The last priming area is shortened and the excess wipe is moved into the wipe tower if there is enough space inside the wipe tower. --- xs/src/libslic3r/BoundingBox.cpp | 30 +++++---- xs/src/libslic3r/GCode.cpp | 6 +- xs/src/libslic3r/GCode/PrintExtents.cpp | 4 +- xs/src/libslic3r/GCode/PrintExtents.hpp | 4 +- xs/src/libslic3r/GCode/WipeTower.hpp | 11 ++- xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp | 75 ++++++++++++++++----- xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp | 17 ++++- xs/src/libslic3r/Print.cpp | 7 +- 8 files changed, 115 insertions(+), 39 deletions(-) diff --git a/xs/src/libslic3r/BoundingBox.cpp b/xs/src/libslic3r/BoundingBox.cpp index f268bb3fb..66beaa3d5 100644 --- a/xs/src/libslic3r/BoundingBox.cpp +++ b/xs/src/libslic3r/BoundingBox.cpp @@ -125,15 +125,17 @@ template void BoundingBoxBase::merge(const Pointfs &points); template void BoundingBoxBase::merge(const BoundingBoxBase &bb) { - if (this->defined) { - this->min.x = std::min(bb.min.x, this->min.x); - this->min.y = std::min(bb.min.y, this->min.y); - this->max.x = std::max(bb.max.x, this->max.x); - this->max.y = std::max(bb.max.y, this->max.y); - } else { - this->min = bb.min; - this->max = bb.max; - this->defined = true; + if (bb.defined) { + if (this->defined) { + this->min.x = std::min(bb.min.x, this->min.x); + this->min.y = std::min(bb.min.y, this->min.y); + this->max.x = std::max(bb.max.x, this->max.x); + this->max.y = std::max(bb.max.y, this->max.y); + } else { + this->min = bb.min; + this->max = bb.max; + this->defined = true; + } } } template void BoundingBoxBase::merge(const BoundingBoxBase &bb); @@ -160,11 +162,13 @@ template void BoundingBox3Base::merge(const Pointf3s &points); template void BoundingBox3Base::merge(const BoundingBox3Base &bb) { - if (this->defined) { - this->min.z = std::min(bb.min.z, this->min.z); - this->max.z = std::max(bb.max.z, this->max.z); + if (bb.defined) { + if (this->defined) { + this->min.z = std::min(bb.min.z, this->min.z); + this->max.z = std::max(bb.max.z, this->max.z); + } + BoundingBoxBase::merge(bb); } - BoundingBoxBase::merge(bb); } template void BoundingBox3Base::merge(const BoundingBox3Base &bb); diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index a2e2f5607..478864e74 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -700,15 +700,17 @@ bool GCode::_do_export(Print &print, FILE *file) BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); bbox_prime.offset(0.5f); // Beep for 500ms, tone 800Hz. Yet better, play some Morse. + write(file, this->retract()); fprintf(file, "M300 S800 P500\n"); if (bbox_prime.overlap(bbox_print)) { // Wait for the user to remove the priming extrusions, otherwise they would // get covered by the print. - fprintf(file, "M1 Remove priming towers and click button.\n"); + fprintf(file, "M1 Remove priming towers and click button.\nM117 Printing\n"); } else { // Just wait for a bit to let the user check, that the priming succeeded. - fprintf(file, "M0 S10\n"); + fprintf(file, "M117 Verify extruder priming\nM0 S10\nM117 Printing\n"); } + write(file, this->unretract()); } else write(file, WipeTowerIntegration::prime_single_color_print(print, initial_extruder_id, *this)); } diff --git a/xs/src/libslic3r/GCode/PrintExtents.cpp b/xs/src/libslic3r/GCode/PrintExtents.cpp index 98dc59f58..db33627ec 100644 --- a/xs/src/libslic3r/GCode/PrintExtents.cpp +++ b/xs/src/libslic3r/GCode/PrintExtents.cpp @@ -101,7 +101,7 @@ BoundingBoxf get_print_extrusions_extents(const Print &print) return bbox; } -BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coord_t max_print_z) +BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z) { BoundingBoxf bbox; for (const Layer *layer : print_object.layers) { @@ -129,7 +129,7 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object // Returns a bounding box of a projection of the wipe tower for the layers <= max_print_z. // The projection does not contain the priming regions. -BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coord_t max_print_z) +BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z) { BoundingBoxf bbox; for (const std::vector &tool_changes : print.m_wipe_tower_tool_changes) { diff --git a/xs/src/libslic3r/GCode/PrintExtents.hpp b/xs/src/libslic3r/GCode/PrintExtents.hpp index 2706e2cab..db507689d 100644 --- a/xs/src/libslic3r/GCode/PrintExtents.hpp +++ b/xs/src/libslic3r/GCode/PrintExtents.hpp @@ -16,11 +16,11 @@ class BoundingBoxf; BoundingBoxf get_print_extrusions_extents(const Print &print); // Returns a bounding box of a projection of the object extrusions at z <= max_print_z. -BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coord_t max_print_z); +BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object, const coordf_t max_print_z); // Returns a bounding box of a projection of the wipe tower for the layers <= max_print_z. // The projection does not contain the priming regions. -BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coord_t max_print_z); +BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z); // Returns a bounding box of the wipe tower priming extrusions. BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print); diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp index cccbe23d8..c5fa27392 100644 --- a/xs/src/libslic3r/GCode/WipeTower.hpp +++ b/xs/src/libslic3r/GCode/WipeTower.hpp @@ -105,7 +105,16 @@ public: }; // Returns gcode to prime the nozzles at the front edge of the print bed. - virtual ToolChangeResult prime(float first_layer_height, std::vector tools, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0; + virtual ToolChangeResult prime( + // print_z of the first layer. + float first_layer_height, + // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. + std::vector tools, + // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. + // If false, the last priming are will be large enough to wipe the last extruder sufficiently. + bool last_wipe_inside_wipe_tower, + // May be used by a stand alone post processor. + Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0; // Returns gcode for toolchange and the end position. // if new_tool == -1, just unload the current filament over the wipe tower. diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 760ff03f0..14b67936d 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -364,7 +364,16 @@ WipeTowerPrusaMM::material_type WipeTowerPrusaMM::parse_material(const char *nam } // Returns gcode to prime the nozzles at the front edge of the print bed. -WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(float first_layer_height, std::vector tools, Purpose purpose) +WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( + // print_z of the first layer. + float first_layer_height, + // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. + std::vector tools, + // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. + // If false, the last priming are will be large enough to wipe the last extruder sufficiently. + bool last_wipe_inside_wipe_tower, + // May be used by a stand alone post processor. + Purpose purpose) { this->set_layer(first_layer_height, first_layer_height, tools.size(), true, false); @@ -411,6 +420,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(float first_layer_height, st .set_extruder_trimpot(750); if (purpose == PURPOSE_EXTRUDE || purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) { + float y_end = 0.f; for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) { unsigned int tool = tools[idx_tool]; // Select the tool, set a speed override for soluble and flex materials. @@ -419,10 +429,20 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(float first_layer_height, st toolchange_Load(writer, cleaning_box); if (idx_tool + 1 == tools.size()) { // Last tool should not be unloaded, but it should be wiped enough to become of a pure color. - toolchange_Wipe(writer, cleaning_box); + if (last_wipe_inside_wipe_tower) { + // Shrink the last wipe area to the area of the other purge areas, + // remember the last initial wipe width to be purged into the 1st layer of the wipe tower. + this->m_initial_extra_wipe = std::max(0.f, wipe_area - (y_end + 0.5f * 0.85f * m_perimeter_width - cleaning_box.ld.y)); + cleaning_box.lu.y -= this->m_initial_extra_wipe; + cleaning_box.ru.y -= this->m_initial_extra_wipe; + } + toolchange_Wipe(writer, cleaning_box, false); } else { // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. + writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200); toolchange_Unload(writer, cleaning_box, m_material[m_current_tool], m_first_layer_temperature[tool]); + // Save the y end of the non-last priming area. + y_end = writer.y(); cleaning_box.translate(m_wipe_tower_width, 0.f); writer.travel(cleaning_box.ld, 7200); } @@ -546,7 +566,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo toolchange_Change(writer, tool, m_material[tool]); toolchange_Load(writer, cleaning_box); // Wipe the newly loaded filament until the end of the assigned wipe area. - toolchange_Wipe(writer, cleaning_box); + toolchange_Wipe(writer, cleaning_box, false); // Draw a perimeter around cleaning_box and wipe. box_coordinates box = cleaning_box; if (m_current_shape == SHAPE_REVERSED) { @@ -647,6 +667,21 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(Purpose purpose, b } } + if (m_initial_extra_wipe > m_perimeter_width * 1.9f) { + box_coordinates cleaning_box( + m_wipe_tower_pos + xy(0.f, 0.5f * m_perimeter_width), + m_wipe_tower_width, + m_initial_extra_wipe - m_perimeter_width); + writer.travel(cleaning_box.ld + xy(m_perimeter_width, 0.5f * m_perimeter_width), 6000); + // Wipe the newly loaded filament until the end of the assigned wipe area. + toolchange_Wipe(writer, cleaning_box, true); + // Draw a perimeter around cleaning_box. + writer.travel(cleaning_box.lu, 7000) + .extrude(cleaning_box.ld, 3200).extrude(cleaning_box.rd) + .extrude(cleaning_box.ru).extrude(cleaning_box.lu); + m_current_wipe_start_y = m_initial_extra_wipe; + } + // Move to the front left corner. writer.travel(wipeTower_box.ld, 7000); @@ -786,6 +821,9 @@ void WipeTowerPrusaMM::toolchange_Load( { float xl = cleaning_box.ld.x + m_perimeter_width; float xr = cleaning_box.rd.x - m_perimeter_width; + //FIXME flipping left / right side, so that the following toolchange_Wipe will start + // where toolchange_Load ends. + std::swap(xl, xr); writer.append("; CP TOOLCHANGE LOAD\n") // Load the filament while moving left / right, @@ -819,7 +857,8 @@ void WipeTowerPrusaMM::toolchange_Load( // Wipe the newly loaded filament until the end of the assigned wipe area. void WipeTowerPrusaMM::toolchange_Wipe( PrusaMultiMaterial::Writer &writer, - const box_coordinates &cleaning_box) + const box_coordinates &cleaning_box, + bool skip_initial_y_move) { // Increase flow on first layer, slow down print. writer.set_extrusion_flow(m_extrusion_flow * (m_is_first_layer ? 1.18f : 1.f)) @@ -833,23 +872,27 @@ void WipeTowerPrusaMM::toolchange_Wipe( float wipe_speed_max = 4800.f; // Y increment per wipe line. float dy = ((m_current_shape == SHAPE_NORMAL) ? 1.f : -1.f) * m_perimeter_width * 0.8f; - for (bool p = true; ; p = ! p) { + for (bool p = true; + // Next wipe line fits the cleaning box. + ((m_current_shape == SHAPE_NORMAL) ? + (writer.y() <= cleaning_box.lu.y - m_perimeter_width) : + (writer.y() >= cleaning_box.ld.y + m_perimeter_width)); + p = ! p) + { wipe_speed = std::min(wipe_speed_max, wipe_speed + wipe_speed_inc); - if (p) { - writer.extrude(xl - m_perimeter_width / 2, writer.y() + dy, wipe_speed * wipe_coeff); - writer.extrude(xr + m_perimeter_width, writer.y()); - } else { - writer.extrude(xl - m_perimeter_width, writer.y() + dy, wipe_speed * wipe_coeff); - writer.extrude(xr + m_perimeter_width * 2, writer.y()); - } - wipe_speed = std::min(wipe_speed_max, wipe_speed + wipe_speed_inc); - writer.extrude(xr + m_perimeter_width, writer.y() + dy, wipe_speed * wipe_coeff); - writer.extrude(xl - m_perimeter_width, writer.y()); + if (skip_initial_y_move) + skip_initial_y_move = false; + else + writer.extrude(xl - (p ? m_perimeter_width / 2 : m_perimeter_width), writer.y() + dy, wipe_speed * wipe_coeff); + writer.extrude(xr + (p ? m_perimeter_width : m_perimeter_width * 2), writer.y(), wipe_speed * wipe_coeff); + // Next wipe line fits the cleaning box. if ((m_current_shape == SHAPE_NORMAL) ? (writer.y() > cleaning_box.lu.y - m_perimeter_width) : (writer.y() < cleaning_box.ld.y + m_perimeter_width)) - // Next wipe line does not fit the cleaning box. break; + wipe_speed = std::min(wipe_speed_max, wipe_speed + wipe_speed_inc); + writer.extrude(xr + m_perimeter_width, writer.y() + dy, wipe_speed * wipe_coeff); + writer.extrude(xl - m_perimeter_width, writer.y()); } // Reset the extrusion flow. writer.set_extrusion_flow(m_extrusion_flow); diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index c21c62486..15a96d367 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -108,7 +108,16 @@ public: virtual bool finished() const { return m_max_color_changes == 0; } // Returns gcode to prime the nozzles at the front edge of the print bed. - virtual ToolChangeResult prime(float first_layer_height, std::vector tools, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE); + virtual ToolChangeResult prime( + // print_z of the first layer. + float first_layer_height, + // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. + std::vector tools, + // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. + // If false, the last priming are will be large enough to wipe the last extruder sufficiently. + bool last_wipe_inside_wipe_tower, + // May be used by a stand alone post processor. + Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE); // Returns gcode for a toolchange and a final print head position. // On the first layer, extrude a brim around the future wipe tower first. @@ -176,6 +185,9 @@ private: unsigned int m_current_tool = 0; // Current y position at the wipe tower. float m_current_wipe_start_y = 0.f; + // How much to wipe the 1st extruder over the wipe tower at the 1st layer + // after the wipe tower brim has been extruded? + float m_initial_extra_wipe = 0.f; struct box_coordinates { @@ -230,7 +242,8 @@ private: void toolchange_Wipe( PrusaMultiMaterial::Writer &writer, - const box_coordinates &cleaning_box); + const box_coordinates &cleaning_box, + bool skip_initial_y_move); void toolchange_Perimeter(); }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 766acbe9b..667a3b4ea 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -992,8 +992,13 @@ void Print::_make_wipe_tower() this->config.temperature.get_at(i), this->config.first_layer_temperature.get_at(i)); + // When printing the first layer's wipe tower, the first extruder is expected to be active and primed. + // Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer. + // The following variable is true if the last priming section cannot be squeezed inside the wipe tower. + bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions; + m_wipe_tower_priming = Slic3r::make_unique( - wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), WipeTower::PURPOSE_EXTRUDE)); + wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE)); // Generate the wipe tower layers. m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size());