Make G26 work with all mesh leveling.

Example Configuration.h files are not updated yet.   You need to cross
your settings over to the default Configuration.h file in the \Marlin
directory.   (UBL_G26_MESH_VALIDATION enablement has moved to a new
location in the file.)
master
Roxy-3D 6 years ago committed by Scott Lahteine
parent 82f41d6e46
commit 8282d732c1

@ -99,7 +99,7 @@ script:
# Test a probeless build of AUTO_BED_LEVELING_UBL
#
- restore_configs
- opt_enable AUTO_BED_LEVELING_UBL UBL_G26_MESH_EDITING ENABLE_LEVELING_FADE_HEIGHT EEPROM_SETTINGS G3D_PANEL
- opt_enable AUTO_BED_LEVELING_UBL G26_MESH_EDITING ENABLE_LEVELING_FADE_HEIGHT EEPROM_SETTINGS G3D_PANEL
- opt_enable_adv CUSTOM_USER_MENUS I2C_POSITION_ENCODERS BABYSTEPPING
- build_marlin
#
@ -128,7 +128,7 @@ script:
# Test MESH_BED_LEVELING feature, with LCD
#
- restore_configs
- opt_enable MESH_BED_LEVELING MESH_G28_REST_ORIGIN LCD_BED_LEVELING ULTIMAKERCONTROLLER
- opt_enable MESH_BED_LEVELING G26_MESH_EDITING MESH_G28_REST_ORIGIN LCD_BED_LEVELING ULTIMAKERCONTROLLER
- build_marlin
#
# Test MINIRAMBO for PWM_MOTOR_CURRENT
@ -142,7 +142,7 @@ script:
#
- restore_configs
- opt_set MOTHERBOARD BOARD_MINIRAMBO
- opt_enable PROBE_MANUALLY AUTO_BED_LEVELING_BILINEAR LCD_BED_LEVELING ULTIMAKERCONTROLLER
- opt_enable PROBE_MANUALLY AUTO_BED_LEVELING_BILINEAR G26_MESH_EDITING LCD_BED_LEVELING ULTIMAKERCONTROLLER
- opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT M100_FREE_MEMORY_WATCHER M100_FREE_MEMORY_DUMPER M100_FREE_MEMORY_CORRUPTOR INCH_MODE_SUPPORT TEMPERATURE_UNITS_SUPPORT
- opt_enable ULTIMAKERCONTROLLER SDSUPPORT
- opt_enable PRINTCOUNTER NOZZLE_PARK_FEATURE NOZZLE_CLEAN_FEATURE PCA9632 USE_XMAX_PLUG

@ -890,6 +890,18 @@
// at which point movement will be level to the machine's XY plane.
// The height can be set with M420 Z<height>
#define ENABLE_LEVELING_FADE_HEIGHT
/**
* Enable the G26 Mesh Validation Pattern tool.
*/
#define G26_MESH_VALIDATION // Enable G26 mesh validation
#if ENABLED(G26_MESH_VALIDATION)
#define MESH_TEST_NOZZLE_SIZE 0.4 // (mm) Diameter of primary nozzle.
#define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for the G26 Mesh Validation Tool.
#define MESH_TEST_HOTEND_TEMP 205.0 // (°C) Default nozzle temperature for the G26 Mesh Validation Tool.
#define MESH_TEST_BED_TEMP 60.0 // (°C) Default bed temperature for the G26 Mesh Validation Tool.
#endif
#endif
#if ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(AUTO_BED_LEVELING_BILINEAR)
@ -956,13 +968,6 @@
#define UBL_PROBE_PT_3_X 180
#define UBL_PROBE_PT_3_Y 20
//#define UBL_G26_MESH_VALIDATION // Enable G26 mesh validation
#if ENABLED(UBL_G26_MESH_VALIDATION)
#define MESH_TEST_NOZZLE_SIZE 0.4 // (mm) Diameter of primary nozzle.
#define MESH_TEST_LAYER_HEIGHT 0.2 // (mm) Default layer height for the G26 Mesh Validation Tool.
#define MESH_TEST_HOTEND_TEMP 205.0 // (°C) Default nozzle temperature for the G26 Mesh Validation Tool.
#define MESH_TEST_BED_TEMP 60.0 // (°C) Default bed temperature for the G26 Mesh Validation Tool.
#endif
#define UBL_MESH_EDIT_MOVES_Z // Sophisticated users prefer no movement of nozzle
#define UBL_SAVE_ACTIVE_ON_M500 // Save the currently active mesh in the current slot on M500

@ -26,15 +26,21 @@
#include "MarlinConfig.h"
#if ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(UBL_G26_MESH_VALIDATION)
#if ENABLED(G26_MESH_VALIDATION)
#include "ubl.h"
#include "Marlin.h"
#include "planner.h"
#include "stepper.h"
#include "temperature.h"
#include "ultralcd.h"
#include "gcode.h"
#include "bitmap_flags.h"
#if ENABLED(MESH_BED_LEVELING)
#include "mesh_bed_leveling.h"
#elif ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl.h"
#endif
#define EXTRUSION_MULTIPLIER 1.0
#define RETRACTION_MULTIPLIER 1.0
@ -48,6 +54,9 @@
#error "SIZE_OF_CROSSHAIRS must be less than SIZE_OF_INTERSECTION_CIRCLES."
#endif
#define G26_OK false
#define G26_ERROR true
/**
* G26 Mesh Validation Tool
*
@ -146,35 +155,42 @@
static bool g26_retracted = false; // Track the retracted state of the nozzle so mismatched
// retracts/recovers won't result in a bad state.
float valid_trig_angle(float);
float unified_bed_leveling::g26_extrusion_multiplier,
unified_bed_leveling::g26_retraction_multiplier,
unified_bed_leveling::g26_nozzle,
unified_bed_leveling::g26_filament_diameter,
unified_bed_leveling::g26_layer_height,
unified_bed_leveling::g26_prime_length,
unified_bed_leveling::g26_x_pos,
unified_bed_leveling::g26_y_pos,
unified_bed_leveling::g26_ooze_amount;
int16_t unified_bed_leveling::g26_bed_temp,
unified_bed_leveling::g26_hotend_temp;
int8_t unified_bed_leveling::g26_prime_flag;
bool unified_bed_leveling::g26_continue_with_closest,
unified_bed_leveling::g26_keep_heaters_on;
int16_t unified_bed_leveling::g26_repeats;
void unified_bed_leveling::G26_line_to_destination(const float &feed_rate) {
void G26_line_to_destination(const float &feed_rate) {
const float save_feedrate = feedrate_mm_s;
feedrate_mm_s = feed_rate; // use specified feed rate
prepare_move_to_destination(); // will ultimately call ubl.line_to_destination_cartesian or ubl.prepare_linear_move_to for UBL_DELTA
prepare_move_to_destination(); // will ultimately call ubl.line_to_destination_cartesian for UBL or ubl.prepare_linear_move_to for UBL_DELTA
feedrate_mm_s = save_feedrate; // restore global feed rate
}
static bool exit_from_g26();
static bool parse_G26_parameters();
static mesh_index_pair find_closest_circle_to_print(const float&, const float&);
static bool look_for_lines_to_connect();
static bool turn_on_heaters();
static bool prime_nozzle();
static void retract_filament(const float where[XYZE]);
static void recover_filament(const float where[XYZE]);
static void print_line_from_here_to_there(const float&, const float&, const float&, const float&, const float&, const float&);
static void move_to(const float&, const float&, const float&, const float&);
#if ENABLED(NEWPANEL)
extern bool ubl_lcd_clicked();
#endif
static void move_to(const float where[XYZE], const float &de) { move_to(where[X_AXIS], where[Y_AXIS], where[Z_AXIS], de); }
static float g26_extrusion_multiplier,
g26_retraction_multiplier,
g26_nozzle,
g26_filament_diameter,
g26_prime_length,
g26_x_pos, g26_y_pos,
g26_ooze_amount,
g26_layer_height;
static int16_t g26_bed_temp,
g26_hotend_temp,
g26_repeats;
static int8_t g26_prime_flag;
static bool g26_continue_with_closest, g26_keep_heaters_on;
#if ENABLED(NEWPANEL)
/**
@ -207,7 +223,7 @@
* Used to interactively edit UBL's Mesh by placing the
* nozzle in a problem area and doing a G29 P4 R command.
*/
void unified_bed_leveling::G26() {
void gcode_G26() {
SERIAL_ECHOLNPGM("G26 command started. Waiting for heater(s).");
float tmp, start_angle, end_angle;
int i, xi, yi;
@ -250,7 +266,10 @@
move_to(destination, 0.0);
move_to(destination, g26_ooze_amount);
has_control_of_lcd_panel = true;
#if ENABLED(ULTRA_LCD)
lcd_external_control = true;
#endif
//debug_current_and_destination(PSTR("Starting G26 Mesh Validation Pattern."));
/**
@ -269,8 +288,8 @@
: find_closest_circle_to_print(g26_x_pos, g26_y_pos); // Find the closest Mesh Intersection to where we are now.
if (location.x_index >= 0 && location.y_index >= 0) {
const float circle_x = mesh_index_to_xpos(location.x_index),
circle_y = mesh_index_to_ypos(location.y_index);
const float circle_x = _GET_MESH_X(location.x_index),
circle_y = _GET_MESH_Y(location.y_index);
// If this mesh location is outside the printable_radius, skip it.
@ -373,7 +392,9 @@
move_to(destination, 0); // Move back to the starting position
//debug_current_and_destination(PSTR("done doing X/Y move."));
has_control_of_lcd_panel = false; // Give back control of the LCD Panel!
#if ENABLED(ULTRA_LCD)
lcd_external_control = false; // Give back control of the LCD Panel!
#endif
if (!g26_keep_heaters_on) {
#if HAS_TEMP_BED
@ -389,7 +410,7 @@
return d;
}
mesh_index_pair unified_bed_leveling::find_closest_circle_to_print(const float &X, const float &Y) {
mesh_index_pair find_closest_circle_to_print(const float &X, const float &Y) {
float closest = 99999.99;
mesh_index_pair return_val;
@ -398,8 +419,8 @@
for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++) {
if (!is_bit_set(circle_flags, i, j)) {
const float mx = mesh_index_to_xpos(i), // We found a circle that needs to be printed
my = mesh_index_to_ypos(j);
const float mx = _GET_MESH_X(i), // We found a circle that needs to be printed
my = _GET_MESH_Y(j);
// Get the distance to this intersection
float f = HYPOT(X - mx, Y - my);
@ -427,7 +448,7 @@
return return_val;
}
bool unified_bed_leveling::look_for_lines_to_connect() {
bool look_for_lines_to_connect() {
float sx, sy, ex, ey;
for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) {
@ -447,11 +468,11 @@
// We found two circles that need a horizontal line to connect them
// Print it!
//
sx = mesh_index_to_xpos( i ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge
ex = mesh_index_to_xpos(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge
sx = _GET_MESH_X( i ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // right edge
ex = _GET_MESH_X(i + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // left edge
sx = constrain(sx, X_MIN_POS + 1, X_MAX_POS - 1);
sy = ey = constrain(mesh_index_to_ypos(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
sy = ey = constrain(_GET_MESH_Y(j), Y_MIN_POS + 1, Y_MAX_POS - 1);
ex = constrain(ex, X_MIN_POS + 1, X_MAX_POS - 1);
if (position_is_reachable(sx, sy) && position_is_reachable(ex, ey)) {
@ -480,10 +501,10 @@
// We found two circles that need a vertical line to connect them
// Print it!
//
sy = mesh_index_to_ypos( j ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge
ey = mesh_index_to_ypos(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge
sy = _GET_MESH_Y( j ) + (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // top edge
ey = _GET_MESH_Y(j + 1) - (SIZE_OF_INTERSECTION_CIRCLES - (SIZE_OF_CROSSHAIRS)); // bottom edge
sx = ex = constrain(mesh_index_to_xpos(i), X_MIN_POS + 1, X_MAX_POS - 1);
sx = ex = constrain(_GET_MESH_X(i), X_MIN_POS + 1, X_MAX_POS - 1);
sy = constrain(sy, Y_MIN_POS + 1, Y_MAX_POS - 1);
ey = constrain(ey, Y_MIN_POS + 1, Y_MAX_POS - 1);
@ -496,7 +517,10 @@
SERIAL_ECHOPAIR(", ey=", ey);
SERIAL_CHAR(')');
SERIAL_EOL();
debug_current_and_destination(PSTR("Connecting vertical line."));
#if ENABLED(AUTO_BED_LEVELING_UBL)
debug_current_and_destination(PSTR("Connecting vertical line."));
#endif
}
print_line_from_here_to_there(sx, sy, g26_layer_height, ex, ey, g26_layer_height);
}
@ -510,7 +534,7 @@
return false;
}
void unified_bed_leveling::move_to(const float &x, const float &y, const float &z, const float &e_delta) {
void move_to(const float &x, const float &y, const float &z, const float &e_delta) {
float feed_value;
static float last_z = -999.99;
@ -548,14 +572,14 @@
}
void unified_bed_leveling::retract_filament(const float where[XYZE]) {
void retract_filament(const float where[XYZE]) {
if (!g26_retracted) { // Only retract if we are not already retracted!
g26_retracted = true;
move_to(where, -1.0 * g26_retraction_multiplier);
}
}
void unified_bed_leveling::recover_filament(const float where[XYZE]) {
void recover_filament(const float where[XYZE]) {
if (g26_retracted) { // Only un-retract if we are retracted.
move_to(where, 1.2 * g26_retraction_multiplier);
g26_retracted = false;
@ -577,7 +601,7 @@
* segment of a 'circle'. The time this requires is very short and is easily saved by the other
* cases where the optimization comes into play.
*/
void unified_bed_leveling::print_line_from_here_to_there(const float &sx, const float &sy, const float &sz, const float &ex, const float &ey, const float &ez) {
void print_line_from_here_to_there(const float &sx, const float &sy, const float &sz, const float &ex, const float &ey, const float &ez) {
const float dx_s = current_position[X_AXIS] - sx, // find our distance from the start of the actual line segment
dy_s = current_position[Y_AXIS] - sy,
dist_start = HYPOT2(dx_s, dy_s), // We don't need to do a sqrt(), we can compare the distance^2
@ -615,7 +639,7 @@
* parameters it made sense to turn them into static globals and get
* this code out of sight of the main routine.
*/
bool unified_bed_leveling::parse_G26_parameters() {
bool parse_G26_parameters() {
g26_extrusion_multiplier = EXTRUSION_MULTIPLIER;
g26_retraction_multiplier = RETRACTION_MULTIPLIER;
@ -635,7 +659,7 @@
g26_bed_temp = parser.value_celsius();
if (!WITHIN(g26_bed_temp, 15, 140)) {
SERIAL_PROTOCOLLNPGM("?Specified bed temperature not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
@ -643,7 +667,7 @@
g26_layer_height = parser.value_linear_units();
if (!WITHIN(g26_layer_height, 0.0, 2.0)) {
SERIAL_PROTOCOLLNPGM("?Specified layer height not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
@ -652,12 +676,12 @@
g26_retraction_multiplier = parser.value_float();
if (!WITHIN(g26_retraction_multiplier, 0.05, 15.0)) {
SERIAL_PROTOCOLLNPGM("?Specified Retraction Multiplier not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
else {
SERIAL_PROTOCOLLNPGM("?Retraction Multiplier must be specified.");
return UBL_ERR;
return G26_ERROR;
}
}
@ -665,7 +689,7 @@
g26_nozzle = parser.value_float();
if (!WITHIN(g26_nozzle, 0.1, 1.0)) {
SERIAL_PROTOCOLLNPGM("?Specified nozzle size not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
@ -675,7 +699,7 @@
g26_prime_flag = -1;
#else
SERIAL_PROTOCOLLNPGM("?Prime length must be specified when not using an LCD.");
return UBL_ERR;
return G26_ERROR;
#endif
}
else {
@ -683,7 +707,7 @@
g26_prime_length = parser.value_linear_units();
if (!WITHIN(g26_prime_length, 0.0, 25.0)) {
SERIAL_PROTOCOLLNPGM("?Specified prime length not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
}
@ -692,7 +716,7 @@
g26_filament_diameter = parser.value_linear_units();
if (!WITHIN(g26_filament_diameter, 1.0, 4.0)) {
SERIAL_PROTOCOLLNPGM("?Specified filament size not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
g26_extrusion_multiplier *= sq(1.75) / sq(g26_filament_diameter); // If we aren't using 1.75mm filament, we need to
@ -705,7 +729,7 @@
g26_hotend_temp = parser.value_celsius();
if (!WITHIN(g26_hotend_temp, 165, 280)) {
SERIAL_PROTOCOLLNPGM("?Specified nozzle temperature not plausible.");
return UBL_ERR;
return G26_ERROR;
}
}
@ -720,21 +744,21 @@
#else
if (!parser.seen('R')) {
SERIAL_PROTOCOLLNPGM("?(R)epeat must be specified when not using an LCD.");
return UBL_ERR;
return G26_ERROR;
}
else
g26_repeats = parser.has_value() ? parser.value_int() : GRID_MAX_POINTS + 1;
#endif
if (g26_repeats < 1) {
SERIAL_PROTOCOLLNPGM("?(R)epeat value not plausible; must be at least 1.");
return UBL_ERR;
return G26_ERROR;
}
g26_x_pos = parser.seenval('X') ? RAW_X_POSITION(parser.value_linear_units()) : current_position[X_AXIS];
g26_y_pos = parser.seenval('Y') ? RAW_Y_POSITION(parser.value_linear_units()) : current_position[Y_AXIS];
if (!position_is_reachable(g26_x_pos, g26_y_pos)) {
SERIAL_PROTOCOLLNPGM("?Specified X,Y coordinate out of bounds.");
return UBL_ERR;
return G26_ERROR;
}
/**
@ -742,14 +766,14 @@
*/
set_bed_leveling_enabled(!parser.seen('D'));
return UBL_OK;
return G26_OK;
}
#if ENABLED(NEWPANEL)
bool unified_bed_leveling::exit_from_g26() {
bool exit_from_g26() {
lcd_setstatusPGM(PSTR("Leaving G26"), -1);
while (ubl_lcd_clicked()) idle();
return UBL_ERR;
return G26_ERROR;
}
#endif
@ -757,15 +781,15 @@
* Turn on the bed and nozzle heat and
* wait for them to get up to temperature.
*/
bool unified_bed_leveling::turn_on_heaters() {
bool turn_on_heaters() {
millis_t next = millis() + 5000UL;
#if HAS_TEMP_BED
#if ENABLED(ULTRA_LCD)
if (g26_bed_temp > 25) {
lcd_setstatusPGM(PSTR("G26 Heating Bed."), 99);
lcd_quick_feedback();
lcd_external_control = true;
#endif
has_control_of_lcd_panel = true;
thermalManager.setTargetBed(g26_bed_temp);
while (abs(thermalManager.degBed() - g26_bed_temp) > 3) {
@ -808,20 +832,20 @@
lcd_quick_feedback();
#endif
return UBL_OK;
return G26_OK;
}
/**
* Prime the nozzle if needed. Return true on error.
*/
bool unified_bed_leveling::prime_nozzle() {
bool prime_nozzle() {
#if ENABLED(NEWPANEL)
float Total_Prime = 0.0;
if (g26_prime_flag == -1) { // The user wants to control how much filament gets purged
has_control_of_lcd_panel = true;
lcd_external_control = true;
lcd_setstatusPGM(PSTR("User-Controlled Prime"), 99);
chirp_at_user();
@ -834,7 +858,7 @@
destination[E_AXIS] += 0.25;
#ifdef PREVENT_LENGTHY_EXTRUDE
Total_Prime += 0.25;
if (Total_Prime >= EXTRUDE_MAXLENGTH) return UBL_ERR;
if (Total_Prime >= EXTRUDE_MAXLENGTH) return G26_ERROR;
#endif
G26_line_to_destination(planner.max_feedrate_mm_s[E_AXIS] / 15.0);
@ -853,10 +877,8 @@
// So... We cheat to get a message up.
lcd_setstatusPGM(PSTR("Done Priming"), 99);
lcd_quick_feedback();
lcd_external_control = false;
#endif
has_control_of_lcd_panel = false;
}
else {
#else
@ -874,7 +896,7 @@
retract_filament(destination);
}
return UBL_OK;
return G26_OK;
}
#endif // AUTO_BED_LEVELING_UBL && UBL_G26_MESH_VALIDATION
#endif // G26_MESH_VALIDATION

@ -311,6 +311,23 @@ void report_current_position();
void forward_kinematics_SCARA(const float &a, const float &b);
#endif
#if ENABLED(G26_MESH_VALIDATION)
extern bool g26_debug_flag;
#elif ENABLED(AUTO_BED_LEVELING_UBL)
constexpr bool g26_debug_flag = false;
#endif
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
#define _GET_MESH_X(I) bilinear_start[X_AXIS] + I * bilinear_grid_spacing[X_AXIS]
#define _GET_MESH_Y(J) bilinear_start[Y_AXIS] + J * bilinear_grid_spacing[Y_AXIS]
#elif ENABLED(AUTO_BED_LEVELING_UBL)
#define _GET_MESH_X(I) ubl.mesh_index_to_xpos(I)
#define _GET_MESH_Y(J) ubl.mesh_index_to_ypos(J)
#elif ENABLED(MESH_BED_LEVELING)
#define _GET_MESH_X(I) mbl.index_to_xpos[I]
#define _GET_MESH_Y(J) mbl.index_to_ypos[J]
#endif
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
extern int bilinear_grid_spacing[2], bilinear_start[2];
extern float bilinear_grid_factor[2],

@ -59,7 +59,7 @@
* G19 - Select Plane YZ (Requires CNC_WORKSPACE_PLANES)
* G20 - Set input units to inches (Requires INCH_MODE_SUPPORT)
* G21 - Set input units to millimeters (Requires INCH_MODE_SUPPORT)
* G26 - Mesh Validation Pattern (Requires UBL_G26_MESH_VALIDATION)
* G26 - Mesh Validation Pattern (Requires G26_MESH_VALIDATION)
* G27 - Park Nozzle (Requires NOZZLE_PARK_FEATURE)
* G28 - Home one or more axes
* G29 - Start or continue the bed leveling probe procedure (Requires bed leveling)
@ -326,6 +326,11 @@
void M100_dump_routine(const char * const title, const char *start, const char *end);
#endif
#if ENABLED(G26_MESH_VALIDATION)
bool g26_debug_flag; // =false
void gcode_G26();
#endif
#if ENABLED(SDSUPPORT)
CardReader card;
#endif
@ -6197,17 +6202,6 @@ void home_all_axes() { gcode_G28(true); }
return;
}
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
#define _GET_MESH_X(I) bilinear_start[X_AXIS] + I * bilinear_grid_spacing[X_AXIS]
#define _GET_MESH_Y(J) bilinear_start[Y_AXIS] + J * bilinear_grid_spacing[Y_AXIS]
#elif ENABLED(AUTO_BED_LEVELING_UBL)
#define _GET_MESH_X(I) ubl.mesh_index_to_xpos(I)
#define _GET_MESH_Y(J) ubl.mesh_index_to_ypos(J)
#elif ENABLED(MESH_BED_LEVELING)
#define _GET_MESH_X(I) mbl.index_to_xpos[I]
#define _GET_MESH_Y(J) mbl.index_to_ypos[J]
#endif
set_destination_from_current();
if (hasI) destination[X_AXIS] = _GET_MESH_X(ix);
if (hasJ) destination[Y_AXIS] = _GET_MESH_Y(iy);
@ -7567,15 +7561,15 @@ inline void gcode_M42() {
#endif // Z_MIN_PROBE_REPEATABILITY_TEST
#if ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(UBL_G26_MESH_VALIDATION)
#if ENABLED(G26_MESH_VALIDATION)
inline void gcode_M49() {
ubl.g26_debug_flag ^= true;
SERIAL_PROTOCOLPGM("UBL Debug Flag turned ");
serialprintPGM(ubl.g26_debug_flag ? PSTR("on.") : PSTR("off."));
g26_debug_flag ^= true;
SERIAL_PROTOCOLPGM("G26 Debug ");
serialprintPGM(g26_debug_flag ? PSTR("on.") : PSTR("off."));
}
#endif // AUTO_BED_LEVELING_UBL && UBL_G26_MESH_VALIDATION
#endif // G26_MESH_VALIDATION
#if ENABLED(ULTRA_LCD) && ENABLED(LCD_SET_PROGRESS_MANUALLY)
/**
@ -11295,11 +11289,11 @@ void process_parsed_command() {
break;
#endif // INCH_MODE_SUPPORT
#if ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(UBL_G26_MESH_VALIDATION)
#if ENABLED(G26_MESH_VALIDATION)
case 26: // G26: Mesh Validation Pattern generation
gcode_G26();
break;
#endif // AUTO_BED_LEVELING_UBL
#endif // G26_MESH_VALIDATION
#if ENABLED(NOZZLE_PARK_FEATURE)
case 27: // G27: Nozzle Park
@ -11459,11 +11453,11 @@ void process_parsed_command() {
break;
#endif // Z_MIN_PROBE_REPEATABILITY_TEST
#if ENABLED(AUTO_BED_LEVELING_UBL) && ENABLED(UBL_G26_MESH_VALIDATION)
#if ENABLED(G26_MESH_VALIDATION)
case 49: // M49: Turn on or off G26 debug flag for verbose output
gcode_M49();
break;
#endif // AUTO_BED_LEVELING_UBL && UBL_G26_MESH_VALIDATION
#endif // G26_MESH_VALIDATION
#if ENABLED(ULTRA_LCD) && ENABLED(LCD_SET_PROGRESS_MANUALLY)
case 73: // M73: Set print progress percentage

@ -180,10 +180,12 @@
#error "MESH_NUM_[XY]_POINTS is now GRID_MAX_POINTS_[XY]. Please update your configuration."
#elif defined(UBL_MESH_NUM_X_POINTS) || defined(UBL_MESH_NUM_Y_POINTS)
#error "UBL_MESH_NUM_[XY]_POINTS is now GRID_MAX_POINTS_[XY]. Please update your configuration."
#elif defined(UBL_G26_MESH_VALIDATION)
#error "UBL_G26_MESH_VALIDATION is now G26_MESH_VALIDATION. Please update your configuration."
#elif defined(UBL_MESH_EDIT_ENABLED)
#error "UBL_MESH_EDIT_ENABLED is now UBL_G26_MESH_VALIDATION. Please update your configuration."
#error "UBL_MESH_EDIT_ENABLED is now G26_MESH_VALIDATION. Please update your configuration."
#elif defined(UBL_MESH_EDITING)
#error "UBL_MESH_EDITING is now UBL_G26_MESH_VALIDATION. Please update your configuration."
#error "UBL_MESH_EDITING is now G26_MESH_VALIDATION. Please update your configuration."
#elif defined(BLTOUCH_HEATERS_OFF)
#error "BLTOUCH_HEATERS_OFF is now PROBING_HEATERS_OFF. Please update your configuration."
#elif defined(BEEPER)
@ -804,6 +806,10 @@ static_assert(1 >= 0
#endif
#if !HAS_MESH && ENABLED(G26_MESH_VALIDATION)
#error "G26_MESH_VALIDATION requires MESH_BED_LEVELING, AUTO_BED_LEVELING_BILINEAR, or AUTO_BED_LEVELING_UBL."
#endif
/**
* LCD_BED_LEVELING requirements
*/

@ -0,0 +1,38 @@
/**
* Marlin 3D Printer Firmware
* Copyright (C) 2016, 2017 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _BITMAP_FLAGS_H_
#define _BITMAP_FLAGS_H_
#include "macros.h"
/**
* These support functions allow the use of large bit arrays of flags that take very
* little RAM. Currently they are limited to being 16x16 in size. Changing the declaration
* to unsigned long will allow us to go to 32x32 if higher resolution meshes are needed
* in the future.
*/
FORCE_INLINE void bit_clear(uint16_t bits[16], const uint8_t x, const uint8_t y) { CBI(bits[y], x); }
FORCE_INLINE void bit_set(uint16_t bits[16], const uint8_t x, const uint8_t y) { SBI(bits[y], x); }
FORCE_INLINE bool is_bit_set(uint16_t bits[16], const uint8_t x, const uint8_t y) { return TEST(bits[y], x); }
#endif // _BITMAP_FLAGS_H_

@ -58,6 +58,7 @@
*
*/
#include "MarlinConfig.h"
#include "planner.h"
#include "stepper.h"
#include "temperature.h"

@ -25,4 +25,9 @@
typedef unsigned long millis_t;
typedef struct {
int8_t x_index, y_index;
float distance; // When populated, the distance from the search location
} mesh_index_pair;
#endif

@ -30,16 +30,6 @@
#include "temperature.h"
#include "planner.h"
/**
* These support functions allow the use of large bit arrays of flags that take very
* little RAM. Currently they are limited to being 16x16 in size. Changing the declaration
* to unsigned long will allow us to go to 32x32 if higher resolution Mesh's are needed
* in the future.
*/
void bit_clear(uint16_t bits[16], const uint8_t x, const uint8_t y) { CBI(bits[y], x); }
void bit_set(uint16_t bits[16], const uint8_t x, const uint8_t y) { SBI(bits[y], x); }
bool is_bit_set(uint16_t bits[16], const uint8_t x, const uint8_t y) { return TEST(bits[y], x); }
uint8_t ubl_cnt = 0;
void unified_bed_leveling::echo_name() { SERIAL_PROTOCOLPGM("Unified Bed Leveling"); }
@ -70,9 +60,6 @@
constexpr float unified_bed_leveling::_mesh_index_to_xpos[16],
unified_bed_leveling::_mesh_index_to_ypos[16];
bool unified_bed_leveling::g26_debug_flag = false,
unified_bed_leveling::has_control_of_lcd_panel = false;
#if ENABLED(ULTIPANEL)
bool unified_bed_leveling::lcd_map_control = false;
#endif

@ -39,17 +39,6 @@
#define USE_NOZZLE_AS_REFERENCE 0
#define USE_PROBE_AS_REFERENCE 1
typedef struct {
int8_t x_index, y_index;
float distance; // When populated, the distance from the search location
} mesh_index_pair;
// ubl.cpp
void bit_clear(uint16_t bits[16], const uint8_t x, const uint8_t y);
void bit_set(uint16_t bits[16], const uint8_t x, const uint8_t y);
bool is_bit_set(uint16_t bits[16], const uint8_t x, const uint8_t y);
// ubl_motion.cpp
void debug_current_and_destination(const char * const title);
@ -93,22 +82,6 @@
static int g29_grid_size;
#endif
#if ENABLED(UBL_G26_MESH_VALIDATION)
static float g26_extrusion_multiplier,
g26_retraction_multiplier,
g26_nozzle,
g26_filament_diameter,
g26_prime_length,
g26_x_pos, g26_y_pos,
g26_ooze_amount,
g26_layer_height;
static int16_t g26_bed_temp,
g26_hotend_temp,
g26_repeats;
static int8_t g26_prime_flag;
static bool g26_continue_with_closest, g26_keep_heaters_on;
#endif
static float measure_point_with_encoder();
static float measure_business_card_thickness(float);
static bool g29_parameter_parsing();
@ -125,21 +98,6 @@
static bool smart_fill_one(const uint8_t x, const uint8_t y, const int8_t xdir, const int8_t ydir);
static void smart_fill_mesh();
#if ENABLED(UBL_G26_MESH_VALIDATION)
static bool exit_from_g26();
static bool parse_G26_parameters();
static void G26_line_to_destination(const float &feed_rate);
static mesh_index_pair find_closest_circle_to_print(const float&, const float&);
static bool look_for_lines_to_connect();
static bool turn_on_heaters();
static bool prime_nozzle();
static void retract_filament(const float where[XYZE]);
static void recover_filament(const float where[XYZE]);
static void print_line_from_here_to_there(const float&, const float&, const float&, const float&, const float&, const float&);
static void move_to(const float&, const float&, const float&, const float&);
inline static void move_to(const float where[XYZE], const float &de) { move_to(where[X_AXIS], where[Y_AXIS], where[Z_AXIS], de); }
#endif
public:
static void echo_name();
@ -147,8 +105,8 @@
static void save_ubl_active_state_and_disable();
static void restore_ubl_active_state_and_leave();
static void display_map(const int);
static mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const float&, const float&, const bool, uint16_t[16]);
static mesh_index_pair find_furthest_invalid_mesh_point();
static mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const float&, const float&, const bool, uint16_t[16]);
static mesh_index_pair find_furthest_invalid_mesh_point();
static void reset();
static void invalidate();
static void set_all_mesh_points_to_value(const float);
@ -156,11 +114,6 @@
static void G29() _O0; // O0 for no optimization
static void smart_fill_wlsf(const float &) _O2; // O2 gives smaller code than Os on A2560
#if ENABLED(UBL_G26_MESH_VALIDATION)
static void G26();
#endif
static int8_t storage_slot;
static float z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
@ -189,8 +142,6 @@
MESH_MIN_Y + 14 * (MESH_Y_DIST), MESH_MIN_Y + 15 * (MESH_Y_DIST)
};
static bool g26_debug_flag, has_control_of_lcd_panel;
#if ENABLED(ULTIPANEL)
static bool lcd_map_control;
#endif
@ -390,15 +341,10 @@
|| isnan(z_values[0][0])
);
}
}; // class unified_bed_leveling
extern unified_bed_leveling ubl;
#if ENABLED(UBL_G26_MESH_VALIDATION)
FORCE_INLINE void gcode_G26() { ubl.G26(); }
#endif
FORCE_INLINE void gcode_G29() { ubl.G29(); }
#endif // AUTO_BED_LEVELING_UBL

@ -32,6 +32,7 @@
#include "stepper.h"
#include "planner.h"
#include "gcode.h"
#include "bitmap_flags.h"
#include <math.h>
#include "least_squares_fit.h"
@ -46,6 +47,7 @@
float lcd_mesh_edit();
void lcd_z_offset_edit_setup(float);
extern void _lcd_ubl_output_map_lcd();
extern bool ubl_lcd_clicked();
float lcd_z_offset_edit();
#endif
@ -676,8 +678,7 @@
lcd_reset_alert_level();
LCD_MESSAGEPGM("");
lcd_quick_feedback();
has_control_of_lcd_panel = false;
lcd_external_control = false;
#endif
return;
@ -736,7 +737,10 @@
void unified_bed_leveling::probe_entire_mesh(const float &rx, const float &ry, const bool do_ubl_mesh_map, const bool stow_probe, bool close_or_far) {
mesh_index_pair location;
has_control_of_lcd_panel = true;
#if ENABLED(NEWPANEL)
lcd_external_control = true;
#endif
save_ubl_active_state_and_disable(); // we don't do bed level correction because we want the raw data when we probe
DEPLOY_PROBE();
@ -751,7 +755,7 @@
lcd_quick_feedback();
STOW_PROBE();
while (ubl_lcd_clicked()) idle();
has_control_of_lcd_panel = false;
lcd_external_control = false;
restore_ubl_active_state_and_leave();
safe_delay(50); // Debounce the Encoder wheel
return;
@ -909,7 +913,7 @@
static void echo_and_take_a_measurement() { SERIAL_PROTOCOLLNPGM(" and take a measurement."); }
float unified_bed_leveling::measure_business_card_thickness(float in_height) {
has_control_of_lcd_panel = true;
lcd_external_control = true;
save_ubl_active_state_and_disable(); // Disable bed level correction for probing
do_blocking_move_to(0.5 * (MESH_MAX_X - (MESH_MIN_X)), 0.5 * (MESH_MAX_Y - (MESH_MIN_Y)), in_height);
@ -943,7 +947,7 @@
in_height = current_position[Z_AXIS]; // do manual probing at lower height
has_control_of_lcd_panel = false;
lcd_external_control = false;
restore_ubl_active_state_and_leave();
@ -952,7 +956,7 @@
void unified_bed_leveling::manually_probe_remaining_mesh(const float &rx, const float &ry, const float &z_clearance, const float &thick, const bool do_ubl_mesh_map) {
has_control_of_lcd_panel = true;
lcd_external_control = true;
save_ubl_active_state_and_disable(); // we don't do bed level correction because we want the raw data when we probe
do_blocking_move_to(rx, ry, Z_CLEARANCE_BETWEEN_PROBES);
@ -976,7 +980,7 @@
do_blocking_move_to_z(z_clearance);
KEEPALIVE_STATE(PAUSED_FOR_USER);
has_control_of_lcd_panel = true;
lcd_external_control = true;
if (do_ubl_mesh_map) display_map(g29_map_type); // show user where we're probing
@ -1008,7 +1012,7 @@
#if ENABLED(NEWPANEL)
lcd_quick_feedback();
while (ubl_lcd_clicked()) idle();
has_control_of_lcd_panel = false;
lcd_external_control = false;
#endif
KEEPALIVE_STATE(IN_HANDLER);
@ -1510,7 +1514,7 @@
new_z = FLOOR(new_z * 1000.0) * 0.001; // Chop off digits after the 1000ths place
KEEPALIVE_STATE(PAUSED_FOR_USER);
has_control_of_lcd_panel = true;
lcd_external_control = true;
if (do_ubl_mesh_map) display_map(g29_map_type); // show the user which point is being adjusted
@ -1531,7 +1535,7 @@
// The technique used here generates a race condition for the encoder click.
// It could get detected in lcd_mesh_edit (actually _lcd_mesh_fine_tune) or here.
// Let's work on specifying a proper API for the LCD ASAP, OK?
has_control_of_lcd_panel = true;
lcd_external_control = true;
// this sequence to detect an ubl_lcd_clicked() debounce it and leave if it is
// a Press and Hold is repeated in a lot of places (including G26_Mesh_Validation.cpp). This
@ -1560,7 +1564,7 @@
FINE_TUNE_EXIT:
has_control_of_lcd_panel = false;
lcd_external_control = false;
KEEPALIVE_STATE(IN_HANDLER);
if (do_ubl_mesh_map) display_map(g29_map_type);

@ -38,23 +38,23 @@
extern void set_current_from_destination();
#endif
#if ENABLED(DELTA)
#if ENABLED(DELTA)
extern float delta[ABC];
extern float delta[ABC];
extern float delta_endstop_adj[ABC],
delta_radius,
delta_tower_angle_trim[ABC],
delta_tower[ABC][2],
delta_diagonal_rod,
delta_calibration_radius,
delta_diagonal_rod_2_tower[ABC],
delta_segments_per_second,
delta_clip_start_height;
extern float delta_endstop_adj[ABC],
delta_radius,
delta_tower_angle_trim[ABC],
delta_tower[ABC][2],
delta_diagonal_rod,
delta_calibration_radius,
delta_diagonal_rod_2_tower[ABC],
delta_segments_per_second,
delta_clip_start_height;
extern float delta_safe_distance_from_top();
extern float delta_safe_distance_from_top();
#endif
#endif
static void debug_echo_axis(const AxisEnum axis) {
@ -68,7 +68,7 @@
// if the title message starts with a '!' it is so important, we are going to
// ignore the status of the g26_debug_flag
if (*title != '!' && !ubl.g26_debug_flag) return;
if (*title != '!' && !g26_debug_flag) return;
const float de = destination[E_AXIS] - current_position[E_AXIS];

@ -57,6 +57,10 @@
extern void mesh_probing_done();
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
bool lcd_external_control;
#endif
// Initialized by settings.load()
int16_t lcd_preheat_hotend_temp[2], lcd_preheat_bed_temp[2], lcd_preheat_fan_speed[2];
@ -4603,8 +4607,8 @@ void lcd_update() {
lcd_buttons_update();
#if ENABLED(AUTO_BED_LEVELING_UBL)
const bool UBL_CONDITION = !ubl.has_control_of_lcd_panel;
#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
const bool UBL_CONDITION = lcd_external_control;
#else
constexpr bool UBL_CONDITION = true;
#endif
@ -5071,7 +5075,7 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; }
case encrot3: ENCODER_SPIN(encrot2, encrot0); break;
}
#if ENABLED(AUTO_BED_LEVELING_UBL)
if (ubl.has_control_of_lcd_panel) {
if (lcd_external_control) {
ubl.encoder_diff = encoderDiff; // Make the encoder's rotation available to G29's Mesh Editor
encoderDiff = 0; // We are going to lie to the LCD Panel and claim the encoder
// knob has not turned.
@ -5087,8 +5091,7 @@ void lcd_reset_alert_level() { lcd_status_message_level = 0; }
bool lcd_detected() { return true; }
#endif
#if ENABLED(AUTO_BED_LEVELING_UBL)
#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
void chirp_at_user() {
#if ENABLED(LCD_USE_I2C_BUZZER)
lcd.buzz(LCD_FEEDBACK_FREQUENCY_DURATION_MS, LCD_FEEDBACK_FREQUENCY_HZ);

@ -27,6 +27,10 @@
#if ENABLED(ULTRA_LCD)
#if ENABLED(AUTO_BED_LEVELING_UBL) || ENABLED(G26_MESH_VALIDATION)
extern bool lcd_external_control;
#endif
#define BUTTON_EXISTS(BN) (defined(BTN_## BN) && BTN_## BN >= 0)
#define BUTTON_PRESSED(BN) !READ(BTN_## BN)

Loading…
Cancel
Save