ENH: support tpu for multi_extruder

jira: none
Change-Id: I556804aadac00406e7214b86f7925170a90c55ce
This commit is contained in:
zhimin.zeng 2024-09-04 09:38:16 +08:00 committed by lane.wei
parent 22feef013c
commit ede9f90a79
6 changed files with 193 additions and 37 deletions

View File

@ -474,6 +474,52 @@ void ToolOrdering::collect_extruders(const PrintObject &object, const std::vecto
}
}
std::set<int> ToolOrdering::get_tpu_filaments() const
{
std::vector<unsigned int> all_filaments;
for (const auto &lt : m_layer_tools) {
append(all_filaments, lt.extruders);
sort_remove_duplicates(all_filaments);
}
std::set<int> tpu_filaments;
for (unsigned int filament_id : all_filaments) {
std::string filament_name = m_print->config().filament_type.get_at(filament_id);
if (filament_name == "TPU") {
tpu_filaments.insert(filament_id);
}
}
return tpu_filaments;
}
bool ToolOrdering::check_tpu_group(std::vector<int> filament_maps) const
{
std::vector<unsigned int> all_filaments;
for (const auto &lt : m_layer_tools) {
append(all_filaments, lt.extruders);
sort_remove_duplicates(all_filaments);
}
int check_extruder_id = -1;
std::map<int, std::vector<int>> extruder_filament_nums;
for (unsigned int filament_id : all_filaments) {
int extruder_id = filament_maps[filament_id];
extruder_filament_nums[extruder_id].push_back(filament_id);
std::string filament_name = m_print->config().filament_type.get_at(filament_id);
if (filament_name == "TPU") {
check_extruder_id = filament_maps[filament_id];
}
if (check_extruder_id != -1 && (extruder_filament_nums[check_extruder_id].size() > 1)) {
return false;
}
}
return true;
}
// Reorder extruders to minimize layer changes.
void ToolOrdering::reorder_extruders(unsigned int last_extruder_id)
{
@ -902,6 +948,18 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
using FlushMatrix = std::vector<std::vector<float>>;
size_t nozzle_nums = print_config->nozzle_diameter.values.size();
std::vector<std::set<int>> extruder_tpu_status(2, std::set<int>());
if (nozzle_nums > 1) {
std::set<int> tpu_filaments = get_tpu_filaments();
if (tpu_filaments.size() > 1) {
throw Slic3r::RuntimeError(std::string("Only supports up to one TPU filament."));
}
// todo multi_exturder: Need to determine whether the TPU can be placed on the left or right head according to the print model.
extruder_tpu_status[0] = tpu_filaments;
}
std::vector<FlushMatrix> nozzle_flush_mtx;
for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
std::vector<float> flush_matrix(cast<float>(get_flush_volumes_matrix(print_config->flush_volumes_matrix.values, nozzle_id, nozzle_nums)));
@ -937,6 +995,15 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
m_print->update_filament_maps_to_config(filament_maps);
}
std::transform(filament_maps.begin(), filament_maps.end(), filament_maps.begin(), [](int value) { return value - 1; });
if (!check_tpu_group(filament_maps)) {
if (map_mode == FilamentMapMode::fmmManual) {
throw Slic3r::RuntimeError(std::string("Manual grouping error: TPU can only be placed in a nozzle alone."));
}
else {
throw Slic3r::RuntimeError(std::string("Auto grouping error: TPU can only be placed in a nozzle alone."));
}
}
}
std::vector<std::vector<unsigned int>>filament_sequences;

View File

@ -238,6 +238,9 @@ private:
void initialize_layers(std::vector<coordf_t> &zs);
void collect_extruders(const PrintObject &object, const std::vector<std::pair<double, unsigned int>> &per_layer_extruder_switches);
void reorder_extruders(unsigned int last_extruder_id);
std::set<int> get_tpu_filaments() const;
bool check_tpu_group(std::vector<int> filament_maps) const;
// BBS
void reorder_extruders(std::vector<unsigned int> tool_order_layer0);
void fill_wipe_tower_partitions(const PrintConfig &config, coordf_t object_bottom_z, coordf_t max_layer_height);

View File

@ -616,7 +616,8 @@ WipeTower::WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origi
//wipe_volumes(flush_matrix)
m_wipe_volume(prime_volume),
m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth),
m_nozzle_change_length(config.extruder_change_length.get_at(0))
m_nozzle_change_length(config.extruder_change_length.get_at(0)),
m_is_multi_extruder(config.nozzle_diameter.size() > 1)
{
// Read absolute value of first layer speed, if given as percentage,
// it is taken over following default. Speeds from config are not
@ -831,7 +832,37 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
// BBS
//writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
// ensure travel to initial_positoin
if (m_is_multi_extruder && is_tpu_filament(tool)) {
float dy = 2 * m_perimeter_width;
float nozzle_change_speed = 60.0f * m_filpar[tool].max_e_speed / m_extrusion_flow;
nozzle_change_speed *= 0.25;
const float &xl = cleaning_box.ld.x();
const float &xr = cleaning_box.rd.x();
Vec2f start_pos = m_nozzle_change_result.start_pos + Vec2f(0, m_perimeter_width);
bool left_to_right = true;
double tpu_travel_length = 5;
double e_flow = extrusion_flow(0.2);
double length = tpu_travel_length / e_flow;
int tpu_line_count = length / (m_wipe_tower_width - 2 * m_perimeter_width) + 1;
writer.travel(start_pos);
for (int i = 0; true; ++i) {
if (left_to_right)
writer.travel(xr - m_perimeter_width, writer.y(), nozzle_change_speed);
else
writer.travel(xl + m_perimeter_width, writer.y(), nozzle_change_speed);
if (i == tpu_line_count - 1)
break;
writer.travel(writer.x(), writer.y() + dy);
left_to_right = !left_to_right;
}
}
{
writer.travel(initial_position - Vec2f(0.5, 0.5));
writer.travel(initial_position);
@ -897,19 +928,22 @@ WipeTower::ToolChangeResult WipeTower::tool_change(size_t tool, bool extrude_per
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;
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;
wipe_length = b.wipe_length;
wipe_depth = b.required_depth;
purge_volume = b.purge_volume;
if (has_tpu_filament())
nozzle_change_line_count = ((b.nozzle_change_depth + WT_EPSILON) / m_perimeter_width + 1) / 2;
else
nozzle_change_line_count = (b.nozzle_change_depth + WT_EPSILON) / m_perimeter_width;
break;
}
} else {
@ -917,7 +951,7 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int
}
float nozzle_change_speed = 60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow;
if (m_filpar[m_current_tool].material == "TPU") {
if (is_tpu_filament(m_current_tool)) {
nozzle_change_speed *= 0.25;
}
@ -932,8 +966,7 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int
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,
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);
@ -945,7 +978,9 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int
const float &xl = cleaning_box.ld.x();
const float &xr = cleaning_box.rd.x();
float dy = m_layer_info->extra_spacing * m_perimeter_width;
float dy = m_layer_info->extra_spacing * m_perimeter_width;
if (has_tpu_filament())
dy = 2 * m_perimeter_width;
float start_y = writer.y();
@ -972,35 +1007,60 @@ WipeTower::NozzleChangeResult WipeTower::nozzle_change(int old_filament_id, int
writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
m_depth_traversed += (nozzle_change_line_count) * dy;
m_depth_traversed += (nozzle_change_line_count - 1) *dy + m_perimeter_width;
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;
if (is_tpu_filament(m_current_tool))
{
bool left_to_right = !m_left_to_right;
double tpu_travel_length = 5;
double e_flow = extrusion_flow(0.2);
double length = tpu_travel_length / e_flow;
int tpu_line_count = length / (m_wipe_tower_width - 2 * m_perimeter_width) + 1;
writer.travel(writer.x(), writer.y() - m_perimeter_width);
for (int i = 0; true; ++i) {
if (left_to_right)
writer.travel(xr - m_perimeter_width, writer.y(), nozzle_change_speed);
else
writer.travel(xl + m_perimeter_width, writer.y(), nozzle_change_speed);
if (i == tpu_line_count - 1)
break;
writer.travel(writer.x(), writer.y() - dy);
left_to_right = !left_to_right;
}
}
else {
wipe_pos.x() += wipe_distance;
}
writer.append("; WIPE_START\n");
writer.extrude_explicit(wipe_pos, -2);
writer.append("; WIPE_END\n");
auto float_to_string_with_precision = [](float value, int precision) {
std::ostringstream out;
out << std::fixed << std::setprecision(precision) << value;
return out.str();
};
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);
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());
result.start_pos = initial_position;
result.end_pos = writer.pos();
result.gcode = std::move(writer.gcode());
return result;
}
@ -1565,7 +1625,10 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in
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;
if (has_tpu_filament())
nozzle_change_depth = (2 * nozzle_change_line_count - 1) * m_perimeter_width;
else
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);
@ -1620,7 +1683,7 @@ void WipeTower::plan_tower()
if (m_enable_timelapse_print && max_depth < EPSILON)
max_depth = min_wipe_tower_depth;
if (max_depth + EPSILON < min_wipe_tower_depth)
if (max_depth + EPSILON < min_wipe_tower_depth && !has_tpu_filament())
m_extra_spacing = min_wipe_tower_depth / max_depth;
else
m_extra_spacing = 1.f;
@ -1723,6 +1786,10 @@ void WipeTower::save_on_last_wipe()
}
}
bool WipeTower::is_tpu_filament(int filament_id) const
{
return m_filpar[filament_id].material == "TPU";
}
// BBS: consider both soluable and support properties
// Return index of first toolchange that switches to non-soluble and non-support extruder

View File

@ -259,6 +259,9 @@ public:
void set_filament_map(const std::vector<int> &filament_map) { m_filament_map = filament_map; }
void set_has_tpu_filament(bool has_tpu) { m_has_tpu_filament = has_tpu; }
bool has_tpu_filament() const { return m_has_tpu_filament; }
struct FilamentParameters {
std::string material = "PLA";
bool is_soluble = false;
@ -320,6 +323,8 @@ private:
size_t m_cur_layer_id;
NozzleChangeResult m_nozzle_change_result;
std::vector<int> m_filament_map;
bool m_has_tpu_filament{false};
bool m_is_multi_extruder{false};
// G-code generator parameters.
// BBS: remove useless config
@ -385,6 +390,8 @@ private:
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
void save_on_last_wipe();
bool is_tpu_filament(int filament_id) const;
// BBS
box_coordinates align_perimeter(const box_coordinates& perimeter_box);

View File

@ -67,6 +67,17 @@ void Print::clear()
m_statistics_by_extruder_count.clear();
}
bool Print::has_tpu_filament() const
{
for (unsigned int filament_id : m_wipe_tower_data.tool_ordering.all_extruders()) {
std::string filament_name = m_config.filament_type.get_at(filament_id);
if (filament_name == "TPU") {
return true;
}
}
return false;
}
// Called by Print::apply().
// This method only accepts PrintConfig option keys.
bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* new_config */, const std::vector<t_config_option_key> &opt_keys)
@ -2458,7 +2469,7 @@ void Print::_make_wipe_tower()
// BBS: in BBL machine, wipe tower is only use to prime extruder. So just use a global wipe volume.
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);
wipe_tower.set_has_tpu_filament(this->has_tpu_filament());
wipe_tower.set_filament_map(this->get_filament_maps());
// Set the extruder & material properties at the wipe tower object.
for (size_t i = 0; i < number_of_extruders; ++ i)

View File

@ -899,6 +899,7 @@ private:
//BBS
static StringObjectException check_multi_filament_valid(const Print &print);
bool has_tpu_filament() const;
bool invalidate_state_by_config_options(const ConfigOptionResolver &new_config, const std::vector<t_config_option_key> &opt_keys);
void _make_skirt();