Tsmith35 per BS PR4631 (#6709)

ENH: support spiral lift with timelapse gcode
The existing implementation did only read the new Z position from the injected timelapse_gcode and flagged the position as unsafe because of this.

This change reads X, Y and Z pos from the timelapgse_gcode and will keep the position state correct to enable safety checks required for using spiral Z hop.

Because of this, spiral Z hop can be used everyhwere now. The same pattern is also applied for layer_change/toolhead gcode injection.

The set_current_position_clear method is unused but will be kept in implementation for future scenarios.

Co-authored-by: Simon ziehmon@users.noreply.github.com
This commit is contained in:
Tom 2024-09-14 10:52:04 -05:00 committed by GitHub
parent 603e3e76b0
commit c8216accfd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 237 additions and 93 deletions

View file

@ -602,16 +602,34 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
toolchange_gcode_str = toolchange_retract_str + toolchange_gcode_str; toolchange_gcode_str = toolchange_retract_str + toolchange_gcode_str;
// BBS // BBS
{ {
// BBS: current position and fan_speed is unclear after interting change_filament_gcode
check_add_eol(toolchange_gcode_str); check_add_eol(toolchange_gcode_str);
// BBS: gcode writer doesn't know fan speed after inserting tool change gcode
toolchange_gcode_str += ";_FORCE_RESUME_FAN_SPEED\n"; toolchange_gcode_str += ";_FORCE_RESUME_FAN_SPEED\n";
gcodegen.writer().set_current_position_clear(false);
// BBS: check whether custom gcode changes the z position. Update if changed // BBS: check whether custom gcode changes the axis positions. Update if changed.
double temp_z_after_tool_change; bool position_changed = false;
if (GCodeProcessor::get_last_z_from_gcode(toolchange_gcode_str, temp_z_after_tool_change)) { Vec3d new_pos = gcodegen.writer().get_position();
Vec3d pos = gcodegen.writer().get_position();
pos(2) = temp_z_after_tool_change; double temp_x_after_toolchange_gcode;
gcodegen.writer().set_position(pos); if (GCodeProcessor::get_last_pos_from_gcode(toolchange_gcode_str, 0, temp_x_after_toolchange_gcode)) {
new_pos(0) = temp_x_after_toolchange_gcode;
position_changed = true;
}
double temp_y_after_toolchange_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(toolchange_gcode_str, 1, temp_y_after_toolchange_gcode)) {
new_pos(1) = temp_y_after_toolchange_gcode;
position_changed = true;
}
double temp_z_after_toolchange_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(toolchange_gcode_str, 2, temp_z_after_toolchange_gcode)) {
new_pos(2) = temp_z_after_toolchange_gcode;
position_changed = true;
}
if (position_changed) {
gcodegen.writer().set_position(new_pos);
} }
} }
@ -3669,17 +3687,37 @@ LayerResult GCode::process_layer(
gcode += this->change_layer(print_z); // this will increase m_layer_index gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer; m_layer = &layer;
m_object_layer_over_raft = false; m_object_layer_over_raft = false;
// insert timelapse_gcode when traditional mode is not used (smooth mode)
if(is_BBL_Printer()){ if(is_BBL_Printer()){
if (printer_structure == PrinterStructure::psI3 && !need_insert_timelapse_gcode_for_traditional && !m_spiral_vase && print.config().print_sequence == PrintSequence::ByLayer) { if (printer_structure == PrinterStructure::psI3 && !need_insert_timelapse_gcode_for_traditional && !m_spiral_vase && print.config().print_sequence == PrintSequence::ByLayer) {
std::string timepals_gcode = insert_timelapse_gcode();
gcode += timepals_gcode; std::string timelapse_gcode = insert_timelapse_gcode();
m_writer.set_current_position_clear(false); gcode += timelapse_gcode;
//BBS: check whether custom gcode changes the z position. Update if changed
double temp_z_after_timepals_gcode; //BBS: check whether custom gcode changes the axis positions. Update if changed.
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) { bool position_changed = false;
Vec3d pos = m_writer.get_position(); Vec3d new_pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode;
m_writer.set_position(pos); double temp_x_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 0, temp_x_after_timelapse_gcode)) {
new_pos(0) = temp_x_after_timelapse_gcode;
position_changed = true;
}
double temp_y_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 1, temp_y_after_timelapse_gcode)) {
new_pos(1) = temp_y_after_timelapse_gcode;
position_changed = true;
}
double temp_z_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 2, temp_z_after_timelapse_gcode)) {
new_pos(2) = temp_z_after_timelapse_gcode;
position_changed = true;
}
if (position_changed) {
m_writer.set_position(new_pos);
} }
} }
} else { } else {
@ -4027,21 +4065,40 @@ LayerResult GCode::process_layer(
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders. // Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
for (unsigned int extruder_id : layer_tools.extruders) for (unsigned int extruder_id : layer_tools.extruders)
{ {
// insert timelapse_gcode when wipe tower is enabled and traditional mode is used
if (has_wipe_tower) { if (has_wipe_tower) {
if (!m_wipe_tower->is_empty_wipe_tower_gcode(*this, extruder_id, extruder_id == layer_tools.extruders.back())) { if (!m_wipe_tower->is_empty_wipe_tower_gcode(*this, extruder_id, extruder_id == layer_tools.extruders.back())) {
if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) { if (need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) {
gcode += this->retract(false, false, LiftType::NormalLift); gcode += this->retract(false, false, LiftType::SpiralLift);
m_writer.add_object_change_labels(gcode); m_writer.add_object_change_labels(gcode);
std::string timepals_gcode = insert_timelapse_gcode(); std::string timelapse_gcode = insert_timelapse_gcode();
gcode += timepals_gcode; gcode += timelapse_gcode;
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed //BBS: check whether custom gcode changes the axis positions. Update if changed.
double temp_z_after_timepals_gcode; bool position_changed = false;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) { Vec3d new_pos = m_writer.get_position();
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode; double temp_x_after_timelapse_gcode;
m_writer.set_position(pos); if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 0, temp_x_after_timelapse_gcode)) {
new_pos(0) = temp_x_after_timelapse_gcode;
position_changed = true;
}
double temp_y_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 1, temp_y_after_timelapse_gcode)) {
new_pos(1) = temp_y_after_timelapse_gcode;
position_changed = true;
}
double temp_z_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 2, temp_z_after_timelapse_gcode)) {
new_pos(2) = temp_z_after_timelapse_gcode;
position_changed = true;
}
if (position_changed) {
m_writer.set_position(new_pos);
} }
has_insert_timelapse_gcode = true; has_insert_timelapse_gcode = true;
} }
@ -4152,18 +4209,22 @@ LayerResult GCode::process_layer(
if (m_config.reduce_crossing_wall) if (m_config.reduce_crossing_wall)
m_avoid_crossing_perimeters.init_layer(*m_layer); m_avoid_crossing_perimeters.init_layer(*m_layer);
std::string start_str;
std::string start_str_a;
std::string temp_start_str;
if (this->config().gcode_label_objects) { if (this->config().gcode_label_objects) {
gcode += std::string("; printing object ") + instance_to_print.print_object.model_object()->name + start_str_a = std::string("; printing object ") + instance_to_print.print_object.model_object()->name +
" id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " + " id:" + std::to_string(instance_to_print.print_object.get_id()) + " copy " +
std::to_string(inst.id) + "\n"; std::to_string(inst.id) + "\n";
} }
// exclude objects // exclude objects
if (m_enable_exclude_object) { if (m_enable_exclude_object) {
if (is_BBL_Printer()) { if (is_BBL_Printer()) {
m_writer.set_object_start_str( start_str =
std::string("; start printing object, unique label id: ") + std::string("; start printing object, unique label id: ") +
std::to_string(instance_to_print.label_object_id) + "\n" + "M624 " + std::to_string(instance_to_print.label_object_id) + "\n" + "M624 " +
_encode_label_ids_to_base64({instance_to_print.label_object_id}) + "\n"); _encode_label_ids_to_base64({instance_to_print.label_object_id}) + "\n";
m_writer.set_object_start_str(start_str);
} else { } else {
const auto gflavor = print.config().gcode_flavor.value; const auto gflavor = print.config().gcode_flavor.value;
if (gflavor == gcfKlipper) { if (gflavor == gcfKlipper) {
@ -4176,6 +4237,8 @@ LayerResult GCode::process_layer(
} }
} }
} }
temp_start_str = start_str + start_str_a;
gcode += start_str_a;
if (m_config.enable_overhang_speed && !m_config.overhang_speed_classic) if (m_config.enable_overhang_speed && !m_config.overhang_speed_classic)
m_extrusion_quality_estimator.set_current_object(&instance_to_print.print_object); m_extrusion_quality_estimator.set_current_object(&instance_to_print.print_object);
@ -4262,20 +4325,39 @@ LayerResult GCode::process_layer(
}; };
//BBS: for first layer, we always print wall firstly to get better bed adhesive force //BBS: for first layer, we always print wall firstly to get better bed adhesive force
//This behaviour is same with cura
// insert timelapse_gcode when no wipe tower, has infill and not first layer
if (is_infill_first && !first_layer) { if (is_infill_first && !first_layer) {
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) { if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) {
gcode += this->retract(false, false, LiftType::NormalLift); gcode += this->retract(false, false, LiftType::SpiralLift);
std::string timepals_gcode = insert_timelapse_gcode(); std::string timelapse_gcode = insert_timelapse_gcode();
gcode += timepals_gcode; gcode += timelapse_gcode;
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed //BBS: check whether custom gcode changes the axis positions. Update if changed.
double temp_z_after_timepals_gcode; bool position_changed = false;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) { Vec3d new_pos = m_writer.get_position();
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode; double temp_x_after_timelapse_gcode;
m_writer.set_position(pos); if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 0, temp_x_after_timelapse_gcode)) {
new_pos(0) = temp_x_after_timelapse_gcode;
position_changed = true;
}
double temp_y_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 1, temp_y_after_timelapse_gcode)) {
new_pos(1) = temp_y_after_timelapse_gcode;
position_changed = true;
}
double temp_z_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 2, temp_z_after_timelapse_gcode)) {
new_pos(2) = temp_z_after_timelapse_gcode;
position_changed = true;
}
if (position_changed) {
m_writer.set_position(new_pos);
} }
has_insert_timelapse_gcode = true; has_insert_timelapse_gcode = true;
@ -4284,18 +4366,37 @@ LayerResult GCode::process_layer(
gcode += this->extrude_perimeters(print, by_region_specific); gcode += this->extrude_perimeters(print, by_region_specific);
} else { } else {
gcode += this->extrude_perimeters(print, by_region_specific); gcode += this->extrude_perimeters(print, by_region_specific);
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) {
gcode += this->retract(false, false, LiftType::NormalLift);
std::string timepals_gcode = insert_timelapse_gcode(); // insert timelapse_gcode when no wipe tower, no infill and is first layer
gcode += timepals_gcode; if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode && has_infill(by_region_specific)) {
m_writer.set_current_position_clear(false); gcode += this->retract(false, false, LiftType::SpiralLift);
//BBS: check whether custom gcode changes the z position. Update if changed std::string timelapse_gcode = insert_timelapse_gcode();
double temp_z_after_timepals_gcode; gcode += timelapse_gcode;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) {
Vec3d pos = m_writer.get_position(); //BBS: check whether custom gcode changes the axis positions. Update if changed.
pos(2) = temp_z_after_timepals_gcode; bool position_changed = false;
m_writer.set_position(pos); Vec3d new_pos = m_writer.get_position();
double temp_x_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 0, temp_x_after_timelapse_gcode)) {
new_pos(0) = temp_x_after_timelapse_gcode;
position_changed = true;
}
double temp_y_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 1, temp_y_after_timelapse_gcode)) {
new_pos(1) = temp_y_after_timelapse_gcode;
position_changed = true;
}
double temp_z_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 2, temp_z_after_timelapse_gcode)) {
new_pos(2) = temp_z_after_timelapse_gcode;
position_changed = true;
}
if (position_changed) {
m_writer.set_position(new_pos);
} }
has_insert_timelapse_gcode = true; has_insert_timelapse_gcode = true;
@ -4362,22 +4463,41 @@ LayerResult GCode::process_layer(
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z << BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info(); log_memory_info();
// insert timelapse_gcode when no wipe tower and no infill
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) { if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) {
if (m_support_traditional_timelapse) if (m_support_traditional_timelapse)
m_support_traditional_timelapse = false; m_support_traditional_timelapse = false;
gcode += this->retract(false, false, LiftType::NormalLift); gcode += this->retract(false, false, LiftType::SpiralLift);
m_writer.add_object_change_labels(gcode); m_writer.add_object_change_labels(gcode);
std::string timepals_gcode = insert_timelapse_gcode(); std::string timelapse_gcode = insert_timelapse_gcode();
gcode += timepals_gcode; gcode += timelapse_gcode;
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed //BBS: check whether custom gcode changes the axis positions. Update if changed.
double temp_z_after_timepals_gcode; bool position_changed = false;
if (GCodeProcessor::get_last_z_from_gcode(timepals_gcode, temp_z_after_timepals_gcode)) { Vec3d new_pos = m_writer.get_position();
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_timepals_gcode; double temp_x_after_timelapse_gcode;
m_writer.set_position(pos); if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 0, temp_x_after_timelapse_gcode)) {
new_pos(0) = temp_x_after_timelapse_gcode;
position_changed = true;
}
double temp_y_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 1, temp_y_after_timelapse_gcode)) {
new_pos(1) = temp_y_after_timelapse_gcode;
position_changed = true;
}
double temp_z_after_timelapse_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(timelapse_gcode, 2, temp_z_after_timelapse_gcode)) {
new_pos(2) = temp_z_after_timelapse_gcode;
position_changed = true;
}
if (position_changed) {
m_writer.set_position(new_pos);
} }
} }
@ -6410,16 +6530,33 @@ std::string GCode::set_extruder(unsigned int extruder_id, double print_z, bool b
//BBS //BBS
{ {
//BBS: gcode writer doesn't know where the extruder is and whether fan speed is changed after inserting tool change gcode //BBS: gcode writer doesn't know fan speed after inserting tool change gcode
//Set this flag so that normal lift will be used the first time after tool change.
gcode += ";_FORCE_RESUME_FAN_SPEED\n"; gcode += ";_FORCE_RESUME_FAN_SPEED\n";
m_writer.set_current_position_clear(false);
//BBS: check whether custom gcode changes the z position. Update if changed //BBS: check whether custom gcode changes the axis positions. Update if changed.
double temp_z_after_tool_change; bool position_changed = false;
if (GCodeProcessor::get_last_z_from_gcode(toolchange_gcode_parsed, temp_z_after_tool_change)) { Vec3d new_pos = m_writer.get_position();
Vec3d pos = m_writer.get_position();
pos(2) = temp_z_after_tool_change; double temp_x_after_toolchange_gcode;
m_writer.set_position(pos); if (GCodeProcessor::get_last_pos_from_gcode(toolchange_gcode_parsed, 0, temp_x_after_toolchange_gcode)) {
new_pos(0) = temp_x_after_toolchange_gcode;
position_changed = true;
}
double temp_y_after_toolchange_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(toolchange_gcode_parsed, 1, temp_y_after_toolchange_gcode)) {
new_pos(1) = temp_y_after_toolchange_gcode;
position_changed = true;
}
double temp_z_after_toolchange_gcode;
if (GCodeProcessor::get_last_pos_from_gcode(toolchange_gcode_parsed, 2, temp_z_after_toolchange_gcode)) {
new_pos(2) = temp_z_after_toolchange_gcode;
position_changed = true;
}
if (position_changed) {
m_writer.set_position(new_pos);
} }
} }
} }
@ -6667,4 +6804,4 @@ void GCode::ObjectByExtruder::Island::Region::append(const Type type, const Extr
// a single object, or for possibly multiple objects with multiple instances. // a single object, or for possibly multiple objects with multiple instances.
} // namespace Slic3r } /* slic3r_GCode_cpp_ */

View file

@ -2185,13 +2185,14 @@ int GCodeProcessor::get_gcode_last_filament(const std::string& gcode_str)
return out_filament; return out_filament;
} }
//BBS: get last z position from gcode //BBS: get last position from gcode for specified axis
bool GCodeProcessor::get_last_z_from_gcode(const std::string& gcode_str, double& z) //axis index is the same as Vec3d (X=0, Y=1, Z=2)
bool GCodeProcessor::get_last_pos_from_gcode(const std::string& gcode_str, int axis, double& pos)
{ {
int str_size = gcode_str.size(); int str_size = gcode_str.size();
int start_index = 0; int start_index = 0;
int end_index = 0; int end_index = 0;
bool is_z_changed = false; bool is_axis_changed = false;
while (end_index < str_size) { while (end_index < str_size) {
//find a full line //find a full line
if (gcode_str[end_index] != '\n') { if (gcode_str[end_index] != '\n') {
@ -2211,24 +2212,32 @@ bool GCodeProcessor::get_last_z_from_gcode(const std::string& gcode_str, double&
|| line_str.find("G2 ") == 0 || line_str.find("G2 ") == 0
|| line_str.find("G3 ") == 0)) || line_str.find("G3 ") == 0))
{ {
auto z_pos = line_str.find(" Z"); std::string axis_str;
double temp_z = 0; if (axis == 0) {
if (z_pos != line_str.npos axis_str = "X";
&& z_pos + 2 < line_str.size()) { } else if (axis == 1) {
axis_str = "Y";
} else if (axis == 2) {
axis_str = "Z";
}
auto axis_pos = line_str.find(" " + axis_str);
double temp_axis_pos = 0;
if (axis_pos != line_str.npos
&& axis_pos + 2 < line_str.size()) {
// Try to parse the numeric value. // Try to parse the numeric value.
std::string z_sub = line_str.substr(z_pos + 2); std::string axis_substr = line_str.substr(axis_pos + 2);
char* c = &z_sub[0]; char* start_ptr = &axis_substr[0];
char* end = c + sizeof(z_sub.c_str()); char* end_ptr = start_ptr + sizeof(axis_substr.c_str());
auto is_end_of_word = [](char c) { auto is_end_of_word = [](char c) {
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';';
}; };
auto [pend, ec] = fast_float::from_chars(c, end, temp_z); auto [parsed_ptr, error_code] = fast_float::from_chars(start_ptr, end_ptr, temp_axis_pos);
if (pend != c && is_end_of_word(*pend)) { if (parsed_ptr != start_ptr && is_end_of_word(*parsed_ptr)) {
// The axis value has been parsed correctly. // The axis value has been parsed correctly.
z = temp_z; pos = temp_axis_pos;
is_z_changed = true; is_axis_changed = true;
} }
} }
} }
@ -2237,7 +2246,7 @@ bool GCodeProcessor::get_last_z_from_gcode(const std::string& gcode_str, double&
start_index = end_index + 1; start_index = end_index + 1;
end_index = start_index; end_index = start_index;
} }
return is_z_changed; return is_axis_changed;
} }
void GCodeProcessor::process_tags(const std::string_view comment, bool producers_enabled) void GCodeProcessor::process_tags(const std::string_view comment, bool producers_enabled)
@ -5401,4 +5410,4 @@ void GCodeProcessor::update_slice_warnings()
m_result.warnings.shrink_to_fit(); m_result.warnings.shrink_to_fit();
} }
} /* namespace Slic3r */ } /* slic3r_GCodeProcessor_cpp_ */

View file

@ -303,7 +303,7 @@ class Print;
static bool contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector<std::string>& found_tag); static bool contains_reserved_tags(const std::string& gcode, unsigned int max_count, std::vector<std::string>& found_tag);
static int get_gcode_last_filament(const std::string &gcode_str); static int get_gcode_last_filament(const std::string &gcode_str);
static bool get_last_z_from_gcode(const std::string& gcode_str, double& z); static bool get_last_pos_from_gcode(const std::string& gcode_str, int axis, double& pos);
static const float Wipe_Width; static const float Wipe_Width;
static const float Wipe_Height; static const float Wipe_Height;
@ -984,5 +984,3 @@ class Print;
} /* namespace Slic3r */ } /* namespace Slic3r */
#endif /* slic3r_GCodeProcessor_hpp_ */ #endif /* slic3r_GCodeProcessor_hpp_ */