Consolidate "bedlevel" code
This commit is contained in:
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
void gcode_G26() {
|
||||
|
||||
ubl.G26();
|
||||
|
||||
}
|
@ -20,12 +20,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
|
||||
#include "../gcode.h"
|
||||
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/endstops.h"
|
||||
|
||||
#if HOTENDS > 1
|
||||
#include "../control/tool_change.h"
|
||||
#include "../../module/tool_change.h"
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
#include "../../lcd/ultralcd.h"
|
||||
|
||||
#if ENABLED(QUICK_HOME)
|
||||
|
||||
static void quick_home_xy() {
|
||||
@ -126,11 +137,11 @@
|
||||
* Z Home to the Z endstop
|
||||
*
|
||||
*/
|
||||
void gcode_G28(const bool always_home_all) {
|
||||
void GcodeSuite::G28(const bool always_home_all) {
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOLNPGM(">>> gcode_G28");
|
||||
SERIAL_ECHOLNPGM(">>> G28");
|
||||
log_machine_info();
|
||||
}
|
||||
#endif
|
||||
@ -288,7 +299,7 @@ void gcode_G28(const bool always_home_all) {
|
||||
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
|
||||
#endif // !DELTA (gcode_G28)
|
||||
#endif // !DELTA (G28)
|
||||
|
||||
endstops.not_homing();
|
||||
|
||||
@ -319,6 +330,6 @@ void gcode_G28(const bool always_home_all) {
|
||||
report_current_position();
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< gcode_G28");
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< G28");
|
||||
#endif
|
||||
}
|
@ -1,946 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ABL_GRID
|
||||
#if ENABLED(PROBE_Y_FIRST)
|
||||
#define PR_OUTER_VAR xCount
|
||||
#define PR_OUTER_END abl_grid_points_x
|
||||
#define PR_INNER_VAR yCount
|
||||
#define PR_INNER_END abl_grid_points_y
|
||||
#else
|
||||
#define PR_OUTER_VAR yCount
|
||||
#define PR_OUTER_END abl_grid_points_y
|
||||
#define PR_INNER_VAR xCount
|
||||
#define PR_INNER_END abl_grid_points_x
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* G29: Detailed Z probe, probes the bed at 3 or more points.
|
||||
* Will fail if the printer has not been homed with G28.
|
||||
*
|
||||
* Enhanced G29 Auto Bed Leveling Probe Routine
|
||||
*
|
||||
* D Dry-Run mode. Just evaluate the bed Topology - Don't apply
|
||||
* or alter the bed level data. Useful to check the topology
|
||||
* after a first run of G29.
|
||||
*
|
||||
* J Jettison current bed leveling data
|
||||
*
|
||||
* V Set the verbose level (0-4). Example: "G29 V3"
|
||||
*
|
||||
* Parameters With LINEAR leveling only:
|
||||
*
|
||||
* P Set the size of the grid that will be probed (P x P points).
|
||||
* Example: "G29 P4"
|
||||
*
|
||||
* X Set the X size of the grid that will be probed (X x Y points).
|
||||
* Example: "G29 X7 Y5"
|
||||
*
|
||||
* Y Set the Y size of the grid that will be probed (X x Y points).
|
||||
*
|
||||
* T Generate a Bed Topology Report. Example: "G29 P5 T" for a detailed report.
|
||||
* This is useful for manual bed leveling and finding flaws in the bed (to
|
||||
* assist with part placement).
|
||||
* Not supported by non-linear delta printer bed leveling.
|
||||
*
|
||||
* Parameters With LINEAR and BILINEAR leveling only:
|
||||
*
|
||||
* S Set the XY travel speed between probe points (in units/min)
|
||||
*
|
||||
* F Set the Front limit of the probing grid
|
||||
* B Set the Back limit of the probing grid
|
||||
* L Set the Left limit of the probing grid
|
||||
* R Set the Right limit of the probing grid
|
||||
*
|
||||
* Parameters with DEBUG_LEVELING_FEATURE only:
|
||||
*
|
||||
* C Make a totally fake grid with no actual probing.
|
||||
* For use in testing when no probing is possible.
|
||||
*
|
||||
* Parameters with BILINEAR leveling only:
|
||||
*
|
||||
* Z Supply an additional Z probe offset
|
||||
*
|
||||
* Extra parameters with PROBE_MANUALLY:
|
||||
*
|
||||
* To do manual probing simply repeat G29 until the procedure is complete.
|
||||
* The first G29 accepts parameters. 'G29 Q' for status, 'G29 A' to abort.
|
||||
*
|
||||
* Q Query leveling and G29 state
|
||||
*
|
||||
* A Abort current leveling procedure
|
||||
*
|
||||
* Extra parameters with BILINEAR only:
|
||||
*
|
||||
* W Write a mesh point. (If G29 is idle.)
|
||||
* I X index for mesh point
|
||||
* J Y index for mesh point
|
||||
* X X for mesh point, overrides I
|
||||
* Y Y for mesh point, overrides J
|
||||
* Z Z for mesh point. Otherwise, raw current Z.
|
||||
*
|
||||
* Without PROBE_MANUALLY:
|
||||
*
|
||||
* E By default G29 will engage the Z probe, test the bed, then disengage.
|
||||
* Include "E" to engage/disengage the Z probe for each sample.
|
||||
* There's no extra effect if you have a fixed Z probe.
|
||||
*
|
||||
*/
|
||||
void gcode_G29() {
|
||||
|
||||
// G29 Q is also available if debugging
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
const bool query = parser.seen('Q');
|
||||
const uint8_t old_debug_flags = marlin_debug_flags;
|
||||
if (query) marlin_debug_flags |= DEBUG_LEVELING;
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
DEBUG_POS(">>> gcode_G29", current_position);
|
||||
log_machine_info();
|
||||
}
|
||||
marlin_debug_flags = old_debug_flags;
|
||||
#if DISABLED(PROBE_MANUALLY)
|
||||
if (query) return;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
const bool seenA = parser.seen('A'), seenQ = parser.seen('Q'), no_action = seenA || seenQ;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE) && DISABLED(PROBE_MANUALLY)
|
||||
const bool faux = parser.boolval('C');
|
||||
#elif ENABLED(PROBE_MANUALLY)
|
||||
const bool faux = no_action;
|
||||
#else
|
||||
bool constexpr faux = false;
|
||||
#endif
|
||||
|
||||
// Don't allow auto-leveling without homing first
|
||||
if (axis_unhomed_error()) return;
|
||||
|
||||
// Define local vars 'static' for manual probing, 'auto' otherwise
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
#define ABL_VAR static
|
||||
#else
|
||||
#define ABL_VAR
|
||||
#endif
|
||||
|
||||
ABL_VAR int verbose_level;
|
||||
ABL_VAR float xProbe, yProbe, measured_z;
|
||||
ABL_VAR bool dryrun, abl_should_enable;
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY) || ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
ABL_VAR int abl_probe_index;
|
||||
#endif
|
||||
|
||||
#if HAS_SOFTWARE_ENDSTOPS && ENABLED(PROBE_MANUALLY)
|
||||
ABL_VAR bool enable_soft_endstops = true;
|
||||
#endif
|
||||
|
||||
#if ABL_GRID
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
ABL_VAR uint8_t PR_OUTER_VAR;
|
||||
ABL_VAR int8_t PR_INNER_VAR;
|
||||
#endif
|
||||
|
||||
ABL_VAR int left_probe_bed_position, right_probe_bed_position, front_probe_bed_position, back_probe_bed_position;
|
||||
ABL_VAR float xGridSpacing = 0, yGridSpacing = 0;
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
ABL_VAR uint8_t abl_grid_points_x = GRID_MAX_POINTS_X,
|
||||
abl_grid_points_y = GRID_MAX_POINTS_Y;
|
||||
ABL_VAR bool do_topography_map;
|
||||
#else // Bilinear
|
||||
uint8_t constexpr abl_grid_points_x = GRID_MAX_POINTS_X,
|
||||
abl_grid_points_y = GRID_MAX_POINTS_Y;
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR) || ENABLED(PROBE_MANUALLY)
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
ABL_VAR int abl2;
|
||||
#else // Bilinear
|
||||
int constexpr abl2 = GRID_MAX_POINTS;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
ABL_VAR float zoffset;
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
|
||||
ABL_VAR int indexIntoAB[GRID_MAX_POINTS_X][GRID_MAX_POINTS_Y];
|
||||
|
||||
ABL_VAR float eqnAMatrix[GRID_MAX_POINTS * 3], // "A" matrix of the linear system of equations
|
||||
eqnBVector[GRID_MAX_POINTS], // "B" vector of Z points
|
||||
mean;
|
||||
#endif
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_3POINT)
|
||||
|
||||
int constexpr abl2 = 3;
|
||||
|
||||
// Probe at 3 arbitrary points
|
||||
ABL_VAR vector_3 points[3] = {
|
||||
vector_3(ABL_PROBE_PT_1_X, ABL_PROBE_PT_1_Y, 0),
|
||||
vector_3(ABL_PROBE_PT_2_X, ABL_PROBE_PT_2_Y, 0),
|
||||
vector_3(ABL_PROBE_PT_3_X, ABL_PROBE_PT_3_Y, 0)
|
||||
};
|
||||
|
||||
#endif // AUTO_BED_LEVELING_3POINT
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
struct linear_fit_data lsf_results;
|
||||
incremental_LSF_reset(&lsf_results);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* On the initial G29 fetch command parameters.
|
||||
*/
|
||||
if (!g29_in_progress) {
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY) || ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
abl_probe_index = -1;
|
||||
#endif
|
||||
|
||||
abl_should_enable = leveling_is_active();
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
if (parser.seen('W')) {
|
||||
if (!leveling_is_valid()) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM("No bilinear grid");
|
||||
return;
|
||||
}
|
||||
|
||||
const float z = parser.floatval('Z', RAW_CURRENT_POSITION(Z));
|
||||
if (!WITHIN(z, -10, 10)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM("Bad Z value");
|
||||
return;
|
||||
}
|
||||
|
||||
const float x = parser.floatval('X', NAN),
|
||||
y = parser.floatval('Y', NAN);
|
||||
int8_t i = parser.byteval('I', -1),
|
||||
j = parser.byteval('J', -1);
|
||||
|
||||
if (!isnan(x) && !isnan(y)) {
|
||||
// Get nearest i / j from x / y
|
||||
i = (x - LOGICAL_X_POSITION(bilinear_start[X_AXIS]) + 0.5 * xGridSpacing) / xGridSpacing;
|
||||
j = (y - LOGICAL_Y_POSITION(bilinear_start[Y_AXIS]) + 0.5 * yGridSpacing) / yGridSpacing;
|
||||
i = constrain(i, 0, GRID_MAX_POINTS_X - 1);
|
||||
j = constrain(j, 0, GRID_MAX_POINTS_Y - 1);
|
||||
}
|
||||
if (WITHIN(i, 0, GRID_MAX_POINTS_X - 1) && WITHIN(j, 0, GRID_MAX_POINTS_Y)) {
|
||||
set_bed_leveling_enabled(false);
|
||||
z_values[i][j] = z;
|
||||
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
|
||||
bed_level_virt_interpolate();
|
||||
#endif
|
||||
set_bed_leveling_enabled(abl_should_enable);
|
||||
}
|
||||
return;
|
||||
} // parser.seen('W')
|
||||
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
|
||||
// Jettison bed leveling data
|
||||
if (parser.seen('J')) {
|
||||
reset_bed_level();
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
verbose_level = parser.intval('V');
|
||||
if (!WITHIN(verbose_level, 0, 4)) {
|
||||
SERIAL_PROTOCOLLNPGM("?(V)erbose level is implausible (0-4).");
|
||||
return;
|
||||
}
|
||||
|
||||
dryrun = parser.boolval('D')
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
|| no_action
|
||||
#endif
|
||||
;
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
|
||||
do_topography_map = verbose_level > 2 || parser.boolval('T');
|
||||
|
||||
// X and Y specify points in each direction, overriding the default
|
||||
// These values may be saved with the completed mesh
|
||||
abl_grid_points_x = parser.intval('X', GRID_MAX_POINTS_X);
|
||||
abl_grid_points_y = parser.intval('Y', GRID_MAX_POINTS_Y);
|
||||
if (parser.seenval('P')) abl_grid_points_x = abl_grid_points_y = parser.value_int();
|
||||
|
||||
if (abl_grid_points_x < 2 || abl_grid_points_y < 2) {
|
||||
SERIAL_PROTOCOLLNPGM("?Number of probe points is implausible (2 minimum).");
|
||||
return;
|
||||
}
|
||||
|
||||
abl2 = abl_grid_points_x * abl_grid_points_y;
|
||||
mean = 0;
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
zoffset = parser.linearval('Z');
|
||||
|
||||
#endif
|
||||
|
||||
#if ABL_GRID
|
||||
|
||||
xy_probe_feedrate_mm_s = MMM_TO_MMS(parser.linearval('S', XY_PROBE_SPEED));
|
||||
|
||||
left_probe_bed_position = (int)parser.linearval('L', LOGICAL_X_POSITION(LEFT_PROBE_BED_POSITION));
|
||||
right_probe_bed_position = (int)parser.linearval('R', LOGICAL_X_POSITION(RIGHT_PROBE_BED_POSITION));
|
||||
front_probe_bed_position = (int)parser.linearval('F', LOGICAL_Y_POSITION(FRONT_PROBE_BED_POSITION));
|
||||
back_probe_bed_position = (int)parser.linearval('B', LOGICAL_Y_POSITION(BACK_PROBE_BED_POSITION));
|
||||
|
||||
const bool left_out_l = left_probe_bed_position < LOGICAL_X_POSITION(MIN_PROBE_X),
|
||||
left_out = left_out_l || left_probe_bed_position > right_probe_bed_position - (MIN_PROBE_EDGE),
|
||||
right_out_r = right_probe_bed_position > LOGICAL_X_POSITION(MAX_PROBE_X),
|
||||
right_out = right_out_r || right_probe_bed_position < left_probe_bed_position + MIN_PROBE_EDGE,
|
||||
front_out_f = front_probe_bed_position < LOGICAL_Y_POSITION(MIN_PROBE_Y),
|
||||
front_out = front_out_f || front_probe_bed_position > back_probe_bed_position - (MIN_PROBE_EDGE),
|
||||
back_out_b = back_probe_bed_position > LOGICAL_Y_POSITION(MAX_PROBE_Y),
|
||||
back_out = back_out_b || back_probe_bed_position < front_probe_bed_position + MIN_PROBE_EDGE;
|
||||
|
||||
if (left_out || right_out || front_out || back_out) {
|
||||
if (left_out) {
|
||||
out_of_range_error(PSTR("(L)eft"));
|
||||
left_probe_bed_position = left_out_l ? LOGICAL_X_POSITION(MIN_PROBE_X) : right_probe_bed_position - (MIN_PROBE_EDGE);
|
||||
}
|
||||
if (right_out) {
|
||||
out_of_range_error(PSTR("(R)ight"));
|
||||
right_probe_bed_position = right_out_r ? LOGICAL_Y_POSITION(MAX_PROBE_X) : left_probe_bed_position + MIN_PROBE_EDGE;
|
||||
}
|
||||
if (front_out) {
|
||||
out_of_range_error(PSTR("(F)ront"));
|
||||
front_probe_bed_position = front_out_f ? LOGICAL_Y_POSITION(MIN_PROBE_Y) : back_probe_bed_position - (MIN_PROBE_EDGE);
|
||||
}
|
||||
if (back_out) {
|
||||
out_of_range_error(PSTR("(B)ack"));
|
||||
back_probe_bed_position = back_out_b ? LOGICAL_Y_POSITION(MAX_PROBE_Y) : front_probe_bed_position + MIN_PROBE_EDGE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// probe at the points of a lattice grid
|
||||
xGridSpacing = (right_probe_bed_position - left_probe_bed_position) / (abl_grid_points_x - 1);
|
||||
yGridSpacing = (back_probe_bed_position - front_probe_bed_position) / (abl_grid_points_y - 1);
|
||||
|
||||
#endif // ABL_GRID
|
||||
|
||||
if (verbose_level > 0) {
|
||||
SERIAL_PROTOCOLLNPGM("G29 Auto Bed Leveling");
|
||||
if (dryrun) SERIAL_PROTOCOLLNPGM("Running in DRY-RUN mode");
|
||||
}
|
||||
|
||||
stepper.synchronize();
|
||||
|
||||
// Disable auto bed leveling during G29
|
||||
planner.abl_enabled = false;
|
||||
|
||||
if (!dryrun) {
|
||||
// Re-orient the current position without leveling
|
||||
// based on where the steppers are positioned.
|
||||
set_current_from_steppers_for_axis(ALL_AXES);
|
||||
|
||||
// Sync the planner to where the steppers stopped
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
}
|
||||
|
||||
#if HAS_BED_PROBE
|
||||
// Deploy the probe. Probe will raise if needed.
|
||||
if (DEPLOY_PROBE()) {
|
||||
planner.abl_enabled = abl_should_enable;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!faux) setup_for_endstop_or_probe_move();
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
if (!no_action)
|
||||
#endif
|
||||
if ( xGridSpacing != bilinear_grid_spacing[X_AXIS]
|
||||
|| yGridSpacing != bilinear_grid_spacing[Y_AXIS]
|
||||
|| left_probe_bed_position != LOGICAL_X_POSITION(bilinear_start[X_AXIS])
|
||||
|| front_probe_bed_position != LOGICAL_Y_POSITION(bilinear_start[Y_AXIS])
|
||||
) {
|
||||
if (dryrun) {
|
||||
// Before reset bed level, re-enable to correct the position
|
||||
planner.abl_enabled = abl_should_enable;
|
||||
}
|
||||
// Reset grid to 0.0 or "not probed". (Also disables ABL)
|
||||
reset_bed_level();
|
||||
|
||||
// Initialize a grid with the given dimensions
|
||||
bilinear_grid_spacing[X_AXIS] = xGridSpacing;
|
||||
bilinear_grid_spacing[Y_AXIS] = yGridSpacing;
|
||||
bilinear_start[X_AXIS] = RAW_X_POSITION(left_probe_bed_position);
|
||||
bilinear_start[Y_AXIS] = RAW_Y_POSITION(front_probe_bed_position);
|
||||
|
||||
// Can't re-enable (on error) until the new grid is written
|
||||
abl_should_enable = false;
|
||||
}
|
||||
|
||||
#endif // AUTO_BED_LEVELING_BILINEAR
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_3POINT)
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("> 3-point Leveling");
|
||||
#endif
|
||||
|
||||
// Probe at 3 arbitrary points
|
||||
points[0].z = points[1].z = points[2].z = 0;
|
||||
|
||||
#endif // AUTO_BED_LEVELING_3POINT
|
||||
|
||||
} // !g29_in_progress
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
|
||||
// For manual probing, get the next index to probe now.
|
||||
// On the first probe this will be incremented to 0.
|
||||
if (!no_action) {
|
||||
++abl_probe_index;
|
||||
g29_in_progress = true;
|
||||
}
|
||||
|
||||
// Abort current G29 procedure, go back to idle state
|
||||
if (seenA && g29_in_progress) {
|
||||
SERIAL_PROTOCOLLNPGM("Manual G29 aborted");
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
soft_endstops_enabled = enable_soft_endstops;
|
||||
#endif
|
||||
planner.abl_enabled = abl_should_enable;
|
||||
g29_in_progress = false;
|
||||
#if ENABLED(LCD_BED_LEVELING)
|
||||
lcd_wait_for_move = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Query G29 status
|
||||
if (verbose_level || seenQ) {
|
||||
SERIAL_PROTOCOLPGM("Manual G29 ");
|
||||
if (g29_in_progress) {
|
||||
SERIAL_PROTOCOLPAIR("point ", min(abl_probe_index + 1, abl2));
|
||||
SERIAL_PROTOCOLLNPAIR(" of ", abl2);
|
||||
}
|
||||
else
|
||||
SERIAL_PROTOCOLLNPGM("idle");
|
||||
}
|
||||
|
||||
if (no_action) return;
|
||||
|
||||
if (abl_probe_index == 0) {
|
||||
// For the initial G29 save software endstop state
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
enable_soft_endstops = soft_endstops_enabled;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// For G29 after adjusting Z.
|
||||
// Save the previous Z before going to the next point
|
||||
measured_z = current_position[Z_AXIS];
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
|
||||
mean += measured_z;
|
||||
eqnBVector[abl_probe_index] = measured_z;
|
||||
eqnAMatrix[abl_probe_index + 0 * abl2] = xProbe;
|
||||
eqnAMatrix[abl_probe_index + 1 * abl2] = yProbe;
|
||||
eqnAMatrix[abl_probe_index + 2 * abl2] = 1;
|
||||
|
||||
incremental_LSF(&lsf_results, xProbe, yProbe, measured_z);
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
z_values[xCount][yCount] = measured_z + zoffset;
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_PROTOCOLPAIR("Save X", xCount);
|
||||
SERIAL_PROTOCOLPAIR(" Y", yCount);
|
||||
SERIAL_PROTOCOLLNPAIR(" Z", measured_z + zoffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_3POINT)
|
||||
|
||||
points[abl_probe_index].z = measured_z;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// If there's another point to sample, move there with optional lift.
|
||||
//
|
||||
|
||||
#if ABL_GRID
|
||||
|
||||
// Skip any unreachable points
|
||||
while (abl_probe_index < abl2) {
|
||||
|
||||
// Set xCount, yCount based on abl_probe_index, with zig-zag
|
||||
PR_OUTER_VAR = abl_probe_index / PR_INNER_END;
|
||||
PR_INNER_VAR = abl_probe_index - (PR_OUTER_VAR * PR_INNER_END);
|
||||
|
||||
// Probe in reverse order for every other row/column
|
||||
bool zig = (PR_OUTER_VAR & 1); // != ((PR_OUTER_END) & 1);
|
||||
|
||||
if (zig) PR_INNER_VAR = (PR_INNER_END - 1) - PR_INNER_VAR;
|
||||
|
||||
const float xBase = xCount * xGridSpacing + left_probe_bed_position,
|
||||
yBase = yCount * yGridSpacing + front_probe_bed_position;
|
||||
|
||||
xProbe = FLOOR(xBase + (xBase < 0 ? 0 : 0.5));
|
||||
yProbe = FLOOR(yBase + (yBase < 0 ? 0 : 0.5));
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
indexIntoAB[xCount][yCount] = abl_probe_index;
|
||||
#endif
|
||||
|
||||
// Keep looping till a reachable point is found
|
||||
if (position_is_reachable_xy(xProbe, yProbe)) break;
|
||||
++abl_probe_index;
|
||||
}
|
||||
|
||||
// Is there a next point to move to?
|
||||
if (abl_probe_index < abl2) {
|
||||
_manual_goto_xy(xProbe, yProbe); // Can be used here too!
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
// Disable software endstops to allow manual adjustment
|
||||
// If G29 is not completed, they will not be re-enabled
|
||||
soft_endstops_enabled = false;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
// Leveling done! Fall through to G29 finishing code below
|
||||
|
||||
SERIAL_PROTOCOLLNPGM("Grid probing done.");
|
||||
|
||||
// Re-enable software endstops, if needed
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
soft_endstops_enabled = enable_soft_endstops;
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_3POINT)
|
||||
|
||||
// Probe at 3 arbitrary points
|
||||
if (abl_probe_index < 3) {
|
||||
xProbe = LOGICAL_X_POSITION(points[abl_probe_index].x);
|
||||
yProbe = LOGICAL_Y_POSITION(points[abl_probe_index].y);
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
// Disable software endstops to allow manual adjustment
|
||||
// If G29 is not completed, they will not be re-enabled
|
||||
soft_endstops_enabled = false;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
SERIAL_PROTOCOLLNPGM("3-point probing done.");
|
||||
|
||||
// Re-enable software endstops, if needed
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
soft_endstops_enabled = enable_soft_endstops;
|
||||
#endif
|
||||
|
||||
if (!dryrun) {
|
||||
vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
|
||||
if (planeNormal.z < 0) {
|
||||
planeNormal.x *= -1;
|
||||
planeNormal.y *= -1;
|
||||
planeNormal.z *= -1;
|
||||
}
|
||||
planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
|
||||
|
||||
// Can't re-enable (on error) until the new grid is written
|
||||
abl_should_enable = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // AUTO_BED_LEVELING_3POINT
|
||||
|
||||
#else // !PROBE_MANUALLY
|
||||
{
|
||||
const bool stow_probe_after_each = parser.boolval('E');
|
||||
|
||||
measured_z = 0;
|
||||
|
||||
#if ABL_GRID
|
||||
|
||||
bool zig = PR_OUTER_END & 1; // Always end at RIGHT and BACK_PROBE_BED_POSITION
|
||||
|
||||
// Outer loop is Y with PROBE_Y_FIRST disabled
|
||||
for (uint8_t PR_OUTER_VAR = 0; PR_OUTER_VAR < PR_OUTER_END && !isnan(measured_z); PR_OUTER_VAR++) {
|
||||
|
||||
int8_t inStart, inStop, inInc;
|
||||
|
||||
if (zig) { // away from origin
|
||||
inStart = 0;
|
||||
inStop = PR_INNER_END;
|
||||
inInc = 1;
|
||||
}
|
||||
else { // towards origin
|
||||
inStart = PR_INNER_END - 1;
|
||||
inStop = -1;
|
||||
inInc = -1;
|
||||
}
|
||||
|
||||
zig ^= true; // zag
|
||||
|
||||
// Inner loop is Y with PROBE_Y_FIRST enabled
|
||||
for (int8_t PR_INNER_VAR = inStart; PR_INNER_VAR != inStop; PR_INNER_VAR += inInc) {
|
||||
|
||||
float xBase = left_probe_bed_position + xGridSpacing * xCount,
|
||||
yBase = front_probe_bed_position + yGridSpacing * yCount;
|
||||
|
||||
xProbe = FLOOR(xBase + (xBase < 0 ? 0 : 0.5));
|
||||
yProbe = FLOOR(yBase + (yBase < 0 ? 0 : 0.5));
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
indexIntoAB[xCount][yCount] = ++abl_probe_index; // 0...
|
||||
#endif
|
||||
|
||||
#if IS_KINEMATIC
|
||||
// Avoid probing outside the round or hexagonal area
|
||||
if (!position_is_reachable_by_probe_xy(xProbe, yProbe)) continue;
|
||||
#endif
|
||||
|
||||
measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
|
||||
|
||||
if (isnan(measured_z)) {
|
||||
planner.abl_enabled = abl_should_enable;
|
||||
break;
|
||||
}
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
|
||||
mean += measured_z;
|
||||
eqnBVector[abl_probe_index] = measured_z;
|
||||
eqnAMatrix[abl_probe_index + 0 * abl2] = xProbe;
|
||||
eqnAMatrix[abl_probe_index + 1 * abl2] = yProbe;
|
||||
eqnAMatrix[abl_probe_index + 2 * abl2] = 1;
|
||||
|
||||
incremental_LSF(&lsf_results, xProbe, yProbe, measured_z);
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
z_values[xCount][yCount] = measured_z + zoffset;
|
||||
|
||||
#endif
|
||||
|
||||
abl_should_enable = false;
|
||||
idle();
|
||||
|
||||
} // inner
|
||||
} // outer
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_3POINT)
|
||||
|
||||
// Probe at 3 arbitrary points
|
||||
|
||||
for (uint8_t i = 0; i < 3; ++i) {
|
||||
// Retain the last probe position
|
||||
xProbe = LOGICAL_X_POSITION(points[i].x);
|
||||
yProbe = LOGICAL_Y_POSITION(points[i].y);
|
||||
measured_z = faux ? 0.001 * random(-100, 101) : probe_pt(xProbe, yProbe, stow_probe_after_each, verbose_level);
|
||||
if (isnan(measured_z)) {
|
||||
planner.abl_enabled = abl_should_enable;
|
||||
break;
|
||||
}
|
||||
points[i].z = measured_z;
|
||||
}
|
||||
|
||||
if (!dryrun && !isnan(measured_z)) {
|
||||
vector_3 planeNormal = vector_3::cross(points[0] - points[1], points[2] - points[1]).get_normal();
|
||||
if (planeNormal.z < 0) {
|
||||
planeNormal.x *= -1;
|
||||
planeNormal.y *= -1;
|
||||
planeNormal.z *= -1;
|
||||
}
|
||||
planner.bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
|
||||
|
||||
// Can't re-enable (on error) until the new grid is written
|
||||
abl_should_enable = false;
|
||||
}
|
||||
|
||||
#endif // AUTO_BED_LEVELING_3POINT
|
||||
|
||||
// Raise to _Z_CLEARANCE_DEPLOY_PROBE. Stow the probe.
|
||||
if (STOW_PROBE()) {
|
||||
planner.abl_enabled = abl_should_enable;
|
||||
measured_z = NAN;
|
||||
}
|
||||
}
|
||||
#endif // !PROBE_MANUALLY
|
||||
|
||||
//
|
||||
// G29 Finishing Code
|
||||
//
|
||||
// Unless this is a dry run, auto bed leveling will
|
||||
// definitely be enabled after this point.
|
||||
//
|
||||
// If code above wants to continue leveling, it should
|
||||
// return or loop before this point.
|
||||
//
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("> probing complete", current_position);
|
||||
#endif
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY)
|
||||
g29_in_progress = false;
|
||||
#if ENABLED(LCD_BED_LEVELING)
|
||||
lcd_wait_for_move = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Calculate leveling, print reports, correct the position
|
||||
if (!isnan(measured_z)) {
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
if (!dryrun) extrapolate_unprobed_bed_level();
|
||||
print_bilinear_leveling_grid();
|
||||
|
||||
refresh_bed_level();
|
||||
|
||||
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
|
||||
print_bilinear_leveling_grid_virt();
|
||||
#endif
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_LINEAR)
|
||||
|
||||
// For LINEAR leveling calculate matrix, print reports, correct the position
|
||||
|
||||
/**
|
||||
* solve the plane equation ax + by + d = z
|
||||
* A is the matrix with rows [x y 1] for all the probed points
|
||||
* B is the vector of the Z positions
|
||||
* the normal vector to the plane is formed by the coefficients of the
|
||||
* plane equation in the standard form, which is Vx*x+Vy*y+Vz*z+d = 0
|
||||
* so Vx = -a Vy = -b Vz = 1 (we want the vector facing towards positive Z
|
||||
*/
|
||||
float plane_equation_coefficients[3];
|
||||
|
||||
finish_incremental_LSF(&lsf_results);
|
||||
plane_equation_coefficients[0] = -lsf_results.A; // We should be able to eliminate the '-' on these three lines and down below
|
||||
plane_equation_coefficients[1] = -lsf_results.B; // but that is not yet tested.
|
||||
plane_equation_coefficients[2] = -lsf_results.D;
|
||||
|
||||
mean /= abl2;
|
||||
|
||||
if (verbose_level) {
|
||||
SERIAL_PROTOCOLPGM("Eqn coefficients: a: ");
|
||||
SERIAL_PROTOCOL_F(plane_equation_coefficients[0], 8);
|
||||
SERIAL_PROTOCOLPGM(" b: ");
|
||||
SERIAL_PROTOCOL_F(plane_equation_coefficients[1], 8);
|
||||
SERIAL_PROTOCOLPGM(" d: ");
|
||||
SERIAL_PROTOCOL_F(plane_equation_coefficients[2], 8);
|
||||
SERIAL_EOL();
|
||||
if (verbose_level > 2) {
|
||||
SERIAL_PROTOCOLPGM("Mean of sampled points: ");
|
||||
SERIAL_PROTOCOL_F(mean, 8);
|
||||
SERIAL_EOL();
|
||||
}
|
||||
}
|
||||
|
||||
// Create the matrix but don't correct the position yet
|
||||
if (!dryrun)
|
||||
planner.bed_level_matrix = matrix_3x3::create_look_at(
|
||||
vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1) // We can eliminate the '-' here and up above
|
||||
);
|
||||
|
||||
// Show the Topography map if enabled
|
||||
if (do_topography_map) {
|
||||
|
||||
SERIAL_PROTOCOLLNPGM("\nBed Height Topography:\n"
|
||||
" +--- BACK --+\n"
|
||||
" | |\n"
|
||||
" L | (+) | R\n"
|
||||
" E | | I\n"
|
||||
" F | (-) N (+) | G\n"
|
||||
" T | | H\n"
|
||||
" | (-) | T\n"
|
||||
" | |\n"
|
||||
" O-- FRONT --+\n"
|
||||
" (0,0)");
|
||||
|
||||
float min_diff = 999;
|
||||
|
||||
for (int8_t yy = abl_grid_points_y - 1; yy >= 0; yy--) {
|
||||
for (uint8_t xx = 0; xx < abl_grid_points_x; xx++) {
|
||||
int ind = indexIntoAB[xx][yy];
|
||||
float diff = eqnBVector[ind] - mean,
|
||||
x_tmp = eqnAMatrix[ind + 0 * abl2],
|
||||
y_tmp = eqnAMatrix[ind + 1 * abl2],
|
||||
z_tmp = 0;
|
||||
|
||||
apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
|
||||
|
||||
NOMORE(min_diff, eqnBVector[ind] - z_tmp);
|
||||
|
||||
if (diff >= 0.0)
|
||||
SERIAL_PROTOCOLPGM(" +"); // Include + for column alignment
|
||||
else
|
||||
SERIAL_PROTOCOLCHAR(' ');
|
||||
SERIAL_PROTOCOL_F(diff, 5);
|
||||
} // xx
|
||||
SERIAL_EOL();
|
||||
} // yy
|
||||
SERIAL_EOL();
|
||||
|
||||
if (verbose_level > 3) {
|
||||
SERIAL_PROTOCOLLNPGM("\nCorrected Bed Height vs. Bed Topology:");
|
||||
|
||||
for (int8_t yy = abl_grid_points_y - 1; yy >= 0; yy--) {
|
||||
for (uint8_t xx = 0; xx < abl_grid_points_x; xx++) {
|
||||
int ind = indexIntoAB[xx][yy];
|
||||
float x_tmp = eqnAMatrix[ind + 0 * abl2],
|
||||
y_tmp = eqnAMatrix[ind + 1 * abl2],
|
||||
z_tmp = 0;
|
||||
|
||||
apply_rotation_xyz(planner.bed_level_matrix, x_tmp, y_tmp, z_tmp);
|
||||
|
||||
float diff = eqnBVector[ind] - z_tmp - min_diff;
|
||||
if (diff >= 0.0)
|
||||
SERIAL_PROTOCOLPGM(" +");
|
||||
// Include + for column alignment
|
||||
else
|
||||
SERIAL_PROTOCOLCHAR(' ');
|
||||
SERIAL_PROTOCOL_F(diff, 5);
|
||||
} // xx
|
||||
SERIAL_EOL();
|
||||
} // yy
|
||||
SERIAL_EOL();
|
||||
}
|
||||
} //do_topography_map
|
||||
|
||||
#endif // AUTO_BED_LEVELING_LINEAR
|
||||
|
||||
#if ABL_PLANAR
|
||||
|
||||
// For LINEAR and 3POINT leveling correct the current position
|
||||
|
||||
if (verbose_level > 0)
|
||||
planner.bed_level_matrix.debug(PSTR("\n\nBed Level Correction Matrix:"));
|
||||
|
||||
if (!dryrun) {
|
||||
//
|
||||
// Correct the current XYZ position based on the tilted plane.
|
||||
//
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("G29 uncorrected XYZ", current_position);
|
||||
#endif
|
||||
|
||||
float converted[XYZ];
|
||||
COPY(converted, current_position);
|
||||
|
||||
planner.abl_enabled = true;
|
||||
planner.unapply_leveling(converted); // use conversion machinery
|
||||
planner.abl_enabled = false;
|
||||
|
||||
// Use the last measured distance to the bed, if possible
|
||||
if ( NEAR(current_position[X_AXIS], xProbe - (X_PROBE_OFFSET_FROM_EXTRUDER))
|
||||
&& NEAR(current_position[Y_AXIS], yProbe - (Y_PROBE_OFFSET_FROM_EXTRUDER))
|
||||
) {
|
||||
const float simple_z = current_position[Z_AXIS] - measured_z;
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("Z from Probe:", simple_z);
|
||||
SERIAL_ECHOPAIR(" Matrix:", converted[Z_AXIS]);
|
||||
SERIAL_ECHOLNPAIR(" Discrepancy:", simple_z - converted[Z_AXIS]);
|
||||
}
|
||||
#endif
|
||||
converted[Z_AXIS] = simple_z;
|
||||
}
|
||||
|
||||
// The rotated XY and corrected Z are now current_position
|
||||
COPY(current_position, converted);
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("G29 corrected XYZ", current_position);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
|
||||
if (!dryrun) {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("G29 uncorrected Z:", current_position[Z_AXIS]);
|
||||
#endif
|
||||
|
||||
// Unapply the offset because it is going to be immediately applied
|
||||
// and cause compensation movement in Z
|
||||
current_position[Z_AXIS] -= bilinear_z_offset(current_position);
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR(" corrected Z:", current_position[Z_AXIS]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ABL_PLANAR
|
||||
|
||||
#ifdef Z_PROBE_END_SCRIPT
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPAIR("Z Probe End Script: ", Z_PROBE_END_SCRIPT);
|
||||
#endif
|
||||
enqueue_and_echo_commands_P(PSTR(Z_PROBE_END_SCRIPT));
|
||||
stepper.synchronize();
|
||||
#endif
|
||||
|
||||
// Auto Bed Leveling is complete! Enable if possible.
|
||||
planner.abl_enabled = dryrun ? abl_should_enable : true;
|
||||
} // !isnan(measured_z)
|
||||
|
||||
// Restore state after probing
|
||||
if (!faux) clean_up_after_endstop_or_probe_move();
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) SERIAL_ECHOLNPGM("<<< gcode_G29");
|
||||
#endif
|
||||
|
||||
report_current_position();
|
||||
|
||||
KEEPALIVE_STATE(IN_HANDLER);
|
||||
|
||||
if (planner.abl_enabled)
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
}
|
@ -1,202 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../queue.h"
|
||||
|
||||
#include "../../libs/buzzer.h"
|
||||
#include "../../lcd/ultralcd.h"
|
||||
|
||||
// Save 130 bytes with non-duplication of PSTR
|
||||
void echo_not_entered() { SERIAL_PROTOCOLLNPGM(" not entered."); }
|
||||
|
||||
void mbl_mesh_report() {
|
||||
SERIAL_PROTOCOLLNPGM("Num X,Y: " STRINGIFY(GRID_MAX_POINTS_X) "," STRINGIFY(GRID_MAX_POINTS_Y));
|
||||
SERIAL_PROTOCOLPGM("Z offset: "); SERIAL_PROTOCOL_F(mbl.z_offset, 5);
|
||||
SERIAL_PROTOCOLLNPGM("\nMeasured points:");
|
||||
print_2d_array(GRID_MAX_POINTS_X, GRID_MAX_POINTS_Y, 5,
|
||||
[](const uint8_t ix, const uint8_t iy) { return mbl.z_values[ix][iy]; }
|
||||
);
|
||||
}
|
||||
|
||||
void mesh_probing_done() {
|
||||
mbl.set_has_mesh(true);
|
||||
home_all_axes();
|
||||
set_bed_leveling_enabled(true);
|
||||
#if ENABLED(MESH_G28_REST_ORIGIN)
|
||||
current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS);
|
||||
set_destination_to_current();
|
||||
line_to_destination(homing_feedrate(Z_AXIS));
|
||||
stepper.synchronize();
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* G29: Mesh-based Z probe, probes a grid and produces a
|
||||
* mesh to compensate for variable bed height
|
||||
*
|
||||
* Parameters With MESH_BED_LEVELING:
|
||||
*
|
||||
* S0 Produce a mesh report
|
||||
* S1 Start probing mesh points
|
||||
* S2 Probe the next mesh point
|
||||
* S3 Xn Yn Zn.nn Manually modify a single point
|
||||
* S4 Zn.nn Set z offset. Positive away from bed, negative closer to bed.
|
||||
* S5 Reset and disable mesh
|
||||
*
|
||||
* The S0 report the points as below
|
||||
*
|
||||
* +----> X-axis 1-n
|
||||
* |
|
||||
* |
|
||||
* v Y-axis 1-n
|
||||
*
|
||||
*/
|
||||
void gcode_G29() {
|
||||
|
||||
static int mbl_probe_index = -1;
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
static bool enable_soft_endstops;
|
||||
#endif
|
||||
|
||||
const MeshLevelingState state = (MeshLevelingState)parser.byteval('S', (int8_t)MeshReport);
|
||||
if (!WITHIN(state, 0, 5)) {
|
||||
SERIAL_PROTOCOLLNPGM("S out of range (0-5).");
|
||||
return;
|
||||
}
|
||||
|
||||
int8_t px, py;
|
||||
|
||||
switch (state) {
|
||||
case MeshReport:
|
||||
if (leveling_is_valid()) {
|
||||
SERIAL_PROTOCOLLNPAIR("State: ", leveling_is_active() ? MSG_ON : MSG_OFF);
|
||||
mbl_mesh_report();
|
||||
}
|
||||
else
|
||||
SERIAL_PROTOCOLLNPGM("Mesh bed leveling has no data.");
|
||||
break;
|
||||
|
||||
case MeshStart:
|
||||
mbl.reset();
|
||||
mbl_probe_index = 0;
|
||||
enqueue_and_echo_commands_P(PSTR("G28\nG29 S2"));
|
||||
break;
|
||||
|
||||
case MeshNext:
|
||||
if (mbl_probe_index < 0) {
|
||||
SERIAL_PROTOCOLLNPGM("Start mesh probing with \"G29 S1\" first.");
|
||||
return;
|
||||
}
|
||||
// For each G29 S2...
|
||||
if (mbl_probe_index == 0) {
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
// For the initial G29 S2 save software endstop state
|
||||
enable_soft_endstops = soft_endstops_enabled;
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
// For G29 S2 after adjusting Z.
|
||||
mbl.set_zigzag_z(mbl_probe_index - 1, current_position[Z_AXIS]);
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
soft_endstops_enabled = enable_soft_endstops;
|
||||
#endif
|
||||
}
|
||||
// If there's another point to sample, move there with optional lift.
|
||||
if (mbl_probe_index < GRID_MAX_POINTS) {
|
||||
mbl.zigzag(mbl_probe_index, px, py);
|
||||
_manual_goto_xy(mbl.index_to_xpos[px], mbl.index_to_ypos[py]);
|
||||
|
||||
#if HAS_SOFTWARE_ENDSTOPS
|
||||
// Disable software endstops to allow manual adjustment
|
||||
// If G29 is not completed, they will not be re-enabled
|
||||
soft_endstops_enabled = false;
|
||||
#endif
|
||||
|
||||
mbl_probe_index++;
|
||||
}
|
||||
else {
|
||||
// One last "return to the bed" (as originally coded) at completion
|
||||
current_position[Z_AXIS] = LOGICAL_Z_POSITION(Z_MIN_POS) + MANUAL_PROBE_HEIGHT;
|
||||
line_to_current_position();
|
||||
stepper.synchronize();
|
||||
|
||||
// After recording the last point, activate home and activate
|
||||
mbl_probe_index = -1;
|
||||
SERIAL_PROTOCOLLNPGM("Mesh probing done.");
|
||||
BUZZ(100, 659);
|
||||
BUZZ(100, 698);
|
||||
mesh_probing_done();
|
||||
}
|
||||
break;
|
||||
|
||||
case MeshSet:
|
||||
if (parser.seenval('X')) {
|
||||
px = parser.value_int() - 1;
|
||||
if (!WITHIN(px, 0, GRID_MAX_POINTS_X - 1)) {
|
||||
SERIAL_PROTOCOLLNPGM("X out of range (1-" STRINGIFY(GRID_MAX_POINTS_X) ").");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SERIAL_CHAR('X'); echo_not_entered();
|
||||
return;
|
||||
}
|
||||
|
||||
if (parser.seenval('Y')) {
|
||||
py = parser.value_int() - 1;
|
||||
if (!WITHIN(py, 0, GRID_MAX_POINTS_Y - 1)) {
|
||||
SERIAL_PROTOCOLLNPGM("Y out of range (1-" STRINGIFY(GRID_MAX_POINTS_Y) ").");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
SERIAL_CHAR('Y'); echo_not_entered();
|
||||
return;
|
||||
}
|
||||
|
||||
if (parser.seenval('Z')) {
|
||||
mbl.z_values[px][py] = parser.value_linear_units();
|
||||
}
|
||||
else {
|
||||
SERIAL_CHAR('Z'); echo_not_entered();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MeshSetZOffset:
|
||||
if (parser.seenval('Z')) {
|
||||
mbl.z_offset = parser.value_linear_units();
|
||||
}
|
||||
else {
|
||||
SERIAL_CHAR('Z'); echo_not_entered();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MeshReset:
|
||||
reset_bed_level();
|
||||
break;
|
||||
|
||||
} // switch(state)
|
||||
|
||||
report_current_position();
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
void gcode_G29() {
|
||||
|
||||
ubl.G29();
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#if ENABLED(MESH_BED_LEVELING) || ENABLED(PROBE_MANUALLY)
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY) && ENABLED(LCD_BED_LEVELING)
|
||||
extern bool lcd_wait_for_move;
|
||||
#endif
|
||||
|
||||
inline void _manual_goto_xy(const float &x, const float &y) {
|
||||
const float old_feedrate_mm_s = feedrate_mm_s;
|
||||
#if MANUAL_PROBE_HEIGHT > 0
|
||||
const float prev_z = current_position[Z_AXIS];
|
||||
feedrate_mm_s = homing_feedrate(Z_AXIS);
|
||||
current_position[Z_AXIS] = LOGICAL_Z_POSITION(MANUAL_PROBE_HEIGHT);
|
||||
line_to_current_position();
|
||||
#endif
|
||||
|
||||
feedrate_mm_s = MMM_TO_MMS(XY_PROBE_SPEED);
|
||||
current_position[X_AXIS] = LOGICAL_X_POSITION(x);
|
||||
current_position[Y_AXIS] = LOGICAL_Y_POSITION(y);
|
||||
line_to_current_position();
|
||||
|
||||
#if MANUAL_PROBE_HEIGHT > 0
|
||||
feedrate_mm_s = homing_feedrate(Z_AXIS);
|
||||
current_position[Z_AXIS] = prev_z; // move back to the previous Z.
|
||||
line_to_current_position();
|
||||
#endif
|
||||
|
||||
feedrate_mm_s = old_feedrate_mm_s;
|
||||
stepper.synchronize();
|
||||
|
||||
#if ENABLED(PROBE_MANUALLY) && ENABLED(LCD_BED_LEVELING)
|
||||
lcd_wait_for_move = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if ENABLED(MESH_BED_LEVELING)
|
||||
#include "G29-mbl.h"
|
||||
#elif ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
#include "G29-ubl.h"
|
||||
#elif HAS_ABL
|
||||
#include "G29-abl.h"
|
||||
#endif
|
@ -20,10 +20,21 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
|
||||
#if HOTENDS > 1
|
||||
#include "../control/tool_change.h"
|
||||
#if ENABLED(DELTA_AUTO_CALIBRATION)
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/delta.h"
|
||||
#include "../../module/probe.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/endstops.h"
|
||||
#include "../../module/tool_change.h"
|
||||
#include "../../lcd/ultralcd.h"
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -54,7 +65,7 @@
|
||||
* E Engage the probe for each point
|
||||
*/
|
||||
|
||||
void print_signed_float(const char * const prefix, const float &f) {
|
||||
static void print_signed_float(const char * const prefix, const float &f) {
|
||||
SERIAL_PROTOCOLPGM(" ");
|
||||
serialprintPGM(prefix);
|
||||
SERIAL_PROTOCOLCHAR(':');
|
||||
@ -62,12 +73,12 @@ void print_signed_float(const char * const prefix, const float &f) {
|
||||
SERIAL_PROTOCOL_F(f, 2);
|
||||
}
|
||||
|
||||
inline void print_G33_settings(const bool end_stops, const bool tower_angles){ // TODO echo these to LCD ???
|
||||
static void print_G33_settings(const bool end_stops, const bool tower_angles){ // TODO echo these to LCD ???
|
||||
SERIAL_PROTOCOLPAIR(".Height:", DELTA_HEIGHT + home_offset[Z_AXIS]);
|
||||
if (end_stops) {
|
||||
print_signed_float(PSTR(" Ex"), endstop_adj[A_AXIS]);
|
||||
print_signed_float(PSTR("Ey"), endstop_adj[B_AXIS]);
|
||||
print_signed_float(PSTR("Ez"), endstop_adj[C_AXIS]);
|
||||
print_signed_float(PSTR(" Ex"), delta_endstop_adj[A_AXIS]);
|
||||
print_signed_float(PSTR("Ey"), delta_endstop_adj[B_AXIS]);
|
||||
print_signed_float(PSTR("Ez"), delta_endstop_adj[C_AXIS]);
|
||||
SERIAL_PROTOCOLPAIR(" Radius:", delta_radius);
|
||||
}
|
||||
SERIAL_EOL();
|
||||
@ -79,7 +90,7 @@ inline void print_G33_settings(const bool end_stops, const bool tower_angles){ /
|
||||
}
|
||||
}
|
||||
|
||||
void G33_cleanup(
|
||||
static void G33_cleanup(
|
||||
#if HOTENDS > 1
|
||||
const uint8_t old_tool_index
|
||||
#endif
|
||||
@ -94,7 +105,7 @@ void G33_cleanup(
|
||||
#endif
|
||||
}
|
||||
|
||||
void gcode_G33() {
|
||||
void GcodeSuite::G33() {
|
||||
|
||||
const int8_t probe_points = parser.intval('P', DELTA_CALIBRATION_DEFAULT_POINTS);
|
||||
if (!WITHIN(probe_points, 1, 7)) {
|
||||
@ -110,7 +121,7 @@ void gcode_G33() {
|
||||
|
||||
const float calibration_precision = parser.floatval('C');
|
||||
if (calibration_precision < 0) {
|
||||
SERIAL_PROTOCOLLNPGM("?(C)alibration precision is implausible (>0).");
|
||||
SERIAL_PROTOCOLLNPGM("?(C)alibration precision is implausible (>=0).");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,7 +132,6 @@ void gcode_G33() {
|
||||
}
|
||||
|
||||
const bool towers_set = parser.boolval('T', true),
|
||||
stow_after_each = parser.boolval('E'),
|
||||
_1p_calibration = probe_points == 1,
|
||||
_4p_calibration = probe_points == 2,
|
||||
_4p_towers_points = _4p_calibration && towers_set,
|
||||
@ -133,18 +143,24 @@ void gcode_G33() {
|
||||
_7p_quadruple_circle = probe_points == 7,
|
||||
_7p_multi_circle = _7p_double_circle || _7p_triple_circle || _7p_quadruple_circle,
|
||||
_7p_intermed_points = _7p_calibration && !_7p_half_circle;
|
||||
|
||||
#if DISABLED(PROBE_MANUALLY)
|
||||
const bool stow_after_each = parser.boolval('E');
|
||||
const float dx = (X_PROBE_OFFSET_FROM_EXTRUDER),
|
||||
dy = (Y_PROBE_OFFSET_FROM_EXTRUDER);
|
||||
#endif
|
||||
|
||||
const static char save_message[] PROGMEM = "Save with M500 and/or copy to Configuration.h";
|
||||
const float dx = (X_PROBE_OFFSET_FROM_EXTRUDER),
|
||||
dy = (Y_PROBE_OFFSET_FROM_EXTRUDER);
|
||||
|
||||
int8_t iterations = 0;
|
||||
float test_precision,
|
||||
zero_std_dev = (verbose_level ? 999.0 : 0.0), // 0.0 in dry-run mode : forced end
|
||||
zero_std_dev_old = zero_std_dev,
|
||||
zero_std_dev_min = zero_std_dev,
|
||||
e_old[XYZ] = {
|
||||
endstop_adj[A_AXIS],
|
||||
endstop_adj[B_AXIS],
|
||||
endstop_adj[C_AXIS]
|
||||
delta_endstop_adj[A_AXIS],
|
||||
delta_endstop_adj[B_AXIS],
|
||||
delta_endstop_adj[C_AXIS]
|
||||
},
|
||||
dr_old = delta_radius,
|
||||
zh_old = home_offset[Z_AXIS],
|
||||
@ -167,6 +183,7 @@ void gcode_G33() {
|
||||
SERIAL_PROTOCOLLNPGM("G33 Auto Calibrate");
|
||||
|
||||
stepper.synchronize();
|
||||
|
||||
#if HAS_LEVELING
|
||||
reset_bed_level(); // After calibration bed-level data is no longer valid
|
||||
#endif
|
||||
@ -274,7 +291,7 @@ void gcode_G33() {
|
||||
|
||||
if ((zero_std_dev < test_precision && zero_std_dev > calibration_precision) || iterations <= force_iterations) {
|
||||
if (zero_std_dev < zero_std_dev_min) {
|
||||
COPY(e_old, endstop_adj);
|
||||
COPY(e_old, delta_endstop_adj);
|
||||
dr_old = delta_radius;
|
||||
zh_old = home_offset[Z_AXIS];
|
||||
alpha_old = delta_tower_angle_trim[A_AXIS];
|
||||
@ -337,20 +354,20 @@ void gcode_G33() {
|
||||
break;
|
||||
}
|
||||
|
||||
LOOP_XYZ(axis) endstop_adj[axis] += e_delta[axis];
|
||||
LOOP_XYZ(axis) delta_endstop_adj[axis] += e_delta[axis];
|
||||
delta_radius += r_delta;
|
||||
delta_tower_angle_trim[A_AXIS] += t_alpha;
|
||||
delta_tower_angle_trim[B_AXIS] += t_beta;
|
||||
|
||||
// adjust delta_height and endstops by the max amount
|
||||
const float z_temp = MAX3(endstop_adj[A_AXIS], endstop_adj[B_AXIS], endstop_adj[C_AXIS]);
|
||||
const float z_temp = MAX3(delta_endstop_adj[A_AXIS], delta_endstop_adj[B_AXIS], delta_endstop_adj[C_AXIS]);
|
||||
home_offset[Z_AXIS] -= z_temp;
|
||||
LOOP_XYZ(i) endstop_adj[i] -= z_temp;
|
||||
LOOP_XYZ(i) delta_endstop_adj[i] -= z_temp;
|
||||
|
||||
recalc_delta_settings(delta_radius, delta_diagonal_rod);
|
||||
}
|
||||
else if (zero_std_dev >= test_precision) { // step one back
|
||||
COPY(endstop_adj, e_old);
|
||||
COPY(delta_endstop_adj, e_old);
|
||||
delta_radius = dr_old;
|
||||
home_offset[Z_AXIS] = zh_old;
|
||||
delta_tower_angle_trim[A_AXIS] = alpha_old;
|
||||
@ -449,3 +466,5 @@ void gcode_G33() {
|
||||
|
||||
G33_CLEANUP();
|
||||
}
|
||||
|
||||
#endif // DELTA_AUTO_CALIBRATION
|
@ -1,121 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* M420: Enable/Disable Bed Leveling and/or set the Z fade height.
|
||||
*
|
||||
* S[bool] Turns leveling on or off
|
||||
* Z[height] Sets the Z fade height (0 or none to disable)
|
||||
* V[bool] Verbose - Print the leveling grid
|
||||
*
|
||||
* With AUTO_BED_LEVELING_UBL only:
|
||||
*
|
||||
* L[index] Load UBL mesh from index (0 is default)
|
||||
*/
|
||||
void gcode_M420() {
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
|
||||
// L to load a mesh from the EEPROM
|
||||
if (parser.seen('L')) {
|
||||
|
||||
#if ENABLED(EEPROM_SETTINGS)
|
||||
const int8_t storage_slot = parser.has_value() ? parser.value_int() : ubl.state.storage_slot;
|
||||
const int16_t a = settings.calc_num_meshes();
|
||||
|
||||
if (!a) {
|
||||
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!WITHIN(storage_slot, 0, a - 1)) {
|
||||
SERIAL_PROTOCOLLNPGM("?Invalid storage slot.");
|
||||
SERIAL_PROTOCOLLNPAIR("?Use 0 to ", a - 1);
|
||||
return;
|
||||
}
|
||||
|
||||
settings.load_mesh(storage_slot);
|
||||
ubl.state.storage_slot = storage_slot;
|
||||
|
||||
#else
|
||||
|
||||
SERIAL_PROTOCOLLNPGM("?EEPROM storage not available.");
|
||||
return;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
// 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
|
||||
SERIAL_ECHOLNPAIR("UBL_MESH_VALID = ", UBL_MESH_VALID);
|
||||
SERIAL_ECHOLNPAIR("ubl.state.storage_slot = ", ubl.state.storage_slot);
|
||||
}
|
||||
|
||||
#endif // AUTO_BED_LEVELING_UBL
|
||||
|
||||
// V to print the matrix or mesh
|
||||
if (parser.seen('V')) {
|
||||
#if ABL_PLANAR
|
||||
planner.bed_level_matrix.debug(PSTR("Bed Level Correction Matrix:"));
|
||||
#else
|
||||
if (leveling_is_valid()) {
|
||||
#if ENABLED(AUTO_BED_LEVELING_BILINEAR)
|
||||
print_bilinear_leveling_grid();
|
||||
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
|
||||
print_bilinear_leveling_grid_virt();
|
||||
#endif
|
||||
#elif ENABLED(MESH_BED_LEVELING)
|
||||
SERIAL_ECHOLNPGM("Mesh Bed Level data:");
|
||||
mbl_mesh_report();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const bool to_enable = parser.boolval('S');
|
||||
if (parser.seen('S'))
|
||||
set_bed_leveling_enabled(to_enable);
|
||||
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
if (parser.seen('Z')) set_z_fade_height(parser.value_linear_units());
|
||||
#endif
|
||||
|
||||
const bool new_status = leveling_is_active();
|
||||
|
||||
if (to_enable && !new_status) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_M420_FAILED);
|
||||
}
|
||||
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOLNPAIR("Bed Leveling ", new_status ? MSG_ON : MSG_OFF);
|
||||
|
||||
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
|
||||
SERIAL_ECHO_START();
|
||||
SERIAL_ECHOPGM("Fade Height ");
|
||||
if (planner.z_fade_height > 0.0)
|
||||
SERIAL_ECHOLN(planner.z_fade_height);
|
||||
else
|
||||
SERIAL_ECHOLNPGM(MSG_OFF);
|
||||
#endif
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* M421: Set a single Mesh Bed Leveling Z coordinate
|
||||
*
|
||||
* Usage:
|
||||
* M421 I<xindex> J<yindex> Z<linear>
|
||||
* M421 I<xindex> J<yindex> Q<offset>
|
||||
*/
|
||||
void gcode_M421() {
|
||||
int8_t ix = parser.intval('I', -1), iy = parser.intval('J', -1);
|
||||
const bool hasI = ix >= 0,
|
||||
hasJ = iy >= 0,
|
||||
hasZ = parser.seen('Z'),
|
||||
hasQ = !hasZ && parser.seen('Q');
|
||||
|
||||
if (!hasI || !hasJ || !(hasZ || hasQ)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS);
|
||||
}
|
||||
else if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY);
|
||||
}
|
||||
else {
|
||||
z_values[ix][iy] = parser.value_linear_units() + (hasQ ? z_values[ix][iy] : 0);
|
||||
#if ENABLED(ABL_BILINEAR_SUBDIVISION)
|
||||
bed_level_virt_interpolate();
|
||||
#endif
|
||||
}
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* M421: Set a single Mesh Bed Leveling Z coordinate
|
||||
*
|
||||
* Usage:
|
||||
* M421 X<linear> Y<linear> Z<linear>
|
||||
* M421 X<linear> Y<linear> Q<offset>
|
||||
* M421 I<xindex> J<yindex> Z<linear>
|
||||
* M421 I<xindex> J<yindex> Q<offset>
|
||||
*/
|
||||
void gcode_M421() {
|
||||
const bool hasX = parser.seen('X'), hasI = parser.seen('I');
|
||||
const int8_t ix = hasI ? parser.value_int() : hasX ? mbl.probe_index_x(RAW_X_POSITION(parser.value_linear_units())) : -1;
|
||||
const bool hasY = parser.seen('Y'), hasJ = parser.seen('J');
|
||||
const int8_t iy = hasJ ? parser.value_int() : hasY ? mbl.probe_index_y(RAW_Y_POSITION(parser.value_linear_units())) : -1;
|
||||
const bool hasZ = parser.seen('Z'), hasQ = !hasZ && parser.seen('Q');
|
||||
|
||||
if (int(hasI && hasJ) + int(hasX && hasY) != 1 || !(hasZ || hasQ)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS);
|
||||
}
|
||||
else if (ix < 0 || iy < 0) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY);
|
||||
}
|
||||
else
|
||||
mbl.set_z(ix, iy, parser.value_linear_units() + (hasQ ? mbl.z_values[ix][iy] : 0));
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* M421: Set a single Mesh Bed Leveling Z coordinate
|
||||
*
|
||||
* Usage:
|
||||
* M421 I<xindex> J<yindex> Z<linear>
|
||||
* M421 I<xindex> J<yindex> Q<offset>
|
||||
* M421 C Z<linear>
|
||||
* M421 C Q<offset>
|
||||
*/
|
||||
void gcode_M421() {
|
||||
int8_t ix = parser.intval('I', -1), iy = parser.intval('J', -1);
|
||||
const bool hasI = ix >= 0,
|
||||
hasJ = iy >= 0,
|
||||
hasC = parser.seen('C'),
|
||||
hasZ = parser.seen('Z'),
|
||||
hasQ = !hasZ && parser.seen('Q');
|
||||
|
||||
if (hasC) {
|
||||
const mesh_index_pair location = ubl.find_closest_mesh_point_of_type(REAL, current_position[X_AXIS], current_position[Y_AXIS], USE_NOZZLE_AS_REFERENCE, NULL, false);
|
||||
ix = location.x_index;
|
||||
iy = location.y_index;
|
||||
}
|
||||
|
||||
if (int(hasC) + int(hasI && hasJ) != 1 || !(hasZ || hasQ)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_M421_PARAMETERS);
|
||||
}
|
||||
else if (!WITHIN(ix, 0, GRID_MAX_POINTS_X - 1) || !WITHIN(iy, 0, GRID_MAX_POINTS_Y - 1)) {
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_MESH_XY);
|
||||
}
|
||||
else
|
||||
ubl.z_values[ix][iy] = parser.value_linear_units() + (hasQ ? ubl.z_values[ix][iy] : 0);
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
void gcode_M49() {
|
||||
ubl.g26_debug_flag ^= true;
|
||||
SERIAL_PROTOCOLPGM("UBL Debug Flag turned ");
|
||||
serialprintPGM(ubl.g26_debug_flag ? PSTR("on.") : PSTR("off."));
|
||||
}
|
@ -33,11 +33,11 @@
|
||||
#endif
|
||||
LOOP_XYZ(i) {
|
||||
if (parser.seen(axis_codes[i])) {
|
||||
endstop_adj[i] = parser.value_linear_units();
|
||||
delta_endstop_adj[i] = parser.value_linear_units();
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) {
|
||||
SERIAL_ECHOPAIR("endstop_adj[", axis_codes[i]);
|
||||
SERIAL_ECHOLNPAIR("] = ", endstop_adj[i]);
|
||||
SERIAL_ECHOPAIR("delta_endstop_adj[", axis_codes[i]);
|
||||
SERIAL_ECHOLNPAIR("] = ", delta_endstop_adj[i]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -48,9 +48,9 @@
|
||||
}
|
||||
#endif
|
||||
// normalize endstops so all are <=0; set the residue to delta height
|
||||
const float z_temp = MAX3(endstop_adj[A_AXIS], endstop_adj[B_AXIS], endstop_adj[C_AXIS]);
|
||||
const float z_temp = MAX3(delta_endstop_adj[A_AXIS], delta_endstop_adj[B_AXIS], delta_endstop_adj[C_AXIS]);
|
||||
home_offset[Z_AXIS] -= z_temp;
|
||||
LOOP_XYZ(i) endstop_adj[i] -= z_temp;
|
||||
LOOP_XYZ(i) delta_endstop_adj[i] -= z_temp;
|
||||
}
|
||||
|
||||
#elif ENABLED(Z_DUAL_ENDSTOPS) // !DELTA && ENABLED(Z_DUAL_ENDSTOPS)
|
||||
|
@ -1,81 +0,0 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef CALIBRATE_COMMON_H
|
||||
#define CALIBRATE_COMMON_H
|
||||
|
||||
#if ENABLED(DELTA)
|
||||
|
||||
/**
|
||||
* A delta can only safely home all axes at the same time
|
||||
* This is like quick_home_xy() but for 3 towers.
|
||||
*/
|
||||
inline bool home_delta() {
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS(">>> home_delta", current_position);
|
||||
#endif
|
||||
// Init the current position of all carriages to 0,0,0
|
||||
ZERO(current_position);
|
||||
sync_plan_position();
|
||||
|
||||
// Move all carriages together linearly until an endstop is hit.
|
||||
current_position[X_AXIS] = current_position[Y_AXIS] = current_position[Z_AXIS] = (DELTA_HEIGHT + home_offset[Z_AXIS] + 10);
|
||||
feedrate_mm_s = homing_feedrate(X_AXIS);
|
||||
line_to_current_position();
|
||||
stepper.synchronize();
|
||||
|
||||
// If an endstop was not hit, then damage can occur if homing is continued.
|
||||
// This can occur if the delta height (DELTA_HEIGHT + home_offset[Z_AXIS]) is
|
||||
// not set correctly.
|
||||
if (!(Endstops::endstop_hit_bits & (_BV(X_MAX) | _BV(Y_MAX) | _BV(Z_MAX)))) {
|
||||
LCD_MESSAGEPGM(MSG_ERR_HOMING_FAILED);
|
||||
SERIAL_ERROR_START();
|
||||
SERIAL_ERRORLNPGM(MSG_ERR_HOMING_FAILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
endstops.hit_on_purpose(); // clear endstop hit flags
|
||||
|
||||
// At least one carriage has reached the top.
|
||||
// Now re-home each carriage separately.
|
||||
HOMEAXIS(A);
|
||||
HOMEAXIS(B);
|
||||
HOMEAXIS(C);
|
||||
|
||||
// Set all carriages to their home positions
|
||||
// Do this here all at once for Delta, because
|
||||
// XYZ isn't ABC. Applying this per-tower would
|
||||
// give the impression that they are the same.
|
||||
LOOP_XYZ(i) set_axis_is_at_home((AxisEnum)i);
|
||||
|
||||
SYNC_PLAN_POSITION_KINEMATIC();
|
||||
|
||||
#if ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_POS("<<< home_delta", current_position);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // DELTA
|
||||
|
||||
#endif // CALIBRATE_COMMON_H
|
Reference in New Issue
Block a user