Skip to content

Commit 65f9f4e

Browse files
committed
extruder: Implement non-linear extrusion
This allows klipper to compensate for slippage in the extruder at high back-pressures. When enabled through SET_NONLINEAR_EXTRUSION, or nonlinear_a/b in the configuration, the actual extrusion velocity will be modified to v(t) + A*v(t)^2 + B*v(t)^3 where v(t) is the requested velocity, and A/B the provided parameters. This is similar to RepRap's M592 command, except correctly applied to accelerating moves rather than simply scaling the distance of the entire move based on its average velocity. Signed-off-by: Tobias Haegermarck <[email protected]>
1 parent 20245d2 commit 65f9f4e

File tree

5 files changed

+87
-6
lines changed

5 files changed

+87
-6
lines changed

klippy/chelper/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,8 @@
113113
struct stepper_kinematics *extruder_stepper_alloc(void);
114114
void extruder_set_smooth_time(struct stepper_kinematics *sk
115115
, double smooth_time);
116+
void extruder_set_nonlinear(struct stepper_kinematics *sk, double a
117+
, double b);
116118
"""
117119

118120
defs_kin_shaper = """

klippy/chelper/itersolve.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ itersolve_generate_steps(struct stepper_kinematics *sk, double flush_time)
174174
, flush_time);
175175
if (ret)
176176
return ret;
177+
178+
if (sk->post_move_cb)
179+
sk->post_move_cb(sk, pm);
177180
pm = list_next_entry(pm, node);
178181
} while (pm != m);
179182
}
@@ -207,6 +210,9 @@ itersolve_generate_steps(struct stepper_kinematics *sk, double flush_time)
207210
if (flush_time + sk->gen_steps_pre_active <= move_end)
208211
return 0;
209212
}
213+
214+
if (sk->post_move_cb)
215+
sk->post_move_cb(sk, m);
210216
m = list_next_entry(m, node);
211217
}
212218
}

klippy/chelper/itersolve.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct stepper_kinematics;
1111
struct move;
1212
typedef double (*sk_calc_callback)(struct stepper_kinematics *sk, struct move *m
1313
, double move_time);
14+
typedef void (*sk_post_move)(struct stepper_kinematics *sk, struct move *m);
1415
typedef void (*sk_post_callback)(struct stepper_kinematics *sk);
1516
struct stepper_kinematics {
1617
double step_dist, commanded_pos;
@@ -22,6 +23,7 @@ struct stepper_kinematics {
2223
double gen_steps_pre_active, gen_steps_post_active;
2324

2425
sk_calc_callback calc_position_cb;
26+
sk_post_move post_move_cb;
2527
sk_post_callback post_cb;
2628
};
2729

klippy/chelper/kin_extruder.c

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,62 @@ pa_range_integrate(struct move *m, double move_time, double hst)
9797
return res;
9898
}
9999

100+
// Calculate the additional non-linear extrusion movement over a move
101+
static double
102+
nonlinear_extrusion_integrate(struct move *m, double move_time, double a, double b)
103+
{
104+
double t2 = move_time * move_time;
105+
double t3 = t2 * move_time;
106+
double t4 = t3 * move_time;
107+
double sv2 = m->start_v * m->start_v;
108+
double sv3 = sv2 * m->start_v;
109+
110+
// Integral of the intended velocity squared
111+
double v2 = sv2 * move_time
112+
+ m->start_v * m->half_accel * t2
113+
+ m->half_accel * m->half_accel * t3 * (4.0 / 3.0);
114+
115+
// Integral of the intended velocity cubed
116+
double v3 = sv3 * move_time
117+
+ sv2 * m->half_accel * t2 * 3.0
118+
+ m->half_accel * m->half_accel * m->start_v * t3 * 4.0
119+
+ m->half_accel * m->half_accel * m->half_accel * t4 * 2.0;
120+
121+
return a * v2 + b * v3;
122+
}
123+
100124
struct extruder_stepper {
101125
struct stepper_kinematics sk;
102126
double half_smooth_time, inv_half_smooth_time2;
127+
double added_travel; // Total amount of extra movement added by nonlinear extrusion
128+
double nonlinear_a, nonlinear_b;
103129
};
104130

105131
static double
106132
extruder_calc_position(struct stepper_kinematics *sk, struct move *m
107133
, double move_time)
108134
{
109135
struct extruder_stepper *es = container_of(sk, struct extruder_stepper, sk);
136+
double pos = m->start_pos.x + es->added_travel;
110137
double hst = es->half_smooth_time;
111-
if (!hst)
112-
// Pressure advance not enabled
113-
return m->start_pos.x + move_get_distance(m, move_time);
114-
// Apply pressure advance and average over smooth_time
115-
double area = pa_range_integrate(m, move_time, hst);
116-
return m->start_pos.x + area * es->inv_half_smooth_time2;
138+
if (hst) {
139+
// Apply pressure advance and average over smooth_time
140+
double area = pa_range_integrate(m, move_time, hst);
141+
pos += area * es->inv_half_smooth_time2;
142+
} else // Pressure advance not enabled
143+
pos += move_get_distance(m, move_time);
144+
145+
if (es->nonlinear_a || es->nonlinear_b)
146+
pos += nonlinear_extrusion_integrate(m, move_time, es->nonlinear_a, es->nonlinear_b);
147+
return pos;
148+
}
149+
150+
static void
151+
extruder_post_move(struct stepper_kinematics *sk, struct move *m)
152+
{
153+
struct extruder_stepper *es = container_of(sk, struct extruder_stepper, sk);
154+
if (es->nonlinear_a || es->nonlinear_b)
155+
es->added_travel += nonlinear_extrusion_integrate(m, m->move_t, es->nonlinear_a, es->nonlinear_b);
117156
}
118157

119158
void __visible
@@ -128,12 +167,20 @@ extruder_set_smooth_time(struct stepper_kinematics *sk, double smooth_time)
128167
es->inv_half_smooth_time2 = 1. / (hst * hst);
129168
}
130169

170+
void __visible
171+
extruder_set_nonlinear(struct stepper_kinematics *sk, double a, double b)
172+
{
173+
struct extruder_stepper *es = container_of(sk, struct extruder_stepper, sk);
174+
es->nonlinear_a = a;
175+
es->nonlinear_b = b;
176+
}
131177
struct stepper_kinematics * __visible
132178
extruder_stepper_alloc(void)
133179
{
134180
struct extruder_stepper *es = malloc(sizeof(*es));
135181
memset(es, 0, sizeof(*es));
136182
es->sk.calc_position_cb = extruder_calc_position;
183+
es->sk.post_move_cb = extruder_post_move;
137184
es->sk.active_flags = AF_X;
138185
return &es->sk;
139186
}

klippy/kinematics/extruder.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ def __init__(self, config, extruder_num):
4545
pressure_advance = config.getfloat('pressure_advance', 0., minval=0.)
4646
smooth_time = config.getfloat('pressure_advance_smooth_time',
4747
0.040, above=0., maxval=.200)
48+
49+
self.nonlinear_a = self.nonlinear_b = 0.
50+
nonlinear_a = config.getfloat('nonlinear_a', 0.)
51+
nonlinear_b = config.getfloat('nonlinear_b', 0.)
52+
4853
# Setup iterative solver
4954
ffi_main, ffi_lib = chelper.get_ffi()
5055
self.trapq = ffi_main.gc(ffi_lib.trapq_alloc(), ffi_lib.trapq_free)
@@ -56,7 +61,9 @@ def __init__(self, config, extruder_num):
5661
self.stepper.set_trapq(self.trapq)
5762
toolhead.register_step_generator(self.stepper.generate_steps)
5863
self.extruder_set_smooth_time = ffi_lib.extruder_set_smooth_time
64+
self.extruder_set_nonlinear = ffi_lib.extruder_set_nonlinear
5965
self._set_pressure_advance(pressure_advance, smooth_time)
66+
self._set_nonlinear_extrusion(nonlinear_a, nonlinear_b)
6067
# Register commands
6168
gcode = self.printer.lookup_object('gcode')
6269
if self.name == 'extruder':
@@ -66,6 +73,9 @@ def __init__(self, config, extruder_num):
6673
gcode.register_mux_command("SET_PRESSURE_ADVANCE", "EXTRUDER", None,
6774
self.cmd_default_SET_PRESSURE_ADVANCE,
6875
desc=self.cmd_SET_PRESSURE_ADVANCE_help)
76+
gcode.register_mux_command("SET_NONLINEAR_EXTRUSION", "EXTRUDER",
77+
self.name, self.cmd_SET_NONLINEAR_EXTRUSION,
78+
desc=self.cmd_SET_NONLINEAR_EXTRUSION_help)
6979
gcode.register_mux_command("SET_PRESSURE_ADVANCE", "EXTRUDER",
7080
self.name, self.cmd_SET_PRESSURE_ADVANCE,
7181
desc=self.cmd_SET_PRESSURE_ADVANCE_help)
@@ -90,6 +100,10 @@ def _set_pressure_advance(self, pressure_advance, smooth_time):
90100
self.extruder_set_smooth_time(self.sk_extruder, new_smooth_time)
91101
self.pressure_advance = pressure_advance
92102
self.pressure_advance_smooth_time = smooth_time
103+
def _set_nonlinear_extrusion(self, a, b):
104+
self.extruder_set_nonlinear(self.sk_extruder, a, b)
105+
self.nonlinear_a = a
106+
self.nonlinear_b = b
93107
def get_status(self, eventtime):
94108
return dict(self.heater.get_status(eventtime),
95109
pressure_advance=self.pressure_advance,
@@ -192,6 +206,16 @@ def cmd_SET_PRESSURE_ADVANCE(self, gcmd):
192206
% (pressure_advance, smooth_time))
193207
self.printer.set_rollover_info(self.name, "%s: %s" % (self.name, msg))
194208
gcmd.respond_info(msg, log=False)
209+
cmd_SET_NONLINEAR_EXTRUSION_help = "Set nonlinear extrusion parameters"
210+
def cmd_SET_NONLINEAR_EXTRUSION(self, gcmd):
211+
a = gcmd.get_float('A', self.nonlinear_a)
212+
b = gcmd.get_float('B', self.nonlinear_b)
213+
self._set_nonlinear_extrusion(a, b)
214+
msg = ("a: %.6f\n"
215+
"b: %.6f"
216+
% (a, b))
217+
self.printer.set_rollover_info(self.name, "%s: %s" % (self.name, msg))
218+
gcmd.respond_info(msg, log=False)
195219
cmd_SET_E_STEP_DISTANCE_help = "Set extruder step distance"
196220
def cmd_SET_E_STEP_DISTANCE(self, gcmd):
197221
toolhead = self.printer.lookup_object('toolhead')

0 commit comments

Comments
 (0)