From 55fdc665caf836bf0d4134093cbf28a468dd871e Mon Sep 17 00:00:00 2001 From: supermerill Date: Mon, 23 Aug 2021 00:38:28 +0200 Subject: [PATCH] max_gcode_per_second added allow a better control than min_length --- resources/ui_layout/printer_fff.ui | 5 +- src/libslic3r/GCode.cpp | 204 +++++++++++++++-------------- src/libslic3r/GCode.hpp | 1 + src/libslic3r/Preset.cpp | 1 + src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 16 ++- src/libslic3r/PrintConfig.hpp | 2 + 7 files changed, 131 insertions(+), 99 deletions(-) diff --git a/resources/ui_layout/printer_fff.ui b/resources/ui_layout/printer_fff.ui index c5d4cd6d2..a31081912 100644 --- a/resources/ui_layout/printer_fff.ui +++ b/resources/ui_layout/printer_fff.ui @@ -19,6 +19,10 @@ group:silent_mode_event:Firmware setting:gcode_precision_xyz setting:gcode_precision_e end_line + line:Processing limit + setting:max_gcode_per_second + setting:min_length + end_line group:Cooling fan line:Speedup setting:label$Speedup time:fan_speedup_time @@ -40,7 +44,6 @@ group:Advanced setting:use_relative_e_distances setting:use_firmware_retraction setting:use_volumetric_e - setting:min_length setting:variable_layer_height page:Custom G-code:cog diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d18d483fe..7391555fa 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3366,14 +3366,19 @@ void GCode::use(const ExtrusionEntityCollection &collection) { } } -std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed) { +std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &description, double speed_mm_per_sec) { ExtrusionPath simplifed_path = path; const double scaled_min_length = scale_(this->config().min_length.value); - if (scaled_min_length > 0 && !m_last_too_small.empty()) { + const double max_gcode_per_second = this->config().max_gcode_per_second.value; + double current_scaled_min_length = scaled_min_length; + if (max_gcode_per_second > 0) { + current_scaled_min_length = std::max(current_scaled_min_length, scale_(_compute_speed_mm_per_sec(path, speed_mm_per_sec)) / max_gcode_per_second); + } + if (current_scaled_min_length > 0 && !m_last_too_small.empty()) { //descr += " trys fusion " + std::to_string(unscaled(m_last_too_small.last_point().x())) + " , " + std::to_string(unscaled(path.first_point().x())); //ensure that it's a continous thing - if (m_last_too_small.last_point().distance_to_square(path.first_point()) < scaled_min_length*scaled_min_length /*&& m_last_too_small.first_point().distance_to_square(path.first_point()) > EPSILON*/) { + if (m_last_too_small.last_point().distance_to_square(path.first_point()) < current_scaled_min_length * current_scaled_min_length /*&& m_last_too_small.first_point().distance_to_square(path.first_point()) > EPSILON*/) { //descr += " ! fusion " + std::to_string(simplifed_path.polyline.points.size()); simplifed_path.height = (m_last_too_small.height * m_last_too_small.length() + simplifed_path.height * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length()); simplifed_path.mm3_per_mm = (m_last_too_small.mm3_per_mm * m_last_too_small.length() + simplifed_path.mm3_per_mm * simplifed_path.length()) / (m_last_too_small.length() + simplifed_path.length()); @@ -3383,11 +3388,11 @@ std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &de } m_last_too_small.polyline.points.clear(); } - if (scaled_min_length > 0) { + if (current_scaled_min_length > 0) { // it's an alternative to simplifed_path.simplify(scale_(this->config().min_length)); with more enphasis ont he segment length that on the feature detail. // because tolerance = min_length /10, douglas_peucker will erase more points if angles are shallower than 6° and then the '_plus' will kick in to keep a bit more. // if angles are all bigger than 6°, then the douglas_peucker will do all the work. - simplifed_path.polyline.points = MultiPoint::_douglas_peucker_plus(simplifed_path.polyline.points, scaled_min_length / 10, scaled_min_length); + simplifed_path.polyline.points = MultiPoint::_douglas_peucker_plus(simplifed_path.polyline.points, current_scaled_min_length / 10, current_scaled_min_length); } //else simplifed_path.simplify(SCALED_RESOLUTION); //should already be simplified if (scaled_min_length > 0 && simplifed_path.length() < scaled_min_length) { @@ -3395,7 +3400,7 @@ std::string GCode::extrude_path(const ExtrusionPath &path, const std::string &de return ""; } - std::string gcode = this->_extrude(simplifed_path, description, speed); + std::string gcode = this->_extrude(simplifed_path, description, speed_mm_per_sec); if (m_wipe.enable) { m_wipe.path = std::move(simplifed_path.polyline); @@ -3737,6 +3742,102 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string &descri return gcode; } +double_t GCode::_compute_speed_mm_per_sec(const ExtrusionPath& path, double speed) { + + // set speed + if (speed < 0) { + //if speed == -1, then it's means "choose yourself, but if it's -1 < speed <0 , then it's a scaling from small_periemter. + //it's a bit hacky, so if you want to rework it, help yourself. + float factor = (-speed); + if (path.role() == erPerimeter) { + speed = m_config.get_abs_value("perimeter_speed"); + } else if (path.role() == erExternalPerimeter) { + speed = m_config.get_abs_value("external_perimeter_speed"); + } else if (path.role() == erBridgeInfill) { + speed = m_config.get_abs_value("bridge_speed"); + } else if (path.role() == erInternalBridgeInfill) { + speed = m_config.get_abs_value("bridge_speed_internal"); + } else if (path.role() == erOverhangPerimeter) { + speed = m_config.get_abs_value("overhangs_speed"); + } else if (path.role() == erInternalInfill) { + speed = m_config.get_abs_value("infill_speed"); + } else if (path.role() == erSolidInfill) { + speed = m_config.get_abs_value("solid_infill_speed"); + } else if (path.role() == erTopSolidInfill) { + speed = m_config.get_abs_value("top_solid_infill_speed"); + } else if (path.role() == erThinWall) { + speed = m_config.get_abs_value("thin_walls_speed"); + } else if (path.role() == erGapFill) { + speed = m_config.get_abs_value("gap_fill_speed"); + } else if (path.role() == erIroning) { + speed = m_config.get_abs_value("ironing_speed"); + } else if (path.role() == erNone) { + speed = m_config.get_abs_value("travel_speed"); + } else if (path.role() == erMilling) { + speed = m_config.get_abs_value("milling_speed"); + } else { + throw Slic3r::InvalidArgument("Invalid speed"); + } + //don't modify bridge speed + if (factor < 1 && !(is_bridge(path.role()))) { + float small_speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); + //apply factor between feature speed and small speed + speed = (speed * factor) + double((1.f - factor) * small_speed); + } + } + if (m_volumetric_speed != 0. && speed == 0) { + //if m_volumetric_speed, use the max size for thinwall & gapfill, to avoid variations + double vol_speed = m_volumetric_speed / path.mm3_per_mm; + if (vol_speed > m_config.max_print_speed.value) + vol_speed = m_config.max_print_speed.value; + // if using a % of an auto speed, use the % over the volumetric speed. + if (path.role() == erExternalPerimeter) { + speed = m_config.external_perimeter_speed.get_abs_value(vol_speed); + } else if (path.role() == erInternalBridgeInfill) { + speed = m_config.bridge_speed_internal.get_abs_value(vol_speed); + } else if (path.role() == erOverhangPerimeter) { + speed = m_config.overhangs_speed.get_abs_value(vol_speed); + } else if (path.role() == erSolidInfill) { + speed = m_config.solid_infill_speed.get_abs_value(vol_speed); + } else if (path.role() == erTopSolidInfill) { + speed = m_config.top_solid_infill_speed.get_abs_value(vol_speed); + } + if (speed == 0) { + speed = vol_speed; + } + } + if (speed == 0) // this code shouldn't trigger as if it's 0, you have to get a m_volumetric_speed + speed = m_config.max_print_speed.value; + if (this->on_first_layer()) { + const double base_speed = speed; + if (path.role() == erInternalInfill || path.role() == erSolidInfill) { + double first_layer_infill_speed = m_config.first_layer_infill_speed.get_abs_value(base_speed); + if (first_layer_infill_speed > 0) + speed = std::min(first_layer_infill_speed, speed); + } else { + double first_layer_speed = m_config.first_layer_speed.get_abs_value(base_speed); + if (first_layer_speed > 0) + speed = std::min(first_layer_speed, speed); + } + double first_layer_min_speed = m_config.first_layer_min_speed.get_abs_value(base_speed); + speed = std::max(first_layer_min_speed, speed); + } + // cap speed with max_volumetric_speed anyway (even if user is not using autospeed) + if (m_config.max_volumetric_speed.value > 0 && path.mm3_per_mm > 0) { + speed = std::min(m_config.max_volumetric_speed.value / path.mm3_per_mm, speed); + } + double filament_max_volumetric_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_volumetric_speed, 0); + if (filament_max_volumetric_speed > 0) { + speed = std::min(filament_max_volumetric_speed / path.mm3_per_mm, speed); + } + double filament_max_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_speed, 0); + if (filament_max_speed > 0) { + speed = std::min(filament_max_speed, speed); + } + + return speed; +} + std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string &description_in, double speed) { std::string gcode; std::string description{ description_in }; @@ -3813,96 +3914,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string // compensate retraction gcode += this->unretract(); - // set speed - if (speed < 0) { - //if speed == -1, then it's means "choose yourself, but if it's -1 < speed <0 , then it's a scaling from small_periemter. - //it's a bit hacky, so if you want to rework it, help yourself. - float factor = (-speed); - if (path.role() == erPerimeter) { - speed = m_config.get_abs_value("perimeter_speed"); - } else if (path.role() == erExternalPerimeter) { - speed = m_config.get_abs_value("external_perimeter_speed"); - } else if (path.role() == erBridgeInfill) { - speed = m_config.get_abs_value("bridge_speed"); - } else if (path.role() == erInternalBridgeInfill) { - speed = m_config.get_abs_value("bridge_speed_internal"); - } else if (path.role() == erOverhangPerimeter) { - speed = m_config.get_abs_value("overhangs_speed"); - } else if (path.role() == erInternalInfill) { - speed = m_config.get_abs_value("infill_speed"); - } else if (path.role() == erSolidInfill) { - speed = m_config.get_abs_value("solid_infill_speed"); - } else if (path.role() == erTopSolidInfill) { - speed = m_config.get_abs_value("top_solid_infill_speed"); - } else if (path.role() == erThinWall) { - speed = m_config.get_abs_value("thin_walls_speed"); - } else if (path.role() == erGapFill) { - speed = m_config.get_abs_value("gap_fill_speed"); - } else if (path.role() == erIroning) { - speed = m_config.get_abs_value("ironing_speed"); - } else if (path.role() == erNone) { - speed = m_config.get_abs_value("travel_speed"); - } else if (path.role() == erMilling) { - speed = m_config.get_abs_value("milling_speed"); - } else { - throw Slic3r::InvalidArgument("Invalid speed"); - } - //don't modify bridge speed - if (factor < 1 && !(is_bridge(path.role()))) { - float small_speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed); - //apply factor between feature speed and small speed - speed = (speed * factor) + double((1.f - factor) * small_speed); - } - } - if (m_volumetric_speed != 0. && speed == 0) { - //if m_volumetric_speed, use the max size for thinwall & gapfill, to avoid variations - double vol_speed = m_volumetric_speed / path.mm3_per_mm; - if (vol_speed > m_config.max_print_speed.value) - vol_speed = m_config.max_print_speed.value; - // if using a % of an auto speed, use the % over the volumetric speed. - if (path.role() == erExternalPerimeter) { - speed = m_config.external_perimeter_speed.get_abs_value(vol_speed); - } else if (path.role() == erInternalBridgeInfill) { - speed = m_config.bridge_speed_internal.get_abs_value(vol_speed); - } else if (path.role() == erOverhangPerimeter) { - speed = m_config.overhangs_speed.get_abs_value(vol_speed); - } else if (path.role() == erSolidInfill) { - speed = m_config.solid_infill_speed.get_abs_value(vol_speed); - } else if (path.role() == erTopSolidInfill) { - speed = m_config.top_solid_infill_speed.get_abs_value(vol_speed); - } - if(speed == 0){ - speed = vol_speed; - } - } - if (speed == 0) // this code shouldn't trigger as if it's 0, you have to get a m_volumetric_speed - speed = m_config.max_print_speed.value; - if (this->on_first_layer()) { - const double base_speed = speed; - if (path.role() == erInternalInfill || path.role() == erSolidInfill) { - double first_layer_infill_speed = m_config.first_layer_infill_speed.get_abs_value(base_speed); - if (first_layer_infill_speed > 0) - speed = std::min(first_layer_infill_speed, speed); - } else { - double first_layer_speed = m_config.first_layer_speed.get_abs_value(base_speed); - if (first_layer_speed > 0) - speed = std::min(first_layer_speed, speed); - } - double first_layer_min_speed = m_config.first_layer_min_speed.get_abs_value(base_speed); - speed = std::max(first_layer_min_speed, speed); - } - // cap speed with max_volumetric_speed anyway (even if user is not using autospeed) - if (m_config.max_volumetric_speed.value > 0 && path.mm3_per_mm > 0) { - speed = std::min(m_config.max_volumetric_speed.value / path.mm3_per_mm, speed); - } - double filament_max_volumetric_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_volumetric_speed, 0); - if (filament_max_volumetric_speed > 0) { - speed = std::min(filament_max_volumetric_speed / path.mm3_per_mm, speed); - } - double filament_max_speed = EXTRUDER_CONFIG_WITH_DEFAULT(filament_max_speed, 0); - if (filament_max_speed > 0) { - speed = std::min(filament_max_speed, speed); - } + speed = _compute_speed_mm_per_sec(path, speed); double F = speed * 60; // convert mm/sec to mm/min // extrude arc or line diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 84c2663ff..016fc4524 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -430,6 +430,7 @@ private: std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); std::string _before_extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); + double_t _compute_speed_mm_per_sec(const ExtrusionPath& path, double speed = -1); std::string _after_extrude(const ExtrusionPath &path); void print_machine_envelope(FILE *file, Print &print); void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait); diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index b4b41fbf8..0d1008c61 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -730,6 +730,7 @@ const std::vector& Preset::printer_options() "use_relative_e_distances", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "min_length", + "max_gcode_per_second", //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. "host_type", "print_host", "printhost_apikey", "printhost_cafile", "printhost_port", "single_extruder_multi_material", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 156ee5257..38565675e 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -128,6 +128,7 @@ bool Print::invalidate_state_by_config_options(const std::vectormode = comAdvanced; def->set_default_value(new ConfigOptionFloats{ 1500., 1250. }); + def = this->add("max_gcode_per_second", coFloat); + def->label = L("Maximum G1 per second"); + def->category = OptionCategory::speed; + def->tooltip = L("If your firmware stops while printing, it may have its gcode queue full." + " Set this parameter to merge extrusions into bigger ones to reduce the number of gcode commands the printer has to process each second." + "\nNote that reducing your printing speed (at least for the external extrusions) will reduce the number of time this will triggger and so increase quality." + "\nSet zero to disable."); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(1500)); + def = this->add("max_fan_speed", coInts); def->label = L("Max"); def->full_label = L("Max fan speed"); @@ -2700,8 +2711,9 @@ void PrintConfigDef::init_fff_params() def = this->add("min_length", coFloat); def->label = L("Minimum extrusion length"); def->category = OptionCategory::speed; - def->tooltip = L("Too many too small commands may overload the firmware / connection. Put a higher value here if you see strange slowdown." - "\nSet zero to disable."); + def->tooltip = L("[Deprecated] Prefer using max_gcode_per_second instead, as it's much better when you have very different speeds for features." + "\nToo many too small commands may overload the firmware / connection. Put a higher value here if you see strange slowdown." + "\nSet zero to disable."); def->sidetext = L("mm"); def->min = 0; def->precision = 8; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 38a6c0767..7deb872c5 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1096,6 +1096,7 @@ public: ConfigOptionInts gcode_precision_e; ConfigOptionString layer_gcode; ConfigOptionString feature_gcode; + ConfigOptionFloat max_gcode_per_second; ConfigOptionFloat max_print_speed; ConfigOptionFloat max_volumetric_speed; #ifdef HAS_PRESSURE_EQUALIZER @@ -1209,6 +1210,7 @@ protected: OPT_PTR(gcode_precision_e); OPT_PTR(layer_gcode); OPT_PTR(feature_gcode); + OPT_PTR(max_gcode_per_second); OPT_PTR(max_print_speed); OPT_PTR(max_volumetric_speed); OPT_PTR(milling_z_lift);