diff --git a/resources/calib/pressure_advance/pressure_advance_test.stl b/resources/calib/pressure_advance/pressure_advance_test.stl new file mode 100644 index 000000000..0df26de76 Binary files /dev/null and b/resources/calib/pressure_advance/pressure_advance_test.stl differ diff --git a/resources/calib/pressure_advance/tower.stl b/resources/calib/pressure_advance/tower.stl new file mode 100644 index 000000000..efe8db857 Binary files /dev/null and b/resources/calib/pressure_advance/tower.stl differ diff --git a/resources/calib/pressure_advance/tower_with_seam.stl b/resources/calib/pressure_advance/tower_with_seam.stl new file mode 100644 index 000000000..325ffb1d7 Binary files /dev/null and b/resources/calib/pressure_advance/tower_with_seam.stl differ diff --git a/resources/calib/retraction/retraction_tower.stl b/resources/calib/retraction/retraction_tower.stl new file mode 100644 index 000000000..bae70d592 Binary files /dev/null and b/resources/calib/retraction/retraction_tower.stl differ diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index d325c0e3c..0424aac5e 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -37,6 +37,7 @@ set(lisbslic3r_sources Brim.hpp BuildVolume.cpp BuildVolume.hpp + Calib.cpp Calib.hpp Circle.cpp Circle.hpp diff --git a/src/libslic3r/Calib.cpp b/src/libslic3r/Calib.cpp new file mode 100644 index 000000000..0718f6828 --- /dev/null +++ b/src/libslic3r/Calib.cpp @@ -0,0 +1,221 @@ +#include "Calib.hpp" +#include "Point.hpp" +#include "PrintConfig.hpp" +#include "GCodeWriter.hpp" +#include "GCode.hpp" +#include + + +namespace Slic3r { + + calib_pressure_advance::calib_pressure_advance(GCode* gcodegen) :mp_gcodegen(gcodegen), m_length_short(20.0), m_length_long(40.0), m_space_y(3.5), m_line_width(0.6), m_draw_numbers(true) {} + + std::string calib_pressure_advance::generate_test(double start_pa, double step_pa, int count ) { + BoundingBoxf bed_ext = get_extents(mp_gcodegen->config().printable_area.values); + bool is_delta = false; + if (mp_gcodegen->config().printable_area.values.size() > 4) { + is_delta = true; + bed_ext.scale(1.0f / 1.41421f); + } + + auto bed_sizes = mp_gcodegen->config().printable_area.values; + const auto &w = bed_ext.size().x(); + const auto &h = bed_ext.size().y(); + count = std::min(count, int((h - 10) / m_space_y)); + + m_length_long = 40 + std::min(w - 120.0, 0.0); + + auto startx = (w - m_length_short * 2 - m_length_long - 20) / 2; + auto starty = (h - count * m_space_y) / 2; + if (is_delta) { + startx = -startx; + starty = -(count * m_space_y) / 2; + } + + return print_pa_lines(startx, starty, start_pa, step_pa, count); + } + + std::string calib_pressure_advance::move_to(Vec2d pt) { + std::stringstream gcode; + gcode << mp_gcodegen->retract(); + gcode << mp_gcodegen->writer().travel_to_xyz(Vec3d(pt.x(), pt.y(), 0.2)); + gcode << mp_gcodegen->unretract(); + return gcode.str(); + } + + std::string calib_pressure_advance::print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num) { + + auto& writer = mp_gcodegen->writer(); + Flow line_flow = Flow(m_line_width, 0.2, mp_gcodegen->config().nozzle_diameter.get_at(0)); + Flow thin_line_flow = Flow(0.44, 0.2, mp_gcodegen->config().nozzle_diameter.get_at(0)); + const double e_calib = line_flow.mm3_per_mm() / 2.40528; // filament_mm/extrusion_mm + const double e = thin_line_flow.mm3_per_mm() / 2.40528; // filament_mm/extrusion_mm + + + const double fast = m_fast_speed * 60.0; + const double slow = m_slow_speed * 60.0; + std::stringstream gcode; + gcode << mp_gcodegen->writer().travel_to_z(0.2); + double y_pos = start_y; + + // prime line + auto prime_x = start_x - 2; + gcode << move_to(Vec2d(prime_x, y_pos + (num - 4) * m_space_y)); + gcode << writer.set_speed(slow); + gcode << writer.extrude_to_xy(Vec2d(prime_x, y_pos + 3 * m_space_y), e_calib * m_space_y * num * 1.1); + + for (int i = 0; i < num; ++i) { + + gcode << writer.set_pressure_advance(start_pa + i * step_pa); + gcode << move_to(Vec2d(start_x, y_pos + i * m_space_y)); + gcode << writer.set_speed(slow); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + i * m_space_y), e_calib * m_length_short); + gcode << writer.set_speed(fast); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + i * m_space_y), e_calib * m_length_long); + gcode << writer.set_speed(slow); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long + m_length_short, y_pos + i * m_space_y), e_calib * m_length_short); + + } + gcode << writer.set_pressure_advance(0.0); + + if (m_draw_numbers) { + // draw indicator lines + gcode << writer.set_speed(fast); + gcode << move_to(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 2)); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short, y_pos + (num - 1) * m_space_y + 7), e * 7); + gcode << move_to(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 7)); + gcode << writer.extrude_to_xy(Vec2d(start_x + m_length_short + m_length_long, y_pos + (num - 1) * m_space_y + 2), e * 7); + + for (int i = 0; i < num; i += 2) { + gcode << draw_number(start_x + m_length_short + m_length_long + m_length_short + 3, y_pos + i * m_space_y + m_space_y / 2, start_pa + i * step_pa); + } + } + return gcode.str(); + } + + + std::string calib_pressure_advance::draw_digit(double startx, double starty, char c) { + auto& writer = mp_gcodegen->writer(); + std::stringstream gcode; + const double lw = 0.48; + Flow line_flow = Flow(lw, 0.2, mp_gcodegen->config().nozzle_diameter.get_at(0)); + const double len = 2; + const double gap = lw / 2.0; + const double e = line_flow.mm3_per_mm() / 2.40528; // filament_mm/extrusion_mm + + // 0-------1 + // | | + // 3-------2 + // | | + // 4-------5 + const Vec2d p0(startx, starty); + const Vec2d p1(startx + len, starty); + const Vec2d p2(startx + len, starty - len); + const Vec2d p3(startx, starty - len); + const Vec2d p4(startx, starty - len * 2); + const Vec2d p5(startx + len, starty - len * 2); + + switch (c) + { + case '0': + gcode << move_to(p0); + gcode << writer.extrude_to_xy(p1, e * len); + gcode << writer.extrude_to_xy(p5, e * len * 2); + gcode << writer.extrude_to_xy(p4, e * len); + gcode << writer.extrude_to_xy(p0 - Vec2d(0, gap), e * len * 2); + break; + case '1': + gcode << move_to(p0 + Vec2d(len / 2, 0)); + gcode << writer.extrude_to_xy(p4 + Vec2d(len / 2, 0), e * len * 2); + break; + case '2': + gcode << move_to(p0); + gcode << writer.extrude_to_xy(p1, e * len); + gcode << writer.extrude_to_xy(p2, e * len); + gcode << writer.extrude_to_xy(p3, e * len); + gcode << writer.extrude_to_xy(p4, e * len); + gcode << writer.extrude_to_xy(p5, e * len); + break; + case '3': + gcode << move_to(p0); + gcode << writer.extrude_to_xy(p1, e * len); + gcode << writer.extrude_to_xy(p5, e * len * 2); + gcode << writer.extrude_to_xy(p4, e * len); + gcode << move_to(p2 - Vec2d(gap, 0)); + gcode << writer.extrude_to_xy(p3, e * len); + break; + case '4': + gcode << move_to(p0); + gcode << writer.extrude_to_xy(p3, e * len); + gcode << writer.extrude_to_xy(p2, e * len); + gcode << move_to(p1); + gcode << writer.extrude_to_xy(p5, e * len * 2); + break; + case '5': + gcode << move_to(p1); + gcode << writer.extrude_to_xy(p0, e * len); + gcode << writer.extrude_to_xy(p3, e * len); + gcode << writer.extrude_to_xy(p2, e * len); + gcode << writer.extrude_to_xy(p5, e * len); + gcode << writer.extrude_to_xy(p4, e * len); + break; + case '6': + gcode << move_to(p1); + gcode << writer.extrude_to_xy(p0, e * len); + gcode << writer.extrude_to_xy(p4, e * len * 2); + gcode << writer.extrude_to_xy(p5, e * len); + gcode << writer.extrude_to_xy(p2, e * len); + gcode << writer.extrude_to_xy(p3, e * len); + break; + case '7': + gcode << move_to(p0); + gcode << writer.extrude_to_xy(p1, e * len); + gcode << writer.extrude_to_xy(p5, e * len * 2); + break; + case '8': + gcode << move_to(p2); + gcode << writer.extrude_to_xy(p3, e * len); + gcode << writer.extrude_to_xy(p4, e * len); + gcode << writer.extrude_to_xy(p5, e * len); + gcode << writer.extrude_to_xy(p1, e * len * 2); + gcode << writer.extrude_to_xy(p0, e * len); + gcode << writer.extrude_to_xy(p3, e * len); + break; + case '9': + gcode << move_to(p5); + gcode << writer.extrude_to_xy(p1, e * len * 2); + gcode << writer.extrude_to_xy(p0, e * len); + gcode << writer.extrude_to_xy(p3, e * len); + gcode << writer.extrude_to_xy(p2, e * len); + break; + case '.': + gcode << move_to(p4 + Vec2d(len / 2, 0)); + gcode << writer.extrude_to_xy(p4 + Vec2d(len / 2, len / 2), e * len); + break; + default: + break; + } + + return gcode.str(); + } + // draw number + std::string calib_pressure_advance::draw_number(double startx, double starty, double value) { + double spacing = 3.0; + auto sNumber = std::to_string(value); + sNumber.erase(sNumber.find_last_not_of('0') + 1, std::string::npos); + sNumber.erase(sNumber.find_last_not_of('.') + 1, std::string::npos); + std::stringstream gcode; + gcode << mp_gcodegen->writer().set_speed(3600); + + + for (int i = 0; i < sNumber.length(); ++i) { + if (i > 5) + break; + gcode << draw_digit(startx + i * spacing, starty, sNumber[i]); + + } + + return gcode.str(); + } +} // namespace Slic3r + diff --git a/src/libslic3r/Calib.hpp b/src/libslic3r/Calib.hpp index 53f32ad2d..84cbcad68 100644 --- a/src/libslic3r/Calib.hpp +++ b/src/libslic3r/Calib.hpp @@ -13,9 +13,11 @@ enum class CalibMode : int { Calib_Flow_Rate, Calib_Temp_Tower, Calib_Vol_speed_Tower, - Calib_VFA_Tower + Calib_VFA_Tower, + Calib_Retraction_tower }; + struct Calib_Params { Calib_Params() : mode(CalibMode::Calib_None){} @@ -23,4 +25,35 @@ struct Calib_Params bool print_numbers; CalibMode mode; }; + +class calib_pressure_advance +{ +public: + calib_pressure_advance(GCode *gcodegen); + ~calib_pressure_advance() {} + + std::string generate_test(double start_pa = 0, double step_pa = 0.002, int count = 50); + void set_speed(double fast = 100.0, double slow = 20.0) + { + m_slow_speed = slow; + m_fast_speed = fast; + } + double &line_width() { return m_line_width; }; + bool & draw_numbers() { return m_draw_numbers; } + +private: + std::string move_to(Vec2d pt); + std::string print_pa_lines(double start_x, double start_y, double start_pa, double step_pa, int num); + std::string draw_digit(double startx, double starty, char c); + std::string draw_number(double startx, double starty, double value); + +private: + GCode *mp_gcodegen; + double m_length_short, m_length_long; + double m_space_y; + double m_slow_speed, m_fast_speed; + double m_line_width; + bool m_draw_numbers; +}; + } // namespace Slic3r diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 426eeee34..03e84cfdd 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1849,98 +1849,124 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } if (this->m_objsWithBrim.empty() && this->m_objSupportsWithBrim.empty()) m_brim_done = true; - //BBS: open spaghetti detector - // if (print.config().spaghetti_detector.value) - if (print.is_BBL_Printer()) - file.write("M981 S1 P20000 ;open spaghetti detector\n"); - - // Do all objects for each layer. - if (print.config().print_sequence == PrintSequence::ByObject && !has_wipe_tower) { - size_t finished_objects = 0; - const PrintObject *prev_object = (*print_object_instance_sequential_active)->print_object; - for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++ print_object_instance_sequential_active) { - const PrintObject &object = *(*print_object_instance_sequential_active)->print_object; - if (&object != prev_object || tool_ordering.first_extruder() != final_extruder_id) { - tool_ordering = ToolOrdering(object, final_extruder_id); - unsigned int new_extruder_id = tool_ordering.first_extruder(); - if (new_extruder_id == (unsigned int)-1) - // Skip this object. - continue; - initial_extruder_id = new_extruder_id; - final_extruder_id = tool_ordering.last_extruder(); - assert(final_extruder_id != (unsigned int)-1); - } - print.throw_if_canceled(); - this->set_origin(unscale((*print_object_instance_sequential_active)->shift)); - - // BBS: prime extruder if extruder change happens before this object instance - bool prime_extruder = false; - if (finished_objects > 0) { - // 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. - m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer - m_avoid_crossing_perimeters.use_external_mp_once(); - // BBS. change tool before moving to origin point. - if (m_writer.need_toolchange(initial_extruder_id)) { - const PrintObjectConfig& object_config = object.config(); - coordf_t initial_layer_print_height = print.config().initial_layer_print_height.value; - file.write(this->set_extruder(initial_extruder_id, initial_layer_print_height)); - prime_extruder = true; - } - else { - file.write(this->retract()); - } - file.write(m_writer.travel_to_z(m_max_layer_z)); - file.write(this->travel_to(Point(0, 0), erNone, "move to origin position for next object")); - m_enable_cooling_markers = true; - // Disable motion planner when traveling to first object point. - m_avoid_crossing_perimeters.disable_once(); - // Ff 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. - m_placeholder_parser.set("current_object_idx", int(finished_objects)); - //BBS: remove printing_by_object_gcode - //std::string printing_by_object_gcode = this->placeholder_parser_process("printing_by_object_gcode", print.config().printing_by_object_gcode.value, initial_extruder_id); - std::string printing_by_object_gcode; - // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature. - this->_print_first_layer_bed_temperature(file, print, printing_by_object_gcode, initial_extruder_id, false); - this->_print_first_layer_extruder_temperatures(file, print, printing_by_object_gcode, initial_extruder_id, false); - file.writeln(printing_by_object_gcode); - } - // Reset the cooling buffer internal state (the current position, feed rate, accelerations). - m_cooling_buffer->reset(this->writer().get_position()); - m_cooling_buffer->set_current_extruder(initial_extruder_id); - // Process all layers of a single object instance (sequential mode) with a parallel pipeline: - // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser - // and export G-code into file. - this->process_layers(print, tool_ordering, collect_layers_to_print(object), *print_object_instance_sequential_active - object.instances().data(), file, prime_extruder); - //BBS: close powerlost recovery - { - if (m_second_layer_things_done && print.is_BBL_Printer()) { - file.write("; close powerlost recovery\n"); - file.write("M1003 S0\n"); - } - } -#ifdef HAS_PRESSURE_EQUALIZER - if (m_pressure_equalizer) - file.write(m_pressure_equalizer->process("", true)); -#endif /* HAS_PRESSURE_EQUALIZER */ - ++ finished_objects; - // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed. - // Reset it when starting another object from 1st layer. - m_second_layer_things_done = false; - prev_object = &object; + // SoftFever: calib + if (print.calib_params().mode == CalibMode::Calib_PA_Line) { + std::string gcode; + if ((m_config.default_acceleration.value > 0 && m_config.outer_wall_acceleration.value > 0)) { + gcode += m_writer.set_acceleration((unsigned int) floor(m_config.outer_wall_acceleration.value + 0.5)); } - } else { - // Sort layers by Z. - // All extrusion moves with the same top layer height are extruded uninterrupted. - std::vector>> layers_to_print = collect_layers_to_print(print); - // Prusa Multi-Material wipe tower. - if (has_wipe_tower && ! layers_to_print.empty()) { - m_wipe_tower.reset(new WipeTowerIntegration(print.config(), print.get_plate_index(), print.get_plate_origin(), * print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); - //BBS - //file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height")); - file.write(m_writer.travel_to_z(initial_layer_print_height, "Move to the first layer height")); + + // todo: 3rd party printer need + //if (m_config.default_jerk.value > 0) { + // double jerk = m_config.outer_wall_jerk.value; + // gcode += m_writer.set_jerk_xy(jerk); + //} + + calib_pressure_advance pa_test(this); + double filament_max_volumetric_speed = m_config.option("filament_max_volumetric_speed")->get_at(initial_extruder_id); + Flow pattern_line = Flow(pa_test.line_width(), 0.2, m_config.nozzle_diameter.get_at(0)); + auto fast_speed = std::min(print.default_region_config().outer_wall_speed.value, filament_max_volumetric_speed / pattern_line.mm3_per_mm()); + auto slow_speed = std::max(20.0, fast_speed / 10.0); + pa_test.set_speed(fast_speed, slow_speed); + pa_test.draw_numbers() = print.calib_params().print_numbers; + auto params = print.calib_params(); + gcode += pa_test.generate_test(params.start, params.step, std::llround(std::ceil((params.end - params.start) / params.step))); + + file.write(gcode); + } + else { + // BBS: open spaghetti detector + // if (print.config().spaghetti_detector.value) + if (print.is_BBL_Printer()) file.write("M981 S1 P20000 ;open spaghetti detector\n"); + + // Do all objects for each layer. + if (print.config().print_sequence == PrintSequence::ByObject && !has_wipe_tower) { + size_t finished_objects = 0; + const PrintObject *prev_object = (*print_object_instance_sequential_active)->print_object; + for (; print_object_instance_sequential_active != print_object_instances_ordering.end(); ++print_object_instance_sequential_active) { + const PrintObject &object = *(*print_object_instance_sequential_active)->print_object; + if (&object != prev_object || tool_ordering.first_extruder() != final_extruder_id) { + tool_ordering = ToolOrdering(object, final_extruder_id); + unsigned int new_extruder_id = tool_ordering.first_extruder(); + if (new_extruder_id == (unsigned int) -1) + // Skip this object. + continue; + initial_extruder_id = new_extruder_id; + final_extruder_id = tool_ordering.last_extruder(); + assert(final_extruder_id != (unsigned int) -1); + } + print.throw_if_canceled(); + this->set_origin(unscale((*print_object_instance_sequential_active)->shift)); + + // BBS: prime extruder if extruder change happens before this object instance + bool prime_extruder = false; + if (finished_objects > 0) { + // 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. + m_enable_cooling_markers = false; // we're not filtering these moves through CoolingBuffer + m_avoid_crossing_perimeters.use_external_mp_once(); + // BBS. change tool before moving to origin point. + if (m_writer.need_toolchange(initial_extruder_id)) { + const PrintObjectConfig &object_config = object.config(); + coordf_t initial_layer_print_height = print.config().initial_layer_print_height.value; + file.write(this->set_extruder(initial_extruder_id, initial_layer_print_height)); + prime_extruder = true; + } else { + file.write(this->retract()); + } + file.write(m_writer.travel_to_z(m_max_layer_z)); + file.write(this->travel_to(Point(0, 0), erNone, "move to origin position for next object")); + m_enable_cooling_markers = true; + // Disable motion planner when traveling to first object point. + m_avoid_crossing_perimeters.disable_once(); + // Ff 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. + m_placeholder_parser.set("current_object_idx", int(finished_objects)); + // BBS: remove printing_by_object_gcode + // std::string printing_by_object_gcode = this->placeholder_parser_process("printing_by_object_gcode", print.config().printing_by_object_gcode.value, + // initial_extruder_id); + std::string printing_by_object_gcode; + // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature. + this->_print_first_layer_bed_temperature(file, print, printing_by_object_gcode, initial_extruder_id, false); + this->_print_first_layer_extruder_temperatures(file, print, printing_by_object_gcode, initial_extruder_id, false); + file.writeln(printing_by_object_gcode); + } + // Reset the cooling buffer internal state (the current position, feed rate, accelerations). + m_cooling_buffer->reset(this->writer().get_position()); + m_cooling_buffer->set_current_extruder(initial_extruder_id); + // Process all layers of a single object instance (sequential mode) with a parallel pipeline: + // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser + // and export G-code into file. + this->process_layers(print, tool_ordering, collect_layers_to_print(object), *print_object_instance_sequential_active - object.instances().data(), file, + prime_extruder); + // BBS: close powerlost recovery + { + if (m_second_layer_things_done && print.is_BBL_Printer()) { + file.write("; close powerlost recovery\n"); + file.write("M1003 S0\n"); + } + } +#ifdef HAS_PRESSURE_EQUALIZER + if (m_pressure_equalizer) file.write(m_pressure_equalizer->process("", true)); +#endif /* HAS_PRESSURE_EQUALIZER */ + ++finished_objects; + // Flag indicating whether the nozzle temperature changes from 1st to 2nd layer were performed. + // Reset it when starting another object from 1st layer. + m_second_layer_things_done = false; + prev_object = &object; + } + } else { + // Sort layers by Z. + // All extrusion moves with the same top layer height are extruded uninterrupted. + std::vector>> layers_to_print = collect_layers_to_print(print); + // Prusa Multi-Material wipe tower. + if (has_wipe_tower && !layers_to_print.empty()) { + m_wipe_tower.reset(new WipeTowerIntegration(print.config(), print.get_plate_index(), print.get_plate_origin(), *print.wipe_tower_data().priming.get(), + print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get())); + // BBS + // file.write(m_writer.travel_to_z(initial_layer_print_height + m_config.z_offset.value, "Move to the first layer height")); + file.write(m_writer.travel_to_z(initial_layer_print_height, "Move to the first layer height")); #if 0 if (print.config().single_extruder_multi_material_priming) { file.write(m_wipe_tower->prime(*this)); @@ -1979,26 +2005,26 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato //} } #endif - print.throw_if_canceled(); - } - // Process all layers of all objects (non-sequential mode) with a parallel pipeline: - // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser - // and export G-code into file. - this->process_layers(print, tool_ordering, print_object_instances_ordering, layers_to_print, file); - //BBS: close powerlost recovery - { - if (m_second_layer_things_done && print.is_BBL_Printer()) { - file.write("; close powerlost recovery\n"); - file.write("M1003 S0\n"); + print.throw_if_canceled(); + } + // Process all layers of all objects (non-sequential mode) with a parallel pipeline: + // Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser + // and export G-code into file. + this->process_layers(print, tool_ordering, print_object_instances_ordering, layers_to_print, file); + // BBS: close powerlost recovery + { + if (m_second_layer_things_done && print.is_BBL_Printer()) { + file.write("; close powerlost recovery\n"); + file.write("M1003 S0\n"); + } } - } #ifdef HAS_PRESSURE_EQUALIZER - if (m_pressure_equalizer) - file.write(m_pressure_equalizer->process("", true)); + if (m_pressure_equalizer) file.write(m_pressure_equalizer->process("", true)); #endif /* HAS_PRESSURE_EQUALIZER */ - if (m_wipe_tower) - // Purge the extruder, pull out the active filament. - file.write(m_wipe_tower->finalize(*this)); + if (m_wipe_tower) + // Purge the extruder, pull out the active filament. + file.write(m_wipe_tower->finalize(*this)); + } } //BBS: the last retraction @@ -2748,6 +2774,14 @@ GCode::LayerResult GCode::process_layer( auto _speed = print.calib_params().start + std::floor(print_z / 5.0) * print.calib_params().step; m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed))); } + else if (print.calib_mode() == CalibMode::Calib_Retraction_tower) { + auto _length = print.calib_params().start + std::floor(std::max(0.0, print_z - 0.4)) * print.calib_params().step; + DynamicConfig _cfg; + _cfg.set_key_value("retraction_length", new ConfigOptionFloats{_length}); + writer().config.apply(_cfg); + sprintf(buf, "; Calib_Retraction_tower: Z_HEIGHT: %g, length:%g\n", print_z, _length); + gcode += buf; + } //BBS if (first_layer) { diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 10beff9dc..498869963 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -198,6 +198,11 @@ public: // append full config to the given string static void append_full_config(const Print& print, std::string& str); + // BBS: detect lift type in needs_retraction + bool needs_retraction(const Polyline &travel, ExtrusionRole role, LiftType &lift_type); + std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::SpiralLift); + std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } + // Object and support extrusions of the same PrintObject at the same print_z. // public, so that it could be accessed by free helper functions from GCode.cpp struct LayerToPrint @@ -400,10 +405,7 @@ private: std::string travel_to(const Point &point, ExtrusionRole role, std::string comment); // BBS LiftType to_lift_type(ZHopType z_hop_types); - // BBS: detect lift type in needs_retraction - bool needs_retraction(const Polyline& travel, ExtrusionRole role, LiftType& lift_type); - std::string retract(bool toolchange = false, bool is_last_retraction = false, LiftType lift_type = LiftType::SpiralLift); - std::string unretract() { return m_writer.unlift() + m_writer.unretract(); } + std::string set_extruder(unsigned int extruder_id, double print_z); std::set m_objsWithBrim; // indicates the objs with brim std::set m_objSupportsWithBrim; // indicates the objs' supports with brim diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index a4b574265..536d17b66 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -182,6 +182,24 @@ std::string GCodeWriter::set_acceleration(unsigned int acceleration) return gcode.str(); } +std::string GCodeWriter::set_pressure_advance(double pa) const +{ + std::ostringstream gcode; + if (pa < 0) return gcode.str(); + if (false) { // todo: bbl printer + // SoftFever: set L1000 to use linear model + gcode << "M900 K" << std::setprecision(4) << pa << " L1000 M10 ; Override pressure advance value\n"; + } else { + if (this->config.gcode_flavor == gcfKlipper) + gcode << "SET_PRESSURE_ADVANCE ADVANCE=" << std::setprecision(4) << pa << "; Override pressure advance value\n"; + else if (this->config.gcode_flavor == gcfRepRapFirmware) + gcode << ("M572 D0 S") << std::setprecision(4) << pa << "; Override pressure advance value\n"; + else + gcode << "M900 K" << std::setprecision(4) << pa << "; Override pressure advance value\n"; + } + return gcode.str(); +} + std::string GCodeWriter::reset_e(bool force) { if (FLAVOR_IS(gcfMach3) diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 0a0cd2ecf..01935ee0f 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -50,6 +50,7 @@ public: std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; std::string set_bed_temperature(int temperature, bool wait = false); std::string set_acceleration(unsigned int acceleration); + std::string set_pressure_advance(double pa) const; std::string reset_e(bool force = false); std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const; // return false if this extruder was already selected diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index a024f3981..361b9e024 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -33,7 +33,7 @@ namespace Slic3r { enum GCodeFlavor : unsigned char { gcfMarlinLegacy, gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinFirmware, gcfSailfish, gcfMach3, gcfMachinekit, - gcfSmoothie, gcfNoExtrusion, + gcfSmoothie, gcfNoExtrusion, gcfKlipper }; enum class FuzzySkinType { diff --git a/src/slic3r/GUI/CalibrationWizard.cpp b/src/slic3r/GUI/CalibrationWizard.cpp index 90f539c6d..e26e84a24 100644 --- a/src/slic3r/GUI/CalibrationWizard.cpp +++ b/src/slic3r/GUI/CalibrationWizard.cpp @@ -2782,7 +2782,7 @@ bool MaxVolumetricSpeedWizard::start_calibration(std::vector tray_ids) std::string error_message; CalibUtils::calib_max_vol_speed(calib_info, error_message); if (!error_message.empty()) { - MessageDialog msg_dlg(nullptr, error_message, wxEmptyString, wxICON_WARNING | wxOK); + MessageDialog msg_dlg(nullptr, _L(error_message), wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); return false; } @@ -2960,7 +2960,7 @@ bool TemperatureWizard::start_calibration(std::vector tray_ids) std::string error_message; CalibUtils::calib_temptue(calib_info, error_message); if (!error_message.empty()) { - MessageDialog msg_dlg(nullptr, error_message, wxEmptyString, wxICON_WARNING | wxOK); + MessageDialog msg_dlg(nullptr, _L(error_message), wxEmptyString, wxICON_WARNING | wxOK); msg_dlg.ShowModal(); return false; } diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index c295e8007..eba7e2b77 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -7,9 +7,6 @@ #include "libslic3r/Model.hpp" -// todo test -#include "../GUI/BBLStatusBar.hpp" - namespace Slic3r { namespace GUI { @@ -66,6 +63,16 @@ static void read_model_from_file(const std::string& input_file, Model& model) object->ensure_on_bed(); } +std::array get_cut_plane(const BoundingBoxf3 &bbox, const double &cut_height) +{ + std::array plane_pts; + plane_pts[0] = Vec3d(bbox.min(0), bbox.min(1), cut_height); + plane_pts[1] = Vec3d(bbox.max(0), bbox.min(1), cut_height); + plane_pts[2] = Vec3d(bbox.max(0), bbox.max(1), cut_height); + plane_pts[3] = Vec3d(bbox.min(0), bbox.max(1), cut_height); + return plane_pts; +} + void CalibUtils::calib_PA(const X1CCalibInfos& calib_infos, std::string& error_message) { DeviceManager *dev = Slic3r::GUI::wxGetApp().getDeviceManager(); @@ -306,6 +313,33 @@ void CalibUtils::calib_flowrate(int pass, const CalibInfo& calib_info, std::stri send_to_print(calib_info.dev_id, calib_info.select_ams, calib_info.process_bar, calib_info.bed_type, error_message); } +void CalibUtils::calib_generic_PA(const CalibInfo &calib_info, std::string &error_message) +{ + const Calib_Params ¶ms = calib_info.params; + if (params.mode != CalibMode::Calib_PA_Line) + return; + + Model model; + std::string input_file = Slic3r::resources_dir() + "/calib/pressure_advance/pressure_advance_test.stl"; + read_model_from_file(input_file, model); + + DynamicPrintConfig print_config = calib_info.print_prest->config; + DynamicPrintConfig filament_config = calib_info.filament_prest->config; + DynamicPrintConfig printer_config = calib_info.printer_prest->config; + + DynamicPrintConfig full_config; + full_config.apply(FullPrintConfig::defaults()); + full_config.apply(print_config); + full_config.apply(filament_config); + full_config.apply(printer_config); + + process_and_store_3mf(&model, full_config, params, error_message); + if (!error_message.empty()) + return; + + send_to_print(calib_info.dev_id, calib_info.select_ams, calib_info.process_bar, calib_info.bed_type, error_message); +} + void CalibUtils::calib_temptue(const CalibInfo& calib_info, std::string& error_message) { const Calib_Params ¶ms = calib_info.params; @@ -509,6 +543,55 @@ void CalibUtils::calib_VFA(const CalibInfo& calib_info, std::string& error_messa send_to_print(calib_info.dev_id, calib_info.select_ams, calib_info.process_bar, calib_info.bed_type, error_message); } +void CalibUtils::calib_retraction(const CalibInfo &calib_info, std::string &error_message) +{ + const Calib_Params ¶ms = calib_info.params; + if (params.mode != CalibMode::Calib_Retraction_tower) + return; + + Model model; + std::string input_file = Slic3r::resources_dir() + "/calib/retraction/retraction_tower.stl"; + read_model_from_file(input_file, model); + + DynamicPrintConfig print_config = calib_info.print_prest->config; + DynamicPrintConfig filament_config = calib_info.filament_prest->config; + DynamicPrintConfig printer_config = calib_info.printer_prest->config; + + auto obj = model.objects[0]; + + double layer_height = 0.2; + + auto max_lh = printer_config.option("max_layer_height"); + if (max_lh->values[0] < layer_height) max_lh->values[0] = {layer_height}; + + obj->config.set_key_value("wall_loops", new ConfigOptionInt(2)); + obj->config.set_key_value("top_shell_layers", new ConfigOptionInt(0)); + obj->config.set_key_value("bottom_shell_layers", new ConfigOptionInt(3)); + obj->config.set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); + obj->config.set_key_value("initial_layer_print_height", new ConfigOptionFloat(layer_height)); + obj->config.set_key_value("layer_height", new ConfigOptionFloat(layer_height)); + + // cut upper + auto obj_bb = obj->bounding_box(); + auto height = 1.0 + 0.4 + ((params.end - params.start)) / params.step; + if (height < obj_bb.size().z()) { + std::array plane_pts = get_cut_plane(obj_bb, height); + cut_model(model, plane_pts, ModelObjectCutAttribute::KeepLower); + } + + DynamicPrintConfig full_config; + full_config.apply(FullPrintConfig::defaults()); + full_config.apply(print_config); + full_config.apply(filament_config); + full_config.apply(printer_config); + + process_and_store_3mf(&model, full_config, params, error_message); + if (!error_message.empty()) + return; + + send_to_print(calib_info.dev_id, calib_info.select_ams, calib_info.process_bar, calib_info.bed_type, error_message); +} + void CalibUtils::process_and_store_3mf(Model* model, const DynamicPrintConfig& full_config, const Calib_Params& params, std::string& error_message) { Pointfs bedfs = full_config.opt("printable_area")->values; @@ -544,7 +627,7 @@ void CalibUtils::process_and_store_3mf(Model* model, const DynamicPrintConfig& f BuildVolume build_volume(bedfs, print_height); unsigned int count = model->update_print_volume_state(build_volume); if (count == 0) { - error_message = "Nothing to be sliced, either the print is empty or no object is fully inside the print volume before apply."; + error_message = "Unable to calibrate: maybe because the set calibration value range is too large, or the step is too small"; return; } diff --git a/src/slic3r/Utils/CalibUtils.hpp b/src/slic3r/Utils/CalibUtils.hpp index 49e9048e7..aa92bde16 100644 --- a/src/slic3r/Utils/CalibUtils.hpp +++ b/src/slic3r/Utils/CalibUtils.hpp @@ -42,9 +42,11 @@ public: static bool get_flow_ratio_calib_results(std::vector &flow_ratio_calib_results); static void calib_flowrate(int pass, const CalibInfo& calib_info, std::string& error_message); + static void calib_generic_PA(const CalibInfo& calib_info, std::string &error_message); static void calib_temptue(const CalibInfo& calib_info, std::string& error_message); static void calib_max_vol_speed(const CalibInfo& calib_info, std::string& error_message); static void calib_VFA(const CalibInfo& calib_info, std::string& error_message); + static void calib_retraction(const CalibInfo &calib_info, std::string &error_message); private: static void process_and_store_3mf(Model* model, const DynamicPrintConfig& full_config, const Calib_Params& params, std::string& error_message);