Input Shaping Frequency

Input Shaping calibration based in https://marlinfw.org/docs/gcode/M593.html
This commit is contained in:
Ian Bassi 2025-03-20 10:17:20 -03:00
parent bf9cce4800
commit 19dae83e40
14 changed files with 217 additions and 8 deletions

Binary file not shown.

View file

@ -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<int>(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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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 };
@ -36,7 +37,7 @@ struct Calib_Params
std::vector<double> 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

View file

@ -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;
}

View file

@ -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

View file

@ -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 };

View file

@ -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<TimelapseType>(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<BrimType>(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()

View file

@ -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;

View file

@ -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, int>(wxColour(0, 137, 123), StateColor::Pressed),
std::pair<wxColour, int>(wxColour(38, 166, 154), StateColor::Hovered),
std::pair<wxColour, int>(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

View file

@ -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

View file

@ -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;
}