From 19dae83e40145ae94174c870ee02a85fcb9576db Mon Sep 17 00:00:00 2001 From: Ian Bassi Date: Thu, 20 Mar 2025 10:17:20 -0300 Subject: [PATCH] Input Shaping Frequency Input Shaping calibration based in https://marlinfw.org/docs/gcode/M593.html --- .../calib/input_shaping/ringing_tower.stl | Bin 0 -> 175284 bytes src/libslic3r/GCode.cpp | 6 +- src/libslic3r/GCodeWriter.cpp | 19 +++ src/libslic3r/GCodeWriter.hpp | 1 + src/libslic3r/calib.cpp | 2 + src/libslic3r/calib.hpp | 10 +- src/slic3r/GUI/CalibrationWizardSavePage.cpp | 2 + src/slic3r/GUI/MainFrame.cpp | 11 ++ src/slic3r/GUI/MainFrame.hpp | 1 + src/slic3r/GUI/Plater.cpp | 34 ++++++ src/slic3r/GUI/Plater.hpp | 1 + src/slic3r/GUI/calib_dlg.cpp | 114 +++++++++++++++++- src/slic3r/GUI/calib_dlg.hpp | 20 ++- src/slic3r/Utils/CalibUtils.cpp | 4 + 14 files changed, 217 insertions(+), 8 deletions(-) create mode 100644 resources/calib/input_shaping/ringing_tower.stl diff --git a/resources/calib/input_shaping/ringing_tower.stl b/resources/calib/input_shaping/ringing_tower.stl new file mode 100644 index 0000000000000000000000000000000000000000..70cae09ea63db2411493f22ab8c4677f64f7467f GIT binary patch literal 175284 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 literal 0 HcmV?d00001 diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index ce3da04890..be180e3cb5 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3749,6 +3749,7 @@ LayerResult GCode::process_layer( //BBS: set layer time fan speed after layer change gcode gcode += ";_SET_FAN_SPEED_CHANGING_LAYER\n"; + //TODO: Why this is not a Switch-case? if (print.calib_mode() == CalibMode::Calib_PA_Tower) { gcode += writer().set_pressure_advance(print.calib_params().start + static_cast(print_z) * print.calib_params().step); } else if (print.calib_mode() == CalibMode::Calib_Temp_Tower) { @@ -3760,14 +3761,15 @@ LayerResult GCode::process_layer( } else if (print.calib_mode() == CalibMode::Calib_Vol_speed_Tower) { auto _speed = print.calib_params().start + print_z * print.calib_params().step; m_calib_config.set_key_value("outer_wall_speed", new ConfigOptionFloat(std::round(_speed))); - } - else if (print.calib_mode() == CalibMode::Calib_Retraction_tower) { + } else if (print.calib_mode() == CalibMode::Calib_Retraction_tower) { auto _length = print.calib_params().start + std::floor(std::max(0.0,print_z-0.4)) * print.calib_params().step; DynamicConfig _cfg; _cfg.set_key_value("retraction_length", new ConfigOptionFloats{_length}); writer().config.apply(_cfg); sprintf(buf, "; Calib_Retraction_tower: Z_HEIGHT: %g, length:%g\n", print_z, _length); gcode += buf; + } else if (print.calib_mode() == CalibMode::Calib_Input_shaping) { + gcode += writer().set_input_shaping(m_layer_index < 2 ? 0.f : (print.calib_params().start) + ((print.calib_params().end)-(print.calib_params().start)) * (m_layer_index - 2) / (m_layer_count - 3), (print.calib_params().step)); } //BBS diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index e72bbb6685..acbff7a667 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -333,6 +333,25 @@ std::string GCodeWriter::set_pressure_advance(double pa) const return gcode.str(); } +std::string GCodeWriter::set_input_shaping(float freq, float damp) const +{ + std::ostringstream gcode; + if (FLAVOR_IS(gcfKlipper)) + { + throw std::runtime_error("M593 - ZV Input Shaping is NOT supported by Klipper"); + } + if (freq < 0.0f || damp < 0.f || damp > 1.0f) + { + throw std::runtime_error("Invalid input shaping parameters: freq=" + std::to_string(freq) + ", damp=" + std::to_string(damp)); + } + gcode << "M593 F" << freq; + if (damp != 0.0f) + { + gcode << " D" << damp; + } + gcode << "; Override input shaping value\n"; + return gcode.str(); +} std::string GCodeWriter::reset_e(bool force) diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 038325b446..69e20515a4 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -54,6 +54,7 @@ public: // Orca: set acceleration and jerk in one command for Klipper std::string set_accel_and_jerk(unsigned int acceleration, double jerk); std::string set_pressure_advance(double pa) const; + std::string set_input_shaping(float freq, float damp) const; std::string reset_e(bool force = false); std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const; // return false if this extruder was already selected diff --git a/src/libslic3r/calib.cpp b/src/libslic3r/calib.cpp index efec782e7f..81d5d507f2 100644 --- a/src/libslic3r/calib.cpp +++ b/src/libslic3r/calib.cpp @@ -879,4 +879,6 @@ double CalibPressureAdvancePattern::pattern_shift() const { return (wall_count() - 1) * line_spacing_first_layer() + line_width_first_layer() + m_glyph_padding_horizontal; } + + } // namespace Slic3r diff --git a/src/libslic3r/calib.hpp b/src/libslic3r/calib.hpp index 2a02be5e62..b8c81db86c 100644 --- a/src/libslic3r/calib.hpp +++ b/src/libslic3r/calib.hpp @@ -21,7 +21,8 @@ enum class CalibMode : int { Calib_Temp_Tower, Calib_Vol_speed_Tower, Calib_VFA_Tower, - Calib_Retraction_tower + Calib_Retraction_tower, + Calib_Input_shaping }; enum class CalibState { Start = 0, Preset, Calibration, CoarseSave, FineCalibration, Save, Finish }; @@ -30,13 +31,13 @@ struct Calib_Params { Calib_Params() : mode(CalibMode::Calib_None){}; double start, end, step; - bool print_numbers; + bool print_numbers; std::vector accelerations; std::vector speeds; CalibMode mode; -}; + }; enum FlowRatioCalibrationType { COMPLETE_CALIBRATION = 0, @@ -335,4 +336,5 @@ private: const double m_glyph_padding_horizontal{1}; const double m_glyph_padding_vertical{1}; }; -} // namespace Slic3r + +} // namespace Slic3 \ No newline at end of file diff --git a/src/slic3r/GUI/CalibrationWizardSavePage.cpp b/src/slic3r/GUI/CalibrationWizardSavePage.cpp index 246623fffe..7131e0a391 100644 --- a/src/slic3r/GUI/CalibrationWizardSavePage.cpp +++ b/src/slic3r/GUI/CalibrationWizardSavePage.cpp @@ -44,6 +44,8 @@ static wxString get_default_name(wxString filament_name, CalibMode mode){ break; case Slic3r::CalibMode::Calib_Retraction_tower: break; + case Slic3r::CalibMode::Calib_Input_shaping: + break; default: break; } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 3b81a41bd4..2767a2a576 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -2974,6 +2974,17 @@ void MainFrame::init_menubar_as_editor() }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); + + append_menu_item( + advance_menu, wxID_ANY, _L("Input Shaping"), _L("Input Shaping"), + [this](wxCommandEvent&) { + std::string url = "https://marlinfw.org/docs/gcode/M593.html";//TODO: Make OrcaSlicer wiki page + if (!m_IS_calib_dlg) + m_IS_calib_dlg = new Input_Shaping_Test_Dlg((wxWindow*)this, wxID_ANY, m_plater); + m_IS_calib_dlg->ShowModal(); + }, + "", nullptr, + [this]() {return m_plater->is_view3D_shown();; }, this); m_topbar->GetCalibMenu()->AppendSubMenu(advance_menu, _L("More...")); // help diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 18682a2071..311a12c855 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -354,6 +354,7 @@ public: MaxVolumetricSpeed_Test_Dlg* m_vol_test_dlg { nullptr }; VFA_Test_Dlg* m_vfa_test_dlg { nullptr }; Retraction_Test_Dlg* m_retraction_calib_dlg{ nullptr }; + Input_Shaping_Test_Dlg* m_IS_calib_dlg{ nullptr }; // BBS. Replace title bar and menu bar with top bar. BBLTopbar* m_topbar{ nullptr }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index fa02512197..a259a3a6ca 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -10149,6 +10149,40 @@ void Plater::calib_VFA(const Calib_Params& params) p->background_process.fff_print()->set_calib_params(params); } + +void Plater::calib_input_shaping(const Calib_Params& params) +{ + const auto calib_input_shaping_name = wxString::Format(L"Input shaping test"); + new_project(false, false, calib_input_shaping_name); + wxGetApp().mainframe->select_tab(size_t(MainFrame::tp3DEditor)); + if (params.mode != CalibMode::Calib_Input_shaping) + return; + + add_model(false, Slic3r::resources_dir() + "/calib/input_shaping/ringing_tower.stl"); + auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; + auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config; + filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 2.0 }); + filament_config->set_key_value("filament_max_volumetric_speed", new ConfigOptionFloats { 200 }); + print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool { false }); + print_config->set_key_value("timelapse_type", new ConfigOptionEnum(tlTraditional)); + print_config->set_key_value("wall_loops", new ConfigOptionInt(1)); + print_config->set_key_value("top_shell_layers", new ConfigOptionInt(0)); + print_config->set_key_value("bottom_shell_layers", new ConfigOptionInt(1)); + print_config->set_key_value("sparse_infill_density", new ConfigOptionPercent(0)); + print_config->set_key_value("spiral_mode", new ConfigOptionBool(true)); + model().objects[0]->config.set_key_value("brim_type", new ConfigOptionEnum(btOuterOnly)); + model().objects[0]->config.set_key_value("brim_width", new ConfigOptionFloat(3.0)); + model().objects[0]->config.set_key_value("brim_object_gap", new ConfigOptionFloat(0.0)); + + changed_objects({ 0 }); + wxGetApp().get_tab(Preset::TYPE_PRINT)->update_dirty(); + wxGetApp().get_tab(Preset::TYPE_FILAMENT)->update_dirty(); + wxGetApp().get_tab(Preset::TYPE_PRINT)->update_ui_from_settings(); + wxGetApp().get_tab(Preset::TYPE_FILAMENT)->update_ui_from_settings(); + + p->background_process.fff_print()->set_calib_params(params); +} + BuildVolume_Type Plater::get_build_volume_type() const { return p->bed.get_build_volume_type(); } void Plater::import_zip_archive() diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 34f276132e..b8f6e93333 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -273,6 +273,7 @@ public: void calib_max_vol_speed(const Calib_Params& params); void calib_retraction(const Calib_Params& params); void calib_VFA(const Calib_Params& params); + void calib_input_shaping(const Calib_Params& params); BuildVolume_Type get_build_volume_type() const; diff --git a/src/slic3r/GUI/calib_dlg.cpp b/src/slic3r/GUI/calib_dlg.cpp index 615114b413..f4d282ed03 100644 --- a/src/slic3r/GUI/calib_dlg.cpp +++ b/src/slic3r/GUI/calib_dlg.cpp @@ -722,7 +722,7 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater auto end_length_sizer = new wxBoxSizer(wxHORIZONTAL); auto end_length_text = new wxStaticText(this, wxID_ANY, end_length_str, wxDefaultPosition, st_size, wxALIGN_LEFT); m_tiEnd = new TextInput(this, std::to_string(2), _L("mm"), "", wxDefaultPosition, ti_size, wxTE_CENTRE); - m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + m_tiEnd->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));//m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));//TODO: IANALEXIS CHECK end_length_sizer->Add(end_length_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); end_length_sizer->Add(m_tiEnd, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); settings_sizer->Add(end_length_sizer); @@ -789,5 +789,117 @@ void Retraction_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) { } +// Input_Shaping_Test_Dlg +// + +Input_Shaping_Test_Dlg::Input_Shaping_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater) + : DPIDialog(parent, id, _L("Input shaping test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), m_plater(plater) +{ + wxBoxSizer* v_sizer = new wxBoxSizer(wxVERTICAL); + SetSizer(v_sizer); + + // Settings + // + wxString start_length_str = _L("Start: "); + wxString end_length_str = _L("End: "); + auto text_size = wxWindow::GetTextExtent(start_length_str); + text_size.IncTo(wxWindow::GetTextExtent(end_length_str)); + text_size.x = text_size.x * 1.5; + wxStaticBoxSizer* settings_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _L("Frequency settings")); + + auto st_size = FromDIP(wxSize(text_size.x, -1)); + auto ti_size = FromDIP(wxSize(90, -1)); + + auto start_length_sizer = new wxBoxSizer(wxHORIZONTAL); + auto start_length_text = new wxStaticText(this, wxID_ANY, start_length_str, wxDefaultPosition, st_size, wxALIGN_LEFT); + m_tiStart = new TextInput(this, std::to_string(15), _L("HZ"), "", wxDefaultPosition, ti_size, wxTE_CENTRE); + m_tiStart->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + auto end_length_text = new wxStaticText(this, wxID_ANY, end_length_str, wxDefaultPosition, st_size, wxALIGN_LEFT); + m_tiEnd = new TextInput(this, std::to_string(45), _L("HZ"), "", wxDefaultPosition, ti_size, wxTE_CENTRE); + m_tiEnd->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + + start_length_sizer->Add(start_length_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); + start_length_sizer->Add(m_tiStart, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); + start_length_sizer->Add(end_length_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); + start_length_sizer->Add(m_tiEnd, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); + settings_sizer->Add(start_length_sizer); + + // Damping Factor + wxString damping_factor_str = _L("Damp: "); + auto damping_factor_sizer = new wxBoxSizer(wxHORIZONTAL); + auto damping_factor_text = new wxStaticText(this, wxID_ANY, damping_factor_str, wxDefaultPosition, st_size, wxALIGN_LEFT); + m_tiDampingFactor = new TextInput(this, wxString::Format("%.2f", 0.15), "", "", wxDefaultPosition, ti_size, wxTE_CENTRE); + m_tiDampingFactor->GetTextCtrl()->SetValidator(wxTextValidator(wxFILTER_NUMERIC)); + + damping_factor_sizer->Add(damping_factor_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); + damping_factor_sizer->Add(m_tiDampingFactor, 0, wxALL | wxALIGN_CENTER_VERTICAL, 2); + settings_sizer->Add(damping_factor_sizer); + + // Add a note explaining that 0 means use default value + auto note_text = new wxStaticText(this, wxID_ANY, _L("Note: 0 Damp = Printer default"), + wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + note_text->SetForegroundColour(wxColour(128, 128, 128)); + settings_sizer->Add(note_text, 0, wxALL, 5); + + v_sizer->Add(settings_sizer); + v_sizer->Add(0, FromDIP(10), 0, wxEXPAND, 5); + m_btnStart = new Button(this, _L("OK")); + StateColor btn_bg_green(std::pair(wxColour(0, 137, 123), StateColor::Pressed), + std::pair(wxColour(38, 166, 154), StateColor::Hovered), + std::pair(wxColour(0, 150, 136), StateColor::Normal)); + + m_btnStart->SetBackgroundColor(btn_bg_green); + m_btnStart->SetBorderColor(wxColour(0, 150, 136)); + m_btnStart->SetTextColor(wxColour("#FFFFFE")); + m_btnStart->SetSize(wxSize(FromDIP(48), FromDIP(24))); + m_btnStart->SetMinSize(wxSize(FromDIP(48), FromDIP(24))); + m_btnStart->SetCornerRadius(FromDIP(3)); + m_btnStart->Bind(wxEVT_BUTTON, &Input_Shaping_Test_Dlg::on_start, this); + v_sizer->Add(m_btnStart, 0, wxALL | wxALIGN_RIGHT, FromDIP(5)); + + m_btnStart->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(Input_Shaping_Test_Dlg::on_start), NULL, this); + + //wxGetApp().UpdateDlgDarkUI(this);//FIXME: dark mode background color + + Layout(); + Fit(); +} + +Input_Shaping_Test_Dlg::~Input_Shaping_Test_Dlg() { + // Disconnect Events + m_btnStart->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(Input_Shaping_Test_Dlg::on_start), NULL, this); +} + +void Input_Shaping_Test_Dlg::on_start(wxCommandEvent& event) { + bool read_double = false; + read_double = m_tiStart->GetTextCtrl()->GetValue().ToDouble(&m_params.start); + read_double = read_double && m_tiEnd->GetTextCtrl()->GetValue().ToDouble(&m_params.end); + + double dampingFactor = 0.0; + bool read_damping = m_tiDampingFactor->GetTextCtrl()->GetValue().ToDouble(&dampingFactor); + + if (!read_double || m_params.start < 0 || m_params.end > 500|| m_params.end < m_params.start) { + MessageDialog msg_dlg(nullptr, _L("Please input valid values:\nStart >= 0\nEnd <= 500\nStart < End"), wxEmptyString, wxICON_WARNING | wxOK); + msg_dlg.ShowModal(); + return; + } + + if (!read_damping || dampingFactor < 0 || dampingFactor >= 1) { + MessageDialog msg_dlg(nullptr, _L("Please input a valid damping factor (0 < Damping/zeta factor <= 1)"), wxEmptyString, wxICON_WARNING | wxOK); + msg_dlg.ShowModal(); + return; + } + + m_params.step = dampingFactor; + m_params.mode = CalibMode::Calib_Input_shaping; + m_plater->calib_input_shaping(m_params); + EndModal(wxID_OK); +} + +void Input_Shaping_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) { + this->Refresh(); + Fit(); + +} }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/calib_dlg.hpp b/src/slic3r/GUI/calib_dlg.hpp index bbd0903586..71720facc2 100644 --- a/src/slic3r/GUI/calib_dlg.hpp +++ b/src/slic3r/GUI/calib_dlg.hpp @@ -125,6 +125,24 @@ protected: Plater* m_plater; }; -}} // namespace Slic3r::GUI +class Input_Shaping_Test_Dlg : public DPIDialog +{ +public: + Input_Shaping_Test_Dlg (wxWindow* parent, wxWindowID id, Plater* plater); + ~Input_Shaping_Test_Dlg (); + void on_dpi_changed(const wxRect& suggested_rect) override; + +protected: + virtual void on_start(wxCommandEvent& event); + Calib_Params m_params; + + TextInput* m_tiStart; + TextInput* m_tiEnd; + TextInput* m_tiDampingFactor; + Button* m_btnStart; + Plater* m_plater; +}; + +}} // namespace Slic3r::GUI #endif diff --git a/src/slic3r/Utils/CalibUtils.cpp b/src/slic3r/Utils/CalibUtils.cpp index 0732b99370..af55d71dd6 100644 --- a/src/slic3r/Utils/CalibUtils.cpp +++ b/src/slic3r/Utils/CalibUtils.cpp @@ -57,6 +57,8 @@ std::string get_calib_mode_name(CalibMode cali_mode, int stage) return "vfa_tower_calib_mode"; case CalibMode::Calib_Retraction_tower: return "retration_tower_calib_mode"; + case CalibMode::Calib_Input_shaping: + return "input_shaping_calib_mode"; default: assert(false); return ""; @@ -196,6 +198,8 @@ CalibMode CalibUtils::get_calib_mode_by_name(const std::string name, int& cali_s return CalibMode::Calib_VFA_Tower; else if (name == "retration_tower_calib_mode") return CalibMode::Calib_Retraction_tower; + else if (name == "input_shaping_calib_mode") + return CalibMode::Calib_Input_shaping; return CalibMode::Calib_None; }