Skip to content
Open
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
32 changes: 27 additions & 5 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@
//#define ASSISTED_TRAMMING
#if ENABLED(ASSISTED_TRAMMING)

// Define from 3 to 9 points to probe.
// Define from 3 to 9 points to probe. Overwritten by "DYNAMIC_MARGINS" if "DYNAMIC_TRAMMING" is enabled.
#define TRAMMING_POINT_XY { { 20, 20 }, { 180, 20 }, { 180, 180 }, { 20, 180 } }

// Define position names for probe points.
Expand Down Expand Up @@ -2448,12 +2448,34 @@
* should the probe position be modified with M851XY then the
* probe points will follow. This prevents any change from causing
* the probe to be unable to reach any points.
*
* If you enable DYNAMIC_MARGINS PROBING_MARGINs are changeable without recompilation.
* They are then bedlevel.margin_l, bedlevel.margin_r, bedlevel.margin_f, bedlevel.margin_b
* and can be overwritten with "M421 L50 R50 F50 B50" for a 50mm margin around the bed
* and saved to the EEPROM on runtime. Default values underneath.
* Setting manually via gcode respects probe_offsets and the min and max positions
* and recalculates if a too low value is set so the probed area is valid.
*
* DYNAMIC_MARGINS can be also enabled to be used for the ASSISTED_TRAMMING points with
* #define DYNAMIC_TRAMMING
*
*/
#if PROBE_SELECTED && !IS_KINEMATIC
//#define PROBING_MARGIN_LEFT PROBING_MARGIN
//#define PROBING_MARGIN_RIGHT PROBING_MARGIN
//#define PROBING_MARGIN_FRONT PROBING_MARGIN
//#define PROBING_MARGIN_BACK PROBING_MARGIN
//#define DYNAMIC_MARGINS
#if ENABLED(DYNAMIC_MARGINS)
#if ENABLED(ASSISTED_TRAMMING)
//#define DYNAMIC_TRAMMING
#endif
#define PROBING_MARGIN_LEFT 45
#define PROBING_MARGIN_RIGHT 45
#define PROBING_MARGIN_FRONT 45
#define PROBING_MARGIN_BACK 45
#else
#define PROBING_MARGIN_LEFT PROBING_MARGIN
#define PROBING_MARGIN_RIGHT PROBING_MARGIN
#define PROBING_MARGIN_FRONT PROBING_MARGIN
#define PROBING_MARGIN_BACK PROBING_MARGIN
#endif
#endif

#if ANY(MESH_BED_LEVELING, AUTO_BED_LEVELING_UBL)
Expand Down
3 changes: 3 additions & 0 deletions Marlin/src/feature/bedlevel/abl/bbl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ xy_float_t LevelingBilinear::grid_factor;
bed_mesh_t LevelingBilinear::z_values;
xy_pos_t LevelingBilinear::cached_rel;
xy_int8_t LevelingBilinear::cached_g;
#if ENABLED(DYNAMIC_MARGINS)
int16_t LevelingBilinear::margin_l, LevelingBilinear::margin_r, LevelingBilinear::margin_f, LevelingBilinear::margin_b;
#endif

/**
* Extrapolate a single point from its neighbors
Expand Down
6 changes: 6 additions & 0 deletions Marlin/src/feature/bedlevel/abl/bbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,17 @@
#pragma once

#include "../../../inc/MarlinConfigPre.h"
#if ENABLED(DYNAMIC_MARGINS)
#include "../../../feature/bedlevel/bedlevel.h"
#endif

class LevelingBilinear {
public:
static bed_mesh_t z_values;
static xy_pos_t grid_spacing, grid_start;
#if ENABLED(DYNAMIC_MARGINS)
static int16_t margin_l, margin_r, margin_f, margin_b;
#endif

private:
static xy_float_t grid_factor;
Expand Down
4 changes: 2 additions & 2 deletions Marlin/src/feature/bedlevel/hilbert_curve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ bool hilbert_curve::search_from(uint8_t x, uint8_t y, hilbert_curve::callback_pt
*/
bool hilbert_curve::search_from_closest(const xy_pos_t &pos, hilbert_curve::callback_ptr func, void *data) {
// Find closest grid intersection
const uint8_t grid_x = LROUND(constrain(float(pos.x - (MESH_MIN_X)) / (MESH_X_DIST), 0, (GRID_MAX_POINTS_X) - 1));
const uint8_t grid_y = LROUND(constrain(float(pos.y - (MESH_MIN_Y)) / (MESH_Y_DIST), 0, (GRID_MAX_POINTS_Y) - 1));
const uint8_t grid_x = LROUND(constrain(float(pos.x - (TERN(DYNAMIC_MARGINS, bedlevel.margin_l, MESH_MIN_X))) / (TERN(DYNAMIC_MARGINS, bedlevel.get_mesh_x_dist(), MESH_X_DIST)), 0, (GRID_MAX_POINTS_X) - 1));
const uint8_t grid_y = LROUND(constrain(float(pos.y - (TERN(DYNAMIC_MARGINS, bedlevel.margin_f, MESH_MIN_Y))) / (TERN(DYNAMIC_MARGINS, bedlevel.get_mesh_y_dist(), MESH_Y_DIST)), 0, (GRID_MAX_POINTS_Y) - 1));
return search_from(grid_x, grid_y, func, data);
}

Expand Down
40 changes: 22 additions & 18 deletions Marlin/src/feature/bedlevel/ubl/ubl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,26 @@ void unified_bed_leveling::report_state() {
int8_t unified_bed_leveling::storage_slot;

float unified_bed_leveling::z_values[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
#if ENABLED(DYNAMIC_MARGINS)
int16_t unified_bed_leveling::margin_l, unified_bed_leveling::margin_r, unified_bed_leveling::margin_f, unified_bed_leveling::margin_b;
#endif

#define _GRIDPOS(A,N) (MESH_MIN_##A + N * (MESH_##A##_DIST))

const float
unified_bed_leveling::_mesh_index_to_xpos[GRID_MAX_POINTS_X] PROGMEM = ARRAY_N(GRID_MAX_POINTS_X,
_GRIDPOS(X, 0), _GRIDPOS(X, 1), _GRIDPOS(X, 2), _GRIDPOS(X, 3),
_GRIDPOS(X, 4), _GRIDPOS(X, 5), _GRIDPOS(X, 6), _GRIDPOS(X, 7),
_GRIDPOS(X, 8), _GRIDPOS(X, 9), _GRIDPOS(X, 10), _GRIDPOS(X, 11),
_GRIDPOS(X, 12), _GRIDPOS(X, 13), _GRIDPOS(X, 14), _GRIDPOS(X, 15)
),
unified_bed_leveling::_mesh_index_to_ypos[GRID_MAX_POINTS_Y] PROGMEM = ARRAY_N(GRID_MAX_POINTS_Y,
_GRIDPOS(Y, 0), _GRIDPOS(Y, 1), _GRIDPOS(Y, 2), _GRIDPOS(Y, 3),
_GRIDPOS(Y, 4), _GRIDPOS(Y, 5), _GRIDPOS(Y, 6), _GRIDPOS(Y, 7),
_GRIDPOS(Y, 8), _GRIDPOS(Y, 9), _GRIDPOS(Y, 10), _GRIDPOS(Y, 11),
_GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15)
);
#if DISABLED(DYNAMIC_MARGINS)
const float
unified_bed_leveling::_mesh_index_to_xpos[GRID_MAX_POINTS_X] PROGMEM = ARRAY_N(GRID_MAX_POINTS_X,
_GRIDPOS(X, 0), _GRIDPOS(X, 1), _GRIDPOS(X, 2), _GRIDPOS(X, 3),
_GRIDPOS(X, 4), _GRIDPOS(X, 5), _GRIDPOS(X, 6), _GRIDPOS(X, 7),
_GRIDPOS(X, 8), _GRIDPOS(X, 9), _GRIDPOS(X, 10), _GRIDPOS(X, 11),
_GRIDPOS(X, 12), _GRIDPOS(X, 13), _GRIDPOS(X, 14), _GRIDPOS(X, 15)
),
unified_bed_leveling::_mesh_index_to_ypos[GRID_MAX_POINTS_Y] PROGMEM = ARRAY_N(GRID_MAX_POINTS_Y,
_GRIDPOS(Y, 0), _GRIDPOS(Y, 1), _GRIDPOS(Y, 2), _GRIDPOS(Y, 3),
_GRIDPOS(Y, 4), _GRIDPOS(Y, 5), _GRIDPOS(Y, 6), _GRIDPOS(Y, 7),
_GRIDPOS(Y, 8), _GRIDPOS(Y, 9), _GRIDPOS(Y, 10), _GRIDPOS(Y, 11),
_GRIDPOS(Y, 12), _GRIDPOS(Y, 13), _GRIDPOS(Y, 14), _GRIDPOS(Y, 15)
);
#endif

volatile int16_t unified_bed_leveling::encoder_diff;

Expand Down Expand Up @@ -174,8 +178,8 @@ void unified_bed_leveling::display_map(const uint8_t map_type) {
SERIAL_ECHOPGM("\nBed Topography Report");
if (human) {
SERIAL_ECHOLNPGM(":\n");
serial_echo_xy(4, MESH_MIN_X, MESH_MAX_Y);
serial_echo_xy(twixt, MESH_MAX_X, MESH_MAX_Y);
serial_echo_xy(4, (TERN(DYNAMIC_MARGINS, unified_bed_leveling::margin_l, MESH_MIN_X)), (TERN(DYNAMIC_MARGINS, (Y_BED_SIZE - unified_bed_leveling::margin_f), MESH_MAX_Y)));
serial_echo_xy(twixt, (TERN(DYNAMIC_MARGINS, (X_BED_SIZE - unified_bed_leveling::margin_r), MESH_MAX_X)), (TERN(DYNAMIC_MARGINS, (Y_BED_SIZE - unified_bed_leveling::margin_f), MESH_MAX_Y)));
SERIAL_EOL();
serial_echo_column_labels(eachsp - 2);
}
Expand Down Expand Up @@ -232,8 +236,8 @@ void unified_bed_leveling::display_map(const uint8_t map_type) {
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_echo_xy(4, (TERN(DYNAMIC_MARGINS, unified_bed_leveling::margin_l, MESH_MIN_X)), (TERN(DYNAMIC_MARGINS, unified_bed_leveling::margin_l, MESH_MIN_Y)));
serial_echo_xy(twixt, (TERN(DYNAMIC_MARGINS, (X_BED_SIZE - unified_bed_leveling::margin_r), MESH_MAX_X)), (TERN(DYNAMIC_MARGINS, unified_bed_leveling::margin_l, MESH_MIN_Y)));
SERIAL_EOL();
SERIAL_EOL();
}
Expand Down
74 changes: 51 additions & 23 deletions Marlin/src/feature/bedlevel/ubl/ubl.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
#include "../../../core/debug_out.h"

#if ENABLED(DYNAMIC_MARGINS)
class unified_bed_leveling;
extern unified_bed_leveling bedlevel;
#endif
#define UBL_VERSION "1.01"
#define UBL_OK false
#define UBL_ERR true
Expand All @@ -37,9 +41,10 @@ enum MeshPointType : char { INVALID, REAL, SET_IN_BITMAP, CLOSEST };
// External references

struct mesh_index_pair;

#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X))
#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y))
#if DISABLED(DYNAMIC_MARGINS)
#define MESH_X_DIST (float((MESH_MAX_X) - (MESH_MIN_X)) / (GRID_MAX_CELLS_X))
#define MESH_Y_DIST (float((MESH_MAX_Y) - (MESH_MIN_Y)) / (GRID_MAX_CELLS_Y))
#endif

#if ENABLED(OPTIMIZED_MESH_STORAGE)
typedef int16_t mesh_store_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
Expand Down Expand Up @@ -110,14 +115,20 @@ class unified_bed_leveling {
static void smart_fill_wlsf(const_float_t ) __O2; // O2 gives smaller code than Os on A2560

static int8_t storage_slot;
#if ENABLED(DYNAMIC_MARGINS)
typedef float bed_mesh_t[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
static int16_t margin_l, margin_r, margin_f, margin_b;
#endif

static bed_mesh_t z_values;
#if ENABLED(OPTIMIZED_MESH_STORAGE)
static void set_store_from_mesh(const bed_mesh_t &in_values, mesh_store_t &stored_values);
static void set_mesh_from_store(const mesh_store_t &stored_values, bed_mesh_t &out_values);
#endif
static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X],
_mesh_index_to_ypos[GRID_MAX_POINTS_Y];
#if DISABLED(DYNAMIC_MARGINS)
static const float _mesh_index_to_xpos[GRID_MAX_POINTS_X],
_mesh_index_to_ypos[GRID_MAX_POINTS_Y];
#endif

#if HAS_MARLINUI_MENU
static bool lcd_map_control;
Expand All @@ -133,12 +144,12 @@ class unified_bed_leveling {
FORCE_INLINE static void set_z(const int8_t px, const int8_t py, const_float_t z) { z_values[px][py] = z; }

static int8_t cell_index_x_raw(const_float_t x) {
return FLOOR((x - (MESH_MIN_X)) * RECIPROCAL(MESH_X_DIST));
return FLOOR((x - (TERN(DYNAMIC_MARGINS, bedlevel.margin_l, MESH_MIN_X))) * TERN(DYNAMIC_MARGINS, RECIPROCAL(get_mesh_x_dist()), RECIPROCAL(MESH_X_DIST)));
}

static int8_t cell_index_y_raw(const_float_t y) {
return FLOOR((y - (MESH_MIN_Y)) * RECIPROCAL(MESH_Y_DIST));
}
return FLOOR((y - (TERN(DYNAMIC_MARGINS, bedlevel.margin_f, MESH_MIN_Y))) * TERN(DYNAMIC_MARGINS, RECIPROCAL(get_mesh_y_dist()), RECIPROCAL(MESH_Y_DIST)));
}

static bool cell_index_x_valid(const_float_t x) {
return WITHIN(cell_index_x_raw(x), 0, GRID_MAX_CELLS_X - 1);
Expand All @@ -162,11 +173,11 @@ class unified_bed_leveling {
static xy_uint8_t cell_indexes(const xy_pos_t &xy) { return cell_indexes(xy.x, xy.y); }

static int8_t closest_x_index(const_float_t x) {
const int8_t px = (x - (MESH_MIN_X) + (MESH_X_DIST) * 0.5) * RECIPROCAL(MESH_X_DIST);
const int8_t px = (x - (TERN(DYNAMIC_MARGINS, bedlevel.margin_l, MESH_MIN_X)) + (TERN(DYNAMIC_MARGINS, get_mesh_x_dist(), MESH_X_DIST)) * 0.5) * TERN(DYNAMIC_MARGINS, RECIPROCAL(get_mesh_x_dist()), RECIPROCAL(MESH_X_DIST));
return WITHIN(px, 0, (GRID_MAX_POINTS_X) - 1) ? px : -1;
}
static int8_t closest_y_index(const_float_t y) {
const int8_t py = (y - (MESH_MIN_Y) + (MESH_Y_DIST) * 0.5) * RECIPROCAL(MESH_Y_DIST);
const int8_t py = (y - (TERN(DYNAMIC_MARGINS, bedlevel.margin_f, MESH_MIN_Y)) + (TERN(DYNAMIC_MARGINS, get_mesh_y_dist(), MESH_Y_DIST)) * 0.5) * TERN(DYNAMIC_MARGINS, RECIPROCAL(get_mesh_y_dist()), RECIPROCAL(MESH_Y_DIST));
return WITHIN(py, 0, (GRID_MAX_POINTS_Y) - 1) ? py : -1;
}
static xy_int8_t closest_indexes(const xy_pos_t &xy) {
Expand Down Expand Up @@ -214,7 +225,7 @@ class unified_bed_leveling {
return _UBL_OUTER_Z_RAISE;
}

const float xratio = (rx0 - get_mesh_x(x1_i)) * RECIPROCAL(MESH_X_DIST),
const float xratio = (rx0 - get_mesh_x(x1_i)) * TERN(DYNAMIC_MARGINS, RECIPROCAL(get_mesh_x_dist()), RECIPROCAL(MESH_X_DIST)),
z1 = z_values[x1_i][yi];

return z1 + xratio * (z_values[_MIN(x1_i, (GRID_MAX_POINTS_X) - 2) + 1][yi] - z1); // Don't allow x1_i+1 to be past the end of the array
Expand All @@ -237,7 +248,7 @@ class unified_bed_leveling {
return _UBL_OUTER_Z_RAISE;
}

const float yratio = (ry0 - get_mesh_y(y1_i)) * RECIPROCAL(MESH_Y_DIST),
const float yratio = (ry0 - get_mesh_y(y1_i)) * TERN(DYNAMIC_MARGINS, RECIPROCAL(get_mesh_y_dist()), RECIPROCAL(MESH_Y_DIST)),
z1 = z_values[xi][y1_i];

return z1 + yratio * (z_values[xi][_MIN(y1_i, (GRID_MAX_POINTS_Y) - 2) + 1] - z1); // Don't allow y1_i+1 to be past the end of the array
Expand All @@ -259,12 +270,12 @@ class unified_bed_leveling {
* UBL_Z_RAISE_WHEN_OFF_MESH is specified, that value is returned.
*/
#ifdef UBL_Z_RAISE_WHEN_OFF_MESH
if (!WITHIN(rx0, MESH_MIN_X, MESH_MAX_X) || !WITHIN(ry0, MESH_MIN_Y, MESH_MAX_Y))
if (!WITHIN(rx0, TERN(DYNAMIC_MARGINS, bedlevel.margin_l, MESH_MIN_X), TERN(DYNAMIC_MARGINS, X_BED_SIZE - bedlevel.margin_r, MESH_MAX_X)) || !WITHIN(ry0, TERN(DYNAMIC_MARGINS, bedlevel.margin_f, MESH_MIN_Y), TERN(DYNAMIC_MARGINS, Y_BED_SIZE - bedlevel.margin_b, MESH_MAX_Y)))
return UBL_Z_RAISE_WHEN_OFF_MESH;
#endif

const uint8_t mx = _MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1, my = _MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1;
const float x0 = get_mesh_x(cx), x1 = get_mesh_x(cx + 1),
IF_DISABLED(DYNAMIC_MARGINS, const) uint8_t mx = _MIN(cx, (GRID_MAX_POINTS_X) - 2) + 1, my = _MIN(cy, (GRID_MAX_POINTS_Y) - 2) + 1;
IF_DISABLED(DYNAMIC_MARGINS, const) float x0 = get_mesh_x(cx), x1 = get_mesh_x(cx + 1),
z1 = calc_z0(rx0, x0, z_values[cx][cy], x1, z_values[mx][cy]),
z2 = calc_z0(rx0, x0, z_values[cx][my], x1, z_values[mx][my]);
float z0 = calc_z0(ry0, get_mesh_y(cy), z1, get_mesh_y(cy + 1), z2);
Expand All @@ -286,13 +297,28 @@ class unified_bed_leveling {
static float get_z_correction(const xy_pos_t &pos) { return get_z_correction(pos.x, pos.y); }

static constexpr float get_z_offset() { return 0.0f; }

static float get_mesh_x(const uint8_t i) {
return i < (GRID_MAX_POINTS_X) ? pgm_read_float(&_mesh_index_to_xpos[i]) : MESH_MIN_X + i * (MESH_X_DIST);
}
static float get_mesh_y(const uint8_t i) {
return i < (GRID_MAX_POINTS_Y) ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST);
}
#if DISABLED(DYNAMIC_MARGINS)
static float get_mesh_x(const uint8_t i) {
return i < (GRID_MAX_POINTS_X) ? pgm_read_float(&_mesh_index_to_xpos[i]) : MESH_MIN_X + i * (MESH_X_DIST);
}
static float get_mesh_y(const uint8_t i) {
return i < (GRID_MAX_POINTS_Y) ? pgm_read_float(&_mesh_index_to_ypos[i]) : MESH_MIN_Y + i * (MESH_Y_DIST);
}
#endif
#if ENABLED(DYNAMIC_MARGINS)
static float get_mesh_x(const uint8_t i) {
return bedlevel.margin_l + i * get_mesh_x_dist();
}
static float get_mesh_y(const uint8_t i) {
return bedlevel.margin_f + i * get_mesh_y_dist();
}
static float get_mesh_x_dist() {
return float((X_BED_SIZE - bedlevel.margin_r) - bedlevel.margin_l) / (GRID_MAX_POINTS_X - 1);
}
static float get_mesh_y_dist() {
return float((Y_BED_SIZE - bedlevel.margin_b) - bedlevel.margin_f) / (GRID_MAX_POINTS_Y - 1);
}
#endif

#if UBL_SEGMENTED
static bool line_to_destination_segmented(const_feedRate_t scaled_fr_mm_s);
Expand All @@ -307,7 +333,9 @@ class unified_bed_leveling {

}; // class unified_bed_leveling

extern unified_bed_leveling bedlevel;
#if DISABLED(DYNAMIC_MARGINS)
extern unified_bed_leveling bedlevel;
#endif

// Prevent debugging propagating to other files
#include "../../../core/debug_out.h"
Loading