Implement Support For Klippers Adaptive Bed Meshing

This commit is contained in:
Dark98
2026-01-30 21:01:36 +00:00
parent 3b67c4cdac
commit 197e46eabc
5 changed files with 129 additions and 4 deletions
@@ -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
+71 -2
View File
@@ -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);
+30 -1
View File
@@ -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))