From 2aa2e5487a2b65ca46019d2718d587777c28405c Mon Sep 17 00:00:00 2001 From: sargonphin <85966195+sargonphin@users.noreply.github.com> Date: Fri, 16 Aug 2024 01:30:55 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20Improve=20Homing=20/=20Pro?= =?UTF-8?q?bing=20Current=20(#26714)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Scott Lahteine --- Marlin/Configuration_adv.h | 9 +- Marlin/src/gcode/calibrate/G28.cpp | 135 +------ Marlin/src/gcode/calibrate/G33.cpp | 4 +- Marlin/src/inc/Conditionals_adv.h | 1 + Marlin/src/inc/Conditionals_type.h | 10 + Marlin/src/inc/SanityCheck.h | 26 +- Marlin/src/inc/Warnings.cpp | 28 +- Marlin/src/module/delta.cpp | 6 + Marlin/src/module/endstops.cpp | 91 ----- Marlin/src/module/endstops.h | 7 - Marlin/src/module/motion.cpp | 564 +++++++++++++++++++++++++++++ Marlin/src/module/motion.h | 5 + Marlin/src/module/probe.cpp | 22 +- Marlin/src/module/scara.cpp | 6 + buildroot/tests/LPC1769 | 5 +- 15 files changed, 691 insertions(+), 228 deletions(-) diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h index f02f06e270..4bea030a9a 100644 --- a/Marlin/Configuration_adv.h +++ b/Marlin/Configuration_adv.h @@ -2969,7 +2969,7 @@ #if AXIS_IS_TMC_CONFIG(X) #define X_CURRENT 800 // (mA) RMS current. Multiply by 1.414 for peak current. - #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for sensorless homing + #define X_CURRENT_HOME X_CURRENT // (mA) RMS current for homing. (Typically lower than *_CURRENT.) #define X_MICROSTEPS 16 // 0..256 #define X_RSENSE 0.11 #define X_CHAIN_POS -1 // -1..0: Not chained. 1: MCU MOSI connected. 2: Next in chain, ... @@ -3179,6 +3179,13 @@ //#define E7_HOLD_MULTIPLIER 0.5 #endif + /** + * Use the homing current for all probing. (e.g., Current may be reduced to the + * point where a collision makes the motor skip instead of damaging the bed, + * though this is unlikely to save delicate probes from being damaged. + */ + //#define PROBING_USE_CURRENT_HOME + // @section tmc/spi /** diff --git a/Marlin/src/gcode/calibrate/G28.cpp b/Marlin/src/gcode/calibrate/G28.cpp index 7468e1fc39..fb52a30690 100644 --- a/Marlin/src/gcode/calibrate/G28.cpp +++ b/Marlin/src/gcode/calibrate/G28.cpp @@ -28,6 +28,10 @@ #include "../../module/planner.h" #include "../../module/stepper.h" // for various +#if HAS_HOMING_CURRENT + #include "../../module/motion.h" // for set/restore_homing_current +#endif + #if HAS_MULTI_HOTEND #include "../../module/tool_change.h" #endif @@ -77,6 +81,14 @@ const float minfr = _MIN(homing_feedrate(X_AXIS), homing_feedrate(Y_AXIS)), fr_mm_s = HYPOT(minfr, minfr); + // Set homing current to X and Y axis if defined + #if HAS_CURRENT_HOME(X) + set_homing_current(X_AXIS); + #endif + #if HAS_CURRENT_HOME(Y) && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + set_homing_current(Y_AXIS); + #endif + #if ENABLED(SENSORLESS_HOMING) sensorless_t stealth_states { NUM_AXIS_LIST( @@ -95,6 +107,13 @@ current_position.set(0.0, 0.0); + #if HAS_CURRENT_HOME(X) + restore_homing_current(X_AXIS); + #endif + #if HAS_CURRENT_HOME(Y) && NONE(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + restore_homing_current(Y_AXIS); + #endif + #if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT) TERN_(X_SENSORLESS, tmc_disable_stallguard(stepperX, stealth_states.x)); TERN_(X2_SENSORLESS, tmc_disable_stallguard(stepperX2, stealth_states.x2)); @@ -254,73 +273,6 @@ void GcodeSuite::G28() { // Reset to the XY plane TERN_(CNC_WORKSPACE_PLANES, workspace_plane = PLANE_XY); - #define _OR_HAS_CURR_HOME(N) HAS_CURRENT_HOME(N) || - #if MAIN_AXIS_MAP(_OR_HAS_CURR_HOME) MAP(_OR_HAS_CURR_HOME, X2, Y2, Z2, Z3, Z4) 0 - #define HAS_HOMING_CURRENT 1 - #endif - - #if HAS_HOMING_CURRENT - - #if ENABLED(DEBUG_LEVELING_FEATURE) - auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) { - if (DEBUGGING(LEVELING)) { DEBUG_ECHOLN(s, F(" current: "), a, F(" -> "), b); } - }; - #else - #define debug_current(...) - #endif - - #define _SAVE_SET_CURRENT(A) \ - const int16_t saved_current_##A = stepper##A.getMilliamps(); \ - stepper##A.rms_current(A##_CURRENT_HOME); \ - debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) - - #if HAS_CURRENT_HOME(X) - _SAVE_SET_CURRENT(X); - #endif - #if HAS_CURRENT_HOME(X2) - _SAVE_SET_CURRENT(X2); - #endif - #if HAS_CURRENT_HOME(Y) - _SAVE_SET_CURRENT(Y); - #endif - #if HAS_CURRENT_HOME(Y2) - _SAVE_SET_CURRENT(Y2); - #endif - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _SAVE_SET_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _SAVE_SET_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _SAVE_SET_CURRENT(Z4); - #endif - #if HAS_CURRENT_HOME(I) - _SAVE_SET_CURRENT(I); - #endif - #if HAS_CURRENT_HOME(J) - _SAVE_SET_CURRENT(J); - #endif - #if HAS_CURRENT_HOME(K) - _SAVE_SET_CURRENT(K); - #endif - #if HAS_CURRENT_HOME(U) - _SAVE_SET_CURRENT(U); - #endif - #if HAS_CURRENT_HOME(V) - _SAVE_SET_CURRENT(V); - #endif - #if HAS_CURRENT_HOME(W) - _SAVE_SET_CURRENT(W); - #endif - #if SENSORLESS_STALLGUARD_DELAY - safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle - #endif - #endif // HAS_HOMING_CURRENT - #if ENABLED(IMPROVE_HOMING_RELIABILITY) motion_state_t saved_motion_state = begin_slow_homing(); #endif @@ -572,55 +524,6 @@ void GcodeSuite::G28() { // Clear endstop state for polled stallGuard endstops TERN_(SPI_ENDSTOPS, endstops.clear_endstop_state()); - #if HAS_HOMING_CURRENT - if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current..."); - #if HAS_CURRENT_HOME(X) - stepperX.rms_current(saved_current_X); - #endif - #if HAS_CURRENT_HOME(X2) - stepperX2.rms_current(saved_current_X2); - #endif - #if HAS_CURRENT_HOME(Y) - stepperY.rms_current(saved_current_Y); - #endif - #if HAS_CURRENT_HOME(Y2) - stepperY2.rms_current(saved_current_Y2); - #endif - #if HAS_CURRENT_HOME(Z) - stepperZ.rms_current(saved_current_Z); - #endif - #if HAS_CURRENT_HOME(Z2) - stepperZ2.rms_current(saved_current_Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - stepperZ3.rms_current(saved_current_Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - stepperZ4.rms_current(saved_current_Z4); - #endif - #if HAS_CURRENT_HOME(I) - stepperI.rms_current(saved_current_I); - #endif - #if HAS_CURRENT_HOME(J) - stepperJ.rms_current(saved_current_J); - #endif - #if HAS_CURRENT_HOME(K) - stepperK.rms_current(saved_current_K); - #endif - #if HAS_CURRENT_HOME(U) - stepperU.rms_current(saved_current_U); - #endif - #if HAS_CURRENT_HOME(V) - stepperV.rms_current(saved_current_V); - #endif - #if HAS_CURRENT_HOME(W) - stepperW.rms_current(saved_current_W); - #endif - #if SENSORLESS_STALLGUARD_DELAY - safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle - #endif - #endif // HAS_HOMING_CURRENT - // Move to a height where we can use the full xy-area TERN_(DELTA_HOME_TO_SAFE_ZONE, do_blocking_move_to_z(delta_clip_start_height)); diff --git a/Marlin/src/gcode/calibrate/G33.cpp b/Marlin/src/gcode/calibrate/G33.cpp index 12aed86316..80c4688a6e 100644 --- a/Marlin/src/gcode/calibrate/G33.cpp +++ b/Marlin/src/gcode/calibrate/G33.cpp @@ -63,9 +63,9 @@ float lcd_probe_pt(const xy_pos_t &xy); void ac_home() { endstops.enable(true); - TERN_(SENSORLESS_HOMING, endstops.set_z_sensorless_current(true)); + TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(true)); home_delta(); - TERN_(SENSORLESS_HOMING, endstops.set_z_sensorless_current(false)); + TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(false)); endstops.not_homing(); } diff --git a/Marlin/src/inc/Conditionals_adv.h b/Marlin/src/inc/Conditionals_adv.h index 3f3dcf8971..5d8c492e2b 100644 --- a/Marlin/src/inc/Conditionals_adv.h +++ b/Marlin/src/inc/Conditionals_adv.h @@ -97,6 +97,7 @@ #if !HAS_BED_PROBE #undef BABYSTEP_ZPROBE_OFFSET + #undef PROBING_USE_CURRENT_HOME #endif #if !HAS_STOWABLE_PROBE #undef PROBE_DEPLOY_STOW_MENU diff --git a/Marlin/src/inc/Conditionals_type.h b/Marlin/src/inc/Conditionals_type.h index 1f9cfcae16..e798a2d934 100644 --- a/Marlin/src/inc/Conditionals_type.h +++ b/Marlin/src/inc/Conditionals_type.h @@ -30,3 +30,13 @@ #ifdef GITHUB_ACTIONS // Extras for CI testing #endif + +// If an axis's Homing Current differs from standard current... +#define HAS_CURRENT_HOME(N) (N##_CURRENT_HOME > 0 && N##_CURRENT_HOME != N##_CURRENT) + +// Does any axis have homing current? +#define _OR_HAS_CURR_HOME(N) HAS_CURRENT_HOME(N) || +#if MAIN_AXIS_MAP(_OR_HAS_CURR_HOME) MAP(_OR_HAS_CURR_HOME, X2, Y2, Z2, Z3, Z4) 0 + #define HAS_HOMING_CURRENT 1 +#endif +#undef _OR_HAS_CURR_HOME diff --git a/Marlin/src/inc/SanityCheck.h b/Marlin/src/inc/SanityCheck.h index 59317002b0..376795a4ce 100644 --- a/Marlin/src/inc/SanityCheck.h +++ b/Marlin/src/inc/SanityCheck.h @@ -237,9 +237,9 @@ static_assert(COUNT(arm) == LOGICAL_AXES, "AXIS_RELATIVE_MODES must contain " _L // Serial DMA is only available for some STM32 MCUs and HC32 #if ENABLED(SERIAL_DMA) - #if defined(ARDUINO_ARCH_HC32) + #ifdef ARDUINO_ARCH_HC32 // checks for HC32 are located in HAL/HC32/inc/SanityCheck.h - #elif !HAL_STM32 || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx) + #elif DISABLED(HAL_STM32) || NONE(STM32F0xx, STM32F1xx, STM32F2xx, STM32F4xx, STM32F7xx) #error "SERIAL_DMA is only available for some STM32 MCUs and requires HAL/STM32." #elif !defined(HAL_UART_MODULE_ENABLED) || defined(HAL_UART_MODULE_ONLY) #error "SERIAL_DMA requires STM32 platform HAL UART (without HAL_UART_MODULE_ONLY)." @@ -1726,6 +1726,28 @@ static_assert(NUM_SERVOS <= NUM_SERVO_PLUGS, "NUM_SERVOS (or some servo index) i #endif #endif +/** + * Assert that the homing current must not be greater than the base current. + * Current may be reduced "to prevent damage" but in fact it's typically reduced to prevent spurious + * DIAG triggering from fast high torque moves with large jerk values which are more prone to cause binding. + */ +#define _BAD_HOME_CURRENT(N) (N##_CURRENT_HOME > N##_CURRENT) || +#if MAIN_AXIS_MAP(_BAD_HOME_CURRENT) MAP(_BAD_HOME_CURRENT, X2, Y2, Z2, Z3, Z4) 0 + #ifndef ALLOW_HIGHER_CURRENT_HOME + #error "*_CURRENT_HOME should be <= *_CURRENT. Define ALLOW_HIGHER_CURRENT_HOME in your configuration to continue anyway." + #else + #define HIGHER_CURRENT_HOME_WARNING 1 + #endif +#endif +#undef _BAD_HOME_CURRENT + +#if ENABLED(PROBING_USE_CURRENT_HOME) + #if (defined(Z_CURRENT_HOME) && !HAS_CURRENT_HOME(Z)) || (defined(Z2_CURRENT_HOME) && !HAS_CURRENT_HOME(Z2)) \ + || (defined(Z3_CURRENT_HOME) && !HAS_CURRENT_HOME(Z3)) || (defined(Z4_CURRENT_HOME) && !HAS_CURRENT_HOME(Z4)) + #error "PROBING_USE_CURRENT_HOME requires a Z_CURRENT_HOME value that differs from Z_CURRENT." + #endif +#endif + /** * Make sure Z_SAFE_HOMING point is reachable */ diff --git a/Marlin/src/inc/Warnings.cpp b/Marlin/src/inc/Warnings.cpp index b808909fd7..520b5704ab 100644 --- a/Marlin/src/inc/Warnings.cpp +++ b/Marlin/src/inc/Warnings.cpp @@ -715,7 +715,33 @@ #endif #if ENABLED(QUICK_HOME) && (X_SPI_SENSORLESS || Y_SPI_SENSORLESS) - #warning "SPI_ENDSTOPS may be unreliable with QUICK_HOME. Adjust back-offs for better results." + #warning "SPI_ENDSTOPS may be unreliable with QUICK_HOME. Adjust SENSORLESS_BACKOFF_MM for better results." +#endif + +#if HIGHER_CURRENT_HOME_WARNING + #warning "High homing currents can lead to damage if a sensor fails or is set up incorrectly." +#endif + +#if USE_SENSORLESS + #if defined(X_CURRENT_HOME) && !HAS_CURRENT_HOME(X) + #warning "It's recommended to set X_CURRENT_HOME lower than X_CURRENT with SENSORLESS_HOMING." + #elif defined(X2_CURRENT_HOME) && !HAS_CURRENT_HOME(X2) + #warning "It's recommended to set X2_CURRENT_HOME lower than X2_CURRENT with SENSORLESS_HOMING." + #endif + #if defined(Y_CURRENT_HOME) && !HAS_CURRENT_HOME(Y) + #warning "It's recommended to set Y_CURRENT_HOME lower than Y_CURRENT with SENSORLESS_HOMING." + #elif defined(Y2_CURRENT_HOME) && !HAS_CURRENT_HOME(Y2) + #warning "It's recommended to set Y2_CURRENT_HOME lower than Y2_CURRENT with SENSORLESS_HOMING." + #endif + #if defined(Z_CURRENT_HOME) && !HAS_CURRENT_HOME(Z) + #warning "It's recommended to set Z_CURRENT_HOME lower than Z_CURRENT with SENSORLESS_HOMING." + #elif defined(Z2_CURRENT_HOME) && !HAS_CURRENT_HOME(Z2) + #warning "It's recommended to set Z2_CURRENT_HOME lower than Z2_CURRENT with SENSORLESS_HOMING." + #elif defined(Z3_CURRENT_HOME) && !HAS_CURRENT_HOME(Z3) + #warning "It's recommended to set Z3_CURRENT_HOME lower than Z3_CURRENT with SENSORLESS_HOMING." + #elif defined(Z4_CURRENT_HOME) && !HAS_CURRENT_HOME(Z4) + #warning "It's recommended to set Z4_CURRENT_HOME lower than Z4_CURRENT with SENSORLESS_HOMING." + #endif #endif #if CANNOT_EMBED_CONFIGURATION diff --git a/Marlin/src/module/delta.cpp b/Marlin/src/module/delta.cpp index cfa134860b..379ef985ab 100644 --- a/Marlin/src/module/delta.cpp +++ b/Marlin/src/module/delta.cpp @@ -241,12 +241,18 @@ void home_delta() { #endif #endif + // Set homing current for all motors + TERN_(HAS_HOMING_CURRENT, set_homing_current(Z_AXIS)); + // Move all carriages together linearly until an endstop is hit. current_position.z = DIFF_TERN(HAS_BED_PROBE, delta_height + 10, probe.offset.z); line_to_current_position(homing_feedrate(Z_AXIS)); planner.synchronize(); TERN_(HAS_DELTA_SENSORLESS_PROBING, endstops.report_states()); + // Restore the homing current for all motors + TERN_(HAS_HOMING_CURRENT, restore_homing_current(Z_AXIS)); + // Re-enable stealthChop if used. Disable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) && DISABLED(ENDSTOPS_ALWAYS_ON_DEFAULT) TERN_(X_SENSORLESS, end_sensorless_homing_per_axis(X_AXIS, stealth_states_x)); diff --git a/Marlin/src/module/endstops.cpp b/Marlin/src/module/endstops.cpp index 03f5ab6d8e..5cee425bef 100644 --- a/Marlin/src/module/endstops.cpp +++ b/Marlin/src/module/endstops.cpp @@ -1370,94 +1370,3 @@ void Endstops::update() { } #endif // PINS_DEBUGGING - -#if USE_SENSORLESS - /** - * Change TMC driver currents to N##_CURRENT_HOME, saving the current configuration of each. - */ - void Endstops::set_z_sensorless_current(const bool onoff) { - #if ENABLED(DELTA) && HAS_CURRENT_HOME(X) - #define HAS_DELTA_X_CURRENT 1 - #endif - #if ENABLED(DELTA) && HAS_CURRENT_HOME(Y) - #define HAS_DELTA_Y_CURRENT 1 - #endif - #if HAS_DELTA_X_CURRENT || HAS_DELTA_Y_CURRENT || HAS_CURRENT_HOME(Z) || HAS_CURRENT_HOME(Z2) || HAS_CURRENT_HOME(Z3) || HAS_CURRENT_HOME(Z4) - #if HAS_DELTA_X_CURRENT - static int16_t saved_current_X; - #endif - #if HAS_DELTA_Y_CURRENT - static int16_t saved_current_Y; - #endif - #if HAS_CURRENT_HOME(Z) - static int16_t saved_current_Z; - #endif - #if HAS_CURRENT_HOME(Z2) - static int16_t saved_current_Z2; - #endif - #if HAS_CURRENT_HOME(Z3) - static int16_t saved_current_Z3; - #endif - #if HAS_CURRENT_HOME(Z4) - static int16_t saved_current_Z4; - #endif - - #if ENABLED(DEBUG_LEVELING_FEATURE) - auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) { - if (DEBUGGING(LEVELING)) { DEBUG_ECHOLN(s, F(" current: "), a, F(" -> "), b); } - }; - #else - #define debug_current(...) - #endif - - #define _SAVE_SET_CURRENT(A) \ - saved_current_##A = stepper##A.getMilliamps(); \ - stepper##A.rms_current(A##_CURRENT_HOME); \ - debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) - - #define _RESTORE_CURRENT(A) \ - stepper##A.rms_current(saved_current_##A); \ - debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) - - if (onoff) { - TERN_(HAS_DELTA_X_CURRENT, _SAVE_SET_CURRENT(X)); - TERN_(HAS_DELTA_Y_CURRENT, _SAVE_SET_CURRENT(Y)); - #if HAS_CURRENT_HOME(Z) - _SAVE_SET_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _SAVE_SET_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _SAVE_SET_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _SAVE_SET_CURRENT(Z4); - #endif - } - else { - TERN_(HAS_DELTA_X_CURRENT, _RESTORE_CURRENT(X)); - TERN_(HAS_DELTA_Y_CURRENT, _RESTORE_CURRENT(Y)); - #if HAS_CURRENT_HOME(Z) - _RESTORE_CURRENT(Z); - #endif - #if HAS_CURRENT_HOME(Z2) - _RESTORE_CURRENT(Z2); - #endif - #if HAS_CURRENT_HOME(Z3) - _RESTORE_CURRENT(Z3); - #endif - #if HAS_CURRENT_HOME(Z4) - _RESTORE_CURRENT(Z4); - #endif - } - - TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(onoff)); - - #if SENSORLESS_STALLGUARD_DELAY - safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle - #endif - - #endif - } -#endif // USE_SENSORLESS diff --git a/Marlin/src/module/endstops.h b/Marlin/src/module/endstops.h index 1a76a26a3f..10ae915beb 100644 --- a/Marlin/src/module/endstops.h +++ b/Marlin/src/module/endstops.h @@ -37,8 +37,6 @@ #define _ESN_ITEM(K,A,M) ES_ITEM(K,ES_ENUM(A,M)) #define ES_MINMAX(A) ES_ITEM(HAS_##A##_MIN_STATE, ES_ENUM(A,MIN)) ES_ITEM(HAS_##A##_MAX_STATE, ES_ENUM(A,MAX)) -#define HAS_CURRENT_HOME(N) ((N##_CURRENT_HOME > 0) && (N##_CURRENT_HOME != N##_CURRENT)) - /** * Basic Endstop Flag Bits: * - Each axis with an endstop gets a flag for its homing direction. @@ -288,11 +286,6 @@ class Endstops { static void clear_endstop_state(); static bool tmc_spi_homing_check(); #endif - public: - // Basic functions for Sensorless Homing - #if USE_SENSORLESS - static void set_z_sensorless_current(const bool onoff); - #endif }; extern Endstops endstops; diff --git a/Marlin/src/module/motion.cpp b/Marlin/src/module/motion.cpp index 7016544c20..0360913cec 100644 --- a/Marlin/src/module/motion.cpp +++ b/Marlin/src/module/motion.cpp @@ -253,6 +253,560 @@ void report_current_position_projected() { stepper.report_a_position(planner.position); } +#if HAS_HOMING_CURRENT + + #if ENABLED(DEBUG_LEVELING_FEATURE) + auto debug_current = [](FSTR_P const s, const int16_t a, const int16_t b) { + if (DEBUGGING(LEVELING)) { DEBUG_ECHOLN(s, F(" current: "), a, F(" -> "), b); } + }; + #else + #define debug_current(...) + #endif + + #if HAS_CURRENT_HOME(X) + int16_t saved_current_X; + #endif + #if HAS_CURRENT_HOME(Y) + int16_t saved_current_Y; + #endif + #if HAS_CURRENT_HOME(Z) + int16_t saved_current_Z; + #endif + #if HAS_CURRENT_HOME(X2) + int16_t saved_current_X2; + #endif + #if HAS_CURRENT_HOME(Y2) + int16_t saved_current_Y2; + #endif + #if HAS_CURRENT_HOME(Z2) + int16_t saved_current_Z2; + #endif + #if HAS_CURRENT_HOME(Z3) + int16_t saved_current_Z3; + #endif + #if HAS_CURRENT_HOME(Z4) + int16_t saved_current_Z4; + #endif + #if HAS_CURRENT_HOME(I) + int16_t saved_current_I; + #endif + #if HAS_CURRENT_HOME(J) + int16_t saved_current_J; + #endif + #if HAS_CURRENT_HOME(K) + int16_t saved_current_K; + #endif + #if HAS_CURRENT_HOME(U) + int16_t saved_current_U; + #endif + #if HAS_CURRENT_HOME(V) + int16_t saved_current_V; + #endif + #if HAS_CURRENT_HOME(W) + int16_t saved_current_W; + #endif + + /** + * Set motors to their homing / probing currents. + * Currents are saved first so they can be restored afterward. + */ + void set_homing_current(const AxisEnum axis) { + + // Saves the running current of the motor at the moment the function is called and sets current to CURRENT_HOME + #define _SAVE_SET_CURRENT(A) \ + saved_current_##A = stepper##A.getMilliamps(); \ + stepper##A.rms_current(A##_CURRENT_HOME); \ + debug_current(F(STR_##A), saved_current_##A, A##_CURRENT_HOME) + + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Setting homing driver current"); + + #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + + // CORE and Markforged kinematics + switch (axis) { + default: break; + case X_AXIS: case Y_AXIS: + #if HAS_CURRENT_HOME(X) + _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(X2) + _SAVE_SET_CURRENT(X2); + #endif + #if HAS_CURRENT_HOME(Y) + _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Y2) + _SAVE_SET_CURRENT(Y2); + #endif + break; + case Z_AXIS: + #if HAS_CURRENT_HOME(Z) + _SAVE_SET_CURRENT(Z); + #endif + #if HAS_CURRENT_HOME(Z2) + _SAVE_SET_CURRENT(Z2); + #endif + #if HAS_CURRENT_HOME(Z3) + _SAVE_SET_CURRENT(Z3); + #endif + #if HAS_CURRENT_HOME(Z4) + _SAVE_SET_CURRENT(Z4); + #endif + break; + } + + #elif CORE_IS_XZ + + // CORE XZ / ZX + switch (axis) { + default: break; + case X_AXIS: case Z_AXIS: + #if HAS_CURRENT_HOME(X) + _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(Z) + _SAVE_SET_CURRENT(Z); + #endif + break; + case Y_AXIS: + #if HAS_CURRENT_HOME(Y) + _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Y2) + _SAVE_SET_CURRENT(Y2); + #endif + break; + } + + #elif CORE_IS_YZ + + // CORE YZ / ZY + switch (axis) { + default: break; + case X_AXIS: + #if HAS_CURRENT_HOME(X) + _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(X2) + _SAVE_SET_CURRENT(X2); + #endif + break; + case Y_AXIS: case Z_AXIS: + #if HAS_CURRENT_HOME(Y) + _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Z) + _SAVE_SET_CURRENT(Z); + #endif + break; + } + + #elif IS_SCARA + + // SCARA kinematics + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(X) + case A_AXIS: _SAVE_SET_CURRENT(X); break; + #endif + #if HAS_CURRENT_HOME(Y) + case B_AXIS: _SAVE_SET_CURRENT(Y); break; + #endif + #if HAS_CURRENT_HOME(Z) + case C_AXIS: _SAVE_SET_CURRENT(Z); break; + #endif + } + + #elif ANY(AXEL_TPARA, DELTA) + + // TPARA or DELTA kinematics. + // Z_AXIS is a special mode to apply homing current to all axes. + #if HAS_CURRENT_HOME(X) + if (axis == A_AXIS || axis == Z_AXIS) _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(Y) + if (axis == B_AXIS || axis == Z_AXIS) _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Z) + if (axis == C_AXIS) _SAVE_SET_CURRENT(Z); + #endif + + #elif ANY(POLARGRAPH, POLAR) + + // POLAR kinematics + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(X) + case A_AXIS: _SAVE_SET_CURRENT(X); break; + #endif + #if HAS_CURRENT_HOME(Y) + case B_AXIS: _SAVE_SET_CURRENT(Y); break; + #endif + #if HAS_CURRENT_HOME(Z) + case C_AXIS: _SAVE_SET_CURRENT(Z); break; + #endif + } + + #elif defined(ARTICULATED_ROBOT_ARM) + + // Articulated Robot Arm + // Useful? + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(X) + case A_AXIS: _SAVE_SET_CURRENT(X); break; + #endif + #if HAS_CURRENT_HOME(Y) + case B_AXIS: _SAVE_SET_CURRENT(Y); break; + #endif + #if HAS_CURRENT_HOME(Z) + case C_AXIS: _SAVE_SET_CURRENT(Z); break; + #endif + } + + #elif defined(FOAMCUTTER_XYUV) + + // Foam cutter + switch (axis) { + default: break; + case X_AXIS: case I_AXIS: + #if HAS_CURRENT_HOME(X) + _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(I) + _SAVE_SET_CURRENT(I); + #endif + break; + case Y_AXIS: case J_AXIS: + #if HAS_CURRENT_HOME(Y) + _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(J) + _SAVE_SET_CURRENT(J); + #endif + break; + case Z_AXIS: + #if HAS_CURRENT_HOME(Z) + _SAVE_SET_CURRENT(Z); + #endif + break; + } + + #else + + // Cartesian kinematics + switch (axis) { + default: break; + case X_AXIS: + #if HAS_CURRENT_HOME(X) + _SAVE_SET_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(X2) + _SAVE_SET_CURRENT(X2); + #endif + break; + case Y_AXIS: + #if HAS_CURRENT_HOME(Y) + _SAVE_SET_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Y2) + _SAVE_SET_CURRENT(Y2); + #endif + break; + case Z_AXIS: + #if HAS_CURRENT_HOME(Z) + _SAVE_SET_CURRENT(Z); + #endif + #if HAS_CURRENT_HOME(Z2) + _SAVE_SET_CURRENT(Z2); + #endif + #if HAS_CURRENT_HOME(Z3) + _SAVE_SET_CURRENT(Z3); + #endif + #if HAS_CURRENT_HOME(Z4) + _SAVE_SET_CURRENT(Z4); + #endif + break; + } + + #endif // kinematics + + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(I) && DISABLED(FOAMCUTTER_XYUV) + case I_AXIS: _SAVE_SET_CURRENT(I); break; + #endif + #if HAS_CURRENT_HOME(J) && DISABLED(FOAMCUTTER_XYUV) + case J_AXIS: _SAVE_SET_CURRENT(J); break; + #endif + #if HAS_CURRENT_HOME(K) + case K_AXIS: _SAVE_SET_CURRENT(K); break; + #endif + #if HAS_CURRENT_HOME(U) + case U_AXIS: _SAVE_SET_CURRENT(U); break; + #endif + #if HAS_CURRENT_HOME(V) + case V_AXIS: _SAVE_SET_CURRENT(V); break; + #endif + #if HAS_CURRENT_HOME(W) + case W_AXIS: _SAVE_SET_CURRENT(W); break; + #endif + } + + #if SENSORLESS_STALLGUARD_DELAY + safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle + #endif + + } // set_homing_current() + + /** + * Restore motors to their previously-stored currents. + * Always call set_homing_current() first! + */ + void restore_homing_current(const AxisEnum axis) { + + // Restore the saved current + #define _RESTORE_CURRENT(A) \ + stepper##A.rms_current(saved_current_##A); \ + debug_current(F(STR_##A), A##_CURRENT_HOME, saved_current_##A) + + if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("Restore driver current"); + + #if ANY(CORE_IS_XY, MARKFORGED_XY, MARKFORGED_YX) + + // CORE and Markforged kinematics + switch (axis) { + default: break; + case X_AXIS: case Y_AXIS: + #if HAS_CURRENT_HOME(X) + _RESTORE_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(Y) + _RESTORE_CURRENT(Y); + #endif + break; + case Z_AXIS: + #if HAS_CURRENT_HOME(Z) + _RESTORE_CURRENT(Z); + #endif + #if HAS_CURRENT_HOME(Z2) + _RESTORE_CURRENT(Z2); + #endif + #if HAS_CURRENT_HOME(Z3) + _RESTORE_CURRENT(Z3); + #endif + #if HAS_CURRENT_HOME(Z4) + _RESTORE_CURRENT(Z4); + #endif + break; + } + + #elif CORE_IS_XZ + + // CORE XZ / ZX + switch (axis) { + default: break; + case X_AXIS: case Z_AXIS: + #if HAS_CURRENT_HOME(X) + _RESTORE_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(Z) + _RESTORE_CURRENT(Z); + #endif + break; + case Y_AXIS: + #if HAS_CURRENT_HOME(Y) + _RESTORE_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Y2) + _RESTORE_CURRENT(Y2); + #endif + break; + } + + #elif CORE_IS_YZ + + // CORE YZ / ZY + switch (axis) { + default: break; + case X_AXIS: + #if HAS_CURRENT_HOME(X) + _RESTORE_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(X2) + _RESTORE_CURRENT(X2); + #endif + break; + case Y_AXIS: case Z_AXIS: + #if HAS_CURRENT_HOME(Y) + _RESTORE_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Z) + _RESTORE_CURRENT(Z); + #endif + break; + } + + #elif IS_SCARA // Unsupported for now? + + // SCARA kinematics + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(X) + case A_AXIS: _RESTORE_CURRENT(X); break; + #endif + #if HAS_CURRENT_HOME(Y) + case B_AXIS: _RESTORE_CURRENT(Y); break; + #endif + #if HAS_CURRENT_HOME(Z) + case C_AXIS: _RESTORE_CURRENT(Z); break; + #endif + } + + #elif ANY(AXEL_TPARA, DELTA) + + // TPARA or DELTA kinematics + // Z_AXIS is a special mode to set homing current to all axes + #if HAS_CURRENT_HOME(X) + if (axis == A_AXIS || axis == Z_AXIS) _RESTORE_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(Y) + if (axis == B_AXIS || axis == Z_AXIS) _RESTORE_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Z) + if (axis == C_AXIS) _RESTORE_CURRENT(Z); + #endif + + #elif ANY(POLARGRAPH, POLAR) + + // POLAR kinematics + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(X) + case A_AXIS: _RESTORE_CURRENT(X); break; + #endif + #if HAS_CURRENT_HOME(Y) + case B_AXIS: _RESTORE_CURRENT(Y); break; + #endif + #if HAS_CURRENT_HOME(Z) + case C_AXIS: _RESTORE_CURRENT(Z); break; + #endif + } + + #elif ENABLED(ARTICULATED_ROBOT_ARM) + + // Articulated Robot Arm + // Useful? + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(X) + case A_AXIS: _RESTORE_CURRENT(X); break; + #endif + #if HAS_CURRENT_HOME(Y) + case B_AXIS: _RESTORE_CURRENT(Y); break; + #endif + #if HAS_CURRENT_HOME(Z) + case C_AXIS: _RESTORE_CURRENT(Z); break; + #endif + } + + #elif ENABLED(FOAMCUTTER_XYUV) + + // Foam cutter + switch (axis) { + default: break; + case X_AXIS: case I_AXIS: + #if HAS_CURRENT_HOME(X) + _RESTORE_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(I) + _RESTORE_CURRENT(I); + #endif + break; + case Y_AXIS: case J_AXIS: + #if HAS_CURRENT_HOME(Y) + _RESTORE_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(J) + _RESTORE_CURRENT(J); + #endif + break; + case Z_AXIS: + #if HAS_CURRENT_HOME(Z) + _RESTORE_CURRENT(Z); + #endif + break; + } + + #else + + // Cartesian kinematics + switch (axis) { + default: break; + case X_AXIS: + #if HAS_CURRENT_HOME(X) + _RESTORE_CURRENT(X); + #endif + #if HAS_CURRENT_HOME(X2) + _RESTORE_CURRENT(X2); + #endif + break; + case Y_AXIS: + #if HAS_CURRENT_HOME(Y) + _RESTORE_CURRENT(Y); + #endif + #if HAS_CURRENT_HOME(Y2) + _RESTORE_CURRENT(Y2); + #endif + break; + case Z_AXIS: + #if HAS_CURRENT_HOME(Z) + _RESTORE_CURRENT(Z); + #endif + #if HAS_CURRENT_HOME(Z2) + _RESTORE_CURRENT(Z2); + #endif + #if HAS_CURRENT_HOME(Z3) + _RESTORE_CURRENT(Z3); + #endif + #if HAS_CURRENT_HOME(Z4) + _RESTORE_CURRENT(Z4); + #endif + break; + } + + #endif // kinematics + + switch (axis) { + default: break; + #if HAS_CURRENT_HOME(I) && DISABLED(FOAMCUTTER_XYUV) + case I_AXIS: _RESTORE_CURRENT(I); break; + #endif + #if HAS_CURRENT_HOME(J) && DISABLED(FOAMCUTTER_XYUV) + case J_AXIS: _RESTORE_CURRENT(J); break; + #endif + #if HAS_CURRENT_HOME(K) + case K_AXIS: _RESTORE_CURRENT(K); break; + #endif + #if HAS_CURRENT_HOME(U) + case U_AXIS: _RESTORE_CURRENT(U); break; + #endif + #if HAS_CURRENT_HOME(V) + case V_AXIS: _RESTORE_CURRENT(V); break; + #endif + #if HAS_CURRENT_HOME(W) + case W_AXIS: _RESTORE_CURRENT(W); break; + #endif + } + + #if SENSORLESS_STALLGUARD_DELAY + safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle + #endif + + } // restore_homing_current() + +#endif // HAS_HOMING_CURRENT + #if ENABLED(AUTO_REPORT_POSITION) AutoReporter position_auto_reporter; #endif @@ -2140,6 +2694,11 @@ void prepare_line_to_destination() { } #endif + // + // Set a new current for the homed axis motor(s) + // + TERN_(HAS_HOMING_CURRENT, set_homing_current(axis)); + // // Back away to prevent an early sensorless trigger // @@ -2428,6 +2987,11 @@ void prepare_line_to_destination() { if (DEBUGGING(LEVELING)) DEBUG_ECHOLNPGM("<<< homeaxis(", C(AXIS_CHAR(axis)), ")"); + // + // Restore axis motor(s) current after homing + // + TERN_(HAS_HOMING_CURRENT, restore_homing_current(axis)); + } // homeaxis() #endif // HAS_ENDSTOPS diff --git a/Marlin/src/module/motion.h b/Marlin/src/module/motion.h index 8aa66354ac..2dcc8202e8 100644 --- a/Marlin/src/module/motion.h +++ b/Marlin/src/module/motion.h @@ -632,3 +632,8 @@ void home_if_needed(const bool keeplev=false); sensorless_t start_sensorless_homing_per_axis(const AxisEnum axis); void end_sensorless_homing_per_axis(const AxisEnum axis, sensorless_t enable_stealth); #endif + +#if HAS_HOMING_CURRENT + void set_homing_current(const AxisEnum axis); + void restore_homing_current(const AxisEnum axis); +#endif diff --git a/Marlin/src/module/probe.cpp b/Marlin/src/module/probe.cpp index 616414a027..3df24ce313 100644 --- a/Marlin/src/module/probe.cpp +++ b/Marlin/src/module/probe.cpp @@ -627,7 +627,8 @@ bool Probe::probe_down_to_z(const_float_t z, const_feedRate_t fr_mm_s) { #endif #endif } - endstops.set_z_sensorless_current(true); // The "homing" current also applies to probing + TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(true)); + endstops.enable(true); #endif // SENSORLESS_PROBING @@ -671,7 +672,7 @@ bool Probe::probe_down_to_z(const_float_t z, const_feedRate_t fr_mm_s) { #endif #endif } - endstops.set_z_sensorless_current(false); + TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(false)); #endif // SENSORLESS_PROBING #if ENABLED(BLTOUCH) @@ -983,14 +984,20 @@ float Probe::probe_at_point(const_float_t rx, const_float_t ry, const ProbePtRai // Move the probe to the starting XYZ do_blocking_move_to(npos, feedRate_t(XY_PROBE_FEEDRATE_MM_S)); + // Change Z motor current to homing current + TERN_(PROBING_USE_CURRENT_HOME, set_homing_current(Z_AXIS)); + + float measured_z; + #if ENABLED(BD_SENSOR) safe_delay(4); - return current_position.z - bdl.read(); // Difference between Z-home-relative Z and sensor reading + + measured_z = current_position.z - bdl.read(); // Difference between Z-home-relative Z and sensor reading #else // !BD_SENSOR - float measured_z = deploy() ? NAN : run_z_probe(sanity_check, z_min_point, z_clearance) + offset.z; + measured_z = deploy() ? NAN : run_z_probe(sanity_check, z_min_point, z_clearance) + offset.z; // Deploy succeeded and a successful measurement was done. // Raise and/or stow the probe depending on 'raise_after' and settings. @@ -1028,9 +1035,12 @@ float Probe::probe_at_point(const_float_t rx, const_float_t ry, const ProbePtRai SERIAL_ECHOLNPGM("Bed X: ", LOGICAL_X_POSITION(rx), " Y: ", LOGICAL_Y_POSITION(ry), " Z: ", measured_z); } - return measured_z; - #endif // !BD_SENSOR + + // Restore the Z homing current + TERN_(PROBING_USE_CURRENT_HOME, restore_homing_current(Z_AXIS)); + + return measured_z; } #if HAS_Z_SERVO_PROBE diff --git a/Marlin/src/module/scara.cpp b/Marlin/src/module/scara.cpp index 0f00ab5643..d6656d36d8 100644 --- a/Marlin/src/module/scara.cpp +++ b/Marlin/src/module/scara.cpp @@ -229,10 +229,16 @@ float segments_per_second = DEFAULT_SEGMENTS_PER_SECOND; // Move all carriages together linearly until an endstop is hit. //do_blocking_move_to_xy_z(pos, mlz, homing_feedrate(Z_AXIS)); + // Set the homing current for all motors + TERN_(HAS_HOMING_CURRENT, set_homing_current(Z_AXIS)); + current_position.set(0, 0, max_length(Z_AXIS)); line_to_current_position(homing_feedrate(Z_AXIS)); planner.synchronize(); + // Restore the homing current for all motors + TERN_(HAS_HOMING_CURRENT, restore_homing_current(Z_AXIS)); + // Re-enable stealthChop if used. Disable diag1 pin on driver. #if ENABLED(SENSORLESS_HOMING) TERN_(X_SENSORLESS, end_sensorless_homing_per_axis(X_AXIS, stealth_states_x)); diff --git a/buildroot/tests/LPC1769 b/buildroot/tests/LPC1769 index dd4f5f28ea..54a023a46c 100755 --- a/buildroot/tests/LPC1769 +++ b/buildroot/tests/LPC1769 @@ -55,9 +55,10 @@ opt_set MOTHERBOARD BOARD_COHESION3D_REMIX \ NOZZLE_TO_PROBE_OFFSET '{ 0, 0, 0, 0 }' \ I_MIN_PIN P1_25 \ X_CURRENT_HOME 750 Y_CURRENT_HOME 750 Z_CURRENT_HOME 750 -opt_enable AUTO_BED_LEVELING_BILINEAR EEPROM_SETTINGS EEPROM_CHITCHAT MECHANICAL_GANTRY_CALIBRATION \ +opt_enable EEPROM_SETTINGS EEPROM_CHITCHAT MECHANICAL_GANTRY_CALIBRATION \ TMC_USE_SW_SPI MONITOR_DRIVER_STATUS STEALTHCHOP_XY STEALTHCHOP_Z HYBRID_THRESHOLD \ - SENSORLESS_PROBING SENSORLESS_HOMING Z_SAFE_HOMING X_STALL_SENSITIVITY Y_STALL_SENSITIVITY Z_STALL_SENSITIVITY TMC_DEBUG \ + SENSORLESS_HOMING Z_SAFE_HOMING X_STALL_SENSITIVITY Y_STALL_SENSITIVITY Z_STALL_SENSITIVITY TMC_DEBUG \ + AUTO_BED_LEVELING_BILINEAR SENSORLESS_PROBING PROBING_USE_CURRENT_HOME \ AXIS4_ROTATES I_MIN_POS I_MAX_POS I_HOME_DIR I_ENABLE_ON INVERT_I_DIR \ EXPERIMENTAL_I2CBUS opt_disable PSU_CONTROL Z_MIN_PROBE_USES_Z_MIN_ENDSTOP_PIN