Update Resonance Avoidance

This commit is contained in:
QIDI TECH
2024-06-21 14:19:23 +08:00
parent b7e961c443
commit 69126621fc
9 changed files with 337 additions and 277 deletions

View File

@@ -128,11 +128,13 @@ ironing_type = top
layer_height = 0.2
max_bridge_length = 10
max_print_speed = 600
max_resonance_avoidance_speed = 120
max_volumetric_extrusion_rate_slope_negative = 0
max_volumetric_extrusion_rate_slope_positive = 0
max_volumetric_speed = 0
min_bead_width = 85%
min_feature_size = 25%
min_resonance_avoidance_speed = 70
min_skirt_length = 5
mmu_segmented_region_interlocking_depth = 0
mmu_segmented_region_max_width = 0
@@ -160,6 +162,7 @@ raft_first_layer_density = 90%
raft_first_layer_expansion = 3
raft_layers = 0
resolution = 0
resonance_avoidance = 1
seam_gap = 15%
seam_position = aligned
single_extruder_multi_material_priming = 0
@@ -169,7 +172,7 @@ skirts = 0
slice_closing_radius = 0.049
slicing_mode = regular
slow_down_layers = 0
small_perimeter_speed = 70
small_perimeter_speed = 100
solid_infill_acceleration = 10000
solid_infill_below_area = 15
solid_infill_every_layers = 0
@@ -2529,9 +2532,7 @@ machine_min_extruding_rate = 0
machine_min_travel_rate = 0
max_layer_height = 0.28
max_print_height = 315
max_resonance_avoidance_speed = 115
min_layer_height = 0.08
min_resonance_avoidance_speed = 70
multimaterial_purging = 45
nozzle_diameter = 0.4
parking_pos_retraction = 92
@@ -2546,7 +2547,6 @@ printer_vendor = QIDI
printhost_apikey =
printhost_cafile =
remaining_times = 1
resonance_avoidance = 1
retract_before_travel = 1
retract_before_wipe = 0%
retract_layer_change = 1

View File

@@ -83,7 +83,6 @@ namespace Slic3r {
gcode += '\n';
}
// Return true if tch_prefix is found in custom_gcode
static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder)
{
@@ -146,13 +145,14 @@ namespace Slic3r {
int OozePrevention::_get_temp(const GCodeGenerator &gcodegen) const
{
// First layer temperature should be used when on the first layer (obviously) and when
// "other layers" is set to zero (which means it should not be used).
return (gcodegen.layer() == nullptr || gcodegen.layer()->id() == 0
|| gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id()) == 0)
? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().extruder()->id())
: gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id());
}
const std::vector<std::string> ColorPrintColors::Colors = { "#C0392B", "#E67E22", "#F1C40F", "#27AE60", "#1ABC9C", "#2980B9", "#9B59B6" };
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
@@ -208,6 +208,7 @@ void GCodeGenerator::PlaceholderParserIntegration::init(const GCodeWriter &write
this->position.assign(3, 0);
this->opt_position = new ConfigOptionFloats(this->position);
this->output_config.set_key_value("position", this->opt_position);
// Store zhop variable into the parser itself, it is a read-only variable to the script.
this->opt_zhop = new ConfigOptionFloat(writer.get_zhop());
this->parser.set("zhop", this->opt_zhop);
@@ -230,6 +231,7 @@ void GCodeGenerator::PlaceholderParserIntegration::update_from_gcodewriter(const
for (const Extruder &e : extruders) {
this->e_retracted[e.id()] = e.retracted();
this->e_restart_extra[e.id()] = e.restart_extra();
// Wipe tower filament consumption has to be added separately, because that gcode is not generated by GCodeWriter.
double wt_vol = 0.;
const std::vector<std::pair<float, std::vector<float>>>& wtuf = wipe_tower_data.used_filament_until_layer;
@@ -552,8 +554,11 @@ GCodeGenerator::GCodeGenerator(const Print* print) :
m_brim_done(false),
m_second_layer_things_done(false),
m_silent_time_estimator_enabled(false),
//Y27
m_resonance_avoidance(true),
m_print(print)
{}
void GCodeGenerator::do_export(Print* print, const char* path, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb)
{
CNumericLocalesSetter locales_setter;
@@ -789,6 +794,7 @@ namespace DoExport {
print_statistics.total_wipe_tower_filament_weight += has_wipe_tower ? (extruded_volume - extruder.extruded_volume()) * extruder.filament_density() * 0.001 : 0.;
print_statistics.total_wipe_tower_cost += has_wipe_tower ? (extruded_volume - extruder.extruded_volume())* extruder.filament_density() * 0.001 * extruder.filament_cost() * 0.001 : 0.;
}
if (!export_binary_data) {
filament_stats_string_out += out_filament_used_mm.first;
filament_stats_string_out += "\n" + out_filament_used_cm3.first;
@@ -899,6 +905,7 @@ static inline std::optional<std::string> find_M84(const std::string &gcode) {
return std::nullopt;
}
void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGeneratorCallback thumbnail_cb)
{
const bool export_to_binary_gcode = print.full_print_config().option<ConfigOptionBool>("binary_gcode")->value;
@@ -1002,15 +1009,16 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
// Write information on the generator.
file.write_format("; %s\n\n", Slic3r::header_slic3r_generated().c_str());
if (! export_to_binary_gcode) {
// if exporting gcode in ascii format, generate the thumbnails here
auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config());
if (errors != enum_bitmask<ThumbnailError>()) {
std::string error_str = format("Invalid thumbnails value:");
error_str += GCodeThumbnails::get_error_string(errors);
throw Slic3r::ExportError(error_str);
}
if (!thumbnails.empty())
GCodeThumbnails::export_thumbnails_to_file(thumbnail_cb, thumbnails,
[&file](const char* sz) { file.write(sz); },
@@ -1053,8 +1061,9 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
}
print.throw_if_canceled();
}
//B41
// adds tags for time estimators
//B41
// if (print.config().remaining_times.value)
// file.write_format(";%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::First_Line_M73_Placeholder).c_str());
@@ -1229,6 +1238,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
}
GCode::SmoothPathCache smooth_path_cache_global = smooth_path_interpolate_global(print);
// Do all objects for each layer.
if (print.config().complete_objects.value) {
size_t finished_objects = 0;
@@ -1285,6 +1295,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
m_second_layer_things_done = false;
prev_object = &object;
}
file.write(m_label_objects.maybe_stop_instance());
} else {
// Sort layers by Z.
@@ -1293,10 +1304,12 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
// QIDI Multi-Material wipe tower.
if (has_wipe_tower && ! layers_to_print.empty()) {
m_wipe_tower = std::make_unique<GCode::WipeTowerIntegration>(print.config(), *print.wipe_tower_data().priming.get(), print.wipe_tower_data().tool_changes, *print.wipe_tower_data().final_purge.get());
// Set position for wipe tower generation.
Vec3d new_position = this->writer().get_position();
new_position.z() = first_layer_height;
this->writer().update_position(new_position);
if (print.config().single_extruder_multi_material_priming) {
file.write(m_wipe_tower->prime(*this));
// Verify, whether the print overaps the priming extrusions.
@@ -1414,6 +1427,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
file.write_format("; objects_info = %s\n", m_label_objects.all_objects_header_singleline_json().c_str());
file.write(filament_stats_string_out);
}
if (export_to_binary_gcode) {
bgcode::binarize::BinaryData& binary_data = m_processor.get_binary_data();
if (print.m_print_statistics.total_toolchanges > 0)
@@ -1421,6 +1435,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
char buf[1024];
sprintf(buf, "%.2lf", m_max_layer_z);
binary_data.printer_metadata.raw_data.emplace_back("max_layer_z", buf);
// Now the objects info.
binary_data.printer_metadata.raw_data.emplace_back("objects_info", m_label_objects.all_objects_header_singleline_json());
}
@@ -1436,7 +1451,6 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
//B3
if (!export_to_binary_gcode) {
// if exporting gcode in ascii format, generate the thumbnails here
auto [thumbnails, errors] = GCodeThumbnails::make_and_check_thumbnail_list(print.full_print_config());
if (errors != enum_bitmask<ThumbnailError>()) {
std::string error_str = format("Invalid thumbnails value:");
@@ -1450,6 +1464,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
file.write("\n");
// if exporting gcode in ascii format, config export is done here
// Append full config, delimited by two 'phony' configuration keys qidislicer_config = begin and qidislicer_config = end.
// The delimiters are structured as configuration key / value pairs to be parsable by older versions of QIDISlicer G-code viewer.
{
@@ -1485,6 +1500,7 @@ void GCodeGenerator::smooth_path_interpolate(
if (const SupportLayer *layer = object_layer_to_print.support_layer; layer)
out.interpolate_add(layer->support_fills, params);
}
// Process all layers of all objects (non-sequential mode) with a parallel pipeline:
// Generate G-code, run the filters (vase mode, cooling buffer), run the G-code analyser
// and export G-code into file.
@@ -1542,7 +1558,6 @@ void GCodeGenerator::process_layers(
[spiral_vase = this->m_spiral_vase.get(), &layers_to_print](LayerResult in) -> LayerResult {
if (in.nop_layer_result)
return in;
spiral_vase->enable(in.spiral_vase_enable);
bool last_layer = in.layer_id == layers_to_print.size() - 1;
return { spiral_vase->process_layer(std::move(in.gcode), last_layer), in.layer_id, in.spiral_vase_enable, in.cooling_buffer_flush};
@@ -1575,10 +1590,10 @@ void GCodeGenerator::process_layers(
tbb::filter<LayerResult, std::string> pipeline_to_string = cooling;
if (m_find_replace)
pipeline_to_string = pipeline_to_string & find_replace;
// It registers a handler that sets locales to "C" before any TBB thread starts participating in tbb::parallel_pipeline.
// Handler is unregistered when the destructor is called.
TBBLocalesSetter locales_setter;
// The pipeline elements are joined using const references, thus no copying is performed.
output_stream.find_replace_supress();
tbb::parallel_pipeline(12, pipeline_to_layerresult & pipeline_to_string & output);
@@ -1668,10 +1683,10 @@ void GCodeGenerator::process_layers(
tbb::filter<LayerResult, std::string> pipeline_to_string = cooling;
if (m_find_replace)
pipeline_to_string = pipeline_to_string & find_replace;
// It registers a handler that sets locales to "C" before any TBB thread starts participating in tbb::parallel_pipeline.
// Handler is unregistered when the destructor is called.
TBBLocalesSetter locales_setter;
// The pipeline elements are joined using const references, thus no copying is performed.
output_stream.find_replace_supress();
tbb::parallel_pipeline(12, pipeline_to_layerresult & pipeline_to_string & output);
@@ -1709,6 +1724,7 @@ std::string GCodeGenerator::placeholder_parser_process(
throw Slic3r::PlaceholderParserError(format("\"%s\" custom G-code needs to be added to s_CustomGcodeSpecificOptions", name.c_str()));
}
#endif
PlaceholderParserIntegration &ppi = m_placeholder_parser_integration;
try {
ppi.update_from_gcodewriter(m_writer, m_print->wipe_tower_data());
@@ -2016,8 +2032,10 @@ static std::string emit_custom_color_change_gcode_per_print_z(
// see GH issue #6362
gcodegen.writer().unretract();
}
return gcode;
}
static std::string emit_custom_gcode_per_print_z(
GCodeGenerator &gcodegen,
const CustomGCode::Item &custom_gcode,
@@ -2043,11 +2061,13 @@ static std::string emit_custom_color_change_gcode_per_print_z(
} else {
if (gcode_type == CustomGCode::PausePrint) { // Pause print
const std::string pause_print_msg = custom_gcode.extra;
// add tag for processor
gcode += ";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Pause_Print) + "\n";
//! FIXME_in_fw show message during print pause
if (!pause_print_msg.empty())
gcode += "M117 " + pause_print_msg + "\n";
DynamicConfig cfg;
cfg.set_key_value("color_change_extruder", new ConfigOptionInt(int(current_extruder_id)));
gcode += gcodegen.placeholder_parser_process("pause_print_gcode", config.pause_print_gcode, current_extruder_id, &cfg);
@@ -2058,7 +2078,6 @@ static std::string emit_custom_color_change_gcode_per_print_z(
gcode += gcodegen.placeholder_parser_process("template_custom_gcode", config.template_custom_gcode, current_extruder_id);
else // custom Gcode
gcode += custom_gcode.extra;
}
gcode += "\n";
}
@@ -2146,6 +2165,7 @@ bool GCodeGenerator::line_distancer_is_required(const std::vector<unsigned int>&
}
return false;
}
Polyline GCodeGenerator::get_layer_change_xy_path(const Vec3d &from, const Vec3d &to) {
bool could_be_wipe_disabled{false};
@@ -2233,6 +2253,7 @@ std::string GCodeGenerator::generate_ramping_layer_change_gcode(
const GCode::Impl::Travels::ElevatedTravelParams &elevation_params
) const {
using namespace GCode::Impl::Travels;
const std::vector<double> ensure_points_at_distances = linspace(
elevation_params.slope_end - elevation_params.blend_width / 2.0,
elevation_params.slope_end + elevation_params.blend_width / 2.0,
@@ -2254,6 +2275,7 @@ std::string GCodeGenerator::generate_ramping_layer_change_gcode(
}
return travel_gcode;
}
// In sequential mode, process_layer is called once per each object and its copy,
// therefore layers will contain a single entry and single_object_instance_idx will point to the copy of the object.
// In non-sequential mode, process_layer is called per each print_z height with all object and support layers accumulated.
@@ -2330,6 +2352,7 @@ LayerResult GCodeGenerator::process_layer(
m_enable_loop_clipping = !enable;
}
std::string gcode;
assert(is_decimal_separator_point()); // for the sprintfs
@@ -2365,6 +2388,7 @@ LayerResult GCodeGenerator::process_layer(
m_layer = &layer;
if (this->line_distancer_is_required(layer_tools.extruders) && this->m_layer != nullptr && this->m_layer->lower_layer != nullptr)
m_travel_obstacle_tracker.init_layer(layer, layers);
m_object_layer_over_raft = false;
if (!first_layer && ! print.config().layer_gcode.value.empty()) {
DynamicConfig config;
@@ -2452,11 +2476,13 @@ LayerResult GCodeGenerator::process_layer(
// Now we have picked the right extruder, so we can emit the custom g-code.
gcode += ProcessLayer::emit_custom_gcode_per_print_z(*this, *layer_tools.custom_gcode, m_writer.extruder()->id(), first_extruder_id, print.config());
}
if (auto loops_it = skirt_loops_per_extruder.find(extruder_id); loops_it != skirt_loops_per_extruder.end()) {
if (!this->m_config.complete_objects.value) {
gcode += this->m_label_objects.maybe_stop_instance();
}
this->m_label_objects.update(nullptr);
const std::pair<size_t, size_t> loops = loops_it->second;
this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp();
@@ -2478,10 +2504,12 @@ LayerResult GCodeGenerator::process_layer(
// Extrude brim with the extruder of the 1st region.
if (! m_brim_done) {
if (!this->m_config.complete_objects.value) {
gcode += this->m_label_objects.maybe_stop_instance();
}
this->m_label_objects.update(nullptr);
this->set_origin(0., 0.);
m_avoid_crossing_perimeters.use_external_mp();
for (const ExtrusionEntity *ee : print.brim().entities)
@@ -2491,7 +2519,6 @@ LayerResult GCodeGenerator::process_layer(
// Allow a straight travel move to the first object point.
m_avoid_crossing_perimeters.disable_once();
}
this->m_label_objects.update(first_instance);
// We are almost ready to print. However, we must go through all the objects twice to print the the overridden extrusions first (infill/perimeter wiping feature):
@@ -2515,6 +2542,7 @@ LayerResult GCodeGenerator::process_layer(
is_anything_overridden, false /* print_wipe_extrusions */);
}
// During layer change the starting position of next layer is now known.
// The solution is thus to emplace a temporary tag to the gcode, cache the postion and
// replace the tag later. The tag is Layer_Change_Travel, the cached position is
@@ -2582,6 +2610,7 @@ LayerResult GCodeGenerator::process_layer(
}
boost::algorithm::replace_first(gcode, tag, layer_change_gcode);
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
@@ -2640,7 +2669,6 @@ void GCodeGenerator::process_layer_single_object(
const PrintObject &print_object = print_instance.print_object;
const Print &print = *print_object.print();
if (! print_wipe_extrusions && layer_to_print.support_layer != nullptr)
if (const SupportLayer &support_layer = *layer_to_print.support_layer; ! support_layer.support_fills.entities.empty()) {
ExtrusionRole role = support_layer.support_fills.role();
@@ -2814,11 +2842,8 @@ void GCodeGenerator::process_layer_single_object(
}
}
}
}
void GCodeGenerator::apply_print_config(const PrintConfig &print_config)
{
m_writer.apply_print_config(print_config);
@@ -2862,7 +2887,6 @@ void GCodeGenerator::encode_full_config(const Print& print, std::vector<std::pai
void GCodeGenerator::set_extruders(const std::vector<unsigned int> &extruder_ids)
{
m_writer.set_extruders(extruder_ids);
m_wipe.init(this->config(), extruder_ids);
}
@@ -2872,6 +2896,7 @@ void GCodeGenerator::set_origin(const Vec2d &pointf)
const auto offset = Point::new_scale(m_origin - pointf);
if (last_position.has_value())
*(this->last_position) += offset;
m_wipe.offset_path(offset);
m_origin = pointf;
}
@@ -2889,7 +2914,6 @@ std::string GCodeGenerator::preamble()
return gcode;
}
// called by GCodeGenerator::process_layer()
std::string GCodeGenerator::change_layer(
coordf_t previous_layer_z,
@@ -2904,6 +2928,7 @@ std::string GCodeGenerator::change_layer(
if (m_writer.multiple_extruders) {
gcode += m_label_objects.maybe_change_instance(m_writer);
}
if (!EXTRUDER_CONFIG(travel_ramping_lift) && EXTRUDER_CONFIG(retract_layer_change)) {
gcode += this->retract_and_wipe();
} else if (EXTRUDER_CONFIG(travel_ramping_lift) && !vase_mode){
@@ -2931,6 +2956,7 @@ std::string GCodeGenerator::change_layer(
// forget last wiping path as wiping after raising Z is pointless
m_wipe.reset_path();
return gcode;
}
@@ -2945,10 +2971,11 @@ static inline bool validate_smooth_path(const GCode::SmoothPath &smooth_path, bo
return true;
}
#endif //NDEBUG
static constexpr const double min_gcode_segment_length = 0.002;
std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed)
{
// Extrude all loops CCW.
//w38
//bool is_hole = loop_src.is_clockwise();
@@ -2966,7 +2993,6 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
//w38
seam_point = m_seam_placer.place_seam(m_layer, new_loop_src, m_config.external_perimeters_first, seam_point);
}
// Because the G-code export has 1um resolution, don't generate segments shorter than 1.5 microns,
// thus empty path segments will not be produced by G-code export.
//w38
@@ -2982,32 +3008,38 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
if (smooth_path.empty())
return {};
assert(validate_smooth_path(smooth_path, ! m_enable_loop_clipping));
// Apply the small perimeter speed.
//w38
if (new_loop_src.paths.front().role().is_perimeter() && new_loop_src.length() <= SMALL_PERIMETER_LENGTH && speed == -1)
//w38//Y27
bool is_small_perimeter_length = false;
if (new_loop_src.paths.front().role().is_perimeter() && new_loop_src.length() <= SMALL_PERIMETER_LENGTH && speed == -1) {
speed = m_config.small_perimeter_speed.get_abs_value(m_config.perimeter_speed);
is_small_perimeter_length = true;
}
// Extrude along the smooth path.
std::string gcode;
for (const GCode::SmoothPathElement &el : smooth_path)
//Y27
for (const GCode::SmoothPathElement &el : smooth_path) {
m_resonance_avoidance = !is_small_perimeter_length;
gcode += this->_extrude(el.path_attributes, el.path, description, speed);
}
// reset acceleration
gcode += m_writer.set_print_acceleration(fast_round_up<unsigned int>(m_config.default_acceleration.value));
if (m_wipe.enabled()) {
// Wipe will hide the seam.
m_wipe.set_path(std::move(smooth_path));
}//w38
}
//w38
else if (new_loop_src.paths.back().role().is_external_perimeter() && m_layer != nullptr && m_config.perimeters.value > 1) {
// Only wipe inside if the wipe along the perimeter is disabled.
// Make a little move inwards before leaving loop.
if (std::optional<Point> pt = wipe_hide_seam(smooth_path, is_hole, scale_(EXTRUDER_CONFIG(nozzle_diameter))); pt) {
// Generate the seam hiding travel move.
gcode += m_writer.travel_to_xy(this->point_to_gcode(*pt), "move inwards before travel");
this->last_position = *pt;
@@ -3016,6 +3048,7 @@ std::string GCodeGenerator::extrude_loop(const ExtrusionLoop &loop_src, const GC
return gcode;
}
std::string GCodeGenerator::extrude_skirt(
const ExtrusionLoop &loop_src, const ExtrusionFlow &extrusion_flow_override,
const GCode::SmoothPathCache &smooth_path_cache, const std::string_view description, double speed)
@@ -3024,13 +3057,16 @@ std::string GCodeGenerator::extrude_skirt(
Point seam_point = this->last_position.has_value() ? *this->last_position : Point::Zero();
GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit_split_with_seam(
loop_src, false, m_scaled_resolution, seam_point, scaled<double>(0.0015));
// Clip the path to avoid the extruder to get exactly on the first point of the loop;
// if polyline was shorter than the clipping distance we'd get a null polyline, so
// we discard it in that case.
if (m_enable_loop_clipping)
clip_end(smooth_path, scale_(EXTRUDER_CONFIG(nozzle_diameter)) * LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER, scaled<double>(min_gcode_segment_length));
if (smooth_path.empty())
return {};
assert(validate_smooth_path(smooth_path, ! m_enable_loop_clipping));
// Extrude along the smooth path.
@@ -3041,8 +3077,10 @@ std::string GCodeGenerator::extrude_skirt(
el.path_attributes.height = extrusion_flow_override.height;
gcode += this->_extrude(el.path_attributes, el.path, description, speed);
}
// reset acceleration
gcode += m_writer.set_print_acceleration(fast_round_up<unsigned int>(m_config.default_acceleration.value));
if (m_wipe.enabled())
// Wipe will hide the seam.
m_wipe.set_path(std::move(smooth_path));
@@ -3059,13 +3097,15 @@ std::string GCodeGenerator::extrude_multi_path(const ExtrusionMultiPath &multipa
}
#endif // NDEBUG
GCode::SmoothPath smooth_path = smooth_path_cache.resolve_or_fit(multipath, reverse, m_scaled_resolution);
// extrude along the path
// extrude along the path
std::string gcode;
for (GCode::SmoothPathElement &el : smooth_path)
gcode += this->_extrude(el.path_attributes, el.path, description, speed);
GCode::reverse(smooth_path);
m_wipe.set_path(std::move(smooth_path));
// reset acceleration
gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5));
return gcode;
@@ -3214,6 +3254,7 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const
this->m_layer_change_used_external_mp = this->m_avoid_crossing_perimeters.use_external_mp_once;
this->m_layer_change_layer = this->layer();
this->m_layer_change_origin = this->origin();
double lift{
EXTRUDER_CONFIG(travel_ramping_lift) ? EXTRUDER_CONFIG(travel_max_lift) :
EXTRUDER_CONFIG(retract_lift)};
@@ -3230,6 +3271,7 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const
gcode += this->writer().get_travel_to_z_gcode(from_z + lift, "lift");
}
}
const std::string comment{"move to first layer point"};
gcode += insert_gcode();
@@ -3240,7 +3282,9 @@ std::string GCodeGenerator::travel_to_first_position(const Vec3crd& point, const
this->last_position = point.head<2>();
this->writer().update_position(gcode_point);
}
m_current_layer_first_position = gcode_point;
return gcode;
}
@@ -3257,6 +3301,7 @@ double cap_speed(
}
return speed;
}
std::string GCodeGenerator::_extrude(
const ExtrusionAttributes &path_attr,
const Geometry::ArcWelder::Path &path,
@@ -3272,6 +3317,7 @@ std::string GCodeGenerator::_extrude(
if (m_writer.multiple_extruders && has_active_instance) {
gcode += m_label_objects.maybe_change_instance(m_writer);
}
if (!m_current_layer_first_position) {
const Vec3crd point = to_3d(path.front().point, scaled(this->m_last_layer_z));
gcode += this->travel_to_first_position(point, unscaled(point.z()), path_attr.role, [&](){
@@ -3307,6 +3353,7 @@ std::string GCodeGenerator::_extrude(
} else {
this->m_already_unretracted = true;
gcode += "FIRST_UNRETRACT" + this->unretract();
//First unretract may or may not be removed thus we must start from E0.
gcode += this->writer().reset_e();
}
@@ -3409,7 +3456,6 @@ std::string GCodeGenerator::_extrude(
std::pair<float, float> dynamic_speed_and_fan_speed{-1, -1};
if (path_attr.overhang_attributes.has_value()) {
double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed");
if (external_perim_reference_speed == 0)
external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm;
@@ -3421,22 +3467,33 @@ std::string GCodeGenerator::_extrude(
external_perim_reference_speed, speed);
}
//Y27
bool dont_speed_down_by_overhang = true;
if (path_attr.role == ExtrusionRole::ExternalPerimeter && m_config.opt_bool("resonance_avoidance")) {
if (dynamic_speed_and_fan_speed.first > -1) {
if (speed != dynamic_speed_and_fan_speed.first) {
dont_speed_down_by_overhang = false;
speed = dynamic_speed_and_fan_speed.first;
double min_speed = cap_speed(speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id());
if (min_speed > m_config.opt_float("max_resonance_avoidance_speed")) {
m_resonance_avoidance = false;
}
}
speed = dynamic_speed_and_fan_speed.first;
}
// cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
speed = cap_speed(speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id());
//Y27
if (path_attr.role == ExtrusionRole::ExternalPerimeter && m_config.opt_bool("resonance_avoidance" ) && dont_speed_down_by_overhang) {
if (m_resonance_avoidance) {
if (speed <= m_config.opt_float("max_resonance_avoidance_speed")) {
speed = std::min(speed, m_config.opt_float("min_resonance_avoidance_speed"));
}
m_resonance_avoidance = true;
}
} else {
if (dynamic_speed_and_fan_speed.first > -1) {
speed = dynamic_speed_and_fan_speed.first;
}
speed = cap_speed(speed, path_attr.mm3_per_mm, m_config, m_writer.extruder()->id());
}
double F = speed * 60; // convert mm/sec to mm/min
// extrude arc or line
@@ -3502,6 +3559,7 @@ std::string GCodeGenerator::_extrude(
gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments);
if (dynamic_speed_and_fan_speed.second >= 0)
gcode += ";_SET_FAN_SPEED" + std::to_string(int(dynamic_speed_and_fan_speed.second)) + "\n";
std::string comment;
if (m_config.gcode_comments) {
comment = description;
@@ -3550,7 +3608,6 @@ std::string GCodeGenerator::_extrude(
}
}
if (m_enable_cooling_markers)
gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n";
@@ -3561,13 +3618,13 @@ std::string GCodeGenerator::_extrude(
return gcode;
}
std::string GCodeGenerator::generate_travel_gcode(
const Points3& travel,
const std::string& comment,
const std::function<std::string()>& insert_gcode
) {
std::string gcode;
const unsigned acceleration =(unsigned)(m_config.travel_acceleration.value + 0.5);
if (travel.empty()) {
@@ -3576,7 +3633,6 @@ std::string GCodeGenerator::generate_travel_gcode(
// generate G-code for the travel move
// use G1 because we rely on paths being straight (G0 may make round paths)
gcode += this->m_writer.set_travel_acceleration(acceleration);
Vec3d previous_point{this->point_to_gcode(travel.front())};
@@ -3589,6 +3645,7 @@ std::string GCodeGenerator::generate_travel_gcode(
gcode += insert_gcode();
already_inserted = true;
}
gcode += this->m_writer.travel_to_xyz(previous_point, gcode_point, comment);
this->last_position = point.head<2>();
previous_point = gcode_point;
@@ -3690,7 +3747,6 @@ std::string GCodeGenerator::travel_to(
const std::string &comment,
const std::function<std::string()>& insert_gcode
) {
// check whether a straight travel move would need retraction
bool could_be_wipe_disabled {false};
@@ -3735,6 +3791,7 @@ std::string GCodeGenerator::travel_to(
(upper_limit > 0 && initial_elevation > upper_limit)) {
can_be_flat = true;
}
const Points3 travel = (
can_be_flat ?
GCode::Impl::Travels::generate_flat_travel(xy_path.points, initial_elevation) :
@@ -3807,6 +3864,7 @@ std::string GCodeGenerator::set_extruder(unsigned int extruder_id, double print_
if (!this->m_config.complete_objects.value) {
gcode += this->m_label_objects.maybe_stop_instance();
}
// prepend retraction on the current extruder
gcode += this->retract_and_wipe(true);
@@ -3976,7 +4034,6 @@ Point GCodeGenerator::gcode_to_point(const Vec2d &point) const
// This function may be called at the very start from toolchange G-code when the extruder is not assigned yet.
pt += m_config.extruder_offset.get_at(extruder->id());
return scaled<coord_t>(pt);
}
} // namespace Slic3r

View File

@@ -456,6 +456,9 @@ private:
// Processor
GCodeProcessor m_processor;
//Y27
bool m_resonance_avoidance;
// Back-pointer to Print (const).
const Print* m_print;
std::string _extrude(

View File

@@ -466,39 +466,42 @@ static std::vector<std::string> s_Preset_print_options {
"wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width",
"mmu_segmented_region_interlocking_depth", "wipe_tower_extruder", "wipe_tower_no_sparse_layers", "wipe_tower_extra_flow", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits",
"perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width"
"wall_distribution_count", "min_feature_size", "min_bead_width",
//B36
,"first_layer_travel_speed"
"first_layer_travel_speed",
//B37
,"first_layer_infill_speed"
"first_layer_infill_speed",
//w11
,"detect_narrow_internal_solid_infill"
"detect_narrow_internal_solid_infill",
//Y21
,"seam_gap"
"seam_gap",
//w16
, "top_one_wall_type"
"top_one_wall_type",
//w17
,"top_area_threshold"
"top_area_threshold",
//w21
,"filter_top_gap_infill"
"filter_top_gap_infill",
//w23
,"only_one_wall_first_layer"
"only_one_wall_first_layer",
//w25
,"slow_down_layers"
"slow_down_layers",
//w26
,"elefant_foot_compensation_layers"
"elefant_foot_compensation_layers",
//w27
,"precise_z_height"
"precise_z_height",
//w28
,"max_bridge_length"
"max_bridge_length",
//w30
,"top_solid_infill_flow_ratio", "bottom_solid_infill_flow_ratio"
"top_solid_infill_flow_ratio", "bottom_solid_infill_flow_ratio",
//w33
,"ironing_pattern"
"ironing_pattern",
//w38
,"overhang_reverse","overhang_reverse_internal_only","overhang_reverse_threshold"
"overhang_reverse", "overhang_reverse_internal_only", "overhang_reverse_threshold",
//w39
,"precise_outer_wall"};
"precise_outer_wall",
//Y27
"resonance_avoidance", "min_resonance_avoidance_speed", "max_resonance_avoidance_speed"
};
static std::vector<std::string> s_Preset_filament_options {
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
@@ -567,8 +570,6 @@ static std::vector<std::string> s_Preset_printer_options {
"bed_exclude_area",
//Y25
"wipe_device",
//Y27
"resonance_avoidance", "min_resonance_avoidance_speed", "max_resonance_avoidance_speed",
//Y16
"chamber_temperature", "auxiliary_fan", "chamber_fan"
};

View File

@@ -228,10 +228,6 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "single_extruder_multi_material"
//Y25
|| opt_key == "wipe_device"
//Y27
|| opt_key == "resonance_avoidance"
|| opt_key == "min_resonance_avoidance_speed"
|| opt_key == "max_resonance_avoidance_speed"
|| opt_key == "temperature"
|| opt_key == "idle_temperature"
|| opt_key == "wipe_tower"

View File

@@ -702,6 +702,30 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionBools{false});
//Y27
def = this->add("resonance_avoidance", coBool);
def->label = L("Resonance avoidance");
def->tooltip = L("By reducing the speed of the outer wall to avoid the resonance zone of the printer, ringing on the surface of the model are avoided.\n"
"Please turn this option off when testing ringing.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("min_resonance_avoidance_speed", coFloat);
def->label = L("Min");
def->tooltip = L("Minimum speed of resonance avoidance.");
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(70));
def = this->add("max_resonance_avoidance_speed", coFloat);
def->label = L("Max");
def->tooltip = L("Maximum speed of resonance avoidance.");
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(120));
// TRN FilamentSettings : "Dynamic fan speeds"
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). "
@@ -3007,30 +3031,6 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(false));
//Y27
def = this->add("resonance_avoidance", coBool);
def->label = L("Resonance avoidance");
def->tooltip = L("By reducing the speed of the outer wall to avoid the resonance zone of the printer, ringing on the surface of the model are avoided. "
"Turn this option off when testing ringing.");
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(true));
def = this->add("min_resonance_avoidance_speed", coFloat);
def->label = L("Min");
def->tooltip = L("Minimum speed of resonance avoidance.");
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(70));
def = this->add("max_resonance_avoidance_speed", coFloat);
def->label = L("Max");
def->tooltip = L("Maximum speed of resonance avoidance.");
def->sidetext = L("mm/s");
def->min = 0;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(115));
def = this->add("single_extruder_multi_material_priming", coBool);
def->label = L("Prime all printing extruders");
def->tooltip = L("If enabled, all printing extruders will be primed at the front edge of the print bed at the start of the print.");

View File

@@ -626,6 +626,10 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionFloatOrPercent, overhang_speed_1))
((ConfigOptionFloatOrPercent, overhang_speed_2))
((ConfigOptionFloatOrPercent, overhang_speed_3))
//Y27
((ConfigOptionBool, resonance_avoidance))
((ConfigOptionFloat, min_resonance_avoidance_speed))
((ConfigOptionFloat, max_resonance_avoidance_speed))
((ConfigOptionBool, external_perimeters_first))
((ConfigOptionBool, extra_perimeters))
((ConfigOptionBool, extra_perimeters_on_overhangs))
@@ -785,10 +789,6 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, single_extruder_multi_material))
//Y25
((ConfigOptionBool, wipe_device))
//Y27
((ConfigOptionBool, resonance_avoidance))
((ConfigOptionFloat, min_resonance_avoidance_speed))
((ConfigOptionFloat, max_resonance_avoidance_speed))
((ConfigOptionBool, single_extruder_multi_material_priming))
((ConfigOptionBool, wipe_tower_no_sparse_layers))
((ConfigOptionString, toolchange_gcode))

View File

@@ -253,6 +253,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
toggle_field("overhang_speed_" + std::to_string(i), config->opt_bool("enable_dynamic_overhang_speeds"));
}
//Y27
bool resonance_avoidance = config->opt_bool("resonance_avoidance");
toggle_field("min_resonance_avoidance_speed", resonance_avoidance);
toggle_field("max_resonance_avoidance_speed", resonance_avoidance);
bool have_infill = config->option<ConfigOptionPercent>("fill_density")->value > 0;
// infill_extruder uses the same logic as in Print::extruders()
for (auto el : { "fill_pattern", "infill_every_layers", "infill_only_where_needed",

View File

@@ -1625,6 +1625,14 @@ void TabPrint::build()
optgroup->append_single_option_line("overhang_speed_2");
optgroup->append_single_option_line("overhang_speed_3");
//Y27
optgroup = page->new_optgroup(L("Resonance Avoidance"));
optgroup->append_single_option_line("resonance_avoidance");
line = { L("Resonance Avoidance Speed"), "" };
line.append_option(optgroup->get_option("min_resonance_avoidance_speed"));
line.append_option(optgroup->get_option("max_resonance_avoidance_speed"));
optgroup->append_line(line);
optgroup = page->new_optgroup(L("Speed for non-print moves"));
optgroup->append_single_option_line("travel_speed");
optgroup->append_single_option_line("travel_speed_z");
@@ -2738,12 +2746,6 @@ void TabPrinter::build_fff()
Option option(def, "extruders_count");
optgroup->append_single_option_line(option);
optgroup->append_single_option_line("single_extruder_multi_material");
//Y27
optgroup->append_single_option_line("resonance_avoidance");
Line line = { L("Resonance Avoidance Speed"), "" };
line.append_option(optgroup->get_option("min_resonance_avoidance_speed"));
line.append_option(optgroup->get_option("max_resonance_avoidance_speed"));
optgroup->append_line(line);
optgroup->m_on_change = [this, optgroup_wk = ConfigOptionsGroupWkp(optgroup)](t_config_option_key opt_key, boost::any value) {
auto optgroup_sh = optgroup_wk.lock();
@@ -3615,10 +3617,6 @@ void TabPrinter::toggle_options()
toggle_option("toolchange_gcode", have_multiple_extruders);
if (m_active_page->title() == "General") {
toggle_option("single_extruder_multi_material", have_multiple_extruders);
//Y27
bool resonance_avoidance = m_config->opt_bool("resonance_avoidance");
toggle_option("min_resonance_avoidance_speed", resonance_avoidance);
toggle_option("max_resonance_avoidance_speed", resonance_avoidance);
bool is_marlin_flavor = flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware;
// Disable silent mode for non-marlin firmwares.