Skip to content

Commit

Permalink
[FEATURE] Enable pre-heating of toolheads for all toolchangers
Browse files Browse the repository at this point in the history
  • Loading branch information
mjonuschat committed Dec 30, 2024
1 parent ae0b025 commit e8968e9
Show file tree
Hide file tree
Showing 10 changed files with 78 additions and 29 deletions.
37 changes: 23 additions & 14 deletions src/libslic3r/GCode/GCodeProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,11 +627,14 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_producer = EProducer::PrusaSlicer;
m_flavor = config.gcode_flavor;

m_result.backtrace_enabled = is_XL_printer(config);

size_t extruders_count = config.nozzle_diameter.values.size();
m_result.extruders_count = extruders_count;

m_is_XL_printer = is_XL_printer(config);
m_single_extruder_multi_material = config.single_extruder_multi_material;
m_preheat_time = config.preheat_time;
m_preheat_steps = std::max<int>(config.preheat_steps, 1);

m_extruder_offsets.resize(extruders_count);
m_extruder_colors.resize(extruders_count);
m_result.filament_diameters.resize(extruders_count);
Expand All @@ -640,7 +643,8 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_extruder_temps.resize(extruders_count);
m_extruder_temps_config.resize(extruders_count);
m_extruder_temps_first_layer_config.resize(extruders_count);
m_is_XL_printer = is_XL_printer(config);

m_result.backtrace_enabled = m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && extruders_count > 1));

for (size_t i = 0; i < extruders_count; ++ i) {
m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(i).cast<float>().eval(), 0.f);
Expand Down Expand Up @@ -682,8 +686,6 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
m_time_processor.filament_unload_times[i] = static_cast<float>(config.filament_unload_time.values[i]);
}

m_single_extruder_multi_material = config.single_extruder_multi_material;

// With MM setups like Prusa MMU2, the filaments may be expected to be parked at the beginning.
// Remember the parking position so the initial load is not included in filament estimate.
if (m_single_extruder_multi_material && extruders_count > 1 && config.wipe_tower) {
Expand Down Expand Up @@ -1075,6 +1077,8 @@ void GCodeProcessor::reset()
m_kissslicer_toolchange_time_correction = 0.0f;

m_single_extruder_multi_material = false;
m_preheat_time = 0.f;
m_preheat_steps = 1;
}

static inline const char* skip_whitespaces(const char *begin, const char *end) {
Expand Down Expand Up @@ -4315,13 +4319,19 @@ void GCodeProcessor::post_process()
// line inserter
[tool_number, this](unsigned int id, const std::vector<float>& time_diffs) {
const int temperature = int(m_layer_id != 1 ? m_extruder_temps_config[tool_number] : m_extruder_temps_first_layer_config[tool_number]);
std::string out = "M104.1 T" + std::to_string(tool_number);
if (time_diffs.size() > 0)
out += " P" + std::to_string(int(std::round(time_diffs[0])));
if (time_diffs.size() > 1)
out += " Q" + std::to_string(int(std::round(time_diffs[1])));
out += " S" + std::to_string(temperature) + "\n";
return out;
if (m_is_XL_printer) {
std::string out = "M104.1 T" + std::to_string(tool_number);
if (time_diffs.size() > 0)
out += " P" + std::to_string(int(std::round(time_diffs[0])));
if (time_diffs.size() > 1)
out += " Q" + std::to_string(int(std::round(time_diffs[1])));
out += " S" + std::to_string(temperature) + "\n";
return out;
} else {
std::string comment = "preheat T" + std::to_string(tool_number) +
" time: " + std::to_string((int) std::round(time_diffs[0])) + "s";
return GCodeWriter::set_temperature(temperature, m_flavor, false, tool_number, comment);
}
},
// line replacer
[this, tool_number](const std::string& line) {
Expand All @@ -4346,7 +4356,7 @@ void GCodeProcessor::post_process()

unsigned int line_id = 0;
// Backtrace data for Tx gcode lines
static const ExportLines::Backtrace backtrace_T = { 120.0f, 10 };
static const ExportLines::Backtrace backtrace_T = { m_preheat_time, static_cast<unsigned int>(m_preheat_steps) };
// In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed
// to flush the backtrace cache accordingly
float max_backtrace_time = 120.0f;
Expand Down Expand Up @@ -4766,4 +4776,3 @@ double GCodeProcessor::extract_absolute_position_on_axis(Axis axis, const GCodeR
}

} /* namespace Slic3r */

4 changes: 2 additions & 2 deletions src/libslic3r/GCode/GCodeProcessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,8 @@ namespace Slic3r {
size_t m_last_default_color_id;
float m_kissslicer_toolchange_time_correction;
bool m_single_extruder_multi_material;
float m_preheat_time;
int m_preheat_steps;

enum class EProducer
{
Expand Down Expand Up @@ -784,5 +786,3 @@ namespace Slic3r {
} /* namespace Slic3r */

#endif /* slic3r_GCodeProcessor_hpp_ */


35 changes: 22 additions & 13 deletions src/libslic3r/GCode/GCodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,48 +107,57 @@ std::string GCodeWriter::postamble() const
return gcode.str();
}

std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, int tool) const
std::string GCodeWriter::set_temperature(unsigned int temperature, GCodeFlavor flavor, bool wait, int tool, std::string comment)
{
if (wait && (FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)))
if (wait && (flavor == gcfMakerWare || flavor == gcfSailfish))
return {};

std::string_view code, comment;
if (wait && FLAVOR_IS_NOT(gcfTeacup) && FLAVOR_IS_NOT(gcfRepRapFirmware)) {
std::string_view code;
if (wait && flavor != gcfTeacup && flavor != gcfRepRapFirmware) {
code = "M109"sv;
comment = "set temperature and wait for it to be reached"sv;
if(comment.empty())
comment = "set temperature and wait for it to be reached"sv;
} else {
if (FLAVOR_IS(gcfRepRapFirmware)) { // M104 is deprecated on RepRapFirmware
if (flavor == gcfRepRapFirmware) { // M104 is deprecated on RepRapFirmware
code = "G10"sv;
} else {
code = "M104"sv;
}
comment = "set temperature"sv;
if(comment.empty())
comment = "set temperature"sv;
}

std::ostringstream gcode;
gcode << code << " ";
if (FLAVOR_IS(gcfMach3) || FLAVOR_IS(gcfMachinekit)) {
if (flavor == gcfMach3 || flavor == gcfMachinekit) {
gcode << "P";
} else {
gcode << "S";
}
gcode << temperature;
bool multiple_tools = this->multiple_extruders && ! m_single_extruder_multi_material;
if (tool != -1 && (multiple_tools || FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish) || FLAVOR_IS(gcfRepRapFirmware)) ) {
if (FLAVOR_IS(gcfRepRapFirmware)) {
if (tool != -1) {
if (flavor == gcfRepRapFirmware) {
gcode << " P" << tool;
} else {
gcode << " T" << tool;
}
}
gcode << " ; " << comment << "\n";

if ((FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepRapFirmware)) && wait)
if ((flavor == gcfTeacup || flavor == gcfRepRapFirmware) && wait)
gcode << "M116 ; wait for temperature to be reached\n";

return gcode.str();
}

std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, int tool) const
{
// set tool to -1 to make sure we won't emit T parameter for single extruder or SEMM
if (!this->multiple_extruders || m_single_extruder_multi_material)
tool = -1;
return set_temperature(temperature, this->config.gcode_flavor, wait, tool);
}

std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait)
{
if (temperature == m_last_bed_temperature && (! wait || m_last_bed_temperature_reached))
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/GCode/GCodeWriter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class GCodeWriter {
}
std::string preamble();
std::string postamble() const;
static std::string set_temperature(unsigned int temperature, GCodeFlavor flavor, bool wait = false, int tool = -1, std::string comment = std::string());
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_chamber_temperature(unsigned int temperature, bool wait, bool accurate) const;
Expand Down
3 changes: 3 additions & 0 deletions src/libslic3r/Preset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,9 @@ static std::vector<std::string> s_Preset_print_options {
"top_layer_flow_ratio",

"print_extrusion_multiplier",

"preheat_time",
"preheat_steps",
};

static std::vector<std::string> s_Preset_filament_options {
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"solid_infill_minimum_cruise_ratio",
"solid_infill_jerk",
"standby_temperature_delta",
"preheat_time",
"preheat_steps",
"start_gcode",
"start_filament_gcode",
"toolchange_gcode",
Expand Down
19 changes: 19 additions & 0 deletions src/libslic3r/PrintConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3422,6 +3422,25 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert;
def->set_default_value(new ConfigOptionBool(true));

def = this->add("preheat_time", coFloat);
def->label = L("Preheat time");
def->tooltip = L("To reduce the waiting time after tool change, the next tool can be preheated while the current "
"tool is still in use. This setting specifies the time in seconds to preheat the next tool. A M104 "
"command to preheat the tool in advance will be inserted into the G-Code.");
def->sidetext = "s";
def->min = 0;
def->max = 120;
def->mode = comExpert;
def->set_default_value(new ConfigOptionFloat(120.0));

def = this->add("preheat_steps", coInt);
def->label = L("Preheat steps");
def->tooltip = L("Insert multiple preheat commands (e.g. M104.1). Only useful for Prusa XL. For other printers, please set it to 1.");
def->min = 1;
def->max = 10;
def->mode = comExpert;
def->set_default_value(new ConfigOptionInt(1));

def = this->add("start_gcode", coString);
def->label = L("Start G-code");
def->tooltip = L("This start procedure is inserted at the beginning, possibly prepended by "
Expand Down
2 changes: 2 additions & 0 deletions src/libslic3r/PrintConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionBool, wiping_volumes_use_custom_matrix))
((ConfigOptionFloat, z_offset))
((ConfigOptionFloat, init_z_rotate))
((ConfigOptionFloat, preheat_time))
((ConfigOptionInt, preheat_steps))
)

PRINT_CONFIG_CLASS_DERIVED_DEFINE0(
Expand Down
2 changes: 2 additions & 0 deletions src/slic3r/GUI/ConfigManipulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)

bool have_ooze_prevention = config->opt_bool("ooze_prevention");
toggle_field("standby_temperature_delta", have_ooze_prevention);
toggle_field("preheat_time", have_ooze_prevention);
toggle_field("preheat_steps", have_ooze_prevention);

bool have_wipe_tower = config->opt_bool("wipe_tower");
for (auto el : { "wipe_tower_width", "wipe_tower_brim_width", "wipe_tower_cone_angle",
Expand Down
2 changes: 2 additions & 0 deletions src/slic3r/GUI/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1755,6 +1755,8 @@ void TabPrint::build()
optgroup = page->new_optgroup(L("Ooze prevention"));
optgroup->append_single_option_line("ooze_prevention");
optgroup->append_single_option_line("standby_temperature_delta");
optgroup->append_single_option_line("preheat_time");
optgroup->append_single_option_line("preheat_steps");

optgroup = page->new_optgroup(L("Wipe tower"));
optgroup->append_single_option_line("wipe_tower");
Expand Down

0 comments on commit e8968e9

Please sign in to comment.