Implemented dynamic fan control. Cooling buffer does not yet relfect that
This commit is contained in:
parent
278f633a3d
commit
10d04529d6
@ -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<ProcessedPoint> new_points{};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds && !this->on_first_layer() && path.role().is_perimeter()) {
|
||||
std::vector<std::pair<int, ConfigOptionFloatOrPercent>> 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<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}};
|
||||
if (this->m_config.enable_dynamic_overhang_speeds) {
|
||||
std::vector<std::pair<int, ConfigOptionFloatOrPercent>> 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<std::pair<int, ConfigOptionInts>> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}};
|
||||
if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) {
|
||||
std::vector<std::pair<int, ConfigOptionInts>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<ProcessedPoint> estimate_extrusion_quality(const ExtrusionPath &path,
|
||||
const std::vector<std::pair<int, ConfigOptionFloatOrPercent>> overhangs_w_speeds,
|
||||
float ext_perimeter_speed,
|
||||
float original_speed)
|
||||
const std::vector<std::pair<int, ConfigOptionInts>> 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<std::pair<float, float>> speed_sections;
|
||||
float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed;
|
||||
std::map<float, float> 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<float, float> &a, const std::pair<float, float> &b) {
|
||||
if (a.first == b.first) {
|
||||
return a.second > b.second;
|
||||
}
|
||||
return a.first < b.first;
|
||||
});
|
||||
|
||||
std::pair<float, float> 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<float, float> 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<ExtendedPoint> 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<float, float> &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;
|
||||
}
|
||||
|
@ -440,7 +440,7 @@ static std::vector<std::string> 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<std::string> 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",
|
||||
|
@ -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",
|
||||
|
@ -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");
|
||||
|
@ -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))
|
||||
|
@ -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"
|
||||
|
@ -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")
|
||||
|
Loading…
Reference in New Issue
Block a user