Skip to content

Commit a06a0b2

Browse files
lujiosrobbycandraellensp
authored andcommitted
⚡️ Improve Sensorless homing/probing accuracy for G28, G33, M48 (MarlinFirmware#24220)
Co-authored-by: Robby Candra <robbycandra.mail@gmail.com> Co-authored-by: ellensp <530024+ellensp@users.noreply.github.com>
1 parent 78d64ff commit a06a0b2

13 files changed

+202
-79
lines changed

Marlin/src/gcode/calibrate/G28.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ void GcodeSuite::G28() {
321321
stepperW.rms_current(W_CURRENT_HOME);
322322
if (DEBUGGING(LEVELING)) debug_current(F(STR_W), tmc_save_current_W, W_CURRENT_HOME);
323323
#endif
324+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
324325
#endif
325326

326327
#if ENABLED(IMPROVE_HOMING_RELIABILITY)
@@ -576,6 +577,7 @@ void GcodeSuite::G28() {
576577
#if HAS_CURRENT_HOME(W)
577578
stepperW.rms_current(tmc_save_current_W);
578579
#endif
580+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
579581
#endif // HAS_HOMING_CURRENT
580582

581583
ui.refresh();

Marlin/src/gcode/calibrate/G33.cpp

+40-7
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ float lcd_probe_pt(const xy_pos_t &xy);
7171

7272
void ac_home() {
7373
endstops.enable(true);
74-
TERN_(HAS_DELTA_SENSORLESS_PROBING, probe.set_homing_current(true));
74+
TERN_(SENSORLESS_HOMING, endstops.set_homing_current(true));
7575
home_delta();
76-
TERN_(HAS_DELTA_SENSORLESS_PROBING, probe.set_homing_current(false));
76+
TERN_(SENSORLESS_HOMING, endstops.set_homing_current(false));
7777
endstops.not_homing();
7878
}
7979

@@ -390,6 +390,8 @@ static float auto_tune_a(const float dcr) {
390390
* X Don't activate stallguard on X.
391391
* Y Don't activate stallguard on Y.
392392
* Z Don't activate stallguard on Z.
393+
*
394+
* S Save offset_sensorless_adj
393395
*/
394396
void GcodeSuite::G33() {
395397

@@ -411,7 +413,8 @@ void GcodeSuite::G33() {
411413
dcr -= probe_at_offset ? _MAX(total_offset, PROBING_MARGIN) : total_offset;
412414
#endif
413415
NOMORE(dcr, DELTA_PRINTABLE_RADIUS);
414-
if (parser.seenval('R')) dcr -= _MAX(parser.value_float(),0);
416+
if (parser.seenval('R')) dcr -= _MAX(parser.value_float(), 0.0f);
417+
TERN_(HAS_DELTA_SENSORLESS_PROBING, dcr *= sensorless_radius_factor);
415418

416419
const float calibration_precision = parser.floatval('C', 0.0f);
417420
if (calibration_precision < 0) {
@@ -434,9 +437,8 @@ void GcodeSuite::G33() {
434437
const bool stow_after_each = parser.seen_test('E');
435438

436439
#if HAS_DELTA_SENSORLESS_PROBING
437-
probe.test_sensitivity.x = !parser.seen_test('X');
438-
TERN_(HAS_Y_AXIS, probe.test_sensitivity.y = !parser.seen_test('Y'));
439-
TERN_(HAS_Z_AXIS, probe.test_sensitivity.z = !parser.seen_test('Z'));
440+
probe.test_sensitivity.set(!parser.seen_test('X'), !parser.seen_test('Y'), !parser.seen_test('Z'));
441+
const bool do_save_offset_adj = parser.seen_test('S');
440442
#endif
441443

442444
const bool _0p_calibration = probe_points == 0,
@@ -475,6 +477,25 @@ void GcodeSuite::G33() {
475477

476478
if (!_0p_calibration) ac_home();
477479

480+
#if HAS_DELTA_SENSORLESS_PROBING
481+
if (verbose_level > 0 && do_save_offset_adj) {
482+
offset_sensorless_adj.reset();
483+
484+
auto caltower = [&](Probe::sense_bool_t s){
485+
float z_at_pt[NPP + 1];
486+
LOOP_CAL_ALL(rad) z_at_pt[rad] = 0.0f;
487+
probe.test_sensitivity = s;
488+
if (probe_calibration_points(z_at_pt, 1, dcr, false, false, probe_at_offset))
489+
probe.set_offset_sensorless_adj(z_at_pt[CEN]);
490+
};
491+
caltower({ true, false, false }); // A
492+
caltower({ false, true, false }); // B
493+
caltower({ false, false, true }); // C
494+
495+
probe.test_sensitivity = { true, true, true }; // reset to all
496+
}
497+
#endif
498+
478499
do { // start iterations
479500

480501
float z_at_pt[NPP + 1] = { 0.0f };
@@ -598,8 +619,17 @@ void GcodeSuite::G33() {
598619

599620
// print report
600621

601-
if (verbose_level == 3 || verbose_level == 0)
622+
if (verbose_level == 3 || verbose_level == 0) {
602623
print_calibration_results(z_at_pt, _tower_results, _opposite_results);
624+
#if HAS_DELTA_SENSORLESS_PROBING
625+
if (verbose_level == 0 && probe_points == 1) {
626+
if (do_save_offset_adj)
627+
probe.set_offset_sensorless_adj(z_at_pt[CEN]);
628+
else
629+
probe.refresh_largest_sensorless_adj();
630+
}
631+
#endif
632+
}
603633

604634
if (verbose_level != 0) { // !dry run
605635
if ((zero_std_dev >= test_precision && iterations > force_iterations) || zero_std_dev <= calibration_precision) { // end iterations
@@ -660,6 +690,9 @@ void GcodeSuite::G33() {
660690
ac_cleanup(TERN_(HAS_MULTI_HOTEND, old_tool_index));
661691

662692
TERN_(FULL_REPORT_TO_HOST_FEATURE, set_and_report_grblstate(M_IDLE));
693+
#if HAS_DELTA_SENSORLESS_PROBING
694+
probe.test_sensitivity = { true, true, true };
695+
#endif
663696
}
664697

665698
#endif // DELTA_AUTO_CALIBRATION

Marlin/src/inc/Conditionals_adv.h

+5
Original file line numberDiff line numberDiff line change
@@ -1048,3 +1048,8 @@
10481048
#if ANY(DISABLE_INACTIVE_X, DISABLE_INACTIVE_Y, DISABLE_INACTIVE_Z, DISABLE_INACTIVE_I, DISABLE_INACTIVE_J, DISABLE_INACTIVE_K, DISABLE_INACTIVE_U, DISABLE_INACTIVE_V, DISABLE_INACTIVE_W, DISABLE_INACTIVE_E)
10491049
#define HAS_DISABLE_INACTIVE_AXIS 1
10501050
#endif
1051+
1052+
// Delay Sensorless Homing/Probing
1053+
#if EITHER(SENSORLESS_HOMING, SENSORLESS_PROBING) && !defined(SENSORLESS_STALLGUARD_DELAY)
1054+
#define SENSORLESS_STALLGUARD_DELAY 0
1055+
#endif

Marlin/src/lcd/extui/dgus/mks/DGUSScreenHandler.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ void DGUSScreenHandlerMKS::DGUSLCD_SendTMCStepValue(DGUS_VP_Variable &var) {
193193
if (!ExtUI::isPrintingFromMedia()) return; // avoid race condition when user stays in this menu and printer finishes.
194194
switch (swap16(*(uint16_t*)val_ptr)) {
195195
case 0: { // Resume
196-
197196
auto cs = getCurrentScreen();
198197
if (runout_mks.runout_status != RUNOUT_WAITING_STATUS && runout_mks.runout_status != UNRUNOUT_STATUS) {
199198
if (cs == MKSLCD_SCREEN_PRINT || cs == MKSLCD_SCREEN_PAUSE)
@@ -213,7 +212,6 @@ void DGUSScreenHandlerMKS::DGUSLCD_SendTMCStepValue(DGUS_VP_Variable &var) {
213212
} break;
214213

215214
case 1: // Pause
216-
217215
GotoScreen(MKSLCD_SCREEN_PAUSE);
218216
if (!ExtUI::isPrintingFromMediaPaused()) {
219217
nozzle_park_mks.print_pause_start_flag = 1;
@@ -222,6 +220,7 @@ void DGUSScreenHandlerMKS::DGUSLCD_SendTMCStepValue(DGUS_VP_Variable &var) {
222220
//ExtUI::mks_pausePrint();
223221
}
224222
break;
223+
225224
case 2: // Abort
226225
HandleUserConfirmationPopUp(VP_SD_AbortPrintConfirmed, nullptr, PSTR("Abort printing"), filelist.filename(), PSTR("?"), true, true, false, true);
227226
break;

Marlin/src/lcd/menu/menu_delta_calibrate.cpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
#include "../extui/ui_api.h"
4242
#endif
4343

44+
#if HAS_PROBE_XY_OFFSET
45+
#include "../../module/probe.h"
46+
#endif
47+
4448
void _man_probe_pt(const xy_pos_t &xy) {
4549
if (!ui.wait_for_move) {
4650
ui.wait_for_move = true;
@@ -88,7 +92,9 @@ void _man_probe_pt(const xy_pos_t &xy) {
8892
}
8993

9094
void _goto_tower_a(const_float_t a) {
91-
constexpr float dcr = DELTA_PRINTABLE_RADIUS;
95+
float dcr = DELTA_PRINTABLE_RADIUS - PROBING_MARGIN;
96+
TERN_(HAS_PROBE_XY_OFFSET, dcr -= HYPOT(probe.offset_xy.x, probe.offset_xy.y));
97+
TERN_(HAS_DELTA_SENSORLESS_PROBING, dcr *= sensorless_radius_factor);
9298
xy_pos_t tower_vec = { cos(RADIANS(a)), sin(RADIANS(a)) };
9399
_man_probe_pt(tower_vec * dcr);
94100
}

Marlin/src/module/delta.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ xy_float_t delta_tower[ABC];
6060
abc_float_t delta_diagonal_rod_2_tower;
6161
float delta_clip_start_height = Z_MAX_POS;
6262
abc_float_t delta_diagonal_rod_trim;
63+
#if HAS_DELTA_SENSORLESS_PROBING
64+
abc_float_t offset_sensorless_adj{0};
65+
float largest_sensorless_adj = 0;
66+
#endif
6367

6468
float delta_safe_distance_from_top();
6569

@@ -236,6 +240,7 @@ void home_delta() {
236240
TERN_(U_SENSORLESS, sensorless_t stealth_states_u = start_sensorless_homing_per_axis(U_AXIS));
237241
TERN_(V_SENSORLESS, sensorless_t stealth_states_v = start_sensorless_homing_per_axis(V_AXIS));
238242
TERN_(W_SENSORLESS, sensorless_t stealth_states_w = start_sensorless_homing_per_axis(W_AXIS));
243+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
239244
#endif
240245

241246
// Move all carriages together linearly until an endstop is hit.
@@ -255,6 +260,7 @@ void home_delta() {
255260
TERN_(U_SENSORLESS, end_sensorless_homing_per_axis(U_AXIS, stealth_states_u));
256261
TERN_(V_SENSORLESS, end_sensorless_homing_per_axis(V_AXIS, stealth_states_v));
257262
TERN_(W_SENSORLESS, end_sensorless_homing_per_axis(W_AXIS, stealth_states_w));
263+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
258264
#endif
259265

260266
endstops.validate_homing_move();

Marlin/src/module/delta.h

+11
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,24 @@ extern xy_float_t delta_tower[ABC];
3838
extern abc_float_t delta_diagonal_rod_2_tower;
3939
extern float delta_clip_start_height;
4040
extern abc_float_t delta_diagonal_rod_trim;
41+
#if HAS_DELTA_SENSORLESS_PROBING
42+
extern abc_float_t offset_sensorless_adj;
43+
extern float largest_sensorless_adj;
44+
#endif
4145

4246
/**
4347
* Recalculate factors used for delta kinematics whenever
4448
* settings have been changed (e.g., by M665).
4549
*/
4650
void recalc_delta_settings();
4751

52+
/**
53+
* Get a safe radius for calibration
54+
*/
55+
#if HAS_DELTA_SENSORLESS_PROBING
56+
static constexpr float sensorless_radius_factor = 0.7f;
57+
#endif
58+
4859
/**
4960
* Delta Inverse Kinematics
5061
*

Marlin/src/module/endstops.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
#include "temperature.h"
3232
#include "../lcd/marlinui.h"
3333

34+
#define DEBUG_OUT BOTH(USE_SENSORLESS, DEBUG_LEVELING_FEATURE)
35+
#include "../core/debug_out.h"
36+
3437
#if ENABLED(ENDSTOP_INTERRUPTS_FEATURE)
3538
#include HAL_PATH(../HAL, endstop_interrupts.h)
3639
#endif
@@ -1621,3 +1624,63 @@ void Endstops::update() {
16211624
}
16221625

16231626
#endif // PINS_DEBUGGING
1627+
1628+
#if USE_SENSORLESS
1629+
/**
1630+
* Change TMC driver currents to N##_CURRENT_HOME, saving the current configuration of each.
1631+
*/
1632+
void Endstops::set_homing_current(const bool onoff) {
1633+
#define HAS_CURRENT_HOME(N) (defined(N##_CURRENT_HOME) && N##_CURRENT_HOME != N##_CURRENT)
1634+
#define HAS_DELTA_X_CURRENT (ENABLED(DELTA) && HAS_CURRENT_HOME(X))
1635+
#define HAS_DELTA_Y_CURRENT (ENABLED(DELTA) && HAS_CURRENT_HOME(Y))
1636+
#if HAS_DELTA_X_CURRENT || HAS_DELTA_Y_CURRENT || HAS_CURRENT_HOME(Z)
1637+
#if HAS_DELTA_X_CURRENT
1638+
static int16_t saved_current_x;
1639+
#endif
1640+
#if HAS_DELTA_Y_CURRENT
1641+
static int16_t saved_current_y;
1642+
#endif
1643+
#if HAS_CURRENT_HOME(Z)
1644+
static int16_t saved_current_z;
1645+
#endif
1646+
auto debug_current_on = [](PGM_P const s, const int16_t a, const int16_t b) {
1647+
if (DEBUGGING(LEVELING)) { DEBUG_ECHOPGM_P(s); DEBUG_ECHOLNPGM(" current: ", a, " -> ", b); }
1648+
};
1649+
if (onoff) {
1650+
#if HAS_DELTA_X_CURRENT
1651+
saved_current_x = stepperX.getMilliamps();
1652+
stepperX.rms_current(X_CURRENT_HOME);
1653+
debug_current_on(PSTR("X"), saved_current_x, X_CURRENT_HOME);
1654+
#endif
1655+
#if HAS_DELTA_Y_CURRENT
1656+
saved_current_y = stepperY.getMilliamps();
1657+
stepperY.rms_current(Y_CURRENT_HOME);
1658+
debug_current_on(PSTR("Y"), saved_current_y, Y_CURRENT_HOME);
1659+
#endif
1660+
#if HAS_CURRENT_HOME(Z)
1661+
saved_current_z = stepperZ.getMilliamps();
1662+
stepperZ.rms_current(Z_CURRENT_HOME);
1663+
debug_current_on(PSTR("Z"), saved_current_z, Z_CURRENT_HOME);
1664+
#endif
1665+
}
1666+
else {
1667+
#if HAS_DELTA_X_CURRENT
1668+
stepperX.rms_current(saved_current_x);
1669+
debug_current_on(PSTR("X"), X_CURRENT_HOME, saved_current_x);
1670+
#endif
1671+
#if HAS_DELTA_Y_CURRENT
1672+
stepperY.rms_current(saved_current_y);
1673+
debug_current_on(PSTR("Y"), Y_CURRENT_HOME, saved_current_y);
1674+
#endif
1675+
#if HAS_CURRENT_HOME(Z)
1676+
stepperZ.rms_current(saved_current_z);
1677+
debug_current_on(PSTR("Z"), Z_CURRENT_HOME, saved_current_z);
1678+
#endif
1679+
}
1680+
1681+
TERN_(IMPROVE_HOMING_RELIABILITY, planner.enable_stall_prevention(onoff));
1682+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
1683+
1684+
#endif // XYZ
1685+
}
1686+
#endif

Marlin/src/module/endstops.h

+5
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,11 @@ class Endstops {
247247
static void clear_endstop_state();
248248
static bool tmc_spi_homing_check();
249249
#endif
250+
public:
251+
// Basic functions for Sensorless Homing
252+
#if USE_SENSORLESS
253+
static void set_homing_current(const bool onoff);
254+
#endif
250255
};
251256

252257
extern Endstops endstops;

Marlin/src/module/motion.cpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -1663,7 +1663,10 @@ void prepare_line_to_destination() {
16631663
}
16641664

16651665
// Disable stealthChop if used. Enable diag1 pin on driver.
1666-
TERN_(SENSORLESS_HOMING, stealth_states = start_sensorless_homing_per_axis(axis));
1666+
#if ENABLED(SENSORLESS_HOMING)
1667+
stealth_states = start_sensorless_homing_per_axis(axis);
1668+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
1669+
#endif
16671670
}
16681671

16691672
#if EITHER(MORGAN_SCARA, MP_SCARA)
@@ -1699,7 +1702,10 @@ void prepare_line_to_destination() {
16991702
endstops.validate_homing_move();
17001703

17011704
// Re-enable stealthChop if used. Disable diag1 pin on driver.
1702-
TERN_(SENSORLESS_HOMING, end_sensorless_homing_per_axis(axis, stealth_states));
1705+
#if ENABLED(SENSORLESS_HOMING)
1706+
end_sensorless_homing_per_axis(axis, stealth_states);
1707+
safe_delay(SENSORLESS_STALLGUARD_DELAY); // Short delay needed to settle
1708+
#endif
17031709
}
17041710
}
17051711

Marlin/src/module/planner.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -1663,10 +1663,7 @@ void Planner::quick_stop() {
16631663
// forced to empty, there's no risk the ISR will touch this.
16641664
delay_before_delivering = BLOCK_DELAY_FOR_1ST_MOVE;
16651665

1666-
#if HAS_WIRED_LCD
1667-
// Clear the accumulated runtime
1668-
clear_block_buffer_runtime();
1669-
#endif
1666+
TERN_(HAS_WIRED_LCD, clear_block_buffer_runtime()); // Clear the accumulated runtime
16701667

16711668
// Make sure to drop any attempt of queuing moves for 1 second
16721669
cleaning_buffer_counter = TEMP_TIMER_FREQUENCY;

0 commit comments

Comments
 (0)