update wipe tower according to latest PrusaSlicer

This commit is contained in:
SoftFever 2024-07-09 22:20:36 +08:00
parent 1c68d58343
commit 860a41baed
9 changed files with 256 additions and 128 deletions

View file

@ -1,6 +1,4 @@
// Orca: This file is ported from latest PrusaSlicer // Orca: WipeTower2 for all non bbl printers, support all MMU device and toolchanger.
// Original PrusaSlicer Copyright:
#include "WipeTower2.hpp" #include "WipeTower2.hpp"
#include <cassert> #include <cassert>
@ -26,6 +24,20 @@
namespace Slic3r namespace Slic3r
{ {
// Calculates length of extrusion line to extrude given volume
static float volume_to_length(float volume, float line_width, float layer_height)
{
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
}
static float length_to_volume(float length, float line_width, float layer_height)
{
return std::max(0.f, length * layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f)));
}
class WipeTowerWriter2 class WipeTowerWriter2
{ {
public: public:
@ -37,12 +49,9 @@ public:
m_extrusion_flow(0.f), m_extrusion_flow(0.f),
m_preview_suppressed(false), m_preview_suppressed(false),
m_elapsed_time(0.f), m_elapsed_time(0.f),
#if ENABLE_GCODE_VIEWER_DATA_CHECKING m_gcode_flavor(flavor),
m_default_analyzer_line_width(line_width), m_filpar(filament_parameters)
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING {
m_gcode_flavor(flavor),
m_filpar(filament_parameters)
{
// ORCA: This class is only used by non BBL printers, so set the parameter appropriately. // ORCA: This class is only used by non BBL printers, so set the parameter appropriately.
// This fixes an issue where the wipe tower was using BBL tags resulting in statistics for purging in the purge tower not being displayed. // This fixes an issue where the wipe tower was using BBL tags resulting in statistics for purging in the purge tower not being displayed.
GCodeProcessor::s_IsBBLPrinter = false; GCodeProcessor::s_IsBBLPrinter = false;
@ -62,18 +71,6 @@ public:
return *this; return *this;
} }
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter2& change_analyzer_mm3_per_mm(float len, float e) {
static const float area = float(M_PI) * 1.75f * 1.75f / 4.f;
float mm3_per_mm = (len == 0.f ? 0.f : area * e / len);
// adds tag for processor:
std::stringstream str;
str << ";" << GCodeProcessor::Mm3_Per_Mm_Tag << mm3_per_mm << "\n";
m_gcode += str.str();
return *this;
}
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter2& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) { WipeTowerWriter2& set_initial_position(const Vec2f &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) {
m_wipe_tower_width = width; m_wipe_tower_width = width;
m_wipe_tower_depth = depth; m_wipe_tower_depth = depth;
@ -109,16 +106,16 @@ public:
return *this; return *this;
} }
WipeTowerWriter2& switch_filament_monitoring(bool enable) {
m_gcode += std::string("G4 S0\n") + "M591 " + (enable ? "R" : "S0") + "\n";
return *this;
}
// Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various // Suppress / resume G-code preview in Slic3r. Slic3r will have difficulty to differentiate the various
// filament loading and cooling moves from normal extrusion moves. Therefore the writer // filament loading and cooling moves from normal extrusion moves. Therefore the writer
// is asked to suppres output of some lines, which look like extrusions. // is asked to suppres output of some lines, which look like extrusions.
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter2& suppress_preview() { change_analyzer_line_width(0.f); m_preview_suppressed = true; return *this; }
WipeTowerWriter2& resume_preview() { change_analyzer_line_width(m_default_analyzer_line_width); m_preview_suppressed = false; return *this; }
#else
WipeTowerWriter2& suppress_preview() { m_preview_suppressed = true; return *this; } WipeTowerWriter2& suppress_preview() { m_preview_suppressed = true; return *this; }
WipeTowerWriter2& resume_preview() { m_preview_suppressed = false; return *this; } WipeTowerWriter2& resume_preview() { m_preview_suppressed = false; return *this; }
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter2& feedrate(float f) WipeTowerWriter2& feedrate(float f)
{ {
@ -140,8 +137,8 @@ public:
float get_and_reset_used_filament_length() { float temp = m_used_filament_length; m_used_filament_length = 0.f; return temp; } float get_and_reset_used_filament_length() { float temp = m_used_filament_length; m_used_filament_length = 0.f; return temp; }
// Extrude with an explicitely provided amount of extrusion. // Extrude with an explicitely provided amount of extrusion.
WipeTowerWriter2& extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) WipeTowerWriter2& extrude_explicit(float x, float y, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true)
{ {
if (x == m_current_pos.x() && y == m_current_pos.y() && e == 0.f && (f == 0.f || f == m_current_feedrate)) if (x == m_current_pos.x() && y == m_current_pos.y() && e == 0.f && (f == 0.f || f == m_current_feedrate))
// Neither extrusion nor a travel move. // Neither extrusion nor a travel move.
return *this; return *this;
@ -157,12 +154,9 @@ public:
Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go Vec2f rot(this->rotate(Vec2f(x,y))); // this is where we want to go
if (! m_preview_suppressed && e > 0.f && len > 0.f) { if (! m_preview_suppressed && e > 0.f && len > 0.f) {
#if ENABLE_GCODE_VIEWER_DATA_CHECKING // Width of a squished extrusion, corrected for the roundings of the squished extrusions.
change_analyzer_mm3_per_mm(len, e);
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
// This is left zero if it is a travel move. // This is left zero if it is a travel move.
float width = e * m_filpar[0].filament_area / (len * m_layer_height); float width = e * m_filpar[0].filament_area / (len * m_layer_height);
// Correct for the roundings of a squished extrusion. // Correct for the roundings of a squished extrusion.
width += m_layer_height * float(1. - M_PI / 4.); width += m_layer_height * float(1. - M_PI / 4.);
if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos) if (m_extrusions.empty() || m_extrusions.back().pos != rotated_current_pos)
@ -204,17 +198,17 @@ public:
return *this; return *this;
} }
WipeTowerWriter2& extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true) WipeTowerWriter2& extrude_explicit(const Vec2f &dest, float e, float f = 0.f, bool record_length = false, bool limit_volumetric_flow = true)
{ return extrude_explicit(dest.x(), dest.y(), e, f, record_length); } { return extrude_explicit(dest.x(), dest.y(), e, f, record_length); }
// Travel to a new XY position. f=0 means use the current value. // Travel to a new XY position. f=0 means use the current value.
WipeTowerWriter2& travel(float x, float y, float f = 0.f) WipeTowerWriter2& travel(float x, float y, float f = 0.f)
{ return extrude_explicit(x, y, 0.f, f); } { return extrude_explicit(x, y, 0.f, f); }
WipeTowerWriter2& travel(const Vec2f &dest, float f = 0.f) WipeTowerWriter2& travel(const Vec2f &dest, float f = 0.f)
{ return extrude_explicit(dest.x(), dest.y(), 0.f, f); } { return extrude_explicit(dest.x(), dest.y(), 0.f, f); }
// Extrude a line from current position to x, y with the extrusion amount given by m_extrusion_flow. // Extrude a line from current position to x, y with the extrusion amount given by m_extrusion_flow.
WipeTowerWriter2& extrude(float x, float y, float f = 0.f) WipeTowerWriter2& extrude(float x, float y, float f = 0.f)
{ {
float dx = x - m_current_pos.x(); float dx = x - m_current_pos.x();
@ -222,8 +216,8 @@ public:
return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true); return extrude_explicit(x, y, std::sqrt(dx*dx+dy*dy) * m_extrusion_flow, f, true);
} }
WipeTowerWriter2& extrude(const Vec2f &dest, const float f = 0.f) WipeTowerWriter2& extrude(const Vec2f &dest, const float f = 0.f)
{ return extrude(dest.x(), dest.y(), f); } { return extrude(dest.x(), dest.y(), f); }
WipeTowerWriter2& rectangle(const Vec2f& ld,float width,float height,const float f = 0.f) WipeTowerWriter2& rectangle(const Vec2f& ld,float width,float height,const float f = 0.f)
{ {
@ -291,6 +285,25 @@ public:
return extrude_explicit(end_point, y(), loading_dist, x_speed * 60.f, false, false); return extrude_explicit(end_point, y(), loading_dist, x_speed * 60.f, false, false);
} }
// Loads filament while also moving towards given point in x-axis. Unlike the previous function, this one respects
// both the loading_speed and x_speed. Can shorten the move.
WipeTowerWriter2& load_move_x_advanced_there_and_back(float farthest_x, float e_dist, float e_speed, float x_speed)
{
float old_x = x();
float time = std::abs(e_dist / e_speed); // time that the whole move must take
float x_max_dist = std::abs(farthest_x - x()); // max x-distance that we can travel
float x_dist = x_speed * time; // totel x-distance to travel during the move
int n = int(x_dist / (2*x_max_dist) + 1.f); // how many there and back moves should we do
float r = 2*n*x_max_dist / x_dist; // actual/required dist if the move is not shortened
float end_point = x() + (farthest_x > x() ? 1.f : -1.f) * x_max_dist / r;
for (int i=0; i<n; ++i) {
extrude_explicit(end_point, y(), e_dist/(2.f*n), x_speed * 60.f, false, false);
extrude_explicit(old_x, y(), e_dist/(2.f*n), x_speed * 60.f, false, false);
}
return *this;
}
// Elevate the extruder head above the current print_z position. // Elevate the extruder head above the current print_z position.
WipeTowerWriter2& z_hop(float hop, float f = 0.f) WipeTowerWriter2& z_hop(float hop, float f = 0.f)
{ {
@ -309,8 +322,8 @@ public:
// extrude quickly amount e to x2 with feed f. // extrude quickly amount e to x2 with feed f.
WipeTowerWriter2& ram(float x1, float x2, float dy, float e0, float e, float f) WipeTowerWriter2& ram(float x1, float x2, float dy, float e0, float e, float f)
{ {
extrude_explicit(x1, m_current_pos.y() + dy, e0, f, true, false); extrude_explicit(x1, m_current_pos.y() + dy, e0, f, true, false);
extrude_explicit(x2, m_current_pos.y(), e, 0.f, true, false); extrude_explicit(x2, m_current_pos.y(), e, 0.f, true, false);
return *this; return *this;
} }
@ -333,6 +346,7 @@ public:
// Set extruder temperature, don't wait by default. // Set extruder temperature, don't wait by default.
WipeTowerWriter2& set_extruder_temp(int temperature, bool wait = false) WipeTowerWriter2& set_extruder_temp(int temperature, bool wait = false)
{ {
m_gcode += "G4 S0\n"; // to flush planner queue
m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n"; m_gcode += "M" + std::to_string(wait ? 109 : 104) + " S" + std::to_string(temperature) + "\n";
return *this; return *this;
} }
@ -452,9 +466,6 @@ private:
float m_wipe_tower_depth = 0.f; float m_wipe_tower_depth = 0.f;
unsigned m_last_fan_speed = 0; unsigned m_last_fan_speed = 0;
int current_temp = -1; int current_temp = -1;
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
const float m_default_analyzer_line_width;
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
float m_used_filament_length = 0.f; float m_used_filament_length = 0.f;
GCodeFlavor m_gcode_flavor; GCodeFlavor m_gcode_flavor;
const std::vector<WipeTower2::FilamentParameters>& m_filpar; const std::vector<WipeTower2::FilamentParameters>& m_filpar;
@ -533,7 +544,9 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)), m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
m_wipe_tower_brim_width(float(config.prime_tower_brim_width)), m_wipe_tower_brim_width(float(config.prime_tower_brim_width)),
m_wipe_tower_cone_angle(float(config.wipe_tower_cone_angle)), m_wipe_tower_cone_angle(float(config.wipe_tower_cone_angle)),
m_extra_spacing(float(config.wipe_tower_extra_spacing/100.)), m_extra_flow(float(config.wipe_tower_extra_flow/100.)),
m_extra_spacing_wipe(float(config.wipe_tower_extra_spacing/100. * config.wipe_tower_extra_flow/100.)),
m_extra_spacing_ramming(float(config.wipe_tower_extra_spacing/100.)),
m_y_shift(0.f), m_y_shift(0.f),
m_z_pos(0.f), m_z_pos(0.f),
m_bridging(float(config.wipe_tower_bridging)), m_bridging(float(config.wipe_tower_bridging)),
@ -571,6 +584,8 @@ WipeTower2::WipeTower2(const PrintConfig& config, const PrintRegionConfig& defau
m_set_extruder_trimpot = config.high_current_on_filament_swap; m_set_extruder_trimpot = config.high_current_on_filament_swap;
} }
m_is_mk4mmu3 = boost::icontains(config.printer_notes.value, "PRINTER_MODEL_MK4") && boost::icontains(config.printer_notes.value, "MMU");
// Calculate where the priming lines should be - very naive test not detecting parallelograms etc. // Calculate where the priming lines should be - very naive test not detecting parallelograms etc.
const std::vector<Vec2d>& bed_points = config.printable_area.values; const std::vector<Vec2d>& bed_points = config.printable_area.values;
BoundingBoxf bb(bed_points); BoundingBoxf bb(bed_points);
@ -605,6 +620,7 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config)
m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx); m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx);
m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx); m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx);
m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx); m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx);
m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx);
// If this is a single extruder MM printer, we will use all the SE-specific config values. // If this is a single extruder MM printer, we will use all the SE-specific config values.
// Otherwise, the defaults will be used to turn off the SE stuff. // Otherwise, the defaults will be used to turn off the SE stuff.
@ -617,6 +633,8 @@ void WipeTower2::set_extruder(size_t idx, const PrintConfig& config)
m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx); m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx);
m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx)); m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx));
m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx)); m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx));
m_filpar[idx].filament_stamping_loading_speed = float(config.filament_stamping_loading_speed.get_at(idx));
m_filpar[idx].filament_stamping_distance = float(config.filament_stamping_distance.get_at(idx));
} }
m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point
@ -730,7 +748,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
toolchange_Wipe(writer, cleaning_box , 20.f); toolchange_Wipe(writer, cleaning_box , 20.f);
WipeTower::box_coordinates box = cleaning_box; WipeTower::box_coordinates box = cleaning_box;
box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width); box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width);
toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[tools[idx_tool + 1]].first_layer_temperature); toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature);
cleaning_box.translate(prime_section_width, 0.f); cleaning_box.translate(prime_section_width, 0.f);
writer.travel(cleaning_box.ld, 7200); writer.travel(cleaning_box.ld, 7200);
} }
@ -777,7 +795,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
for (const auto &b : m_layer_info->tool_changes) for (const auto &b : m_layer_info->tool_changes)
if ( b.new_tool == tool ) { if ( b.new_tool == tool ) {
wipe_volume = b.wipe_volume; wipe_volume = b.wipe_volume;
wipe_area = b.required_depth * m_layer_info->extra_spacing; wipe_area = b.required_depth;
break; break;
} }
} }
@ -797,10 +815,10 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
.set_initial_tool(m_current_tool) .set_initial_tool(m_current_tool)
.set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f)) .set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f))
.append(";--------------------\n" .append(";--------------------\n"
"; CP TOOLCHANGE START\n") "; CP TOOLCHANGE START\n");
.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
if (tool != (unsigned)(-1)){ if (tool != (unsigned)(-1)){
writer.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str()) writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str())
.append(";--------------------\n"); .append(";--------------------\n");
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n"); writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_Start) + "\n");
@ -819,7 +837,8 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
// Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool. // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
if (tool != (unsigned int)-1){ // This is not the last change. if (tool != (unsigned int)-1){ // This is not the last change.
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material,
is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature); (is_first_layer() ? m_filpar[m_current_tool].first_layer_temperature : m_filpar[m_current_tool].temperature),
(is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature));
toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials. toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
toolchange_Load(writer, cleaning_box); toolchange_Load(writer, cleaning_box);
writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
@ -827,7 +846,7 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t tool)
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n"); writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Wipe_Tower_End) + "\n");
++ m_num_tool_changes; ++ m_num_tool_changes;
} else } else
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature); toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature, m_filpar[m_current_tool].temperature);
m_depth_traversed += wipe_area; m_depth_traversed += wipe_area;
@ -854,13 +873,14 @@ void WipeTower2::toolchange_Unload(
WipeTowerWriter2 &writer, WipeTowerWriter2 &writer,
const WipeTower::box_coordinates &cleaning_box, const WipeTower::box_coordinates &cleaning_box,
const std::string& current_material, const std::string& current_material,
const int old_temperature,
const int new_temperature) const int new_temperature)
{ {
float xl = cleaning_box.ld.x() + 1.f * m_perimeter_width; float xl = cleaning_box.ld.x() + 1.f * m_perimeter_width;
float xr = cleaning_box.rd.x() - 1.f * m_perimeter_width; float xr = cleaning_box.rd.x() - 1.f * m_perimeter_width;
const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness
const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing_ramming; // spacing between lines in mm
const Vec2f ramming_start_pos = Vec2f(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f); const Vec2f ramming_start_pos = Vec2f(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f);
@ -873,10 +893,14 @@ void WipeTower2::toolchange_Unload(
float e_done = 0; // measures E move done from each segment float e_done = 0; // measures E move done from each segment
const bool do_ramming = m_enable_filament_ramming && (m_semm || m_filpar[m_current_tool].multitool_ramming); const bool do_ramming = m_enable_filament_ramming && (m_semm || m_filpar[m_current_tool].multitool_ramming);
const bool cold_ramming = m_is_mk4mmu3;
if (do_ramming) { if (do_ramming) {
writer.travel(ramming_start_pos); // move to starting position writer.travel(ramming_start_pos); // move to starting position
writer.disable_linear_advance(); if (! m_is_mk4mmu3)
writer.disable_linear_advance();
if (cold_ramming)
writer.set_extruder_temp(old_temperature - 20);
} }
else else
writer.set_position(ramming_start_pos); writer.set_position(ramming_start_pos);
@ -897,7 +921,7 @@ void WipeTower2::toolchange_Unload(
if (tch.old_tool == m_current_tool) { if (tch.old_tool == m_current_tool) {
sum_of_depths += tch.ramming_depth; sum_of_depths += tch.ramming_depth;
float ramming_end_y = sum_of_depths; float ramming_end_y = sum_of_depths;
ramming_end_y -= (y_step/m_extra_spacing-m_perimeter_width) / 2.f; // center of final ramming line ramming_end_y -= (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f; // center of final ramming line
if ( (m_current_shape == SHAPE_REVERSED && ramming_end_y < sparse_beginning_y - 0.5f*m_perimeter_width ) || if ( (m_current_shape == SHAPE_REVERSED && ramming_end_y < sparse_beginning_y - 0.5f*m_perimeter_width ) ||
(m_current_shape == SHAPE_NORMAL && ramming_end_y > sparse_beginning_y + 0.5f*m_perimeter_width ) ) (m_current_shape == SHAPE_NORMAL && ramming_end_y > sparse_beginning_y + 0.5f*m_perimeter_width ) )
@ -911,6 +935,11 @@ void WipeTower2::toolchange_Unload(
} }
} }
if (m_is_mk4mmu3) {
writer.switch_filament_monitoring(false);
writer.wait(1.5f);
}
// now the ramming itself: // now the ramming itself:
while (do_ramming && i < m_filpar[m_current_tool].ramming_speed.size()) while (do_ramming && i < m_filpar[m_current_tool].ramming_speed.size())
@ -953,32 +982,70 @@ void WipeTower2::toolchange_Unload(
.retract(0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed * 60.f) .retract(0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed * 60.f)
.resume_preview(); .resume_preview();
} }
const int& number_of_cooling_moves = m_filpar[m_current_tool].cooling_moves;
const bool cooling_will_happen = m_semm && number_of_cooling_moves > 0;
bool change_temp_later = false;
// Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should // Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should
// be already set and there is no need to change anything. Also, the temperature could be changed // be already set and there is no need to change anything. Also, the temperature could be changed
// for wrong extruder. // for wrong extruder.
if (m_semm) { if (m_semm) {
if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer()) ) { // Set the extruder temperature, but don't wait. if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer() || cold_ramming) ) { // Set the extruder temperature, but don't wait.
// If the required temperature is the same as last time, don't emit the M104 again (if user adjusted the value, it would be reset) // If the required temperature is the same as last time, don't emit the M104 again (if user adjusted the value, it would be reset)
// However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off). // However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off).
writer.set_extruder_temp(new_temperature, false); if (cold_ramming && cooling_will_happen)
change_temp_later = true;
else
writer.set_extruder_temp(new_temperature, false);
m_old_temperature = new_temperature; m_old_temperature = new_temperature;
} }
} }
// Cooling: // Cooling:
const int& number_of_moves = m_filpar[m_current_tool].cooling_moves; if (cooling_will_happen) {
if (m_semm && number_of_moves > 0 && m_cooling_tube_length != 0) {
writer.append("; Cooling\n"); writer.append("; Cooling\n");
const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed; const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed;
const float& final_speed = m_filpar[m_current_tool].cooling_final_speed; const float& final_speed = m_filpar[m_current_tool].cooling_final_speed;
float speed_inc = (final_speed - initial_speed) / (2.f * number_of_moves - 1.f); float speed_inc = (final_speed - initial_speed) / (2.f * number_of_cooling_moves - 1.f);
if (m_is_mk4mmu3)
writer.disable_linear_advance();
writer.suppress_preview() writer.suppress_preview()
.travel(writer.x(), writer.y() + y_step); .travel(writer.x(), writer.y() + y_step);
old_x = writer.x(); old_x = writer.x();
turning_point = xr-old_x > old_x-xl ? xr : xl; turning_point = xr-old_x > old_x-xl ? xr : xl;
for (int i=0; i<number_of_moves; ++i) { float stamping_dist_e = m_filpar[m_current_tool].filament_stamping_distance + m_cooling_tube_length / 2.f;
for (int i=0; i<number_of_cooling_moves; ++i) {
// Stamping - happens after every cooling move except for the last one.
if (i>0 && m_filpar[m_current_tool].filament_stamping_distance != 0) {
// Stamping turning point shall be no farther than 20mm from the current nozzle position:
float stamping_turning_point = std::clamp(old_x + 20.f * (turning_point - old_x > 0.f ? 1.f : -1.f), xl, xr);
// Only last 5mm will be done with the fast x travel. The point is to spread possible blobs
// along the whole wipe tower.
if (stamping_dist_e > 5) {
float cent = writer.x();
writer.load_move_x_advanced(stamping_turning_point, (stamping_dist_e - 5), m_filpar[m_current_tool].filament_stamping_loading_speed, 200);
writer.load_move_x_advanced(cent, 5, m_filpar[m_current_tool].filament_stamping_loading_speed, m_travel_speed);
writer.travel(cent, writer.y());
} else
writer.load_move_x_advanced_there_and_back(stamping_turning_point, stamping_dist_e, m_filpar[m_current_tool].filament_stamping_loading_speed, m_travel_speed);
// Retract while the print head is stationary, so if there is a blob, it is not dragged along.
writer.retract(stamping_dist_e, m_filpar[m_current_tool].unloading_speed * 60.f);
}
if (i == number_of_cooling_moves - 1 && change_temp_later) {
// If cold_ramming, the temperature change should be done before the last cooling move.
writer.set_extruder_temp(new_temperature, false);
}
float speed = initial_speed + speed_inc * 2*i; float speed = initial_speed + speed_inc * 2*i;
writer.load_move_x_advanced(turning_point, m_cooling_tube_length, speed); writer.load_move_x_advanced(turning_point, m_cooling_tube_length, speed);
speed += speed_inc; speed += speed_inc;
@ -998,7 +1065,7 @@ void WipeTower2::toolchange_Unload(
// this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start: // this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start:
// the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material // the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material
Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing-m_perimeter_width) / 2.f + m_perimeter_width); Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f + m_perimeter_width);
if (do_ramming) if (do_ramming)
writer.travel(pos, 2400.f); writer.travel(pos, 2400.f);
else else
@ -1018,11 +1085,14 @@ void WipeTower2::toolchange_Change(
if (m_current_tool < m_used_filament_length.size()) if (m_current_tool < m_used_filament_length.size())
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
// This is where we want to place the custom gcodes. We will use placeholders for this. // This is where we want to place the custom gcodes. We will use placeholders for this.
// These will be substituted by the actual gcodes when the gcode is generated. // These will be substituted by the actual gcodes when the gcode is generated.
//writer.append("[end_filament_gcode]\n");
writer.append("[change_filament_gcode]\n"); writer.append("[change_filament_gcode]\n");
if (m_is_mk4mmu3)
writer.switch_filament_monitoring(true);
// Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc) // Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc)
// gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the // gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the
// postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before. // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before.
@ -1030,10 +1100,11 @@ void WipeTower2::toolchange_Change(
writer.feedrate(m_travel_speed * 60.f) // see https://github.com/prusa3d/PrusaSlicer/issues/5483 writer.feedrate(m_travel_speed * 60.f) // see https://github.com/prusa3d/PrusaSlicer/issues/5483
.append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x()) .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x())
+ " Y" + Slic3r::float_to_string_decimal_point(current_pos.y()) + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y())
+ never_skip_tag() + "\n"); + never_skip_tag() + "\n"
);
writer.append("[deretraction_from_wipe_tower_generator]"); writer.append("[deretraction_from_wipe_tower_generator]");
// Orca TODO: handle multi extruders
// The toolchange Tn command will be inserted later, only in case that the user does // The toolchange Tn command will be inserted later, only in case that the user does
// not provide a custom toolchange gcode. // not provide a custom toolchange gcode.
writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed. writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed.
@ -1084,21 +1155,25 @@ void WipeTower2::toolchange_Wipe(
const float& xl = cleaning_box.ld.x(); const float& xl = cleaning_box.ld.x();
const float& xr = cleaning_box.rd.x(); const float& xr = cleaning_box.rd.x();
writer.set_extrusion_flow(m_extrusion_flow * m_extra_flow);
const float line_width = m_perimeter_width * m_extra_flow;
writer.change_analyzer_line_width(line_width);
// Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least // Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least
// the ordered volume, even if it means violating the box. This can later be removed and simply // the ordered volume, even if it means violating the box. This can later be removed and simply
// wipe until the end of the assigned area. // wipe until the end of the assigned area.
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) * (is_first_layer() ? m_extra_spacing : 1.f); float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) / m_extra_flow;
float dy = (is_first_layer() ? 1.f : m_extra_spacing) * m_perimeter_width; // Don't use the extra spacing for the first layer. float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; // Don't use the extra spacing for the first layer, but do use the spacing resulting from increased flow.
// All the calculations in all other places take the spacing into account for all the layers. // All the calculations in all other places take the spacing into account for all the layers.
// If spare layers are excluded->if 1 or less toolchange has been done, it must be sill the first layer, too.So slow down. // If spare layers are excluded->if 1 or less toolchange has been done, it must be sill the first layer, too.So slow down.
const float target_speed = is_first_layer() || (m_num_tool_changes <= 1 && m_no_sparse_layers) ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f); const float target_speed = is_first_layer() || (m_num_tool_changes <= 1 && m_no_sparse_layers) ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f);
float wipe_speed = 0.33f * target_speed; float wipe_speed = 0.33f * target_speed;
// if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway) // if there is less than 2.5*line_width to the edge, advance straightaway (there is likely a blob anyway)
if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*m_perimeter_width) { if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*line_width) {
writer.travel((m_left_to_right ? xr-m_perimeter_width : xl+m_perimeter_width),writer.y()+dy); writer.travel((m_left_to_right ? xr-line_width : xl+line_width),writer.y()+dy);
m_left_to_right = !m_left_to_right; m_left_to_right = !m_left_to_right;
} }
@ -1113,21 +1188,21 @@ void WipeTower2::toolchange_Wipe(
float traversed_x = writer.x(); float traversed_x = writer.x();
if (m_left_to_right) if (m_left_to_right)
writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed); writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
else else
writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*m_perimeter_width), writer.y(), wipe_speed); writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*m_perimeter_width) if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width)
break; // in case next line would not fit break; // in case next line would not fit
traversed_x -= writer.x(); traversed_x -= writer.x();
x_to_wipe -= std::abs(traversed_x); x_to_wipe -= std::abs(traversed_x);
if (x_to_wipe < WT_EPSILON) { if (x_to_wipe < WT_EPSILON) {
writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200); writer.travel(m_left_to_right ? xl + 1.5f*line_width : xr - 1.5f*line_width, writer.y(), 7200);
break; break;
} }
// stepping to the next line: // stepping to the next line:
writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*m_perimeter_width, writer.y() + dy); writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*line_width, writer.y() + dy);
m_left_to_right = !m_left_to_right; m_left_to_right = !m_left_to_right;
} }
@ -1141,6 +1216,7 @@ void WipeTower2::toolchange_Wipe(
m_left_to_right = !m_left_to_right; m_left_to_right = !m_left_to_right;
writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow. writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
writer.change_analyzer_line_width(m_perimeter_width);
} }
@ -1414,16 +1490,15 @@ std::vector<std::vector<float>> WipeTower2::extract_wipe_volumes(const PrintConf
std::vector<float> wiping_matrix(cast<float>(config.flush_volumes_matrix.values)); std::vector<float> wiping_matrix(cast<float>(config.flush_volumes_matrix.values));
auto scale = config.flush_multiplier; auto scale = config.flush_multiplier;
// Orca todo: currently we only/always support SEMM.
// The values shall only be used when SEMM is enabled. The purging for other printers // The values shall only be used when SEMM is enabled. The purging for other printers
// is determined by filament_minimal_purge_on_wipe_tower. // is determined by filament_minimal_purge_on_wipe_tower.
if (! config.purge_in_prime_tower.value) if (! config.purge_in_prime_tower.value || ! config.single_extruder_multi_material.value)
std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f); std::fill(wiping_matrix.begin(), wiping_matrix.end(), 0.f);
// Extract purging volumes for each extruder pair: // Extract purging volumes for each extruder pair:
std::vector<std::vector<float>> wipe_volumes; std::vector<std::vector<float>> wipe_volumes;
const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON); const unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+EPSILON);
for (unsigned int i = 0; i<number_of_extruders; ++i) for (size_t i = 0; i<number_of_extruders; ++i)
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders)); wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders, wiping_matrix.begin()+(i+1)*number_of_extruders));
// Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview. // Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview.
@ -1434,6 +1509,14 @@ std::vector<std::vector<float>> WipeTower2::extract_wipe_volumes(const PrintConf
return wipe_volumes; return wipe_volumes;
} }
static float get_wipe_depth(float volume, float layer_height, float perimeter_width, float extra_flow, float extra_spacing, float width)
{
float length_to_extrude = (volume_to_length(volume, perimeter_width, layer_height)) / extra_flow;
length_to_extrude = std::max(length_to_extrude,0.f);
return (int(length_to_extrude / width) + 1) * perimeter_width * extra_spacing;
}
// Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box
void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool,
unsigned int new_tool, float wipe_volume) unsigned int new_tool, float wipe_volume)
@ -1449,23 +1532,18 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i
if (old_tool == new_tool) // new layer without toolchanges - we are done if (old_tool == new_tool) // new layer without toolchanges - we are done
return; return;
// this is an actual toolchange - let's calculate depth to reserve on the wipe tower // this is an actual toolchange - let's calculate depth to reserve on the wipe tower
float depth = 0.f; float width = m_wipe_tower_width - 3*m_perimeter_width;
float width = m_wipe_tower_width - 3*m_perimeter_width;
float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f), float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f),
m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator, m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator,
layer_height_par); layer_height_par);
depth = (int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator); float ramming_depth = (int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator) * m_extra_spacing_ramming;
float ramming_depth = depth; float first_wipe_line = - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width);
length_to_extrude = width*((length_to_extrude / width)-int(length_to_extrude / width)) - width;
float first_wipe_line = -length_to_extrude;
length_to_extrude += volume_to_length(wipe_volume, m_perimeter_width, layer_height_par);
length_to_extrude = std::max(length_to_extrude,0.f);
depth += (int(length_to_extrude / width) + 1) * m_perimeter_width; float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height_par);
depth *= m_extra_spacing; float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height_par, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width);
m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, ramming_depth, first_wipe_line, wipe_volume)); m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume));
} }
@ -1505,20 +1583,25 @@ void WipeTower2::save_on_last_wipe()
// Which toolchange will finish_layer extrusions be subtracted from? // Which toolchange will finish_layer extrusions be subtracted from?
int idx = first_toolchange_to_nonsoluble(m_layer_info->tool_changes); int idx = first_toolchange_to_nonsoluble(m_layer_info->tool_changes);
if (idx == -1) {
// In this case, finish_layer will be called at the very beginning.
finish_layer().total_extrusion_length_in_plane();
}
for (int i=0; i<int(m_layer_info->tool_changes.size()); ++i) { for (int i=0; i<int(m_layer_info->tool_changes.size()); ++i) {
auto& toolchange = m_layer_info->tool_changes[i]; auto& toolchange = m_layer_info->tool_changes[i];
tool_change(toolchange.new_tool); tool_change(toolchange.new_tool);
if (i == idx) { if (i == idx) {
float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into
float length_to_save = finish_layer().total_extrusion_length_in_plane();
float length_to_wipe = volume_to_length(toolchange.wipe_volume,
m_perimeter_width, m_layer_info->height) - toolchange.first_wipe_line - length_to_save;
length_to_wipe = std::max(length_to_wipe,0.f); float volume_to_save = length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height);
float depth_to_wipe = m_perimeter_width * (std::floor(length_to_wipe/width) + ( length_to_wipe > 0.f ? 1.f : 0.f ) ) * m_extra_spacing; float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save);
float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height));
float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, m_extra_spacing_wipe, width);
toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe; toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe;
toolchange.wipe_volume = volume_left_to_wipe;
} }
} }
} }
@ -1563,7 +1646,7 @@ void WipeTower2::generate(std::vector<std::vector<WipeTower::ToolChangeResult>>
return; return;
plan_tower(); plan_tower();
for (int i=0;i<5;++i) { for (int i = 0; i<5; ++i) {
save_on_last_wipe(); save_on_last_wipe();
plan_tower(); plan_tower();
} }
@ -1579,14 +1662,15 @@ void WipeTower2::generate(std::vector<std::vector<WipeTower::ToolChangeResult>>
} }
} }
for (auto& used : m_used_filament_length) // reset used filament stats m_used_filament_length.assign(m_used_filament_length.size(), 0.f); // reset used filament stats
used = 0.f; assert(m_used_filament_length_until_layer.empty());
m_used_filament_length_until_layer.emplace_back(0.f, m_used_filament_length);
m_old_temperature = -1; // reset last temperature written in the gcode m_old_temperature = -1; // reset last temperature written in the gcode
std::vector<WipeTower::ToolChangeResult> layer_result;
for (const WipeTower2::WipeTowerInfo& layer : m_plan) for (const WipeTower2::WipeTowerInfo& layer : m_plan)
{ {
std::vector<WipeTower::ToolChangeResult> layer_result;
set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z); set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z);
m_internal_rotation += 180.f; m_internal_rotation += 180.f;
@ -1623,6 +1707,10 @@ void WipeTower2::generate(std::vector<std::vector<WipeTower::ToolChangeResult>>
} }
result.emplace_back(std::move(layer_result)); result.emplace_back(std::move(layer_result));
if (m_used_filament_length_until_layer.empty() || m_used_filament_length_until_layer.back().first != layer.z)
m_used_filament_length_until_layer.emplace_back();
m_used_filament_length_until_layer.back() = std::make_pair(layer.z, m_used_filament_length);
} }
} }

View file

@ -1,6 +1,5 @@
// Orca: This file is ported from latest PrusaSlicer // Orca: WipeTower2 for all non bbl printers, support all MMU device and toolchanger
// Original PrusaSlicer Copyright:
#ifndef WipeTower2_ #ifndef WipeTower2_
#define WipeTower2_ #define WipeTower2_
@ -128,6 +127,7 @@ public:
} }
std::vector<float> get_used_filament() const { return m_used_filament_length; } std::vector<float> get_used_filament() const { return m_used_filament_length; }
std::vector<std::pair<float, std::vector<float>>> get_used_filament_until_layer() const { return m_used_filament_length_until_layer; }
int get_number_of_toolchanges() const { return m_num_tool_changes; } int get_number_of_toolchanges() const { return m_num_tool_changes; }
struct FilamentParameters { struct FilamentParameters {
@ -140,6 +140,10 @@ public:
float unloading_speed = 0.f; float unloading_speed = 0.f;
float unloading_speed_start = 0.f; float unloading_speed_start = 0.f;
float delay = 0.f ; float delay = 0.f ;
float filament_stamping_loading_speed = 0.f;
float filament_stamping_distance = 0.f;
int cooling_moves = 0; int cooling_moves = 0;
float cooling_initial_speed = 0.f; float cooling_initial_speed = 0.f;
float cooling_final_speed = 0.f; float cooling_final_speed = 0.f;
@ -151,6 +155,7 @@ public:
float filament_area; float filament_area;
bool multitool_ramming; bool multitool_ramming;
float multitool_ramming_time = 0.f; float multitool_ramming_time = 0.f;
float filament_minimal_purge_on_wipe_tower = 0.f;
}; };
private: private:
@ -169,6 +174,7 @@ private:
bool m_semm = true; // Are we using a single extruder multimaterial printer? bool m_semm = true; // Are we using a single extruder multimaterial printer?
bool m_enable_filament_ramming = true; bool m_enable_filament_ramming = true;
bool m_is_mk4mmu3 = false;
Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_width; // Width of the wipe tower.
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
@ -219,8 +225,7 @@ private:
// State of the wipe tower generator. // State of the wipe tower generator.
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics. unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics. unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
bool m_print_brim = true;
// A fill-in direction (positive Y, negative Y) alternates with each layer. // A fill-in direction (positive Y, negative Y) alternates with each layer.
wipe_shape m_current_shape = SHAPE_NORMAL; wipe_shape m_current_shape = SHAPE_NORMAL;
size_t m_current_tool = 0; size_t m_current_tool = 0;
@ -229,7 +234,9 @@ private:
float m_depth_traversed = 0.f; // Current y position at the wipe tower. float m_depth_traversed = 0.f; // Current y position at the wipe tower.
bool m_current_layer_finished = false; bool m_current_layer_finished = false;
bool m_left_to_right = true; bool m_left_to_right = true;
float m_extra_spacing = 1.f; float m_extra_flow = 1.f;
float m_extra_spacing_wipe = 1.f;
float m_extra_spacing_ramming = 1.f;
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; } bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
@ -241,17 +248,10 @@ private:
return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area(); return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area();
} }
// Calculates length of extrusion line to extrude given volume
float volume_to_length(float volume, float line_width, float layer_height) const {
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
}
// Calculates depth for all layers and propagates them downwards // Calculates depth for all layers and propagates them downwards
void plan_tower(); void plan_tower();
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
void make_wipe_tower_square();
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe // Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
void save_on_last_wipe(); void save_on_last_wipe();
@ -265,19 +265,19 @@ private:
float ramming_depth; float ramming_depth;
float first_wipe_line; float first_wipe_line;
float wipe_volume; float wipe_volume;
float wipe_volume_total;
ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f) ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f)
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv} {} : old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth}, first_wipe_line{fwl}, wipe_volume{wv}, wipe_volume_total{wv} {}
}; };
float z; // z position of the layer float z; // z position of the layer
float height; // layer height float height; // layer height
float depth; // depth of the layer based on all layers above float depth; // depth of the layer based on all layers above
float extra_spacing;
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; } float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
std::vector<ToolChange> tool_changes; std::vector<ToolChange> tool_changes;
WipeTowerInfo(float z_par, float layer_height_par) WipeTowerInfo(float z_par, float layer_height_par)
: z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {} : z{z_par}, height{layer_height_par}, depth{0} {}
}; };
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...)) std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
@ -289,6 +289,7 @@ private:
// Stores information about used filament length per extruder: // Stores information about used filament length per extruder:
std::vector<float> m_used_filament_length; std::vector<float> m_used_filament_length;
std::vector<std::pair<float, std::vector<float>>> m_used_filament_length_until_layer;
// Return index of first toolchange that switches to non-soluble extruder // Return index of first toolchange that switches to non-soluble extruder
// ot -1 if there is no such toolchange. // ot -1 if there is no such toolchange.
@ -299,6 +300,7 @@ private:
WipeTowerWriter2 &writer, WipeTowerWriter2 &writer,
const WipeTower::box_coordinates &cleaning_box, const WipeTower::box_coordinates &cleaning_box,
const std::string& current_material, const std::string& current_material,
const int old_temperature,
const int new_temperature); const int new_temperature);
void toolchange_Change( void toolchange_Change(
@ -316,6 +318,9 @@ private:
float wipe_volume); float wipe_volume);
}; };
} // namespace Slic3r } // namespace Slic3r
#endif // WipeTowerPrusaMM_hpp_ #endif // slic3r_GCode_WipeTower_hpp_

View file

@ -809,7 +809,7 @@ static std::vector<std::string> s_Preset_print_options {
"tree_support_brim_width", "gcode_comments", "gcode_label_objects", "tree_support_brim_width", "gcode_comments", "gcode_label_objects",
"initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width", "initial_layer_travel_speed", "exclude_object", "slow_down_layers", "infill_anchor", "infill_anchor_max","initial_layer_min_bead_width",
"make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes", "make_overhang_printable", "make_overhang_printable_angle", "make_overhang_printable_hole_size" ,"notes",
"wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "single_extruder_multi_material_priming", "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wiping_volumes_extruders","wipe_tower_bridging", "wipe_tower_extra_flow","single_extruder_multi_material_priming",
"wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic", "wipe_tower_rotation_angle", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_branch_angle_organic",
"hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth", "hole_to_polyhole", "hole_to_polyhole_threshold", "hole_to_polyhole_twisted", "mmu_segmented_region_max_width", "mmu_segmented_region_interlocking_depth",
"small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model", "small_area_infill_flow_compensation", "small_area_infill_flow_compensation_model",
@ -842,7 +842,7 @@ static std::vector<std::string> s_Preset_filament_options {
//SoftFever //SoftFever
"enable_pressure_advance", "pressure_advance","chamber_temperature", "filament_shrink", "support_material_interface_fan_speed", "filament_notes" /*,"filament_seam_gap"*/, "enable_pressure_advance", "pressure_advance","chamber_temperature", "filament_shrink", "support_material_interface_fan_speed", "filament_notes" /*,"filament_seam_gap"*/,
"filament_loading_speed", "filament_loading_speed_start", "filament_load_time", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
"filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_unloading_speed", "filament_unloading_speed_start", "filament_unload_time", "filament_toolchange_delay", "filament_cooling_moves", "filament_stamping_loading_speed", "filament_stamping_distance",
"filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters",
"filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control", "filament_multitool_ramming", "filament_multitool_ramming_volume", "filament_multitool_ramming_flow", "activate_chamber_temp_control",
"filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature" "filament_long_retractions_when_cut","filament_retraction_distances_when_cut", "idle_temperature"

View file

@ -252,6 +252,8 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "filament_unloading_speed_start" || opt_key == "filament_unloading_speed_start"
|| opt_key == "filament_toolchange_delay" || opt_key == "filament_toolchange_delay"
|| opt_key == "filament_cooling_moves" || opt_key == "filament_cooling_moves"
|| opt_key == "filament_stamping_loading_speed"
|| opt_key == "filament_stamping_distance"
|| opt_key == "filament_cooling_initial_speed" || opt_key == "filament_cooling_initial_speed"
|| opt_key == "filament_cooling_final_speed" || opt_key == "filament_cooling_final_speed"
|| opt_key == "filament_ramming_parameters" || opt_key == "filament_ramming_parameters"
@ -273,6 +275,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
|| opt_key == "other_layers_print_sequence" || opt_key == "other_layers_print_sequence"
|| opt_key == "other_layers_print_sequence_nums" || opt_key == "other_layers_print_sequence_nums"
|| opt_key == "wipe_tower_bridging" || opt_key == "wipe_tower_bridging"
|| opt_key == "wipe_tower_extra_flow"
|| opt_key == "wipe_tower_no_sparse_layers" || opt_key == "wipe_tower_no_sparse_layers"
|| opt_key == "flush_volumes_matrix" || opt_key == "flush_volumes_matrix"
|| opt_key == "prime_volume" || opt_key == "prime_volume"

View file

@ -1883,6 +1883,21 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionInts { 4 }); def->set_default_value(new ConfigOptionInts { 4 });
def = this->add("filament_stamping_loading_speed", coFloats);
def->label = L("Stamping loading speed");
def->tooltip = L("Speed used for stamping.");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_stamping_distance", coFloats);
def->label = L("Stamping distance measured from the center of the cooling tube");
def->tooltip = L("If set to nonzero value, filament is moved toward the nozzle between the individual cooling moves (\"stamping\"). "
"This option configures how long this movement should be before the filament is retracted again.");
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloats { 0. });
def = this->add("filament_cooling_initial_speed", coFloats); def = this->add("filament_cooling_initial_speed", coFloats);
def->label = L("Speed of the first cooling move"); def->label = L("Speed of the first cooling move");
def->tooltip = L("Cooling moves are gradually accelerating beginning at this speed."); def->tooltip = L("Cooling moves are gradually accelerating beginning at this speed.");
@ -4958,6 +4973,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced; def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(10.)); def->set_default_value(new ConfigOptionFloat(10.));
def = this->add("wipe_tower_extra_flow", coPercent);
def->label = L("MATHIEU TEST: extra flow");
def->tooltip = L("");
def->sidetext = L("%");
def->mode = comAdvanced;
def->min = 100.;
def->max = 300.;
def->set_default_value(new ConfigOptionPercent(100.));
def = this->add("idle_temperature", coInts); def = this->add("idle_temperature", coInts);
def->label = L("Idle temperature"); def->label = L("Idle temperature");
def->tooltip = L("Nozzle temperature when the tool is currently not used in multi-tool setups." def->tooltip = L("Nozzle temperature when the tool is currently not used in multi-tool setups."

View file

@ -1130,6 +1130,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBools, filament_multitool_ramming)) ((ConfigOptionBools, filament_multitool_ramming))
((ConfigOptionFloats, filament_multitool_ramming_volume)) ((ConfigOptionFloats, filament_multitool_ramming_volume))
((ConfigOptionFloats, filament_multitool_ramming_flow)) ((ConfigOptionFloats, filament_multitool_ramming_flow))
((ConfigOptionFloats, filament_stamping_loading_speed))
((ConfigOptionFloats, filament_stamping_distance))
((ConfigOptionBool, purge_in_prime_tower)) ((ConfigOptionBool, purge_in_prime_tower))
((ConfigOptionBool, enable_filament_ramming)) ((ConfigOptionBool, enable_filament_ramming))
((ConfigOptionBool, support_multi_bed_types)) ((ConfigOptionBool, support_multi_bed_types))
@ -1238,6 +1240,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloat, wipe_tower_rotation_angle)) ((ConfigOptionFloat, wipe_tower_rotation_angle))
((ConfigOptionFloat, prime_tower_brim_width)) ((ConfigOptionFloat, prime_tower_brim_width))
((ConfigOptionFloat, wipe_tower_bridging)) ((ConfigOptionFloat, wipe_tower_bridging))
((ConfigOptionPercent, wipe_tower_extra_flow))
((ConfigOptionFloats, flush_volumes_matrix)) ((ConfigOptionFloats, flush_volumes_matrix))
((ConfigOptionFloats, flush_volumes_vector)) ((ConfigOptionFloats, flush_volumes_vector))

View file

@ -675,9 +675,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower"); bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower");
// Orca: do we really need to hide these options when not purge_in_primetower? for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle",
for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"}) "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed",
toggle_line(el, have_prime_tower); "wipe_tower_bridging", "wipe_tower_extra_flow",
"wipe_tower_no_sparse_layers",
"single_extruder_multi_material_priming"})
toggle_line(el, have_prime_tower);
toggle_line("prime_volume",have_prime_tower && !purge_in_primetower); toggle_line("prime_volume",have_prime_tower && !purge_in_primetower);

View file

@ -2771,7 +2771,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
"brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers", "brim_width", "wall_loops", "wall_filament", "sparse_infill_density", "sparse_infill_filament", "top_shell_layers",
"enable_support", "support_filament", "support_interface_filament", "enable_support", "support_filament", "support_interface_filament",
"support_top_z_distance", "support_bottom_z_distance", "raft_layers", "support_top_z_distance", "support_bottom_z_distance", "raft_layers",
"wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing","wipe_tower_max_purge_speed", "wipe_tower_filament", "wipe_tower_rotation_angle", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "wipe_tower_extra_flow", "wipe_tower_max_purge_speed", "wipe_tower_filament",
"best_object_pos" "best_object_pos"
})) }))
, sidebar(new Sidebar(q)) , sidebar(new Sidebar(q))

View file

@ -2302,6 +2302,7 @@ void TabPrint::build()
optgroup->append_single_option_line("wipe_tower_bridging"); optgroup->append_single_option_line("wipe_tower_bridging");
optgroup->append_single_option_line("wipe_tower_cone_angle"); optgroup->append_single_option_line("wipe_tower_cone_angle");
optgroup->append_single_option_line("wipe_tower_extra_spacing"); optgroup->append_single_option_line("wipe_tower_extra_spacing");
optgroup->append_single_option_line("wipe_tower_extra_flow");
optgroup->append_single_option_line("wipe_tower_max_purge_speed"); optgroup->append_single_option_line("wipe_tower_max_purge_speed");
optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); optgroup->append_single_option_line("wipe_tower_no_sparse_layers");
optgroup->append_single_option_line("single_extruder_multi_material_priming"); optgroup->append_single_option_line("single_extruder_multi_material_priming");
@ -3444,7 +3445,8 @@ void TabFilament::build()
optgroup->append_single_option_line("filament_cooling_moves", "semm"); optgroup->append_single_option_line("filament_cooling_moves", "semm");
optgroup->append_single_option_line("filament_cooling_initial_speed", "semm"); optgroup->append_single_option_line("filament_cooling_initial_speed", "semm");
optgroup->append_single_option_line("filament_cooling_final_speed", "semm"); optgroup->append_single_option_line("filament_cooling_final_speed", "semm");
optgroup->append_single_option_line("filament_stamping_loading_speed");
optgroup->append_single_option_line("filament_stamping_distance");
create_line_with_widget(optgroup.get(), "filament_ramming_parameters", "", [this](wxWindow* parent) { create_line_with_widget(optgroup.get(), "filament_ramming_parameters", "", [this](wxWindow* parent) {
auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxGetApp().UpdateDarkUI(ramming_dialog_btn); wxGetApp().UpdateDarkUI(ramming_dialog_btn);