mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-21 18:02:09 +00:00
Add "First layer fan speed" option (per filament) (#14270)
Implement First layer fan speed
This commit is contained in:
committed by
GitHub
parent
03568b5200
commit
3c8c667dbd
@@ -744,6 +744,13 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
int close_fan_the_first_x_layers = EXTRUDER_CONFIG(close_fan_the_first_x_layers);
|
||||
// Is the fan speed ramp enabled?
|
||||
int full_fan_speed_layer = EXTRUDER_CONFIG(full_fan_speed_layer);
|
||||
// ORCA: explicit per-filament first-layer override (-1 = disabled, 0-100 = forced PWM percent on layer 0).
|
||||
// The override is only honoured when the "No cooling for the first" gate is 0; otherwise the gate would
|
||||
// force layers 1..N-1 to zero while the override sets layer 0 to a non-zero value, which is confusing
|
||||
// and non-monotonic. The UI greys out and resets the value in that case, but we also guard here so
|
||||
// legacy profiles loaded with both set are neutralised at the slicer level.
|
||||
int initial_layer_fan_speed = EXTRUDER_CONFIG(initial_layer_fan_speed);
|
||||
const bool has_initial_layer_override = initial_layer_fan_speed >= 0 && close_fan_the_first_x_layers <= 0;
|
||||
supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed);
|
||||
|
||||
// ORCA: previously a silent override forced `close_fan_the_first_x_layers` from 0 up to 1 whenever a ramp
|
||||
@@ -751,7 +758,24 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
// That hid the user's literal "no cooling for the first 0 layers" setting and produced a non-zero starting
|
||||
// factor on the ramp denominator. The override has been removed: with N=0 and M>0 the ramp now genuinely
|
||||
// starts on layer 0 at a factor of 1/M and reaches 100% at layer M-1, matching the intent of the option.
|
||||
if (int(layer_id) >= close_fan_the_first_x_layers) {
|
||||
//
|
||||
// ORCA: First-layer hard override (`initial_layer_fan_speed`). When the user has set this option to a
|
||||
// value >= 0, layer 0 emits exactly that percentage so the entire first layer
|
||||
// is at one stable fan speed. The override wins over the `close_fan_the_first_x_layers` gate when
|
||||
// layer_id == 0. From layer 1 onwards the regular logic resumes.
|
||||
if (has_initial_layer_override && layer_id == 0) {
|
||||
fan_speed_new = initial_layer_fan_speed;
|
||||
overhang_fan_speed = initial_layer_fan_speed;
|
||||
overhang_fan_control = false;
|
||||
internal_bridge_fan_speed = initial_layer_fan_speed;
|
||||
internal_bridge_fan_control = false;
|
||||
supp_interface_fan_speed = initial_layer_fan_speed;
|
||||
supp_interface_fan_control = false;
|
||||
ironing_fan_speed = initial_layer_fan_speed;
|
||||
ironing_fan_control = false;
|
||||
// additional_fan_speed_new is left at its configured value (auxiliary fan is independent of the
|
||||
// part-cooling override).
|
||||
} else if (int(layer_id) >= close_fan_the_first_x_layers) {
|
||||
float fan_max_speed = EXTRUDER_CONFIG(fan_max_speed);
|
||||
float slow_down_layer_time = float(EXTRUDER_CONFIG(slow_down_layer_time));
|
||||
float fan_cooling_layer_time = float(EXTRUDER_CONFIG(fan_cooling_layer_time));
|
||||
@@ -769,10 +793,25 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
//}
|
||||
overhang_fan_speed = EXTRUDER_CONFIG(overhang_fan_speed);
|
||||
if (int(layer_id) >= close_fan_the_first_x_layers && int(layer_id) + 1 < full_fan_speed_layer) {
|
||||
// Ramp up the fan speed from close_fan_the_first_x_layers to full_fan_speed_layer.
|
||||
float factor = float(int(layer_id + 1) - close_fan_the_first_x_layers) / float(full_fan_speed_layer - close_fan_the_first_x_layers);
|
||||
fan_speed_new = std::clamp(int(float(fan_speed_new) * factor + 0.5f), 0, 255);
|
||||
overhang_fan_speed = std::clamp(int(float(overhang_fan_speed) * factor + 0.5f), 0, 255);
|
||||
if (has_initial_layer_override && close_fan_the_first_x_layers == 0 && full_fan_speed_layer > 1) {
|
||||
// ORCA: Option-B anchored ramp. When the first-layer override is configured and there's
|
||||
// no "no cooling" gate, the ramp interpolates linearly from `initial_layer_fan_speed` on
|
||||
// layer 0 up to the computed target on layer `full_fan_speed_layer - 1` instead of
|
||||
// scaling the target by `factor` from zero. Layer 0 itself is handled by the override
|
||||
// branch above; this branch only runs for layer_id >= 1, but the formula uses t = 0 at
|
||||
// layer 0 conceptually so the curve is continuous. Guarantees a monotonic transition
|
||||
// even when the override is larger than the natural 1/M starting value.
|
||||
const float anchor = float(initial_layer_fan_speed);
|
||||
const float denom = float(full_fan_speed_layer - 1);
|
||||
const float t = float(int(layer_id)) / denom;
|
||||
fan_speed_new = std::clamp(int(anchor + t * (float(fan_speed_new) - anchor) + 0.5f), 0, 255);
|
||||
overhang_fan_speed = std::clamp(int(anchor + t * (float(overhang_fan_speed) - anchor) + 0.5f), 0, 255);
|
||||
} else {
|
||||
// Ramp up the fan speed from close_fan_the_first_x_layers to full_fan_speed_layer.
|
||||
float factor = float(int(layer_id + 1) - close_fan_the_first_x_layers) / float(full_fan_speed_layer - close_fan_the_first_x_layers);
|
||||
fan_speed_new = std::clamp(int(float(fan_speed_new) * factor + 0.5f), 0, 255);
|
||||
overhang_fan_speed = std::clamp(int(float(overhang_fan_speed) * factor + 0.5f), 0, 255);
|
||||
}
|
||||
}
|
||||
supp_interface_fan_speed = EXTRUDER_CONFIG(support_material_interface_fan_speed);
|
||||
supp_interface_fan_control = supp_interface_fan_speed >= 0;
|
||||
|
||||
@@ -1318,7 +1318,7 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
|
||||
// "bed_type",
|
||||
//BBS:temperature_vitrification
|
||||
"temperature_vitrification", "reduce_fan_stop_start_freq","dont_slow_down_outer_wall", "slow_down_for_layer_cooling", "fan_min_speed",
|
||||
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "close_additional_fan_first_x_layers", "first_x_layer_fan_speed", "full_fan_speed_layer", "additional_fan_full_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
|
||||
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "close_additional_fan_first_x_layers", "first_x_layer_fan_speed", "full_fan_speed_layer", "initial_layer_fan_speed", "additional_fan_full_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
|
||||
"filament_start_gcode", "filament_end_gcode", "filament_change_extrusion_role_gcode",
|
||||
//exhaust fan control
|
||||
"activate_air_filtration","activate_air_filtration_during_print","activate_air_filtration_on_completion","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
|
||||
|
||||
@@ -134,6 +134,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|
||||
"dont_slow_down_outer_wall",
|
||||
"fan_cooling_layer_time",
|
||||
"full_fan_speed_layer",
|
||||
"initial_layer_fan_speed",
|
||||
"fan_kickstart",
|
||||
"part_cooling_fan_min_pwm",
|
||||
"fan_speedup_overhangs",
|
||||
|
||||
@@ -3348,7 +3348,25 @@ void PrintConfigDef::init_fff_params()
|
||||
def->max = 1000;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInts { 0 });
|
||||
|
||||
|
||||
// ORCA: explicit override for the part cooling fan speed on the first printed layer.
|
||||
def = this->add("initial_layer_fan_speed", coInts);
|
||||
def->label = L("First layer fan speed");
|
||||
def->tooltip = L("Sets an exact fan speed for the first layer, overriding all other cooling settings. "
|
||||
"Useful for protecting 3D-printed toolhead parts (e.g. Voron-style ABS/ASA ducts) from "
|
||||
"a hot bed. A small amount of airflow cools the ducts down, without using full cooling that "
|
||||
"may in certain conditions hurt first-layer adhesion."
|
||||
"\nFrom the second layer onwards, normal cooling resumes."
|
||||
"\nIf \"Full fan speed at layer\" is also set, the fan ramps smoothly from this value "
|
||||
"on the first layer up to your target by the chosen layer."
|
||||
"\nOnly available when \"No cooling for the first\" is 0."
|
||||
"\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("support_material_interface_fan_speed", coInts);
|
||||
def->label = L("Support interface fan speed");
|
||||
def->tooltip = L("This part cooling fan speed is applied when printing support interfaces. Setting this parameter to a higher than regular speed "
|
||||
|
||||
@@ -1555,6 +1555,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionFloatsNullable, initial_layer_infill_speed))
|
||||
((ConfigOptionInts, nozzle_temperature_initial_layer))
|
||||
((ConfigOptionInts, full_fan_speed_layer))
|
||||
// ORCA: explicit override for the part cooling fan speed on the first printed layer.
|
||||
((ConfigOptionInts, initial_layer_fan_speed))
|
||||
((ConfigOptionFloats, fan_max_speed))
|
||||
((ConfigOptionFloats, max_layer_height))
|
||||
((ConfigOptionFloats, fan_min_speed))
|
||||
|
||||
@@ -4368,6 +4368,8 @@ void TabFilament::build()
|
||||
//optgroup->append_line(line);
|
||||
optgroup = page->new_optgroup(L("Cooling for specific layer"), L"param_cooling_specific_layer");
|
||||
optgroup->append_single_option_line("close_fan_the_first_x_layers", "material_cooling#no-cooling-for-the-first");
|
||||
// ORCA: explicit override for the part cooling fan on layer 0; also anchors the ramp when "Full fan speed at layer" is set.
|
||||
optgroup->append_single_option_line("initial_layer_fan_speed", "material_cooling#first-layer-fan-speed");
|
||||
optgroup->append_single_option_line("full_fan_speed_layer", "material_cooling#full-fan-speed-at-layer");
|
||||
|
||||
optgroup = page->new_optgroup(L("Part cooling fan"), L"param_cooling_part_fan");
|
||||
@@ -4589,6 +4591,29 @@ void TabFilament::toggle_options()
|
||||
bool has_slow_down_for_layer_cooling = m_config->opt_bool("slow_down_for_layer_cooling", 0);
|
||||
toggle_option("dont_slow_down_outer_wall", has_slow_down_for_layer_cooling);
|
||||
|
||||
// ORCA: First layer fan speed override only makes sense when no layers are gated off ("No cooling for
|
||||
// the first" == 0). Otherwise the override would set layer 0 to a non-zero value while the gate forces
|
||||
// layers 1..N-1 to zero, producing a confusing non-monotonic profile. When the gate is active we both
|
||||
// grey out the UI line and force the underlying value to -1 so the cooling buffer never enters the
|
||||
// override branch.
|
||||
const int close_fan_first_n = m_config->opt_int("close_fan_the_first_x_layers", 0);
|
||||
const bool initial_layer_fan_speed_enabled = close_fan_first_n <= 0;
|
||||
toggle_line("initial_layer_fan_speed", initial_layer_fan_speed_enabled);
|
||||
if (!initial_layer_fan_speed_enabled) {
|
||||
if (auto* opt = dynamic_cast<const ConfigOptionInts*>(m_config->option("initial_layer_fan_speed"))) {
|
||||
bool needs_reset = false;
|
||||
for (int v : opt->values) {
|
||||
if (v != -1) { needs_reset = true; break; }
|
||||
}
|
||||
if (needs_reset) {
|
||||
std::vector<int> reset_values(opt->values.size(), -1);
|
||||
m_config->set_key_value("initial_layer_fan_speed", new ConfigOptionInts(reset_values));
|
||||
update_dirty();
|
||||
reload_config();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggle_line("additional_cooling_fan_speed", printer_cfg.opt_bool("auxiliary_fan"));
|
||||
|
||||
bool support_air_filtration = printer_cfg.opt_bool("support_air_filtration");
|
||||
|
||||
Reference in New Issue
Block a user