ENH: enhance the travel path of change filament

Change-Id: I720b833fc203f7ece63487e00290f4d91423c9f9
(cherry picked from commit 55e5fd8df1576d2b9252b2bd9e3e494db76218bf)
This commit is contained in:
zhimin.zeng 2023-01-12 16:54:17 +08:00 committed by Lane.Wei
parent de8b37b63c
commit 1015b7bca9
5 changed files with 159 additions and 2 deletions

View file

@ -1,7 +1,7 @@
{
"name": "Bambulab",
"url": "http://www.bambulab.com/Parameters/vendor/BBL.json",
"version": "01.05.00.05",
"version": "01.05.00.06",
"force_update": "0",
"description": "the initial version of BBL configurations",
"machine_model_list": [

View file

@ -154,7 +154,7 @@
"nozzle_type": "hardened_steel",
"silent_mode": "0",
"single_extruder_multi_material": "1",
"change_filament_gcode": "M620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1}\nG17\nG2 Z{max_layer_z + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}M104 S[old_filament_temp]{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\nM620.1 X F21000\nT[next_extruder]\nM620.1 E F{new_filament_e_feedrate}\n; always use highest temperature to flush\nM400\nM109 S[nozzle_temperature_range_high]\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\nG1 E[old_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n; FLUSH_START\nM400\nM109 S[new_filament_temp]\nG1 E2 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\nG1 Z[z_after_toolchange] F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A",
"change_filament_gcode": "M620 S[next_extruder]A\nM204 S9000\n{if toolchange_count > 1}\nG17\nG2 Z{max_layer_z + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little from second lift\n{endif}\nG1 Z{max_layer_z + 3.0} F1200\n\nG1 X70 F21000\nG1 Y245\nG1 Y265 F3000\nM400\nM106 P1 S0\nM106 P2 S0\n{if old_filament_temp > 142 && next_extruder < 255}M104 S[old_filament_temp]{endif}\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 X120 F15000\n\nG1 X20 Y50 F21000\nG1 Y-3\nM620.1 X F21000\n{if toolchange_count == 1}\n; get travel path for change filament\nM620.1 X[travel_point_1_x] Y[travel_point_1_y] F21000 P0\nM620.1 X[travel_point_2_x] Y[travel_point_2_y] F21000 P1\nM620.1 X[travel_point_3_x] Y[travel_point_3_y] F21000 P2\n{endif}\nT[next_extruder]\nM620.1 E F{new_filament_e_feedrate}\n; always use highest temperature to flush\nM400\nM109 S[nozzle_temperature_range_high]\n\n{if next_extruder < 255}\nM400\n\nG92 E0\n{if flush_length_1 > 1}\n; FLUSH_START\n{if flush_length_1 > 23.7}\nG1 E23.7 F{old_filament_e_feedrate} ; do not need pulsatile flushing for start part\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{old_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\nG1 E{(flush_length_1 - 23.7) * 0.02} F50\nG1 E{(flush_length_1 - 23.7) * 0.23} F{new_filament_e_feedrate}\n{else}\nG1 E{flush_length_1} F{old_filament_e_feedrate}\n{endif}\n; FLUSH_END\nG1 E-[old_retract_length_toolchange] F1800\nG1 E[old_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_2 > 1}\n; FLUSH_START\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\nG1 E{flush_length_2 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_2 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_3 > 1}\n; FLUSH_START\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\nG1 E{flush_length_3 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_3 * 0.02} F50\n; FLUSH_END\nG1 E-[new_retract_length_toolchange] F1800\nG1 E[new_retract_length_toolchange] F300\n{endif}\n\n{if flush_length_4 > 1}\n; FLUSH_START\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\nG1 E{flush_length_4 * 0.18} F{new_filament_e_feedrate}\nG1 E{flush_length_4 * 0.02} F50\n; FLUSH_END\n{endif}\n; FLUSH_START\nM400\nM109 S[new_filament_temp]\nG1 E2 F{new_filament_e_feedrate} ;Compensate for filament spillage during waiting temperature\n; FLUSH_END\nM400\nG92 E0\nG1 E-[new_retract_length_toolchange] F1800\nM106 P1 S255\nM400 S3\nG1 X80 F15000\nG1 X60 F15000\nG1 X80 F15000\nG1 X60 F15000; shake to put down garbage\n\nG1 X70 F5000\nG1 X90 F3000\nG1 Y255 F4000\nG1 X100 F5000\nG1 Y265 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X70 F10000\nG1 X100 F5000\nG1 X165 F15000; wipe and shake\nG1 Y256 ; move Y to aside, prevent collision\nM400\nG1 Z[z_after_toolchange] F3000\n{if layer_z <= (initial_layer_print_height + 0.001)}\nM204 S[initial_layer_acceleration]\n{else}\nM204 S[default_acceleration]\n{endif}\n{else}\nG1 X[x_after_toolchange] Y[y_after_toolchange] Z[z_after_toolchange] F12000\n{endif}\nM621 S[next_extruder]A",
"layer_change_gcode": "; layer num/total_layer_count: {layer_num+1}/[total_layer_count]\nM622.1 S1 ; for prev firware, default turned on\nM1002 judge_flag timelapse_record_flag\nM622 J1\n{if timelapse_type == 0} ; timelapse without wipe tower\nM971 S11 C10 O0\n{elsif timelapse_type == 1} ; timelapse with wipe tower\nG92 E0\nG1 E-[retraction_length] F1800\nG17\nG2 Z{layer_z + 0.4} I0.86 J0.86 P1 F10000 ; spiral lift a little\nG1 X65 Y245 F12000 ; move to safe pos\nG17\nG2 Z{layer_z} I0.86 J0.86 P1 F10000\nG1 Y265 F3000\nM400 P100\nM971 S11 C10 O0\nG92 E0\nG1 E[retraction_length] F300\nG1 X100 F5000\nG1 Y255\n{endif}\nM623\n; update layer progress\nM73 L{layer_num+1}\nM991 S0 P{layer_num} ;notify layer change",
"machine_end_gcode": ";===== date: 20230110 =====================\n{if timelapse_type == 0}\nM991 S0 P-1 ;end traditional timelapse immediately\n{endif}\nM400 ; wait for buffer to clear\nG92 E0 ; zero the extruder\nG1 E-0.8 F1800 ; retract\nG1 Z{max_layer_z + 0.5} F900 ; lower z a little\nG1 X65 Y245 F12000 ; move to safe pos \nG1 Y265 F3000\n{if timelapse_type == 1}\nM991 S0 P-1 ;end smooth timelapse at safe pos\nM400 S2 ;wait for last picture to be taken\n{endif}\n\nG1 X65 Y245 F12000\nG1 Y265 F3000\nM140 S0 ; turn off bed\nM106 S0 ; turn off fan\nM106 P2 S0 ; turn off remote part cooling fan\nM106 P3 S0 ; turn off chamber cooling fan\n\nG1 X100 F12000 ; wipe\n; pull back filament to AMS\nM620 S255\nG1 X20 Y50 F12000\nG1 Y-3\nT255\nG1 X65 F12000\nG1 Y265\nG1 X100 F12000 ; wipe\nM621 S255\nM104 S0 ; turn off hotend\n\nM400 ; wait all motion done\nM17 S\nM17 Z0.4 ; lower z motor current to reduce impact if there is something in the bottom\n{if (max_layer_z + 100.0) < 250}\n G1 Z{max_layer_z + 100.0} F600\n G1 Z{max_layer_z +98.0}\n{else}\n G1 Z250 F600\n G1 Z248\n{endif}\nM400 P100\nM17 R ; restore z current\n\nG90\nG1 X128 Y250 F3600\n\nM220 S100 ; Reset feedrate magnitude\nM201.2 K1.0 ; Reset acc magnitude\nM73.2 R1.0 ;Reset left time magnitude\nM1002 set_gcode_claim_speed_level : 0\n\nM17 X0.8 Y0.8 Z0.5 ; lower motor current to 45% power\n",
"machine_pause_gcode": "M400 U1\n",

View file

@ -81,6 +81,132 @@ static const int g_max_flush_count = 4;
bool GCode::gcode_label_objects = false;
Vec2d travel_point_1;
Vec2d travel_point_2;
Vec2d travel_point_3;
static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
{
// give safe value in case there is no start_end_points in config
std::vector<Vec2d> out_points;
out_points.emplace_back(Vec2d(54, 0));
out_points.emplace_back(Vec2d(54, 120));
out_points.emplace_back(Vec2d(54, 245));
// get the start_end_points from config (20, -3) (54, 245)
Pointfs points = print.config().start_end_points.values;
if (points.size() != 2)
return out_points;
Vec2d start_point = points[0];
Vec2d end_point = points[1];
// the cutter area size(18, 28)
Pointfs excluse_area = print.config().bed_exclude_area.values;
if (excluse_area.size() != 4)
return out_points;
double cutter_area_x = excluse_area[2].x() + 2;
double cutter_area_y = excluse_area[2].y() + 2;
double start_x_position = start_point.x();
double end_x_position = end_point.x();
double end_y_position = end_point.y();
bool can_travel_form_left = true;
// step 1: get the x-range intervals of all objects
std::vector<std::pair<double, double>> object_intervals;
for (PrintObject *print_object : print.objects()) {
const PrintInstances &print_instances = print_object->instances();
BoundingBoxf3 bounding_box = print_instances[0].model_instance->get_object()->bounding_box();
if (bounding_box.min.x() < start_x_position && bounding_box.min.y() < cutter_area_y)
can_travel_form_left = false;
std::pair<double, double> object_scope = std::make_pair(bounding_box.min.x() - 2, bounding_box.max.x() + 2);
if (object_intervals.empty())
object_intervals.push_back(object_scope);
else {
std::vector<std::pair<double, double>> new_object_intervals;
bool intervals_intersect = false;
std::pair<double, double> new_merged_scope;
for (auto object_interval : object_intervals) {
if (object_interval.second >= object_scope.first && object_interval.first <= object_scope.second) {
if (intervals_intersect) {
new_merged_scope = std::make_pair(std::min(object_interval.first, new_merged_scope.first), std::max(object_interval.second, new_merged_scope.second));
} else { // it is the first intersection
new_merged_scope = std::make_pair(std::min(object_interval.first, object_scope.first), std::max(object_interval.second, object_scope.second));
}
intervals_intersect = true;
} else {
new_object_intervals.push_back(object_interval);
}
}
if (intervals_intersect) {
new_object_intervals.push_back(new_merged_scope);
object_intervals = new_object_intervals;
} else
object_intervals.push_back(object_scope);
}
}
// step 2: get the available x-range
std::sort(object_intervals.begin(), object_intervals.end(),
[](const std::pair<double, double> &left, const std::pair<double, double> &right) {
return left.first < right.first;
});
std::vector<std::pair<double, double>> available_intervals;
double start_position = 0;
for (auto object_interval : object_intervals) {
if (object_interval.first > start_position)
available_intervals.push_back(std::make_pair(start_position, object_interval.first));
start_position = object_interval.second;
}
available_intervals.push_back(std::make_pair(start_position, 255));
// step 3: get the nearest path
double new_path = 255;
for (auto available_interval : available_intervals) {
if (available_interval.first > end_x_position) {
double distance = available_interval.first - end_x_position;
new_path = abs(end_x_position - new_path) < distance ? new_path : available_interval.first;
break;
} else {
if (available_interval.second >= end_x_position) {
new_path = end_x_position;
break;
} else if (!can_travel_form_left && available_interval.second < start_x_position) {
continue;
} else {
new_path = available_interval.second;
}
}
}
// step 4: generate path points (new_path == start_x_position means not need to change path)
Vec2d out_point_1;
Vec2d out_point_2;
Vec2d out_point_3;
if (new_path < start_x_position) {
out_point_1 = Vec2d(start_x_position, cutter_area_y);
out_point_2 = Vec2d(new_path, cutter_area_y);
out_point_3 = Vec2d(new_path, end_y_position);
} else {
out_point_1 = Vec2d(new_path, 0);
out_point_2 = Vec2d(new_path, end_y_position / 2);
out_point_3 = Vec2d(new_path, end_y_position);
}
out_points.clear();
out_points.emplace_back(out_point_1);
out_points.emplace_back(out_point_2);
out_points.emplace_back(out_point_3);
return out_points;
}
// Only add a newline in case the current G-code does not end with a newline.
static inline void check_add_eol(std::string& gcode)
{
@ -367,6 +493,12 @@ bool GCode::gcode_label_objects = false;
config.set_key_value("second_flush_volume", new ConfigOptionFloat(purge_length / 2.f));
config.set_key_value("old_filament_e_feedrate", new ConfigOptionInt(old_filament_e_feedrate));
config.set_key_value("new_filament_e_feedrate", new ConfigOptionInt(new_filament_e_feedrate));
config.set_key_value("travel_point_1_x", new ConfigOptionFloat(float(travel_point_1.x())));
config.set_key_value("travel_point_1_y", new ConfigOptionFloat(float(travel_point_1.y())));
config.set_key_value("travel_point_2_x", new ConfigOptionFloat(float(travel_point_2.x())));
config.set_key_value("travel_point_2_y", new ConfigOptionFloat(float(travel_point_2.y())));
config.set_key_value("travel_point_3_x", new ConfigOptionFloat(float(travel_point_3.x())));
config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y())));
int flush_count = std::min(g_max_flush_count, (int)std::round(purge_volume / g_purge_volume_one_time));
float flush_unit = purge_length / flush_count;
@ -1569,6 +1701,16 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato
std::function<void(void)> throw_if_canceled_func = [&print]() { print.throw_if_canceled(); };
m_seam_placer.init(print, throw_if_canceled_func);
// BBS: get path for change filament
if (m_writer.multiple_extruders) {
std::vector<Vec2d> points = get_path_of_change_filament(print);
if (points.size() == 3) {
travel_point_1 = points[0];
travel_point_2 = points[1];
travel_point_3 = points[2];
}
}
// BBS: priming logic is removed, always set first extruer here.
//if (! (has_wipe_tower && print.config().single_extruder_multi_material_priming))
{
@ -3991,6 +4133,12 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z)
dyn_config.set_key_value("second_flush_volume", new ConfigOptionFloat(wipe_length / 2.f));
dyn_config.set_key_value("old_filament_e_feedrate", new ConfigOptionInt(old_filament_e_feedrate));
dyn_config.set_key_value("new_filament_e_feedrate", new ConfigOptionInt(new_filament_e_feedrate));
dyn_config.set_key_value("travel_point_1_x", new ConfigOptionFloat(float(travel_point_1.x())));
dyn_config.set_key_value("travel_point_1_y", new ConfigOptionFloat(float(travel_point_1.y())));
dyn_config.set_key_value("travel_point_2_x", new ConfigOptionFloat(float(travel_point_2.x())));
dyn_config.set_key_value("travel_point_2_y", new ConfigOptionFloat(float(travel_point_2.y())));
dyn_config.set_key_value("travel_point_3_x", new ConfigOptionFloat(float(travel_point_3.x())));
dyn_config.set_key_value("travel_point_3_y", new ConfigOptionFloat(float(travel_point_3.y())));
int flush_count = std::min(g_max_flush_count, (int)std::round(wipe_volume / g_purge_volume_one_time));
float flush_unit = wipe_length / flush_count;

View file

@ -1935,6 +1935,14 @@ void PrintConfigDef::init_fff_params()
def->readonly = true;
def->set_default_value(new ConfigOptionFloat { 0.0 });
def = this->add("start_end_points", coPoints);
def->label = L("Start end points");
def->tooltip = L("The start and end points which is from cutter area to garbage can.");
def->mode = comDevelop;
def->readonly = true;
// start and end point is from the change_filament_gcode
def->set_default_value(new ConfigOptionPoints{Vec2d(30, -3), Vec2d(54, 245)});
def = this->add("reduce_infill_retraction", coBool);
def->label = L("Reduce infill retraction");
def->tooltip = L("Don't retract when the travel is in infill area absolutely. That means the oozing can't been seen. "

View file

@ -939,6 +939,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
// BBS: not in any preset, calculated before slicing
((ConfigOptionBool, has_prime_tower))
((ConfigOptionFloat, nozzle_volume))
((ConfigOptionPoints, start_end_points))
((ConfigOptionEnum<TimelapseType>, timelapse_type))
// BBS: move from PrintObjectConfig
((ConfigOptionBool, independent_support_layer_height))