Machine Input Shaping (#11202)
* Base IS Machine * Toggle line * Rebase * Intento 1 * Wiki IS * Flavorized * Tooltips * Calibration using the same list * max * Reorder JD validation * Refactor set input shaping * Calibrations IS * Default values * Axis * Orca comments * Rename input_shaping_enable to input_shaping_emit Refactor all references of the input shaping configuration option from 'input_shaping_enable' to 'input_shaping_emit' across the codebase. This improves clarity by better reflecting the option's purpose of controlling whether input shaping commands are emitted in the generated G-code. Restore DONT EMIT FOR KLIPPER * Refactor input shaping option toggling logic Simplifies and consolidates the logic for toggling input shaping related options in TabPrinter::toggle_options(). Uses a loop to handle enabling/disabling lines based on GCode flavor compatibility, and refines the conditions for toggling individual options. * Improve input shaping option toggling logic in TabPrinter * GrayOut Emit to gcode limits for klipper * Typo Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Typo * Skip Y input-shaper when type is Disable If marlin2 and disabled it will be already disabled at X. * IS expert Co-Authored-By: SoftFever <softfeverever@gmail.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
@@ -3925,6 +3925,17 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print)
|
||||
|
||||
// New Marlin uses M205 J[mm] for junction deviation (only apply if it is > 0)
|
||||
file.write_format(writer().set_junction_deviation(config().machine_max_junction_deviation.values.front()).c_str());
|
||||
|
||||
// Orca: Override input shaping values
|
||||
if (print.config().input_shaping_emit.value && flavor != gcfMarlinLegacy) {
|
||||
const bool input_shaping_disable = print.config().input_shaping_type.value == InputShaperType::Disable;
|
||||
file.write_format(writer().set_input_shaping('X', print.config().input_shaping_damp_x.value,
|
||||
print.config().input_shaping_freq_x.value, print.config().opt_serialize("input_shaping_type")).c_str());
|
||||
if (flavor != gcfRepRapFirmware && !input_shaping_disable) {
|
||||
file.write_format(writer().set_input_shaping('Y', print.config().input_shaping_damp_y.value,
|
||||
print.config().input_shaping_freq_y.value, "").c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -350,7 +350,7 @@ std::string GCodeWriter::set_accel_and_jerk(unsigned int acceleration, double je
|
||||
|
||||
std::string GCodeWriter::set_junction_deviation(double junction_deviation){
|
||||
std::ostringstream gcode;
|
||||
if (FLAVOR_IS(gcfMarlinFirmware) && junction_deviation > 0 && m_max_junction_deviation > 0) {
|
||||
if (FLAVOR_IS(gcfMarlinFirmware) && m_max_junction_deviation > 0 && junction_deviation > 0) {
|
||||
// Clamp the junction deviation to the allowed maximum.
|
||||
gcode << "M205 J";
|
||||
if (junction_deviation <= m_max_junction_deviation) {
|
||||
@@ -390,68 +390,88 @@ std::string GCodeWriter::set_pressure_advance(double pa) const
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
// Orca: input shaping support
|
||||
std::string GCodeWriter::set_input_shaping(char axis, float damp, float freq, std::string type) const
|
||||
{
|
||||
if (FLAVOR_IS(gcfMarlinLegacy))
|
||||
throw std::runtime_error("Input shaping is not supported by Marlin < 2.1.2.\nCheck your firmware version and update your G-code flavor to ´Marlin 2´");
|
||||
if (freq < 0.0f || damp < 0.f || damp > 1.0f || (axis != 'X' && axis != 'Y' && axis != 'Z' && axis != 'A'))// A = all axis
|
||||
{
|
||||
throw std::runtime_error("Invalid input shaping parameters: freq=" + std::to_string(freq) + ", damp=" + std::to_string(damp));
|
||||
bool disable = type == "Disable";
|
||||
if (disable){
|
||||
freq = 0.0f;
|
||||
damp = 0.0f;
|
||||
axis = 'A';
|
||||
type = "Default";
|
||||
} else if (freq < 0.0f || damp < 0.f || damp > 1.0f || (axis != 'X' && axis != 'Y' && axis != 'Z' && axis != 'A')) { // A = all axis
|
||||
throw std::runtime_error("Invalid input shaping parameters: axis=" + std::string(1, axis) + ", freq=" + std::to_string(freq) + ", damp=" + std::to_string(damp));
|
||||
}
|
||||
std::ostringstream gcode;
|
||||
if (FLAVOR_IS(gcfKlipper)) {
|
||||
gcode << "SET_INPUT_SHAPER";
|
||||
std::ostringstream params;
|
||||
switch (this->config.gcode_flavor) {
|
||||
case gcfKlipper: {
|
||||
if (!type.empty() && type != "Default") {
|
||||
gcode << " SHAPER_TYPE=" << type;
|
||||
params << " SHAPER_TYPE=" << type;
|
||||
}
|
||||
if (axis != 'A')
|
||||
{
|
||||
if (freq > 0.0f) {
|
||||
gcode << " SHAPER_FREQ_" << axis << "=" << std::fixed << std::setprecision(2) << freq;
|
||||
}
|
||||
if (damp > 0.0f){
|
||||
gcode << " DAMPING_RATIO_" << axis << "=" << std::fixed << std::setprecision(3) << damp;
|
||||
}
|
||||
} else {
|
||||
if (freq > 0.0f) {
|
||||
gcode << " SHAPER_FREQ_X=" << std::fixed << std::setprecision(2) << freq << " SHAPER_FREQ_Y=" << std::fixed << std::setprecision(2) << freq;
|
||||
params << " SHAPER_FREQ_" << axis << "=" << std::fixed << std::setprecision(2) << freq;
|
||||
}
|
||||
if (damp > 0.0f) {
|
||||
gcode << " DAMPING_RATIO_X=" << std::fixed << std::setprecision(3) << damp << " DAMPING_RATIO_Y=" << std::fixed << std::setprecision(3) << damp;
|
||||
params << " DAMPING_RATIO_" << axis << "=" << std::fixed << std::setprecision(3) << damp;
|
||||
}
|
||||
} else {
|
||||
if (freq > 0.0f || disable) {
|
||||
params << " SHAPER_FREQ_X=" << std::fixed << std::setprecision(2) << freq << " SHAPER_FREQ_Y=" << std::fixed << std::setprecision(2) << freq;
|
||||
}
|
||||
if (damp > 0.0f || disable) {
|
||||
params << " DAMPING_RATIO_X=" << std::fixed << std::setprecision(3) << damp << " DAMPING_RATIO_Y=" << std::fixed << std::setprecision(3) << damp;
|
||||
}
|
||||
}
|
||||
} else if (FLAVOR_IS(gcfRepRapFirmware)) {
|
||||
gcode << "M593";
|
||||
if (!params.str().empty()) {
|
||||
gcode << "SET_INPUT_SHAPER" << params.str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gcfRepRapFirmware: {
|
||||
if (!type.empty() && type != "Default" && type != "DAA") {
|
||||
gcode << " P\"" << type << "\"";
|
||||
params << " P\"" << type << "\"";
|
||||
}
|
||||
if (freq > 0.0f) {
|
||||
gcode << " F" << std::fixed << std::setprecision(2) << freq;
|
||||
if (freq > 0.0f || disable) {
|
||||
params << " F" << std::fixed << std::setprecision(2) << freq;
|
||||
}
|
||||
if (damp > 0.0f){
|
||||
gcode << " S" << std::fixed << std::setprecision(3) << damp;
|
||||
if (damp > 0.0f || disable) {
|
||||
params << " S" << std::fixed << std::setprecision(3) << damp;
|
||||
}
|
||||
} else if (FLAVOR_IS(gcfMarlinFirmware)) {
|
||||
gcode << "M593";
|
||||
if (axis != 'A')
|
||||
{
|
||||
gcode << " " << axis;
|
||||
if (!params.str().empty()) {
|
||||
gcode << "M593" << params.str();
|
||||
}
|
||||
if (freq > 0.0f)
|
||||
{
|
||||
gcode << " F" << std::fixed << std::setprecision(2) << freq;
|
||||
break;
|
||||
}
|
||||
case gcfMarlinFirmware: {
|
||||
if (axis != 'A') {
|
||||
params << " " << axis;
|
||||
}
|
||||
if (damp > 0.0f)
|
||||
{
|
||||
gcode << " D" << std::fixed << std::setprecision(3) << damp;
|
||||
if (freq > 0.0f || disable) {
|
||||
params << " F" << std::fixed << std::setprecision(2) << freq;
|
||||
}
|
||||
} else {
|
||||
if (damp > 0.0f || disable) {
|
||||
params << " D" << std::fixed << std::setprecision(3) << damp;
|
||||
}
|
||||
if (!params.str().empty()) {
|
||||
gcode << "M593" << params.str();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case gcfMarlinLegacy: {
|
||||
throw std::runtime_error("Input shaping is not supported by Marlin < 2.1.2.\nCheck your firmware version and update your G-code flavor to ´Marlin 2´");
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Input shaping is only supported by Klipper, RepRapFirmware and Marlin 2");
|
||||
}
|
||||
if (GCodeWriter::full_gcode_comment){
|
||||
gcode << " ; Override input shaping";
|
||||
if (!gcode.str().empty()) {
|
||||
if (GCodeWriter::full_gcode_comment) {
|
||||
gcode << " ; Override input shaping";
|
||||
}
|
||||
gcode << "\n";
|
||||
}
|
||||
gcode << "\n";
|
||||
return gcode.str();
|
||||
}
|
||||
|
||||
|
||||
@@ -1318,6 +1318,8 @@ static std::vector<std::string> s_Preset_machine_limits_options {
|
||||
"machine_max_junction_deviation",
|
||||
//resonance avoidance ported from qidi slicer
|
||||
"resonance_avoidance", "min_resonance_avoidance_speed", "max_resonance_avoidance_speed",
|
||||
// Orca: input shaping
|
||||
"input_shaping_emit", "input_shaping_type", "input_shaping_freq_x", "input_shaping_freq_y", "input_shaping_damp_x", "input_shaping_damp_y",
|
||||
};
|
||||
|
||||
static std::vector<std::string> s_Preset_printer_options {
|
||||
|
||||
@@ -91,6 +91,25 @@ size_t get_extruder_index(const GCodeConfig& config, unsigned int filament_id)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Orca: input shaping values types by flavor
|
||||
std::vector<std::string> get_shaper_type_values_for_flavor(GCodeFlavor flavor)
|
||||
{
|
||||
switch (flavor) {
|
||||
case GCodeFlavor::gcfKlipper:
|
||||
return {"Default", "MZV", "ZV", "ZVD", "EI", "2HUMP_EI", "3HUMP_EI"};
|
||||
case GCodeFlavor::gcfRepRapFirmware:
|
||||
return {"Default", "MZV", "ZV", "ZVD", "ZVDD", "ZVDDD", "EI2", "EI3", "DAA"};
|
||||
case GCodeFlavor::gcfMarlinFirmware:
|
||||
return {"ZV"};
|
||||
case GCodeFlavor::gcfMarlinLegacy:
|
||||
return {};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return {"Default"};
|
||||
}
|
||||
|
||||
static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map)
|
||||
{
|
||||
t_config_enum_names names;
|
||||
@@ -481,6 +500,23 @@ static t_config_enum_values s_keys_map_PrinterStructure {
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(PrinterStructure)
|
||||
|
||||
static t_config_enum_values s_keys_map_InputShaperType {
|
||||
{"Default", int(InputShaperType::Default)},
|
||||
{"MZV", int(InputShaperType::MZV)},
|
||||
{"ZV", int(InputShaperType::ZV)},
|
||||
{"ZVD", int(InputShaperType::ZVD)},
|
||||
{"ZVDD", int(InputShaperType::ZVDD)},
|
||||
{"ZVDDD", int(InputShaperType::ZVDDD)},
|
||||
{"EI", int(InputShaperType::EI)},
|
||||
{"EI2", int(InputShaperType::EI2)},
|
||||
{"2HUMP_EI",int(InputShaperType::TwoHumpEI)},
|
||||
{"EI3", int(InputShaperType::EI3)},
|
||||
{"3HUMP_EI",int(InputShaperType::ThreeHumpEI)},
|
||||
{"DAA", int(InputShaperType::DAA)},
|
||||
{"Disable", int(InputShaperType::Disable)}
|
||||
};
|
||||
CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(InputShaperType)
|
||||
|
||||
static t_config_enum_values s_keys_map_PerimeterGeneratorType{
|
||||
{ "classic", int(PerimeterGeneratorType::Classic) },
|
||||
{ "arachne", int(PerimeterGeneratorType::Arachne) }
|
||||
@@ -4243,8 +4279,8 @@ void PrintConfigDef::init_fff_params()
|
||||
def = this->add("emit_machine_limits_to_gcode", coBool);
|
||||
def->label = L("Emit limits to G-code");
|
||||
def->category = L("Machine limits");
|
||||
def->tooltip = L("If enabled, the machine limits will be emitted to G-code file.\nThis option will be ignored if the G-code flavor is "
|
||||
"set to Klipper.");
|
||||
def->tooltip = L("If enabled, the machine limits will be emitted to G-code file.\nThis option will be ignored if the G-code flavor is "
|
||||
"set to Klipper.");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionBool(true));
|
||||
|
||||
@@ -4455,6 +4491,56 @@ void PrintConfigDef::init_fff_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(120));
|
||||
|
||||
// Orca: Input Shaping support
|
||||
def = this->add("input_shaping_emit", coBool);
|
||||
def->label = L("Emit input shaping");
|
||||
def->tooltip = L("Override firmware input shaping settings.\nIf disabled, firmware settings are used.");
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionBool(false));
|
||||
|
||||
def = this->add("input_shaping_type", coEnum);
|
||||
def->label = L("Input shaper type");
|
||||
def->tooltip = L("Choose the input shaper algorithm.\nDefault uses the firmware default settings.\nDisable turns off input shaping in the firmware.");
|
||||
def->enum_keys_map = &ConfigOptionEnum<InputShaperType>::get_enum_values();
|
||||
def->enum_values = {"Default", "MZV", "ZV", "ZVD", "ZVDD", "ZVDDD", "EI", "EI2", "2HUMP_EI", "EI3", "3HUMP_EI", "DAA", "Disable"};
|
||||
def->enum_labels = {L("Default"), L("MZV"), L("ZV"), L("ZVD"), L("ZVDD"), L("ZVDDD"), L("EI"), L("EI2"), L("2HUMP_EI"), L("EI3"), L("3HUMP_EI"), L("DAA"), L("Disable")};
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionEnum<InputShaperType>(InputShaperType::Default));
|
||||
|
||||
def = this->add("input_shaping_freq_x", coFloat);
|
||||
def->label = L("X");
|
||||
def->tooltip = L("Resonant frequency for the X axis input shaper.\nZero will use the firmware frequency.\nTo disable input shaping, use the Disable type.\nRRF: X and Y values are equal.");
|
||||
def->sidetext = "Hz";
|
||||
def->min = 0;
|
||||
def->max = 1000;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("input_shaping_freq_y", coFloat);
|
||||
def->label = L("Y");
|
||||
def->tooltip = L("Resonant frequency for the Y axis input shaper.\nZero will use the firmware frequency.\nTo disable input shaping, use the Disable type.");
|
||||
def->sidetext = "Hz";
|
||||
def->min = 0;
|
||||
def->max = 1000;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0));
|
||||
|
||||
def = this->add("input_shaping_damp_x", coFloat);
|
||||
def->label = L("X");
|
||||
def->tooltip = L("Damping ratio for the X axis input shaper.\nZero will use the firmware damping ratio.\nTo disable input shaping, use the Disable type.\nRRF: X and Y values are equal.");
|
||||
def->min = 0;
|
||||
def->max = 1;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0.1));
|
||||
|
||||
def = this->add("input_shaping_damp_y", coFloat);
|
||||
def->label = L("Y");
|
||||
def->tooltip = L("Damping ratio for the Y axis input shaper.\nZero will use the firmware damping ratio.\nTo disable input shaping, use the Disable type.");
|
||||
def->min = 0;
|
||||
def->max = 1;
|
||||
def->mode = comExpert;
|
||||
def->set_default_value(new ConfigOptionFloat(0.1));
|
||||
|
||||
def = this->add("fan_max_speed", coFloats);
|
||||
def->label = L("Fan speed");
|
||||
def->tooltip = L("Part cooling fan speed may be increased when auto cooling is enabled. "
|
||||
|
||||
@@ -362,6 +362,22 @@ enum PrinterStructure {
|
||||
psDelta
|
||||
};
|
||||
|
||||
enum class InputShaperType : unsigned char {
|
||||
Default = 0,
|
||||
MZV,
|
||||
ZV,
|
||||
ZVD,
|
||||
ZVDD,
|
||||
ZVDDD,
|
||||
EI,
|
||||
EI2,
|
||||
TwoHumpEI,
|
||||
EI3,
|
||||
ThreeHumpEI,
|
||||
DAA,
|
||||
Disable
|
||||
};
|
||||
|
||||
// BBS
|
||||
enum ZHopType {
|
||||
zhtAuto = 0,
|
||||
@@ -525,6 +541,7 @@ CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BrimType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(TimelapseType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(BedType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(SkirtType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(InputShaperType)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(DraftShield)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(ForwardCompatibilitySubstitutionRule)
|
||||
CONFIG_OPTION_ENUM_DECLARE_STATIC_MAPS(GCodeThumbnailsFormat)
|
||||
@@ -1259,6 +1276,14 @@ PRINT_CONFIG_CLASS_DEFINE(
|
||||
((ConfigOptionBool, resonance_avoidance))
|
||||
((ConfigOptionFloat, min_resonance_avoidance_speed))
|
||||
((ConfigOptionFloat, max_resonance_avoidance_speed))
|
||||
|
||||
//Orca: Input shaping
|
||||
((ConfigOptionBool, input_shaping_emit))
|
||||
((ConfigOptionEnum<InputShaperType>, input_shaping_type))
|
||||
((ConfigOptionFloat, input_shaping_freq_x))
|
||||
((ConfigOptionFloat, input_shaping_freq_y))
|
||||
((ConfigOptionFloat, input_shaping_damp_x))
|
||||
((ConfigOptionFloat, input_shaping_damp_y))
|
||||
)
|
||||
|
||||
// This object is mapped to Perl as Slic3r::Config::GCode.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
#include <regex>
|
||||
#include <cstdint>
|
||||
#include <wx/numformatter.h>
|
||||
#include <wx/tooltip.h>
|
||||
#include <wx/notebook.h>
|
||||
@@ -1626,18 +1627,45 @@ void Choice::set_value(const boost::any& value, bool change_event)
|
||||
}
|
||||
case coEnum:
|
||||
// BBS
|
||||
case coEnums: {
|
||||
case coEnums: {
|
||||
int val = boost::any_cast<int>(value);
|
||||
int selection = val;
|
||||
|
||||
// Support ThirdPartyPrinter
|
||||
if (m_opt_id.compare("host_type") == 0 && val != 0 &&
|
||||
m_opt.enum_values.size() > field->GetCount()) // for case, when PrusaLink isn't used as a HostType
|
||||
val--;
|
||||
if (m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" ||
|
||||
m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" ||
|
||||
m_opt_id == "support_base_pattern" || m_opt_id == "support_interface_pattern" ||
|
||||
m_opt_id == "ironing_pattern" || m_opt_id == "support_ironing_pattern" ||
|
||||
m_opt_id == "support_style" || m_opt_id == "curr_bed_type" || m_opt_id == "wipe_tower_wall_type")
|
||||
if (m_opt_id == "input_shaping_type") {
|
||||
if (field != nullptr) {
|
||||
const unsigned int count = field->GetCount();
|
||||
int match_index = -1;
|
||||
for (unsigned int idx = 0; idx < count; ++idx) {
|
||||
if (void* data = field->GetClientData(idx)) {
|
||||
int stored = static_cast<int>(reinterpret_cast<uintptr_t>(data));
|
||||
if (stored == val) {
|
||||
match_index = static_cast<int>(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match_index >= 0)
|
||||
selection = match_index;
|
||||
else if (val >= 0 && val < static_cast<int>(count))
|
||||
selection = val;
|
||||
else if (count > 0)
|
||||
selection = 0;
|
||||
else
|
||||
selection = -1;
|
||||
}
|
||||
} else {
|
||||
// Support ThirdPartyPrinter
|
||||
if (m_opt_id.compare("host_type") == 0 && val != 0 &&
|
||||
m_opt.enum_values.size() > field->GetCount()) // for case, when PrusaLink isn't used as a HostType
|
||||
selection = val - 1;
|
||||
else
|
||||
selection = val;
|
||||
|
||||
if (m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" ||
|
||||
m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" ||
|
||||
m_opt_id == "support_base_pattern" || m_opt_id == "support_interface_pattern" ||
|
||||
m_opt_id == "ironing_pattern" || m_opt_id == "support_ironing_pattern" ||
|
||||
m_opt_id == "support_style" || m_opt_id == "curr_bed_type" || m_opt_id == "wipe_tower_wall_type")
|
||||
{
|
||||
std::string key;
|
||||
const t_config_enum_values& map_names = *m_opt.enum_keys_map;
|
||||
@@ -1649,15 +1677,16 @@ void Choice::set_value(const boost::any& value, bool change_event)
|
||||
|
||||
const std::vector<std::string>& values = m_opt.enum_values;
|
||||
auto it = std::find(values.begin(), values.end(), key);
|
||||
val = it == values.end() ? 0 : it - values.begin();
|
||||
selection = it == values.end() ? 0 : static_cast<int>(it - values.begin());
|
||||
}
|
||||
}
|
||||
if (m_opt.nullable) {
|
||||
if (val != ConfigOptionEnumsGenericNullable::nil_value())
|
||||
m_last_meaningful_value = value;
|
||||
else
|
||||
val = -1;
|
||||
selection = -1;
|
||||
}
|
||||
field->SetSelection(val);
|
||||
field->SetSelection(selection);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -1724,6 +1753,17 @@ boost::any& Choice::get_value()
|
||||
{
|
||||
if (m_opt.nullable && field->GetSelection() == -1)
|
||||
m_value = ConfigOptionEnumsGenericNullable::nil_value();
|
||||
else if (m_opt_id == "input_shaping_type")
|
||||
{
|
||||
int selection = field->GetSelection();
|
||||
if (selection >= 0) {
|
||||
if (void* data = field->GetClientData(selection))
|
||||
m_value = static_cast<int>(reinterpret_cast<uintptr_t>(data));
|
||||
else
|
||||
m_value = selection;
|
||||
} else
|
||||
m_value = 0;
|
||||
}
|
||||
else if ( m_opt_id == "top_surface_pattern" || m_opt_id == "bottom_surface_pattern" ||
|
||||
m_opt_id == "internal_solid_infill_pattern" || m_opt_id == "sparse_infill_pattern" ||
|
||||
m_opt_id == "support_base_pattern" || m_opt_id == "support_interface_pattern" ||
|
||||
|
||||
@@ -13296,6 +13296,8 @@ void Plater::calib_VFA(const Calib_Params& params)
|
||||
auto filament_config = &wxGetApp().preset_bundle->filaments.get_edited_preset().config;
|
||||
auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{true});
|
||||
printer_config->set_key_value("input_shaping_type", new ConfigOptionEnum<InputShaperType>(InputShaperType::Disable));
|
||||
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 0.0 });
|
||||
print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool { false });
|
||||
print_config->set_key_value("timelapse_type", new ConfigOptionEnum<TimelapseType>(tlTraditional));
|
||||
@@ -13359,10 +13361,12 @@ void Plater::calib_input_shaping_freq(const Calib_Params& params)
|
||||
}
|
||||
|
||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{false});
|
||||
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 0.0 });
|
||||
filament_config->set_key_value("slow_down_min_speed", new ConfigOptionFloats { 0.0 });
|
||||
filament_config->set_key_value("slow_down_for_layer_cooling", new ConfigOptionBools{false});
|
||||
print_config->set_key_value("enable_overhang_speed", new ConfigOptionBool { false });
|
||||
print_config->set_key_value("layer_height", new ConfigOptionFloat(0.2));
|
||||
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));
|
||||
@@ -13420,6 +13424,7 @@ void Plater::calib_input_shaping_damp(const Calib_Params& params)
|
||||
}
|
||||
|
||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{false});
|
||||
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 0.0 });
|
||||
filament_config->set_key_value("slow_down_min_speed", new ConfigOptionFloats { 0.0 });
|
||||
filament_config->set_key_value("slow_down_for_layer_cooling", new ConfigOptionBools{false});
|
||||
@@ -13482,6 +13487,8 @@ void Plater::Calib_Cornering(const Calib_Params& params)
|
||||
}
|
||||
|
||||
printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false});
|
||||
printer_config->set_key_value("input_shaping_emit", new ConfigOptionBool{true});
|
||||
printer_config->set_key_value("input_shaping_type", new ConfigOptionEnum<InputShaperType>(InputShaperType::Disable));
|
||||
filament_config->set_key_value("slow_down_layer_time", new ConfigOptionFloats { 0.0 });
|
||||
filament_config->set_key_value("slow_down_min_speed", new ConfigOptionFloats { 0.0 });
|
||||
filament_config->set_key_value("slow_down_for_layer_cooling", new ConfigOptionBools{false});
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "Widgets/Label.hpp"
|
||||
#include "Widgets/SwitchButton.hpp"
|
||||
#include "Widgets/TabCtrl.hpp"
|
||||
#include "Widgets/ComboBox.hpp"
|
||||
#include "MarkdownTip.hpp"
|
||||
#include "Search.hpp"
|
||||
#include "BedShapeDialog.hpp"
|
||||
@@ -1494,6 +1495,11 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
return;
|
||||
}
|
||||
|
||||
if (opt_key == "gcode_flavor" && m_type == Preset::TYPE_PRINTER) {
|
||||
if (auto printer_tab = dynamic_cast<TabPrinter*>(this))
|
||||
printer_tab->on_gcode_flavor_changed();
|
||||
}
|
||||
|
||||
if (opt_key == "compatible_prints")
|
||||
this->compatible_widget_reload(m_compatible_prints);
|
||||
if (opt_key == "compatible_printers")
|
||||
@@ -4796,7 +4802,7 @@ PageShp TabPrinter::build_kinematics_page()
|
||||
optgroup->append_single_option_line("emit_machine_limits_to_gcode", "printer_motion_ability#emit-limits-to-g-code");
|
||||
|
||||
// resonance avoidance ported over from qidi slicer
|
||||
optgroup = page->new_optgroup(L("Resonance Avoidance"), "param_resonance_avoidance");
|
||||
optgroup = page->new_optgroup(L("Resonance Compensation"), "param_resonance_avoidance");
|
||||
optgroup->append_single_option_line("resonance_avoidance", "printer_motion_ability#resonance-avoidance");
|
||||
// Resonance‑avoidance speed inputs
|
||||
{
|
||||
@@ -4806,6 +4812,20 @@ PageShp TabPrinter::build_kinematics_page()
|
||||
resonance_line.append_option(optgroup->get_option("max_resonance_avoidance_speed"));
|
||||
optgroup->append_line(resonance_line);
|
||||
}
|
||||
optgroup->append_single_option_line("input_shaping_emit", "input-shaping-calib");
|
||||
optgroup->append_single_option_line("input_shaping_type", "input-shaping-calib");
|
||||
{
|
||||
Line freq_line = {L("Frequency"), L("The frequency of the anti-vibration signal will correspond to the natural frequency of the frame.")};
|
||||
freq_line.append_option(optgroup->get_option("input_shaping_freq_x"));
|
||||
freq_line.append_option(optgroup->get_option("input_shaping_freq_y"));
|
||||
optgroup->append_line(freq_line);
|
||||
}
|
||||
{
|
||||
Line damping_line = {L("Damping"), L("Damping ratio for the input shaping filter.")};
|
||||
damping_line.append_option(optgroup->get_option("input_shaping_damp_x"));
|
||||
damping_line.append_option(optgroup->get_option("input_shaping_damp_y"));
|
||||
optgroup->append_line(damping_line);
|
||||
}
|
||||
|
||||
const std::vector<std::string> speed_axes{
|
||||
"machine_max_speed_x",
|
||||
@@ -5248,6 +5268,115 @@ void TabPrinter::clear_pages()
|
||||
m_reset_to_filament_color = nullptr;
|
||||
}
|
||||
|
||||
std::vector<InputShaperType> input_shaper_types_for_flavor(GCodeFlavor flavor)
|
||||
{
|
||||
switch (flavor) {
|
||||
case GCodeFlavor::gcfKlipper:
|
||||
return {
|
||||
InputShaperType::Default,
|
||||
InputShaperType::ZV,
|
||||
InputShaperType::MZV,
|
||||
InputShaperType::ZVD,
|
||||
InputShaperType::EI,
|
||||
InputShaperType::TwoHumpEI,
|
||||
InputShaperType::ThreeHumpEI,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
case GCodeFlavor::gcfRepRapFirmware:
|
||||
return {
|
||||
InputShaperType::Default,
|
||||
InputShaperType::MZV,
|
||||
InputShaperType::ZVD,
|
||||
InputShaperType::ZVDD,
|
||||
InputShaperType::ZVDDD,
|
||||
InputShaperType::EI2,
|
||||
InputShaperType::EI3,
|
||||
InputShaperType::DAA,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
case GCodeFlavor::gcfMarlinFirmware:
|
||||
return {
|
||||
InputShaperType::ZV,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
default:
|
||||
return {
|
||||
InputShaperType::Default,
|
||||
InputShaperType::Disable
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void TabPrinter::update_input_shaper_menu(GCodeFlavor flavor)
|
||||
{
|
||||
if (m_presets->get_edited_preset().printer_technology() != ptFFF)
|
||||
return;
|
||||
|
||||
const std::vector<InputShaperType> allowed = input_shaper_types_for_flavor(flavor);
|
||||
if (allowed.empty())
|
||||
return;
|
||||
|
||||
const InputShaperType current = m_config->opt_enum<InputShaperType>("input_shaping_type");
|
||||
const bool needs_reset = std::find(allowed.begin(), allowed.end(), current) == allowed.end();
|
||||
const InputShaperType desired = needs_reset ? allowed.front() : current;
|
||||
|
||||
if (needs_reset && current != desired) {
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
new_conf.set_key_value("input_shaping_type", new ConfigOptionEnum<InputShaperType>(desired));
|
||||
m_config_manipulation.apply(m_config, &new_conf);
|
||||
}
|
||||
|
||||
Page* owning_page = nullptr;
|
||||
Field* field = get_field("input_shaping_type", &owning_page);
|
||||
if (field == nullptr)
|
||||
return;
|
||||
|
||||
auto choice_field = dynamic_cast<Choice*>(field);
|
||||
if (choice_field == nullptr)
|
||||
return;
|
||||
|
||||
auto combo = dynamic_cast<ComboBox*>(choice_field->getWindow());
|
||||
if (combo == nullptr)
|
||||
return;
|
||||
|
||||
const ConfigOptionDef* def = m_config->def()->get("input_shaping_type");
|
||||
if (def == nullptr)
|
||||
return;
|
||||
|
||||
const auto& labels = def->enum_labels;
|
||||
const auto& values = def->enum_values;
|
||||
|
||||
wxWindowUpdateLocker locker(combo);
|
||||
combo->Clear();
|
||||
|
||||
for (InputShaperType type : allowed) {
|
||||
const size_t idx = static_cast<size_t>(type);
|
||||
wxString label;
|
||||
if (idx < labels.size() && !labels[idx].empty())
|
||||
label = _(labels[idx]);
|
||||
else if (idx < values.size())
|
||||
label = wxString::FromUTF8(values[idx].c_str());
|
||||
else
|
||||
label = wxString::Format("%d", static_cast<int>(type));
|
||||
|
||||
combo->Append(label, wxNullBitmap,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(static_cast<int>(type))));
|
||||
}
|
||||
|
||||
if (combo->GetCount() == 0)
|
||||
return;
|
||||
|
||||
choice_field->set_value(static_cast<int>(desired), false);
|
||||
}
|
||||
|
||||
void TabPrinter::on_gcode_flavor_changed()
|
||||
{
|
||||
auto* flavor_option = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor");
|
||||
if (!flavor_option)
|
||||
return;
|
||||
update_input_shaper_menu(flavor_option->value);
|
||||
}
|
||||
|
||||
void TabPrinter::toggle_options()
|
||||
{
|
||||
if (!m_active_page || m_presets->get_edited_preset().printer_technology() == ptSLA)
|
||||
@@ -5400,6 +5529,7 @@ void TabPrinter::toggle_options()
|
||||
|
||||
if (m_active_page->title() == L("Motion ability")) {
|
||||
auto gcf = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
|
||||
update_input_shaper_menu(gcf);
|
||||
bool silent_mode = m_config->opt_bool("silent_mode");
|
||||
int max_field = silent_mode ? 2 : 1;
|
||||
for (int i = 0; i < max_field; ++i)
|
||||
@@ -5427,9 +5557,31 @@ void TabPrinter::toggle_options()
|
||||
toggle_option("machine_max_jerk_e", enable_jerk, i);
|
||||
}
|
||||
|
||||
bool emittable_limits = m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfMarlinLegacy || m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfMarlinFirmware || m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfRepRapFirmware;
|
||||
toggle_option("emit_machine_limits_to_gcode", emittable_limits);
|
||||
|
||||
bool resonance_avoidance = m_config->opt_bool("resonance_avoidance");
|
||||
toggle_option("min_resonance_avoidance_speed", resonance_avoidance);
|
||||
toggle_option("max_resonance_avoidance_speed", resonance_avoidance);
|
||||
|
||||
bool input_shaping_compatible = m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfMarlinFirmware || m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfRepRapFirmware;
|
||||
|
||||
for (auto is : {"input_shaping_emit", "input_shaping_type", "input_shaping_freq_x", "input_shaping_freq_y",
|
||||
"input_shaping_damp_x", "input_shaping_damp_y"})
|
||||
toggle_line(is, input_shaping_compatible);
|
||||
|
||||
if (input_shaping_compatible) {
|
||||
bool emit_machine_limits_to_gcode = m_config->opt_bool("emit_machine_limits_to_gcode");
|
||||
toggle_option("input_shaping_emit", emit_machine_limits_to_gcode);
|
||||
bool input_shaping_emit = emit_machine_limits_to_gcode && m_config->opt_bool("input_shaping_emit");
|
||||
bool reprap = m_config->opt_enum<GCodeFlavor>("gcode_flavor") == GCodeFlavor::gcfRepRapFirmware;
|
||||
toggle_option("input_shaping_type", input_shaping_emit);
|
||||
toggle_option("input_shaping_freq_x", input_shaping_emit);
|
||||
toggle_option("input_shaping_freq_y", input_shaping_emit && !reprap);
|
||||
toggle_option("input_shaping_damp_x", input_shaping_emit);
|
||||
toggle_option("input_shaping_damp_y", input_shaping_emit && !reprap);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@ namespace GUI {
|
||||
class TabPresetComboBox;
|
||||
class OG_CustomCtrl;
|
||||
|
||||
std::vector<InputShaperType> input_shaper_types_for_flavor(GCodeFlavor flavor);
|
||||
|
||||
// Single Tab page containing a{ vsizer } of{ optgroups }
|
||||
// package Slic3r::GUI::Tab::Page;
|
||||
using ConfigOptionsGroupShp = std::shared_ptr<ConfigOptionsGroup>;
|
||||
@@ -600,6 +602,7 @@ private:
|
||||
bool m_use_silent_mode = false;
|
||||
void append_option_line(ConfigOptionsGroupShp optgroup, const std::string opt_key, const std::string& label_path = "");
|
||||
bool m_rebuild_kinematics_page = false;
|
||||
void update_input_shaper_menu(GCodeFlavor flavor);
|
||||
|
||||
ogStaticText* m_fff_print_host_upload_description_line {nullptr};
|
||||
ogStaticText* m_sla_print_host_upload_description_line {nullptr};
|
||||
@@ -637,6 +640,7 @@ public:
|
||||
void update_fff();
|
||||
void update_sla();
|
||||
void update_pages(); // update m_pages according to printer technology
|
||||
void on_gcode_flavor_changed();
|
||||
void extruders_count_changed(size_t extruders_count);
|
||||
PageShp build_kinematics_page();
|
||||
void build_unregular_pages(bool from_initial_build = false);
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
std::vector<InputShaperType> input_shaper_types_for_flavor(GCodeFlavor flavor);
|
||||
|
||||
namespace {
|
||||
|
||||
void ParseStringValues(std::string str, std::vector<double> &vec)
|
||||
@@ -36,18 +38,29 @@ std::vector<std::string> get_shaper_type_values()
|
||||
{
|
||||
if (auto* preset_bundle = wxGetApp().preset_bundle) {
|
||||
auto printer_config = &preset_bundle->printers.get_edited_preset().config;
|
||||
if (auto* gcode_flavor_option = printer_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")) {
|
||||
switch (gcode_flavor_option->value) {
|
||||
case GCodeFlavor::gcfKlipper:
|
||||
return {"Default", "ZV", "MZV", "ZVD", "EI", "2HUMP_EI", "3HUMP_EI"};
|
||||
case GCodeFlavor::gcfRepRapFirmware:
|
||||
return {"Default", "MZV", "ZVD", "ZVDD", "ZVDDD", "EI2", "EI3", "DAA"};
|
||||
case GCodeFlavor::gcfMarlinFirmware:
|
||||
return {"ZV"};
|
||||
default:
|
||||
break;
|
||||
const auto* gcode_flavor_option = printer_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor");
|
||||
const ConfigOptionDef* def = printer_config->def()->get("input_shaping_type");
|
||||
if (gcode_flavor_option) {
|
||||
auto types = input_shaper_types_for_flavor(gcode_flavor_option->value);
|
||||
if (!types.empty()) {
|
||||
std::vector<std::string> values;
|
||||
values.reserve(types.size());
|
||||
for (InputShaperType type : types) {
|
||||
if (type == InputShaperType::Disable)
|
||||
continue;
|
||||
const size_t idx = static_cast<size_t>(type);
|
||||
if (def && idx < def->enum_values.size())
|
||||
values.push_back(def->enum_values[idx]);
|
||||
else
|
||||
values.push_back(std::to_string(static_cast<int>(type)));
|
||||
}
|
||||
if (!values.empty())
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
if (def && !def->enum_values.empty())
|
||||
return {def->enum_values.front()};
|
||||
}
|
||||
return {"Default"};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user