ENH: support traditional timelapse for i3 structure

Jira: 3935
Change-Id: I38a270f7d9060ea1b271c69fd0d427205817e705
(cherry picked from commit 3f50b94adef5e48b169ad72e777135389d0e4ebf)
This commit is contained in:
zhimin.zeng 2023-08-29 09:04:13 +08:00 committed by Lane.Wei
parent dcf3e736fe
commit 433a48cd00
11 changed files with 174 additions and 5 deletions

View file

@ -289,6 +289,7 @@ static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type";
static constexpr const char* OUTSIDE_ATTR = "outside";
static constexpr const char* SUPPORT_USED_ATTR = "support_used";
static constexpr const char* LABEL_OBJECT_ENABLED_ATTR = "label_object_enabled";
static constexpr const char* TIMELAPSE_TYPE_ATTR = "timelapse_type";
static constexpr const char* SKIPPED_ATTR = "skipped";
static constexpr const char* OBJECT_TYPE = "object";
@ -5255,7 +5256,7 @@ void PlateData::parse_filament_info(GCodeProcessorResult *result)
bool _add_project_embedded_presets_to_archive(mz_zip_archive& archive, Model& model, std::vector<Preset*> project_presets);
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, const ObjectToObjectDataMap &objects_data, int export_plate_idx = -1, bool save_gcode = true, bool use_loaded_id = false);
bool _add_cut_information_file_to_archive(mz_zip_archive &archive, Model &model);
bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config);
bool _add_slice_info_config_file_to_archive(mz_zip_archive &archive, const Model &model, PlateDataPtrs &plate_data_list, const ObjectToObjectDataMap &objects_data, const DynamicPrintConfig& config);
bool _add_gcode_file_to_archive(mz_zip_archive& archive, const Model& model, PlateDataPtrs& plate_data_list, Export3mfProgressFn proFn = nullptr);
bool _add_custom_gcode_per_print_z_file_to_archive(mz_zip_archive& archive, Model& model, const DynamicPrintConfig* config);
bool _add_auxiliary_dir_to_archive(mz_zip_archive &archive, const std::string &aux_dir, PackingTemporaryData &data);

View file

@ -736,6 +736,33 @@ static std::vector<Vec2d> get_path_of_change_filament(const Print& print)
return gcode;
}
bool WipeTowerIntegration::is_empty_wipe_tower_gcode(GCode &gcodegen, int extruder_id, bool finish_layer)
{
assert(m_layer_idx >= 0);
if (m_layer_idx >= (int) m_tool_changes.size())
return true;
bool ignore_sparse = false;
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
}
if (m_enable_timelapse_print && m_is_first_print) {
return false;
}
if (gcodegen.writer().need_toolchange(extruder_id) || finish_layer) {
if (!(size_t(m_tool_change_idx) < m_tool_changes[m_layer_idx].size()))
throw Slic3r::RuntimeError("Wipe tower generation failed, possibly due to empty first layer.");
if (!ignore_sparse) {
return false;
}
}
return true;
}
// Print is finished. Now it remains to unload the filament safely with ramming over the wipe tower.
std::string WipeTowerIntegration::finalize(GCode& gcodegen)
{
@ -1011,6 +1038,7 @@ namespace DoExport {
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Machine end G-code")), config.machine_end_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Before layer change G-code")), config.before_layer_change_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Layer change G-code")), config.layer_change_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Time lapse G-code")), config.time_lapse_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change filament G-code")), config.change_filament_gcode.value);
//BBS
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Printing by object G-code")), config.printing_by_object_gcode.value);
@ -1132,6 +1160,8 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
// Post-process the G-code to update time stamps.
m_processor.result().timelapse_warning_code = m_timelapse_warning_code;
m_processor.finalize(true);
// DoExport::update_print_estimated_times_stats(m_processor, print->m_print_statistics);
DoExport::update_print_estimated_stats(m_processor, m_writer.extruders(), print->m_print_statistics);
@ -2827,10 +2857,35 @@ GCode::LayerResult GCode::process_layer(
+ "\n";
}
PrinterStructure printer_structure = m_config.printer_structure.value;
bool need_insert_timelapse_gcode_for_traditional = false;
if (printer_structure == PrinterStructure::psI3 && (!m_wipe_tower || !m_wipe_tower->enable_timelapse_print())) {
need_insert_timelapse_gcode_for_traditional = true;
}
bool has_insert_timelapse_gcode = false;
bool has_wipe_tower = (layer_tools.has_wipe_tower && m_wipe_tower);
auto insert_timelapse_gcode = [this, print_z, &print]() -> std::string {
std::string gcode_res;
if (!print.config().time_lapse_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
config.set_key_value("layer_z", new ConfigOptionFloat(print_z));
gcode_res = this->placeholder_parser_process("timelapse_gcode", print.config().time_lapse_gcode.value, m_writer.extruder()->id(), &config) + "\n";
config.set_key_value("max_layer_z", new ConfigOptionFloat(m_max_layer_z));
}
return gcode_res;
};
// BBS: don't use lazy_raise when enable spiral vase
gcode += this->change_layer(print_z); // this will increase m_layer_index
m_layer = &layer;
m_object_layer_over_raft = false;
if (printer_structure == PrinterStructure::psI3 && !need_insert_timelapse_gcode_for_traditional) {
gcode += insert_timelapse_gcode();
//todo: get the last position of timelapse_gcode, and set into m_writer. Then delete the m_writer.set_current_position_clear(false)
m_writer.set_current_position_clear(false);
}
if (! print.config().layer_change_gcode.value.empty()) {
DynamicConfig config;
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index));
@ -3137,9 +3192,21 @@ GCode::LayerResult GCode::process_layer(
// Extrude the skirt, brim, support, perimeters, infill ordered by the extruders.
for (unsigned int extruder_id : layer_tools.extruders)
{
gcode += (layer_tools.has_wipe_tower && m_wipe_tower) ?
m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back()) :
this->set_extruder(extruder_id, print_z);
if (has_wipe_tower) {
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) {
gcode += this->retract(false, false, LiftType::NormalLift);
m_writer.add_object_change_labels(gcode);
gcode += insert_timelapse_gcode();
//todo: get the last position of timelapse_gcode, and set into m_writer. Then delete the m_writer.set_current_position_clear(false)
m_writer.set_current_position_clear(false);
has_insert_timelapse_gcode = true;
}
gcode += m_wipe_tower->tool_change(*this, extruder_id, extruder_id == layer_tools.extruders.back());
}
} else {
gcode += this->set_extruder(extruder_id, print_z);
}
// let analyzer tag generator aware of a role type change
if (layer_tools.has_wipe_tower && m_wipe_tower)
@ -3234,12 +3301,15 @@ GCode::LayerResult GCode::process_layer(
m_object_layer_over_raft = object_layer_over_raft;
if (m_config.reduce_crossing_wall)
m_avoid_crossing_perimeters.init_layer(*m_layer);
std::string temp_start_str;
if (m_enable_label_object) {
std::string start_str = std::string("; start printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n";
if (print.is_BBL_Printer()) {
start_str += ("M624 " + _encode_label_ids_to_base64({ instance_to_print.label_object_id }));
start_str += "\n";
}
temp_start_str = start_str;
m_writer.set_object_start_str(start_str);
}
//Orca's implementation for skipping object, for klipper firmware printer only
@ -3325,13 +3395,58 @@ GCode::LayerResult GCode::process_layer(
//FIXME the following code prints regions in the order they are defined, the path is not optimized in any way.
bool is_infill_first = print.config().wall_infill_order == WallInfillOrder::InfillInnerOuter ||
print.config().wall_infill_order == WallInfillOrder::InfillOuterInner;
auto has_infill = [](const std::vector<ObjectByExtruder::Island::Region> &by_region) {
for (auto region : by_region) {
if (!region.infills.empty())
return true;
}
return false;
};
//BBS: for first layer, we always print wall firstly to get better bed adhesive force
//This behaviour is same with cura
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)) {
gcode += this->retract(false, false, LiftType::NormalLift);
if (!temp_start_str.empty() && m_writer.empty_object_start_str()) {
std::string end_str = std::string("; stop printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n";
if (print.is_BBL_Printer())
end_str += "M625\n";
gcode += end_str;
}
gcode += insert_timelapse_gcode();
//todo: get the last position of timelapse_gcode, and set into m_writer. Then delete the m_writer.set_current_position_clear(false)
m_writer.set_current_position_clear(false);
if (!temp_start_str.empty() && m_writer.empty_object_start_str())
gcode += temp_start_str;
temp_start_str.clear();
has_insert_timelapse_gcode = true;
}
gcode += this->extrude_infill(print, by_region_specific, false);
gcode += this->extrude_perimeters(print, by_region_specific);
} else {
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);
if (!temp_start_str.empty() && m_writer.empty_object_start_str()) {
std::string end_str = std::string("; stop printing object, unique label id: ") + std::to_string(instance_to_print.label_object_id) + "\n";
if (print.is_BBL_Printer())
end_str += "M625\n";
gcode += end_str;
}
gcode += insert_timelapse_gcode();
//todo: get the last position of timelapse_gcode, and set into m_writer. Then delete the m_writer.set_current_position_clear(false)
m_writer.set_current_position_clear(false);
if (!temp_start_str.empty() && m_writer.empty_object_start_str())
gcode += temp_start_str;
temp_start_str.clear();
has_insert_timelapse_gcode = true;
}
gcode += this->extrude_infill(print,by_region_specific, false);
}
// ironing
@ -3387,6 +3502,16 @@ GCode::LayerResult GCode::process_layer(
BOOST_LOG_TRIVIAL(trace) << "Exported layer " << layer.id() << " print_z " << print_z <<
log_memory_info();
if (!has_wipe_tower && need_insert_timelapse_gcode_for_traditional && !has_insert_timelapse_gcode) {
if (m_timelapse_warning_code == 0)
m_timelapse_warning_code = 1;
gcode += this->retract(false, false, LiftType::NormalLift);
m_writer.add_object_change_labels(gcode);
gcode += insert_timelapse_gcode();
//todo: get the last position of timelapse_gcode, and set into m_writer. Then delete the m_writer.set_current_position_clear(false)
m_writer.set_current_position_clear(false);
}
result.gcode = std::move(gcode);
result.cooling_buffer_flush = object_layer || raft_layer || last_layer;
return result;

View file

@ -91,6 +91,7 @@ public:
std::string prime(GCode &gcodegen);
void next_layer() { ++ m_layer_idx; m_tool_change_idx = 0; }
std::string tool_change(GCode &gcodegen, int extruder_id, bool finish_layer);
bool is_empty_wipe_tower_gcode(GCode &gcodegen, int extruder_id, bool finish_layer);
std::string finalize(GCode &gcodegen);
std::vector<float> used_filament_length() const;
@ -490,6 +491,8 @@ private:
std::vector<size_t> m_label_objects_ids;
std::string _encode_label_ids_to_base64(std::vector<size_t> ids);
int m_timelapse_warning_code = 0;
bool m_silent_time_estimator_enabled;
// Processor

View file

@ -788,6 +788,7 @@ void GCodeProcessorResult::reset() {
toolpath_outside = false;
//BBS: add label_object_enabled
label_object_enabled = false;
timelapse_warning_code = 0;
printable_height = 0.0f;
settings_ids.reset();
extruders_count = 0;
@ -815,6 +816,7 @@ void GCodeProcessorResult::reset() {
toolpath_outside = false;
//BBS: add label_object_enabled
label_object_enabled = false;
timelapse_warning_code = 0;
printable_height = 0.0f;
settings_ids.reset();
extruders_count = 0;
@ -4320,6 +4322,15 @@ void GCodeProcessor::update_slice_warnings()
m_result.warnings.push_back(warning);
}
// bbs:HRC checker
warning.params.clear();
warning.level = 1;
if (m_result.timelapse_warning_code != 0) {
warning.msg = NOT_SUPPORT_TRADITIONAL_TIMELAPSE;
warning.error_code = "1000C003";
m_result.warnings.push_back(warning);
}
m_result.warnings.shrink_to_fit();
}

View file

@ -20,6 +20,7 @@ namespace Slic3r {
// slice warnings enum strings
#define NOZZLE_HRC_CHECKER "the_actual_nozzle_hrc_smaller_than_the_required_nozzle_hrc"
#define BED_TEMP_TOO_HIGH_THAN_FILAMENT "bed_temperature_too_high_than_filament"
#define NOT_SUPPORT_TRADITIONAL_TIMELAPSE "not_support_traditional_timelapse"
enum class EMoveType : unsigned char
{
@ -179,6 +180,7 @@ namespace Slic3r {
bool toolpath_outside;
//BBS: add object_label_enabled
bool label_object_enabled;
int timelapse_warning_code {0};
float printable_height;
SettingsIds settings_ids;
size_t extruders_count;
@ -211,6 +213,7 @@ namespace Slic3r {
bed_exclude_area = other.bed_exclude_area;
toolpath_outside = other.toolpath_outside;
label_object_enabled = other.label_object_enabled;
timelapse_warning_code = other.timelapse_warning_code;
printable_height = other.printable_height;
settings_ids = other.settings_ids;
extruders_count = other.extruders_count;
@ -709,6 +712,7 @@ namespace Slic3r {
void reset();
const GCodeProcessorResult& get_result() const { return m_result; }
GCodeProcessorResult& result() { return m_result; }
GCodeProcessorResult&& extract_result() { return std::move(m_result); }
// Load a G-code into a stand-alone G-code viewer.

View file

@ -846,7 +846,7 @@ static std::vector<std::string> s_Preset_machine_limits_options {
static std::vector<std::string> s_Preset_printer_options {
"printer_technology",
"printable_area", "bed_exclude_area","bed_custom_texture", "bed_custom_model", "gcode_flavor",
"single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "change_filament_gcode",
"single_extruder_multi_material", "machine_start_gcode", "machine_end_gcode", "before_layer_change_gcode", "layer_change_gcode", "time_lapse_gcode", "change_filament_gcode",
"printer_model", "printer_variant", "printable_height", "extruder_clearance_radius", "extruder_clearance_max_radius","extruder_clearance_height_to_lid", "extruder_clearance_height_to_rod",
"default_print_profile", "inherits",
"silent_mode",

View file

@ -117,6 +117,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n
"textured_plate_temp_initial_layer",
"gcode_add_line_number",
"layer_change_gcode",
"time_lapse_gcode",
"fan_min_speed",
"fan_max_speed",
"printable_height",

View file

@ -2011,6 +2011,14 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("time_lapse_gcode",coString);
def->label = L("Time lapse G-code");
def->multiline = true;
def->full_width = true;
def->height =5;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("silent_mode", coBool);
def->label = L("Supports silent mode");
def->tooltip = L("Whether the machine supports silent mode in which machine use lower acceleration to print");

View file

@ -857,6 +857,7 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, bbl_bed_temperature_gcode))
((ConfigOptionEnum<GCodeFlavor>, gcode_flavor))
((ConfigOptionString, layer_change_gcode))
((ConfigOptionString, time_lapse_gcode))
//#ifdef HAS_PRESSURE_EQUALIZER
// ((ConfigOptionFloat, max_volumetric_extrusion_rate_slope_positive))
// ((ConfigOptionFloat, max_volumetric_extrusion_rate_slope_negative))

View file

@ -2839,6 +2839,8 @@ wxString Plater::get_slice_warning_string(GCodeProcessorResult::SliceWarning& wa
return _L("The bed temperature exceeds filament's vitrification temperature. Please open the front door of printer before printing to avoid nozzle clog.");
} else if (warning.msg == NOZZLE_HRC_CHECKER) {
return _L("The nozzle hardness required by the filament is higher than the default nozzle hardness of the printer. Please replace the hardened nozzle or filament, otherwise, the nozzle will be attrited or damaged.");
} else if (warning.msg == NOT_SUPPORT_TRADITIONAL_TIMELAPSE) {
return _L("Enable traditional timelapse will cause artifacts on this model.");
} else {
return wxString(warning.msg);
}

View file

@ -3155,6 +3155,16 @@ void TabPrinter::build_fff()
option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Time lapse G-code"), L"param_gcode", 0);
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup, opt_key, value);
};
option = optgroup->get_option("time_lapse_gcode");
option.opt.full_width = true;
option.opt.is_code = true;
option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Change filament G-code"), L"param_gcode", 0);
optgroup->m_on_change = [this, optgroup](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup, opt_key, value);
@ -3680,6 +3690,9 @@ void TabPrinter::toggle_options()
toggle_option(el, !is_BBL_printer);
}
if (m_active_page->title() == "Machine gcode") {
toggle_line("time_lapse_gcode", m_preset_bundle->printers.get_edited_preset().config.opt_enum<PrinterStructure>("printer_structure") == PrinterStructure::psI3);
}
wxString extruder_number;
long val = 1;
if ( m_active_page->title().IsSameAs("Extruder") ||