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
16.19k stars 19.22k forks source link

LINEAR ADVANCE 2.0 #10812

Closed ejtagle closed 5 years ago

ejtagle commented 6 years ago

I am opening this "issue" as a way to collect ideas and opinions/advice on the ongoing Linear Advance implementation (before I actually start coding it!) that should not only compensate the usual trapezoidal speed profile, but also the Bézier Curve Speed profile.

First, let me link (and also cut&paste, before it is lost forever) the references to Pressure Advance (that is the idea we will try to implement);

The original analysis was done by Bernhard Kubicek (http://bernhardkubicek.soup.io/post/168776124/Another-acceleration-extrusion-compensation-for-repraps), and was inspired by some mails with Matt (http://reprap.org/pipermail/reprap-dev/2011-May/003323.html)

There was also a PDF, but this PDF is now lost (I don´t have a copy of it). But nevertheless, let´s continue:

Quoting the original author… ``` I have tried to redo the calculations that Mattroberts did in his mail and came to a different extruder acceleration-compensation method than him. Warning! Math ahead! For thoose savy, please check for mistakes. Matt roberts assumes the pressure difference through the nozzle is governed by the bernoulli equations. rho*v^2/2+p=const. and hence [delta]p=(vout^2-vin^2) rho/2 where: rho: density of fluid v: velocity p: pressure, vin=solid filament input velocity, vout: molten fiber output velocity Yes this is a factor. But also, so is friction. According to the Darcy Weisbach equation the friction in a pipe is: p=f L/D rho v^2/2 where: f: darcy friction factor see later L length of the frictioning part D: hydraulic diameter of the pipe, aka diameter The friction factor for a laminar flow is: f=64/reynoldsnr=64*mu/(rho v D) where mu: viscosity The total friction is hence: p= 64*mu/(rho v D)*L/D rho v^2/2 = 32 mu v /D^2 So lets do some trial calculations: The input diameter is 3mm, the output diameter 0.25. The density approx 1000kg/m^3, the viscosity is similar to ketchup, aka 100 pa s. The pressure drop due to Bernouli, for extrusion of 1cm/sec molten filament, multiplied by the solid filament area is: 7e-7 Pascal. The pressure drop due to friction for the same speed, times the area of the nozzle: 2.5 Pascal So the extrusion resistance is friction dominated, and we can neglect the Bernoulli pressure drop. So the next step. Lets assume that we have some overpressure p in the hot end (and maybe bowden cable, in my case). > nd that we can increase the overpressure by inserting more material than we get out, and a spring constant k. p=k [delta]x/Ain where x being the too much inserted material from the solid filament Ain is the crossection area of the solid filament x can be calculated from the previous history: [delta]x=[delta]Volume/Ain=[delta]t*(vin*Ain-vout*Aout)/Ain simplification: no thermal expansion or something. This overpressure causes the hot end to extrude the material. p=32 mu vout /Dout^2= alpha*vout where alpha= just some machine dependent factor alpha*vout=k [delta]t*(vin-vout*Aout/Ain) or d/dt vout=[factor] vin- [otherfactor] vout If we throw around all material-dependent stuff to constant factors d/dt vout is the movement acceleration in x-y. Finally we get the needed extruder velocity: vin= [something]*vout+ [something else]*acceleration. So for a stop-acceleration-plateau-deceleration-stop move we get a extruder velocity profile: [instant velocity to, acceleration extrusion+constant factor, instant decrease of velocity, plateau, instant ecrease of velocity, acceleration extrusion-constant factor (even to negative extrusion, stop] So if one allows jerking of the extruder motor, thats quite an easy change in the firmwares, especially > ince [something] is already implemented. ```

So, the formula we want to implement is:

vin= [something]vout+ [something else]acceleration.

Basically, we want to add, to the extruder steps commanded by the Gcode, another term that is proportional in a factor K to the acceleration of the axis motors.

Linear Acceleration 1.5 was designed with trapezoidal speed profile in mind, and in that profile, the 1st part of the movement has uniform acceleration, then the second part has no acceleration, and the 3rd part has constant deceleration, so it just needs to add a constant to the Extruder steps at the start of the movement (taking into account maximum E acceleration and jerk), and then substract it at the start of the 2nd part of the profile, then substract a constant at the end of the 2nd part and readd it at the end of the 3rd part.

profile

But now, using Bézier interpolation, the acceleration is not constant anymore. Starts at 0, and gradually increases, reaches a maximum and decreases to 0 again (https://github.com/synthetos/TinyG/wiki/Jerk-Controlled-Motion-Explained)

So, the only feasible approach is to estimate that 2nd term! ...

In the stepper ISR, for each ISR we calculate the current speed in steps per second (and using that we calculate period between steps, etc).

If we keep the previous speed, then we can estimate acceleration as:

interval = 1/old_step_rate // time between steps acceleration = (step_rate - old_step_rate) / interval

But, we can remove the divide:

 => acceleration = (step_rate - old_step_rate) / (1/old_step_rate); 
 =>  = (step_rate * old_step_rate/scale - old_step_rate*old_step_rate/1);
 =>  = (step_rate * old_step_rate - old_step_rate*old_step_rate) / 1;
 =>  = (step_rate - old_step_rate) * old_step_rate; 

The last formula gives "instantaneous" acceleration in pulses/s^2 If we assume a maximum possible speed of 300 mm/s, a maximum acceleration of 3000mm/s^2 and using 96 pulses per mm, then this multiplication is a 15bit x 16bit signed multiplication. And mostly of the time, in fact it is 8bit by 16 bit, That happens because the faster the movement is, the smaller the difference between old and current speeds will be.

So, the above formula is mostly all what is required to calculate the 2nd term of the Pressure advance algorithm. The acceleration must be multiplied by a K factor, and divided by the steps per mm. And, in fact, the only thing required is to multiply by K, as we want also acceleration to be calculated in steps!!

We can easily convert that last multiplication to a fixed point multiplication, and there is no need for perfection here. An error of 2% is perfectly acceptable.

The only remaining thing I would add is backslash compensation for bowdens, as, as explained, the lenght of filament in the tube changes based on if it is being compressed (pushed), or pulled from the nozzle - Thats easy: Each time extruder motor direction changes, we must add or substract the hysteresis length of filament.

Before starting coding this, I´d want to know if there is any pitfall or problem you could see on the idea. I know that AVR will probably need a little assembler to perform the multiplication in realtime, but ARM solves 32bit multiplications in 1 cycles, so no problems on 32 bits to perform this.

Any suggestion, any advice ?

Sineos commented 6 years ago

There was also a PDF, but this PDF is now lost (I don´t have a copy of it)

Are you talking about this one? https://drive.google.com/file/d/0B5UvosQgK3adaHVtdUI5OFR3VUU/view It is linked in the LA Marlin documentation

For reference the LA 1.5 Threads: #9379, #9700

In an issue thread there has been a discussion, if different K-Factors for the acceleration and deceleration phase might be needed. This came from the observation that the K-Factor Test Pattern shows distinct differences between the transition from slow to fast versus the transition from fast to slow. Something I can confirm on my setup.

ejtagle commented 6 years ago

@Sineos @Sebastianv650: I do suspect the "backslash" problem of bowdens could be the culprit. No Linear Advance implementation so far has taken it into account... And unfortunately, overcompensation using the K factor is not exactly equivalent. On Bézier, directly we need to estimate advance at each step of the stepper - There is no workaround

The other problem that exists is the Jerk value... If we allow jerk between movements, that requires instantaneous changes of the extruder motor position - And that can´t be done, so, either the axis motors are slown down (bad thing!!) or the extruder does not respect its own jerk/maximum speed.

But, here happens a very, very strange thing: If using Bezier control, there are no abrupt acceleration jumps on axis, thus the acceleration term changes very slowly, then the extruder motion will ALSO be smooth, And, when using the Junction deviation algorithm instead of Jerk control, Jerk can be set to 0, yes, as you read, and no axis jerk,

profile-2

In that picture, look at the middle graph. A sudden change of speed (jerk) essentially destroys linear advance...

That is why a new Linear Advance is required: To capitalize the advantages of all this improvements ... ;)

lrpirlet commented 6 years ago

@ejtagle Are you looking for Bernhard Kubicek paper over Improved oozing compensation for DIY fused deposition 3d printers? Have a look there http://web.archive.org/web/20140801235854/http://kariert.org/advanceV2.pdf

lrpirlet commented 6 years ago

@ejtagle I knew I had something else hidden (well, lost in my pile of "read carefully" references) that may be of interrest… (I was having a huge problem of blobs) see http://basdebruijn.com/2014/05/machinekit-and-additive-manufacturing/

Also, some discussion took place a while ago in the Marlin issues threads, see #1600 and #4044 (there may be more, but I did save the reference to those two).

Sebastianv650 commented 6 years ago

@ejtagle please, please, don't implement some untested formulas! I have done a hughe bunch of tests when I started with LA, and all my results have shown that the formulas posted above are not the ones we need! Why? It's quite simple: There might be some pressure effects inside the nozzle (bernouli), but they are incredible small and therefore not noticeable compared to the hughe effect we see due to filament compression. Of course we could build an additional layer, compensating for these effects, but it's doing nothing except eating cycles.

The backlash problem is nothing we have to compensate for in my opinion:

The real problem with bowdens, where I have no solution for, is friction inside the tube. This prevents LA from working with most bowden systems, as the fast pressure adjustment moves are "eaten up" by the tube. You can see the effect quite good when printing a slow line, followed by a fast one along the same axis. While you would expect to see a recovery of the extruded width over time, this is not the case for a very long distance. Even using LA, this isn't changing. Friction and buckling isn't allowing the filament to "leave" the tube even if we push hard on the inlet. Try to push a peace of rubber through a tube - you will see what I mean.

Sebastianv650 commented 6 years ago

My honest recommendation is to fix LA by not changing its way of working. Then adopt it for bezier. When we have a working system to play with, feel free to make changes as much as you want creating a 2.0. That way, we always have the possibility to compare you results to LA 1.5. And if it works better, we can replace it - I have no problem with that.

ejtagle commented 6 years ago

@Sebastianv650 : That is exactly the idea of this thread. To collect experience and make sure not to waste effort on things that will not work.

ejtagle commented 6 years ago

But @Sebastianv650 , you are already describing the problem pretty well, and giving me several ideas...

There might be some pressure effects inside the nozzle (bernouli), but they are incredible small and therefore not noticeable compared to the hughe effect we see due to filament compression.

and

The real problem with bowdens, where I have no solution for, is friction inside the tube. This prevents LA from working with most bowden systems, as the fast pressure adjustment moves are "eaten up" by the tube.

This seems to indicate that you saw the most problematic thing to be friction and compression - Friction seemed to have a non-linear dependency on speed, probably quadratic or cubic (it doesn´t actually matter. The fact is that faster filament moves make friction much more heavier. Combine that distributed friction with a distributed elastic constant, and you end up in something like a delay line - And there is a lot of things you can do to fix it.

As instantaneous torque is limited by the motor itself, instantaneous changes of pressure can´t be realized, but, you can do much better by just anticipating the required changes and distribute them along time... Lets do some sims... ;)

pressure sim

Green trace is the expected position (as commanded from the extruder motor) of the filament, and the red one is what we actually have due to compression and friction combined.

Note the red is a delayed and smoother version (low pass filtered version). The main question is what is the required compensation, on the motor side, so we get what we want, and not that delayed version

Sebastianv650 commented 6 years ago

Friction as a part, yes, but I expect buckling is the even bigger portion. If we have buckling once, there is nothing we can do anymore as long as it is gone again - like a jam.

Yes, it sounds easy to play with time shift. My problem which prevented me from an implementation was always the small buffer Marlin is able to use (at least on AVR). With 16 blocks, there is nearly nothing to look forward on organic shapes. Each segment might only be 0.1mm long or even shorter, at 60mm/s thats around 0.017s if we ignore acceleration for the moment.

One solution to the bowden problem, which is also already in use by one FW I forgot its name, is to calculate the main (average) needed nozzle pressure some specific time in the future and adjust to that pressure more slowly than we would do with LA at the moment. This will not result in sharp edges, but would at least enable bowden printer users to use different print speeds in one print without missing (fast) infill lines and so on.

ejtagle commented 6 years ago

@Sebastianv650 : Continuing on the simulation thing...

sim-2

Here: Red trace is the desired "pressure" or "position" of the filament at the hotend Green line is what is actually there, after friction and compression Blue line is the derivative of the position againt time Pink line is a low pass filtered version of that derivative (basically slowly converging to the derivative) - This is the Linear Advance we could estimate Then, Cyan line represents the position of the filament in the hotend nozzle if the compensation term was added to the motor..

As you see, it is possible to compensate it pretty well. As far as i understand your algorithm, basically you are doing mostly the same thing, but without the smoothing of the derivative...

ejtagle commented 6 years ago

And, note most of the problems are caused by the abrupt change of acceleration (derivative of speed). I expect this to radically change when using Bezier control, as there is no such change, so the required compensation term would not change at that high speed, thus reducing or probably removing the need of forward planning extruder volumes, as you said a firmware was already doing... ;)

ejtagle commented 6 years ago

Yes, buckling is a non linear effect, but I assume it only happens on sudden changes of position, so slowing those changes could reduce them. I highly hope and expect Bézier will do that.

ejtagle commented 6 years ago

@Sebastianv650 : After careful analysis, what i think the LA.15 implementation is doing is just to advance the movements. If you carefully look at the green and red traces, if you just advance in time the green trace, you end up also getting a very very good compensation! ... Undoubtly that is cheaper than computing the derivative formula, but i am not completely sure if it is doable for Beziers... Note that the advance depends also on acceleration speed of extruder (the E/D ratio you are using)

Sineos commented 6 years ago

Guess this thread might also be valuable

Sebastianv650 commented 6 years ago

@ejtagle I don't think a time shift will have the same effect, at least on direct drive system where we see a very fast (I would say instant) response. If we start to deplete pressure before the real deceleration happens, we will see a gap between the perimeters.

The E/D ratio is only a work around in the end, as the extruder speed isn't directly known inside the stepper ISR. It's just the ratio between extruder speed and the leading axis. This was more obvious in LA 1.0. In this initial release, I calculated the extruder velocity based on this factor and the actual step rate inside every ISR loop. The additional esteps to be executed until the next main stepper ISR will happen is: actual_extruder_velocity * K - advance_steps_already_executed.

The main reason why I was moving away from this method using actual speed to now used acceleration is that the step rate isn't what it should be especialy during the block junctions due to Marlins way of interpolation. There was always the bad chance of seeing a velocity jump at junctions where there is not even a real one in a perfect planner trapezoid.

ejtagle commented 6 years ago

I agree : The jerk code was a workaround (to try to keep speed at direction changes), and that caused a lot of issues..

FiCacador commented 6 years ago

Ideally there would be two independent factors, the current k to compensate pressure on accelerations/decelerations and another factor or value to anticipate E movements to compensate for the response delay on bowdens.

ejtagle commented 6 years ago

In fact, you are right. The model has 2 parameters. One of them compensates the pressure, and the other compensates the delay. On the graphs i did, there were those 2 parameters. I tuned them to get the best possible compensation

boelle commented 5 years ago

@ejtagle any news?

github-actions[bot] commented 4 years ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.