Automatic PA calibration using hotend loadcells

Hi all,

I have been working for some time on automatic PA calibration using load cells in the hotends, and while some improvements are still needed, I think my code reached a stage where it can be tested by and potentially used on a regular basis by others. The code is published in this branch. There is also some basic configuration reference, description of gcode commands, and status reference (all subject to change; suggestions on improvements are also welcome).

Some suggestions for installation and configuration:

  • You must install numpy, e.g. via ~/klippy-env/bin/pip install -v "numpy<1.26" (this is from official Klipper docs, perhaps you can actually drop that <1.26 version restriction part.
  • I recommend if at all possible to install scipy too via ~/klippy-env/bin/pip install scipy and `sudo apt install libatlas-base-dev libopenblas-dev` and set use_scipy = true in the [pa_tester] configuration section.
  • For the load_cell, I think that sample_rate above 100 is required, and actually should be above 300, ideally 500+ (I personally tested at 1000 with ADS131M02). This means that, in practice, it should be possible to test with HX717 (supports 320 samples/sec), ADS1220 (supports high sampling rates, 660 is the default), and ADS131M0x (supports very high sampling rates, though I think it makes sense to stick with 500-1000) - all these ADCs are currently supported by mainline Klipper (though perhaps if you can patch a different sensor support over my branch, that should work too).

Some notable [pa_tester] parameters:

  • purge_length is the length of initial purge, this is needed to purge old potentially degraded filament from the hotend and build-up initial pressure in the hotend; I’d recommend to set it to the length of the hot side of the hotend (on Volcano, I set it to 25 mm)
  • high_flow (in mm^3/sec) determines the fastest extrusion rate during the test, I’d recommend to set it up to 80% of a maximum typical flow rate for your hotend or below - e.g. to the maximum extrusion rate you’d be printing with the tested filament (for example, I set it to 16 mm^3/sec on Volcano hotend).
  • slow_flow is the flow rate for slow extrusion during the test, default is 2 and can probably be left at that value (which corresponds to 25 mm/sec linear extrusion speed when printing at 0.2 mm layer height and 0.4 mm extrusion width - this would be a reasonable linear speed for features like bridges or very strong overhangs).
  • segment_time - this is a duration of a single element of the test, default value of 0.5 seconds is good for direct drive extruders and reasonably hard filaments. If you want to test PA calibration on bowden extruders or with flexible filaments, you’ll need to increase the value of this parameter to 1-3 seconds.
  • filter_window - the duration of signal smoothing filter, default value is 0.01 sec, though it can be increased to 0.015-0.02 sec if you suspect strong noise in the sensor output. However, if output signal has strong pulsations from power lines (at 50-60 Hz) and/or Klipper hotend/fans PWM (which is 10 Hz by default) - which may happen especially if load cell wires go near hotend or fan wires - signal filter may not help really and you should better focus on resolving these cross-talks.
  • extrude_force_sign - this tells whether the force readings increase (1) or decrease (-1) as extrusion goes faster; the algorithms can detect this automatically, but it can also be overridden or just hard-coded for a specific loadcell for (slightly?) improved reliability.
  • method - determines test method to be used for PA calibration.

Note that all of the parameters above can be overridden at runtime via GCode command parameters (so you can easily adjust them). As for the methods, two methods have been implemented:

  • step_response - this method simply oscillates between high and slow extrusion rates, measures force response, and fits it to exponential decay model A + B * exp(-C * t) + D * t, which naturally follows from linear PA model (actual PA value is 1/C, and D is introduce to account for potential sensor drift) using weighted non-linear minimal squares method.
  • search_overshoot - this method uses binary-search-like method to test different PA values (by extruding with the tested PA value, measuring force response, and searching for signs of PA overshoot - force overshooting and then dropping) to find an optimal PA value just before an overshoot occurs.

step_response is faster and requires much less filament, but I guess it depends more on the filament flow following the theoretical model, while search_overshoot is slower and requires more plastic, but it measures effects of Pressure Advance ‘more directly’ if you will. For testing, it would be great to try both out, and then print more regular PA tests with the same filament to compare results, and then, most importantly, try to print real prints with the PA values from both methods (if they are different) to see how the automatically calibrated PA values work for real-life prints (so, I’d say, not just compare against more classical PA print tests, but also try to print with the calibrated PA value(s) and see how they work). Also, during automatic PA tests please scrape debug data using motan script:

python3 ~/klipper/scripts/motan/data_logger.py ~/printer_data/comms/klippy.sock /tmp/<some-test-name> -s '*'

especially if you run into some issues, and attach both generated files per test to you report alongside with klippy.log - it would help a ton to collect more real-life data.

On a separate note, I am aware of other recent (and not so recent) projects in this area, e.g. PrusaPATuner (by CNC Kitchen), bd_pressure (semi-opensource project), autopa (partially a port of PATuner to Klipper) to name a few. However, my implementation is completely independent and not based on any of them, though basic principles behind the approaches are somewhat similar. That said, given that this area got a lot of momentum and interest both from users and developers recently, I really hope we can merge some working version of automatic PA calibration into the mainline Klipper some time soon.

3 Likes

Interesting, I had a similar idea (also independent, but probably later than everyone else ;-)). I would like to test your approach, but unfortunately I cannot right now because I only have a HX711 which is way too slow (yes I should and likely will upgrade, but that’s a different story).

The approach I came up with was slightly different: We could measure the pressure advance coefficient in two pieces: The relationship between extruder movement (i.e. distance) and force, and the relationship between force and extruder speed. Multiplying these two quantities should give the PA coefficient.

I have not yet tried this out, but I will soon try some back-on-the-envelope test to see if this approach even has a chance. Since I cannot really believe that so many people work on this but did not think about this approach, it is likely not working. If it does though, I see two potential advantages: Since it is only measuring steady-state quantities, we do not have to rely on fast ADCs and potentially even knowing when ADC samples are exactly taken w.r.t. motor positions. Secondly, we might even be able to update the force-speed relationship during the print, in case it changes for whatever reason (e.g. changing temperature). Also the force-distance relationship can be measured with no filament use, potentially even before every print as part of the start code.

A downside will be that the distance-force relationship has to be measured at a temperature below the melting point. I am not sure how much of a difference this will make, since pressure advance is about the properties of the piece of filament between hotend and extruder, which is in solid state anyway and will have mostly similar temperatures if the hotend is a bit colder. But there will be a transition region inside the hotend where the material becomes soft, and I am not sure how much of an influence this might have.

Any thoughts about this approach?

Interesting approach.

The relationship between extruder movement (i.e. distance) and force

When I read this, I immediately thought, but how exactly would you do that? Until I read

the distance-force relationship has to be measured at a temperature below the melting point

and then I was, OK, I see.

Please take my thoughts with a grain of salt, since I did not try it myself, so I could be wrong. But I see two potential problems with it:

  • Sensor force drift - so measuring the force difference between two extrusion speeds might be challenging. Plus you may argue that PA should compensate at dynamics rather than between steady states.
  • That way of measuring position-force relationship ignores the melted state of plastic completely, which also compresses, but may exhibit different properties. Plus, at temperatures below melting point the plastic in the hot zone binds with the nozzle and the heatbreak, so you’ll be measuring the k factor of a shorter filament length than in real printing.

So, I think you may be able to estimate PA by order, but likely not very precisely. Alas, PA is one of the parameters that need to be reasonably precise. So, estimating, say, 0.05 PA value instead of real 0.03 or 0.07 will likely have detrimental effects on print quality, even though it is better than nothing. But I suspect this might be a reason why this approach was not explored in detail, or at least the results of such explorations are not widely available. But again, these are just my thoughts on this matter.

1 Like

2 more variables come to mind. The preposed method “measures” by assuming the filament always moves 1:1 with extruder motor rotation.

  1. Upstream filament tension.
  2. downstream filament force
    Both effect the actual length of filament movement for a given rotation angle.

True, but maybe we can work around this. The relationship will be mostly proportional. So as long as we use relatively fast transitions between two steady states (e.g. no extrusion in travel moves and a certain constant extrusion speed), and the transition is shorter than say 0.5 seconds, I think those sensor drifts are negligible.

From a theoretical standpoint, my proposed measurement should exactly measure what PA needs. PA doesn’t actually act on the change of the extruder speed, it adds to the extruder position in dependence of the speed. This is steady state behaviour. You may be absolutely right though, because maybe there are some additional effects which PA actually can also compensate for (at least approximately), and those would be completely ignored by assuming a (simplified) model.

Liquids are incompressible, this is also true for molten plastic. This is the one point I am pretty sure about will not play a role here :slight_smile:

Yes, that may be a real problem. My hope would be that the effect is rather minimal, since this region must be very short. The material at those temperatures is extraordinary sticky. If there is an elongated zone with plastic right below the melting point, it would become very difficult to extrude anything. This is also the reason why hotends need a heatbreak in the first place. Those are designed to keep that zone short. Still, I cannot judge if that means we can ignored that…

Good point. Although I think that if you have significant slippage due to upstream filament tension (aka the spool is hard to rotate and/or you have long filament tubes causing a lot of friction) you are operating at a rather unstable regime and are likely to observe frequent print failures due to that excessive force. (I actually think maybe people who thing they have a problem with nozzle clogging are actually suffering from exactly such problem…)

I unfortunately wasn’t yet able to try it out. A very brief experiment showed me that it will be a bit more complicated to try it, since readings with extruder movement below the melting point are too unstable to make any sense out of it when doing the measurement manually. It probably takes too much time to read out the load cell after the extruder motion, and load cells tend to drift (especially my setup with two load cells in parallel does so when heat and mechanical stress is involved). I have to write some module to automate this, maybe essentially my using the same algorithm as for the load-cell probe (just moving the E axis instead of the Z axis). That might give me a stable slope to work with - if not, I can already stop I guess :wink:

PS: My comments are not meant to stop you from your approach, which looks certainly more promising. I just cannot try it out for now, I need to get a faster ADC first, which won’t happen in time for me being any help for you I guess - I have to sort out too many other “construction sites” with my printer to attack this right now…

So as long as we use relatively fast transitions between two steady states (e.g. no extrusion in travel moves and a certain constant extrusion speed), and the transition is shorter than say 0.5 seconds, I think those sensor drifts are negligible.

Alas, my experience is that it is not negligible. It likely has to do with back pressure force and sheer stress settling, not sensor drift, but it does not matter for the point I’m making.

You may be absolutely right though, because maybe there are some additional effects which PA actually can also compensate for (at least approximately), and those would be completely ignored by assuming a (simplified) model.

Yes, I meant those ones. You could argue that only PA value search truly measures the actual response to PA, but exponential decay relies on the linear simple model - but at least it measures true decay and then tries to fit whatever exponent value fits best - so potentially approximating those effects.

Liquids are incompressible, this is also true for molten plastic. This is the one point I am pretty sure about will not play a role here :slight_smile:

Well, liquids are typically not less compressible than solid state AFAICT :slight_smile: For example, if you look at Bulk Modulus, it is defined for liquids too. Alas, the data for plastics is sparse, so I was able to pull some data only with the help of AI - so might not be reliable, you may be able to find more reliable data yourself - but typically Bulk Modulus is smaller for plastic liquid state than solid one, and it also further drops with temperature (for example, for PLA the numbers quoted are 2-3 GPa for solid and 1-2 GPa for liquid states; water has 2 GPa in comparison). You can argue these values are very high - perhaps other parts of extruder also contribute to PA value, but it is hard to quantify individual contributions.

Yes, that may be a real problem. My hope would be that the effect is rather minimal, since this region must be very short. The material at those temperatures is extraordinary sticky

No, it is not short - this region spans the whole length of the nozzle (see my other comment about compressiability of liquid state), which on high flow hotends is quite substantial (starting from volcano).

1 Like

Well, if you put it that way, all (everyday) solid and liquid materials are incompressible in good approximation. What actually matters is deformation. If you have a column of plastic (aka the filament) and you apply longitudinal pressure, the column will get a bit shorter but also thicker in diameter. The total volume will stay the same. The molten plastic inside the hotend has no space to go anywhere when you apply pressure, hence it will behave “incompressible”. That’s why we teach in Physics classes that liquids are incompressible. That tiny bit of compressibility is entirely negligible. If you find a solid material which you think is compressible, it is usually actually not completely solid but contains gas bubbles or so (e.g. foamed materials).

In a similar way, the softened material will quickly be pushed against the walls by the normal extrusion force and then stop expanding any further. Hence I believe that it really does not matter so much what happens inside hot zone and the transition zone. Only where the material has space around it in the lateral direction it can “compress” longitudinally in a way that we have to compensate for it.

Anyway, I don’t want to distract from your original approach too much. I have doubts myself that my approach will lead anywhere, and the discussion with you has increased those doubts :slight_smile:

Well, if you put it that way, all (everyday) solid and liquid materials are incompressible in good approximation. What actually matters is deformation. If you have a column of plastic (aka the filament) and you apply longitudinal pressure, the column will get a bit shorter but also thicker in diameter. The total volume will stay the same. The molten plastic inside the hotend has no space to go anywhere when you apply pressure, hence it will behave “incompressible”.

You are right in that I oversimplified my message in an attempt to not bring in Young’s Modulus into the picture - so let me correct that.

For liquids, we must use Bulk Modulus. By definition, it is K=-V*dP/dV. Let’s assume the molten plastic is in the nozzle of internal radius R_n (=1mm) and the length of the molten phase is L_m. Then F=P*pi*R_n^2, V=pi*R_n^2*L_m, dP=dF/(pi*R_n^2), dV=pi*R_n^2*dL_m, and then we get K=-L_m*dF/(pi*R_n^2*dL_m), or dF=-pi*R_n^2*K*dL_m/L_m. And if we are looking for a “spring constant” k as in F=-k*x, we have for a molten plastic k_m=pi*R_n^2*K/L_m.

Now for solid plastic we can use Hook’s law and the variant for a rod, which says delta_L=F*L_f/(pi*R_f^2*E) , with R_f - filament radius (=0.875mm), L_f - non-deformed length, and E - elastic modulus (Young’s modulus). From here we get again this “spring constant” k_s=pi*R_f^2*E/L_f.

So, as you can see, k_m and k_s look very similar, just using different radii (but they are very close), different lengths (these are different, but typically L_f is 2-3 times larger than L_m), and different moduli. However, here’s the catch: for rigid plastics, Young’s modulus is typically comparable to Bulks Modulus of a solid phase (FWIW, it is also true for many metals). For example, for PLA Wikipedia quotes E=2.7-16 GPa (and for example, Bambulab quotes E=2-2.5 GPa for their PLA Basic). So, if we estimate spring factors for molten and solid phases for volcano hotend (R_d=1mm, L_m~=25mm) and some extruder with L=40mm, for PLA with K=3GPa and E=2GPa, we get k_m ~= 377 kN/m and k_s ~= 120 kN/m. So, while k_m is larger than k_s due to K higher than E and shorter molten section, they are still quite comparable and I’m not sure you can completely ignore the molten phase (and even more so for high-flow hotends like Goliath which have very long heated zone).

Here’s what I got for Bulk and Young’s moduli today (but the usual notice to take the data with a fair share of caution applies):

Polymer Liquid Bulk Modulus (K\_{l}) Solid Bulk Modulus (K\_{s}) Young’s Modulus (E)
PLA 2.0 - 3.0 \text{ GPa} 3.5 - 4.5 \text{ GPa} 2.0 - 4.5 \text{ GPa}
ABS 1.5 - 2.1 \text{ GPa} 3.0 - 3.8 \text{ GPa} 1.8 - 2.6 \text{ GPa}
PETG 1.8 - 2.4 \text{ GPa} 3.2 - 4.0 \text{ GPa} 1.9 - 2.3 \text{ GPa}
PA 12 1.2 - 1.8 \text{ GPa} 2.5 - 3.1 \text{ GPa} 1.1 - 1.8 \text{ GPa}
PC 1.6 - 2.2 \text{ GPa} 4.0 - 4.8 \text{ GPa} 2.2 - 2.5 \text{ GPa}
TPU 1.1 - 1.5 \text{ GPa} 1.8 - 2.5 \text{ GPa} 0.01 - 0.1 \text{ GPa}

So, E << K_l (and K_s) only for flexible filaments (for instance PolyFlex TPU95 is listed having E = 33.6 MPa, which would give k_s ~= 2 kN/m).

Let me know if you think my approach is flawed and/or I missed any other important factors or considerations. But regardless, do not take my comments as trying to discourage you from testing your approach. I was merely explaining my thoughts on why it may not produce particularly accurate results - but then I cannot exclude the possibility that the practice may very well deviate from my train of thoughts.

1 Like

You are right. I have to admit I never checked the numbers. I expected the Moduluses (what’s the plural? Maybe Moduli?) to be further apart. I guess I was misled by the simplification “liquids are incompressible” - but that’s probably meant in contrast to gases, not solids.