ENH: wipe tower support nozzle change
jira: none Change-Id: I398a508cbc8d02644b60e504405392254329ef10
This commit is contained in:
parent
9801a10f7f
commit
8b2a94ed5f
|
@ -288,6 +288,57 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||||
: gcodegen.config().nozzle_temperature.get_at(gcodegen.writer().filament()->id());
|
: gcodegen.config().nozzle_temperature.get_at(gcodegen.writer().filament()->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string transform_gcode(const std::string &gcode, Vec2f pos, const Vec2f &translation, float angle)
|
||||||
|
{
|
||||||
|
Vec2f extruder_offset(0, 0);
|
||||||
|
std::istringstream gcode_str(gcode);
|
||||||
|
std::string gcode_out;
|
||||||
|
std::string line;
|
||||||
|
Vec2f transformed_pos = pos;
|
||||||
|
Vec2f old_pos(-1000.1f, -1000.1f);
|
||||||
|
|
||||||
|
while (gcode_str) {
|
||||||
|
std::getline(gcode_str, line); // we read the gcode line by line
|
||||||
|
|
||||||
|
if (line.find("G1 ") == 0) {
|
||||||
|
bool never_skip = false;
|
||||||
|
auto it = line.find(WipeTower::never_skip_tag());
|
||||||
|
if (it != std::string::npos) {
|
||||||
|
// remove the tag and remember we saw it
|
||||||
|
never_skip = true;
|
||||||
|
line.erase(it, it + WipeTower::never_skip_tag().size());
|
||||||
|
}
|
||||||
|
std::ostringstream line_out;
|
||||||
|
std::istringstream line_str(line);
|
||||||
|
line_str >> std::noskipws; // don't skip whitespace
|
||||||
|
char ch = 0;
|
||||||
|
while (line_str >> ch) {
|
||||||
|
if (ch == 'X' || ch == 'Y')
|
||||||
|
line_str >> (ch == 'X' ? pos.x() : pos.y());
|
||||||
|
else
|
||||||
|
line_out << ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
transformed_pos = Eigen::Rotation2Df(angle) * pos + translation;
|
||||||
|
|
||||||
|
if (transformed_pos != old_pos || never_skip) {
|
||||||
|
line = line_out.str();
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << std::fixed << std::setprecision(3) << "G1 ";
|
||||||
|
if (transformed_pos.x() != old_pos.x() || never_skip) oss << " X" << transformed_pos.x() - extruder_offset.x();
|
||||||
|
if (transformed_pos.y() != old_pos.y() || never_skip) oss << " Y" << transformed_pos.y() - extruder_offset.y();
|
||||||
|
oss << " ";
|
||||||
|
line.replace(line.find("G1 "), 3, oss.str());
|
||||||
|
old_pos = transformed_pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gcode_out += line + "\n";
|
||||||
|
}
|
||||||
|
return gcode_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string Wipe::wipe(GCode& gcodegen, bool toolchange, bool is_last)
|
std::string Wipe::wipe(GCode& gcodegen, bool toolchange, bool is_last)
|
||||||
{
|
{
|
||||||
std::string gcode;
|
std::string gcode;
|
||||||
|
@ -441,6 +492,12 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||||
check_add_eol(end_filament_gcode_str);
|
check_add_eol(end_filament_gcode_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string nozzle_change_gcode_trans;
|
||||||
|
if (!tcr.nozzle_change_result.gcode.empty()) {
|
||||||
|
nozzle_change_gcode_trans = transform_gcode(tcr.nozzle_change_result.gcode, tcr.start_pos, wipe_tower_offset, wipe_tower_rotation);
|
||||||
|
}
|
||||||
|
|
||||||
//BBS: increase toolchange count
|
//BBS: increase toolchange count
|
||||||
gcodegen.m_toolchange_count++;
|
gcodegen.m_toolchange_count++;
|
||||||
|
|
||||||
|
@ -532,6 +589,13 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toolchange_gcode_str = gcodegen.placeholder_parser_process("change_filament_gcode", change_filament_gcode, new_filament_id, &config);
|
toolchange_gcode_str = gcodegen.placeholder_parser_process("change_filament_gcode", change_filament_gcode, new_filament_id, &config);
|
||||||
|
|
||||||
|
std::string target_str = ";nozzle_change_gcode";
|
||||||
|
size_t pos = toolchange_gcode_str.find(target_str);
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
toolchange_gcode_str.replace(pos, target_str.length(), nozzle_change_gcode_trans);
|
||||||
|
}
|
||||||
|
|
||||||
check_add_eol(toolchange_gcode_str);
|
check_add_eol(toolchange_gcode_str);
|
||||||
|
|
||||||
// retract before toolchange
|
// retract before toolchange
|
||||||
|
|
|
@ -586,6 +586,7 @@ WipeTower::ToolChangeResult WipeTower::construct_tcr(WipeTowerWriter& writer,
|
||||||
result.extrusions = std::move(writer.extrusions());
|
result.extrusions = std::move(writer.extrusions());
|
||||||
result.wipe_path = std::move(writer.wipe_path());
|
result.wipe_path = std::move(writer.wipe_path());
|
||||||
result.is_finish_first = is_finish;
|
result.is_finish_first = is_finish;
|
||||||
|
result.nozzle_change_result = m_nozzle_change_result;
|
||||||
// BBS
|
// BBS
|
||||||
result.purge_volume = purge_volume;
|
result.purge_volume = purge_volume;
|
||||||
return result;
|
return result;
|
||||||
|
@ -614,7 +615,8 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
|
||||||
m_current_tool(initial_tool),
|
m_current_tool(initial_tool),
|
||||||
//wipe_volumes(flush_matrix)
|
//wipe_volumes(flush_matrix)
|
||||||
m_wipe_volume(prime_volume),
|
m_wipe_volume(prime_volume),
|
||||||
m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth)
|
m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth),
|
||||||
|
m_nozzle_change_length(config.extruder_change_length.get_at(0))
|
||||||
{
|
{
|
||||||
// Read absolute value of first layer speed, if given as percentage,
|
// Read absolute value of first layer speed, if given as percentage,
|
||||||
// it is taken over following default. Speeds from config are not
|
// it is taken over following default. Speeds from config are not
|
||||||
|
@ -729,14 +731,49 @@ std::vector<WipeTower::ToolChangeResult> WipeTower::prime(
|
||||||
return std::vector<ToolChangeResult>();
|
return std::vector<ToolChangeResult>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec2f WipeTower::get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length)
|
||||||
|
{
|
||||||
|
const float &xl = cleaning_box.ld.x();
|
||||||
|
const float &xr = cleaning_box.rd.x();
|
||||||
|
int line_count = wipe_length / (xr - xl);
|
||||||
|
|
||||||
|
float dy = m_layer_info->extra_spacing * m_perimeter_width;
|
||||||
|
float y_offset = float(line_count) * dy;
|
||||||
|
const Vec2f pos_offset = Vec2f(0.f, m_depth_traversed);
|
||||||
|
|
||||||
|
Vec2f res;
|
||||||
|
int index = m_cur_layer_id % 4;
|
||||||
|
switch (index % 4) {
|
||||||
|
case 0:
|
||||||
|
res = cleaning_box.ld + pos_offset;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
res = cleaning_box.rd + pos_offset + Vec2f(0, y_offset);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
res = cleaning_box.rd + pos_offset;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
res = cleaning_box.ld + pos_offset + Vec2f(0, y_offset);
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_perimeter, bool first_toolchange_to_nonsoluble)
|
WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_perimeter, bool first_toolchange_to_nonsoluble)
|
||||||
{
|
{
|
||||||
|
m_nozzle_change_result.gcode.clear();
|
||||||
|
if (!m_filament_map.empty() && tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[tool]) {
|
||||||
|
m_nozzle_change_result = nozzle_change(m_current_tool, tool);
|
||||||
|
}
|
||||||
|
|
||||||
size_t old_tool = m_current_tool;
|
size_t old_tool = m_current_tool;
|
||||||
|
|
||||||
float wipe_depth = 0.f;
|
float wipe_depth = 0.f;
|
||||||
float wipe_length = 0.f;
|
float wipe_length = 0.f;
|
||||||
float purge_volume = 0.f;
|
float purge_volume = 0.f;
|
||||||
|
float nozzle_change_depth = 0.f;
|
||||||
// Finds this toolchange info
|
// Finds this toolchange info
|
||||||
if (tool != (unsigned int)(-1))
|
if (tool != (unsigned int)(-1))
|
||||||
{
|
{
|
||||||
|
@ -745,6 +782,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||||
wipe_length = b.wipe_length;
|
wipe_length = b.wipe_length;
|
||||||
wipe_depth = b.required_depth;
|
wipe_depth = b.required_depth;
|
||||||
purge_volume = b.purge_volume;
|
purge_volume = b.purge_volume;
|
||||||
|
nozzle_change_depth = b.nozzle_change_depth;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -775,7 +813,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||||
writer.speed_override_backup();
|
writer.speed_override_backup();
|
||||||
writer.speed_override(100);
|
writer.speed_override(100);
|
||||||
|
|
||||||
Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed);
|
Vec2f initial_position = get_next_pos(cleaning_box, wipe_length);
|
||||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||||
|
|
||||||
// Increase the extruder driver current to allow fast ramming.
|
// Increase the extruder driver current to allow fast ramming.
|
||||||
|
@ -792,9 +830,17 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||||
toolchange_Load(writer, cleaning_box);
|
toolchange_Load(writer, cleaning_box);
|
||||||
// BBS
|
// BBS
|
||||||
//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
|
||||||
|
|
||||||
|
// ensure travel to initial_positoin
|
||||||
|
{
|
||||||
|
writer.travel(initial_position - Vec2f(0.5, 0.5));
|
||||||
|
writer.travel(initial_position);
|
||||||
|
}
|
||||||
|
toolchange_Wipe(writer, cleaning_box, wipe_length); // Wipe the newly loaded filament until the end of the assigned wipe area.
|
||||||
|
|
||||||
if (extrude_perimeter) {
|
if (extrude_perimeter) {
|
||||||
box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED) ? m_layer_info->toolchanges_depth() - m_layer_info->depth : 0.f),
|
box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED) ? m_layer_info->toolchanges_depth() - m_layer_info->depth : 0.f), m_wipe_tower_width,
|
||||||
m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
|
m_layer_info->depth + m_perimeter_width);
|
||||||
// align the perimeter
|
// align the perimeter
|
||||||
|
|
||||||
Vec2f pos = initial_position;
|
Vec2f pos = initial_position;
|
||||||
|
@ -829,7 +875,7 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||||
} else
|
} else
|
||||||
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature);
|
toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature);
|
||||||
|
|
||||||
m_depth_traversed += wipe_depth;
|
m_depth_traversed += (wipe_depth - nozzle_change_depth);
|
||||||
|
|
||||||
//BBS
|
//BBS
|
||||||
//if (m_set_extruder_trimpot)
|
//if (m_set_extruder_trimpot)
|
||||||
|
@ -849,6 +895,114 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
|
||||||
return construct_tcr(writer, false, old_tool, false, purge_volume);
|
return construct_tcr(writer, false, old_tool, false, purge_volume);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int new_filament_id)
|
||||||
|
{
|
||||||
|
float wipe_depth = 0.f;
|
||||||
|
float wipe_length = 0.f;
|
||||||
|
float purge_volume = 0.f;
|
||||||
|
int nozzle_change_line_count = 0;
|
||||||
|
|
||||||
|
// Finds this toolchange info
|
||||||
|
if (new_filament_id != (unsigned int) (-1)) {
|
||||||
|
for (const auto &b : m_layer_info->tool_changes)
|
||||||
|
if (b.new_tool == new_filament_id) {
|
||||||
|
wipe_length = b.wipe_length;
|
||||||
|
wipe_depth = b.required_depth;
|
||||||
|
purge_volume = b.purge_volume;
|
||||||
|
nozzle_change_line_count = (b.nozzle_change_depth + WT_EPSILON) / m_perimeter_width;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise we are going to Unload only. And m_layer_info would be invalid.
|
||||||
|
}
|
||||||
|
|
||||||
|
float nozzle_change_speed = 60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow;
|
||||||
|
|
||||||
|
WipeTowerWriter writer(m_layer_height, m_perimeter_width, m_gcode_flavor, m_filpar);
|
||||||
|
writer.set_extrusion_flow(m_extrusion_flow)
|
||||||
|
.set_z(m_z_pos)
|
||||||
|
.set_initial_tool(m_current_tool)
|
||||||
|
.set_extrusion_flow(m_extrusion_flow)
|
||||||
|
.set_y_shift(m_y_shift + (new_filament_id != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f))
|
||||||
|
.append("; Nozzle change start\n");
|
||||||
|
|
||||||
|
writer.speed_override_backup();
|
||||||
|
writer.speed_override(100);
|
||||||
|
|
||||||
|
box_coordinates cleaning_box(Vec2f(m_perimeter_width, m_perimeter_width),
|
||||||
|
m_wipe_tower_width - 2 * m_perimeter_width,
|
||||||
|
(new_filament_id != (unsigned int) (-1) ? wipe_depth + m_depth_traversed - m_perimeter_width : m_wipe_tower_depth - m_perimeter_width));
|
||||||
|
|
||||||
|
Vec2f initial_position = cleaning_box.ld + Vec2f(0.f, m_depth_traversed);
|
||||||
|
writer.travel(initial_position, 30000);
|
||||||
|
writer.append("G1 Z" + std::to_string(m_z_pos) + "\n");
|
||||||
|
writer.append("G1 E2 F1800\n");
|
||||||
|
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||||
|
|
||||||
|
const float &xl = cleaning_box.ld.x();
|
||||||
|
const float &xr = cleaning_box.rd.x();
|
||||||
|
|
||||||
|
float dy = m_layer_info->extra_spacing * m_perimeter_width;
|
||||||
|
|
||||||
|
const float target_speed = 4800.f;
|
||||||
|
float wipe_speed = std::max(target_speed, nozzle_change_speed);
|
||||||
|
|
||||||
|
float start_y = writer.y();
|
||||||
|
|
||||||
|
m_left_to_right = true;
|
||||||
|
|
||||||
|
bool need_change_flow = false;
|
||||||
|
// now the wiping itself:
|
||||||
|
for (int i = 0; true; ++i) {
|
||||||
|
if (m_left_to_right)
|
||||||
|
writer.extrude(xr + 0.25f * m_perimeter_width, writer.y(), wipe_speed);
|
||||||
|
else
|
||||||
|
writer.extrude(xl - 0.25f * m_perimeter_width, writer.y(), wipe_speed);
|
||||||
|
|
||||||
|
if (writer.y() - float(EPSILON) > cleaning_box.lu.y())
|
||||||
|
break; // in case next line would not fit
|
||||||
|
|
||||||
|
if (i == nozzle_change_line_count - 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// stepping to the next line:
|
||||||
|
writer.extrude(writer.x(), writer.y() + dy);
|
||||||
|
m_left_to_right = !m_left_to_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
|
||||||
|
|
||||||
|
m_depth_traversed += (nozzle_change_line_count) * dy;
|
||||||
|
|
||||||
|
auto float_to_string_with_precision = [](float value, int precision) {
|
||||||
|
std::ostringstream out;
|
||||||
|
out << std::fixed << std::setprecision(precision) << value;
|
||||||
|
return out.str();
|
||||||
|
};
|
||||||
|
|
||||||
|
float wipe_distance = 2;
|
||||||
|
Vec2f wipe_pos = writer.pos();
|
||||||
|
if (m_left_to_right) {
|
||||||
|
wipe_pos.x() -= wipe_distance;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wipe_pos.x() += wipe_distance;
|
||||||
|
}
|
||||||
|
writer.append("; WIPE_START\n");
|
||||||
|
writer.extrude_explicit(wipe_pos, -2);
|
||||||
|
writer.append("; WIPE_END\n");
|
||||||
|
|
||||||
|
std::string lift_gcode = "G2 Z" + float_to_string_with_precision(m_z_pos + 0.4, 3) + " I0.86 J0.86 P1 F10000\n";
|
||||||
|
writer.append(lift_gcode);
|
||||||
|
|
||||||
|
writer.append("; Nozzle change end\n");
|
||||||
|
|
||||||
|
NozzleChangeResult result;
|
||||||
|
result.start_pos = writer.start_pos_rotated();
|
||||||
|
result.end_pos = writer.pos();
|
||||||
|
result.gcode = std::move(writer.gcode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
void WipeTower::toolchange_Unload(
|
void WipeTower::toolchange_Unload(
|
||||||
|
@ -1094,7 +1248,8 @@ void WipeTower::toolchange_Wipe(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_left_to_right = true;
|
m_left_to_right = ((m_cur_layer_id + 3) % 4 >= 2);
|
||||||
|
bool is_from_up = (m_cur_layer_id % 2 == 1);
|
||||||
|
|
||||||
// BBS: do not need to move dy
|
// BBS: do not need to move dy
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -1130,9 +1285,12 @@ void WipeTower::toolchange_Wipe(
|
||||||
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n");
|
writer.append(";" + GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Height) + std::to_string(m_layer_height) + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (writer.y() - float(EPSILON) > cleaning_box.lu.y())
|
if (!is_from_up && (writer.y() - float(EPSILON) > cleaning_box.lu.y()))
|
||||||
break; // in case next line would not fit
|
break; // in case next line would not fit
|
||||||
|
|
||||||
|
if (is_from_up && (writer.y() + float(EPSILON) < cleaning_box.ld.y()))
|
||||||
|
break;
|
||||||
|
|
||||||
x_to_wipe -= (xr - xl);
|
x_to_wipe -= (xr - xl);
|
||||||
if (x_to_wipe < WT_EPSILON) {
|
if (x_to_wipe < WT_EPSILON) {
|
||||||
// BBS: Delete some unnecessary travel
|
// BBS: Delete some unnecessary travel
|
||||||
|
@ -1140,7 +1298,11 @@ void WipeTower::toolchange_Wipe(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// stepping to the next line:
|
// stepping to the next line:
|
||||||
writer.extrude(writer.x(), writer.y() + dy);
|
if (is_from_up)
|
||||||
|
writer.extrude(writer.x(), writer.y() - dy);
|
||||||
|
else
|
||||||
|
writer.extrude(writer.x(), writer.y() + dy);
|
||||||
|
|
||||||
m_left_to_right = !m_left_to_right;
|
m_left_to_right = !m_left_to_right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1208,7 +1370,6 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||||
bool first_layer = is_first_layer();
|
bool first_layer = is_first_layer();
|
||||||
// BBS: speed up perimeter speed to 90mm/s for non-first layer
|
// BBS: speed up perimeter speed to 90mm/s for non-first layer
|
||||||
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
|
float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
|
||||||
writer.feedrate(feedrate);
|
|
||||||
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
|
float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
|
||||||
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y),
|
box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y),
|
||||||
m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
|
m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
|
||||||
|
@ -1319,7 +1480,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer(bool extrude_perimeter, bool
|
||||||
box_coordinates box = wt_box;
|
box_coordinates box = wt_box;
|
||||||
for (size_t i = 0; i < loops_num; ++i) {
|
for (size_t i = 0; i < loops_num; ++i) {
|
||||||
box.expand(spacing);
|
box.expand(spacing);
|
||||||
writer.rectangle(box);
|
writer.rectangle(box, feedrate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first_layer) {
|
if (first_layer) {
|
||||||
|
@ -1399,7 +1560,17 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in
|
||||||
depth += std::ceil(length_to_extrude / width) * m_perimeter_width;
|
depth += std::ceil(length_to_extrude / width) * m_perimeter_width;
|
||||||
//depth *= m_extra_spacing;
|
//depth *= m_extra_spacing;
|
||||||
|
|
||||||
m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume));
|
float nozzle_change_depth = 0;
|
||||||
|
if (!m_filament_map.empty() && m_filament_map[old_tool] != m_filament_map[new_tool]) {
|
||||||
|
double e_flow = extrusion_flow(0.2);
|
||||||
|
double length = m_nozzle_change_length / e_flow;
|
||||||
|
int nozzle_change_line_count = length / (m_wipe_tower_width - m_perimeter_width) + 1;
|
||||||
|
nozzle_change_depth = nozzle_change_line_count * m_perimeter_width;
|
||||||
|
depth += nozzle_change_depth;
|
||||||
|
}
|
||||||
|
WipeTowerInfo::ToolChange tool_change = WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume);
|
||||||
|
tool_change.nozzle_change_depth = nozzle_change_depth;
|
||||||
|
m_plan.back().tool_changes.push_back(tool_change);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1467,6 +1638,12 @@ void WipeTower::plan_tower()
|
||||||
x_to_wipe_new = std::max(x_to_wipe_new, x_to_wipe);
|
x_to_wipe_new = std::max(x_to_wipe_new, x_to_wipe);
|
||||||
|
|
||||||
int line_count = std::ceil((x_to_wipe_new - WT_EPSILON) / line_len);
|
int line_count = std::ceil((x_to_wipe_new - WT_EPSILON) / line_len);
|
||||||
|
|
||||||
|
{ // nozzle change length
|
||||||
|
int nozzle_change_line_count = (toolchange.nozzle_change_depth + WT_EPSILON) / m_perimeter_width;
|
||||||
|
line_count += nozzle_change_line_count;
|
||||||
|
}
|
||||||
|
|
||||||
toolchange.required_depth = line_count * m_perimeter_width;
|
toolchange.required_depth = line_count * m_perimeter_width;
|
||||||
toolchange.wipe_volume = x_to_wipe_new / x_to_wipe * toolchange.wipe_volume;
|
toolchange.wipe_volume = x_to_wipe_new / x_to_wipe * toolchange.wipe_volume;
|
||||||
toolchange.wipe_length = x_to_wipe_new;
|
toolchange.wipe_length = x_to_wipe_new;
|
||||||
|
@ -1490,7 +1667,7 @@ void WipeTower::plan_tower()
|
||||||
float max_depth_for_all = 0;
|
float max_depth_for_all = 0;
|
||||||
for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
|
for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
|
||||||
{
|
{
|
||||||
float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth());
|
float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth());
|
||||||
if (m_enable_timelapse_print && this_layer_depth < EPSILON)
|
if (m_enable_timelapse_print && this_layer_depth < EPSILON)
|
||||||
this_layer_depth = min_wipe_tower_depth;
|
this_layer_depth = min_wipe_tower_depth;
|
||||||
|
|
||||||
|
@ -1615,6 +1792,7 @@ void WipeTower::generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &
|
||||||
m_old_temperature = -1; // reset last temperature written in the gcode
|
m_old_temperature = -1; // reset last temperature written in the gcode
|
||||||
int index = 0;
|
int index = 0;
|
||||||
std::vector<WipeTower::ToolChangeResult> layer_result;
|
std::vector<WipeTower::ToolChangeResult> layer_result;
|
||||||
|
int index = 0;
|
||||||
for (auto layer : m_plan)
|
for (auto layer : m_plan)
|
||||||
{
|
{
|
||||||
m_cur_layer_id = index++;
|
m_cur_layer_id = index++;
|
||||||
|
|
|
@ -17,7 +17,6 @@ class PrintConfig;
|
||||||
enum GCodeFlavor : unsigned char;
|
enum GCodeFlavor : unsigned char;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WipeTower
|
class WipeTower
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -38,6 +37,16 @@ public:
|
||||||
unsigned int tool;
|
unsigned int tool;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct NozzleChangeResult
|
||||||
|
{
|
||||||
|
std::string gcode;
|
||||||
|
|
||||||
|
Vec2f start_pos;
|
||||||
|
Vec2f end_pos;
|
||||||
|
|
||||||
|
std::vector<Vec2f> wipe_path;
|
||||||
|
};
|
||||||
|
|
||||||
struct ToolChangeResult
|
struct ToolChangeResult
|
||||||
{
|
{
|
||||||
// Print heigh of this tool change.
|
// Print heigh of this tool change.
|
||||||
|
@ -81,6 +90,8 @@ public:
|
||||||
// executing the gcode finish_layer_tcr.
|
// executing the gcode finish_layer_tcr.
|
||||||
bool is_finish_first = false;
|
bool is_finish_first = false;
|
||||||
|
|
||||||
|
NozzleChangeResult nozzle_change_result;
|
||||||
|
|
||||||
// Sum the total length of the extrusion.
|
// Sum the total length of the extrusion.
|
||||||
float total_extrusion_length_in_plane() {
|
float total_extrusion_length_in_plane() {
|
||||||
float e_length = 0.f;
|
float e_length = 0.f;
|
||||||
|
@ -190,7 +201,7 @@ public:
|
||||||
m_num_tool_changes = 0;
|
m_num_tool_changes = 0;
|
||||||
} else
|
} else
|
||||||
++ m_num_layer_changes;
|
++ m_num_layer_changes;
|
||||||
|
|
||||||
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
|
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
|
||||||
m_extrusion_flow = extrusion_flow(layer_height);
|
m_extrusion_flow = extrusion_flow(layer_height);
|
||||||
|
|
||||||
|
@ -209,7 +220,7 @@ public:
|
||||||
// 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<ToolChangeResult> prime(
|
std::vector<ToolChangeResult> prime(
|
||||||
// print_z of the first layer.
|
// print_z of the first layer.
|
||||||
float initial_layer_print_height,
|
float initial_layer_print_height,
|
||||||
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
|
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
|
||||||
const std::vector<unsigned int> &tools,
|
const std::vector<unsigned int> &tools,
|
||||||
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
||||||
|
@ -221,6 +232,8 @@ public:
|
||||||
// BBS
|
// BBS
|
||||||
ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter = false, bool first_toolchange_to_nonsoluble = false);
|
ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter = false, bool first_toolchange_to_nonsoluble = false);
|
||||||
|
|
||||||
|
NozzleChangeResult nozzle_change(int old_filament_id, int new_filament_id);
|
||||||
|
|
||||||
// Fill the unfilled space with a sparse infill.
|
// Fill the unfilled space with a sparse infill.
|
||||||
// Call this method only if layer_finished() is false.
|
// Call this method only if layer_finished() is false.
|
||||||
ToolChangeResult finish_layer(bool extruder_perimeter = true, bool extruder_fill = true);
|
ToolChangeResult finish_layer(bool extruder_perimeter = true, bool extruder_fill = true);
|
||||||
|
@ -244,6 +257,8 @@ 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; }
|
||||||
int get_number_of_toolchanges() const { return m_num_tool_changes; }
|
int get_number_of_toolchanges() const { return m_num_tool_changes; }
|
||||||
|
|
||||||
|
void set_filament_map(const std::vector<int> &filament_map) { m_filament_map = filament_map; }
|
||||||
|
|
||||||
struct FilamentParameters {
|
struct FilamentParameters {
|
||||||
std::string material = "PLA";
|
std::string material = "PLA";
|
||||||
bool is_soluble = false;
|
bool is_soluble = false;
|
||||||
|
@ -300,7 +315,12 @@ private:
|
||||||
float m_travel_speed = 0.f;
|
float m_travel_speed = 0.f;
|
||||||
float m_first_layer_speed = 0.f;
|
float m_first_layer_speed = 0.f;
|
||||||
size_t m_first_layer_idx = size_t(-1);
|
size_t m_first_layer_idx = size_t(-1);
|
||||||
size_t m_cur_layer_id;
|
|
||||||
|
double m_nozzle_change_length = 10;
|
||||||
|
size_t m_cur_layer_id;
|
||||||
|
NozzleChangeResult m_nozzle_change_result;
|
||||||
|
std::vector<int> m_filament_map;
|
||||||
|
|
||||||
// G-code generator parameters.
|
// G-code generator parameters.
|
||||||
// BBS: remove useless config
|
// BBS: remove useless config
|
||||||
//float m_cooling_tube_retraction = 0.f;
|
//float m_cooling_tube_retraction = 0.f;
|
||||||
|
@ -360,6 +380,8 @@ private:
|
||||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||||
void make_wipe_tower_square();
|
void make_wipe_tower_square();
|
||||||
|
|
||||||
|
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length);
|
||||||
|
|
||||||
// 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();
|
||||||
|
|
||||||
|
@ -377,6 +399,7 @@ private:
|
||||||
float first_wipe_line;
|
float first_wipe_line;
|
||||||
float wipe_volume;
|
float wipe_volume;
|
||||||
float wipe_length;
|
float wipe_length;
|
||||||
|
float nozzle_change_depth{0};
|
||||||
// BBS
|
// BBS
|
||||||
float purge_volume;
|
float purge_volume;
|
||||||
ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f, float wl = 0, float pv = 0)
|
ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f, float wl = 0, float pv = 0)
|
||||||
|
@ -409,7 +432,7 @@ private:
|
||||||
|
|
||||||
void toolchange_Unload(
|
void toolchange_Unload(
|
||||||
WipeTowerWriter &writer,
|
WipeTowerWriter &writer,
|
||||||
const box_coordinates &cleaning_box,
|
const box_coordinates &cleaning_box,
|
||||||
const std::string& current_material,
|
const std::string& current_material,
|
||||||
const int new_temperature);
|
const int new_temperature);
|
||||||
|
|
||||||
|
@ -417,11 +440,11 @@ private:
|
||||||
WipeTowerWriter &writer,
|
WipeTowerWriter &writer,
|
||||||
const size_t new_tool,
|
const size_t new_tool,
|
||||||
const std::string& new_material);
|
const std::string& new_material);
|
||||||
|
|
||||||
void toolchange_Load(
|
void toolchange_Load(
|
||||||
WipeTowerWriter &writer,
|
WipeTowerWriter &writer,
|
||||||
const box_coordinates &cleaning_box);
|
const box_coordinates &cleaning_box);
|
||||||
|
|
||||||
void toolchange_Wipe(
|
void toolchange_Wipe(
|
||||||
WipeTowerWriter &writer,
|
WipeTowerWriter &writer,
|
||||||
const box_coordinates &cleaning_box,
|
const box_coordinates &cleaning_box,
|
||||||
|
@ -433,4 +456,4 @@ private:
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif // WipeTowerPrusaMM_hpp_
|
#endif // WipeTowerPrusaMM_hpp_
|
||||||
|
|
|
@ -952,7 +952,7 @@ static std::vector<std::string> s_Preset_printer_options {
|
||||||
// BBS
|
// BBS
|
||||||
"scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "machine_pause_gcode", "template_custom_gcode",
|
"scan_first_layer", "machine_load_filament_time", "machine_unload_filament_time", "machine_pause_gcode", "template_custom_gcode",
|
||||||
"nozzle_type","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types","support_chamber_temp_control","support_air_filtration","printer_structure","thumbnail_size",
|
"nozzle_type","auxiliary_fan", "nozzle_volume","upward_compatible_machine", "z_hop_types","support_chamber_temp_control","support_air_filtration","printer_structure","thumbnail_size",
|
||||||
"best_object_pos","head_wrap_detect_zone","printer_notes",
|
"best_object_pos","extruder_change_length","head_wrap_detect_zone","printer_notes",
|
||||||
"enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut",
|
"enable_long_retraction_when_cut","long_retractions_when_cut","retraction_distances_when_cut",
|
||||||
//OrcaSlicer
|
//OrcaSlicer
|
||||||
"host_type", "print_host", "printhost_apikey",
|
"host_type", "print_host", "printhost_apikey",
|
||||||
|
|
|
@ -2456,6 +2456,7 @@ void Print::_make_wipe_tower()
|
||||||
WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(),
|
WipeTower wipe_tower(m_config, m_plate_index, m_origin, m_config.prime_volume, m_wipe_tower_data.tool_ordering.first_extruder(),
|
||||||
m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z);
|
m_wipe_tower_data.tool_ordering.empty() ? 0.f : m_wipe_tower_data.tool_ordering.back().print_z);
|
||||||
|
|
||||||
|
wipe_tower.set_filament_map(this->get_filament_maps());
|
||||||
// Set the extruder & material properties at the wipe tower object.
|
// Set the extruder & material properties at the wipe tower object.
|
||||||
for (size_t i = 0; i < number_of_extruders; ++ i)
|
for (size_t i = 0; i < number_of_extruders; ++ i)
|
||||||
wipe_tower.set_extruder(i, m_config);
|
wipe_tower.set_extruder(i, m_config);
|
||||||
|
|
|
@ -3087,6 +3087,14 @@ void PrintConfigDef::init_fff_params()
|
||||||
def->set_default_value(new ConfigOptionStrings { "Direct Drive Normal" });
|
def->set_default_value(new ConfigOptionStrings { "Direct Drive Normal" });
|
||||||
def->cli = ConfigOptionDef::nocli;
|
def->cli = ConfigOptionDef::nocli;
|
||||||
|
|
||||||
|
def = this->add("extruder_change_length", coFloats);
|
||||||
|
def->label = L("Extruder change length");
|
||||||
|
def->tooltip = L("Extruder change length");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->min = 0;
|
||||||
|
def->mode = comAdvanced;
|
||||||
|
def->set_default_value(new ConfigOptionFloats{10});
|
||||||
|
|
||||||
def = this->add("extruder_ams_count", coStrings);
|
def = this->add("extruder_ams_count", coStrings);
|
||||||
def->label = "Extruder ams count";
|
def->label = "Extruder ams count";
|
||||||
def->tooltip = "Ams counts of per extruder";
|
def->tooltip = "Ams counts of per extruder";
|
||||||
|
|
|
@ -1054,6 +1054,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||||
((ConfigOptionBool, reduce_crossing_wall))
|
((ConfigOptionBool, reduce_crossing_wall))
|
||||||
((ConfigOptionFloatOrPercent, max_travel_detour_distance))
|
((ConfigOptionFloatOrPercent, max_travel_detour_distance))
|
||||||
((ConfigOptionPoints, printable_area))
|
((ConfigOptionPoints, printable_area))
|
||||||
|
((ConfigOptionFloats, extruder_change_length))
|
||||||
//BBS: add bed_exclude_area
|
//BBS: add bed_exclude_area
|
||||||
((ConfigOptionPoints, bed_exclude_area))
|
((ConfigOptionPoints, bed_exclude_area))
|
||||||
((ConfigOptionPoints, head_wrap_detect_zone))
|
((ConfigOptionPoints, head_wrap_detect_zone))
|
||||||
|
|
|
@ -3052,7 +3052,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",
|
||||||
"best_object_pos"
|
"best_object_pos", "extruder_change_length"
|
||||||
}))
|
}))
|
||||||
, sidebar(new Sidebar(q))
|
, sidebar(new Sidebar(q))
|
||||||
, notification_manager(std::make_unique<NotificationManager>(q))
|
, notification_manager(std::make_unique<NotificationManager>(q))
|
||||||
|
|
|
@ -3546,6 +3546,8 @@ void TabPrinter::build_fff()
|
||||||
optgroup->append_single_option_line("printable_height");
|
optgroup->append_single_option_line("printable_height");
|
||||||
optgroup->append_single_option_line("nozzle_volume");
|
optgroup->append_single_option_line("nozzle_volume");
|
||||||
optgroup->append_single_option_line("best_object_pos");
|
optgroup->append_single_option_line("best_object_pos");
|
||||||
|
// todo: for multi_extruder test
|
||||||
|
optgroup->append_single_option_line("extruder_change_length");
|
||||||
// BBS
|
// BBS
|
||||||
#if 0
|
#if 0
|
||||||
//optgroup->append_single_option_line("z_offset");
|
//optgroup->append_single_option_line("z_offset");
|
||||||
|
|
Loading…
Reference in New Issue