Multimaterial initial priming for non-Prusa printers (https://github.com/prusa3d/PrusaSlicer/issues/1121)

The initial priming now does not assume anything about bed width and always uses the space it has
In case of circular beds it places the priming lines along the diameter
Custom beds are not supported (they are treated as circular with no extra checks whether it is sane)
Slight refactoring of the WipeTower class (constructor now gets reference to PrintConfig and not the individual values, same with set_extruder). This was legacy from times when the wipe tower was meant to be abstract and independent on the rest)
This commit is contained in:
Lukas Matena 2019-08-15 01:20:38 +02:00
parent fbda7be89d
commit c84b1ca34b
3 changed files with 94 additions and 102 deletions

View File

@ -22,6 +22,7 @@ TODO LIST
#include <numeric> #include <numeric>
#include "Analyzer.hpp" #include "Analyzer.hpp"
#include "BoundingBox.hpp"
#if defined(__linux) || defined(__GNUC__ ) #if defined(__linux) || defined(__GNUC__ )
#include <strings.h> #include <strings.h>
@ -470,6 +471,83 @@ private:
WipeTower::WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool) :
m_semm(config.single_extruder_multi_material.value),
m_wipe_tower_pos(config.wipe_tower_x, config.wipe_tower_y),
m_wipe_tower_width(config.wipe_tower_width),
m_wipe_tower_rotation_angle(config.wipe_tower_rotation_angle),
m_y_shift(0.f),
m_z_pos(0.f),
m_is_first_layer(false),
m_bridging(config.wipe_tower_bridging),
m_gcode_flavor(config.gcode_flavor),
m_current_tool(initial_tool),
wipe_volumes(wiping_matrix)
{
// 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.
if (m_semm) {
m_cooling_tube_retraction = config.cooling_tube_retraction;
m_cooling_tube_length = config.cooling_tube_length;
m_parking_pos_retraction = config.parking_pos_retraction;
m_extra_loading_move = config.extra_loading_move;
m_set_extruder_trimpot = config.high_current_on_filament_swap;
}
// Calculate where the priming lines should be - very naive test not detecting parallelograms or custom shapes
const std::vector<Vec2d>& bed_points = config.bed_shape.values;
m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
m_bed_width = BoundingBoxf(bed_points).size().x();
}
void WipeTower::set_extruder(size_t idx, const PrintConfig& config)
{
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
m_filpar.push_back(FilamentParameters());
m_filpar[idx].material = config.filament_type.get_at(idx);
m_filpar[idx].temperature = config.temperature.get_at(idx);
m_filpar[idx].first_layer_temperature = config.first_layer_temperature.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.
if (m_semm) {
m_filpar[idx].loading_speed = config.filament_loading_speed.get_at(idx);
m_filpar[idx].loading_speed_start = config.filament_loading_speed_start.get_at(idx);
m_filpar[idx].unloading_speed = config.filament_unloading_speed.get_at(idx);
m_filpar[idx].unloading_speed_start = config.filament_unloading_speed_start.get_at(idx);
m_filpar[idx].delay = config.filament_toolchange_delay.get_at(idx);
m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx);
m_filpar[idx].cooling_initial_speed = config.filament_cooling_initial_speed.get_at(idx);
m_filpar[idx].cooling_final_speed = config.filament_cooling_final_speed.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
float nozzle_diameter = config.nozzle_diameter.get_at(idx);
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
float max_vol_speed = config.filament_max_volumetric_speed.get_at(idx);
if (max_vol_speed!= 0.f)
m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
if (m_semm) {
std::istringstream stream{config.filament_ramming_parameters.get_at(idx)};
float speed = 0.f;
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
m_filpar[idx].ramming_line_width_multiplicator /= 100;
m_filpar[idx].ramming_step_multiplicator /= 100;
while (stream >> speed)
m_filpar[idx].ramming_speed.push_back(speed);
}
m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later
}
// Returns gcode to prime the nozzles at the front edge of the print bed. // Returns gcode to prime the nozzles at the front edge of the print bed.
std::vector<WipeTower::ToolChangeResult> WipeTower::prime( std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
// print_z of the first layer. // print_z of the first layer.
@ -488,9 +566,11 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
// therefore the homing position is shifted inside the bed by 0.2 in the firmware to [0.2, -2.0]. // therefore the homing position is shifted inside the bed by 0.2 in the firmware to [0.2, -2.0].
// box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area); // box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area);
const float prime_section_width = std::min(240.f / tools.size(), 60.f); float prime_section_width = std::min(0.9f * m_bed_width / tools.size(), 60.f);
box_coordinates cleaning_box(Vec2f(5.f, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f); box_coordinates cleaning_box(Vec2f(0.02f * m_bed_width, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f);
// In case of a circular bed, place it so it goes across the diameter and hope it will fit
if (m_bed_shape == CircularBed)
cleaning_box.translate(-m_bed_width/2 + m_bed_width * 0.03f, -m_bed_width * 0.12f);
std::vector<ToolChangeResult> results; std::vector<ToolChangeResult> results;

View File

@ -78,83 +78,12 @@ public:
// y -- y coordinates of wipe tower in mm ( left bottom corner ) // y -- y coordinates of wipe tower in mm ( left bottom corner )
// width -- width of wipe tower in mm ( default 60 mm - leave as it is ) // width -- width of wipe tower in mm ( default 60 mm - leave as it is )
// wipe_area -- space available for one toolchange in mm // wipe_area -- space available for one toolchange in mm
WipeTower(bool semm, float x, float y, float width, float rotation_angle, float cooling_tube_retraction, WipeTower(const PrintConfig& config, const std::vector<std::vector<float>>& wiping_matrix, size_t initial_tool);
float cooling_tube_length, float parking_pos_retraction, float extra_loading_move,
float bridging, bool set_extruder_trimpot, GCodeFlavor flavor,
const std::vector<std::vector<float>>& wiping_matrix, unsigned int initial_tool) :
m_semm(semm),
m_wipe_tower_pos(x, y),
m_wipe_tower_width(width),
m_wipe_tower_rotation_angle(rotation_angle),
m_y_shift(0.f),
m_z_pos(0.f),
m_is_first_layer(false),
m_gcode_flavor(flavor),
m_bridging(bridging),
m_current_tool(initial_tool),
wipe_volumes(wiping_matrix)
{
// 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.
if (m_semm) {
m_cooling_tube_retraction = cooling_tube_retraction;
m_cooling_tube_length = cooling_tube_length;
m_parking_pos_retraction = parking_pos_retraction;
m_extra_loading_move = extra_loading_move;
m_set_extruder_trimpot = set_extruder_trimpot;
}
}
virtual ~WipeTower() {} virtual ~WipeTower() {}
// Set the extruder properties. // Set the extruder properties.
void set_extruder(size_t idx, std::string material, int temp, int first_layer_temp, float loading_speed, float loading_speed_start, void set_extruder(size_t idx, const PrintConfig& config);
float unloading_speed, float unloading_speed_start, float delay, int cooling_moves,
float cooling_initial_speed, float cooling_final_speed, std::string ramming_parameters, float max_volumetric_speed,
float nozzle_diameter, float filament_diameter)
{
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
m_filpar.push_back(FilamentParameters());
m_filpar[idx].material = material;
m_filpar[idx].temperature = temp;
m_filpar[idx].first_layer_temperature = first_layer_temp;
// 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.
if (m_semm) {
m_filpar[idx].loading_speed = loading_speed;
m_filpar[idx].loading_speed_start = loading_speed_start;
m_filpar[idx].unloading_speed = unloading_speed;
m_filpar[idx].unloading_speed_start = unloading_speed_start;
m_filpar[idx].delay = delay;
m_filpar[idx].cooling_moves = cooling_moves;
m_filpar[idx].cooling_initial_speed = cooling_initial_speed;
m_filpar[idx].cooling_final_speed = cooling_final_speed;
}
m_filpar[idx].filament_area = float((M_PI/4.f) * pow(filament_diameter, 2)); // all extruders are assumed to have the same filament diameter at this point
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
if (max_volumetric_speed != 0.f)
m_filpar[idx].max_e_speed = (max_volumetric_speed / filament_area());
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
if (m_semm) {
std::stringstream stream{ramming_parameters};
float speed = 0.f;
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
m_filpar[idx].ramming_line_width_multiplicator /= 100;
m_filpar[idx].ramming_step_multiplicator /= 100;
while (stream >> speed)
m_filpar[idx].ramming_speed.push_back(speed);
}
m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later
}
// Appends into internal structure m_plan containing info about the future wipe tower // Appends into internal structure m_plan containing info about the future wipe tower
// to be used before building begins. The entries must be added ordered in z. // to be used before building begins. The entries must be added ordered in z.
@ -263,7 +192,6 @@ private:
SHAPE_REVERSED = -1 SHAPE_REVERSED = -1
}; };
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
const float WT_EPSILON = 1e-3f; const float WT_EPSILON = 1e-3f;
@ -295,6 +223,13 @@ private:
bool m_adhesion = true; bool m_adhesion = true;
GCodeFlavor m_gcode_flavor; GCodeFlavor m_gcode_flavor;
// Bed properties
enum {
RectangularBed,
CircularBed
} m_bed_shape;
float m_bed_width; // width of the bed bounding box
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill. float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter. float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.

View File

@ -1760,15 +1760,7 @@ void Print::_make_wipe_tower()
this->throw_if_canceled(); this->throw_if_canceled();
// Initialize the wipe tower. // Initialize the wipe tower.
WipeTower wipe_tower( WipeTower wipe_tower(m_config, wipe_volumes, m_wipe_tower_data.tool_ordering.first_extruder());
m_config.single_extruder_multi_material.value,
float(m_config.wipe_tower_x.value), float(m_config.wipe_tower_y.value),
float(m_config.wipe_tower_width.value),
float(m_config.wipe_tower_rotation_angle.value), float(m_config.cooling_tube_retraction.value),
float(m_config.cooling_tube_length.value), float(m_config.parking_pos_retraction.value),
float(m_config.extra_loading_move.value), float(m_config.wipe_tower_bridging),
m_config.high_current_on_filament_swap.value, m_config.gcode_flavor, wipe_volumes,
m_wipe_tower_data.tool_ordering.first_extruder());
//wipe_tower.set_retract(); //wipe_tower.set_retract();
//wipe_tower.set_zhop(); //wipe_tower.set_zhop();
@ -1777,22 +1769,7 @@ void Print::_make_wipe_tower()
for (size_t i = 0; i < number_of_extruders; ++ i) for (size_t i = 0; i < number_of_extruders; ++ i)
wipe_tower.set_extruder( wipe_tower.set_extruder(
i, i, m_config);
m_config.filament_type.get_at(i),
m_config.temperature.get_at(i),
m_config.first_layer_temperature.get_at(i),
(float)m_config.filament_loading_speed.get_at(i),
(float)m_config.filament_loading_speed_start.get_at(i),
(float)m_config.filament_unloading_speed.get_at(i),
(float)m_config.filament_unloading_speed_start.get_at(i),
(float)m_config.filament_toolchange_delay.get_at(i),
m_config.filament_cooling_moves.get_at(i),
(float)m_config.filament_cooling_initial_speed.get_at(i),
(float)m_config.filament_cooling_final_speed.get_at(i),
m_config.filament_ramming_parameters.get_at(i),
(float)m_config.filament_max_volumetric_speed.get_at(i),
(float)m_config.nozzle_diameter.get_at(i),
(float)m_config.filament_diameter.get_at(i));
m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>( m_wipe_tower_data.priming = Slic3r::make_unique<std::vector<WipeTower::ToolChangeResult>>(
wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false)); wipe_tower.prime((float)this->skirt_first_layer_height(), m_wipe_tower_data.tool_ordering.all_extruders(), false));