From 249c794ee35d22f64d6e8d0e939be650bf743b86 Mon Sep 17 00:00:00 2001 From: Marcio T Date: Thu, 11 Mar 2021 10:09:00 -0700 Subject: [PATCH 1/7] Implemented Hilbert curve probe point ordering --- Marlin/src/feature/bedlevel/ubl/ubl.h | 5 ++ Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 53 +++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index d5da43a6a26a..db16067f5696 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -98,6 +98,11 @@ class unified_bed_leveling { static void display_map(const int) _O0; static mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const xy_pos_t&, const bool=false, MeshFlags *done_flags=nullptr) _O0; static mesh_index_pair find_furthest_invalid_mesh_point() _O0; + #if ENABLED(UBL_HILBERT_CURVE) + static void check_if_missing(mesh_index_pair &pt, int x, int y) _O0; + static void hilbert(mesh_index_pair &pt, float x, float y, float xi, float xj, float yi, float yj, int n) _O0; + static mesh_index_pair next_point_in_grid() _O0; + #endif static void reset(); static void invalidate(); static void set_all_mesh_points_to_value(const float value); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 8c70feb6616a..602b962e03b9 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -759,7 +759,11 @@ void unified_bed_leveling::shift_mesh_height() { best = do_furthest ? find_furthest_invalid_mesh_point() + #if ENABLED(UBL_HILBERT_CURVE) + : next_point_in_grid(); + #else : find_closest_mesh_point_of_type(INVALID, nearby, true); + #endif if (best.pos.x >= 0) { // mesh point found and is reachable by probe TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::PROBE_START)); @@ -1298,6 +1302,55 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh return closest; } +#if ENABLED(UBL_HILBERT_CURVE) + void unified_bed_leveling::hilbert(mesh_index_pair &pt, float x, float y, float xi, float xj, float yi, float yj, int n) { + /* Hilbert space filling curve implementation + * + * x and y are the coordinates of the bottom left corner + * xi & xj are the i & j components of the unit x vector of the frame + * similarly yi and yj + * + * From: http://www.fundza.com/algorithmic/space_filling/hilbert/basics/index.html + */ + if (n <= 0) { + check_if_missing(pt, x + (xi + yi)/2, y + (xj + yj)/2); + } else { + hilbert(pt, x, y, yi/2, yj/2, xi/2, xj/2, n-1); + hilbert(pt, x+xi/2, y+xj/2, xi/2, xj/2, yi/2, yj/2, n-1); + hilbert(pt, x+xi/2+yi/2, y+xj/2+yj/2, xi/2, xj/2, yi/2, yj/2, n-1); + hilbert(pt, x+xi/2+yi, y+xj/2+yj, -yi/2, -yj/2, -xi/2, -xj/2, n-1); + } + } + + constexpr size_t log2(size_t n) { + return (n > 1) ? 1 + log2(n >> 1) : 0; + } + + constexpr size_t order(size_t n) { + return size_t(log2(n-1))+1; + } + + void unified_bed_leveling::check_if_missing(mesh_index_pair &pt, int x, int y) { + if (pt.distance < 0 && + x < GRID_MAX_POINTS_X && + y < GRID_MAX_POINTS_Y && + isnan(z_values[x][y]) && + probe.can_reach(mesh_index_to_xpos(x), mesh_index_to_ypos(y))) { + pt.pos.set(x, y); + pt.distance = 1; + } + } + + mesh_index_pair unified_bed_leveling::next_point_in_grid() { + mesh_index_pair pt; + pt.invalidate(); + pt.distance = -99999.9f; + constexpr int n = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); + hilbert(pt, 0, 0, 1 << n, 0, 0, 1 << n, n); + return pt; + } +#endif + /** * 'Smart Fill': Scan from the outward edges of the mesh towards the center. * If an invalid location is found, use the next two points (if valid) to From fbfdf76d992ff7ee5b5eb584d503b6da4c65d375 Mon Sep 17 00:00:00 2001 From: Marcio T Date: Mon, 22 Mar 2021 13:24:31 -0600 Subject: [PATCH 2/7] Use fixed point math when generating Hilbert curve - Reduce stack memory consumpution four-fold, while supporting meshes up to 64x64 --- Marlin/src/feature/bedlevel/ubl/ubl.h | 6 +-- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 56 ++++++++++----------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.h b/Marlin/src/feature/bedlevel/ubl/ubl.h index db16067f5696..0c4667eed876 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.h +++ b/Marlin/src/feature/bedlevel/ubl/ubl.h @@ -99,9 +99,9 @@ class unified_bed_leveling { static mesh_index_pair find_closest_mesh_point_of_type(const MeshPointType, const xy_pos_t&, const bool=false, MeshFlags *done_flags=nullptr) _O0; static mesh_index_pair find_furthest_invalid_mesh_point() _O0; #if ENABLED(UBL_HILBERT_CURVE) - static void check_if_missing(mesh_index_pair &pt, int x, int y) _O0; - static void hilbert(mesh_index_pair &pt, float x, float y, float xi, float xj, float yi, float yj, int n) _O0; - static mesh_index_pair next_point_in_grid() _O0; + static void check_if_missing(mesh_index_pair &pt, int x, int y); + static void hilbert(mesh_index_pair &pt, int8_t x, int8_t y, int8_t xi, int8_t xj, int8_t yi, int8_t yj, uint8_t n); + static mesh_index_pair find_next_mesh_point(); #endif static void reset(); static void invalidate(); diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 602b962e03b9..ced245dec2ad 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -1303,32 +1303,29 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh } #if ENABLED(UBL_HILBERT_CURVE) - void unified_bed_leveling::hilbert(mesh_index_pair &pt, float x, float y, float xi, float xj, float yi, float yj, int n) { - /* Hilbert space filling curve implementation - * - * x and y are the coordinates of the bottom left corner - * xi & xj are the i & j components of the unit x vector of the frame - * similarly yi and yj - * - * From: http://www.fundza.com/algorithmic/space_filling/hilbert/basics/index.html - */ - if (n <= 0) { - check_if_missing(pt, x + (xi + yi)/2, y + (xj + yj)/2); - } else { - hilbert(pt, x, y, yi/2, yj/2, xi/2, xj/2, n-1); - hilbert(pt, x+xi/2, y+xj/2, xi/2, xj/2, yi/2, yj/2, n-1); - hilbert(pt, x+xi/2+yi/2, y+xj/2+yj/2, xi/2, xj/2, yi/2, yj/2, n-1); - hilbert(pt, x+xi/2+yi, y+xj/2+yj, -yi/2, -yj/2, -xi/2, -xj/2, n-1); - } - } - - constexpr size_t log2(size_t n) { - return (n > 1) ? 1 + log2(n >> 1) : 0; - } - - constexpr size_t order(size_t n) { - return size_t(log2(n-1))+1; - } + constexpr int8_t to_fix(int8_t v) {return v << 1;} + constexpr int8_t to_int(int8_t v) {return v >> 1;} + constexpr uint8_t log2(uint8_t n) {return (n > 1) ? 1 + log2(n >> 1) : 0;} + constexpr uint8_t order(uint8_t n) {return uint8_t(log2(n - 1)) + 1;} + + void unified_bed_leveling::hilbert(mesh_index_pair &pt, int8_t x, int8_t y, int8_t xi, int8_t xj, int8_t yi, int8_t yj, uint8_t n) { + /* Hilbert space filling curve implementation + * + * x and y are the coordinates of the bottom left corner + * xi & xj are the i & j components of the unit x vector of the frame + * similarly yi and yj + * + * From: http://www.fundza.com/algorithmic/space_filling/hilbert/basics/index.html + */ + if (n <= 0) + check_if_missing(pt, to_int(x+(xi+yi)/2),to_int(y+(xj+yj)/2)); + else { + hilbert(pt, x, y, yi/2, yj/2, xi/2, xj/2, n-1); + hilbert(pt, x+xi/2, y+xj/2, xi/2, xj/2, yi/2, yj/2, n-1); + hilbert(pt, x+xi/2+yi/2, y+xj/2+yj/2, xi/2, xj/2, yi/2, yj/2, n-1); + hilbert(pt, x+xi/2+yi, y+xj/2+yj, -yi/2, -yj/2, -xi/2, -xj/2, n-1); + } + } void unified_bed_leveling::check_if_missing(mesh_index_pair &pt, int x, int y) { if (pt.distance < 0 && @@ -1341,12 +1338,13 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh } } - mesh_index_pair unified_bed_leveling::next_point_in_grid() { + mesh_index_pair unified_bed_leveling::find_next_mesh_point() { mesh_index_pair pt; pt.invalidate(); pt.distance = -99999.9f; - constexpr int n = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); - hilbert(pt, 0, 0, 1 << n, 0, 0, 1 << n, n); + constexpr uint8_t ord = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); + constexpr uint8_t dim = 1 << ord; + hilbert(pt, to_fix(0), to_fix(0),to_fix(dim), to_fix(0), to_fix(0), to_fix(dim), ord); return pt; } #endif From 38120298b4bc7d3bcf16195a0cdf3f9f564420e1 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 23 Mar 2021 01:12:54 -0500 Subject: [PATCH 3/7] some formatting --- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 39 +++++++++++---------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index ced245dec2ad..44d24d71fb48 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -757,13 +757,13 @@ void unified_bed_leveling::shift_mesh_height() { } #endif - best = do_furthest - ? find_furthest_invalid_mesh_point() - #if ENABLED(UBL_HILBERT_CURVE) - : next_point_in_grid(); - #else - : find_closest_mesh_point_of_type(INVALID, nearby, true); - #endif + best = do_furthest ? find_furthest_invalid_mesh_point() : + #if ENABLED(UBL_HILBERT_CURVE) + next_point_in_grid() + #else + find_closest_mesh_point_of_type(INVALID, nearby, true) + #endif + ; if (best.pos.x >= 0) { // mesh point found and is reachable by probe TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::PROBE_START)); @@ -1303,16 +1303,16 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh } #if ENABLED(UBL_HILBERT_CURVE) - constexpr int8_t to_fix(int8_t v) {return v << 1;} - constexpr int8_t to_int(int8_t v) {return v >> 1;} - constexpr uint8_t log2(uint8_t n) {return (n > 1) ? 1 + log2(n >> 1) : 0;} - constexpr uint8_t order(uint8_t n) {return uint8_t(log2(n - 1)) + 1;} + constexpr int8_t to_fix(int8_t v) { return v << 1; } + constexpr int8_t to_int(int8_t v) { return v >> 1; } + constexpr uint8_t log2(uint8_t n) { return (n > 1) ? 1 + log2(n >> 1) : 0; } + constexpr uint8_t order(uint8_t n) { return uint8_t(log2(n - 1)) + 1; } void unified_bed_leveling::hilbert(mesh_index_pair &pt, int8_t x, int8_t y, int8_t xi, int8_t xj, int8_t yi, int8_t yj, uint8_t n) { /* Hilbert space filling curve implementation * - * x and y are the coordinates of the bottom left corner - * xi & xj are the i & j components of the unit x vector of the frame + * x and y are the coordinates of the bottom left corner + * xi & xj are the i & j components of the unit x vector of the frame * similarly yi and yj * * From: http://www.fundza.com/algorithmic/space_filling/hilbert/basics/index.html @@ -1328,11 +1328,12 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh } void unified_bed_leveling::check_if_missing(mesh_index_pair &pt, int x, int y) { - if (pt.distance < 0 && - x < GRID_MAX_POINTS_X && - y < GRID_MAX_POINTS_Y && - isnan(z_values[x][y]) && - probe.can_reach(mesh_index_to_xpos(x), mesh_index_to_ypos(y))) { + if ( pt.distance < 0 + && x < GRID_MAX_POINTS_X + && y < GRID_MAX_POINTS_Y + && isnan(z_values[x][y]) + && probe.can_reach(mesh_index_to_xpos(x), mesh_index_to_ypos(y)) + ) { pt.pos.set(x, y); pt.distance = 1; } @@ -1343,7 +1344,7 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh pt.invalidate(); pt.distance = -99999.9f; constexpr uint8_t ord = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); - constexpr uint8_t dim = 1 << ord; + constexpr uint8_t dim = 1 << ord; hilbert(pt, to_fix(0), to_fix(0),to_fix(dim), to_fix(0), to_fix(0), to_fix(dim), ord); return pt; } From a77176e1ea0d54459f72dba91d64d18c97faa1de Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 23 Mar 2021 01:17:44 -0500 Subject: [PATCH 4/7] ternify --- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index 44d24d71fb48..e47643907aa0 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -757,13 +757,11 @@ void unified_bed_leveling::shift_mesh_height() { } #endif - best = do_furthest ? find_furthest_invalid_mesh_point() : - #if ENABLED(UBL_HILBERT_CURVE) - next_point_in_grid() - #else - find_closest_mesh_point_of_type(INVALID, nearby, true) - #endif - ; + best = do_furthest ? find_furthest_invalid_mesh_point() + : TERN(UBL_HILBERT_CURVE, + next_point_in_grid(), + find_closest_mesh_point_of_type(INVALID, nearby, true) + ); if (best.pos.x >= 0) { // mesh point found and is reachable by probe TERN_(EXTENSIBLE_UI, ExtUI::onMeshUpdate(best.pos, ExtUI::PROBE_START)); From 0741aac784770b6a6ad5d40bb1e92ff2951b5361 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 23 Mar 2021 01:19:38 -0500 Subject: [PATCH 5/7] etc. --- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index e47643907aa0..3ea777fd9a45 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -1301,6 +1301,7 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh } #if ENABLED(UBL_HILBERT_CURVE) + constexpr int8_t to_fix(int8_t v) { return v << 1; } constexpr int8_t to_int(int8_t v) { return v >> 1; } constexpr uint8_t log2(uint8_t n) { return (n > 1) ? 1 + log2(n >> 1) : 0; } @@ -1342,11 +1343,12 @@ mesh_index_pair unified_bed_leveling::find_closest_mesh_point_of_type(const Mesh pt.invalidate(); pt.distance = -99999.9f; constexpr uint8_t ord = order(_MAX(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y)); - constexpr uint8_t dim = 1 << ord; - hilbert(pt, to_fix(0), to_fix(0),to_fix(dim), to_fix(0), to_fix(0), to_fix(dim), ord); + constexpr uint8_t dim = _BV(ord); + hilbert(pt, to_fix(0), to_fix(0), to_fix(dim), to_fix(0), to_fix(0), to_fix(dim), ord); return pt; } -#endif + +#endif // UBL_HILBERT_CURVE /** * 'Smart Fill': Scan from the outward edges of the mesh towards the center. From 8afba1d9e222ef091ac6db68c594485565384d0f Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 23 Mar 2021 01:24:07 -0500 Subject: [PATCH 6/7] Config option UBL_HILBERT_CURVE --- Marlin/Configuration.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Marlin/Configuration.h b/Marlin/Configuration.h index ce847c0d6513..339dae7702d1 100644 --- a/Marlin/Configuration.h +++ b/Marlin/Configuration.h @@ -1478,6 +1478,8 @@ #define GRID_MAX_POINTS_X 10 // Don't use more than 15 points per axis, implementation limited. #define GRID_MAX_POINTS_Y GRID_MAX_POINTS_X + //#define UBL_HILBERT_CURVE // Use Hilbert distribution for less travel when probing multiple points + #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 From 9a6a8020244cb6f6c29891078d4e5b497e90ca72 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 23 Mar 2021 01:25:07 -0500 Subject: [PATCH 7/7] add a test --- buildroot/tests/mega2560 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildroot/tests/mega2560 b/buildroot/tests/mega2560 index d961ab4effe3..e3209899ce92 100755 --- a/buildroot/tests/mega2560 +++ b/buildroot/tests/mega2560 @@ -36,7 +36,7 @@ opt_set MOTHERBOARD BOARD_AZTEEG_X3_PRO LCD_LANGUAGE jp_kana \ opt_enable REPRAP_DISCOUNT_FULL_GRAPHIC_SMART_CONTROLLER LIGHTWEIGHT_UI SHOW_CUSTOM_BOOTSCREEN BOOT_MARLIN_LOGO_SMALL \ LCD_SET_PROGRESS_MANUALLY PRINT_PROGRESS_SHOW_DECIMALS SHOW_REMAINING_TIME STATUS_MESSAGE_SCROLLING SCROLL_LONG_FILENAMES \ SDSUPPORT SDCARD_SORT_ALPHA NO_SD_AUTOSTART USB_FLASH_DRIVE_SUPPORT CANCEL_OBJECTS \ - Z_PROBE_SLED AUTO_BED_LEVELING_UBL RESTORE_LEVELING_AFTER_G28 DEBUG_LEVELING_FEATURE G26_MESH_VALIDATION ENABLE_LEVELING_FADE_HEIGHT \ + Z_PROBE_SLED AUTO_BED_LEVELING_UBL UBL_HILBERT_CURVE RESTORE_LEVELING_AFTER_G28 DEBUG_LEVELING_FEATURE G26_MESH_VALIDATION ENABLE_LEVELING_FADE_HEIGHT \ EEPROM_SETTINGS EEPROM_CHITCHAT GCODE_MACROS CUSTOM_USER_MENUS \ MULTI_NOZZLE_DUPLICATION CLASSIC_JERK LIN_ADVANCE QUICK_HOME \ NANODLP_Z_SYNC I2C_POSITION_ENCODERS M114_DETAIL \