Merge upstream changes from Marlin 2.1.1
This commit is contained in:
@@ -24,8 +24,9 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/endstops.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/stepper.h" // for various
|
||||
|
||||
#if HAS_MULTI_HOTEND
|
||||
#include "../../module/tool_change.h"
|
||||
@@ -35,6 +36,10 @@
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(BD_SENSOR)
|
||||
#include "../../feature/bedlevel/bdl/bdl.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
#include "../../feature/tmc_util.h"
|
||||
#endif
|
||||
@@ -51,15 +56,11 @@
|
||||
#include "../../lcd/extui/ui_api.h"
|
||||
#elif ENABLED(DWIN_CREALITY_LCD)
|
||||
#include "../../lcd/e3v2/creality/dwin.h"
|
||||
#elif ENABLED(DWIN_CREALITY_LCD_ENHANCED)
|
||||
#include "../../lcd/e3v2/enhanced/dwin.h"
|
||||
#elif ENABLED(DWIN_LCD_PROUI)
|
||||
#include "../../lcd/e3v2/proui/dwin.h"
|
||||
#endif
|
||||
|
||||
#if HAS_L64XX // set L6470 absolute position registers to counts
|
||||
#include "../../libs/L64XX/L64XX_Marlin.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(LASER_MOVE_G28_OFF)
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
#include "../../feature/spindle_laser.h"
|
||||
#endif
|
||||
|
||||
@@ -76,42 +77,33 @@
|
||||
|
||||
const int x_axis_home_dir = TOOL_X_HOME_DIR(active_extruder);
|
||||
|
||||
const float mlx = max_length(X_AXIS),
|
||||
mly = max_length(Y_AXIS),
|
||||
mlratio = mlx > mly ? mly / mlx : mlx / mly,
|
||||
fr_mm_s = _MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)) * SQRT(sq(mlratio) + 1.0);
|
||||
// Use a higher diagonal feedrate so axes move at homing speed
|
||||
const float minfr = _MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)),
|
||||
fr_mm_s = HYPOT(minfr, minfr);
|
||||
|
||||
#if ENABLED(SENSORLESS_HOMING)
|
||||
sensorless_t stealth_states {
|
||||
tmc_enable_stallguard(stepperX)
|
||||
, tmc_enable_stallguard(stepperY)
|
||||
, false
|
||||
, false
|
||||
#if AXIS_HAS_STALLGUARD(X2)
|
||||
|| tmc_enable_stallguard(stepperX2)
|
||||
#endif
|
||||
, false
|
||||
#if AXIS_HAS_STALLGUARD(Y2)
|
||||
|| tmc_enable_stallguard(stepperY2)
|
||||
#endif
|
||||
NUM_AXIS_LIST(
|
||||
TERN0(X_SENSORLESS, tmc_enable_stallguard(stepperX)),
|
||||
TERN0(Y_SENSORLESS, tmc_enable_stallguard(stepperY)),
|
||||
false, false, false, false
|
||||
)
|
||||
, TERN0(X2_SENSORLESS, tmc_enable_stallguard(stepperX2))
|
||||
, TERN0(Y2_SENSORLESS, tmc_enable_stallguard(stepperY2))
|
||||
};
|
||||
#endif
|
||||
|
||||
do_blocking_move_to_xy(1.5 * mlx * x_axis_home_dir, 1.5 * mly * Y_HOME_DIR, fr_mm_s);
|
||||
do_blocking_move_to_xy(1.5 * max_length(X_AXIS) * x_axis_home_dir, 1.5 * max_length(Y_AXIS) * Y_HOME_DIR, fr_mm_s);
|
||||
|
||||
endstops.validate_homing_move();
|
||||
|
||||
current_position.set(0.0, 0.0);
|
||||
|
||||
#if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT)
|
||||
tmc_disable_stallguard(stepperX, stealth_states.x);
|
||||
tmc_disable_stallguard(stepperY, stealth_states.y);
|
||||
#if AXIS_HAS_STALLGUARD(X2)
|
||||
tmc_disable_stallguard(stepperX2, stealth_states.x2);
|
||||
#endif
|
||||
#if AXIS_HAS_STALLGUARD(Y2)
|
||||
tmc_disable_stallguard(stepperY2, stealth_states.y2);
|
||||
#endif
|
||||
TERN_(X_SENSORLESS, tmc_disable_stallguard(stepperX, stealth_states.x));
|
||||
TERN_(X2_SENSORLESS, tmc_disable_stallguard(stepperX2, stealth_states.x2));
|
||||
TERN_(Y_SENSORLESS, tmc_disable_stallguard(stepperY, stealth_states.y));
|
||||
TERN_(Y2_SENSORLESS, tmc_disable_stallguard(stepperY2, stealth_states.y2));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -156,7 +148,7 @@
|
||||
homeaxis(Z_AXIS);
|
||||
}
|
||||
else {
|
||||
LCD_MESSAGEPGM(MSG_ZPROBE_OUT);
|
||||
LCD_MESSAGE(MSG_ZPROBE_OUT);
|
||||
SERIAL_ECHO_MSG(STR_ZPROBE_OUT_SER);
|
||||
}
|
||||
}
|
||||
@@ -178,7 +170,7 @@
|
||||
motion_state.jerk_state = planner.max_jerk;
|
||||
planner.max_jerk.set(0, 0 OPTARG(DELTA, 0));
|
||||
#endif
|
||||
planner.reset_acceleration_rates();
|
||||
planner.refresh_acceleration_rates();
|
||||
return motion_state;
|
||||
}
|
||||
|
||||
@@ -187,7 +179,7 @@
|
||||
planner.settings.max_acceleration_mm_per_s2[Y_AXIS] = motion_state.acceleration.y;
|
||||
TERN_(DELTA, planner.settings.max_acceleration_mm_per_s2[Z_AXIS] = motion_state.acceleration.z);
|
||||
TERN_(HAS_CLASSIC_JERK, planner.max_jerk = motion_state.jerk_state);
|
||||
planner.reset_acceleration_rates();
|
||||
planner.refresh_acceleration_rates();
|
||||
}
|
||||
|
||||
#endif // IMPROVE_HOMING_RELIABILITY
|
||||
@@ -214,9 +206,14 @@ void GcodeSuite::G28() {
|
||||
DEBUG_SECTION(log_G28, "G28", DEBUGGING(LEVELING));
|
||||
if (DEBUGGING(LEVELING)) log_machine_info();
|
||||
|
||||
TERN_(LASER_MOVE_G28_OFF, cutter.set_inline_enabled(false)); // turn off laser
|
||||
TERN_(BD_SENSOR, bdl.config_state = 0);
|
||||
|
||||
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_HOMING));
|
||||
/**
|
||||
* Set the laser power to false to stop the planner from processing the current power setting.
|
||||
*/
|
||||
#if ENABLED(LASER_FEATURE)
|
||||
planner.laser_inline.status.isPowered = false;
|
||||
#endif
|
||||
|
||||
#if ENABLED(DUAL_X_CARRIAGE)
|
||||
bool IDEX_saved_duplication_state = extruder_duplication_enabled;
|
||||
@@ -225,7 +222,7 @@ void GcodeSuite::G28() {
|
||||
|
||||
#if ENABLED(MARLIN_DEV_MODE)
|
||||
if (parser.seen_test('S')) {
|
||||
LOOP_LINEAR_AXES(a) set_axis_is_at_home((AxisEnum)a);
|
||||
LOOP_NUM_AXES(a) set_axis_is_at_home((AxisEnum)a);
|
||||
sync_plan_position();
|
||||
SERIAL_ECHOLNPGM("Simulated Homing");
|
||||
report_current_position();
|
||||
@@ -239,7 +236,12 @@ void GcodeSuite::G28() {
|
||||
return;
|
||||
}
|
||||
|
||||
TERN_(HAS_DWIN_E3V2_BASIC, DWIN_StartHoming());
|
||||
#if ENABLED(FULL_REPORT_TO_HOST_FEATURE)
|
||||
const M_StateEnum old_grblstate = M_State_grbl;
|
||||
set_and_report_grblstate(M_HOMING);
|
||||
#endif
|
||||
|
||||
TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingStart());
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onHomingStart());
|
||||
|
||||
planner.synchronize(); // Wait for planner moves to finish!
|
||||
@@ -264,38 +266,71 @@ void GcodeSuite::G28() {
|
||||
reset_stepper_timeout();
|
||||
|
||||
#define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT)
|
||||
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z))
|
||||
#if HAS_CURRENT_HOME(X) || HAS_CURRENT_HOME(X2) || HAS_CURRENT_HOME(Y) || HAS_CURRENT_HOME(Y2) || (ENABLED(DELTA) && HAS_CURRENT_HOME(Z)) || HAS_CURRENT_HOME(I) || HAS_CURRENT_HOME(J) || HAS_CURRENT_HOME(K) || HAS_CURRENT_HOME(U) || HAS_CURRENT_HOME(V) || HAS_CURRENT_HOME(W)
|
||||
#define HAS_HOMING_CURRENT 1
|
||||
#endif
|
||||
|
||||
#if HAS_HOMING_CURRENT
|
||||
auto debug_current = [](PGM_P const s, const int16_t a, const int16_t b) {
|
||||
DEBUG_ECHOPGM_P(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b);
|
||||
auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) {
|
||||
DEBUG_ECHOF(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b);
|
||||
};
|
||||
#if HAS_CURRENT_HOME(X)
|
||||
const int16_t tmc_save_current_X = stepperX.getMilliamps();
|
||||
stepperX.rms_current(X_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(PSTR("X"), tmc_save_current_X, X_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_X), tmc_save_current_X, X_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(X2)
|
||||
const int16_t tmc_save_current_X2 = stepperX2.getMilliamps();
|
||||
stepperX2.rms_current(X2_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(PSTR("X2"), tmc_save_current_X2, X2_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_X2), tmc_save_current_X2, X2_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(Y)
|
||||
const int16_t tmc_save_current_Y = stepperY.getMilliamps();
|
||||
stepperY.rms_current(Y_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(PSTR("Y"), tmc_save_current_Y, Y_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y), tmc_save_current_Y, Y_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(Y2)
|
||||
const int16_t tmc_save_current_Y2 = stepperY2.getMilliamps();
|
||||
stepperY2.rms_current(Y2_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(PSTR("Y2"), tmc_save_current_Y2, Y2_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_Y2), tmc_save_current_Y2, Y2_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(Z) && ENABLED(DELTA)
|
||||
const int16_t tmc_save_current_Z = stepperZ.getMilliamps();
|
||||
stepperZ.rms_current(Z_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(PSTR("Z"), tmc_save_current_Z, Z_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_Z), tmc_save_current_Z, Z_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(I)
|
||||
const int16_t tmc_save_current_I = stepperI.getMilliamps();
|
||||
stepperI.rms_current(I_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_I), tmc_save_current_I, I_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(J)
|
||||
const int16_t tmc_save_current_J = stepperJ.getMilliamps();
|
||||
stepperJ.rms_current(J_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_J), tmc_save_current_J, J_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(K)
|
||||
const int16_t tmc_save_current_K = stepperK.getMilliamps();
|
||||
stepperK.rms_current(K_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_K), tmc_save_current_K, K_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(U)
|
||||
const int16_t tmc_save_current_U = stepperU.getMilliamps();
|
||||
stepperU.rms_current(U_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_U), tmc_save_current_U, U_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(V)
|
||||
const int16_t tmc_save_current_V = stepperV.getMilliamps();
|
||||
stepperV.rms_current(V_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_V), tmc_save_current_V, V_CURRENT_HOME);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(W)
|
||||
const int16_t tmc_save_current_W = stepperW.getMilliamps();
|
||||
stepperW.rms_current(W_CURRENT_HOME);
|
||||
if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME);
|
||||
#endif
|
||||
#if SENSORLESS_STALLGUARD_DELAY
|
||||
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -340,23 +375,28 @@ void GcodeSuite::G28() {
|
||||
#define _UNSAFE(A) (homeZ && TERN0(Z_SAFE_HOMING, axes_should_home(_BV(A##_AXIS))))
|
||||
|
||||
const bool homeZ = TERN0(HAS_Z_AXIS, parser.seen_test('Z')),
|
||||
LINEAR_AXIS_LIST( // Other axes should be homed before Z safe-homing
|
||||
NUM_AXIS_LIST( // Other axes should be homed before Z safe-homing
|
||||
needX = _UNSAFE(X), needY = _UNSAFE(Y), needZ = false, // UNUSED
|
||||
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K)
|
||||
needI = _UNSAFE(I), needJ = _UNSAFE(J), needK = _UNSAFE(K),
|
||||
needU = _UNSAFE(U), needV = _UNSAFE(V), needW = _UNSAFE(W)
|
||||
),
|
||||
LINEAR_AXIS_LIST( // Home each axis if needed or flagged
|
||||
NUM_AXIS_LIST( // Home each axis if needed or flagged
|
||||
homeX = needX || parser.seen_test('X'),
|
||||
homeY = needY || parser.seen_test('Y'),
|
||||
homeZZ = homeZ,
|
||||
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME), homeK = needK || parser.seen_test(AXIS6_NAME),
|
||||
homeI = needI || parser.seen_test(AXIS4_NAME), homeJ = needJ || parser.seen_test(AXIS5_NAME),
|
||||
homeK = needK || parser.seen_test(AXIS6_NAME), homeU = needU || parser.seen_test(AXIS7_NAME),
|
||||
homeV = needV || parser.seen_test(AXIS8_NAME), homeW = needW || parser.seen_test(AXIS9_NAME)
|
||||
),
|
||||
home_all = LINEAR_AXIS_GANG( // Home-all if all or none are flagged
|
||||
home_all = NUM_AXIS_GANG( // Home-all if all or none are flagged
|
||||
homeX == homeX, && homeY == homeX, && homeZ == homeX,
|
||||
&& homeI == homeX, && homeJ == homeX, && homeK == homeX
|
||||
&& homeI == homeX, && homeJ == homeX, && homeK == homeX,
|
||||
&& homeU == homeX, && homeV == homeX, && homeW == homeX
|
||||
),
|
||||
LINEAR_AXIS_LIST(
|
||||
NUM_AXIS_LIST(
|
||||
doX = home_all || homeX, doY = home_all || homeY, doZ = home_all || homeZ,
|
||||
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK
|
||||
doI = home_all || homeI, doJ = home_all || homeJ, doK = home_all || homeK,
|
||||
doU = home_all || homeU, doV = home_all || homeV, doW = home_all || homeW
|
||||
);
|
||||
|
||||
#if HAS_Z_AXIS
|
||||
@@ -367,9 +407,10 @@ void GcodeSuite::G28() {
|
||||
|
||||
TERN_(HOME_Z_FIRST, if (doZ) homeaxis(Z_AXIS));
|
||||
|
||||
const float z_homing_height = parser.seenval('R') ? parser.value_linear_units() : Z_HOMING_HEIGHT;
|
||||
const bool seenR = parser.seenval('R');
|
||||
const float z_homing_height = seenR ? parser.value_linear_units() : Z_HOMING_HEIGHT;
|
||||
|
||||
if (z_homing_height && (LINEAR_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK))) {
|
||||
if (z_homing_height && (seenR || NUM_AXIS_GANG(doX, || doY, || TERN0(Z_SAFE_HOMING, doZ), || doI, || doJ, || doK, || doU, || doV, || doW))) {
|
||||
// Raise Z before homing any other axes and z is not already high enough (never lower z)
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Raise Z (before homing) by ", z_homing_height);
|
||||
do_z_clearance(z_homing_height);
|
||||
@@ -409,33 +450,51 @@ void GcodeSuite::G28() {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BOTH(FOAMCUTTER_XYUV, HAS_I_AXIS)
|
||||
// Home I (after X)
|
||||
if (doI) homeaxis(I_AXIS);
|
||||
#endif
|
||||
|
||||
// Home Y (after X)
|
||||
if (DISABLED(HOME_Y_BEFORE_X) && doY)
|
||||
homeaxis(Y_AXIS);
|
||||
|
||||
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
|
||||
|
||||
// Home Z last if homing towards the bed
|
||||
#if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST)
|
||||
if (doZ) {
|
||||
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
|
||||
stepper.set_all_z_lock(false);
|
||||
stepper.set_separate_multi_axis(false);
|
||||
#endif
|
||||
|
||||
TERN(Z_SAFE_HOMING, home_z_safely(), homeaxis(Z_AXIS));
|
||||
probe.move_z_after_homing();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINEAR_AXES >= 4
|
||||
if (doI) homeaxis(I_AXIS);
|
||||
#endif
|
||||
#if LINEAR_AXES >= 5
|
||||
#if BOTH(FOAMCUTTER_XYUV, HAS_J_AXIS)
|
||||
// Home J (after Y)
|
||||
if (doJ) homeaxis(J_AXIS);
|
||||
#endif
|
||||
#if LINEAR_AXES >= 6
|
||||
if (doK) homeaxis(K_AXIS);
|
||||
|
||||
TERN_(IMPROVE_HOMING_RELIABILITY, end_slow_homing(saved_motion_state));
|
||||
|
||||
#if ENABLED(FOAMCUTTER_XYUV)
|
||||
// skip homing of unused Z axis for foamcutters
|
||||
if (doZ) set_axis_is_at_home(Z_AXIS);
|
||||
#else
|
||||
// Home Z last if homing towards the bed
|
||||
#if HAS_Z_AXIS && DISABLED(HOME_Z_FIRST)
|
||||
if (doZ) {
|
||||
#if EITHER(Z_MULTI_ENDSTOPS, Z_STEPPER_AUTO_ALIGN)
|
||||
stepper.set_all_z_lock(false);
|
||||
stepper.set_separate_multi_axis(false);
|
||||
#endif
|
||||
|
||||
#if ENABLED(Z_SAFE_HOMING)
|
||||
if (TERN1(POWER_LOSS_RECOVERY, !parser.seen_test('H'))) home_z_safely(); else homeaxis(Z_AXIS);
|
||||
#else
|
||||
homeaxis(Z_AXIS);
|
||||
#endif
|
||||
probe.move_z_after_homing();
|
||||
}
|
||||
#endif
|
||||
|
||||
SECONDARY_AXIS_CODE(
|
||||
if (doI) homeaxis(I_AXIS),
|
||||
if (doJ) homeaxis(J_AXIS),
|
||||
if (doK) homeaxis(K_AXIS),
|
||||
if (doU) homeaxis(U_AXIS),
|
||||
if (doV) homeaxis(V_AXIS),
|
||||
if (doW) homeaxis(W_AXIS)
|
||||
);
|
||||
#endif
|
||||
|
||||
sync_plan_position();
|
||||
@@ -519,34 +578,30 @@ void GcodeSuite::G28() {
|
||||
#if HAS_CURRENT_HOME(K)
|
||||
stepperK.rms_current(tmc_save_current_K);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(U)
|
||||
stepperU.rms_current(tmc_save_current_U);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(V)
|
||||
stepperV.rms_current(tmc_save_current_V);
|
||||
#endif
|
||||
#if HAS_CURRENT_HOME(W)
|
||||
stepperW.rms_current(tmc_save_current_W);
|
||||
#endif
|
||||
#if SENSORLESS_STALLGUARD_DELAY
|
||||
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
|
||||
#endif
|
||||
#endif // HAS_HOMING_CURRENT
|
||||
|
||||
ui.refresh();
|
||||
|
||||
TERN_(HAS_DWIN_E3V2_BASIC, DWIN_CompletedHoming());
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onHomingComplete());
|
||||
TERN_(HAS_DWIN_E3V2_BASIC, DWIN_HomingDone());
|
||||
TERN_(EXTENSIBLE_UI, ExtUI::onHomingDone());
|
||||
|
||||
report_current_position();
|
||||
|
||||
if (ENABLED(NANODLP_Z_SYNC) && (doZ || ENABLED(NANODLP_ALL_AXIS)))
|
||||
SERIAL_ECHOLNPGM(STR_Z_MOVE_COMP);
|
||||
|
||||
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE));
|
||||
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(old_grblstate));
|
||||
|
||||
#if HAS_L64XX
|
||||
// Set L6470 absolute position registers to counts
|
||||
// constexpr *might* move this to PROGMEM.
|
||||
// If not, this will need a PROGMEM directive and an accessor.
|
||||
#define _EN_ITEM(N) , E_AXIS
|
||||
static constexpr AxisEnum L64XX_axis_xref[MAX_L64XX] = {
|
||||
LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS),
|
||||
X_AXIS, Y_AXIS, Z_AXIS, Z_AXIS, Z_AXIS
|
||||
REPEAT(E_STEPPERS, _EN_ITEM)
|
||||
};
|
||||
#undef _EN_ITEM
|
||||
for (uint8_t j = 1; j <= L64XX::chain[0]; j++) {
|
||||
const uint8_t cv = L64XX::chain[j];
|
||||
L64xxManager.set_param((L64XX_axis_t)cv, L6470_ABS_POS, stepper.position(L64XX_axis_xref[cv]));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include "../gcode.h"
|
||||
#include "../../module/delta.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/endstops.h"
|
||||
#include "../../lcd/marlinui.h"
|
||||
|
||||
@@ -69,13 +69,11 @@ enum CalEnum : char { // the 7 main calibration points -
|
||||
|
||||
float lcd_probe_pt(const xy_pos_t &xy);
|
||||
|
||||
float dcr;
|
||||
|
||||
void ac_home() {
|
||||
endstops.enable(true);
|
||||
TERN_(SENSORLESS_HOMING, probe.set_homing_current(true));
|
||||
TERN_(SENSORLESS_HOMING, endstops.set_homing_current(true));
|
||||
home_delta();
|
||||
TERN_(SENSORLESS_HOMING, probe.set_homing_current(false));
|
||||
TERN_(SENSORLESS_HOMING, endstops.set_homing_current(false));
|
||||
endstops.not_homing();
|
||||
}
|
||||
|
||||
@@ -97,12 +95,10 @@ void ac_cleanup(TERN_(HAS_MULTI_HOTEND, const uint8_t old_tool_index)) {
|
||||
TERN_(HAS_MULTI_HOTEND, tool_change(old_tool_index, true));
|
||||
}
|
||||
|
||||
void print_signed_float(PGM_P const prefix, const_float_t f) {
|
||||
void print_signed_float(FSTR_P const prefix, const_float_t f) {
|
||||
SERIAL_ECHOPGM(" ");
|
||||
SERIAL_ECHOPGM_P(prefix);
|
||||
SERIAL_CHAR(':');
|
||||
if (f >= 0) SERIAL_CHAR('+');
|
||||
SERIAL_ECHO_F(f, 2);
|
||||
SERIAL_ECHOF(prefix, AS_CHAR(':'));
|
||||
serial_offset(f);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,24 +107,23 @@ void print_signed_float(PGM_P const prefix, const_float_t f) {
|
||||
static void print_calibration_settings(const bool end_stops, const bool tower_angles) {
|
||||
SERIAL_ECHOPGM(".Height:", delta_height);
|
||||
if (end_stops) {
|
||||
print_signed_float(PSTR("Ex"), delta_endstop_adj.a);
|
||||
print_signed_float(PSTR("Ey"), delta_endstop_adj.b);
|
||||
print_signed_float(PSTR("Ez"), delta_endstop_adj.c);
|
||||
print_signed_float(F("Ex"), delta_endstop_adj.a);
|
||||
print_signed_float(F("Ey"), delta_endstop_adj.b);
|
||||
print_signed_float(F("Ez"), delta_endstop_adj.c);
|
||||
}
|
||||
if (end_stops && tower_angles) {
|
||||
SERIAL_ECHOPGM(" Radius:", delta_radius);
|
||||
SERIAL_EOL();
|
||||
SERIAL_ECHOLNPGM(" Radius:", delta_radius);
|
||||
SERIAL_CHAR('.');
|
||||
SERIAL_ECHO_SP(13);
|
||||
}
|
||||
if (tower_angles) {
|
||||
print_signed_float(PSTR("Tx"), delta_tower_angle_trim.a);
|
||||
print_signed_float(PSTR("Ty"), delta_tower_angle_trim.b);
|
||||
print_signed_float(PSTR("Tz"), delta_tower_angle_trim.c);
|
||||
print_signed_float(F("Tx"), delta_tower_angle_trim.a);
|
||||
print_signed_float(F("Ty"), delta_tower_angle_trim.b);
|
||||
print_signed_float(F("Tz"), delta_tower_angle_trim.c);
|
||||
}
|
||||
if ((!end_stops && tower_angles) || (end_stops && !tower_angles)) { // XOR
|
||||
if (end_stops != tower_angles)
|
||||
SERIAL_ECHOPGM(" Radius:", delta_radius);
|
||||
}
|
||||
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
@@ -137,11 +132,11 @@ static void print_calibration_settings(const bool end_stops, const bool tower_an
|
||||
*/
|
||||
static void print_calibration_results(const float z_pt[NPP + 1], const bool tower_points, const bool opposite_points) {
|
||||
SERIAL_ECHOPGM(". ");
|
||||
print_signed_float(PSTR("c"), z_pt[CEN]);
|
||||
print_signed_float(F("c"), z_pt[CEN]);
|
||||
if (tower_points) {
|
||||
print_signed_float(PSTR(" x"), z_pt[__A]);
|
||||
print_signed_float(PSTR(" y"), z_pt[__B]);
|
||||
print_signed_float(PSTR(" z"), z_pt[__C]);
|
||||
print_signed_float(F(" x"), z_pt[__A]);
|
||||
print_signed_float(F(" y"), z_pt[__B]);
|
||||
print_signed_float(F(" z"), z_pt[__C]);
|
||||
}
|
||||
if (tower_points && opposite_points) {
|
||||
SERIAL_EOL();
|
||||
@@ -149,9 +144,9 @@ static void print_calibration_results(const float z_pt[NPP + 1], const bool towe
|
||||
SERIAL_ECHO_SP(13);
|
||||
}
|
||||
if (opposite_points) {
|
||||
print_signed_float(PSTR("yz"), z_pt[_BC]);
|
||||
print_signed_float(PSTR("zx"), z_pt[_CA]);
|
||||
print_signed_float(PSTR("xy"), z_pt[_AB]);
|
||||
print_signed_float(F("yz"), z_pt[_BC]);
|
||||
print_signed_float(F("zx"), z_pt[_CA]);
|
||||
print_signed_float(F("xy"), z_pt[_AB]);
|
||||
}
|
||||
SERIAL_EOL();
|
||||
}
|
||||
@@ -179,7 +174,7 @@ static float std_dev_points(float z_pt[NPP + 1], const bool _0p_cal, const bool
|
||||
*/
|
||||
static float calibration_probe(const xy_pos_t &xy, const bool stow, const bool probe_at_offset) {
|
||||
#if HAS_BED_PROBE
|
||||
return probe.probe_at_point(xy, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, true, probe_at_offset);
|
||||
return probe.probe_at_point(xy, stow ? PROBE_PT_STOW : PROBE_PT_RAISE, 0, probe_at_offset, false);
|
||||
#else
|
||||
UNUSED(stow);
|
||||
return lcd_probe_pt(xy);
|
||||
@@ -189,7 +184,7 @@ static float calibration_probe(const xy_pos_t &xy, const bool stow, const bool p
|
||||
/**
|
||||
* - Probe a grid
|
||||
*/
|
||||
static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_points, const bool towers_set, const bool stow_after_each, const bool probe_at_offset) {
|
||||
static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_points, const float dcr, const bool towers_set, const bool stow_after_each, const bool probe_at_offset) {
|
||||
const bool _0p_calibration = probe_points == 0,
|
||||
_1p_calibration = probe_points == 1 || probe_points == -1,
|
||||
_4p_calibration = probe_points == 2,
|
||||
@@ -273,7 +268,7 @@ static bool probe_calibration_points(float z_pt[NPP + 1], const int8_t probe_poi
|
||||
* - formulae for approximative forward kinematics in the end-stop displacement matrix
|
||||
* - definition of the matrix scaling parameters
|
||||
*/
|
||||
static void reverse_kinematics_probe_points(float z_pt[NPP + 1], abc_float_t mm_at_pt_axis[NPP + 1]) {
|
||||
static void reverse_kinematics_probe_points(float z_pt[NPP + 1], abc_float_t mm_at_pt_axis[NPP + 1], const float dcr) {
|
||||
xyz_pos_t pos{0};
|
||||
|
||||
LOOP_CAL_ALL(rad) {
|
||||
@@ -285,7 +280,7 @@ static void reverse_kinematics_probe_points(float z_pt[NPP + 1], abc_float_t mm_
|
||||
}
|
||||
}
|
||||
|
||||
static void forward_kinematics_probe_points(abc_float_t mm_at_pt_axis[NPP + 1], float z_pt[NPP + 1]) {
|
||||
static void forward_kinematics_probe_points(abc_float_t mm_at_pt_axis[NPP + 1], float z_pt[NPP + 1], const float dcr) {
|
||||
const float r_quot = dcr / delta_radius;
|
||||
|
||||
#define ZPP(N,I,A) (((1.0f + r_quot * (N)) / 3.0f) * mm_at_pt_axis[I].A)
|
||||
@@ -304,19 +299,19 @@ static void forward_kinematics_probe_points(abc_float_t mm_at_pt_axis[NPP + 1],
|
||||
z_pt[_AB] = Zp1(_AB, a) + Zp1(_AB, b) + Zm2(_AB, c);
|
||||
}
|
||||
|
||||
static void calc_kinematics_diff_probe_points(float z_pt[NPP + 1], abc_float_t delta_e, const float delta_r, abc_float_t delta_t) {
|
||||
static void calc_kinematics_diff_probe_points(float z_pt[NPP + 1], const float dcr, abc_float_t delta_e, const float delta_r, abc_float_t delta_t) {
|
||||
const float z_center = z_pt[CEN];
|
||||
abc_float_t diff_mm_at_pt_axis[NPP + 1], new_mm_at_pt_axis[NPP + 1];
|
||||
|
||||
reverse_kinematics_probe_points(z_pt, diff_mm_at_pt_axis);
|
||||
reverse_kinematics_probe_points(z_pt, diff_mm_at_pt_axis, dcr);
|
||||
|
||||
delta_radius += delta_r;
|
||||
delta_tower_angle_trim += delta_t;
|
||||
recalc_delta_settings();
|
||||
reverse_kinematics_probe_points(z_pt, new_mm_at_pt_axis);
|
||||
reverse_kinematics_probe_points(z_pt, new_mm_at_pt_axis, dcr);
|
||||
|
||||
LOOP_CAL_ALL(rad) diff_mm_at_pt_axis[rad] -= new_mm_at_pt_axis[rad] + delta_e;
|
||||
forward_kinematics_probe_points(diff_mm_at_pt_axis, z_pt);
|
||||
forward_kinematics_probe_points(diff_mm_at_pt_axis, z_pt, dcr);
|
||||
|
||||
LOOP_CAL_RAD(rad) z_pt[rad] -= z_pt[CEN] - z_center;
|
||||
z_pt[CEN] = z_center;
|
||||
@@ -326,31 +321,31 @@ static void calc_kinematics_diff_probe_points(float z_pt[NPP + 1], abc_float_t d
|
||||
recalc_delta_settings();
|
||||
}
|
||||
|
||||
static float auto_tune_h() {
|
||||
static float auto_tune_h(const float dcr) {
|
||||
const float r_quot = dcr / delta_radius;
|
||||
return RECIPROCAL(r_quot / (2.0f / 3.0f)); // (2/3)/CR
|
||||
}
|
||||
|
||||
static float auto_tune_r() {
|
||||
static float auto_tune_r(const float dcr) {
|
||||
constexpr float diff = 0.01f, delta_r = diff;
|
||||
float r_fac = 0.0f, z_pt[NPP + 1] = { 0.0f };
|
||||
abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f };
|
||||
|
||||
calc_kinematics_diff_probe_points(z_pt, delta_e, delta_r, delta_t);
|
||||
calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t);
|
||||
r_fac = -(z_pt[__A] + z_pt[__B] + z_pt[__C] + z_pt[_BC] + z_pt[_CA] + z_pt[_AB]) / 6.0f;
|
||||
r_fac = diff / r_fac / 3.0f; // 1/(3*delta_Z)
|
||||
return r_fac;
|
||||
}
|
||||
|
||||
static float auto_tune_a() {
|
||||
static float auto_tune_a(const float dcr) {
|
||||
constexpr float diff = 0.01f, delta_r = 0.0f;
|
||||
float a_fac = 0.0f, z_pt[NPP + 1] = { 0.0f };
|
||||
abc_float_t delta_e = { 0.0f }, delta_t = { 0.0f };
|
||||
|
||||
delta_t.reset();
|
||||
LOOP_LINEAR_AXES(axis) {
|
||||
LOOP_NUM_AXES(axis) {
|
||||
delta_t[axis] = diff;
|
||||
calc_kinematics_diff_probe_points(z_pt, delta_e, delta_r, delta_t);
|
||||
calc_kinematics_diff_probe_points(z_pt, dcr, delta_e, delta_r, delta_t);
|
||||
delta_t[axis] = 0;
|
||||
a_fac += z_pt[uint8_t((axis * _4P_STEP) - _7P_STEP + NPP) % NPP + 1] / 6.0f;
|
||||
a_fac -= z_pt[uint8_t((axis * _4P_STEP) + 1 + _7P_STEP)] / 6.0f;
|
||||
@@ -372,7 +367,7 @@ static float auto_tune_a() {
|
||||
* P3 Probe all positions: center, towers and opposite towers. Calibrate all.
|
||||
* P4-P10 Probe all positions at different intermediate locations and average them.
|
||||
*
|
||||
* Rn.nn override default calibration Radius
|
||||
* Rn.nn Temporary reduce the probe grid by the specified amount (mm)
|
||||
*
|
||||
* T Don't calibrate tower angle corrections
|
||||
*
|
||||
@@ -388,13 +383,15 @@ static float auto_tune_a() {
|
||||
*
|
||||
* E Engage the probe for each point
|
||||
*
|
||||
* O Probe at offset points (this is wrong but it seems to work)
|
||||
* O Probe at offsetted probe positions (this is wrong but it seems to work)
|
||||
*
|
||||
* With SENSORLESS_PROBING:
|
||||
* Use these flags to calibrate stall sensitivity: (e.g., `G33 P1 Y Z` to calibrate X only.)
|
||||
* X Don't activate stallguard on X.
|
||||
* Y Don't activate stallguard on Y.
|
||||
* Z Don't activate stallguard on Z.
|
||||
*
|
||||
* S Save offset_sensorless_adj
|
||||
*/
|
||||
void GcodeSuite::G33() {
|
||||
|
||||
@@ -406,27 +403,18 @@ void GcodeSuite::G33() {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool probe_at_offset = TERN0(HAS_PROBE_XY_OFFSET, parser.boolval('O')),
|
||||
const bool probe_at_offset = TERN0(HAS_PROBE_XY_OFFSET, parser.seen_test('O')),
|
||||
towers_set = !parser.seen_test('T');
|
||||
|
||||
float max_dcr = dcr = DELTA_PRINTABLE_RADIUS;
|
||||
// The calibration radius is set to a calculated value
|
||||
float dcr = probe_at_offset ? DELTA_PRINTABLE_RADIUS : DELTA_PRINTABLE_RADIUS - PROBING_MARGIN;
|
||||
#if HAS_PROBE_XY_OFFSET
|
||||
// For offset probes the calibration radius is set to a safe but non-optimal value
|
||||
dcr -= HYPOT(probe.offset_xy.x, probe.offset_xy.y);
|
||||
if (probe_at_offset) {
|
||||
// With probe positions both probe and nozzle need to be within the printable area
|
||||
max_dcr = dcr;
|
||||
}
|
||||
// else with nozzle positions there is a risk of the probe being outside the bed
|
||||
// but as long the nozzle stays within the printable area there is no risk of
|
||||
// the effector crashing into the towers.
|
||||
const float total_offset = HYPOT(probe.offset_xy.x, probe.offset_xy.y);
|
||||
dcr -= probe_at_offset ? _MAX(total_offset, PROBING_MARGIN) : total_offset;
|
||||
#endif
|
||||
|
||||
if (parser.seenval('R')) dcr = parser.value_float();
|
||||
if (!WITHIN(dcr, 0, max_dcr)) {
|
||||
SERIAL_ECHOLNPGM("?calibration (R)adius implausible.");
|
||||
return;
|
||||
}
|
||||
NOMORE(dcr, DELTA_PRINTABLE_RADIUS);
|
||||
if (parser.seenval('R')) dcr -= _MAX(parser.value_float(), 0.0f);
|
||||
TERN_(HAS_DELTA_SENSORLESS_PROBING, dcr *= sensorless_radius_factor);
|
||||
|
||||
const float calibration_precision = parser.floatval('C', 0.0f);
|
||||
if (calibration_precision < 0) {
|
||||
@@ -449,9 +437,8 @@ void GcodeSuite::G33() {
|
||||
const bool stow_after_each = parser.seen_test('E');
|
||||
|
||||
#if HAS_DELTA_SENSORLESS_PROBING
|
||||
probe.test_sensitivity.x = !parser.seen_test('X');
|
||||
TERN_(HAS_Y_AXIS, probe.test_sensitivity.y = !parser.seen_test('Y'));
|
||||
TERN_(HAS_Z_AXIS, probe.test_sensitivity.z = !parser.seen_test('Z'));
|
||||
probe.test_sensitivity = { !parser.seen_test('X'), !parser.seen_test('Y'), !parser.seen_test('Z') };
|
||||
const bool do_save_offset_adj = parser.seen_test('S');
|
||||
#endif
|
||||
|
||||
const bool _0p_calibration = probe_points == 0,
|
||||
@@ -479,9 +466,10 @@ void GcodeSuite::G33() {
|
||||
// Report settings
|
||||
PGM_P const checkingac = PSTR("Checking... AC");
|
||||
SERIAL_ECHOPGM_P(checkingac);
|
||||
SERIAL_ECHOPGM(" at radius:", dcr);
|
||||
if (verbose_level == 0) SERIAL_ECHOPGM(" (DRY-RUN)");
|
||||
SERIAL_EOL();
|
||||
ui.set_status_P(checkingac);
|
||||
ui.set_status(checkingac);
|
||||
|
||||
print_calibration_settings(_endstop_results, _angle_results);
|
||||
|
||||
@@ -489,6 +477,25 @@ void GcodeSuite::G33() {
|
||||
|
||||
if (!_0p_calibration) ac_home();
|
||||
|
||||
#if HAS_DELTA_SENSORLESS_PROBING
|
||||
if (verbose_level > 0 && do_save_offset_adj) {
|
||||
offset_sensorless_adj.reset();
|
||||
|
||||
auto caltower = [&](Probe::sense_bool_t s){
|
||||
float z_at_pt[NPP + 1];
|
||||
LOOP_CAL_ALL(rad) z_at_pt[rad] = 0.0f;
|
||||
probe.test_sensitivity = s;
|
||||
if (probe_calibration_points(z_at_pt, 1, dcr, false, false, probe_at_offset))
|
||||
probe.set_offset_sensorless_adj(z_at_pt[CEN]);
|
||||
};
|
||||
caltower({ true, false, false }); // A
|
||||
caltower({ false, true, false }); // B
|
||||
caltower({ false, false, true }); // C
|
||||
|
||||
probe.test_sensitivity = { true, true, true }; // reset to all
|
||||
}
|
||||
#endif
|
||||
|
||||
do { // start iterations
|
||||
|
||||
float z_at_pt[NPP + 1] = { 0.0f };
|
||||
@@ -498,7 +505,7 @@ void GcodeSuite::G33() {
|
||||
|
||||
// Probe the points
|
||||
zero_std_dev_old = zero_std_dev;
|
||||
if (!probe_calibration_points(z_at_pt, probe_points, towers_set, stow_after_each, probe_at_offset)) {
|
||||
if (!probe_calibration_points(z_at_pt, probe_points, dcr, towers_set, stow_after_each, probe_at_offset)) {
|
||||
SERIAL_ECHOLNPGM("Correct delta settings with M665 and M666");
|
||||
return ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index));
|
||||
}
|
||||
@@ -538,10 +545,10 @@ void GcodeSuite::G33() {
|
||||
|
||||
// calculate factors
|
||||
if (_7p_9_center) dcr *= 0.9f;
|
||||
h_factor = auto_tune_h();
|
||||
r_factor = auto_tune_r();
|
||||
a_factor = auto_tune_a();
|
||||
dcr /= 0.9f;
|
||||
h_factor = auto_tune_h(dcr);
|
||||
r_factor = auto_tune_r(dcr);
|
||||
a_factor = auto_tune_a(dcr);
|
||||
if (_7p_9_center) dcr /= 0.9f;
|
||||
|
||||
switch (probe_points) {
|
||||
case 0:
|
||||
@@ -550,7 +557,7 @@ void GcodeSuite::G33() {
|
||||
|
||||
case 1:
|
||||
test_precision = 0.0f; // forced end
|
||||
LOOP_LINEAR_AXES(axis) e_delta[axis] = +Z4(CEN);
|
||||
LOOP_NUM_AXES(axis) e_delta[axis] = +Z4(CEN);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@@ -598,22 +605,31 @@ void GcodeSuite::G33() {
|
||||
// Normalize angles to least-squares
|
||||
if (_angle_results) {
|
||||
float a_sum = 0.0f;
|
||||
LOOP_LINEAR_AXES(axis) a_sum += delta_tower_angle_trim[axis];
|
||||
LOOP_LINEAR_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f;
|
||||
LOOP_NUM_AXES(axis) a_sum += delta_tower_angle_trim[axis];
|
||||
LOOP_NUM_AXES(axis) delta_tower_angle_trim[axis] -= a_sum / 3.0f;
|
||||
}
|
||||
|
||||
// adjust delta_height and endstops by the max amount
|
||||
const float z_temp = _MAX(delta_endstop_adj.a, delta_endstop_adj.b, delta_endstop_adj.c);
|
||||
delta_height -= z_temp;
|
||||
LOOP_LINEAR_AXES(axis) delta_endstop_adj[axis] -= z_temp;
|
||||
LOOP_NUM_AXES(axis) delta_endstop_adj[axis] -= z_temp;
|
||||
}
|
||||
recalc_delta_settings();
|
||||
NOMORE(zero_std_dev_min, zero_std_dev);
|
||||
|
||||
// print report
|
||||
|
||||
if (verbose_level == 3 || verbose_level == 0)
|
||||
if (verbose_level == 3 || verbose_level == 0) {
|
||||
print_calibration_results(z_at_pt, _tower_results, _opposite_results);
|
||||
#if HAS_DELTA_SENSORLESS_PROBING
|
||||
if (verbose_level == 0 && probe_points == 1) {
|
||||
if (do_save_offset_adj)
|
||||
probe.set_offset_sensorless_adj(z_at_pt[CEN]);
|
||||
else
|
||||
probe.refresh_largest_sensorless_adj();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (verbose_level != 0) { // !dry run
|
||||
if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) { // end iterations
|
||||
@@ -653,13 +669,13 @@ void GcodeSuite::G33() {
|
||||
}
|
||||
}
|
||||
else { // dry run
|
||||
PGM_P const enddryrun = PSTR("End DRY-RUN");
|
||||
SERIAL_ECHOPGM_P(enddryrun);
|
||||
FSTR_P const enddryrun = F("End DRY-RUN");
|
||||
SERIAL_ECHOF(enddryrun);
|
||||
SERIAL_ECHO_SP(35);
|
||||
SERIAL_ECHOLNPAIR_F("std dev:", zero_std_dev, 3);
|
||||
|
||||
char mess[21];
|
||||
strcpy_P(mess, enddryrun);
|
||||
strcpy_P(mess, FTOP(enddryrun));
|
||||
strcpy_P(&mess[11], PSTR(" sd:"));
|
||||
if (zero_std_dev < 1)
|
||||
sprintf_P(&mess[15], PSTR("0.%03i"), (int)LROUND(zero_std_dev * 1000.0f));
|
||||
@@ -674,6 +690,9 @@ void GcodeSuite::G33() {
|
||||
ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index));
|
||||
|
||||
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE));
|
||||
#if HAS_DELTA_SENSORLESS_PROBING
|
||||
probe.test_sensitivity = { true, true, true };
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // DELTA_AUTO_CALIBRATION
|
||||
|
@@ -26,9 +26,12 @@
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/endstops.h"
|
||||
|
||||
#if ANY(HAS_MOTOR_CURRENT_SPI, HAS_MOTOR_CURRENT_PWM, HAS_TRINAMIC_CONFIG)
|
||||
#include "../../module/stepper.h"
|
||||
#endif
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
@@ -47,7 +50,7 @@ void GcodeSuite::G34() {
|
||||
TemporaryGlobalEndstopsState unlock_z(false);
|
||||
|
||||
#ifdef GANTRY_CALIBRATION_COMMANDS_PRE
|
||||
gcode.process_subcommands_now_P(PSTR(GANTRY_CALIBRATION_COMMANDS_PRE));
|
||||
process_subcommands_now(F(GANTRY_CALIBRATION_COMMANDS_PRE));
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Sub Commands Processed");
|
||||
#endif
|
||||
|
||||
@@ -79,7 +82,7 @@ void GcodeSuite::G34() {
|
||||
stepper.set_digipot_current(Z_AXIS, target_current);
|
||||
#elif HAS_MOTOR_CURRENT_PWM
|
||||
const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT);
|
||||
const uint32_t previous_current = stepper.motor_current_setting[Z_AXIS];
|
||||
const uint32_t previous_current = stepper.motor_current_setting[1]; // Z
|
||||
stepper.set_digipot_current(1, target_current);
|
||||
#elif HAS_MOTOR_CURRENT_DAC
|
||||
const float target_current = parser.floatval('S', GANTRY_CALIBRATION_CURRENT);
|
||||
@@ -91,7 +94,7 @@ void GcodeSuite::G34() {
|
||||
digipot_i2c.set_current(Z_AXIS, target_current)
|
||||
#elif HAS_TRINAMIC_CONFIG
|
||||
const uint16_t target_current = parser.intval('S', GANTRY_CALIBRATION_CURRENT);
|
||||
static uint16_t previous_current_arr[NUM_Z_STEPPER_DRIVERS];
|
||||
static uint16_t previous_current_arr[NUM_Z_STEPPERS];
|
||||
#if AXIS_IS_TMC(Z)
|
||||
previous_current_arr[0] = stepperZ.getMilliamps();
|
||||
stepperZ.rms_current(target_current);
|
||||
@@ -114,10 +117,6 @@ void GcodeSuite::G34() {
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Final Z Move");
|
||||
do_blocking_move_to_z(zgrind, MMM_TO_MMS(GANTRY_CALIBRATION_FEEDRATE));
|
||||
|
||||
// Back off end plate, back to normal motion range
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Backoff");
|
||||
do_blocking_move_to_z(zpounce, MMM_TO_MMS(GANTRY_CALIBRATION_FEEDRATE));
|
||||
|
||||
#if _REDUCE_CURRENT
|
||||
// Reset current to original values
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore Current");
|
||||
@@ -146,9 +145,13 @@ void GcodeSuite::G34() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Back off end plate, back to normal motion range
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Z Backoff");
|
||||
do_blocking_move_to_z(zpounce, MMM_TO_MMS(GANTRY_CALIBRATION_FEEDRATE));
|
||||
|
||||
#ifdef GANTRY_CALIBRATION_COMMANDS_POST
|
||||
if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Running Post Commands");
|
||||
gcode.process_subcommands_now_P(PSTR(GANTRY_CALIBRATION_COMMANDS_POST));
|
||||
process_subcommands_now(F(GANTRY_CALIBRATION_COMMANDS_POST));
|
||||
#endif
|
||||
|
||||
SET_SOFT_ENDSTOP_LOOSE(false);
|
||||
|
@@ -31,7 +31,7 @@
|
||||
#include "../../module/stepper.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/probe.h"
|
||||
#include "../../lcd/marlinui.h" // for LCD_MESSAGEPGM
|
||||
#include "../../lcd/marlinui.h" // for LCD_MESSAGE
|
||||
|
||||
#if HAS_LEVELING
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
@@ -41,16 +41,20 @@
|
||||
#include "../../module/tool_change.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
#if HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
#include "../../libs/least_squares_fit.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(BLTOUCH)
|
||||
#include "../../feature/bltouch.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG_OUT ENABLED(DEBUG_LEVELING_FEATURE)
|
||||
#include "../../core/debug_out.h"
|
||||
|
||||
#if NUM_Z_STEPPER_DRIVERS >= 3
|
||||
#if NUM_Z_STEPPERS >= 3
|
||||
#define TRIPLE_Z 1
|
||||
#if NUM_Z_STEPPER_DRIVERS >= 4
|
||||
#if NUM_Z_STEPPERS >= 4
|
||||
#define QUAD_Z 1
|
||||
#endif
|
||||
#endif
|
||||
@@ -118,7 +122,7 @@ void GcodeSuite::G34() {
|
||||
break;
|
||||
}
|
||||
|
||||
const float z_auto_align_amplification = TERN(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, Z_STEPPER_ALIGN_AMP, parser.floatval('A', Z_STEPPER_ALIGN_AMP));
|
||||
const float z_auto_align_amplification = TERN(HAS_Z_STEPPER_ALIGN_STEPPER_XY, Z_STEPPER_ALIGN_AMP, parser.floatval('A', Z_STEPPER_ALIGN_AMP));
|
||||
if (!WITHIN(ABS(z_auto_align_amplification), 0.5f, 2.0f)) {
|
||||
SERIAL_ECHOLNPGM("?(A)mplification out of bounds (0.5-2.0).");
|
||||
break;
|
||||
@@ -149,7 +153,7 @@ void GcodeSuite::G34() {
|
||||
// In BLTOUCH HS mode, the probe travels in a deployed state.
|
||||
// Users of G34 might have a badly misaligned bed, so raise Z by the
|
||||
// length of the deployed pin (BLTOUCH stroke < 7mm)
|
||||
#define Z_BASIC_CLEARANCE (Z_CLEARANCE_BETWEEN_PROBES + 7.0f * BOTH(BLTOUCH, BLTOUCH_HS_MODE))
|
||||
#define Z_BASIC_CLEARANCE (Z_CLEARANCE_BETWEEN_PROBES + TERN0(BLTOUCH, bltouch.z_extra_clearance()))
|
||||
|
||||
// Compute a worst-case clearance height to probe from. After the first
|
||||
// iteration this will be re-calculated based on the actual bed position
|
||||
@@ -175,16 +179,16 @@ void GcodeSuite::G34() {
|
||||
// Now, the Z origin lies below the build plate. That allows to probe deeper, before run_z_probe throws an error.
|
||||
// This hack is un-done at the end of G34 - either by re-homing, or by using the probed heights of the last iteration.
|
||||
|
||||
#if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
float last_z_align_move[NUM_Z_STEPPER_DRIVERS] = ARRAY_N_1(NUM_Z_STEPPER_DRIVERS, 10000.0f);
|
||||
#if !HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
float last_z_align_move[NUM_Z_STEPPERS] = ARRAY_N_1(NUM_Z_STEPPERS, 10000.0f);
|
||||
#else
|
||||
float last_z_align_level_indicator = 10000.0f;
|
||||
#endif
|
||||
float z_measured[NUM_Z_STEPPER_DRIVERS] = { 0 },
|
||||
float z_measured[NUM_Z_STEPPERS] = { 0 },
|
||||
z_maxdiff = 0.0f,
|
||||
amplification = z_auto_align_amplification;
|
||||
|
||||
#if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
#if !HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
bool adjustment_reverse = false;
|
||||
#endif
|
||||
|
||||
@@ -213,23 +217,25 @@ void GcodeSuite::G34() {
|
||||
float z_measured_max = -100000.0f;
|
||||
|
||||
// Probe all positions (one per Z-Stepper)
|
||||
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) {
|
||||
LOOP_L_N(i, NUM_Z_STEPPERS) {
|
||||
// iteration odd/even --> downward / upward stepper sequence
|
||||
const uint8_t iprobe = (iteration & 1) ? NUM_Z_STEPPER_DRIVERS - 1 - i : i;
|
||||
const uint8_t iprobe = (iteration & 1) ? NUM_Z_STEPPERS - 1 - i : i;
|
||||
|
||||
// Safe clearance even on an incline
|
||||
if ((iteration == 0 || i > 0) && z_probe > current_position.z) do_blocking_move_to_z(z_probe);
|
||||
|
||||
xy_pos_t &ppos = z_stepper_align.xy[iprobe];
|
||||
|
||||
if (DEBUGGING(LEVELING))
|
||||
DEBUG_ECHOLNPGM_P(PSTR("Probing X"), z_stepper_align.xy[iprobe].x, SP_Y_STR, z_stepper_align.xy[iprobe].y);
|
||||
DEBUG_ECHOLNPGM_P(PSTR("Probing X"), ppos.x, SP_Y_STR, ppos.y);
|
||||
|
||||
// Probe a Z height for each stepper.
|
||||
// Probing sanity check is disabled, as it would trigger even in normal cases because
|
||||
// current_position.z has been manually altered in the "dirty trick" above.
|
||||
const float z_probed_height = probe.probe_at_point(z_stepper_align.xy[iprobe], raise_after, 0, true, false);
|
||||
const float z_probed_height = probe.probe_at_point(DIFF_TERN(HAS_HOME_OFFSET, ppos, xy_pos_t(home_offset)), raise_after, 0, true, false);
|
||||
if (isnan(z_probed_height)) {
|
||||
SERIAL_ECHOLNPGM("Probing failed");
|
||||
LCD_MESSAGEPGM(MSG_LCD_PROBING_FAILED);
|
||||
LCD_MESSAGE(MSG_LCD_PROBING_FAILED);
|
||||
err_break = true;
|
||||
break;
|
||||
}
|
||||
@@ -252,7 +258,7 @@ void GcodeSuite::G34() {
|
||||
z_maxdiff = z_measured_max - z_measured_min;
|
||||
z_probe = Z_BASIC_CLEARANCE + z_measured_max + z_maxdiff;
|
||||
|
||||
#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
#if HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
// Replace the initial values in z_measured with calculated heights at
|
||||
// each stepper position. This allows the adjustment algorithm to be
|
||||
// shared between both possible probing mechanisms.
|
||||
@@ -266,20 +272,20 @@ void GcodeSuite::G34() {
|
||||
// This allows the actual adjustment logic to be shared by both algorithms.
|
||||
linear_fit_data lfd;
|
||||
incremental_LSF_reset(&lfd);
|
||||
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) {
|
||||
LOOP_L_N(i, NUM_Z_STEPPERS) {
|
||||
SERIAL_ECHOLNPGM("PROBEPT_", i, ": ", z_measured[i]);
|
||||
incremental_LSF(&lfd, z_stepper_align.xy[i], z_measured[i]);
|
||||
}
|
||||
finish_incremental_LSF(&lfd);
|
||||
|
||||
z_measured_min = 100000.0f;
|
||||
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) {
|
||||
LOOP_L_N(i, NUM_Z_STEPPERS) {
|
||||
z_measured[i] = -(lfd.A * z_stepper_align.stepper_xy[i].x + lfd.B * z_stepper_align.stepper_xy[i].y + lfd.D);
|
||||
z_measured_min = _MIN(z_measured_min, z_measured[i]);
|
||||
}
|
||||
|
||||
SERIAL_ECHOLNPGM(
|
||||
LIST_N(DOUBLE(NUM_Z_STEPPER_DRIVERS),
|
||||
LIST_N(DOUBLE(NUM_Z_STEPPERS),
|
||||
"Calculated Z1=", z_measured[0],
|
||||
" Z2=", z_measured[1],
|
||||
" Z3=", z_measured[2],
|
||||
@@ -303,7 +309,7 @@ void GcodeSuite::G34() {
|
||||
|
||||
#if HAS_STATUS_MESSAGE
|
||||
char fstr1[10];
|
||||
char msg[6 + (6 + 5) * NUM_Z_STEPPER_DRIVERS + 1]
|
||||
char msg[6 + (6 + 5) * NUM_Z_STEPPERS + 1]
|
||||
#if TRIPLE_Z
|
||||
, fstr2[10], fstr3[10]
|
||||
#if QUAD_Z
|
||||
@@ -328,25 +334,25 @@ void GcodeSuite::G34() {
|
||||
auto decreasing_accuracy = [](const_float_t v1, const_float_t v2) {
|
||||
if (v1 < v2 * 0.7f) {
|
||||
SERIAL_ECHOLNPGM("Decreasing Accuracy Detected.");
|
||||
LCD_MESSAGEPGM(MSG_DECREASING_ACCURACY);
|
||||
LCD_MESSAGE(MSG_DECREASING_ACCURACY);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
#if HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
// Check if the applied corrections go in the correct direction.
|
||||
// Calculate the sum of the absolute deviations from the mean of the probe measurements.
|
||||
// Compare to the last iteration to ensure it's getting better.
|
||||
|
||||
// Calculate mean value as a reference
|
||||
float z_measured_mean = 0.0f;
|
||||
LOOP_L_N(zstepper, NUM_Z_STEPPER_DRIVERS) z_measured_mean += z_measured[zstepper];
|
||||
z_measured_mean /= NUM_Z_STEPPER_DRIVERS;
|
||||
LOOP_L_N(zstepper, NUM_Z_STEPPERS) z_measured_mean += z_measured[zstepper];
|
||||
z_measured_mean /= NUM_Z_STEPPERS;
|
||||
|
||||
// Calculate the sum of the absolute deviations from the mean value
|
||||
float z_align_level_indicator = 0.0f;
|
||||
LOOP_L_N(zstepper, NUM_Z_STEPPER_DRIVERS)
|
||||
LOOP_L_N(zstepper, NUM_Z_STEPPERS)
|
||||
z_align_level_indicator += ABS(z_measured[zstepper] - z_measured_mean);
|
||||
|
||||
// If it's getting worse, stop and throw an error
|
||||
@@ -361,12 +367,12 @@ void GcodeSuite::G34() {
|
||||
|
||||
bool success_break = true;
|
||||
// Correct the individual stepper offsets
|
||||
LOOP_L_N(zstepper, NUM_Z_STEPPER_DRIVERS) {
|
||||
LOOP_L_N(zstepper, NUM_Z_STEPPERS) {
|
||||
// Calculate current stepper move
|
||||
float z_align_move = z_measured[zstepper] - z_measured_min;
|
||||
const float z_align_abs = ABS(z_align_move);
|
||||
|
||||
#if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
#if !HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
// Optimize one iteration's correction based on the first measurements
|
||||
if (z_align_abs) amplification = (iteration == 1) ? _MIN(last_z_align_move[zstepper] / z_align_abs, 2.0f) : z_auto_align_amplification;
|
||||
|
||||
@@ -390,7 +396,7 @@ void GcodeSuite::G34() {
|
||||
// Lock all steppers except one
|
||||
stepper.set_all_z_lock(true, zstepper);
|
||||
|
||||
#if DISABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
#if !HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
// Decreasing accuracy was detected so move was inverted.
|
||||
// Will match reversed Z steppers on dual steppers. Triple will need more work to map.
|
||||
if (adjustment_reverse) {
|
||||
@@ -411,7 +417,7 @@ void GcodeSuite::G34() {
|
||||
|
||||
if (success_break) {
|
||||
SERIAL_ECHOLNPGM("Target accuracy achieved.");
|
||||
LCD_MESSAGEPGM(MSG_ACCURACY_ACHIEVED);
|
||||
LCD_MESSAGE(MSG_ACCURACY_ACHIEVED);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -433,7 +439,7 @@ void GcodeSuite::G34() {
|
||||
// After this operation the z position needs correction
|
||||
set_axis_never_homed(Z_AXIS);
|
||||
// Home Z after the alignment procedure
|
||||
process_subcommands_now_P(PSTR("G28Z"));
|
||||
process_subcommands_now(F("G28Z"));
|
||||
#else
|
||||
// Use the probed height from the last iteration to determine the Z height.
|
||||
// z_measured_min is used, because all steppers are aligned to z_measured_min.
|
||||
@@ -463,7 +469,7 @@ void GcodeSuite::G34() {
|
||||
*
|
||||
* S<index> : Index of the probe point to set
|
||||
*
|
||||
* With Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS:
|
||||
* With Z_STEPPER_ALIGN_STEPPER_XY:
|
||||
* W<index> : Index of the Z stepper position to set
|
||||
* The W and S parameters may not be combined.
|
||||
*
|
||||
@@ -482,42 +488,43 @@ void GcodeSuite::M422() {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_probe_point = parser.seen('S');
|
||||
const bool is_probe_point = parser.seen_test('S');
|
||||
|
||||
if (TERN0(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, is_probe_point && parser.seen('W'))) {
|
||||
if (TERN0(HAS_Z_STEPPER_ALIGN_STEPPER_XY, is_probe_point && parser.seen_test('W'))) {
|
||||
SERIAL_ECHOLNPGM("?(S) and (W) may not be combined.");
|
||||
return;
|
||||
}
|
||||
|
||||
xy_pos_t *pos_dest = (
|
||||
TERN_(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, !is_probe_point ? z_stepper_align.stepper_xy :)
|
||||
xy_pos_t * const pos_dest = (
|
||||
TERN_(HAS_Z_STEPPER_ALIGN_STEPPER_XY, !is_probe_point ? z_stepper_align.stepper_xy :)
|
||||
z_stepper_align.xy
|
||||
);
|
||||
|
||||
if (!is_probe_point && TERN1(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, !parser.seen('W'))) {
|
||||
SERIAL_ECHOLNPGM("?(S)" TERN_(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS, " or (W)") " is required.");
|
||||
if (!is_probe_point && TERN1(HAS_Z_STEPPER_ALIGN_STEPPER_XY, !parser.seen_test('W'))) {
|
||||
SERIAL_ECHOLNPGM("?(S)" TERN_(HAS_Z_STEPPER_ALIGN_STEPPER_XY, " or (W)") " is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the Probe Position Index or Z Stepper Index
|
||||
int8_t position_index;
|
||||
if (is_probe_point) {
|
||||
position_index = parser.intval('S') - 1;
|
||||
if (!WITHIN(position_index, 0, int8_t(NUM_Z_STEPPER_DRIVERS) - 1)) {
|
||||
SERIAL_ECHOLNPGM("?(S) Probe-position index invalid.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
int8_t position_index = 1;
|
||||
FSTR_P err_string = F("?(S) Probe-position");
|
||||
if (is_probe_point)
|
||||
position_index = parser.intval('S');
|
||||
else {
|
||||
#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
position_index = parser.intval('W') - 1;
|
||||
if (!WITHIN(position_index, 0, NUM_Z_STEPPER_DRIVERS - 1)) {
|
||||
SERIAL_ECHOLNPGM("?(W) Z-stepper index invalid.");
|
||||
return;
|
||||
}
|
||||
#if HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
err_string = F("?(W) Z-stepper");
|
||||
position_index = parser.intval('W');
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!WITHIN(position_index, 1, NUM_Z_STEPPERS)) {
|
||||
SERIAL_ECHOF(err_string);
|
||||
SERIAL_ECHOLNPGM(" index invalid (1.." STRINGIFY(NUM_Z_STEPPERS) ").");
|
||||
return;
|
||||
}
|
||||
|
||||
--position_index;
|
||||
|
||||
const xy_pos_t pos = {
|
||||
parser.floatval('X', pos_dest[position_index].x),
|
||||
parser.floatval('Y', pos_dest[position_index].y)
|
||||
@@ -538,8 +545,8 @@ void GcodeSuite::M422() {
|
||||
}
|
||||
|
||||
void GcodeSuite::M422_report(const bool forReplay/*=true*/) {
|
||||
report_heading(forReplay, PSTR(STR_Z_AUTO_ALIGN));
|
||||
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) {
|
||||
report_heading(forReplay, F(STR_Z_AUTO_ALIGN));
|
||||
LOOP_L_N(i, NUM_Z_STEPPERS) {
|
||||
report_echo_start(forReplay);
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M422 S"), i + 1,
|
||||
@@ -547,8 +554,8 @@ void GcodeSuite::M422_report(const bool forReplay/*=true*/) {
|
||||
SP_Y_STR, z_stepper_align.xy[i].y
|
||||
);
|
||||
}
|
||||
#if ENABLED(Z_STEPPER_ALIGN_KNOWN_STEPPER_POSITIONS)
|
||||
LOOP_L_N(i, NUM_Z_STEPPER_DRIVERS) {
|
||||
#if HAS_Z_STEPPER_ALIGN_STEPPER_XY
|
||||
LOOP_L_N(i, NUM_Z_STEPPERS) {
|
||||
report_echo_start(forReplay);
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M422 W"), i + 1,
|
||||
|
@@ -73,22 +73,31 @@
|
||||
#if BOTH(CALIBRATION_MEASURE_LEFT, CALIBRATION_MEASURE_RIGHT)
|
||||
#define HAS_X_CENTER 1
|
||||
#endif
|
||||
#if HAS_Y_AXIS && BOTH(CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK)
|
||||
#if ALL(HAS_Y_AXIS, CALIBRATION_MEASURE_FRONT, CALIBRATION_MEASURE_BACK)
|
||||
#define HAS_Y_CENTER 1
|
||||
#endif
|
||||
#if LINEAR_AXES >= 4 && BOTH(CALIBRATION_MEASURE_IMIN, CALIBRATION_MEASURE_IMAX)
|
||||
#if ALL(HAS_I_AXIS, CALIBRATION_MEASURE_IMIN, CALIBRATION_MEASURE_IMAX)
|
||||
#define HAS_I_CENTER 1
|
||||
#endif
|
||||
#if LINEAR_AXES >= 5 && BOTH(CALIBRATION_MEASURE_JMIN, CALIBRATION_MEASURE_JMAX)
|
||||
#if ALL(HAS_J_AXIS, CALIBRATION_MEASURE_JMIN, CALIBRATION_MEASURE_JMAX)
|
||||
#define HAS_J_CENTER 1
|
||||
#endif
|
||||
#if LINEAR_AXES >= 6 && BOTH(CALIBRATION_MEASURE_KMIN, CALIBRATION_MEASURE_KMAX)
|
||||
#if ALL(HAS_K_AXIS, CALIBRATION_MEASURE_KMIN, CALIBRATION_MEASURE_KMAX)
|
||||
#define HAS_K_CENTER 1
|
||||
#endif
|
||||
#if ALL(HAS_U_AXIS, CALIBRATION_MEASURE_UMIN, CALIBRATION_MEASURE_UMAX)
|
||||
#define HAS_U_CENTER 1
|
||||
#endif
|
||||
#if ALL(HAS_V_AXIS, CALIBRATION_MEASURE_VMIN, CALIBRATION_MEASURE_VMAX)
|
||||
#define HAS_V_CENTER 1
|
||||
#endif
|
||||
#if ALL(HAS_W_AXIS, CALIBRATION_MEASURE_WMIN, CALIBRATION_MEASURE_WMAX)
|
||||
#define HAS_W_CENTER 1
|
||||
#endif
|
||||
|
||||
enum side_t : uint8_t {
|
||||
TOP, RIGHT, FRONT, LEFT, BACK, NUM_SIDES,
|
||||
LIST_N(DOUBLE(SUB3(LINEAR_AXES)), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM)
|
||||
LIST_N(DOUBLE(SECONDARY_AXES), IMINIMUM, IMAXIMUM, JMINIMUM, JMAXIMUM, KMINIMUM, KMAXIMUM, UMINIMUM, UMAXIMUM, VMINIMUM, VMAXIMUM, WMINIMUM, WMAXIMUM)
|
||||
};
|
||||
|
||||
static constexpr xyz_pos_t true_center CALIBRATION_OBJECT_CENTER;
|
||||
@@ -105,13 +114,27 @@ struct measurements_t {
|
||||
};
|
||||
|
||||
#if ENABLED(BACKLASH_GCODE)
|
||||
#define TEMPORARY_BACKLASH_CORRECTION(value) REMEMBER(tbst, backlash.correction, value)
|
||||
class restorer_correction {
|
||||
const uint8_t val_;
|
||||
public:
|
||||
restorer_correction(const uint8_t temp_val) : val_(backlash.get_correction_uint8()) { backlash.set_correction_uint8(temp_val); }
|
||||
~restorer_correction() { backlash.set_correction_uint8(val_); }
|
||||
};
|
||||
|
||||
#define TEMPORARY_BACKLASH_CORRECTION(value) restorer_correction restorer_tbst(value)
|
||||
#else
|
||||
#define TEMPORARY_BACKLASH_CORRECTION(value)
|
||||
#endif
|
||||
|
||||
#if ENABLED(BACKLASH_GCODE) && defined(BACKLASH_SMOOTHING_MM)
|
||||
#define TEMPORARY_BACKLASH_SMOOTHING(value) REMEMBER(tbsm, backlash.smoothing_mm, value)
|
||||
class restorer_smoothing {
|
||||
const float val_;
|
||||
public:
|
||||
restorer_smoothing(const float temp_val) : val_(backlash.get_smoothing_mm()) { backlash.set_smoothing_mm(temp_val); }
|
||||
~restorer_smoothing() { backlash.set_smoothing_mm(val_); }
|
||||
};
|
||||
|
||||
#define TEMPORARY_BACKLASH_SMOOTHING(value) restorer_smoothing restorer_tbsm(value)
|
||||
#else
|
||||
#define TEMPORARY_BACKLASH_SMOOTHING(value)
|
||||
#endif
|
||||
@@ -241,14 +264,15 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t
|
||||
|
||||
park_above_object(m, uncertainty);
|
||||
|
||||
#define _ACASE(N,A,B) case A: dir = -1; case B: axis = N##_AXIS; break
|
||||
#define _PCASE(N) _ACASE(N, N##MINIMUM, N##MAXIMUM)
|
||||
|
||||
switch (side) {
|
||||
#if AXIS_CAN_CALIBRATE(X)
|
||||
case RIGHT: dir = -1;
|
||||
case LEFT: axis = X_AXIS; break;
|
||||
_ACASE(X, RIGHT, LEFT);
|
||||
#endif
|
||||
#if LINEAR_AXES >= 2 && AXIS_CAN_CALIBRATE(Y)
|
||||
case BACK: dir = -1;
|
||||
case FRONT: axis = Y_AXIS; break;
|
||||
#if HAS_Y_AXIS && AXIS_CAN_CALIBRATE(Y)
|
||||
_ACASE(Y, BACK, FRONT);
|
||||
#endif
|
||||
#if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z)
|
||||
case TOP: {
|
||||
@@ -258,17 +282,23 @@ inline void probe_side(measurements_t &m, const float uncertainty, const side_t
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if LINEAR_AXES >= 4 && AXIS_CAN_CALIBRATE(I)
|
||||
case IMINIMUM: dir = -1;
|
||||
case IMAXIMUM: axis = I_AXIS; break;
|
||||
#if HAS_I_AXIS && AXIS_CAN_CALIBRATE(I)
|
||||
_PCASE(I);
|
||||
#endif
|
||||
#if LINEAR_AXES >= 5 && AXIS_CAN_CALIBRATE(J)
|
||||
case JMINIMUM: dir = -1;
|
||||
case JMAXIMUM: axis = J_AXIS; break;
|
||||
#if HAS_J_AXIS && AXIS_CAN_CALIBRATE(J)
|
||||
_PCASE(J);
|
||||
#endif
|
||||
#if LINEAR_AXES >= 6 && AXIS_CAN_CALIBRATE(K)
|
||||
case KMINIMUM: dir = -1;
|
||||
case KMAXIMUM: axis = K_AXIS; break;
|
||||
#if HAS_K_AXIS && AXIS_CAN_CALIBRATE(K)
|
||||
_PCASE(K);
|
||||
#endif
|
||||
#if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U)
|
||||
_PCASE(U);
|
||||
#endif
|
||||
#if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V)
|
||||
_PCASE(V);
|
||||
#endif
|
||||
#if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W)
|
||||
_PCASE(W);
|
||||
#endif
|
||||
default: return;
|
||||
}
|
||||
@@ -323,6 +353,12 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
TERN_(CALIBRATION_MEASURE_JMAX, probe_side(m, uncertainty, JMAXIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_KMIN, probe_side(m, uncertainty, KMINIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_KMAX, probe_side(m, uncertainty, KMAXIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_UMIN, probe_side(m, uncertainty, UMINIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_UMAX, probe_side(m, uncertainty, UMAXIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_VMIN, probe_side(m, uncertainty, VMINIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_VMAX, probe_side(m, uncertainty, VMAXIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_WMIN, probe_side(m, uncertainty, WMINIMUM, probe_top_at_edge));
|
||||
TERN_(CALIBRATION_MEASURE_WMAX, probe_side(m, uncertainty, WMAXIMUM, probe_top_at_edge));
|
||||
|
||||
// Compute the measured center of the calibration object.
|
||||
TERN_(HAS_X_CENTER, m.obj_center.x = (m.obj_side[LEFT] + m.obj_side[RIGHT]) / 2);
|
||||
@@ -330,6 +366,9 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
TERN_(HAS_I_CENTER, m.obj_center.i = (m.obj_side[IMINIMUM] + m.obj_side[IMAXIMUM]) / 2);
|
||||
TERN_(HAS_J_CENTER, m.obj_center.j = (m.obj_side[JMINIMUM] + m.obj_side[JMAXIMUM]) / 2);
|
||||
TERN_(HAS_K_CENTER, m.obj_center.k = (m.obj_side[KMINIMUM] + m.obj_side[KMAXIMUM]) / 2);
|
||||
TERN_(HAS_U_CENTER, m.obj_center.u = (m.obj_side[UMINIMUM] + m.obj_side[UMAXIMUM]) / 2);
|
||||
TERN_(HAS_V_CENTER, m.obj_center.v = (m.obj_side[VMINIMUM] + m.obj_side[VMAXIMUM]) / 2);
|
||||
TERN_(HAS_W_CENTER, m.obj_center.w = (m.obj_side[WMINIMUM] + m.obj_side[WMAXIMUM]) / 2);
|
||||
|
||||
// Compute the outside diameter of the nozzle at the height
|
||||
// at which it makes contact with the calibration object
|
||||
@@ -340,13 +379,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
|
||||
// The difference between the known and the measured location
|
||||
// of the calibration object is the positional error
|
||||
LINEAR_AXIS_CODE(
|
||||
NUM_AXIS_CODE(
|
||||
m.pos_error.x = TERN0(HAS_X_CENTER, true_center.x - m.obj_center.x),
|
||||
m.pos_error.y = TERN0(HAS_Y_CENTER, true_center.y - m.obj_center.y),
|
||||
m.pos_error.z = true_center.z - m.obj_center.z,
|
||||
m.pos_error.i = TERN0(HAS_I_CENTER, true_center.i - m.obj_center.i),
|
||||
m.pos_error.j = TERN0(HAS_J_CENTER, true_center.j - m.obj_center.j),
|
||||
m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k)
|
||||
m.pos_error.k = TERN0(HAS_K_CENTER, true_center.k - m.obj_center.k),
|
||||
m.pos_error.u = TERN0(HAS_U_CENTER, true_center.u - m.obj_center.u),
|
||||
m.pos_error.v = TERN0(HAS_V_CENTER, true_center.v - m.obj_center.v),
|
||||
m.pos_error.w = TERN0(HAS_W_CENTER, true_center.w - m.obj_center.w)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -370,7 +412,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" Back: ", m.obj_side[BACK]);
|
||||
#endif
|
||||
#endif
|
||||
#if LINEAR_AXES >= 4
|
||||
#if HAS_I_AXIS
|
||||
#if ENABLED(CALIBRATION_MEASURE_IMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_I_MIN ": ", m.obj_side[IMINIMUM]);
|
||||
#endif
|
||||
@@ -378,7 +420,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" " STR_I_MAX ": ", m.obj_side[IMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if LINEAR_AXES >= 5
|
||||
#if HAS_J_AXIS
|
||||
#if ENABLED(CALIBRATION_MEASURE_JMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_J_MIN ": ", m.obj_side[JMINIMUM]);
|
||||
#endif
|
||||
@@ -386,7 +428,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" " STR_J_MAX ": ", m.obj_side[JMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if LINEAR_AXES >= 6
|
||||
#if HAS_K_AXIS
|
||||
#if ENABLED(CALIBRATION_MEASURE_KMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_K_MIN ": ", m.obj_side[KMINIMUM]);
|
||||
#endif
|
||||
@@ -394,6 +436,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.obj_side[KMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_U_AXIS
|
||||
#if ENABLED(CALIBRATION_MEASURE_UMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.obj_side[UMINIMUM]);
|
||||
#endif
|
||||
#if ENABLED(CALIBRATION_MEASURE_UMAX)
|
||||
SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.obj_side[UMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_V_AXIS
|
||||
#if ENABLED(CALIBRATION_MEASURE_VMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.obj_side[VMINIMUM]);
|
||||
#endif
|
||||
#if ENABLED(CALIBRATION_MEASURE_VMAX)
|
||||
SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.obj_side[VMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_W_AXIS
|
||||
#if ENABLED(CALIBRATION_MEASURE_WMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.obj_side[WMINIMUM]);
|
||||
#endif
|
||||
#if ENABLED(CALIBRATION_MEASURE_WMAX)
|
||||
SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.obj_side[WMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
@@ -415,6 +481,15 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
#if HAS_K_CENTER
|
||||
SERIAL_ECHOLNPGM_P(SP_K_STR, m.obj_center.k);
|
||||
#endif
|
||||
#if HAS_U_CENTER
|
||||
SERIAL_ECHOLNPGM_P(SP_U_STR, m.obj_center.u);
|
||||
#endif
|
||||
#if HAS_V_CENTER
|
||||
SERIAL_ECHOLNPGM_P(SP_V_STR, m.obj_center.v);
|
||||
#endif
|
||||
#if HAS_W_CENTER
|
||||
SERIAL_ECHOLNPGM_P(SP_W_STR, m.obj_center.w);
|
||||
#endif
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
@@ -439,7 +514,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
#if HAS_Z_AXIS && AXIS_CAN_CALIBRATE(Z)
|
||||
SERIAL_ECHOLNPGM(" Top: ", m.backlash[TOP]);
|
||||
#endif
|
||||
#if LINEAR_AXES >= 4 && AXIS_CAN_CALIBRATE(I)
|
||||
#if HAS_I_AXIS && AXIS_CAN_CALIBRATE(I)
|
||||
#if ENABLED(CALIBRATION_MEASURE_IMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_I_MIN ": ", m.backlash[IMINIMUM]);
|
||||
#endif
|
||||
@@ -447,7 +522,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" " STR_I_MAX ": ", m.backlash[IMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if LINEAR_AXES >= 5 && AXIS_CAN_CALIBRATE(J)
|
||||
#if HAS_J_AXIS && AXIS_CAN_CALIBRATE(J)
|
||||
#if ENABLED(CALIBRATION_MEASURE_JMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_J_MIN ": ", m.backlash[JMINIMUM]);
|
||||
#endif
|
||||
@@ -455,7 +530,7 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" " STR_J_MAX ": ", m.backlash[JMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if LINEAR_AXES >= 6 && AXIS_CAN_CALIBRATE(K)
|
||||
#if HAS_K_AXIS && AXIS_CAN_CALIBRATE(K)
|
||||
#if ENABLED(CALIBRATION_MEASURE_KMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_K_MIN ": ", m.backlash[KMINIMUM]);
|
||||
#endif
|
||||
@@ -463,6 +538,30 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM(" " STR_K_MAX ": ", m.backlash[KMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_U_AXIS && AXIS_CAN_CALIBRATE(U)
|
||||
#if ENABLED(CALIBRATION_MEASURE_UMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_U_MIN ": ", m.backlash[UMINIMUM]);
|
||||
#endif
|
||||
#if ENABLED(CALIBRATION_MEASURE_UMAX)
|
||||
SERIAL_ECHOLNPGM(" " STR_U_MAX ": ", m.backlash[UMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_V_AXIS && AXIS_CAN_CALIBRATE(V)
|
||||
#if ENABLED(CALIBRATION_MEASURE_VMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_V_MIN ": ", m.backlash[VMINIMUM]);
|
||||
#endif
|
||||
#if ENABLED(CALIBRATION_MEASURE_VMAX)
|
||||
SERIAL_ECHOLNPGM(" " STR_V_MAX ": ", m.backlash[VMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
#if HAS_W_AXIS && AXIS_CAN_CALIBRATE(W)
|
||||
#if ENABLED(CALIBRATION_MEASURE_WMIN)
|
||||
SERIAL_ECHOLNPGM(" " STR_W_MIN ": ", m.backlash[WMINIMUM]);
|
||||
#endif
|
||||
#if ENABLED(CALIBRATION_MEASURE_WMAX)
|
||||
SERIAL_ECHOLNPGM(" " STR_W_MAX ": ", m.backlash[WMAXIMUM]);
|
||||
#endif
|
||||
#endif
|
||||
SERIAL_EOL();
|
||||
}
|
||||
|
||||
@@ -486,7 +585,16 @@ inline void probe_sides(measurements_t &m, const float uncertainty) {
|
||||
SERIAL_ECHOLNPGM_P(SP_J_STR, m.pos_error.j);
|
||||
#endif
|
||||
#if HAS_K_CENTER && AXIS_CAN_CALIBRATE(K)
|
||||
SERIAL_ECHOLNPGM_P(SP_Z_STR, m.pos_error.z);
|
||||
SERIAL_ECHOLNPGM_P(SP_K_STR, m.pos_error.k);
|
||||
#endif
|
||||
#if HAS_U_CENTER && AXIS_CAN_CALIBRATE(U)
|
||||
SERIAL_ECHOLNPGM_P(SP_U_STR, m.pos_error.u);
|
||||
#endif
|
||||
#if HAS_V_CENTER && AXIS_CAN_CALIBRATE(V)
|
||||
SERIAL_ECHOLNPGM_P(SP_V_STR, m.pos_error.v);
|
||||
#endif
|
||||
#if HAS_W_CENTER && AXIS_CAN_CALIBRATE(W)
|
||||
SERIAL_ECHOLNPGM_P(SP_W_STR, m.pos_error.w);
|
||||
#endif
|
||||
SERIAL_EOL();
|
||||
}
|
||||
@@ -526,7 +634,7 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
|
||||
|
||||
{
|
||||
// New scope for TEMPORARY_BACKLASH_CORRECTION
|
||||
TEMPORARY_BACKLASH_CORRECTION(all_off);
|
||||
TEMPORARY_BACKLASH_CORRECTION(backlash.all_off);
|
||||
TEMPORARY_BACKLASH_SMOOTHING(0.0f);
|
||||
|
||||
probe_sides(m, uncertainty);
|
||||
@@ -534,45 +642,69 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
|
||||
#if ENABLED(BACKLASH_GCODE)
|
||||
|
||||
#if HAS_X_CENTER
|
||||
backlash.distance_mm.x = (m.backlash[LEFT] + m.backlash[RIGHT]) / 2;
|
||||
backlash.set_distance_mm(X_AXIS, (m.backlash[LEFT] + m.backlash[RIGHT]) / 2);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_LEFT)
|
||||
backlash.distance_mm.x = m.backlash[LEFT];
|
||||
backlash.set_distance_mm(X_AXIS, m.backlash[LEFT]);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_RIGHT)
|
||||
backlash.distance_mm.x = m.backlash[RIGHT];
|
||||
backlash.set_distance_mm(X_AXIS, m.backlash[RIGHT]);
|
||||
#endif
|
||||
|
||||
#if HAS_Y_CENTER
|
||||
backlash.distance_mm.y = (m.backlash[FRONT] + m.backlash[BACK]) / 2;
|
||||
backlash.set_distance_mm(Y_AXIS, (m.backlash[FRONT] + m.backlash[BACK]) / 2);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_FRONT)
|
||||
backlash.distance_mm.y = m.backlash[FRONT];
|
||||
backlash.set_distance_mm(Y_AXIS, m.backlash[FRONT]);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_BACK)
|
||||
backlash.distance_mm.y = m.backlash[BACK];
|
||||
backlash.set_distance_mm(Y_AXIS, m.backlash[BACK]);
|
||||
#endif
|
||||
|
||||
TERN_(HAS_Z_AXIS, if (AXIS_CAN_CALIBRATE(Z)) backlash.distance_mm.z = m.backlash[TOP]);
|
||||
TERN_(HAS_Z_AXIS, if (AXIS_CAN_CALIBRATE(Z)) backlash.set_distance_mm(Z_AXIS, m.backlash[TOP]));
|
||||
|
||||
#if HAS_I_CENTER
|
||||
backlash.distance_mm.i = (m.backlash[IMINIMUM] + m.backlash[IMAXIMUM]) / 2;
|
||||
backlash.set_distance_mm(I_AXIS, (m.backlash[IMINIMUM] + m.backlash[IMAXIMUM]) / 2);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_IMIN)
|
||||
backlash.distance_mm.i = m.backlash[IMINIMUM];
|
||||
backlash.set_distance_mm(I_AXIS, m.backlash[IMINIMUM]);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_IMAX)
|
||||
backlash.distance_mm.i = m.backlash[IMAXIMUM];
|
||||
backlash.set_distance_mm(I_AXIS, m.backlash[IMAXIMUM]);
|
||||
#endif
|
||||
|
||||
#if HAS_J_CENTER
|
||||
backlash.distance_mm.j = (m.backlash[JMINIMUM] + m.backlash[JMAXIMUM]) / 2;
|
||||
backlash.set_distance_mm(J_AXIS, (m.backlash[JMINIMUM] + m.backlash[JMAXIMUM]) / 2);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_JMIN)
|
||||
backlash.distance_mm.j = m.backlash[JMINIMUM];
|
||||
backlash.set_distance_mm(J_AXIS, m.backlash[JMINIMUM]);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_JMAX)
|
||||
backlash.distance_mm.j = m.backlash[JMAXIMUM];
|
||||
backlash.set_distance_mm(J_AXIS, m.backlash[JMAXIMUM]);
|
||||
#endif
|
||||
|
||||
#if HAS_K_CENTER
|
||||
backlash.distance_mm.k = (m.backlash[KMINIMUM] + m.backlash[KMAXIMUM]) / 2;
|
||||
backlash.set_distance_mm(K_AXIS, (m.backlash[KMINIMUM] + m.backlash[KMAXIMUM]) / 2);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_KMIN)
|
||||
backlash.distance_mm.k = m.backlash[KMINIMUM];
|
||||
backlash.set_distance_mm(K_AXIS, m.backlash[KMINIMUM]);
|
||||
#elif ENABLED(CALIBRATION_MEASURE_KMAX)
|
||||
backlash.distance_mm.k = m.backlash[KMAXIMUM];
|
||||
backlash.set_distance_mm(K_AXIS, m.backlash[KMAXIMUM]);
|
||||
#endif
|
||||
|
||||
#if HAS_U_CENTER
|
||||
backlash.distance_mm.u = (m.backlash[UMINIMUM] + m.backlash[UMAXIMUM]) / 2;
|
||||
#elif ENABLED(CALIBRATION_MEASURE_UMIN)
|
||||
backlash.distance_mm.u = m.backlash[UMINIMUM];
|
||||
#elif ENABLED(CALIBRATION_MEASURE_UMAX)
|
||||
backlash.distance_mm.u = m.backlash[UMAXIMUM];
|
||||
#endif
|
||||
|
||||
#if HAS_V_CENTER
|
||||
backlash.distance_mm.v = (m.backlash[VMINIMUM] + m.backlash[VMAXIMUM]) / 2;
|
||||
#elif ENABLED(CALIBRATION_MEASURE_VMIN)
|
||||
backlash.distance_mm.v = m.backlash[VMINIMUM];
|
||||
#elif ENABLED(CALIBRATION_MEASURE_UMAX)
|
||||
backlash.distance_mm.v = m.backlash[VMAXIMUM];
|
||||
#endif
|
||||
|
||||
#if HAS_W_CENTER
|
||||
backlash.distance_mm.w = (m.backlash[WMINIMUM] + m.backlash[WMAXIMUM]) / 2;
|
||||
#elif ENABLED(CALIBRATION_MEASURE_WMIN)
|
||||
backlash.distance_mm.w = m.backlash[WMINIMUM];
|
||||
#elif ENABLED(CALIBRATION_MEASURE_WMAX)
|
||||
backlash.distance_mm.w = m.backlash[WMAXIMUM];
|
||||
#endif
|
||||
|
||||
#endif // BACKLASH_GCODE
|
||||
@@ -583,11 +715,12 @@ inline void calibrate_backlash(measurements_t &m, const float uncertainty) {
|
||||
// allowed directions to take up any backlash
|
||||
{
|
||||
// New scope for TEMPORARY_BACKLASH_CORRECTION
|
||||
TEMPORARY_BACKLASH_CORRECTION(all_on);
|
||||
TEMPORARY_BACKLASH_CORRECTION(backlash.all_on);
|
||||
TEMPORARY_BACKLASH_SMOOTHING(0.0f);
|
||||
const xyz_float_t move = LINEAR_AXIS_ARRAY(
|
||||
const xyz_float_t move = NUM_AXIS_ARRAY(
|
||||
AXIS_CAN_CALIBRATE(X) * 3, AXIS_CAN_CALIBRATE(Y) * 3, AXIS_CAN_CALIBRATE(Z) * 3,
|
||||
AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3
|
||||
AXIS_CAN_CALIBRATE(I) * 3, AXIS_CAN_CALIBRATE(J) * 3, AXIS_CAN_CALIBRATE(K) * 3,
|
||||
AXIS_CAN_CALIBRATE(U) * 3, AXIS_CAN_CALIBRATE(V) * 3, AXIS_CAN_CALIBRATE(W) * 3
|
||||
);
|
||||
current_position += move; calibration_move();
|
||||
current_position -= move; calibration_move();
|
||||
@@ -613,7 +746,7 @@ inline void update_measurements(measurements_t &m, const AxisEnum axis) {
|
||||
* - Call calibrate_backlash() beforehand for best accuracy
|
||||
*/
|
||||
inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const uint8_t extruder) {
|
||||
TEMPORARY_BACKLASH_CORRECTION(all_on);
|
||||
TEMPORARY_BACKLASH_CORRECTION(backlash.all_on);
|
||||
TEMPORARY_BACKLASH_SMOOTHING(0.0f);
|
||||
|
||||
TERN(HAS_MULTI_HOTEND, set_nozzle(m, extruder), UNUSED(extruder));
|
||||
@@ -638,6 +771,9 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const
|
||||
TERN_(HAS_I_CENTER, update_measurements(m, I_AXIS));
|
||||
TERN_(HAS_J_CENTER, update_measurements(m, J_AXIS));
|
||||
TERN_(HAS_K_CENTER, update_measurements(m, K_AXIS));
|
||||
TERN_(HAS_U_CENTER, update_measurements(m, U_AXIS));
|
||||
TERN_(HAS_V_CENTER, update_measurements(m, V_AXIS));
|
||||
TERN_(HAS_W_CENTER, update_measurements(m, W_AXIS));
|
||||
|
||||
sync_plan_position();
|
||||
}
|
||||
@@ -650,7 +786,7 @@ inline void calibrate_toolhead(measurements_t &m, const float uncertainty, const
|
||||
* uncertainty in - How far away from the object to begin probing
|
||||
*/
|
||||
inline void calibrate_all_toolheads(measurements_t &m, const float uncertainty) {
|
||||
TEMPORARY_BACKLASH_CORRECTION(all_on);
|
||||
TEMPORARY_BACKLASH_CORRECTION(backlash.all_on);
|
||||
TEMPORARY_BACKLASH_SMOOTHING(0.0f);
|
||||
|
||||
HOTEND_LOOP() calibrate_toolhead(m, uncertainty, e);
|
||||
@@ -666,7 +802,7 @@ inline void calibrate_all_toolheads(measurements_t &m, const float uncertainty)
|
||||
* 1) For each nozzle, touch top and sides of object to determine object position and
|
||||
* nozzle offsets. Do a fast but rough search over a wider area.
|
||||
* 2) With the first nozzle, touch top and sides of object to determine backlash values
|
||||
* for all axis (if BACKLASH_GCODE is enabled)
|
||||
* for all axes (if BACKLASH_GCODE is enabled)
|
||||
* 3) For each nozzle, touch top and sides of object slowly to determine precise
|
||||
* position of object. Adjust coordinate system and nozzle offsets so probed object
|
||||
* location corresponds to known object location with a high degree of precision.
|
||||
@@ -676,7 +812,7 @@ inline void calibrate_all() {
|
||||
|
||||
TERN_(HAS_HOTEND_OFFSET, reset_hotend_offsets());
|
||||
|
||||
TEMPORARY_BACKLASH_CORRECTION(all_on);
|
||||
TEMPORARY_BACKLASH_CORRECTION(backlash.all_on);
|
||||
TEMPORARY_BACKLASH_SMOOTHING(0.0f);
|
||||
|
||||
// Do a fast and rough calibration of the toolheads
|
||||
@@ -709,7 +845,7 @@ inline void calibrate_all() {
|
||||
void GcodeSuite::G425() {
|
||||
|
||||
#ifdef CALIBRATION_SCRIPT_PRE
|
||||
GcodeSuite::process_subcommands_now_P(PSTR(CALIBRATION_SCRIPT_PRE));
|
||||
process_subcommands_now(F(CALIBRATION_SCRIPT_PRE));
|
||||
#endif
|
||||
|
||||
if (homing_needed_error()) return;
|
||||
@@ -745,7 +881,7 @@ void GcodeSuite::G425() {
|
||||
SET_SOFT_ENDSTOP_LOOSE(false);
|
||||
|
||||
#ifdef CALIBRATION_SCRIPT_POST
|
||||
GcodeSuite::process_subcommands_now_P(PSTR(CALIBRATION_SCRIPT_POST));
|
||||
process_subcommands_now(F(CALIBRATION_SCRIPT_POST));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -1,358 +0,0 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* G76_M871.cpp - Temperature calibration/compensation for z-probing
|
||||
*/
|
||||
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
|
||||
#if ENABLED(PROBE_TEMP_COMPENSATION)
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/probe.h"
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#include "../../module/temperature.h"
|
||||
#include "../../module/probe.h"
|
||||
#include "../../feature/probe_temp_comp.h"
|
||||
#include "../../lcd/marlinui.h"
|
||||
|
||||
/**
|
||||
* G76: calibrate probe and/or bed temperature offsets
|
||||
* Notes:
|
||||
* - When calibrating probe, bed temperature is held constant.
|
||||
* Compensation values are deltas to first probe measurement at probe temp. = 30°C.
|
||||
* - When calibrating bed, probe temperature is held constant.
|
||||
* Compensation values are deltas to first probe measurement at bed temp. = 60°C.
|
||||
* - The hotend will not be heated at any time.
|
||||
* - On my Průša MK3S clone I put a piece of paper between the probe and the hotend
|
||||
* so the hotend fan would not cool my probe constantly. Alternatively you could just
|
||||
* make sure the fan is not running while running the calibration process.
|
||||
*
|
||||
* Probe calibration:
|
||||
* - Moves probe to cooldown point.
|
||||
* - Heats up bed to 100°C.
|
||||
* - Moves probe to probing point (1mm above heatbed).
|
||||
* - Waits until probe reaches target temperature (30°C).
|
||||
* - Does a z-probing (=base value) and increases target temperature by 5°C.
|
||||
* - Waits until probe reaches increased target temperature.
|
||||
* - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C.
|
||||
* - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further).
|
||||
* - Compensation values of higher temperatures will be extrapolated (using linear regression first).
|
||||
* While this is not exact by any means it is still better than simply using the last compensation value.
|
||||
*
|
||||
* Bed calibration:
|
||||
* - Moves probe to cooldown point.
|
||||
* - Heats up bed to 60°C.
|
||||
* - Moves probe to probing point (1mm above heatbed).
|
||||
* - Waits until probe reaches target temperature (30°C).
|
||||
* - Does a z-probing (=base value) and increases bed temperature by 5°C.
|
||||
* - Moves probe to cooldown point.
|
||||
* - Waits until probe is below 30°C and bed has reached target temperature.
|
||||
* - Moves probe to probing point and waits until it reaches target temperature (30°C).
|
||||
* - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C.
|
||||
* - Repeats last four points until max. bed temperature reached (110°C) or timeout.
|
||||
* - Compensation values of higher temperatures will be extrapolated (using linear regression first).
|
||||
* While this is not exact by any means it is still better than simply using the last compensation value.
|
||||
*
|
||||
* G76 [B | P]
|
||||
* - no flag - Both calibration procedures will be run.
|
||||
* - `B` - Run bed temperature calibration.
|
||||
* - `P` - Run probe temperature calibration.
|
||||
*/
|
||||
|
||||
static void say_waiting_for() { SERIAL_ECHOPGM("Waiting for "); }
|
||||
static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); }
|
||||
static void say_successfully_calibrated() { SERIAL_ECHOPGM("Successfully calibrated"); }
|
||||
static void say_failed_to_calibrate() { SERIAL_ECHOPGM("!Failed to calibrate"); }
|
||||
|
||||
void GcodeSuite::G76() {
|
||||
// Check if heated bed is available and z-homing is done with probe
|
||||
#if TEMP_SENSOR_BED == 0 || !(HOMING_Z_WITH_PROBE)
|
||||
return;
|
||||
#endif
|
||||
|
||||
auto report_temps = [](millis_t &ntr, millis_t timeout=0) {
|
||||
idle_no_sleep();
|
||||
const millis_t ms = millis();
|
||||
if (ELAPSED(ms, ntr)) {
|
||||
ntr = ms + 1000;
|
||||
thermalManager.print_heater_states(active_extruder);
|
||||
}
|
||||
return (timeout && ELAPSED(ms, timeout));
|
||||
};
|
||||
|
||||
auto wait_for_temps = [&](const celsius_t tb, const celsius_t tp, millis_t &ntr, const millis_t timeout=0) {
|
||||
say_waiting_for(); SERIAL_ECHOLNPGM("bed and probe temperature.");
|
||||
while (thermalManager.wholeDegBed() != tb || thermalManager.wholeDegProbe() > tp)
|
||||
if (report_temps(ntr, timeout)) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
auto g76_probe = [](const TempSensorID sid, celsius_t &targ, const xy_pos_t &nozpos) {
|
||||
do_z_clearance(5.0); // Raise nozzle before probing
|
||||
const float measured_z = probe.probe_at_point(nozpos, PROBE_PT_STOW, 0, false); // verbose=0, probe_relative=false
|
||||
if (isnan(measured_z))
|
||||
SERIAL_ECHOLNPGM("!Received NAN. Aborting.");
|
||||
else {
|
||||
SERIAL_ECHOLNPAIR_F("Measured: ", measured_z);
|
||||
if (targ == cali_info_init[sid].start_temp)
|
||||
temp_comp.prepare_new_calibration(measured_z);
|
||||
else
|
||||
temp_comp.push_back_new_measurement(sid, measured_z);
|
||||
targ += cali_info_init[sid].temp_res;
|
||||
}
|
||||
return measured_z;
|
||||
};
|
||||
|
||||
#if ENABLED(BLTOUCH)
|
||||
// Make sure any BLTouch error condition is cleared
|
||||
bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY);
|
||||
set_bltouch_deployed(false);
|
||||
#endif
|
||||
|
||||
bool do_bed_cal = parser.boolval('B'), do_probe_cal = parser.boolval('P');
|
||||
if (!do_bed_cal && !do_probe_cal) do_bed_cal = do_probe_cal = true;
|
||||
|
||||
// Synchronize with planner
|
||||
planner.synchronize();
|
||||
|
||||
const xyz_pos_t parkpos = temp_comp.park_point,
|
||||
probe_pos_xyz = xyz_pos_t(temp_comp.measure_point) + xyz_pos_t({ 0.0f, 0.0f, PTC_PROBE_HEATING_OFFSET }),
|
||||
noz_pos_xyz = probe_pos_xyz - probe.offset_xy; // Nozzle position based on probe position
|
||||
|
||||
if (do_bed_cal || do_probe_cal) {
|
||||
// Ensure park position is reachable
|
||||
bool reachable = position_is_reachable(parkpos) || WITHIN(parkpos.z, Z_MIN_POS - fslop, Z_MAX_POS + fslop);
|
||||
if (!reachable)
|
||||
SERIAL_ECHOLNPGM("!Park");
|
||||
else {
|
||||
// Ensure probe position is reachable
|
||||
reachable = probe.can_reach(probe_pos_xyz);
|
||||
if (!reachable) SERIAL_ECHOLNPGM("!Probe");
|
||||
}
|
||||
|
||||
if (!reachable) {
|
||||
SERIAL_ECHOLNPGM(" position unreachable - aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
process_subcommands_now_P(G28_STR);
|
||||
}
|
||||
|
||||
remember_feedrate_scaling_off();
|
||||
|
||||
/******************************************
|
||||
* Calibrate bed temperature offsets
|
||||
******************************************/
|
||||
|
||||
// Report temperatures every second and handle heating timeouts
|
||||
millis_t next_temp_report = millis() + 1000;
|
||||
|
||||
auto report_targets = [&](const celsius_t tb, const celsius_t tp) {
|
||||
SERIAL_ECHOLNPGM("Target Bed:", tb, " Probe:", tp);
|
||||
};
|
||||
|
||||
if (do_bed_cal) {
|
||||
|
||||
celsius_t target_bed = cali_info_init[TSI_BED].start_temp,
|
||||
target_probe = temp_comp.bed_calib_probe_temp;
|
||||
|
||||
say_waiting_for(); SERIAL_ECHOLNPGM(" cooling.");
|
||||
while (thermalManager.wholeDegBed() > target_bed || thermalManager.wholeDegProbe() > target_probe)
|
||||
report_temps(next_temp_report);
|
||||
|
||||
// Disable leveling so it won't mess with us
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
|
||||
|
||||
for (;;) {
|
||||
thermalManager.setTargetBed(target_bed);
|
||||
|
||||
report_targets(target_bed, target_probe);
|
||||
|
||||
// Park nozzle
|
||||
do_blocking_move_to(parkpos);
|
||||
|
||||
// Wait for heatbed to reach target temp and probe to cool below target temp
|
||||
if (wait_for_temps(target_bed, target_probe, next_temp_report, millis() + MIN_TO_MS(15))) {
|
||||
SERIAL_ECHOLNPGM("!Bed heating timeout.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Move the nozzle to the probing point and wait for the probe to reach target temp
|
||||
do_blocking_move_to(noz_pos_xyz);
|
||||
say_waiting_for_probe_heating();
|
||||
SERIAL_EOL();
|
||||
while (thermalManager.wholeDegProbe() < target_probe)
|
||||
report_temps(next_temp_report);
|
||||
|
||||
const float measured_z = g76_probe(TSI_BED, target_bed, noz_pos_xyz);
|
||||
if (isnan(measured_z) || target_bed > (BED_MAX_TARGET)) break;
|
||||
}
|
||||
|
||||
SERIAL_ECHOLNPGM("Retrieved measurements: ", temp_comp.get_index());
|
||||
if (temp_comp.finish_calibration(TSI_BED)) {
|
||||
say_successfully_calibrated();
|
||||
SERIAL_ECHOLNPGM(" bed.");
|
||||
}
|
||||
else {
|
||||
say_failed_to_calibrate();
|
||||
SERIAL_ECHOLNPGM(" bed. Values reset.");
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
thermalManager.setTargetBed(0);
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(true));
|
||||
} // do_bed_cal
|
||||
|
||||
/********************************************
|
||||
* Calibrate probe temperature offsets
|
||||
********************************************/
|
||||
|
||||
if (do_probe_cal) {
|
||||
|
||||
// Park nozzle
|
||||
do_blocking_move_to(parkpos);
|
||||
|
||||
// Initialize temperatures
|
||||
const celsius_t target_bed = temp_comp.probe_calib_bed_temp;
|
||||
thermalManager.setTargetBed(target_bed);
|
||||
|
||||
celsius_t target_probe = cali_info_init[TSI_PROBE].start_temp;
|
||||
|
||||
report_targets(target_bed, target_probe);
|
||||
|
||||
// Wait for heatbed to reach target temp and probe to cool below target temp
|
||||
wait_for_temps(target_bed, target_probe, next_temp_report);
|
||||
|
||||
// Disable leveling so it won't mess with us
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
|
||||
|
||||
bool timeout = false;
|
||||
for (;;) {
|
||||
// Move probe to probing point and wait for it to reach target temperature
|
||||
do_blocking_move_to(noz_pos_xyz);
|
||||
|
||||
say_waiting_for_probe_heating();
|
||||
SERIAL_ECHOLNPGM(" Bed:", target_bed, " Probe:", target_probe);
|
||||
const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL);
|
||||
while (thermalManager.degProbe() < target_probe) {
|
||||
if (report_temps(next_temp_report, probe_timeout_ms)) {
|
||||
SERIAL_ECHOLNPGM("!Probe heating timed out.");
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (timeout) break;
|
||||
|
||||
const float measured_z = g76_probe(TSI_PROBE, target_probe, noz_pos_xyz);
|
||||
if (isnan(measured_z) || target_probe > cali_info_init[TSI_PROBE].end_temp) break;
|
||||
}
|
||||
|
||||
SERIAL_ECHOLNPGM("Retrieved measurements: ", temp_comp.get_index());
|
||||
if (temp_comp.finish_calibration(TSI_PROBE))
|
||||
say_successfully_calibrated();
|
||||
else
|
||||
say_failed_to_calibrate();
|
||||
SERIAL_ECHOLNPGM(" probe.");
|
||||
|
||||
// Cleanup
|
||||
thermalManager.setTargetBed(0);
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(true));
|
||||
|
||||
SERIAL_ECHOLNPGM("Final compensation values:");
|
||||
temp_comp.print_offsets();
|
||||
} // do_probe_cal
|
||||
|
||||
restore_feedrate_and_scaling();
|
||||
}
|
||||
|
||||
/**
|
||||
* M871: Report / reset temperature compensation offsets.
|
||||
* Note: This does not affect values in EEPROM until M500.
|
||||
*
|
||||
* M871 [ R | B | P | E ]
|
||||
*
|
||||
* No Parameters - Print current offset values.
|
||||
*
|
||||
* Select only one of these flags:
|
||||
* R - Reset all offsets to zero (i.e., disable compensation).
|
||||
* B - Manually set offset for bed
|
||||
* P - Manually set offset for probe
|
||||
* E - Manually set offset for extruder
|
||||
*
|
||||
* With B, P, or E:
|
||||
* I[index] - Index in the array
|
||||
* V[value] - Adjustment in µm
|
||||
*/
|
||||
void GcodeSuite::M871() {
|
||||
|
||||
if (parser.seen('R')) {
|
||||
// Reset z-probe offsets to factory defaults
|
||||
temp_comp.clear_all_offsets();
|
||||
SERIAL_ECHOLNPGM("Offsets reset to default.");
|
||||
}
|
||||
else if (parser.seen("BPE")) {
|
||||
if (!parser.seenval('V')) return;
|
||||
const int16_t offset_val = parser.value_int();
|
||||
if (!parser.seenval('I')) return;
|
||||
const int16_t idx = parser.value_int();
|
||||
const TempSensorID mod = (parser.seen('B') ? TSI_BED :
|
||||
#if ENABLED(USE_TEMP_EXT_COMPENSATION)
|
||||
parser.seen('E') ? TSI_EXT :
|
||||
#endif
|
||||
TSI_PROBE
|
||||
);
|
||||
if (idx > 0 && temp_comp.set_offset(mod, idx - 1, offset_val))
|
||||
SERIAL_ECHOLNPGM("Set value: ", offset_val);
|
||||
else
|
||||
SERIAL_ECHOLNPGM("!Invalid index. Failed to set value (note: value at index 0 is constant).");
|
||||
|
||||
}
|
||||
else // Print current Z-probe adjustments. Note: Values in EEPROM might differ.
|
||||
temp_comp.print_offsets();
|
||||
}
|
||||
|
||||
/**
|
||||
* M192: Wait for probe temperature sensor to reach a target
|
||||
*
|
||||
* Select only one of these flags:
|
||||
* R - Wait for heating or cooling
|
||||
* S - Wait only for heating
|
||||
*/
|
||||
void GcodeSuite::M192() {
|
||||
if (DEBUGGING(DRYRUN)) return;
|
||||
|
||||
const bool no_wait_for_cooling = parser.seenval('S');
|
||||
if (!no_wait_for_cooling && ! parser.seenval('R')) {
|
||||
SERIAL_ERROR_MSG("No target temperature set.");
|
||||
return;
|
||||
}
|
||||
|
||||
const celsius_t target_temp = parser.value_celsius();
|
||||
ui.set_status_P(thermalManager.isProbeBelowTemp(target_temp) ? GET_TEXT(MSG_PROBE_HEATING) : GET_TEXT(MSG_PROBE_COOLING));
|
||||
thermalManager.wait_for_probe(target_temp, no_wait_for_cooling);
|
||||
}
|
||||
|
||||
#endif // PROBE_TEMP_COMPENSATION
|
339
Marlin/src/gcode/calibrate/G76_M871.cpp
Normal file
339
Marlin/src/gcode/calibrate/G76_M871.cpp
Normal file
@@ -0,0 +1,339 @@
|
||||
/**
|
||||
* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* G76_M871.cpp - Temperature calibration/compensation for z-probing
|
||||
*/
|
||||
|
||||
#include "../../inc/MarlinConfig.h"
|
||||
|
||||
#if HAS_PTC
|
||||
|
||||
#include "../gcode.h"
|
||||
#include "../../module/motion.h"
|
||||
#include "../../module/planner.h"
|
||||
#include "../../module/probe.h"
|
||||
#include "../../feature/bedlevel/bedlevel.h"
|
||||
#include "../../module/temperature.h"
|
||||
#include "../../module/probe.h"
|
||||
#include "../../feature/probe_temp_comp.h"
|
||||
#include "../../lcd/marlinui.h"
|
||||
|
||||
/**
|
||||
* G76: calibrate probe and/or bed temperature offsets
|
||||
* Notes:
|
||||
* - When calibrating probe, bed temperature is held constant.
|
||||
* Compensation values are deltas to first probe measurement at probe temp. = 30°C.
|
||||
* - When calibrating bed, probe temperature is held constant.
|
||||
* Compensation values are deltas to first probe measurement at bed temp. = 60°C.
|
||||
* - The hotend will not be heated at any time.
|
||||
* - On my Průša MK3S clone I put a piece of paper between the probe and the hotend
|
||||
* so the hotend fan would not cool my probe constantly. Alternatively you could just
|
||||
* make sure the fan is not running while running the calibration process.
|
||||
*
|
||||
* Probe calibration:
|
||||
* - Moves probe to cooldown point.
|
||||
* - Heats up bed to 100°C.
|
||||
* - Moves probe to probing point (1mm above heatbed).
|
||||
* - Waits until probe reaches target temperature (30°C).
|
||||
* - Does a z-probing (=base value) and increases target temperature by 5°C.
|
||||
* - Waits until probe reaches increased target temperature.
|
||||
* - Does a z-probing (delta to base value will be a compensation value) and increases target temperature by 5°C.
|
||||
* - Repeats last two steps until max. temperature reached or timeout (i.e. probe does not heat up any further).
|
||||
* - Compensation values of higher temperatures will be extrapolated (using linear regression first).
|
||||
* While this is not exact by any means it is still better than simply using the last compensation value.
|
||||
*
|
||||
* Bed calibration:
|
||||
* - Moves probe to cooldown point.
|
||||
* - Heats up bed to 60°C.
|
||||
* - Moves probe to probing point (1mm above heatbed).
|
||||
* - Waits until probe reaches target temperature (30°C).
|
||||
* - Does a z-probing (=base value) and increases bed temperature by 5°C.
|
||||
* - Moves probe to cooldown point.
|
||||
* - Waits until probe is below 30°C and bed has reached target temperature.
|
||||
* - Moves probe to probing point and waits until it reaches target temperature (30°C).
|
||||
* - Does a z-probing (delta to base value will be a compensation value) and increases bed temperature by 5°C.
|
||||
* - Repeats last four points until max. bed temperature reached (110°C) or timeout.
|
||||
* - Compensation values of higher temperatures will be extrapolated (using linear regression first).
|
||||
* While this is not exact by any means it is still better than simply using the last compensation value.
|
||||
*
|
||||
* G76 [B | P]
|
||||
* - no flag - Both calibration procedures will be run.
|
||||
* - `B` - Run bed temperature calibration.
|
||||
* - `P` - Run probe temperature calibration.
|
||||
*/
|
||||
|
||||
#if BOTH(PTC_PROBE, PTC_BED)
|
||||
|
||||
static void say_waiting_for() { SERIAL_ECHOPGM("Waiting for "); }
|
||||
static void say_waiting_for_probe_heating() { say_waiting_for(); SERIAL_ECHOLNPGM("probe heating."); }
|
||||
static void say_successfully_calibrated() { SERIAL_ECHOPGM("Successfully calibrated"); }
|
||||
static void say_failed_to_calibrate() { SERIAL_ECHOPGM("!Failed to calibrate"); }
|
||||
|
||||
void GcodeSuite::G76() {
|
||||
auto report_temps = [](millis_t &ntr, millis_t timeout=0) {
|
||||
idle_no_sleep();
|
||||
const millis_t ms = millis();
|
||||
if (ELAPSED(ms, ntr)) {
|
||||
ntr = ms + 1000;
|
||||
thermalManager.print_heater_states(active_extruder);
|
||||
}
|
||||
return (timeout && ELAPSED(ms, timeout));
|
||||
};
|
||||
|
||||
auto wait_for_temps = [&](const celsius_t tb, const celsius_t tp, millis_t &ntr, const millis_t timeout=0) {
|
||||
say_waiting_for(); SERIAL_ECHOLNPGM("bed and probe temperature.");
|
||||
while (thermalManager.wholeDegBed() != tb || thermalManager.wholeDegProbe() > tp)
|
||||
if (report_temps(ntr, timeout)) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
auto g76_probe = [](const TempSensorID sid, celsius_t &targ, const xy_pos_t &nozpos) {
|
||||
do_z_clearance(5.0); // Raise nozzle before probing
|
||||
ptc.set_enabled(false);
|
||||
const float measured_z = probe.probe_at_point(nozpos, PROBE_PT_STOW, 0, false); // verbose=0, probe_relative=false
|
||||
ptc.set_enabled(true);
|
||||
if (isnan(measured_z))
|
||||
SERIAL_ECHOLNPGM("!Received NAN. Aborting.");
|
||||
else {
|
||||
SERIAL_ECHOLNPAIR_F("Measured: ", measured_z);
|
||||
if (targ == ProbeTempComp::cali_info[sid].start_temp)
|
||||
ptc.prepare_new_calibration(measured_z);
|
||||
else
|
||||
ptc.push_back_new_measurement(sid, measured_z);
|
||||
targ += ProbeTempComp::cali_info[sid].temp_resolution;
|
||||
}
|
||||
return measured_z;
|
||||
};
|
||||
|
||||
#if ENABLED(BLTOUCH)
|
||||
// Make sure any BLTouch error condition is cleared
|
||||
bltouch_command(BLTOUCH_RESET, BLTOUCH_RESET_DELAY);
|
||||
set_bltouch_deployed(false);
|
||||
#endif
|
||||
|
||||
bool do_bed_cal = parser.boolval('B'), do_probe_cal = parser.boolval('P');
|
||||
if (!do_bed_cal && !do_probe_cal) do_bed_cal = do_probe_cal = true;
|
||||
|
||||
// Synchronize with planner
|
||||
planner.synchronize();
|
||||
|
||||
#ifndef PTC_PROBE_HEATING_OFFSET
|
||||
#define PTC_PROBE_HEATING_OFFSET 0
|
||||
#endif
|
||||
const xyz_pos_t parkpos = PTC_PARK_POS,
|
||||
probe_pos_xyz = xyz_pos_t(PTC_PROBE_POS) + xyz_pos_t({ 0.0f, 0.0f, PTC_PROBE_HEATING_OFFSET }),
|
||||
noz_pos_xyz = probe_pos_xyz - probe.offset_xy; // Nozzle position based on probe position
|
||||
|
||||
if (do_bed_cal || do_probe_cal) {
|
||||
// Ensure park position is reachable
|
||||
bool reachable = position_is_reachable(parkpos) || WITHIN(parkpos.z, Z_MIN_POS - fslop, Z_MAX_POS + fslop);
|
||||
if (!reachable)
|
||||
SERIAL_ECHOLNPGM("!Park");
|
||||
else {
|
||||
// Ensure probe position is reachable
|
||||
reachable = probe.can_reach(probe_pos_xyz);
|
||||
if (!reachable) SERIAL_ECHOLNPGM("!Probe");
|
||||
}
|
||||
|
||||
if (!reachable) {
|
||||
SERIAL_ECHOLNPGM(" position unreachable - aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
process_subcommands_now(FPSTR(G28_STR));
|
||||
}
|
||||
|
||||
remember_feedrate_scaling_off();
|
||||
|
||||
/******************************************
|
||||
* Calibrate bed temperature offsets
|
||||
******************************************/
|
||||
|
||||
// Report temperatures every second and handle heating timeouts
|
||||
millis_t next_temp_report = millis() + 1000;
|
||||
|
||||
auto report_targets = [&](const celsius_t tb, const celsius_t tp) {
|
||||
SERIAL_ECHOLNPGM("Target Bed:", tb, " Probe:", tp);
|
||||
};
|
||||
|
||||
if (do_bed_cal) {
|
||||
|
||||
celsius_t target_bed = PTC_BED_START,
|
||||
target_probe = PTC_PROBE_TEMP;
|
||||
|
||||
say_waiting_for(); SERIAL_ECHOLNPGM(" cooling.");
|
||||
while (thermalManager.wholeDegBed() > target_bed || thermalManager.wholeDegProbe() > target_probe)
|
||||
report_temps(next_temp_report);
|
||||
|
||||
// Disable leveling so it won't mess with us
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
|
||||
|
||||
for (uint8_t idx = 0; idx <= PTC_BED_COUNT; idx++) {
|
||||
thermalManager.setTargetBed(target_bed);
|
||||
|
||||
report_targets(target_bed, target_probe);
|
||||
|
||||
// Park nozzle
|
||||
do_blocking_move_to(parkpos);
|
||||
|
||||
// Wait for heatbed to reach target temp and probe to cool below target temp
|
||||
if (wait_for_temps(target_bed, target_probe, next_temp_report, millis() + MIN_TO_MS(15))) {
|
||||
SERIAL_ECHOLNPGM("!Bed heating timeout.");
|
||||
break;
|
||||
}
|
||||
|
||||
// Move the nozzle to the probing point and wait for the probe to reach target temp
|
||||
do_blocking_move_to(noz_pos_xyz);
|
||||
say_waiting_for_probe_heating();
|
||||
SERIAL_EOL();
|
||||
while (thermalManager.wholeDegProbe() < target_probe)
|
||||
report_temps(next_temp_report);
|
||||
|
||||
const float measured_z = g76_probe(TSI_BED, target_bed, noz_pos_xyz);
|
||||
if (isnan(measured_z) || target_bed > (BED_MAX_TARGET)) break;
|
||||
}
|
||||
|
||||
SERIAL_ECHOLNPGM("Retrieved measurements: ", ptc.get_index());
|
||||
if (ptc.finish_calibration(TSI_BED)) {
|
||||
say_successfully_calibrated();
|
||||
SERIAL_ECHOLNPGM(" bed.");
|
||||
}
|
||||
else {
|
||||
say_failed_to_calibrate();
|
||||
SERIAL_ECHOLNPGM(" bed. Values reset.");
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
thermalManager.setTargetBed(0);
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(true));
|
||||
} // do_bed_cal
|
||||
|
||||
/********************************************
|
||||
* Calibrate probe temperature offsets
|
||||
********************************************/
|
||||
|
||||
if (do_probe_cal) {
|
||||
|
||||
// Park nozzle
|
||||
do_blocking_move_to(parkpos);
|
||||
|
||||
// Initialize temperatures
|
||||
const celsius_t target_bed = BED_MAX_TARGET;
|
||||
thermalManager.setTargetBed(target_bed);
|
||||
|
||||
celsius_t target_probe = PTC_PROBE_START;
|
||||
|
||||
report_targets(target_bed, target_probe);
|
||||
|
||||
// Wait for heatbed to reach target temp and probe to cool below target temp
|
||||
wait_for_temps(target_bed, target_probe, next_temp_report);
|
||||
|
||||
// Disable leveling so it won't mess with us
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
|
||||
|
||||
bool timeout = false;
|
||||
for (uint8_t idx = 0; idx <= PTC_PROBE_COUNT; idx++) {
|
||||
// Move probe to probing point and wait for it to reach target temperature
|
||||
do_blocking_move_to(noz_pos_xyz);
|
||||
|
||||
say_waiting_for_probe_heating();
|
||||
SERIAL_ECHOLNPGM(" Bed:", target_bed, " Probe:", target_probe);
|
||||
const millis_t probe_timeout_ms = millis() + SEC_TO_MS(900UL);
|
||||
while (thermalManager.degProbe() < target_probe) {
|
||||
if (report_temps(next_temp_report, probe_timeout_ms)) {
|
||||
SERIAL_ECHOLNPGM("!Probe heating timed out.");
|
||||
timeout = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (timeout) break;
|
||||
|
||||
const float measured_z = g76_probe(TSI_PROBE, target_probe, noz_pos_xyz);
|
||||
if (isnan(measured_z)) break;
|
||||
}
|
||||
|
||||
SERIAL_ECHOLNPGM("Retrieved measurements: ", ptc.get_index());
|
||||
if (ptc.finish_calibration(TSI_PROBE))
|
||||
say_successfully_calibrated();
|
||||
else
|
||||
say_failed_to_calibrate();
|
||||
SERIAL_ECHOLNPGM(" probe.");
|
||||
|
||||
// Cleanup
|
||||
thermalManager.setTargetBed(0);
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(true));
|
||||
|
||||
SERIAL_ECHOLNPGM("Final compensation values:");
|
||||
ptc.print_offsets();
|
||||
} // do_probe_cal
|
||||
|
||||
restore_feedrate_and_scaling();
|
||||
}
|
||||
|
||||
#endif // PTC_PROBE && PTC_BED
|
||||
|
||||
/**
|
||||
* M871: Report / reset temperature compensation offsets.
|
||||
* Note: This does not affect values in EEPROM until M500.
|
||||
*
|
||||
* M871 [ R | B | P | E ]
|
||||
*
|
||||
* No Parameters - Print current offset values.
|
||||
*
|
||||
* Select only one of these flags:
|
||||
* R - Reset all offsets to zero (i.e., disable compensation).
|
||||
* B - Manually set offset for bed
|
||||
* P - Manually set offset for probe
|
||||
* E - Manually set offset for extruder
|
||||
*
|
||||
* With B, P, or E:
|
||||
* I[index] - Index in the array
|
||||
* V[value] - Adjustment in µm
|
||||
*/
|
||||
void GcodeSuite::M871() {
|
||||
|
||||
if (parser.seen('R')) {
|
||||
// Reset z-probe offsets to factory defaults
|
||||
ptc.clear_all_offsets();
|
||||
SERIAL_ECHOLNPGM("Offsets reset to default.");
|
||||
}
|
||||
else if (parser.seen("BPE")) {
|
||||
if (!parser.seenval('V')) return;
|
||||
const int16_t offset_val = parser.value_int();
|
||||
if (!parser.seenval('I')) return;
|
||||
const int16_t idx = parser.value_int();
|
||||
const TempSensorID mod = TERN_(PTC_BED, parser.seen_test('B') ? TSI_BED :)
|
||||
TERN_(PTC_HOTEND, parser.seen_test('E') ? TSI_EXT :)
|
||||
TERN_(PTC_PROBE, parser.seen_test('P') ? TSI_PROBE :) TSI_COUNT;
|
||||
if (mod == TSI_COUNT)
|
||||
SERIAL_ECHOLNPGM("!Invalid sensor.");
|
||||
else if (idx > 0 && ptc.set_offset(mod, idx - 1, offset_val))
|
||||
SERIAL_ECHOLNPGM("Set value: ", offset_val);
|
||||
else
|
||||
SERIAL_ECHOLNPGM("!Invalid index. Failed to set value (note: value at index 0 is constant).");
|
||||
}
|
||||
else // Print current Z-probe adjustments. Note: Values in EEPROM might differ.
|
||||
ptc.print_offsets();
|
||||
}
|
||||
|
||||
#endif // HAS_PTC
|
@@ -51,7 +51,7 @@
|
||||
* Also, there are two support functions that can be called from a developer's C code.
|
||||
*
|
||||
* uint16_t check_for_free_memory_corruption(PGM_P const free_memory_start);
|
||||
* void M100_dump_routine(PGM_P const title, const char * const start, const uintptr_t size);
|
||||
* void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size);
|
||||
*
|
||||
* Initial version by Roxy-3D
|
||||
*/
|
||||
@@ -182,8 +182,8 @@ inline int32_t count_test_bytes(const char * const start_free_memory) {
|
||||
}
|
||||
}
|
||||
|
||||
void M100_dump_routine(PGM_P const title, const char * const start, const uintptr_t size) {
|
||||
SERIAL_ECHOLNPGM_P(title);
|
||||
void M100_dump_routine(FSTR_P const title, const char * const start, const uintptr_t size) {
|
||||
SERIAL_ECHOLNF(title);
|
||||
//
|
||||
// Round the start and end locations to produce full lines of output
|
||||
//
|
||||
@@ -196,8 +196,8 @@ inline int32_t count_test_bytes(const char * const start_free_memory) {
|
||||
|
||||
#endif // M100_FREE_MEMORY_DUMPER
|
||||
|
||||
inline int check_for_free_memory_corruption(PGM_P const title) {
|
||||
SERIAL_ECHOPGM_P(title);
|
||||
inline int check_for_free_memory_corruption(FSTR_P const title) {
|
||||
SERIAL_ECHOF(title);
|
||||
|
||||
char *start_free_memory = free_memory_start, *end_free_memory = free_memory_end;
|
||||
int n = end_free_memory - start_free_memory;
|
||||
@@ -217,7 +217,7 @@ inline int check_for_free_memory_corruption(PGM_P const title) {
|
||||
// idle();
|
||||
serial_delay(20);
|
||||
#if ENABLED(M100_FREE_MEMORY_DUMPER)
|
||||
M100_dump_routine(PSTR(" Memory corruption detected with end_free_memory<Heap\n"), (const char*)0x1B80, 0x0680);
|
||||
M100_dump_routine(F(" Memory corruption detected with end_free_memory<Heap\n"), (const char*)0x1B80, 0x0680);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ inline void free_memory_pool_report(char * const start_free_memory, const int32_
|
||||
"\nMemory Corruption detected in free memory area."
|
||||
"\nLargest free block is ", max_cnt, " bytes at ", hex_address(max_addr)
|
||||
);
|
||||
SERIAL_ECHOLNPGM("check_for_free_memory_corruption() = ", check_for_free_memory_corruption(PSTR("M100 F ")));
|
||||
SERIAL_ECHOLNPGM("check_for_free_memory_corruption() = ", check_for_free_memory_corruption(F("M100 F ")));
|
||||
}
|
||||
|
||||
#if ENABLED(M100_FREE_MEMORY_CORRUPTOR)
|
||||
|
@@ -47,23 +47,17 @@ void GcodeSuite::M425() {
|
||||
bool noArgs = true;
|
||||
|
||||
auto axis_can_calibrate = [](const uint8_t a) {
|
||||
#define _CAN_CASE(N) case N##_AXIS: return AXIS_CAN_CALIBRATE(N);
|
||||
switch (a) {
|
||||
default: return false;
|
||||
LINEAR_AXIS_CODE(
|
||||
case X_AXIS: return AXIS_CAN_CALIBRATE(X),
|
||||
case Y_AXIS: return AXIS_CAN_CALIBRATE(Y),
|
||||
case Z_AXIS: return AXIS_CAN_CALIBRATE(Z),
|
||||
case I_AXIS: return AXIS_CAN_CALIBRATE(I),
|
||||
case J_AXIS: return AXIS_CAN_CALIBRATE(J),
|
||||
case K_AXIS: return AXIS_CAN_CALIBRATE(K),
|
||||
);
|
||||
MAIN_AXIS_MAP(_CAN_CASE)
|
||||
}
|
||||
};
|
||||
|
||||
LOOP_LINEAR_AXES(a) {
|
||||
LOOP_NUM_AXES(a) {
|
||||
if (axis_can_calibrate(a) && parser.seen(AXIS_CHAR(a))) {
|
||||
planner.synchronize();
|
||||
backlash.distance_mm[a] = parser.has_value() ? parser.value_linear_units() : backlash.get_measurement(AxisEnum(a));
|
||||
backlash.set_distance_mm((AxisEnum)a, parser.has_value() ? parser.value_axis_units((AxisEnum)a) : backlash.get_measurement((AxisEnum)a));
|
||||
noArgs = false;
|
||||
}
|
||||
}
|
||||
@@ -77,33 +71,30 @@ void GcodeSuite::M425() {
|
||||
#ifdef BACKLASH_SMOOTHING_MM
|
||||
if (parser.seen('S')) {
|
||||
planner.synchronize();
|
||||
backlash.smoothing_mm = parser.value_linear_units();
|
||||
backlash.set_smoothing_mm(parser.value_linear_units());
|
||||
noArgs = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (noArgs) {
|
||||
SERIAL_ECHOPGM("Backlash Correction ");
|
||||
if (!backlash.correction) SERIAL_ECHOPGM("in");
|
||||
if (!backlash.get_correction_uint8()) SERIAL_ECHOPGM("in");
|
||||
SERIAL_ECHOLNPGM("active:");
|
||||
SERIAL_ECHOLNPGM(" Correction Amount/Fade-out: F", backlash.get_correction(), " (F1.0 = full, F0.0 = none)");
|
||||
SERIAL_ECHOPGM(" Backlash Distance (mm): ");
|
||||
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a)) {
|
||||
SERIAL_CHAR(' ', AXIS_CHAR(a));
|
||||
SERIAL_ECHO(backlash.distance_mm[a]);
|
||||
SERIAL_EOL();
|
||||
LOOP_NUM_AXES(a) if (axis_can_calibrate(a)) {
|
||||
SERIAL_ECHOLNPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_distance_mm((AxisEnum)a));
|
||||
}
|
||||
|
||||
#ifdef BACKLASH_SMOOTHING_MM
|
||||
SERIAL_ECHOLNPGM(" Smoothing (mm): S", backlash.smoothing_mm);
|
||||
SERIAL_ECHOLNPGM(" Smoothing (mm): S", backlash.get_smoothing_mm());
|
||||
#endif
|
||||
|
||||
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
|
||||
SERIAL_ECHOPGM(" Average measured backlash (mm):");
|
||||
if (backlash.has_any_measurement()) {
|
||||
LOOP_LINEAR_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
|
||||
SERIAL_CHAR(' ', AXIS_CHAR(a));
|
||||
SERIAL_ECHO(backlash.get_measurement(AxisEnum(a)));
|
||||
LOOP_NUM_AXES(a) if (axis_can_calibrate(a) && backlash.has_measurement(AxisEnum(a))) {
|
||||
SERIAL_ECHOPGM_P((PGM_P)pgm_read_ptr(&SP_AXIS_STR[a]), backlash.get_measurement((AxisEnum)a));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -114,19 +105,22 @@ void GcodeSuite::M425() {
|
||||
}
|
||||
|
||||
void GcodeSuite::M425_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_BACKLASH_COMPENSATION));
|
||||
report_heading_etc(forReplay, F(STR_BACKLASH_COMPENSATION));
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M425 F"), backlash.get_correction()
|
||||
#ifdef BACKLASH_SMOOTHING_MM
|
||||
, PSTR(" S"), LINEAR_UNIT(backlash.smoothing_mm)
|
||||
, PSTR(" S"), LINEAR_UNIT(backlash.get_smoothing_mm())
|
||||
#endif
|
||||
, LIST_N(DOUBLE(LINEAR_AXES),
|
||||
SP_X_STR, LINEAR_UNIT(backlash.distance_mm.x),
|
||||
SP_Y_STR, LINEAR_UNIT(backlash.distance_mm.y),
|
||||
SP_Z_STR, LINEAR_UNIT(backlash.distance_mm.z),
|
||||
SP_I_STR, LINEAR_UNIT(backlash.distance_mm.i),
|
||||
SP_J_STR, LINEAR_UNIT(backlash.distance_mm.j),
|
||||
SP_K_STR, LINEAR_UNIT(backlash.distance_mm.k)
|
||||
, LIST_N(DOUBLE(NUM_AXES),
|
||||
SP_X_STR, LINEAR_UNIT(backlash.get_distance_mm(X_AXIS)),
|
||||
SP_Y_STR, LINEAR_UNIT(backlash.get_distance_mm(Y_AXIS)),
|
||||
SP_Z_STR, LINEAR_UNIT(backlash.get_distance_mm(Z_AXIS)),
|
||||
SP_I_STR, I_AXIS_UNIT(backlash.get_distance_mm(I_AXIS)),
|
||||
SP_J_STR, J_AXIS_UNIT(backlash.get_distance_mm(J_AXIS)),
|
||||
SP_K_STR, K_AXIS_UNIT(backlash.get_distance_mm(K_AXIS)),
|
||||
SP_U_STR, U_AXIS_UNIT(backlash.get_distance_mm(U_AXIS)),
|
||||
SP_V_STR, V_AXIS_UNIT(backlash.get_distance_mm(V_AXIS)),
|
||||
SP_W_STR, W_AXIS_UNIT(backlash.get_distance_mm(W_AXIS))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@@ -35,11 +35,15 @@
|
||||
#include "../../module/planner.h"
|
||||
#endif
|
||||
|
||||
#if HAS_PTC
|
||||
#include "../../feature/probe_temp_comp.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* M48: Z probe repeatability measurement function.
|
||||
*
|
||||
* Usage:
|
||||
* M48 <P#> <X#> <Y#> <V#> <E> <L#> <S>
|
||||
* M48 <P#> <X#> <Y#> <V#> <E> <L#> <S> <C#>
|
||||
* P = Number of sampled points (4-50, default 10)
|
||||
* X = Sample X position
|
||||
* Y = Sample Y position
|
||||
@@ -47,6 +51,7 @@
|
||||
* E = Engage Z probe for each reading
|
||||
* L = Number of legs of movement before probe
|
||||
* S = Schizoid (Or Star if you prefer)
|
||||
* C = Enable probe temperature compensation (0 or 1, default 1)
|
||||
*
|
||||
* This function requires the machine to be homed before invocation.
|
||||
*/
|
||||
@@ -79,7 +84,7 @@ void GcodeSuite::M48() {
|
||||
};
|
||||
|
||||
if (!probe.can_reach(test_position)) {
|
||||
ui.set_status_P(GET_TEXT(MSG_M48_OUT_OF_BOUNDS), 99);
|
||||
ui.set_status(GET_TEXT_F(MSG_M48_OUT_OF_BOUNDS), 99);
|
||||
SERIAL_ECHOLNPGM("? (X,Y) out of bounds.");
|
||||
return;
|
||||
}
|
||||
@@ -107,6 +112,8 @@ void GcodeSuite::M48() {
|
||||
set_bed_leveling_enabled(false);
|
||||
#endif
|
||||
|
||||
TERN_(HAS_PTC, ptc.set_enabled(!parser.seen('C') || parser.value_bool()));
|
||||
|
||||
// Work with reasonable feedrates
|
||||
remember_feedrate_scaling_off();
|
||||
|
||||
@@ -144,7 +151,7 @@ void GcodeSuite::M48() {
|
||||
LOOP_L_N(n, n_samples) {
|
||||
#if HAS_STATUS_MESSAGE
|
||||
// Display M48 progress in the status bar
|
||||
ui.status_printf_P(0, PSTR(S_FMT ": %d/%d"), GET_TEXT(MSG_M48_POINT), int(n + 1), int(n_samples));
|
||||
ui.status_printf(0, F(S_FMT ": %d/%d"), GET_TEXT(MSG_M48_POINT), int(n + 1), int(n_samples));
|
||||
#endif
|
||||
|
||||
// When there are "legs" of movement move around the point before probing
|
||||
@@ -260,7 +267,7 @@ void GcodeSuite::M48() {
|
||||
#if HAS_STATUS_MESSAGE
|
||||
// Display M48 results in the status bar
|
||||
char sigma_str[8];
|
||||
ui.status_printf_P(0, PSTR(S_FMT ": %s"), GET_TEXT(MSG_M48_DEVIATION), dtostrf(sigma, 2, 6, sigma_str));
|
||||
ui.status_printf(0, F(S_FMT ": %s"), GET_TEXT(MSG_M48_DEVIATION), dtostrf(sigma, 2, 6, sigma_str));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -269,6 +276,9 @@ void GcodeSuite::M48() {
|
||||
// Re-enable bed level correction if it had been on
|
||||
TERN_(HAS_LEVELING, set_bed_leveling_enabled(was_enabled));
|
||||
|
||||
// Re-enable probe temperature correction
|
||||
TERN_(HAS_PTC, ptc.set_enabled(true));
|
||||
|
||||
report_current_position();
|
||||
}
|
||||
|
||||
|
@@ -62,7 +62,7 @@
|
||||
}
|
||||
|
||||
void GcodeSuite::M665_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_DELTA_SETTINGS));
|
||||
report_heading_etc(forReplay, F(STR_DELTA_SETTINGS));
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M665 L"), LINEAR_UNIT(delta_diagonal_rod)
|
||||
, PSTR(" R"), LINEAR_UNIT(delta_radius)
|
||||
@@ -86,13 +86,13 @@
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* S[segments-per-second] - Segments-per-second
|
||||
* S[segments] - Segments-per-second
|
||||
*
|
||||
* Without NO_WORKSPACE_OFFSETS:
|
||||
*
|
||||
* P[theta-psi-offset] - Theta-Psi offset, added to the shoulder (A/X) angle
|
||||
* T[theta-offset] - Theta offset, added to the elbow (B/Y) angle
|
||||
* Z[z-offset] - Z offset, added to Z
|
||||
* P[theta-psi-offset] - Theta-Psi offset, added to the shoulder (A/X) angle
|
||||
* T[theta-offset] - Theta offset, added to the elbow (B/Y) angle
|
||||
* Z[z-offset] - Z offset, added to Z
|
||||
*
|
||||
* A, P, and X are all aliases for the shoulder angle
|
||||
* B, T, and Y are all aliases for the elbow angle
|
||||
@@ -132,7 +132,7 @@
|
||||
}
|
||||
|
||||
void GcodeSuite::M665_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_SCARA_SETTINGS " (" STR_S_SEG_PER_SEC TERN_(HAS_SCARA_OFFSET, " " STR_SCARA_P_T_Z) ")"));
|
||||
report_heading_etc(forReplay, F(STR_SCARA_SETTINGS " (" STR_S_SEG_PER_SEC TERN_(HAS_SCARA_OFFSET, " " STR_SCARA_P_T_Z) ")"));
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M665 S"), segments_per_second
|
||||
#if HAS_SCARA_OFFSET
|
||||
@@ -152,18 +152,35 @@
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* S[segments-per-second] - Segments-per-second
|
||||
* S[segments] - Segments-per-second
|
||||
* L[left] - Work area minimum X
|
||||
* R[right] - Work area maximum X
|
||||
* T[top] - Work area maximum Y
|
||||
* B[bottom] - Work area minimum Y
|
||||
* H[length] - Maximum belt length
|
||||
*/
|
||||
void GcodeSuite::M665() {
|
||||
if (parser.seenval('S'))
|
||||
segments_per_second = parser.value_float();
|
||||
else
|
||||
M665_report();
|
||||
if (!parser.seen_any()) return M665_report();
|
||||
if (parser.seenval('S')) segments_per_second = parser.value_float();
|
||||
if (parser.seenval('L')) draw_area_min.x = parser.value_linear_units();
|
||||
if (parser.seenval('R')) draw_area_max.x = parser.value_linear_units();
|
||||
if (parser.seenval('T')) draw_area_max.y = parser.value_linear_units();
|
||||
if (parser.seenval('B')) draw_area_min.y = parser.value_linear_units();
|
||||
if (parser.seenval('H')) polargraph_max_belt_len = parser.value_linear_units();
|
||||
draw_area_size.x = draw_area_max.x - draw_area_min.x;
|
||||
draw_area_size.y = draw_area_max.y - draw_area_min.y;
|
||||
}
|
||||
|
||||
void GcodeSuite::M665_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_POLARGRAPH_SETTINGS " (" STR_S_SEG_PER_SEC ")"));
|
||||
SERIAL_ECHOLNPGM(" M665 S", segments_per_second);
|
||||
report_heading_etc(forReplay, F(STR_POLARGRAPH_SETTINGS));
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M665 S"), LINEAR_UNIT(segments_per_second),
|
||||
PSTR(" L"), LINEAR_UNIT(draw_area_min.x),
|
||||
PSTR(" R"), LINEAR_UNIT(draw_area_max.x),
|
||||
SP_T_STR, LINEAR_UNIT(draw_area_max.y),
|
||||
SP_B_STR, LINEAR_UNIT(draw_area_min.y),
|
||||
PSTR(" H"), LINEAR_UNIT(polargraph_max_belt_len)
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -44,8 +44,8 @@
|
||||
void GcodeSuite::M666() {
|
||||
DEBUG_SECTION(log_M666, "M666", DEBUGGING(LEVELING));
|
||||
bool is_err = false, is_set = false;
|
||||
LOOP_LINEAR_AXES(i) {
|
||||
if (parser.seen(AXIS_CHAR(i))) {
|
||||
LOOP_NUM_AXES(i) {
|
||||
if (parser.seenval(AXIS_CHAR(i))) {
|
||||
is_set = true;
|
||||
const float v = parser.value_linear_units();
|
||||
if (v > 0)
|
||||
@@ -61,7 +61,7 @@
|
||||
}
|
||||
|
||||
void GcodeSuite::M666_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_ENDSTOP_ADJUSTMENT));
|
||||
report_heading_etc(forReplay, F(STR_ENDSTOP_ADJUSTMENT));
|
||||
SERIAL_ECHOLNPGM_P(
|
||||
PSTR(" M666 X"), LINEAR_UNIT(delta_endstop_adj.a)
|
||||
, SP_Y_STR, LINEAR_UNIT(delta_endstop_adj.b)
|
||||
@@ -93,19 +93,19 @@
|
||||
#if ENABLED(Z_MULTI_ENDSTOPS)
|
||||
if (parser.seenval('Z')) {
|
||||
const float z_adj = parser.value_linear_units();
|
||||
#if NUM_Z_STEPPER_DRIVERS == 2
|
||||
#if NUM_Z_STEPPERS == 2
|
||||
endstops.z2_endstop_adj = z_adj;
|
||||
#else
|
||||
const int ind = parser.intval('S');
|
||||
#define _SET_ZADJ(N) if (!ind || ind == N) endstops.z##N##_endstop_adj = z_adj;
|
||||
REPEAT_S(2, INCREMENT(NUM_Z_STEPPER_DRIVERS), _SET_ZADJ)
|
||||
REPEAT_S(2, INCREMENT(NUM_Z_STEPPERS), _SET_ZADJ)
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GcodeSuite::M666_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_ENDSTOP_ADJUSTMENT));
|
||||
report_heading_etc(forReplay, F(STR_ENDSTOP_ADJUSTMENT));
|
||||
SERIAL_ECHOPGM(" M666");
|
||||
#if ENABLED(X_DUAL_ENDSTOPS)
|
||||
SERIAL_ECHOLNPGM_P(SP_X_STR, LINEAR_UNIT(endstops.x2_endstop_adj));
|
||||
@@ -114,11 +114,11 @@
|
||||
SERIAL_ECHOLNPGM_P(SP_Y_STR, LINEAR_UNIT(endstops.y2_endstop_adj));
|
||||
#endif
|
||||
#if ENABLED(Z_MULTI_ENDSTOPS)
|
||||
#if NUM_Z_STEPPER_DRIVERS >= 3
|
||||
#if NUM_Z_STEPPERS >= 3
|
||||
SERIAL_ECHOPGM(" S2 Z", LINEAR_UNIT(endstops.z3_endstop_adj));
|
||||
report_echo_start(forReplay);
|
||||
SERIAL_ECHOPGM(" M666 S3 Z", LINEAR_UNIT(endstops.z3_endstop_adj));
|
||||
#if NUM_Z_STEPPER_DRIVERS >= 4
|
||||
#if NUM_Z_STEPPERS >= 4
|
||||
report_echo_start(forReplay);
|
||||
SERIAL_ECHOPGM(" M666 S4 Z", LINEAR_UNIT(endstops.z4_endstop_adj));
|
||||
#endif
|
||||
|
@@ -92,8 +92,8 @@ void GcodeSuite::M852() {
|
||||
}
|
||||
|
||||
void GcodeSuite::M852_report(const bool forReplay/*=true*/) {
|
||||
report_heading_etc(forReplay, PSTR(STR_SKEW_FACTOR));
|
||||
SERIAL_ECHOPAIR_F(" M851 I", planner.skew_factor.xy, 6);
|
||||
report_heading_etc(forReplay, F(STR_SKEW_FACTOR));
|
||||
SERIAL_ECHOPAIR_F(" M852 I", planner.skew_factor.xy, 6);
|
||||
#if ENABLED(SKEW_CORRECTION_FOR_Z)
|
||||
SERIAL_ECHOPAIR_F(" J", planner.skew_factor.xz, 6);
|
||||
SERIAL_ECHOPAIR_F(" K", planner.skew_factor.yz, 6);
|
||||
|
Reference in New Issue
Block a user