From c00502638c920b7575cd8af72c8871e5bb5663d6 Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Fri, 18 Jul 2025 16:01:15 +0800 Subject: [PATCH] Add ironing fan speed control (#9944) * Internal bridge fan speed should be applied only if overhang bridge fan control is enabled * Reduce duplicate code * Add ironing fan speed control --- src/libslic3r/GCode.cpp | 121 ++++++++++---------------- src/libslic3r/GCode.hpp | 6 +- src/libslic3r/GCode/CoolingBuffer.cpp | 41 ++++++++- src/libslic3r/Preset.cpp | 1 + src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 11 +++ src/libslic3r/PrintConfig.hpp | 1 + src/slic3r/GUI/Tab.cpp | 1 + 8 files changed, 101 insertions(+), 82 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d1f881c702..9f0c236437 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1839,9 +1839,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato m_last_layer_z = 0.f; m_max_layer_z = 0.f; m_last_width = 0.f; - m_is_overhang_fan_on = false; - m_is_internal_bridge_fan_on = false; - m_is_supp_interface_fan_on = false; + m_is_role_based_fan_on.fill(false); #if ENABLE_GCODE_VIEWER_DATA_CHECKING m_last_mm3_per_mm = 0.; #endif // ENABLE_GCODE_VIEWER_DATA_CHECKING @@ -5602,9 +5600,6 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, auto overhang_fan_threshold = EXTRUDER_CONFIG(overhang_fan_threshold); auto enable_overhang_bridge_fan = EXTRUDER_CONFIG(enable_overhang_bridge_fan); - - auto supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed); - // { "0%", Overhang_threshold_none }, // { "10%", Overhang_threshold_1_4 }, @@ -5647,6 +5642,37 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, comment += ";_EXTERNAL_PERIMETER"; } + // Change fan speed based on current extrusion role + auto append_role_based_fan_marker = [this, &gcode](const ExtrusionRole role, const std::string_view& marker_prefix, const bool fan_on) { + assert(m_enable_cooling_markers); + + if (fan_on) { + if (!m_is_role_based_fan_on[role]) { + gcode += ";"; + gcode += marker_prefix; + gcode += "_FAN_START\n"; + m_is_role_based_fan_on[role] = true; + } + } else { + if (m_is_role_based_fan_on[role]) { + gcode += ";"; + gcode += marker_prefix; + gcode += "_FAN_END\n"; + m_is_role_based_fan_on[role] = false; + } + } + }; + auto apply_role_based_fan_speed = [ + &path, &append_role_based_fan_marker, + supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed), + ironing_fan_speed = EXTRUDER_CONFIG(ironing_fan_speed) + ] { + append_role_based_fan_marker(erSupportMaterialInterface, "_SUPP_INTERFACE"sv, + supp_interface_fan_speed >= 0 && path.role() == erSupportMaterialInterface); + append_role_based_fan_marker(erIroning, "_IRONING"sv, + ironing_fan_speed >= 0 && path.role() == erIroning); + }; + if (!variable_speed) { // F is mm per minute. if( (std::abs(writer().get_current_speed() - F) > EPSILON) || (std::abs(_mm3_per_mm - m_last_mm3_mm) > EPSILON) ){ @@ -5703,41 +5729,15 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (enable_overhang_bridge_fan) { // BBS: Overhang_threshold_none means Overhang_threshold_1_4 and forcing cooling for all external // perimeter - if ((overhang_fan_threshold == Overhang_threshold_none && is_external_perimeter(path.role())) || - (path.role() == erBridgeInfill || path.role() == erOverhangPerimeter)) { // ORCA: Add support for separate internal bridge fan speed control - if (!m_is_overhang_fan_on) { - gcode += ";_OVERHANG_FAN_START\n"; - m_is_overhang_fan_on = true; - } - } else { - if (m_is_overhang_fan_on) { - m_is_overhang_fan_on = false; - gcode += ";_OVERHANG_FAN_END\n"; - } - } - if (path.role() == erInternalBridgeInfill) { // ORCA: Add support for separate internal bridge fan speed control - if (!m_is_internal_bridge_fan_on) { - gcode += ";_INTERNAL_BRIDGE_FAN_START\n"; - m_is_internal_bridge_fan_on = true; - } - } else { - if (m_is_internal_bridge_fan_on) { - m_is_internal_bridge_fan_on = false; - gcode += ";_INTERNAL_BRIDGE_FAN_END\n"; - } - } - } - if (supp_interface_fan_speed >= 0 && path.role() == erSupportMaterialInterface) { - if (!m_is_supp_interface_fan_on) { - gcode += ";_SUPP_INTERFACE_FAN_START\n"; - m_is_supp_interface_fan_on = true; - } - } else { - if (m_is_supp_interface_fan_on) { - gcode += ";_SUPP_INTERFACE_FAN_END\n"; - m_is_supp_interface_fan_on = false; - } + append_role_based_fan_marker(erOverhangPerimeter, "_OVERHANG"sv, + (overhang_fan_threshold == Overhang_threshold_none && is_external_perimeter(path.role())) || + (path.role() == erBridgeInfill || path.role() == erOverhangPerimeter)); // ORCA: Add support for separate internal bridge fan speed control + + // ORCA: Add support for separate internal bridge fan speed control + append_role_based_fan_marker(erInternalBridgeInfill, "_INTERNAL_BRIDGE"sv, path.role() == erInternalBridgeInfill); } + + apply_role_based_fan_speed(); } // BBS: use G1 if not enable arc fitting or has no arc fitting result or in spiral_mode mode or we are doing sloped extrusion // Attention: G2 and G3 is not supported in spiral_mode mode @@ -5870,43 +5870,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, if (m_enable_cooling_markers) { if (enable_overhang_bridge_fan) { cur_fan_enabled = check_overhang_fan(processed_point.overlap, path.role()); - if (pre_fan_enabled && cur_fan_enabled) { - if (!m_is_overhang_fan_on) { - gcode += ";_OVERHANG_FAN_START\n"; - m_is_overhang_fan_on = true; - } - } else { - if (m_is_overhang_fan_on) { - m_is_overhang_fan_on = false; - gcode += ";_OVERHANG_FAN_END\n"; - } - } + append_role_based_fan_marker(erOverhangPerimeter, "_OVERHANG"sv, pre_fan_enabled && cur_fan_enabled); pre_fan_enabled = cur_fan_enabled; + + // ORCA: Add support for separate internal bridge fan speed control + append_role_based_fan_marker(erInternalBridgeInfill, "_INTERNAL_BRIDGE"sv, path.role() == erInternalBridgeInfill); } - // ORCA: Add support for separate internal bridge fan speed control - if (path.role() == erInternalBridgeInfill) { - if (!m_is_internal_bridge_fan_on) { - gcode += ";_INTERNAL_BRIDGE_FAN_START\n"; - m_is_internal_bridge_fan_on = true; - } - } else { - if (m_is_internal_bridge_fan_on) { - gcode += ";_INTERNAL_BRIDGE_FAN_END\n"; - m_is_internal_bridge_fan_on = false; - } - } - - if (supp_interface_fan_speed >= 0 && path.role() == erSupportMaterialInterface) { - if (!m_is_supp_interface_fan_on) { - gcode += ";_SUPP_INTERFACE_FAN_START\n"; - m_is_supp_interface_fan_on = true; - } - } else { - if (m_is_supp_interface_fan_on) { - gcode += ";_SUPP_INTERFACE_FAN_END\n"; - m_is_supp_interface_fan_on = false; - } - } + + apply_role_based_fan_speed(); } const double line_length = (p - prev).norm(); diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index d02b751d0d..f3ce7aaf74 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -517,10 +517,8 @@ private: bool m_enable_exclude_object; std::vector m_label_objects_ids; std::string _encode_label_ids_to_base64(std::vector ids); - // Orca - bool m_is_overhang_fan_on; - bool m_is_internal_bridge_fan_on; // ORCA: Add support for separate internal bridge fan speed control - bool m_is_supp_interface_fan_on; + // ORCA: Add support for role based fan speed control + std::array m_is_role_based_fan_on; // Markers for the Pressure Equalizer to recognize the extrusion type. // The Pressure Equalizer removes the markers from the final G-code. bool m_enable_extrusion_role_markers; diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 194afe9b1b..9541d68034 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -66,8 +66,11 @@ struct CoolingLine TYPE_SUPPORT_INTERFACE_FAN_START = 1 << 15, TYPE_SUPPORT_INTERFACE_FAN_END = 1 << 16, // ORCA: Add support for separate internal bridge fan speed control - TYPE_INTERNAL_BRIDGE_FAN_START = 1 << 17, - TYPE_INTERNAL_BRIDGE_FAN_END = 1 << 18, + TYPE_INTERNAL_BRIDGE_FAN_START = 1 << 17, + TYPE_INTERNAL_BRIDGE_FAN_END = 1 << 18, + // ORCA: Add support for ironing fan speed control + TYPE_IRONING_FAN_START = 1 << 19, + TYPE_IRONING_FAN_END = 1 << 20, }; CoolingLine(unsigned int type, size_t line_start, size_t line_end) : @@ -522,6 +525,10 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: line.type = CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START; } else if (boost::starts_with(sline, ";_SUPP_INTERFACE_FAN_END")) { line.type = CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_END; + } else if (boost::starts_with(sline, ";_IRONING_FAN_START")) { // ORCA: Add support for ironing fan speed control + line.type = CoolingLine::TYPE_IRONING_FAN_START; + } else if (boost::starts_with(sline, ";_IRONING_FAN_END")) { // ORCA: Add support for ironing fan speed control + line.type = CoolingLine::TYPE_IRONING_FAN_END; } else if (boost::starts_with(sline, "G4 ")) { // Parse the wait time. line.type = CoolingLine::TYPE_G4; @@ -716,7 +723,14 @@ std::string CoolingBuffer::apply_layer_cooldown( int internal_bridge_fan_speed = 0; // ORCA: Add support for separate internal bridge fan speed control bool supp_interface_fan_control= false; int supp_interface_fan_speed = 0; - auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, &overhang_fan_control, &overhang_fan_speed, &internal_bridge_fan_control, &internal_bridge_fan_speed, &supp_interface_fan_control, &supp_interface_fan_speed](bool immediately_apply) { + bool ironing_fan_control= false; // ORCA: Add support for ironing fan speed control + int ironing_fan_speed = 0; // ORCA: Add support for ironing fan speed control + auto change_extruder_set_fan = [ this, layer_id, layer_time, &new_gcode, + &overhang_fan_control, &overhang_fan_speed, + &internal_bridge_fan_control, &internal_bridge_fan_speed, + &supp_interface_fan_control, &supp_interface_fan_speed, + &ironing_fan_control, &ironing_fan_speed + ](bool immediately_apply) { #define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_current_extruder) float fan_min_speed = EXTRUDER_CONFIG(fan_min_speed); float fan_speed_new = EXTRUDER_CONFIG(reduce_fan_stop_start_freq) ? fan_min_speed : 0; @@ -768,6 +782,10 @@ std::string CoolingBuffer::apply_layer_cooldown( internal_bridge_fan_speed = overhang_fan_speed; internal_bridge_fan_control = overhang_fan_control; } + + // ORCA: Add support for ironing fan speed control + ironing_fan_speed = EXTRUDER_CONFIG(ironing_fan_speed); + ironing_fan_control = ironing_fan_speed >= 0; #undef EXTRUDER_CONFIG } else { @@ -779,6 +797,8 @@ std::string CoolingBuffer::apply_layer_cooldown( supp_interface_fan_speed = 0; internal_bridge_fan_control = false; // ORCA: Add support for separate internal bridge fan speed control internal_bridge_fan_speed = 0; // ORCA: Add support for separate internal bridge fan speed control + ironing_fan_control = false; // ORCA: Add support for ironing fan speed control + ironing_fan_speed = 0; // ORCA: Add support for ironing fan speed control } if (fan_speed_new != m_fan_speed) { m_fan_speed = fan_speed_new; @@ -803,6 +823,7 @@ std::string CoolingBuffer::apply_layer_cooldown( std::unordered_map fan_speed_change_requests = {{CoolingLine::TYPE_OVERHANG_FAN_START, false}, {CoolingLine::TYPE_INTERNAL_BRIDGE_FAN_START, false}, // ORCA: Add support for separate internal bridge fan speed control {CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START, false}, + {CoolingLine::TYPE_IRONING_FAN_START, false}, // ORCA: Add support for ironing fan speed control {CoolingLine::TYPE_FORCE_RESUME_FAN, false}}; bool need_set_fan = false; @@ -851,6 +872,16 @@ std::string CoolingBuffer::apply_layer_cooldown( fan_speed_change_requests[CoolingLine::TYPE_SUPPORT_INTERFACE_FAN_START] = false; } need_set_fan = true; + } else if (line->type & CoolingLine::TYPE_IRONING_FAN_START) { + if (ironing_fan_control && !fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]) { + fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START] = true; + need_set_fan = true; + } + } else if (line->type & CoolingLine::TYPE_IRONING_FAN_END && fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]) { + if (ironing_fan_control) { + fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START] = false; + } + need_set_fan = true; } else if (line->type & CoolingLine::TYPE_FORCE_RESUME_FAN) { // check if any fan speed change request is active if (m_fan_speed != -1 && !std::any_of(fan_speed_change_requests.begin(), fan_speed_change_requests.end(), [](const std::pair& p) { return p.second; })){ @@ -957,6 +988,10 @@ std::string CoolingBuffer::apply_layer_cooldown( new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, supp_interface_fan_speed); m_current_fan_speed = supp_interface_fan_speed; } + else if (fan_speed_change_requests[CoolingLine::TYPE_IRONING_FAN_START]){ + new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, ironing_fan_speed); + m_current_fan_speed = ironing_fan_speed; + } else if(fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] && m_current_fan_speed != -1){ new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed); fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 35ee46b27d..3ee5733929 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -866,6 +866,7 @@ static std::vector s_Preset_filament_options { "nozzle_temperature_range_low", "nozzle_temperature_range_high", //SoftFever "enable_pressure_advance", "pressure_advance","adaptive_pressure_advance","adaptive_pressure_advance_model","adaptive_pressure_advance_overhangs", "adaptive_pressure_advance_bridges","chamber_temperature", "filament_shrink","filament_shrinkage_compensation_z", "support_material_interface_fan_speed","internal_bridge_fan_speed", "filament_notes" /*,"filament_seam_gap"*/, + "ironing_fan_speed", "filament_loading_speed", "filament_loading_speed_start", "filament_unloading_speed", "filament_unloading_speed_start", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index ae2b420049..858fa32053 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -193,6 +193,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "exclude_object", "support_material_interface_fan_speed", "internal_bridge_fan_speed", // ORCA: Add support for separate internal bridge fan speed control + "ironing_fan_speed", "single_extruder_multi_material_priming", "activate_air_filtration", "during_print_exhaust_fan_speed", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 721475fa92..2b4f53af69 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2770,6 +2770,17 @@ void PrintConfigDef::init_fff_params() def->max = 100; def->mode = comAdvanced; def->set_default_value(new ConfigOptionInts{ -1 }); + + def = this->add("ironing_fan_speed", coInts); + def->label = L("Ironing fan speed"); + def->tooltip = L("This part cooling fan speed is applied when ironing. Setting this parameter to a lower than regular speed " + "reduces possible nozzle clogging due to the low volumetric flow rate, making the interface smoother." + "\nSet to -1 to disable it."); + def->sidetext = "%"; + def->min = -1; + def->max = 100; + def->mode = comAdvanced; + def->set_default_value(new ConfigOptionInts{ -1 }); def = this->add("fuzzy_skin", coEnum); def->label = L("Fuzzy Skin"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index de981319d2..f09a1b5e49 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1396,6 +1396,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionInt, slow_down_layers)) ((ConfigOptionInts, support_material_interface_fan_speed)) ((ConfigOptionInts, internal_bridge_fan_speed)) // ORCA: Add support for separate internal bridge fan speed control + ((ConfigOptionInts, ironing_fan_speed)) // Orca: notes for profiles from PrusaSlicer ((ConfigOptionStrings, filament_notes)) ((ConfigOptionString, notes)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index aa4a5a13fc..9821add07a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -3549,6 +3549,7 @@ void TabFilament::build() optgroup->append_single_option_line("overhang_fan_speed", "auto-cooling"); optgroup->append_single_option_line("internal_bridge_fan_speed"); // ORCA: Add support for separate internal bridge fan speed control optgroup->append_single_option_line("support_material_interface_fan_speed"); + optgroup->append_single_option_line("ironing_fan_speed"); // ORCA: Add support for ironing fan speed control optgroup = page->new_optgroup(L("Auxiliary part cooling fan"), L"param_cooling_aux_fan"); optgroup->append_single_option_line("additional_cooling_fan_speed", "auxiliary-fan");