diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2fca25c96f..0411944358 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1147,10 +1147,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Emit machine envelope limits for the Marlin firmware. this->print_machine_envelope(file, print); - // Disable fan. - if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id)) - file.write(m_writer.set_fan(0)); - // Let the start-up script prime the 1st printing tool. m_placeholder_parser.set("initial_tool", initial_extruder_id); m_placeholder_parser.set("initial_extruder", initial_extruder_id); @@ -1667,23 +1663,25 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) int(print.config().machine_max_feedrate_e.values.front() * factor + 0.5), factor == 60 ? "mm / min" : "mm / sec"); - // Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about - // backwards compatibility: https://github.com/prusa3d/PrusaSlicer/issues/1089 - // Legacy Marlin should export travel acceleration the same as printing acceleration. - // MarlinFirmware has the two separated. - int travel_acc = flavor == gcfMarlinLegacy - ? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5) - : int(print.config().machine_max_acceleration_travel.values.front() + 0.5); - // Retract acceleration not accepted in M204 in RRF + // Now M204 - acceleration. This one is quite hairy... if (flavor == gcfRepRapFirmware) + // Uses M204 P[print] T[travel] file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n", int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), - travel_acc); - else - file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", + int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); + else if (flavor == gcfMarlinLegacy) + // Legacy Marlin uses M204 S[print] T[retract] + file.write_format("M204 " + "S%d T%d ; sets acceleration (S) and retract acceleration (R), mm/sec^2\n", + int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), + int(print.config().machine_max_acceleration_retracting.values.front() + 0.5)); + else if (flavor == gcfMarlinFirmware) + // New Marlin uses M204 P[print] R[retract] T[travel] + file.write_format("M204 " + "P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), - travel_acc); + int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); + else + assert(false); assert(is_decimal_separator_point()); file.write_format(flavor == gcfRepRapFirmware @@ -1710,17 +1708,18 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) // M190 - Set Extruder Temperature and Wait void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) { + bool autoemit = print.config().autoemit_temperature_commands; // Initial bed temperature based on the first extruder. int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id); // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode); - if (temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) + if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if // the custom start G-code emited these. std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait); - if (! temp_set_by_gcode) + if (autoemit && ! temp_set_by_gcode) file.write(set_temp_gcode); } @@ -1731,13 +1730,14 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p // RepRapFirmware: G10 Sxx void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) { + bool autoemit = print.config().autoemit_temperature_commands; // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; bool include_g10 = print.config().gcode_flavor == gcfRepRapFirmware; - if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) { + if (! autoemit || custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) { // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code. int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id); - if (temp_by_gcode >= 0 && temp_by_gcode < 1000) + if (autoemit && temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; m_writer.set_temperature(temp, wait, first_printing_extruder_id); } else { @@ -2547,7 +2547,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr } // reset acceleration - gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5)); if (m_wipe.enable) { m_wipe.path = paths.front().polyline; @@ -2633,7 +2633,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s } } // reset acceleration - gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); return gcode; } @@ -2659,7 +2659,7 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string_view description m_wipe.path.reverse(); } // reset acceleration - gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); return gcode; } @@ -2802,7 +2802,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de } else { acceleration = m_config.default_acceleration.value; } - gcode += m_writer.set_acceleration((unsigned int)floor(acceleration + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)floor(acceleration + 0.5)); } // calculate extrusion length per distance unit @@ -3071,8 +3071,18 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string // use G1 because we rely on paths being straight (G0 may make round paths) if (travel.size() >= 2) { + + gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5)); + for (size_t i = 1; i < travel.size(); ++ i) gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment); + + if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) { + // In case that this flavor does not support separate print and travel acceleration, + // reset acceleration to default. + gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5)); + } + this->set_last_pos(travel.points.back()); } return gcode; diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 71d723ca32..a2c8675050 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -3,6 +3,7 @@ #include "libslic3r/Print.hpp" #include "libslic3r/LocalesUtils.hpp" #include "libslic3r/format.hpp" +#include "libslic3r/GCodeWriter.hpp" #include "GCodeProcessor.hpp" #include @@ -568,10 +569,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.filament_cost[i] = static_cast(config.filament_cost.get_at(i)); } - if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware) && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) { + if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper) + && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) { m_time_processor.machine_limits = reinterpret_cast(config); - if (m_flavor == gcfMarlinLegacy) { - // Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead. + if (m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper) { + // Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead. m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding; } if (m_flavor == gcfRepRapFirmware) { @@ -609,7 +611,12 @@ for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode:: float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i); m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration; m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION; + float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i); + if ( ! GCodeWriter::supports_separate_travel_acceleration(config.gcode_flavor.value) || config.machine_limits_usage.value != MachineLimitsUsage::EmitToGCode) { + // Only clamp travel acceleration when it is accessible in machine limits. + max_travel_acceleration = 0; + } m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration; m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION; } @@ -788,7 +795,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (machine_limits_usage != nullptr) use_machine_limits = machine_limits_usage->value != MachineLimitsUsage::Ignore; - if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware)) { + if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper)) { const ConfigOptionFloats* machine_max_acceleration_x = config.option("machine_max_acceleration_x"); if (machine_max_acceleration_x != nullptr) m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values; @@ -846,8 +853,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values; - // Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead. - const ConfigOptionFloats* machine_max_acceleration_travel = config.option(m_flavor == gcfMarlinLegacy + // Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead. + const ConfigOptionFloats* machine_max_acceleration_travel = config.option((m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper) ? "machine_max_acceleration_extruding" : "machine_max_acceleration_travel"); if (machine_max_acceleration_travel != nullptr) @@ -885,7 +892,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION; } - if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { + if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { // No Klipper here, it does not support silent mode. const ConfigOptionBool* silent_mode = config.option("silent_mode"); if (silent_mode != nullptr) { if (silent_mode->value && m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1) @@ -3244,7 +3251,7 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line) { - if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware) + if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware && m_flavor != gcfKlipper) return; if (line.has('B')) diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 58af2da489..7fdbb69159 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -93,9 +93,12 @@ public: } WipeTowerWriter& disable_linear_advance() { - m_gcode += (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware - ? (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n") - : std::string("M900 K0\n")); + if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) + m_gcode += (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n"); + else if (m_gcode_flavor == gcfKlipper) + m_gcode += "SET_PRESSURE_ADVANCE ADVANCE=0\n"; + else + m_gcode += "M900 K0\n"; return *this; } @@ -363,6 +366,8 @@ public: // Set digital trimpot motor WipeTowerWriter& set_extruder_trimpot(int current) { + if (m_gcode_flavor == gcfKlipper) + return *this; if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) m_gcode += "M906 E"; else diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index c2caf57664..5080fabb4c 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -15,6 +15,12 @@ namespace Slic3r { +// static +bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor) +{ + return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware); +} + void GCodeWriter::apply_print_config(const PrintConfig &print_config) { this->config.apply(print_config, true); @@ -25,6 +31,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config) || print_config.gcode_flavor.value == gcfRepRapFirmware; m_max_acceleration = static_cast(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ? print_config.machine_max_acceleration_extruding.values.front() : 0)); + m_max_travel_acceleration = static_cast(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) ? + print_config.machine_max_acceleration_travel.values.front() : 0)); } void GCodeWriter::set_extruders(std::vector extruder_ids) @@ -53,6 +61,7 @@ std::string GCodeWriter::preamble() FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfMarlinLegacy) || FLAVOR_IS(gcfMarlinFirmware) || + FLAVOR_IS(gcfKlipper) || FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepetier) || FLAVOR_IS(gcfSmoothie)) @@ -154,36 +163,31 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait return gcode.str(); } -std::string GCodeWriter::set_acceleration(unsigned int acceleration) +std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration) { // Clamp the acceleration to the allowed maximum. - if (m_max_acceleration > 0 && acceleration > m_max_acceleration) + if (type == Acceleration::Print && m_max_acceleration > 0 && acceleration > m_max_acceleration) acceleration = m_max_acceleration; + if (type == Acceleration::Travel && m_max_travel_acceleration > 0 && acceleration > m_max_travel_acceleration) + acceleration = m_max_travel_acceleration; - if (acceleration == 0 || acceleration == m_last_acceleration) + // Are we setting travel acceleration for a flavour that supports separate travel and print acc? + bool separate_travel = (type == Acceleration::Travel && supports_separate_travel_acceleration(this->config.gcode_flavor)); + + auto& last_value = separate_travel ? m_last_travel_acceleration : m_last_acceleration ; + if (acceleration == 0 || acceleration == last_value) return std::string(); - m_last_acceleration = acceleration; + last_value = acceleration; std::ostringstream gcode; - if (FLAVOR_IS(gcfRepetier)) { - // M201: Set max printing acceleration - gcode << "M201 X" << acceleration << " Y" << acceleration; - if (this->config.gcode_comments) gcode << " ; adjust acceleration"; - gcode << "\n"; - // M202: Set max travel acceleration - gcode << "M202 X" << acceleration << " Y" << acceleration; - } else if (FLAVOR_IS(gcfRepRapFirmware)) { - // M204: Set default acceleration - gcode << "M204 P" << acceleration; - } else if (FLAVOR_IS(gcfMarlinFirmware)) { - // This is new MarlinFirmware with separated print/retraction/travel acceleration. - // Use M204 P, we don't want to override travel acc by M204 S (which is deprecated anyway). - gcode << "M204 P" << acceleration; - } else { - // M204: Set default acceleration + if (FLAVOR_IS(gcfRepetier)) + gcode << (separate_travel ? "M202 X" : "M201 X") << acceleration << " Y" << acceleration; + else if (FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfMarlinFirmware)) + gcode << (separate_travel ? "M204 T" : "M204 P") << acceleration; + else gcode << "M204 S" << acceleration; - } + if (this->config.gcode_comments) gcode << " ; adjust acceleration"; gcode << "\n"; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 6c36c0d3ac..9e5fce7023 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -43,7 +43,8 @@ public: std::string postamble() const; std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; std::string set_bed_temperature(unsigned int temperature, bool wait = false); - std::string set_acceleration(unsigned int acceleration); + std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); } + std::string set_travel_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Travel, acceleration); } std::string reset_e(bool force = false); std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const; // return false if this extruder was already selected @@ -69,6 +70,9 @@ public: std::string unlift(); Vec3d get_position() const { return m_pos; } + // Returns whether this flavor supports separate print and travel acceleration. + static bool supports_separate_travel_acceleration(GCodeFlavor flavor); + // To be called by the CoolingBuffer from another thread. static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed); // To be called by the main thread. It always emits the G-code, it does not remember the previous state. @@ -81,17 +85,26 @@ private: std::string m_extrusion_axis; bool m_single_extruder_multi_material; Extruder* m_extruder; - unsigned int m_last_acceleration; + unsigned int m_last_acceleration = (unsigned int)(-1); + unsigned int m_last_travel_acceleration = (unsigned int)(-1); // only used for flavors supporting separate print/travel acc // Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware. // If set to zero, the limit is not in action. unsigned int m_max_acceleration; + unsigned int m_max_travel_acceleration; + unsigned int m_last_bed_temperature; bool m_last_bed_temperature_reached; double m_lifted; Vec3d m_pos = Vec3d::Zero(); + enum class Acceleration { + Travel, + Print + }; + std::string _travel_to_z(double z, const std::string &comment); std::string _retract(double length, double restart_extra, const std::string &comment); + std::string set_acceleration_internal(Acceleration type, unsigned int acceleration); }; class GCodeFormatter { diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 3598d36aed..a584920622 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -434,7 +434,7 @@ static std::vector s_Preset_print_options { "enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", - "external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", + "external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", "travel_acceleration", "bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", "min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", @@ -482,7 +482,7 @@ static std::vector s_Preset_machine_limits_options { }; static std::vector s_Preset_printer_options { - "printer_technology", + "printer_technology", "autoemit_temperature_commands", "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 0dd20ea937..67407e5914 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -58,6 +58,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n // Cache the plenty of parameters, which influence the G-code generator only, // or they are only notes not influencing the generated G-code. static std::unordered_set steps_gcode = { + "autoemit_temperature_commands", "avoid_crossing_perimeters", "avoid_crossing_perimeters_max_detour", "bed_shape", @@ -137,6 +138,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "start_filament_gcode", "toolchange_gcode", "top_solid_infill_acceleration", + "travel_acceleration", "thumbnails", "thumbnails_format", "use_firmware_retraction", @@ -501,6 +503,10 @@ std::string Print::validate(std::string* warning) const return _u8L("The Spiral Vase option can only be used when printing single material objects."); } + if (m_config.machine_limits_usage == MachineLimitsUsage::EmitToGCode && m_config.gcode_flavor == gcfKlipper) + return L("Machine limits cannot be emitted to G-Code when Klipper firmware flavor is used. " + "Change the value of machine_limits_usage."); + // Cache of layer height profiles for checking: // 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports. // 2) Whether layer height is constant for Organic supports. @@ -557,8 +563,9 @@ std::string Print::validate(std::string* warning) const } if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && - m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware) - return _u8L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); + m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && + m_config.gcode_flavor != gcfMarlinFirmware && m_config.gcode_flavor != gcfKlipper) + return _u8L("The Wipe Tower is currently only supported for the Marlin, Klipper, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); if (! m_config.use_relative_e_distances) return _u8L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); if (m_config.ooze_prevention && m_config.single_extruder_multi_material) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ed1a08b57f..0089ce4571 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -48,6 +48,7 @@ static const t_config_enum_values s_keys_map_GCodeFlavor { { "makerware", gcfMakerWare }, { "marlin", gcfMarlinLegacy }, { "marlin2", gcfMarlinFirmware }, + { "klipper", gcfKlipper }, { "sailfish", gcfSailfish }, { "smoothie", gcfSmoothie }, { "mach3", gcfMach3 }, @@ -67,6 +68,7 @@ static const t_config_enum_values s_keys_map_PrintHostType { { "prusalink", htPrusaLink }, { "prusaconnect", htPrusaConnect }, { "octoprint", htOctoPrint }, + { "mainsail", htMainSail }, { "duet", htDuet }, { "flashair", htFlashAir }, { "astrobox", htAstroBox }, @@ -1406,6 +1408,7 @@ void PrintConfigDef::init_fff_params() { "makerware", "MakerWare (MakerBot)" }, { "marlin", "Marlin (legacy)" }, { "marlin2", "Marlin 2" }, + { "klipper", "Klipper" }, { "sailfish", "Sailfish (MakerBot)" }, { "mach3", "Mach3/LinuxCNC" }, { "machinekit", "Machinekit" }, @@ -1463,7 +1466,15 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); - + + def = this->add("travel_acceleration", coFloat); + def->label = L("Travel"); + def->tooltip = L("This is the acceleration your printer will use for travel moves. Set zero to disable " + "acceleration control for travel."); + def->sidetext = L("mm/s²"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0)); def = this->add("infill_every_layers", coInt); def->label = L("Combine infill every"); @@ -1792,9 +1803,7 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_max_acceleration_extruding", coFloats); def->full_label = L("Maximum acceleration when extruding"); def->category = L("Machine limits"); - def->tooltip = L("Maximum acceleration when extruding (M204 P)\n\n" - "Marlin (legacy) firmware flavor will use this also " - "as travel acceleration (M204 T)."); + def->tooltip = L("Maximum acceleration when extruding"); def->sidetext = L("mm/s²"); def->min = 0; def->mode = comAdvanced; @@ -1805,7 +1814,8 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_max_acceleration_retracting", coFloats); def->full_label = L("Maximum acceleration when retracting"); def->category = L("Machine limits"); - def->tooltip = L("Maximum acceleration when retracting (M204 R)"); + def->tooltip = L("Maximum acceleration when retracting.\n\n" + "Not used for RepRapFirmware, which does not support it."); def->sidetext = L("mm/s²"); def->min = 0; def->mode = comAdvanced; @@ -1815,7 +1825,7 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_max_acceleration_travel", coFloats); def->full_label = L("Maximum acceleration for travel moves"); def->category = L("Machine limits"); - def->tooltip = L("Maximum acceleration for travel moves (M204 T)"); + def->tooltip = L("Maximum acceleration for travel moves."); def->sidetext = L("mm/s²"); def->min = 0; def->mode = comAdvanced; @@ -1944,6 +1954,7 @@ void PrintConfigDef::init_fff_params() { "prusalink", "PrusaLink" }, { "prusaconnect", "PrusaConnect" }, { "octoprint", "OctoPrint" }, + { "mainsail", "Mainsail/Fluidd" }, { "duet", "Duet" }, { "flashair", "FlashAir" }, { "astrobox", "AstroBox" }, @@ -2478,15 +2489,25 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInt(-5)); + def = this->add("autoemit_temperature_commands", coBool); + def->label = L("Emit temperature commands automatically"); + def->tooltip = L("When enabled, PrusaSlicer will check whether your Custom Start G-Code contains M104 or M190. " + "If so, the temperatures will not be emitted automatically so you're free to customize " + "the order of heating commands and other custom actions. Note that you can use " + "placeholder variables for all PrusaSlicer settings, so you can put " + "a \"M109 S[first_layer_temperature]\" command wherever you want.\n" + "If your Custom Start G-Code does NOT contain M104 or M190, " + "PrusaSlicer will execute the Start G-Code after bed reached its target temperature " + "and extruder just started heating.\n\n" + "When disabled, PrusaSlicer will NOT emit commands to heat up extruder and bed, " + "leaving both to Custom Start G-Code."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("start_gcode", coString); def->label = L("Start G-code"); - def->tooltip = L("This start procedure is inserted at the beginning, after bed has reached " - "the target temperature and extruder just started heating, and before extruder " - "has finished heating. If PrusaSlicer detects M104 or M190 in your custom codes, " - "such commands will not be prepended automatically so you're free to customize " - "the order of heating commands and other custom actions. Note that you can use " - "placeholder variables for all PrusaSlicer settings, so you can put " - "a \"M109 S[first_layer_temperature]\" command wherever you want."); + def->tooltip = L("This start procedure is inserted at the beginning, possibly prepended by " + "temperature-changing commands. See 'autoemit_temperature_commands'."); def->multiline = true; def->full_width = true; def->height = 12; @@ -4413,8 +4434,9 @@ std::string validate(const FullPrintConfig &cfg) cfg.gcode_flavor.value != gcfMarlinLegacy && cfg.gcode_flavor.value != gcfMarlinFirmware && cfg.gcode_flavor.value != gcfMachinekit && - cfg.gcode_flavor.value != gcfRepetier) - return "--use-firmware-retraction is only supported by Marlin, Smoothie, RepRapFirmware, Repetier and Machinekit firmware"; + cfg.gcode_flavor.value != gcfRepetier && + cfg.gcode_flavor.value != gcfKlipper) + return "--use-firmware-retraction is only supported by Marlin, Klipper, Smoothie, RepRapFirmware, Repetier and Machinekit firmware"; if (cfg.use_firmware_retraction.value) for (unsigned char wipe : cfg.wipe.values) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 52924bf91f..d29afe5e71 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -32,7 +32,7 @@ namespace Slic3r { enum GCodeFlavor : unsigned char { - gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfSailfish, gcfMach3, gcfMachinekit, + gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfKlipper, gcfSailfish, gcfMach3, gcfMachinekit, gcfSmoothie, gcfNoExtrusion, }; @@ -44,7 +44,7 @@ enum class MachineLimitsUsage { }; enum PrintHostType { - htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS + htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htMainSail }; enum AuthorizationType { @@ -661,6 +661,7 @@ PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE( GCodeConfig, + ((ConfigOptionBool, autoemit_temperature_commands)) ((ConfigOptionString, before_layer_gcode)) ((ConfigOptionString, between_objects_gcode)) ((ConfigOptionFloats, deretract_speed)) @@ -815,6 +816,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionPoints, thumbnails)) ((ConfigOptionEnum, thumbnails_format)) ((ConfigOptionFloat, top_solid_infill_acceleration)) + ((ConfigOptionFloat, travel_acceleration)) ((ConfigOptionBools, wipe)) ((ConfigOptionBool, wipe_tower)) ((ConfigOptionFloat, wipe_tower_x)) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 1bc2280d5f..4c5b0fd8e2 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -256,7 +256,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) bool have_default_acceleration = config->opt_float("default_acceleration") > 0; for (auto el : { "perimeter_acceleration", "infill_acceleration", "top_solid_infill_acceleration", - "solid_infill_acceleration", "external_perimeter_acceleration" + "solid_infill_acceleration", "external_perimeter_acceleration", "bridge_acceleration", "first_layer_acceleration" }) toggle_field(el, have_default_acceleration); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6382fb0aed..b095d4ea28 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -7,6 +7,7 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" +#include "libslic3r/GCodeWriter.hpp" #include "slic3r/Utils/Http.hpp" #include "slic3r/Utils/PrintHost.hpp" @@ -1573,6 +1574,7 @@ void TabPrint::build() optgroup->append_single_option_line("bridge_acceleration"); optgroup->append_single_option_line("first_layer_acceleration"); optgroup->append_single_option_line("first_layer_acceleration_over_raft"); + optgroup->append_single_option_line("travel_acceleration"); optgroup->append_single_option_line("default_acceleration"); optgroup = page->new_optgroup(L("Autospeed (advanced)")); @@ -2259,6 +2261,12 @@ void TabPrinter::build_print_host_upload_group(Page* page) optgroup->append_line(line); } +static wxString get_info_klipper_string() +{ + return _L("Emitting machine limits to G-code is not supported with Klipper G-code flavor.\n" + "The option was switched to \"Use for time estimate\"."); +} + void TabPrinter::build_fff() { if (!m_pages.empty()) @@ -2376,14 +2384,42 @@ void TabPrinter::build_fff() } } if (opt_key == "gcode_flavor") { - const int flavor = boost::any_cast(value); - bool supports_travel_acceleration = (flavor == int(gcfMarlinFirmware) || flavor == int(gcfRepRapFirmware)); - bool supports_min_feedrates = (flavor == int(gcfMarlinFirmware) || flavor == int(gcfMarlinLegacy)); + const GCodeFlavor flavor = static_cast(boost::any_cast(value)); + bool supports_travel_acceleration = GCodeWriter::supports_separate_travel_acceleration(flavor); + bool supports_min_feedrates = (flavor == gcfMarlinFirmware || flavor == gcfMarlinLegacy); if (supports_travel_acceleration != m_supports_travel_acceleration || supports_min_feedrates != m_supports_min_feedrates) { m_rebuild_kinematics_page = true; m_supports_travel_acceleration = supports_travel_acceleration; m_supports_min_feedrates = supports_min_feedrates; } + + const bool is_emit_to_gcode = m_config->option("machine_limits_usage")->getInt() == static_cast(MachineLimitsUsage::EmitToGCode); + if ((flavor == gcfKlipper && is_emit_to_gcode) || (!m_supports_min_feedrates && m_use_silent_mode)) { + DynamicPrintConfig new_conf = *m_config; + wxString msg; + + if (flavor == gcfKlipper && is_emit_to_gcode) { + msg = get_info_klipper_string(); + + auto machine_limits_usage = static_cast*>(m_config->option("machine_limits_usage")->clone()); + machine_limits_usage->value = MachineLimitsUsage::TimeEstimateOnly; + new_conf.set_key_value("machine_limits_usage", machine_limits_usage); + } + + if (!m_supports_min_feedrates && m_use_silent_mode) { + if (!msg.IsEmpty()) + msg += "\n\n"; + msg += _L("Stealth mode for machine limits to G-code is not supported with selected G-code flavor.\n" + "The Stealth mode was suppressed."); + + auto silent_mode = static_cast(m_config->option("silent_mode")->clone()); + silent_mode->value = false; + new_conf.set_key_value("silent_mode", silent_mode); + } + + InfoDialog(parent(), _L("G-code flavor is switched"), msg).ShowModal(); + load_config(new_conf); + } } build_unregular_pages(); update_dirty(); @@ -2410,6 +2446,9 @@ void TabPrinter::build_fff() option.opt.height = 3 * gcode_field_height;//150; optgroup->append_single_option_line(option); + optgroup = page->new_optgroup(L("Start G-Code options")); + optgroup->append_single_option_line("autoemit_temperature_commands"); + optgroup = page->new_optgroup(L("End G-code"), 0); optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup_title, opt_key, value); @@ -2629,6 +2668,27 @@ PageShp TabPrinter::build_kinematics_page() optgroup->append_line(line); } + optgroup->m_on_change = [this](const t_config_option_key& opt_key, boost::any value) + { + if (opt_key == "machine_limits_usage" && + static_cast(boost::any_cast(value)) == MachineLimitsUsage::EmitToGCode && + static_cast(m_config->option("gcode_flavor")->getInt()) == gcfKlipper) + { + DynamicPrintConfig new_conf = *m_config; + + auto machine_limits_usage = static_cast*>(m_config->option("machine_limits_usage")->clone()); + machine_limits_usage->value = MachineLimitsUsage::TimeEstimateOnly; + + new_conf.set_key_value("machine_limits_usage", machine_limits_usage); + + InfoDialog(parent(), wxEmptyString, get_info_klipper_string()).ShowModal(); + load_config(new_conf); + } + + update_dirty(); + update(); + }; + if (m_use_silent_mode) { // Legend for OptionsGroups auto optgroup = page->new_optgroup(""); @@ -2865,7 +2925,7 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/) { size_t n_before_extruders = 2; // Count of pages before Extruder pages auto flavor = m_config->option>("gcode_flavor")->value; - bool show_mach_limits = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware); + bool show_mach_limits = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware || flavor == gcfKlipper); /* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages * and be cause of application crash, when try to change Preset in moment, @@ -3101,7 +3161,8 @@ void TabPrinter::toggle_options() if (m_active_page->title() == "Machine limits" && m_machine_limits_description_line) { assert(flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware - || flavor == gcfRepRapFirmware); + || flavor == gcfRepRapFirmware + || flavor == gcfKlipper); const auto *machine_limits_usage = m_config->option>("machine_limits_usage"); bool enabled = machine_limits_usage->value != MachineLimitsUsage::Ignore; bool silent_mode = m_config->opt_bool("silent_mode"); @@ -4510,6 +4571,8 @@ bool Tab::validate_custom_gcodes() if (!opt_group->is_activated()) break; std::string key = opt_group->opt_map().begin()->first; + if (key == "autoemit_temperature_commands") + continue; valid &= validate_custom_gcode(opt_group->title, boost::any_cast(opt_group->get_value(key))); if (!valid) break; diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index fd558eb2ce..82c07f6f45 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -139,6 +139,16 @@ protected: void set_http_post_header_args(Http& http, PrintHostPostUploadAction post_action) const override; }; + +class Mainsail : public OctoPrint +{ +public: + Mainsail(DynamicPrintConfig* config) : OctoPrint(config) {} + ~Mainsail() override = default; + + const char* get_name() const override { return "Mainsail/Fluidd"; } +}; + } #endif diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index c8f0e34bca..5cb3187150 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -54,6 +54,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) case htPrusaLink: return new PrusaLink(config); case htPrusaConnect: return new PrusaConnect(config); case htMKS: return new MKS(config); + case htMainSail: return new Mainsail(config); default: return nullptr; } } else {