MarlinFirmware / Marlin

Marlin is an optimized firmware for RepRap 3D printers based on the Arduino platform. Many commercial 3D printers come with Marlin installed. Check with your vendor if you need source code for your specific machine.
https://marlinfw.org
GNU General Public License v3.0
15.97k stars 19.09k forks source link

Add 4th order S_CURVE_ACCELERATION with configurable S_CURVE_FACTOR #27101

Open mh-dm opened 2 weeks ago

mh-dm commented 2 weeks ago

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 speed) 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

InsanityAutomation commented 2 weeks ago

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

cbagwell commented 1 week ago

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.