Marlin icon indicating copy to clipboard operation
Marlin copied to clipboard

Add 4th order S_CURVE_ACCELERATION with configurable S_CURVE_FACTOR

Open mh-dm opened this issue 1 year ago • 13 comments

Description

Add configurable 4th order motion support within S_CURVE_ACCELERATION alongside the existing 6th order motion support.

Background

4th? 6th? What? Short explanation: by default (trapezoidal motion), you set an acceleration limit (example 500mm/s^2), and then whenever the gcode/instructions involve a change in speed it is achieved by accelerating (or decelerating) at that set limit for the required amount of time to achieve the desired speed change. The acceleration goes from 0 (at previous speed) ~instantly to 1x of set limit then back to 0 (at newly desired speed). Force is mass times acceleration which means sudden changes in forces whenever changing speed.

s-curve-no Trapezoidal motion, showing only X-axis. Most speed changes are at 500mm/s^2 acceleration limit.

However, with S_CURVE_ACCELERATION the acceleration will smoothly ramp up from 0, go to roughly 2x of the limit then smoothly ramp down to 0 exactly right to achieve the desired speed change. 2x? Yes. We must temporarily go over 1x to complete the same speed change in the same amount of time but while ramping from 0 acceleration. Overall, the average acceleration remains at the set acceleration limit.

s-curve-6th S_CURVE_ACCELERATION 6th order, showing reaching roughly 2x of the acceleration limit

It's "6th order" because the motion model is position over time as a 6th order polynomial function. However, the actual implementation works with velocity (derivative of position) modeled as a 5th order polynomial.

Details

The problem, I might argue, is that it's "too smooth" for some applications, including 3d printers. S_CURVE_ACCELERATION 6th order spends a lot of time around 0 slowly ramping up then it has to hit high acceleration levels. The solution would be a model with a lower order polynomial. So I did the math for a 4th order polynomial (3rd order in velocity) and this is the result:

s-curve-4th 4th order, with S_CURVE_FACTOR of 0

Note how it only reaches roughly 1.6x of the acceleration limit.

The 4th order motion allows some configuration: the acceleration will start at S_CURVE_FACTOR of the limit, ramp up to above 1x then smoothly back down to S_CURVE_FACTOR of the limit exactly right to achieve the desired speed change.

s-curve-4th-0 25 4th order, with S_CURVE_FACTOR of 0.25

Note how it only reaches roughly 1.4x of the acceleration limit.

Benefits

Less smooth is more smooth™.

For 3d printing in particular, parts are printed line by line with direction changes/corners in between. Cornering is done with "jerk" or junction deviation, both of which involve basically instant speed changes. Basically instant speed change means high acceleration spikes. That doesn't pair that well with a very slowly smoothly ramping S_CURVE_ACCELERATION. It should pair better with a still smooth 4th order motion model that ramps up faster, like starting at a 0.25 S_CURVE_FACTOR. Lower peak acceleration should pair better with low-torque motors used in 3d printers.

TL;DR

Enable S_CURVE_ACCELERATION, uncomment S_CURVE_FACTOR 0.25 and check whether you get less ringing and/or if the printer sounds better/quieter. Then check how much you can increase the acceleration limits before you get too much ringing.

Acceleration only, this will have zero or minimal effect on ringing induced by jerk/junction deviation (but you don't know which type of ringing you have until you test). For the other kind of ringing I think you can try input shaping.

Configurations

This feature is not implemented for AVR. If interested I encourage you to have a go at implementing if you have a logic analyzer, an AVR board and are interested in assembly.

The graphs were obtained with a logic analyzer capturing 15M samples at 12Mhz, directly from the X-axis step/dir pins. (Just FYI my boards are LPC176x). Tiny note that captures were done with PRs #26881 and #27035 already applied. I did that to fix some issues that would pollute the captures a tiny bit.

Test gcode:

G4 P550 ; Delay for capture
G92 X10 Y10
M92 X80 Y80 ; 80 steps per mm
M204 S500
M205 X0.2 Y0.2 ; Low jerk
G0 F1500 X11.5
G0 F1200 X12
G0 F1800 X13.5
G0 F1400 X14.1
G0 F1600 X15.2
G92 Y10 ; sync test
G0 F1800 Y10.1
M204 S250
G0 F2000 X15.33
M204 S350
G0 X15.55
M204 S500
G0 X15.85
M204 S750
G0 X16.5
M204 S420
G0 X16.77
M204 S250
G0 X17
G92 Y10 ; sync test
M204 S500
G0 Y10.1
G0 F600 X17.4
G0 F1800 X18.95
G0 F600 X19.3
G0 F1800 X20.9
G0 F600 X21.3
G0 F1800 X23
G0 F600 X23.4
G0 F1800 X25.2
G0 F1500 X26
G0 F1200 X27
G0 F1800 X24.5
G92 Y10 ; sync test
G0 Y10.1
G0 F6000 X10

Related Issues

mh-dm avatar May 18 '24 12:05 mh-dm

Nice work again! Configurable bow was the biggest drawback to s-curve in my opinion! One more thing to pull into my test branch! Lol

InsanityAutomation avatar May 18 '24 22:05 InsanityAutomation

This will be interesting to test on boards with an STM32G0 (such as SKR Mini E3 V3.0 and BTT Manta boards) because they are using the fallback implementation for S_CURVE_ACCELRATION and that section runs in 500 cycles on those boards since it doesn't have the umull instruction. Each multiplication on STM32G0 takes 52 cycles so this PR takes around 100 cycles off that 500.

cbagwell avatar May 21 '24 00:05 cbagwell

But there is a question - does S_CURVE have meaning at all, taking in consideration that jerk, happening just before/after acceleration/deceleration produces infinite (obviously not) acceleration?

vovodroid avatar Jul 16 '24 18:07 vovodroid

@vovodroid Yes S_CURVE still has meaning but in different ways to different people:

  1. if the primary objective is smooth motion you can use S_CURVE and just set jerk low enough. Note that it's not actually infinite acceleration because the jerk (cornering change in speed) happens from one step to the next so over the duration of a step. At 10mm/s cornering speed and 80 steps/mm that's 800 steps/s or 0.00125s for one step. So a 1mm/s jerk then is equivalent to 800mm/s^2 acceleration. People can do the math or lower jerk and test until it works for their application.
  2. if the primary objective is fast motion/printing then S_CURVE can work with jerk motion. A high jerk means a really high momentary acceleration at the corner. Without S_CURVE you also usually have full deceleration on the segment up to the corner then full acceleration after. S_CURVE avoids all (or most with S_CURVE_FACTOR) of that, flattening the max load on the system. In theory this means less ringing than without S_CURVE at high acceleration and jerk. In practice, the improvement I've personally seen is small. However, without more specific testing/calibration it's hard to judge since the improvement is highly sensitive to the machine's resonance characteristics and the acceleration used. (If you want to know why it's highly sensitive, there's this cool explainer but note that it doesn't reference Marlin 'jerk' rather it uses is 'physics jerk', which I think should be referred to as jolt in 3d printing contexts: https://xenovacivus.github.io/s-vs-t-curve/s-vs-t-curve.html by @xenovacivus . It also confusingly changes the actual overall acceleration of the motion when changing the physics jerk but the overall idea is there)

mh-dm avatar Aug 07 '24 13:08 mh-dm

@mh-dm have you confirmed this modification improves print quality? Do you have some pictures?

dbuezas avatar May 21 '25 06:05 dbuezas

Hi, is there ready to use formula to get peak acceleration from S_CURVE_FACTOR?

vovodroid avatar May 22 '25 12:05 vovodroid

@dbuezas As noted in my August comment: "In theory this means less ringing than without S_CURVE at high acceleration and jerk. In practice, the improvement I've personally seen is small". I saw a small improvement on ringing on some test prints but I didn't take proper photos. I'm doing a round of testing in the next couple weeks for other reasons (swapping belts) so I can compare without vs 0.25 S_CURVE_FACTOR vs pre-existing S_CURVE.

@vovodroid Deriving the formula would probably be an interesting math exercise but I haven't done it. From the data I've shown above: 0, 0.25, and 1 S_CURVE_FACTOR results in momentary peak accelerations of roughly 1.6x, 1.4x, and 1x the set acceleration limit respectively. Best guess it's close enough to a linear interpolation between 1.6x and 1x.

mh-dm avatar May 22 '25 18:05 mh-dm

Can S_CURVE (both current and 4th) go over absolute limits set by M201?

vovodroid avatar May 23 '25 06:05 vovodroid

S_CURVE (current and this PR) is implemented such that it makes the required speed changes in the exact same amount of time that trapezoid motion does. In other words the average acceleration is the same as for trapezoid motion and thus we can say that, on average, it respects the M201 configuration.

But to more directly answer your question: Yes, for peak acceleration. Current S_CURVE peaks at ~2x M201 limits and this PR proposes 4th order S_CURVE that peaks at significantly lower, 1.6x or less depending on S_CURVE_FACTOR.

Good question as this means: The higher peak acceleration means that switching to current S_CURVE has a significant potential to result in skipped steps if the acceleration configuration is set very close to machine limits. It's not as bad as the ~2x implies since A) peak acceleration is different (and 'easier') than average acceleration and B) the peak acceleration happens at a different time than when direction changes / jerk happen (which demand really high peak accelerations from the machine, also past the M201 acceleration configuration).

mh-dm avatar May 23 '25 12:05 mh-dm