Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Marlin/Conditionals_post.h
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,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
*/
Expand Down
33 changes: 29 additions & 4 deletions Marlin/Marlin_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2461,7 +2461,21 @@ void clean_up_after_endstop_or_probe_move() {
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 // ABL
Expand Down Expand Up @@ -9327,6 +9341,14 @@ inline void gcode_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();
}
}

/**
Expand Down Expand Up @@ -9904,6 +9926,7 @@ void quickstop_stepper() {
* 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
*/
inline void gcode_M420() {

Expand Down Expand Up @@ -9942,7 +9965,7 @@ void quickstop_stepper() {

// L to load a mesh from the EEPROM
if (parser.seen('L') || parser.seen('V')) {
ubl.display_map(0); // Currently only supports one map type
ubl.display_map(parser.byteval('T')); // 0=
SERIAL_ECHOLNPAIR("ubl.mesh_is_valid = ", ubl.mesh_is_valid());
SERIAL_ECHOLNPAIR("ubl.storage_slot = ", ubl.storage_slot);
}
Expand Down Expand Up @@ -10073,6 +10096,7 @@ void quickstop_stepper() {
* Usage:
* M421 I<xindex> J<yindex> Z<linear>
* M421 I<xindex> J<yindex> Q<offset>
* M421 I<xindex> J<yindex> N
* M421 C Z<linear>
* M421 C Q<offset>
*/
Expand All @@ -10081,6 +10105,7 @@ void quickstop_stepper() {
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');

Expand All @@ -10090,7 +10115,7 @@ void quickstop_stepper() {
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);
}
Expand All @@ -10099,7 +10124,7 @@ void quickstop_stepper() {
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
Expand Down
14 changes: 8 additions & 6 deletions Marlin/fwretract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ void FWRetract::retract(const bool retracting
#endif
}
SERIAL_ECHOLNPAIR("current_position[z] ", current_position[Z_AXIS]);
SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]);
SERIAL_ECHOLNPAIR("hop_amount ", hop_amount);
//*/

Expand All @@ -139,7 +140,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
Expand All @@ -149,7 +150,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();
}
Expand All @@ -160,17 +161,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
Expand All @@ -195,6 +196,7 @@ void FWRetract::retract(const bool retracting
#endif
}
SERIAL_ECHOLNPAIR("current_position[z] ", current_position[Z_AXIS]);
SERIAL_ECHOLNPAIR("current_position[e] ", current_position[E_AXIS]);
SERIAL_ECHOLNPAIR("hop_amount ", hop_amount);
//*/

Expand Down
2 changes: 1 addition & 1 deletion Marlin/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,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
Expand Down
140 changes: 80 additions & 60 deletions Marlin/ubl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,15 @@
void unified_bed_leveling::report_current_mesh() {
if (!leveling_is_valid()) return;
SERIAL_ECHO_START();
SERIAL_ECHOLNPGM(" G29 I 999");
SERIAL_ECHOLNPGM(" G29 I999");
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])) {
SERIAL_ECHO_START();
SERIAL_ECHOPAIR(" M421 I ", x);
SERIAL_ECHOPAIR(" J ", y);
SERIAL_ECHOPGM(" Z ");
SERIAL_ECHO_F(z_values[x][y], 6);
SERIAL_ECHOPAIR(" ; X ", LOGICAL_X_POSITION(mesh_index_to_xpos(x)));
SERIAL_ECHOPAIR(", Y ", LOGICAL_Y_POSITION(mesh_index_to_ypos(y)));
SERIAL_ECHOPAIR(" M421 I", x);
SERIAL_ECHOPAIR(" J", y);
SERIAL_ECHOPGM(" Z");
SERIAL_ECHO_F(z_values[x][y], 2);
SERIAL_EOL();
}
}
Expand All @@ -63,15 +61,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) {
Expand Down Expand Up @@ -169,81 +158,112 @@
}
}

// 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++) {
const bool is_current = i == current_xi && j == current_yi;

// is the nozzle here? then mark the number
if (map_type == 0) SERIAL_CHAR(is_current ? '[' : ' ');
// Opening Brace or Space
const bool is_current = i == current_xi && j == current_yi;
if (human) 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 ? ']' : ' ');

#if TX_BUFFER_SIZE > 0
SERIAL_FLUSHTX();
#endif
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();
safe_delay(5);
}
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();
}

Expand Down
4 changes: 1 addition & 3 deletions Marlin/ubl_G29.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,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.
Expand Down
14 changes: 8 additions & 6 deletions Marlin/ultralcd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2921,14 +2921,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);
Expand Down