From 0746aff595fde79b62f01fca8588ac803bc3521c Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 15:52:56 -0500 Subject: [PATCH 1/7] Improve UBL mesh report. Add M420 T, M421 N --- Marlin/src/feature/bedlevel/ubl/ubl.cpp | 136 +++++++++++--------- Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp | 4 +- Marlin/src/gcode/bedlevel/M420.cpp | 3 +- Marlin/src/gcode/bedlevel/ubl/M421.cpp | 6 +- 4 files changed, 85 insertions(+), 64 deletions(-) diff --git a/Marlin/src/feature/bedlevel/ubl/ubl.cpp b/Marlin/src/feature/bedlevel/ubl/ubl.cpp index 2ddca1a86..143d7a0fc 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl.cpp @@ -51,7 +51,7 @@ ) { if (!leveling_is_valid()) return; SERIAL_ECHO_START_P(port); - SERIAL_ECHOLNPGM_P(port, " G29 I 999"); + SERIAL_ECHOLNPGM_P(port, " G29 I99"); for (uint8_t x = 0; x < GRID_MAX_POINTS_X; x++) for (uint8_t y = 0; y < GRID_MAX_POINTS_Y; y++) if (!isnan(z_values[x][y])) { @@ -59,9 +59,7 @@ SERIAL_ECHOPAIR_P(port, " M421 I", x); SERIAL_ECHOPAIR_P(port, " J", y); SERIAL_ECHOPGM_P(port, " Z"); - SERIAL_ECHO_F_P(port, z_values[x][y], 6); - SERIAL_ECHOPAIR_P(port, " ; X", LOGICAL_X_POSITION(mesh_index_to_xpos(x))); - SERIAL_ECHOPAIR_P(port, ", Y", LOGICAL_Y_POSITION(mesh_index_to_ypos(y))); + SERIAL_ECHO_F_P(port, z_values[x][y], 2); SERIAL_EOL_P(port); safe_delay(75); // Prevent Printrun from exploding } @@ -83,15 +81,6 @@ safe_delay(50); } - static void serial_echo_xy(const int16_t x, const int16_t y) { - SERIAL_CHAR('('); - SERIAL_ECHO(x); - SERIAL_CHAR(','); - SERIAL_ECHO(y); - SERIAL_CHAR(')'); - safe_delay(10); - } - #if ENABLED(UBL_DEVEL_DEBUGGING) static void debug_echo_axis(const AxisEnum axis) { @@ -189,78 +178,109 @@ } } - // display_map() currently produces three different mesh map types - // 0 : suitable for PronterFace and Repetier's serial console - // 1 : .CSV file suitable for importation into various spread sheets - // 2 : disply of the map data on a RepRap Graphical LCD Panel + static void serial_echo_xy(const uint8_t sp, const int16_t x, const int16_t y) { + SERIAL_ECHO_SP(sp); + SERIAL_CHAR('('); + if (x < 100) { SERIAL_CHAR(' '); if (x < 10) SERIAL_CHAR(' '); } + SERIAL_ECHO(x); + SERIAL_CHAR(','); + if (y < 100) { SERIAL_CHAR(' '); if (y < 10) SERIAL_CHAR(' '); } + SERIAL_ECHO(y); + SERIAL_CHAR(')'); + safe_delay(5); + } + static void serial_echo_column_labels(const uint8_t sp) { + SERIAL_ECHO_SP(7); + for (int8_t i = 0; i < GRID_MAX_POINTS_X; i++) { + if (i < 10) SERIAL_CHAR(' '); + SERIAL_ECHO(i); + SERIAL_ECHO_SP(sp); + } + safe_delay(10); + } + + /** + * Produce one of these mesh maps: + * 0: Human-readable + * 1: CSV format for spreadsheet import + * 2: TODO: Display on Graphical LCD + * 4: Compact Human-Readable + */ void unified_bed_leveling::display_map(const int map_type) { #if HAS_AUTO_REPORTING || ENABLED(HOST_KEEPALIVE_FEATURE) suspend_auto_report = true; #endif - constexpr uint8_t spaces = 8 * (GRID_MAX_POINTS_X - 2); + constexpr uint8_t eachsp = 1 + 6 + 1, // [-3.567] + twixt = eachsp * (GRID_MAX_POINTS_X) - 9 * 2; // Leading 4sp, Coordinates 9sp each - SERIAL_PROTOCOLPGM("\nBed Topography Report"); - if (map_type == 0) { - SERIAL_PROTOCOLPGM(":\n\n"); - serial_echo_xy(0, GRID_MAX_POINTS_Y - 1); - SERIAL_ECHO_SP(spaces + 3); - serial_echo_xy(GRID_MAX_POINTS_X - 1, GRID_MAX_POINTS_Y - 1); - SERIAL_EOL(); - serial_echo_xy(MESH_MIN_X, MESH_MAX_Y); - SERIAL_ECHO_SP(spaces); - serial_echo_xy(MESH_MAX_X, MESH_MAX_Y); + const bool human = !(map_type & 0x3), csv = map_type == 1, lcd = map_type == 2, comp = map_type & 0x4; + + SERIAL_ECHOPGM("\nBed Topography Report"); + if (human) { + SERIAL_ECHOPGM(":\n\n"); + serial_echo_xy(4, MESH_MIN_X, MESH_MAX_Y); + serial_echo_xy(twixt, MESH_MAX_X, MESH_MAX_Y); SERIAL_EOL(); + serial_echo_column_labels(eachsp - 2); } else { - SERIAL_PROTOCOLPGM(" for "); - serialprintPGM(map_type == 1 ? PSTR("CSV:\n\n") : PSTR("LCD:\n\n")); + SERIAL_ECHOPGM(" for "); + serialprintPGM(csv ? PSTR("CSV:\n") : PSTR("LCD:\n")); } const float current_xi = get_cell_index_x(current_position[X_AXIS] + (MESH_X_DIST) / 2.0), current_yi = get_cell_index_y(current_position[Y_AXIS] + (MESH_Y_DIST) / 2.0); + if (!lcd) SERIAL_EOL(); for (int8_t j = GRID_MAX_POINTS_Y - 1; j >= 0; j--) { + + // Row Label (J index) + if (human) { + if (j < 10) SERIAL_CHAR(' '); + SERIAL_ECHO(j); + SERIAL_ECHOPGM(" |"); + } + + // Row Values (I indexes) for (uint8_t i = 0; i < GRID_MAX_POINTS_X; i++) { + + // Opening Brace or Space const bool is_current = i == current_xi && j == current_yi; + if (human) SERIAL_CHAR(is_current ? '[' : ' '); - // is the nozzle here? then mark the number - if (map_type == 0) SERIAL_CHAR(is_current ? '[' : ' '); - + // Z Value at current I, J const float f = z_values[i][j]; - if (isnan(f)) { - serialprintPGM(map_type == 0 ? PSTR(" . ") : PSTR("NAN")); + if (lcd) { + // TODO: Display on Graphical LCD } - else if (map_type <= 1) { - // if we don't do this, the columns won't line up nicely - if (map_type == 0 && f >= 0.0) SERIAL_CHAR(' '); - SERIAL_PROTOCOL_F(f, 3); + else if (isnan(f)) + serialprintPGM(human ? PSTR(" . ") : PSTR("NAN")); + else if (human || csv) { + if (human && f >= 0.0) SERIAL_CHAR(f > 0 ? '+' : ' '); // Space for positive ('-' for negative) + SERIAL_ECHO_F(f, 3); // Positive: 5 digits, Negative: 6 digits } - idle(); - if (map_type == 1 && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR(','); + if (csv && i < GRID_MAX_POINTS_X - 1) SERIAL_CHAR('\t'); + + // Closing Brace or Space + if (human) SERIAL_CHAR(is_current ? ']' : ' '); + SERIAL_FLUSHTX(); - safe_delay(15); - if (map_type == 0) { - SERIAL_CHAR(is_current ? ']' : ' '); - SERIAL_CHAR(' '); - } - } - SERIAL_EOL(); - if (j && map_type == 0) { // we want the (0,0) up tight against the block of numbers - SERIAL_CHAR(' '); - SERIAL_EOL(); + idle(); } + if (!lcd) SERIAL_EOL(); + + // A blank line between rows (unless compact) + if (j && human && !comp) SERIAL_ECHOLNPGM(" |"); } - if (map_type == 0) { - serial_echo_xy(MESH_MIN_X, MESH_MIN_Y); - SERIAL_ECHO_SP(spaces + 4); - serial_echo_xy(MESH_MAX_X, MESH_MIN_Y); + if (human) { + serial_echo_column_labels(eachsp - 2); + SERIAL_EOL(); + serial_echo_xy(4, MESH_MIN_X, MESH_MIN_Y); + serial_echo_xy(twixt, MESH_MAX_X, MESH_MIN_Y); SERIAL_EOL(); - serial_echo_xy(0, 0); - SERIAL_ECHO_SP(spaces + 5); - serial_echo_xy(GRID_MAX_POINTS_X - 1, 0); SERIAL_EOL(); } diff --git a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp index c5d575d40..7a3fb5537 100644 --- a/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp +++ b/Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp @@ -252,9 +252,7 @@ * for subsequent Load and Store operations. Valid storage slot numbers begin at 0 and * extend to a limit related to the available EEPROM storage. * - * S -1 Store Store the current Mesh as a print out that is suitable to be feed back into the system - * at a later date. The GCode output can be saved and later replayed by the host software - * to reconstruct the current mesh on another machine. + * S -1 Store Print the current Mesh as G-code that can be used to restore the mesh anytime. * * T Topology Display the Mesh Map Topology. * 'T' can be used alone (e.g., G29 T) or in combination with most of the other commands. diff --git a/Marlin/src/gcode/bedlevel/M420.cpp b/Marlin/src/gcode/bedlevel/M420.cpp index 1af94893e..f877de881 100644 --- a/Marlin/src/gcode/bedlevel/M420.cpp +++ b/Marlin/src/gcode/bedlevel/M420.cpp @@ -42,6 +42,7 @@ * With AUTO_BED_LEVELING_UBL only: * * L[index] Load UBL mesh from index (0 is default) + * T[map] 0:Human-readable 1:CSV 2:"LCD" 4:Compact */ void GcodeSuite::M420() { @@ -80,7 +81,7 @@ void GcodeSuite::M420() { // L or V display the map info if (parser.seen('L') || parser.seen('V')) { - ubl.display_map(0); // Currently only supports one map type + ubl.display_map(parser.byteval('T')); SERIAL_ECHOLNPAIR("ubl.mesh_is_valid = ", ubl.mesh_is_valid()); SERIAL_ECHOLNPAIR("ubl.storage_slot = ", ubl.storage_slot); } diff --git a/Marlin/src/gcode/bedlevel/ubl/M421.cpp b/Marlin/src/gcode/bedlevel/ubl/M421.cpp index 72a9aa903..e8597eee2 100644 --- a/Marlin/src/gcode/bedlevel/ubl/M421.cpp +++ b/Marlin/src/gcode/bedlevel/ubl/M421.cpp @@ -37,6 +37,7 @@ * Usage: * M421 I J Z * M421 I J Q + * M421 I J N * M421 C Z * M421 C Q */ @@ -45,6 +46,7 @@ void GcodeSuite::M421() { const bool hasI = ix >= 0, hasJ = iy >= 0, hasC = parser.seen('C'), + hasN = parser.seen('N'), hasZ = parser.seen('Z'), hasQ = !hasZ && parser.seen('Q'); @@ -54,7 +56,7 @@ void GcodeSuite::M421() { iy = location.y_index; } - if (int(hasC) + int(hasI && hasJ) != 1 || !(hasZ || hasQ)) { + if (int(hasC) + int(hasI && hasJ) != 1 || !(hasZ || hasQ || hasN)) { SERIAL_ERROR_START(); SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS); } @@ -63,7 +65,7 @@ void GcodeSuite::M421() { SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY); } else - ubl.z_values[ix][iy] = parser.value_linear_units() + (hasQ ? ubl.z_values[ix][iy] : 0); + ubl.z_values[ix][iy] = hasN ? NAN : parser.value_linear_units() + (hasQ ? ubl.z_values[ix][iy] : 0); } #endif // AUTO_BED_LEVELING_UBL From 39c6f65ce7ed07fd0d4ad5dd8dca68c04365ffa3 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 15:57:44 -0500 Subject: [PATCH 2/7] Ignore LCD_BED_LEVELING with UBL --- Marlin/src/inc/Conditionals_post.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Marlin/src/inc/Conditionals_post.h b/Marlin/src/inc/Conditionals_post.h index 4f61dd1ec..7d2650726 100644 --- a/Marlin/src/inc/Conditionals_post.h +++ b/Marlin/src/inc/Conditionals_post.h @@ -1039,6 +1039,10 @@ #define PLANNER_LEVELING (OLDSCHOOL_ABL || ENABLED(MESH_BED_LEVELING) || UBL_SEGMENTED || ENABLED(SKEW_CORRECTION)) #define HAS_PROBING_PROCEDURE (HAS_ABL || ENABLED(Z_MIN_PROBE_REPEATABILITY_TEST)) +#if ENABLED(AUTO_BED_LEVELING_UBL) + #undef LCD_BED_LEVELING +#endif + /** * Heater & Fan Pausing */ From d462be6de62f9e49805a88b0eeca836ab44b658b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 15:59:04 -0500 Subject: [PATCH 3/7] Try FIXFLOAT rounding based on sign --- Marlin/src/core/macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Marlin/src/core/macros.h b/Marlin/src/core/macros.h index c61e7d4cb..28cbbb18a 100644 --- a/Marlin/src/core/macros.h +++ b/Marlin/src/core/macros.h @@ -208,7 +208,7 @@ #define NEAR(x,y) NEAR_ZERO((x)-(y)) #define RECIPROCAL(x) (NEAR_ZERO(x) ? 0.0 : 1.0 / (x)) -#define FIXFLOAT(f) (f + 0.00001) +#define FIXFLOAT(f) (f + (f < 0.0 ? -0.00001 : 0.00001)) // // Maths macros that can be overridden by HAL From e05c825a0556e2193640232b4162c0968c967cad Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 16:02:02 -0500 Subject: [PATCH 4/7] Update position for UBL non-segmented activate/deactivate --- Marlin/src/feature/bedlevel/bedlevel.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Marlin/src/feature/bedlevel/bedlevel.cpp b/Marlin/src/feature/bedlevel/bedlevel.cpp index ea1284efc..507a3baa0 100644 --- a/Marlin/src/feature/bedlevel/bedlevel.cpp +++ b/Marlin/src/feature/bedlevel/bedlevel.cpp @@ -99,7 +99,21 @@ void set_bed_leveling_enabled(const bool enable/*=true*/) { planner.unapply_leveling(current_position); } #else - planner.leveling_active = enable; // just flip the bit, current_position will be wrong until next move. + // UBL equivalents for apply/unapply_leveling + #if ENABLED(SKEW_CORRECTION) + float pos[XYZ] = { current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS] }; + planner.skew(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS]); + #else + const float (&pos)[XYZE] = current_position; + #endif + if (planner.leveling_active) { + current_position[Z_AXIS] += ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS]); + planner.leveling_active = false; + } + else { + planner.leveling_active = true; + current_position[Z_AXIS] -= ubl.get_z_correction(pos[X_AXIS], pos[Y_AXIS], pos[Z_AXIS]); + } #endif #else // OLDSCHOOL_ABL From e4acd2c40ed78df699eddb6bb23f60cbb858a56b Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 16:03:15 -0500 Subject: [PATCH 5/7] One fewer compare in _lcd_move_xyz --- Marlin/src/lcd/ultralcd.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Marlin/src/lcd/ultralcd.cpp b/Marlin/src/lcd/ultralcd.cpp index 59b1221e5..0c25bc5b7 100644 --- a/Marlin/src/lcd/ultralcd.cpp +++ b/Marlin/src/lcd/ultralcd.cpp @@ -2931,14 +2931,16 @@ void kill_screen(const char* lcd_msg) { const float diff = float((int32_t)encoderPosition) * move_menu_scale; #if IS_KINEMATIC manual_move_offset += diff; - // Limit only when trying to move towards the limit - if ((int32_t)encoderPosition < 0) NOLESS(manual_move_offset, min - current_position[axis]); - if ((int32_t)encoderPosition > 0) NOMORE(manual_move_offset, max - current_position[axis]); + if ((int32_t)encoderPosition < 0) + NOLESS(manual_move_offset, min - current_position[axis]); + else + NOMORE(manual_move_offset, max - current_position[axis]); #else current_position[axis] += diff; - // Limit only when trying to move towards the limit - if ((int32_t)encoderPosition < 0) NOLESS(current_position[axis], min); - if ((int32_t)encoderPosition > 0) NOMORE(current_position[axis], max); + if ((int32_t)encoderPosition < 0) + NOLESS(current_position[axis], min); + else + NOMORE(current_position[axis], max); #endif manual_move_to_current(axis); From 01b01f6dfdc6ee87522a01fdff56545c45d9972a Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 16:05:25 -0500 Subject: [PATCH 6/7] Tweak fwretract.retract debug, comments --- Marlin/src/feature/fwretract.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/Marlin/src/feature/fwretract.cpp b/Marlin/src/feature/fwretract.cpp index ab0708840..06065f263 100644 --- a/Marlin/src/feature/fwretract.cpp +++ b/Marlin/src/feature/fwretract.cpp @@ -122,6 +122,7 @@ void FWRetract::retract(const bool retracting SERIAL_ECHOLNPAIR("] ", retracted_swap[i]); } SERIAL_ECHOLNPAIR("current_position[z] ", current_position[Z_AXIS]); + SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]); SERIAL_ECHOLNPAIR("hop_amount ", hop_amount); //*/ @@ -138,7 +139,7 @@ void FWRetract::retract(const bool retracting feedrate_mm_s = retract_feedrate_mm_s; current_position[E_AXIS] += (swapping ? swap_retract_length : retract_length) * renormalize; sync_plan_position_e(); - prepare_move_to_destination(); + prepare_move_to_destination(); // set_current_to_destination // Is a Z hop set, and has the hop not yet been done? // No double zlifting @@ -148,7 +149,7 @@ void FWRetract::retract(const bool retracting hop_amount += retract_zlift; // Add to the hop total (again, only once) destination[Z_AXIS] += retract_zlift; // Raise Z by the zlift (M207 Z) amount feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS]; // Maximum Z feedrate - prepare_move_to_destination(); // Raise up + prepare_move_to_destination(); // Raise up, set_current_to_destination current_position[Z_AXIS] = old_z; // Spoof the Z position in the planner SYNC_PLAN_POSITION_KINEMATIC(); } @@ -159,17 +160,17 @@ void FWRetract::retract(const bool retracting current_position[Z_AXIS] += hop_amount; // Set actual Z (due to the prior hop) SYNC_PLAN_POSITION_KINEMATIC(); // Spoof the Z position in the planner feedrate_mm_s = planner.max_feedrate_mm_s[Z_AXIS]; // Z feedrate to max - prepare_move_to_destination(); // Lower Z and update current_position + prepare_move_to_destination(); // Lower Z, set_current_to_destination hop_amount = 0.0; // Clear the hop amount } // A retract multiplier has been added here to get faster swap recovery feedrate_mm_s = swapping ? swap_retract_recover_feedrate_mm_s : retract_recover_feedrate_mm_s; - const float move_e = swapping ? swap_retract_length + swap_retract_recover_length : retract_length + retract_recover_length; - current_position[E_AXIS] -= move_e * renormalize; + current_position[E_AXIS] -= (swapping ? swap_retract_length + swap_retract_recover_length + : retract_length + retract_recover_length) * renormalize; sync_plan_position_e(); - prepare_move_to_destination(); // Recover E + prepare_move_to_destination(); // Recover E, set_current_to_destination } feedrate_mm_s = old_feedrate_mm_s; // Restore original feedrate @@ -192,6 +193,7 @@ void FWRetract::retract(const bool retracting SERIAL_ECHOLNPAIR("] ", retracted_swap[i]); } SERIAL_ECHOLNPAIR("current_position[z] ", current_position[Z_AXIS]); + SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]); SERIAL_ECHOLNPAIR("hop_amount ", hop_amount); //*/ From 52c024e260d483580f054b79a193faa022e143c0 Mon Sep 17 00:00:00 2001 From: Scott Lahteine Date: Tue, 17 Apr 2018 16:06:25 -0500 Subject: [PATCH 7/7] M221 with no parameters report flow --- Marlin/src/gcode/config/M221.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Marlin/src/gcode/config/M221.cpp b/Marlin/src/gcode/config/M221.cpp index 7d6c64343..e5d4204f5 100644 --- a/Marlin/src/gcode/config/M221.cpp +++ b/Marlin/src/gcode/config/M221.cpp @@ -32,4 +32,12 @@ void GcodeSuite::M221() { planner.flow_percentage[target_extruder] = parser.value_int(); planner.refresh_e_factor(target_extruder); } + else { + SERIAL_ECHO_START(); + SERIAL_CHAR('E'); + SERIAL_CHAR('0' + target_extruder); + SERIAL_ECHOPAIR(" Flow: ", planner.flow_percentage[target_extruder]); + SERIAL_CHAR('%'); + SERIAL_EOL(); + } }