mirror of
https://github.com/Dark98/SliceBeam.git
synced 2026-07-03 00:38:53 +00:00
Implement Support For Klippers Adaptive Bed Meshing
This commit is contained in:
@@ -196,6 +196,27 @@ public class PrinterConfigFragment extends ProfileListFragment {
|
||||
new OptionElement(def.options.get("elegoolink_bed_type"))
|
||||
));
|
||||
}
|
||||
if ("moonraker".equalsIgnoreCase(hostType) || "klipper".equalsIgnoreCase(hostType)) {
|
||||
int insertIndex = list.size();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
OptionElement el = list.get(i);
|
||||
if (el != null && el.simpleItem instanceof SubHeader) {
|
||||
String title = ((SubHeader) el.simpleItem).title;
|
||||
if ("Advanced".equals(title)) {
|
||||
insertIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
list.addAll(insertIndex, Arrays.asList(
|
||||
new OptionElement(new SubHeader("Adaptive bed mesh")),
|
||||
new OptionElement(def.options.get("bed_mesh_probe_distance")),
|
||||
new OptionElement(def.options.get("bed_mesh_limit_min")),
|
||||
new OptionElement(def.options.get("bed_mesh_limit_max")),
|
||||
new OptionElement(def.options.get("adaptive_bed_mesh_margin")),
|
||||
new OptionElement(new SpaceItem(0, ViewUtils.dp(4)))
|
||||
));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,8 @@ public class Slic3rConfigWrapper {
|
||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e",
|
||||
"elegoolink_timelapse", "elegoolink_bed_leveling", "elegoolink_bed_type"
|
||||
"elegoolink_timelapse", "elegoolink_bed_leveling", "elegoolink_bed_type",
|
||||
"bed_mesh_probe_distance", "bed_mesh_limit_min", "bed_mesh_limit_max", "adaptive_bed_mesh_margin"
|
||||
);
|
||||
public final static List<String> PHYSICAL_PRINTER_CONFIG_KEYS = Arrays.asList(
|
||||
"preset_name", // temporary option to compatibility with older Slicer
|
||||
|
||||
@@ -1159,6 +1159,14 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
m_label_objects.init(print.objects(), print.config().gcode_label_objects, print.config().gcode_flavor);
|
||||
file.write(m_label_objects.all_objects_header());
|
||||
|
||||
bool adaptive_bed_mesh_ready = false;
|
||||
Vec2d adaptive_bed_mesh_min;
|
||||
Vec2d adaptive_bed_mesh_max;
|
||||
int adaptive_probe_count_x = 0;
|
||||
int adaptive_probe_count_y = 0;
|
||||
const char *adaptive_bed_mesh_algo = nullptr;
|
||||
const bool host_is_klipper = (this->config().host_type.value == htMoonraker);
|
||||
|
||||
// Update output variables after the extruders were initialized.
|
||||
m_placeholder_parser_integration.init(m_writer);
|
||||
// Let the start-up script prime the 1st printing tool.
|
||||
@@ -1206,7 +1214,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
}
|
||||
{
|
||||
if (host_is_klipper) {
|
||||
// Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
|
||||
// It encompasses the object extrusions, support extrusions, skirt, brim, wipe tower.
|
||||
// It does NOT encompass user extrusions generated by custom G-code,
|
||||
@@ -1222,6 +1230,53 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
|
||||
this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
|
||||
this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size()));
|
||||
|
||||
BoundingBoxf bed_bbox(print.config().bed_shape.values);
|
||||
BoundingBoxf mesh_bbox = bbox;
|
||||
if (bed_bbox.defined) {
|
||||
const double margin = print.config().adaptive_bed_mesh_margin.value;
|
||||
double min_x = bbox.min.x() - margin;
|
||||
double min_y = bbox.min.y() - margin;
|
||||
double max_x = bbox.max.x() + margin;
|
||||
double max_y = bbox.max.y() + margin;
|
||||
|
||||
min_x = std::max(min_x, bed_bbox.min.x());
|
||||
min_y = std::max(min_y, bed_bbox.min.y());
|
||||
max_x = std::min(max_x, bed_bbox.max.x());
|
||||
max_y = std::min(max_y, bed_bbox.max.y());
|
||||
|
||||
const Vec2d limit_min = print.config().bed_mesh_limit_min.value;
|
||||
const Vec2d limit_max = print.config().bed_mesh_limit_max.value;
|
||||
if (limit_min.x() > -99998 || limit_min.y() > -99998) {
|
||||
min_x = std::max(min_x, limit_min.x());
|
||||
min_y = std::max(min_y, limit_min.y());
|
||||
}
|
||||
if (limit_max.x() > -99998 || limit_max.y() > -99998) {
|
||||
max_x = std::min(max_x, limit_max.x());
|
||||
max_y = std::min(max_y, limit_max.y());
|
||||
}
|
||||
|
||||
mesh_bbox.min = Vec2d(min_x, min_y);
|
||||
mesh_bbox.max = Vec2d(max_x, max_y);
|
||||
}
|
||||
|
||||
adaptive_bed_mesh_min = mesh_bbox.min;
|
||||
adaptive_bed_mesh_max = mesh_bbox.max;
|
||||
adaptive_bed_mesh_ready = true;
|
||||
|
||||
this->placeholder_parser().set("adaptive_bed_mesh_min", new ConfigOptionFloats({ mesh_bbox.min.x(), mesh_bbox.min.y() }));
|
||||
this->placeholder_parser().set("adaptive_bed_mesh_max", new ConfigOptionFloats({ mesh_bbox.max.x(), mesh_bbox.max.y() }));
|
||||
|
||||
const Vec2d probe_dist = print.config().bed_mesh_probe_distance.value;
|
||||
const double probe_dist_x = std::max(1.0, probe_dist.x());
|
||||
const double probe_dist_y = std::max(1.0, probe_dist.y());
|
||||
const int probe_count_x = std::max(3, int(std::ceil(mesh_bbox.size().x() / probe_dist_x)) + 1);
|
||||
const int probe_count_y = std::max(3, int(std::ceil(mesh_bbox.size().y() / probe_dist_y)) + 1);
|
||||
adaptive_probe_count_x = probe_count_x;
|
||||
adaptive_probe_count_y = probe_count_y;
|
||||
this->placeholder_parser().set("bed_mesh_probe_count", new ConfigOptionInts({ probe_count_x, probe_count_y }));
|
||||
adaptive_bed_mesh_algo = (probe_count_x < 4 || probe_count_y < 4) ? "lagrange" : "bicubic";
|
||||
this->placeholder_parser().set("bed_mesh_algo", new ConfigOptionString(adaptive_bed_mesh_algo));
|
||||
// PlaceholderParser currently substitues non-existent vector values with the zero'th value, which is harmful in the case of "is_extruder_used[]"
|
||||
// as Slicer may lie about availability of such non-existent extruder.
|
||||
// We rather sacrifice 256B of memory before we change the behavior of the PlaceholderParser, which should really only fill in the non-existent
|
||||
@@ -1235,7 +1290,14 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
// Enable ooze prevention if configured so.
|
||||
DoExport::init_ooze_prevention(print, m_ooze_prevention);
|
||||
|
||||
std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config().start_gcode.value, initial_extruder_id);
|
||||
const std::string &start_gcode_template = print.config().start_gcode.value;
|
||||
const bool uses_adaptive_bed_mesh_placeholders =
|
||||
start_gcode_template.find("adaptive_bed_mesh_min") != std::string::npos ||
|
||||
start_gcode_template.find("adaptive_bed_mesh_max") != std::string::npos ||
|
||||
start_gcode_template.find("bed_mesh_probe_count") != std::string::npos ||
|
||||
start_gcode_template.find("bed_mesh_algo") != std::string::npos;
|
||||
|
||||
std::string start_gcode = this->placeholder_parser_process("start_gcode", start_gcode_template, initial_extruder_id);
|
||||
|
||||
this->_print_first_layer_chamber_temperature(file, print, start_gcode, config().chamber_temperature.get_at(initial_extruder_id), false, false);
|
||||
this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true);
|
||||
@@ -1245,6 +1307,13 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
|
||||
file.write_format(";%s%s\n", GCodeProcessor::reserved_tag(GCodeProcessor::ETags::Role).c_str(), gcode_extrusion_role_to_string(GCodeExtrusionRole::Custom).c_str());
|
||||
|
||||
// Write the custom start G-code
|
||||
if (host_is_klipper && adaptive_bed_mesh_ready && uses_adaptive_bed_mesh_placeholders) {
|
||||
file.write_format("; Adaptive bed mesh: min=%.3f,%.3f max=%.3f,%.3f probe_count=%d,%d algo=%s\n",
|
||||
adaptive_bed_mesh_min.x(), adaptive_bed_mesh_min.y(),
|
||||
adaptive_bed_mesh_max.x(), adaptive_bed_mesh_max.y(),
|
||||
adaptive_probe_count_x, adaptive_probe_count_y,
|
||||
adaptive_bed_mesh_algo ? adaptive_bed_mesh_algo : "");
|
||||
}
|
||||
file.writeln(start_gcode);
|
||||
|
||||
this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true);
|
||||
|
||||
@@ -346,6 +346,35 @@ void PrintConfigDef::init_common_params()
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) });
|
||||
|
||||
def = this->add("bed_mesh_limit_min", coPoint);
|
||||
def->label = L("Bed mesh min");
|
||||
def->tooltip = L("Minimum point for allowed bed mesh area. Default is no limits.");
|
||||
def->sidetext = L("mm");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPoint(Vec2d(-99999, -99999)));
|
||||
|
||||
def = this->add("bed_mesh_limit_max", coPoint);
|
||||
def->label = L("Bed mesh max");
|
||||
def->tooltip = L("Maximum point for allowed bed mesh area. Default is no limits.");
|
||||
def->sidetext = L("mm");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPoint(Vec2d(-99999, -99999)));
|
||||
|
||||
def = this->add("bed_mesh_probe_distance", coPoint);
|
||||
def->label = L("Probe point distance");
|
||||
def->tooltip = L("Distance between probe points for bed mesh, as X,Y.");
|
||||
def->sidetext = L("mm");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionPoint(Vec2d(25, 25)));
|
||||
|
||||
def = this->add("adaptive_bed_mesh_margin", coFloat);
|
||||
def->label = L("Mesh margin");
|
||||
def->tooltip = L("Extra margin around first-layer print area used for adaptive bed mesh.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.0));
|
||||
|
||||
def = this->add("auto_arrange_bed_clearance", coFloat);
|
||||
def->label = L("Auto-arrange bed clearance");
|
||||
def->tooltip = L("Minimum distance from the bed edge when auto arranging.");
|
||||
@@ -2241,7 +2270,7 @@ void PrintConfigDef::init_fff_params()
|
||||
{ "prusalink", "PrusaLink" },
|
||||
{ "prusaconnect", "PrusaConnect" },
|
||||
{ "octoprint", "OctoPrint" },
|
||||
{ "moonraker", "Klipper (via Moonraker)" },
|
||||
{ "moonraker", "Klipper (Moonraker)" },
|
||||
{ "duet", "Duet" },
|
||||
{ "flashair", "FlashAir" },
|
||||
{ "astrobox", "AstroBox" },
|
||||
|
||||
@@ -857,7 +857,11 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionBool, avoid_crossing_perimeters))
|
||||
((ConfigOptionFloatOrPercent, avoid_crossing_perimeters_max_detour))
|
||||
((ConfigOptionPoints, bed_shape))
|
||||
((ConfigOptionPoint, bed_mesh_probe_distance))
|
||||
((ConfigOptionPoint, bed_mesh_limit_min))
|
||||
((ConfigOptionPoint, bed_mesh_limit_max))
|
||||
((ConfigOptionInts, bed_temperature))
|
||||
((ConfigOptionFloat, adaptive_bed_mesh_margin))
|
||||
((ConfigOptionFloat, bridge_acceleration))
|
||||
((ConfigOptionInts, bridge_fan_speed))
|
||||
((ConfigOptionBools, enable_dynamic_fan_speeds))
|
||||
@@ -909,6 +913,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE(
|
||||
((ConfigOptionFloat, perimeter_acceleration))
|
||||
((ConfigOptionStrings, post_process))
|
||||
((ConfigOptionBool, prefer_clockwise_movements))
|
||||
((ConfigOptionEnum<PrintHostType>, host_type))
|
||||
((ConfigOptionString, printer_model))
|
||||
((ConfigOptionString, printer_notes))
|
||||
((ConfigOptionFloat, resolution))
|
||||
|
||||
Reference in New Issue
Block a user