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
2 changes: 1 addition & 1 deletion Marlin/src/core/macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 15 additions & 1 deletion Marlin/src/feature/bedlevel/bedlevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
136 changes: 78 additions & 58 deletions Marlin/src/feature/bedlevel/ubl/ubl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,15 @@
) {
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])) {
SERIAL_ECHO_START_P(port);
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
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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++) {
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 ? ']' : ' ');

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();
}

Expand Down
4 changes: 1 addition & 3 deletions Marlin/src/feature/bedlevel/ubl/ubl_G29.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
14 changes: 8 additions & 6 deletions Marlin/src/feature/fwretract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
//*/

Expand All @@ -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
Expand All @@ -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();
}
Expand All @@ -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
Expand All @@ -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);
//*/

Expand Down
3 changes: 2 additions & 1 deletion Marlin/src/gcode/bedlevel/M420.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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() {

Expand Down Expand Up @@ -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);
}
Expand Down
6 changes: 4 additions & 2 deletions Marlin/src/gcode/bedlevel/ubl/M421.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
* 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 @@ -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');

Expand All @@ -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);
}
Expand All @@ -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
8 changes: 8 additions & 0 deletions Marlin/src/gcode/config/M221.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
4 changes: 4 additions & 0 deletions Marlin/src/inc/Conditionals_post.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
14 changes: 8 additions & 6 deletions Marlin/src/lcd/ultralcd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down