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
// Original PrusaSlicer Copyright:
// Orca: WipeTower2 for all non bbl printers, support all MMU device and toolchanger.
#include "WipeTower2.hpp"
#include <cassert>
@ -26,6 +24,20 @@
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
{
public:
@ -37,9 +49,6 @@ public:
m_extrusion_flow(0.f),
m_preview_suppressed(false),
m_elapsed_time(0.f),
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
m_default_analyzer_line_width(line_width),
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
m_gcode_flavor(flavor),
m_filpar(filament_parameters)
{
@ -62,18 +71,6 @@ public:
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) {
m_wipe_tower_width = width;
m_wipe_tower_depth = depth;
@ -109,16 +106,16 @@ public:
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
// filament loading and cooling moves from normal extrusion moves. Therefore the writer
// 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& resume_preview() { m_preview_suppressed = false; return *this; }
#endif // ENABLE_GCODE_VIEWER_DATA_CHECKING
WipeTowerWriter2& feedrate(float f)
{
@ -157,9 +154,6 @@ public:
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 ENABLE_GCODE_VIEWER_DATA_CHECKING
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.
float width = e * m_filpar[0].filament_area / (len * m_layer_height);
@ -291,6 +285,25 @@ public:
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.
WipeTowerWriter2& z_hop(float hop, float f = 0.f)
{
@ -333,6 +346,7 @@ public:
// Set extruder temperature, don't wait by default.
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";
return *this;
}
@ -452,9 +466,6 @@ private:
float m_wipe_tower_depth = 0.f;
unsigned m_last_fan_speed = 0;
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;
GCodeFlavor m_gcode_flavor;
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_brim_width(float(config.prime_tower_brim_width)),
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_z_pos(0.f),
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_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.
const std::vector<Vec2d>& bed_points = config.printable_area.values;
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].temperature = config.nozzle_temperature.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.
// 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_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].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
@ -730,7 +748,7 @@ std::vector<WipeTower::ToolChangeResult> WipeTower2::prime(
toolchange_Wipe(writer, cleaning_box , 20.f);
WipeTower::box_coordinates box = cleaning_box;
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);
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)
if ( b.new_tool == tool ) {
wipe_volume = b.wipe_volume;
wipe_area = b.required_depth * m_layer_info->extra_spacing;
wipe_area = b.required_depth;
break;
}
}
@ -797,10 +815,10 @@ WipeTower::ToolChangeResult WipeTower2::tool_change(size_t 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))
.append(";--------------------\n"
"; CP TOOLCHANGE START\n")
.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
"; CP TOOLCHANGE START\n");
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())
.append(";--------------------\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.
if (tool != (unsigned int)-1){ // This is not the last change.
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_Load(writer, cleaning_box);
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");
++ m_num_tool_changes;
} 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;
@ -854,13 +873,14 @@ void WipeTower2::toolchange_Unload(
WipeTowerWriter2 &writer,
const WipeTower::box_coordinates &cleaning_box,
const std::string& current_material,
const int old_temperature,
const int new_temperature)
{
float xl = cleaning_box.ld.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 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);
@ -873,10 +893,14 @@ void WipeTower2::toolchange_Unload(
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 cold_ramming = m_is_mk4mmu3;
if (do_ramming) {
writer.travel(ramming_start_pos); // move to starting position
if (! m_is_mk4mmu3)
writer.disable_linear_advance();
if (cold_ramming)
writer.set_extruder_temp(old_temperature - 20);
}
else
writer.set_position(ramming_start_pos);
@ -897,7 +921,7 @@ void WipeTower2::toolchange_Unload(
if (tch.old_tool == m_current_tool) {
sum_of_depths += tch.ramming_depth;
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 ) ||
(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:
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)
.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
// be already set and there is no need to change anything. Also, the temperature could be changed
// for wrong extruder.
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)
// However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off).
if (cold_ramming && cooling_will_happen)
change_temp_later = true;
else
writer.set_extruder_temp(new_temperature, false);
m_old_temperature = new_temperature;
}
}
// Cooling:
const int& number_of_moves = m_filpar[m_current_tool].cooling_moves;
if (m_semm && number_of_moves > 0 && m_cooling_tube_length != 0) {
if (cooling_will_happen) {
writer.append("; Cooling\n");
const float& initial_speed = m_filpar[m_current_tool].cooling_initial_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()
.travel(writer.x(), writer.y() + y_step);
old_x = writer.x();
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;
writer.load_move_x_advanced(turning_point, m_cooling_tube_length, speed);
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:
// 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)
writer.travel(pos, 2400.f);
else
@ -1018,11 +1085,14 @@ void WipeTower2::toolchange_Change(
if (m_current_tool < m_used_filament_length.size())
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.
// 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");
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)
// 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.
@ -1030,10 +1100,11 @@ void WipeTower2::toolchange_Change(
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())
+ " 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]");
// Orca TODO: handle multi extruders
// The toolchange Tn command will be inserted later, only in case that the user does
// not provide a custom toolchange gcode.
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& 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
// 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.
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) * (is_first_layer() ? m_extra_spacing : 1.f);
float dy = (is_first_layer() ? 1.f : m_extra_spacing) * m_perimeter_width; // Don't use the extra spacing for the first layer.
float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) / m_extra_flow;
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.
// 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);
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 ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*m_perimeter_width) {
writer.travel((m_left_to_right ? xr-m_perimeter_width : xl+m_perimeter_width),writer.y()+dy);
// 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*line_width) {
writer.travel((m_left_to_right ? xr-line_width : xl+line_width),writer.y()+dy);
m_left_to_right = !m_left_to_right;
}
@ -1113,21 +1188,21 @@ void WipeTower2::toolchange_Wipe(
float traversed_x = writer.x();
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
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
traversed_x -= writer.x();
x_to_wipe -= std::abs(traversed_x);
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;
}
// 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;
}
@ -1141,6 +1216,7 @@ void WipeTower2::toolchange_Wipe(
m_left_to_right = !m_left_to_right;
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));
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
// 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);
// Extract purging volumes for each extruder pair:
std::vector<std::vector<float>> wipe_volumes;
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));
// 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;
}
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
void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool,
unsigned int new_tool, float wipe_volume)
@ -1450,22 +1533,17 @@ void WipeTower2::plan_toolchange(float z_par, float layer_height_par, unsigned i
return;
// 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 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,
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 = depth;
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);
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 first_wipe_line = - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width);
depth += (int(length_to_extrude / width) + 1) * m_perimeter_width;
depth *= m_extra_spacing;
float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height_par);
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?
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) {
auto& toolchange = m_layer_info->tool_changes[i];
tool_change(toolchange.new_tool);
if (i == idx) {
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 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_to_save = length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height);
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.wipe_volume = volume_left_to_wipe;
}
}
}
@ -1579,14 +1662,15 @@ void WipeTower2::generate(std::vector<std::vector<WipeTower::ToolChangeResult>>
}
}
for (auto& used : m_used_filament_length) // reset used filament stats
used = 0.f;
m_used_filament_length.assign(m_used_filament_length.size(), 0.f); // reset used filament stats
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
std::vector<WipeTower::ToolChangeResult> layer_result;
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);
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));
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_
#define WipeTower2_
@ -128,6 +127,7 @@ public:
}
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; }
struct FilamentParameters {
@ -140,6 +140,10 @@ public:
float unloading_speed = 0.f;
float unloading_speed_start = 0.f;
float delay = 0.f ;
float filament_stamping_loading_speed = 0.f;
float filament_stamping_distance = 0.f;
int cooling_moves = 0;
float cooling_initial_speed = 0.f;
float cooling_final_speed = 0.f;
@ -151,6 +155,7 @@ public:
float filament_area;
bool multitool_ramming;
float multitool_ramming_time = 0.f;
float filament_minimal_purge_on_wipe_tower = 0.f;
};
private:
@ -169,6 +174,7 @@ private:
bool m_semm = true; // Are we using a single extruder multimaterial printer?
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.
float m_wipe_tower_width; // Width 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.
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_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.
wipe_shape m_current_shape = SHAPE_NORMAL;
size_t m_current_tool = 0;
@ -229,7 +234,9 @@ private:
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
bool m_current_layer_finished = false;
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; }
@ -241,17 +248,10 @@ private:
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
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
void save_on_last_wipe();
@ -265,19 +265,19 @@ private:
float ramming_depth;
float first_wipe_line;
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)
: 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 height; // layer height
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; }
std::vector<ToolChange> tool_changes;
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(...))
@ -289,6 +289,7 @@ private:
// Stores information about used filament length per extruder:
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
// ot -1 if there is no such toolchange.
@ -299,6 +300,7 @@ private:
WipeTowerWriter2 &writer,
const WipeTower::box_coordinates &cleaning_box,
const std::string& current_material,
const int old_temperature,
const int new_temperature);
void toolchange_Change(
@ -316,6 +318,9 @@ private:
float wipe_volume);
};
} // 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",
"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",
"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",
"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",
@ -842,7 +842,7 @@ static std::vector<std::string> s_Preset_filament_options {
//SoftFever
"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_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_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"

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_toolchange_delay"
|| 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_final_speed"
|| 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_nums"
|| opt_key == "wipe_tower_bridging"
|| opt_key == "wipe_tower_extra_flow"
|| opt_key == "wipe_tower_no_sparse_layers"
|| opt_key == "flush_volumes_matrix"
|| opt_key == "prime_volume"

View file

@ -1883,6 +1883,21 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
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->label = L("Speed of the first cooling move");
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->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->label = L("Idle temperature");
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))
((ConfigOptionFloats, filament_multitool_ramming_volume))
((ConfigOptionFloats, filament_multitool_ramming_flow))
((ConfigOptionFloats, filament_stamping_loading_speed))
((ConfigOptionFloats, filament_stamping_distance))
((ConfigOptionBool, purge_in_prime_tower))
((ConfigOptionBool, enable_filament_ramming))
((ConfigOptionBool, support_multi_bed_types))
@ -1238,6 +1240,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
((ConfigOptionFloat, wipe_tower_rotation_angle))
((ConfigOptionFloat, prime_tower_brim_width))
((ConfigOptionFloat, wipe_tower_bridging))
((ConfigOptionPercent, wipe_tower_extra_flow))
((ConfigOptionFloats, flush_volumes_matrix))
((ConfigOptionFloats, flush_volumes_vector))

View file

@ -675,8 +675,11 @@ 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");
// 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", "wipe_tower_extra_spacing", "wipe_tower_max_purge_speed", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming"})
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_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);

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",
"enable_support", "support_filament", "support_interface_filament",
"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"
}))
, 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_cone_angle");
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_no_sparse_layers");
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_initial_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) {
auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
wxGetApp().UpdateDarkUI(ramming_dialog_btn);