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_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

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;
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

View File

@ -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);

View File

@ -730,6 +730,7 @@ const std::vector<std::string>& 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",

View File

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

View File

@ -2586,6 +2586,17 @@ void PrintConfigDef::init_fff_params()
def->mode = 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;

View File

@ -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);