max_gcode_per_second added

allow a better control than min_length
This commit is contained in:
supermerill 2021-08-23 00:38:28 +02:00
parent 688121b104
commit 55fdc665ca
7 changed files with 131 additions and 99 deletions

View File

@ -19,6 +19,10 @@ group:silent_mode_event:Firmware
setting:gcode_precision_xyz setting:gcode_precision_xyz
setting:gcode_precision_e setting:gcode_precision_e
end_line end_line
line:Processing limit
setting:max_gcode_per_second
setting:min_length
end_line
group:Cooling fan group:Cooling fan
line:Speedup line:Speedup
setting:label$Speedup time:fan_speedup_time setting:label$Speedup time:fan_speedup_time
@ -40,7 +44,6 @@ group:Advanced
setting:use_relative_e_distances setting:use_relative_e_distances
setting:use_firmware_retraction setting:use_firmware_retraction
setting:use_volumetric_e setting:use_volumetric_e
setting:min_length
setting:variable_layer_height setting:variable_layer_height
page:Custom G-code:cog page:Custom G-code:cog

View File

@ -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; ExtrusionPath simplifed_path = path;
const double scaled_min_length = scale_(this->config().min_length.value); 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())); //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 //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()); //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.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()); 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(); 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. // 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. // 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. // 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 //else simplifed_path.simplify(SCALED_RESOLUTION); //should already be simplified
if (scaled_min_length > 0 && simplifed_path.length() < scaled_min_length) { 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 ""; 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) { if (m_wipe.enable) {
m_wipe.path = std::move(simplifed_path.polyline); 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; 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::_before_extrude(const ExtrusionPath &path, const std::string &description_in, double speed) {
std::string gcode; std::string gcode;
std::string description{ description_in }; std::string description{ description_in };
@ -3813,96 +3914,7 @@ std::string GCode::_before_extrude(const ExtrusionPath &path, const std::string
// compensate retraction // compensate retraction
gcode += this->unretract(); gcode += this->unretract();
// set speed speed = _compute_speed_mm_per_sec(path, 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);
}
double F = speed * 60; // convert mm/sec to mm/min double F = speed * 60; // convert mm/sec to mm/min
// extrude arc or line // extrude arc or line

View File

@ -430,6 +430,7 @@ private:
std::string _extrude(const ExtrusionPath &path, const std::string &description, double speed = -1); 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); 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); std::string _after_extrude(const ExtrusionPath &path);
void print_machine_envelope(FILE *file, Print &print); 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); void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, uint16_t first_printing_extruder_id, bool wait);

View File

@ -730,6 +730,7 @@ const std::vector<std::string>& Preset::printer_options()
"use_relative_e_distances", "use_relative_e_distances",
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
"min_length", "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. //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", "host_type", "print_host", "printhost_apikey", "printhost_cafile", "printhost_port",
"single_extruder_multi_material", "single_extruder_multi_material",

View File

@ -128,6 +128,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
"infill_acceleration", "infill_acceleration",
"layer_gcode", "layer_gcode",
"max_fan_speed", "max_fan_speed",
"max_gcode_per_second",
"max_print_height", "max_print_height",
"max_print_speed", "max_print_speed",
"max_volumetric_speed", "max_volumetric_speed",

View File

@ -2586,6 +2586,17 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats{ 1500., 1250. }); 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 = this->add("max_fan_speed", coInts);
def->label = L("Max"); def->label = L("Max");
def->full_label = L("Max fan speed"); def->full_label = L("Max fan speed");
@ -2700,8 +2711,9 @@ void PrintConfigDef::init_fff_params()
def = this->add("min_length", coFloat); def = this->add("min_length", coFloat);
def->label = L("Minimum extrusion length"); def->label = L("Minimum extrusion length");
def->category = OptionCategory::speed; 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." def->tooltip = L("[Deprecated] Prefer using max_gcode_per_second instead, as it's much better when you have very different speeds for features."
"\nSet zero to disable."); "\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->sidetext = L("mm");
def->min = 0; def->min = 0;
def->precision = 8; def->precision = 8;

View File

@ -1096,6 +1096,7 @@ public:
ConfigOptionInts gcode_precision_e; ConfigOptionInts gcode_precision_e;
ConfigOptionString layer_gcode; ConfigOptionString layer_gcode;
ConfigOptionString feature_gcode; ConfigOptionString feature_gcode;
ConfigOptionFloat max_gcode_per_second;
ConfigOptionFloat max_print_speed; ConfigOptionFloat max_print_speed;
ConfigOptionFloat max_volumetric_speed; ConfigOptionFloat max_volumetric_speed;
#ifdef HAS_PRESSURE_EQUALIZER #ifdef HAS_PRESSURE_EQUALIZER
@ -1209,6 +1210,7 @@ protected:
OPT_PTR(gcode_precision_e); OPT_PTR(gcode_precision_e);
OPT_PTR(layer_gcode); OPT_PTR(layer_gcode);
OPT_PTR(feature_gcode); OPT_PTR(feature_gcode);
OPT_PTR(max_gcode_per_second);
OPT_PTR(max_print_speed); OPT_PTR(max_print_speed);
OPT_PTR(max_volumetric_speed); OPT_PTR(max_volumetric_speed);
OPT_PTR(milling_z_lift); OPT_PTR(milling_z_lift);