From 10d04529d69de5a143060852ebe8dcde45784360 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Wed, 22 Feb 2023 18:59:54 +0100 Subject: [PATCH] Implemented dynamic fan control. Cooling buffer does not yet relfect that --- src/libslic3r/GCode.cpp | 52 +++++++++++---- src/libslic3r/GCode/ExtrusionProcessor.hpp | 71 ++++++++++----------- src/libslic3r/Preset.cpp | 5 +- src/libslic3r/Print.cpp | 5 ++ src/libslic3r/PrintConfig.cpp | 74 ++++++++++++++++------ src/libslic3r/PrintConfig.hpp | 6 +- src/libslic3r/PrintObject.cpp | 1 - src/slic3r/GUI/Tab.cpp | 13 +++- 8 files changed, 151 insertions(+), 76 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 34a252abd..b322be3b0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2868,19 +2868,37 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de ); } - bool variable_speed = false; + bool variable_speed_or_fan_speed = false; std::vector new_points{}; - if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && path.role().is_perimeter()) { - std::vector> overhangs_with_speeds{ - {0, m_config.overhang_speed_0}, {20, m_config.overhang_speed_1}, {40, m_config.overhang_speed_2}, - {60, m_config.overhang_speed_3}, {80, m_config.overhang_speed_4}, - }; + if ((this->m_config.enable_dynamic_overhang_speeds || this->config().enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) && + !this->on_first_layer() && path.role().is_perimeter()) { + std::vector> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}}; + if (this->m_config.enable_dynamic_overhang_speeds) { + std::vector> overhangs_with_speeds = {{0, m_config.overhang_speed_0}, + {25, m_config.overhang_speed_1}, + {50, m_config.overhang_speed_2}, + {75, m_config.overhang_speed_3}, + {100, + ConfigOptionFloatOrPercent{speed, false}}}; + } + + std::vector> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}}; + if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) { + std::vector> overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0}, + {25, m_config.overhang_fan_speed_1}, + {50, m_config.overhang_fan_speed_2}, + {75, m_config.overhang_fan_speed_3}, + {100, ConfigOptionInts{0}}}; + } + double external_perim_reference_speed = std::min(m_config.get_abs_value("external_perimeter_speed"), std::min(EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm, m_config.max_volumetric_speed.value / path.mm3_per_mm)); - new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhangs_with_speeds, external_perim_reference_speed, + new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path, overhangs_with_speeds, overhang_w_fan_speeds, + m_writer.extruder()->id(), external_perim_reference_speed, speed); - variable_speed = std::any_of(new_points.begin(), new_points.end(), [speed](const ProcessedPoint &p) { return p.speed != speed; }); + variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(), + [speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; }); } double F = speed * 60; // convert mm/sec to mm/min @@ -2944,7 +2962,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER"; } - if (!variable_speed) { + if (!variable_speed_or_fan_speed) { // F is mm per minute. gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments); double path_length = 0.; @@ -2969,20 +2987,26 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de marked_comment = description; marked_comment += description_bridge; } - double last_set_speed = new_points[0].speed * 60.0; + double last_set_speed = new_points[0].speed * 60.0; + double last_set_fan_speed = new_points[0].fan_speed; gcode += m_writer.set_speed(last_set_speed, "", cooling_marker_setspeed_comments); + gcode += m_writer.set_fan(last_set_fan_speed); Vec2d prev = this->point_to_gcode_quantized(new_points[0].p); for (size_t i = 1; i < new_points.size(); i++) { - const ProcessedPoint& processed_point = new_points[i]; - Vec2d p = this->point_to_gcode_quantized(processed_point.p); - const double line_length = (p - prev).norm(); + const ProcessedPoint &processed_point = new_points[i]; + Vec2d p = this->point_to_gcode_quantized(processed_point.p); + const double line_length = (p - prev).norm(); gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, marked_comment); - prev = p; + prev = p; double new_speed = processed_point.speed * 60.0; if (last_set_speed != new_speed) { gcode += m_writer.set_speed(new_speed, "", cooling_marker_setspeed_comments); last_set_speed = new_speed; } + if (last_set_fan_speed != processed_point.fan_speed) { + gcode += m_writer.set_fan(processed_point.fan_speed); + last_set_fan_speed = processed_point.fan_speed; + } } } diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index 066f1acd1..3273e31ff 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -238,6 +238,7 @@ struct ProcessedPoint { Point p; float speed = 1.0f; + int fan_speed = 0; }; class ExtrusionQualityEstimator @@ -259,31 +260,25 @@ public: std::vector estimate_extrusion_quality(const ExtrusionPath &path, const std::vector> overhangs_w_speeds, - float ext_perimeter_speed, - float original_speed) + const std::vector> overhangs_w_fan_speeds, + size_t extruder_id, + float ext_perimeter_speed, + float original_speed) { - float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed; - std::vector> speed_sections; + float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed; + std::map speed_sections; for (size_t i = 0; i < overhangs_w_speeds.size(); i++) { - float distance = path.width * (1.0 - (overhangs_w_speeds[i].first / 100.0)); - float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) : - overhangs_w_speeds[i].second.value; - speed_sections.push_back({distance, speed}); + float distance = path.width * (1.0 - (overhangs_w_speeds[i].first / 100.0)); + float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) : + overhangs_w_speeds[i].second.value; + speed_sections[distance] = speed; } - std::sort(speed_sections.begin(), speed_sections.end(), [](const std::pair &a, const std::pair &b) { - if (a.first == b.first) { - return a.second > b.second; - } - return a.first < b.first; - }); - std::pair last_section{INFINITY, 0}; - for (auto §ion : speed_sections) { - if (section.first == last_section.first) { - section.second = last_section.second; - } else { - last_section = section; - } + std::map fan_speed_sections; + for (size_t i = 0; i < overhangs_w_fan_speeds.size(); i++) { + float distance = path.width * (1.0 - (overhangs_w_fan_speeds[i].first / 100.0)); + float fan_speed = overhangs_w_fan_speeds[i].second.get_at(extruder_id); + fan_speed_sections[distance] = fan_speed; } std::vector extended_points = @@ -295,28 +290,26 @@ public: const ExtendedPoint &curr = extended_points[i]; const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i]; - auto calculate_speed = [&speed_sections, &original_speed](float distance) { - float final_speed; - if (distance <= speed_sections.front().first) { - final_speed = original_speed; - } else if (distance >= speed_sections.back().first) { - final_speed = speed_sections.back().second; - } else { - size_t section_idx = 0; - while (distance > speed_sections[section_idx + 1].first) { - section_idx++; - } - float t = (distance - speed_sections[section_idx].first) / - (speed_sections[section_idx + 1].first - speed_sections[section_idx].first); - t = std::clamp(t, 0.0f, 1.0f); - final_speed = (1.0f - t) * speed_sections[section_idx].second + t * speed_sections[section_idx + 1].second; + auto interpolate_speed = [](const std::map &values, float distance) { + auto upper_dist = values.lower_bound(distance); + if (upper_dist == values.end()) { + return values.rend()->second; } - return final_speed; + if (upper_dist == values.begin()) { + return upper_dist->second; + } + + auto lower_dist = --upper_dist; + float t = (distance - lower_dist->first) / (upper_dist->first - lower_dist->first); + return (1.0f - t) * lower_dist->second + t * upper_dist->second; }; - float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance)); + float extrusion_speed = std::min(interpolate_speed(speed_sections, curr.distance), + interpolate_speed(speed_sections, next.distance)); + float fan_speed = std::min(interpolate_speed(fan_speed_sections, curr.distance), + interpolate_speed(fan_speed_sections, next.distance)); - processed_points.push_back({scaled(curr.position), extrusion_speed}); + processed_points.push_back({scaled(curr.position), extrusion_speed, int(fan_speed)}); } return processed_points; } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 60c415cf6..e2fb57b17 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -440,7 +440,7 @@ static std::vector s_Preset_print_options { "fuzzy_skin", "fuzzy_skin_thickness", "fuzzy_skin_point_dist", "max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative", "perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed", - "enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3", "overhang_speed_4", + "enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", "external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", @@ -473,7 +473,8 @@ static std::vector s_Preset_filament_options { "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_minimal_purge_on_wipe_tower", "temperature", "idle_temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", - "start_filament_gcode", "end_filament_gcode", + "start_filament_gcode", "end_filament_gcode", "enable_dynamic_fan_speeds", + "overhang_fan_speed_0", "overhang_fan_speed_1", "overhang_fan_speed_2", "overhang_fan_speed_3", // Retract overrides "filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel", "filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 3c810b178..8d3ad0066 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -66,6 +66,11 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "between_objects_gcode", "bridge_acceleration", "bridge_fan_speed", + "enable_dynamic_fan_speeds", + "overhang_fan_speed_0", + "overhang_fan_speed_1", + "overhang_fan_speed_2", + "overhang_fan_speed_3", "colorprint_heights", "cooling", "default_acceleration", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6af343b38..87499261e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -535,7 +535,7 @@ void PrintConfigDef::init_fff_params() def->label = L("Enable dynamic overhang speeds"); def->category = L("Speed"); def->tooltip = L("This setting enables dynamic speed control on overhangs."); - def->mode = comAdvanced; + def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: " @@ -549,44 +549,82 @@ void PrintConfigDef::init_fff_params() def->tooltip = overhang_speed_setting_description; def->sidetext = L("mm/s or %"); def->min = 0; - def->mode = comAdvanced; + def->mode = comExpert; def->set_default_value(new ConfigOptionFloatOrPercent(15, false)); def = this->add("overhang_speed_1", coFloatOrPercent); - def->label = L("speed for 20\% overlap"); + def->label = L("speed for 25\% overlap"); def->category = L("Speed"); def->tooltip = overhang_speed_setting_description; def->sidetext = L("mm/s or %"); def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(20, false)); + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloatOrPercent(15, false)); def = this->add("overhang_speed_2", coFloatOrPercent); - def->label = L("speed for 40\% overlap"); + def->label = L("speed for 50\% overlap"); def->category = L("Speed"); def->tooltip = overhang_speed_setting_description; def->sidetext = L("mm/s or %"); def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(25, false)); + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloatOrPercent(20, false)); def = this->add("overhang_speed_3", coFloatOrPercent); - def->label = L("speed for 60\% overlap"); + def->label = L("speed for 75\% overlap"); def->category = L("Speed"); def->tooltip = overhang_speed_setting_description; def->sidetext = L("mm/s or %"); def->min = 0; - def->mode = comAdvanced; + def->mode = comExpert; def->set_default_value(new ConfigOptionFloatOrPercent(25, false)); - def = this->add("overhang_speed_4", coFloatOrPercent); - def->label = L("speed for 80\% overlap"); - def->category = L("Speed"); - def->tooltip = overhang_speed_setting_description; - def->sidetext = L("mm/s or %"); - def->min = 0; - def->mode = comAdvanced; - def->set_default_value(new ConfigOptionFloatOrPercent(25, false)); + def = this->add("enable_dynamic_fan_speeds", coBools); + def->label = L("Enable dynamic fan speeds"); + def->tooltip = L("This setting enables dynamic fan speed control on overhangs."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBools{false}); + + auto fan_speed_setting_description = L( + "Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: " + "100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). " + "Fan speeds for overhang sizes in between are calculated via linear interpolation. "); + + def = this->add("overhang_fan_speed_0", coInts); + def->label = L("speed for 0\% overlap (bridge)"); + def->tooltip = fan_speed_setting_description; + def->sidetext = L("%"); + def->min = 0; + def->max = 100; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts{100}); + + def = this->add("overhang_fan_speed_1", coInts); + def->label = L("speed for 25\% overlap"); + def->tooltip = fan_speed_setting_description; + def->sidetext = L("%"); + def->min = 0; + def->max = 100; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts{75}); + + def = this->add("overhang_fan_speed_2", coInts); + def->label = L("speed for 50\% overlap"); + def->tooltip = fan_speed_setting_description; + def->sidetext = L("%"); + def->min = 0; + def->max = 100; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts{50}); + + def = this->add("overhang_fan_speed_3", coInts); + def->label = L("speed for 75\% overlap"); + def->tooltip = fan_speed_setting_description; + def->sidetext = L("%"); + def->min = 0; + def->max = 100; + def->mode = comExpert; + def->set_default_value(new ConfigOptionInts{25}); def = this->add("brim_width", coFloat); def->label = L("Brim width"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index d7889fa01..dde60bee4 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -577,7 +577,6 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionFloatOrPercent, overhang_speed_1)) ((ConfigOptionFloatOrPercent, overhang_speed_2)) ((ConfigOptionFloatOrPercent, overhang_speed_3)) - ((ConfigOptionFloatOrPercent, overhang_speed_4)) ((ConfigOptionBool, external_perimeters_first)) ((ConfigOptionBool, extra_perimeters)) ((ConfigOptionBool, extra_perimeters_on_overhangs)) @@ -750,6 +749,11 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionInts, bed_temperature)) ((ConfigOptionFloat, bridge_acceleration)) ((ConfigOptionInts, bridge_fan_speed)) + ((ConfigOptionBools, enable_dynamic_fan_speeds)) + ((ConfigOptionInts, overhang_fan_speed_0)) + ((ConfigOptionInts, overhang_fan_speed_1)) + ((ConfigOptionInts, overhang_fan_speed_2)) + ((ConfigOptionInts, overhang_fan_speed_3)) ((ConfigOptionBool, complete_objects)) ((ConfigOptionFloats, colorprint_heights)) ((ConfigOptionBools, cooling)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index ad48efb6d..c12eeea82 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -769,7 +769,6 @@ bool PrintObject::invalidate_state_by_config_options( || opt_key == "overhang_speed_1" || opt_key == "overhang_speed_2" || opt_key == "overhang_speed_3" - || opt_key == "overhang_speed_4" || opt_key == "external_perimeter_speed" || opt_key == "infill_speed" || opt_key == "perimeter_speed" diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 2d556471c..ae9bb175f 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1554,7 +1554,6 @@ void TabPrint::build() optgroup->append_single_option_line("overhang_speed_1"); optgroup->append_single_option_line("overhang_speed_2"); optgroup->append_single_option_line("overhang_speed_3"); - optgroup->append_single_option_line("overhang_speed_4"); optgroup = page->new_optgroup(L("Speed for non-print moves")); optgroup->append_single_option_line("travel_speed"); @@ -1988,6 +1987,13 @@ void TabFilament::build() optgroup->append_single_option_line("disable_fan_first_layers", category_path + "fan-settings"); optgroup->append_single_option_line("full_fan_speed_layer", category_path + "fan-settings"); + optgroup = page->new_optgroup(L("Dynamic fan speeds"), 25); + optgroup->append_single_option_line("enable_dynamic_fan_speeds", category_path + "dynamic-fan-speeds"); + optgroup->append_single_option_line("overhang_fan_speed_0", category_path + "dynamic-fan-speeds"); + optgroup->append_single_option_line("overhang_fan_speed_1", category_path + "dynamic-fan-speeds"); + optgroup->append_single_option_line("overhang_fan_speed_2", category_path + "dynamic-fan-speeds"); + optgroup->append_single_option_line("overhang_fan_speed_3", category_path + "dynamic-fan-speeds"); + optgroup = page->new_optgroup(L("Cooling thresholds"), 25); optgroup->append_single_option_line("fan_below_layer_time", category_path + "cooling-thresholds"); optgroup->append_single_option_line("slowdown_below_layer_time", category_path + "cooling-thresholds"); @@ -2140,6 +2146,11 @@ void TabFilament::toggle_options() for (auto el : { "min_fan_speed", "disable_fan_first_layers", "full_fan_speed_layer" }) toggle_option(el, fan_always_on); + + bool dynamic_fan_speeds = m_config->opt_bool("enable_dynamic_fan_speeds", 0); + for (int i = 0; i < 4; i++) { + toggle_option("overhang_fan_speed_"+std::to_string(i),dynamic_fan_speeds); + } } if (m_active_page->title() == "Filament Overrides")