Skip to content

Commit 87c4cd2

Browse files
🐛 Fix steps-to-mm with backlash (MarlinFirmware#23814)
Co-authored-by: Scott Lahteine <[email protected]>
1 parent 103b5f1 commit 87c4cd2

File tree

3 files changed

+54
-13
lines changed

3 files changed

+54
-13
lines changed

Marlin/src/feature/backlash.cpp

+26-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
#include "../module/motion.h"
3030
#include "../module/planner.h"
3131

32+
axis_bits_t Backlash::last_direction_bits;
33+
#ifdef BACKLASH_SMOOTHING_MM
34+
xyz_long_t Backlash::residual_error{0};
35+
#endif
36+
3237
#ifdef BACKLASH_DISTANCE_MM
3338
#if ENABLED(BACKLASH_GCODE)
3439
xyz_float_t Backlash::distance_mm = BACKLASH_DISTANCE_MM;
@@ -61,7 +66,6 @@ Backlash backlash;
6166
*/
6267

6368
void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block) {
64-
static axis_bits_t last_direction_bits;
6569
axis_bits_t changed_dir = last_direction_bits ^ dm;
6670
// Ignore direction change unless steps are taken in that direction
6771
#if DISABLED(CORE_BACKLASH) || EITHER(MARKFORGED_XY, MARKFORGED_YX)
@@ -91,10 +95,6 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const
9195
// smoothing distance. Since the computation of this proportion involves a floating point
9296
// division, defer computation until needed.
9397
float segment_proportion = 0;
94-
95-
// Residual error carried forward across multiple segments, so correction can be applied
96-
// to segments where there is no direction change.
97-
static xyz_long_t residual_error{0};
9898
#else
9999
// No direction change, no correction.
100100
if (!changed_dir) return;
@@ -153,6 +153,27 @@ void Backlash::add_correction_steps(const int32_t &da, const int32_t &db, const
153153
}
154154
}
155155

156+
int32_t Backlash::applied_steps(const AxisEnum axis) {
157+
if (axis >= LINEAR_AXES) return 0;
158+
159+
const bool reversing = TEST(last_direction_bits, axis);
160+
161+
#ifdef BACKLASH_SMOOTHING_MM
162+
const int32_t residual_error_axis = residual_error[axis];
163+
#else
164+
constexpr int32_t residual_error_axis = 0;
165+
#endif
166+
167+
// At startup it is assumed the last move was forwards. So the applied
168+
// steps will always be a non-positive number.
169+
170+
if (!reversing) return -residual_error_axis;
171+
172+
const float f_corr = float(correction) / 255.0f;
173+
const int32_t full_error_axis = -f_corr * distance_mm[axis] * planner.settings.axis_steps_per_mm[axis];
174+
return full_error_axis - residual_error_axis;
175+
}
176+
156177
#if ENABLED(MEASURE_BACKLASH_WHEN_PROBING)
157178

158179
#include "../module/probe.h"

Marlin/src/feature/backlash.h

+8-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@
2727
constexpr uint8_t all_on = 0xFF, all_off = 0x00;
2828

2929
class Backlash {
30+
private:
31+
static axis_bits_t last_direction_bits;
32+
#ifdef BACKLASH_SMOOTHING_MM
33+
static xyz_long_t residual_error;
34+
#endif
35+
3036
public:
3137
#if ENABLED(BACKLASH_GCODE)
3238
static xyz_float_t distance_mm;
@@ -71,7 +77,8 @@ class Backlash {
7177
return has_measurement(X_AXIS) || has_measurement(Y_AXIS) || has_measurement(Z_AXIS);
7278
}
7379

74-
void add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block);
80+
static void add_correction_steps(const int32_t &da, const int32_t &db, const int32_t &dc, const axis_bits_t dm, block_t * const block);
81+
static int32_t applied_steps(const AxisEnum axis);
7582
};
7683

7784
extern Backlash backlash;

Marlin/src/module/planner.cpp

+20-7
Original file line numberDiff line numberDiff line change
@@ -1706,7 +1706,8 @@ void Planner::endstop_triggered(const AxisEnum axis) {
17061706
}
17071707

17081708
float Planner::triggered_position_mm(const AxisEnum axis) {
1709-
return stepper.triggered_position(axis) * mm_per_step[axis];
1709+
const float result = DIFF_TERN(BACKLASH_COMPENSATION, stepper.triggered_position(axis), backlash.applied_steps(axis));
1710+
return result * mm_per_step[axis];
17101711
}
17111712

17121713
void Planner::finish_and_disable() {
@@ -1728,8 +1729,8 @@ float Planner::get_axis_position_mm(const AxisEnum axis) {
17281729
// Protect the access to the position.
17291730
const bool was_enabled = stepper.suspend();
17301731

1731-
const int32_t p1 = stepper.position(CORE_AXIS_1),
1732-
p2 = stepper.position(CORE_AXIS_2);
1732+
const int32_t p1 = DIFF_TERN(BACKLASH_COMPENSATION, stepper.position(CORE_AXIS_1), backlash.applied_steps(CORE_AXIS_1)),
1733+
p2 = DIFF_TERN(BACKLASH_COMPENSATION, stepper.position(CORE_AXIS_2), backlash.applied_steps(CORE_AXIS_2));
17331734

17341735
if (was_enabled) stepper.wake_up();
17351736

@@ -1738,7 +1739,7 @@ float Planner::get_axis_position_mm(const AxisEnum axis) {
17381739
axis_steps = (axis == CORE_AXIS_2 ? CORESIGN(p1 - p2) : p1 + p2) * 0.5f;
17391740
}
17401741
else
1741-
axis_steps = stepper.position(axis);
1742+
axis_steps = DIFF_TERN(BACKLASH_COMPENSATION, stepper.position(axis), backlash.applied_steps(axis));
17421743

17431744
#elif EITHER(MARKFORGED_XY, MARKFORGED_YX)
17441745

@@ -1755,11 +1756,12 @@ float Planner::get_axis_position_mm(const AxisEnum axis) {
17551756
axis_steps = ((axis == CORE_AXIS_1) ? p1 - p2 : p2);
17561757
}
17571758
else
1758-
axis_steps = stepper.position(axis);
1759+
axis_steps = DIFF_TERN(BACKLASH_COMPENSATION, stepper.position(axis), backlash.applied_steps(axis));
17591760

17601761
#else
17611762

17621763
axis_steps = stepper.position(axis);
1764+
TERN_(BACKLASH_COMPENSATION, axis_steps -= backlash.applied_steps(axis));
17631765

17641766
#endif
17651767

@@ -2841,6 +2843,9 @@ void Planner::buffer_sync_block(TERN_(LASER_SYNCHRONOUS_M106_M107, uint8_t sync_
28412843
block->flag = sync_flag;
28422844

28432845
block->position = position;
2846+
#if ENABLED(BACKLASH_COMPENSATION)
2847+
LOOP_LINEAR_AXES(axis) block->position[axis] += backlash.applied_steps((AxisEnum)axis);
2848+
#endif
28442849

28452850
#if BOTH(HAS_FAN, LASER_SYNCHRONOUS_M106_M107)
28462851
FANS_LOOP(i) block->fan_speed[i] = thermalManager.fan_speed[i];
@@ -3108,13 +3113,21 @@ void Planner::set_machine_position_mm(const abce_pos_t &abce) {
31083113
LROUND(abce.k * settings.axis_steps_per_mm[K_AXIS])
31093114
)
31103115
);
3116+
31113117
if (has_blocks_queued()) {
31123118
//previous_nominal_speed_sqr = 0.0; // Reset planner junction speeds. Assume start from rest.
31133119
//previous_speed.reset();
31143120
buffer_sync_block();
31153121
}
3116-
else
3117-
stepper.set_position(position);
3122+
else {
3123+
#if ENABLED(BACKLASH_COMPENSATION)
3124+
abce_long_t stepper_pos = position;
3125+
LOOP_LINEAR_AXES(axis) stepper_pos[axis] += backlash.applied_steps((AxisEnum)axis);
3126+
stepper.set_position(stepper_pos);
3127+
#else
3128+
stepper.set_position(position);
3129+
#endif
3130+
}
31183131
}
31193132

31203133
void Planner::set_position_mm(const xyze_pos_t &xyze) {

0 commit comments

Comments
 (0)