Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

X-Axis twist compensation. Software fix using a mesh for z-probe-offset #23167

Closed
16 changes: 16 additions & 0 deletions Marlin/Configuration_adv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,22 @@
// Set a convenient position to do the calibration (probing point and nozzle/bed-distance)
//#define PROBE_OFFSET_WIZARD_XY_POS { X_CENTER, Y_CENTER }
#endif

#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
// Enable to use a mesh for the Z-offset instead of a fixed Z-offset.
//#define PROBE_OFFSET_MESH
#if ENABLED(PROBE_OFFSET_MESH)
//
// Enable to init the Probe Z-Offset when starting the Wizard.
// Use a height slightly above the estimated nozzle-to-probe Z offset.
// For example, with an offset of -5, consider a starting height of -4.
//
#define PROBE_OFFSET_MESH_START_Z 0.0
// Set the number of grid points per dimension.
#define PROBE_OFFSET_MESH_GRID_MAX_POINTS_X 3
#define PROBE_OFFSET_MESH_GRID_MAX_POINTS_Y PROBE_OFFSET_MESH_GRID_MAX_POINTS_X
#endif
#endif
#endif

// Include a page of printer information in the LCD Main Menu
Expand Down
138 changes: 138 additions & 0 deletions Marlin/src/feature/bedlevel/abl/probe_offset_mesh.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/

#include "../../../inc/MarlinConfigPre.h"

#if ENABLED(PROBE_OFFSET_MESH)

#include "../../../module/planner.h"
#include "../bedlevel.h"
#include "probe_offset_mesh.h"

probe_offset_mesh_t z_offset_mesh;
xy_pos_t z_offset_mesh_grid_spacing;
xy_float_t z_offset_mesh_grid_factor;

void print_z_offset_grid() {
SERIAL_ECHOLNPGM("Z-Offset Grid:");
print_2d_array(PROBE_OFFSET_MESH_GRID_MAX_POINTS_X, PROBE_OFFSET_MESH_GRID_MAX_POINTS_Y, 3,
[](const uint8_t ix, const uint8_t iy) { return z_offset_mesh[ix][iy]; }
);
}


#define POM_BG_SPACING(A) z_offset_mesh_grid_spacing.A
#define POM_BG_FACTOR(A) z_offset_mesh_grid_factor.A
#define POM_BG_POINTS_X GRID_MAX_POINTS_X
#define POM_BG_POINTS_Y GRID_MAX_POINTS_Y
#define POM_BG_GRID(X,Y) z_offset_mesh[X][Y]

// Refresh after other values have been updated
void refresh_probe_offset_mesh() {
z_offset_mesh_grid_factor = z_offset_mesh_grid_spacing.reciprocal();
}

// Get the Z adjustment for non-linear bed leveling
float z_offset_mesh_from_raw_position(const xy_pos_t &raw) {

static float z1, d2, z3, d4, L, D;

static xy_pos_t prev { -999.999, -999.999 }, ratio;

// Whole units for the grid line indices. Constrained within bounds.
static xy_int8_t thisg, nextg, lastg { -99, -99 };

// XY relative to the probed area
xy_pos_t rel = raw - bilinear_start.asFloat();

#if ENABLED(EXTRAPOLATE_BEYOND_GRID)
#define FAR_EDGE_OR_BOX 2 // Keep using the last grid box
#else
#define FAR_EDGE_OR_BOX 1 // Just use the grid far edge
#endif

if (prev.x != rel.x) {
prev.x = rel.x;
ratio.x = rel.x * POM_BG_FACTOR(x);
const float gx = constrain(FLOOR(ratio.x), 0, POM_BG_POINTS_X - (FAR_EDGE_OR_BOX));
ratio.x -= gx; // Subtract whole to get the ratio within the grid box

#if DISABLED(EXTRAPOLATE_BEYOND_GRID)
// Beyond the grid maintain height at grid edges
NOLESS(ratio.x, 0); // Never <0 (>1 is ok when nextg.x==thisg.x)
#endif

thisg.x = gx;
nextg.x = _MIN(thisg.x + 1, POM_BG_POINTS_X - 1);
}

if (prev.y != rel.y || lastg.x != thisg.x) {

if (prev.y != rel.y) {
prev.y = rel.y;
ratio.y = rel.y * POM_BG_FACTOR(y);
const float gy = constrain(FLOOR(ratio.y), 0, POM_BG_POINTS_Y - (FAR_EDGE_OR_BOX));
ratio.y -= gy;

#if DISABLED(EXTRAPOLATE_BEYOND_GRID)
// Beyond the grid maintain height at grid edges
NOLESS(ratio.y, 0); // Never < 0.0. (> 1.0 is ok when nextg.y==thisg.y.)
#endif

thisg.y = gy;
nextg.y = _MIN(thisg.y + 1, POM_BG_POINTS_Y - 1);
}

if (lastg != thisg) {
lastg = thisg;
// Z at the box corners
z1 = POM_BG_GRID(thisg.x, thisg.y); // left-front
d2 = POM_BG_GRID(thisg.x, nextg.y) - z1; // left-back (delta)
z3 = POM_BG_GRID(nextg.x, thisg.y); // right-front
d4 = POM_BG_GRID(nextg.x, nextg.y) - z3; // right-back (delta)
}

// Bilinear interpolate. Needed since rel.y or thisg.x has changed.
L = z1 + d2 * ratio.y; // Linear interp. LF -> LB
const float R = z3 + d4 * ratio.y; // Linear interp. RF -> RB

D = R - L;
}

const float offset = L + ratio.x * D; // the offset almost always changes

/*
static float last_offset = 0;
if (ABS(last_offset - offset) > 0.2) {
SERIAL_ECHOLNPGM("Sudden Shift at x=", rel.x, " / ", bilinear_grid_spacing.x, " -> thisg.x=", thisg.x);
SERIAL_ECHOLNPGM(" y=", rel.y, " / ", bilinear_grid_spacing.y, " -> thisg.y=", thisg.y);
SERIAL_ECHOLNPGM(" ratio.x=", ratio.x, " ratio.y=", ratio.y);
SERIAL_ECHOLNPGM(" z1=", z1, " z2=", z2, " z3=", z3, " z4=", z4);
SERIAL_ECHOLNPGM(" L=", L, " R=", R, " offset=", offset);
}
last_offset = offset;
//*/

return offset;
}

#endif //PROBE_OFFSET_MESH
33 changes: 33 additions & 0 deletions Marlin/src/feature/bedlevel/abl/probe_offset_mesh.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once

#include "../../../inc/MarlinConfigPre.h"

typedef float probe_offset_mesh_t[PROBE_OFFSET_MESH_GRID_MAX_POINTS_X][PROBE_OFFSET_MESH_GRID_MAX_POINTS_Y];
extern probe_offset_mesh_t z_offset_mesh;
extern xy_pos_t z_offset_mesh_grid_spacing;
extern xy_float_t z_offset_mesh_grid_factor;

float z_offset_mesh_from_raw_position(const xy_pos_t &raw);
void refresh_probe_offset_mesh();
void print_z_offset_grid();
3 changes: 3 additions & 0 deletions Marlin/src/feature/bedlevel/bedlevel.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class TemporaryBedLevelingState {

#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
#include "abl/abl.h"
#if ENABLED(PROBE_OFFSET_MESH)
#include "abl/probe_offset_mesh.h"
#endif
#elif ENABLED(AUTO_BED_LEVELING_UBL)
#include "ubl/ubl.h"
#elif ENABLED(MESH_BED_LEVELING)
Expand Down
3 changes: 3 additions & 0 deletions Marlin/src/lcd/language/language_en.h
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,9 @@ namespace Language_en {
LSTR MSG_PROBE_WIZARD_PROBING = _UxGT("Probing Z Reference");
LSTR MSG_PROBE_WIZARD_MOVING = _UxGT("Moving to Probing Pos");

LSTR MSG_PROBE_MESH = _UxGT("Probe Offset Mesh Wizard");
LSTR MSG_PROBE_MESH_DONE = _UxGT("Offset Mesh Created!");

LSTR MSG_SOUND = _UxGT("Sound");

LSTR MSG_TOP_LEFT = _UxGT("Top Left");
Expand Down
2 changes: 1 addition & 1 deletion Marlin/src/lcd/marlinui.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,7 @@ class MarlinUI {
//
// Special handling if a move is underway
//
#if ANY(DELTA_CALIBRATION_MENU, DELTA_AUTO_CALIBRATION, PROBE_OFFSET_WIZARD) || (ENABLED(LCD_BED_LEVELING) && EITHER(PROBE_MANUALLY, MESH_BED_LEVELING))
#if ANY(DELTA_CALIBRATION_MENU, DELTA_AUTO_CALIBRATION, PROBE_OFFSET_WIZARD, PROBE_OFFSET_MESH) || (ENABLED(LCD_BED_LEVELING) && EITHER(PROBE_MANUALLY, MESH_BED_LEVELING))
#define LCD_HAS_WAIT_FOR_MOVE 1
static bool wait_for_move;
#else
Expand Down
5 changes: 5 additions & 0 deletions Marlin/src/lcd/menu/menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ void _lcd_draw_homing();
void goto_probe_offset_wizard();
#endif

#if ENABLED(PROBE_OFFSET_MESH)
void _lcd_probe_offset_mesh_continue();
void menu_advanced_settings();
#endif

#if ENABLED(LCD_BED_LEVELING) || (HAS_LEVELING && DISABLED(SLIM_LCD_MENUS))
void _lcd_toggle_bed_leveling();
#endif
Expand Down
4 changes: 4 additions & 0 deletions Marlin/src/lcd/menu/menu_advanced.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,10 @@ void menu_backlash();
SUBMENU(MSG_PROBE_WIZARD, goto_probe_offset_wizard);
#endif

#if ENABLED(PROBE_OFFSET_MESH)
SUBMENU(MSG_PROBE_MESH, _lcd_probe_offset_mesh_continue);
#endif

END_MENU();
}
#endif
Expand Down
Loading