Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collecting ideas and advises for LIN_ADVANCE v2 #9048

Closed
Sebastianv650 opened this issue Jan 4, 2018 · 44 comments
Closed

Collecting ideas and advises for LIN_ADVANCE v2 #9048

Sebastianv650 opened this issue Jan 4, 2018 · 44 comments
Labels
T: Design Concept Technical ideas about ways and methods. T: Development Makefiles, PlatformIO, Python scripts, etc.

Comments

@Sebastianv650
Copy link
Contributor

This will be a quite long one but if you like to solve problems and you want to help me improving LIN_ADVANCE I would be very pleased if you continue reading and dive with me into the details of planner code, stepper code and nozzle pressure correction.
I will explain as much of my findings and knowledge I got since I started the LIN_ADVANCE implementation as possible so it should be a quite good start point for everyone who want's to touch LIN_ADVANCE related code or help improving it.

Why we need a LIN_ADVANCE "version 2"

While LIN_ADVANCE works great for me and most (I have no real numbers) others, issue reports here are showing it's not working for everyone. Especialy bowden printers struggle with high needed K values and it doesn't work at all for kinematic printers due to the way the extruder speed is calculated.

It's possible to track this down to two main problems:

The extruder step resolution, or the way how the planner treats the extruder

You might know how the trapezoids looks like which are calculated by the planner code. Here is an example I found, just ignore the numbers:

Image of trapezoids

Here we see two joined motion segments. First we have a linear acceleration ramp followed by a cruising distance. Then, the planner decelerates for cornering or something similar to respect jerk limits. Next is accelerating to cruising speed again and decelerating to 0 as this is the last move.
Note that the planner ties final speed of segment 1 and the start speed of segment 2 together. In reality, there can be a small difference due to numerical rounding and the step resolution, but it's nearly perfect.

But the problem is, that's only valid for the 3-dimensional print head move (X, Y, Z). It's physicaly not possible to link the E axis in the same nice way without coming to a full stop, except we have only one extrusion width within the whole print. While this was maybe true during the beginning of 3D printing, nowadays every slicer can use different extrusion widths, for example thin lines for perimeters and thick solid ones for infill. Even variable gap fill, like when you want to fill the tip of a triangle, is done.
As a result, the extruder speed sometimes jumps between motion segments. Imagine the example of the triangle tip again. If we approach the tip from the triangle center, the print head moves along a straight line with a constant speed. But at points defined by the resolution of the slicer, the extrusion width gets reduced further and further. While we have a constant X, Y motion, the E axis reduces it's speed at the segment junction without deceleration.
As extrusion speeds are low during print moves, this speed changes are well below the extruder jerk limits in all cases I have seen so far, and they will never cause the printer to loose steps - well, as long as we don't use a nozzle pressure correction like LIN_ADVANCE..

With LIN_ADVANCE, needed advance extra steps are calculated with "extra_steps = extruder_velocity * some_factor", therefore if we have a sudden speed change like due to the example above, this will result in an amplified sudden extruder move as LIN_ADVANCE wants to adjust the preload step amount.
Up to now, it's my "dogma" that every printer who runs LIN_ADVANCE has to have the capability to do that.

And it becomes even more "funny" due to the resolution of the extruder stepper. The following example will clarify what I mean.
The right section of the sketch below shows the line path that gets printed in our example. It's a straight line, followed by a 90° arc and again a straight line. In the graph on the left, we are only watching the marked section of the line path, so we exclude the acceleration to cruising speed and the deceleration to full stop. The XY jerk setting is high enough, so the planner will not slow down between the arc segments:
Jitter due to e_step resolution
When we have a look at the graph from left to right, we have a nice cruising (extruder) speed line first. As soon as the arc starts, we see some jitter: Some segments are printed at a slightly higher speed than the others. No one is an accelerated move. A stable extruder speed is not reached until the line starts again.
What's going on? Let's have a look into one of the arc gcode segments. While it has a length of 0.583mm, it only needs 0.00772mm of extrusion (0.2mm layer height, 0.48mm line width and 3mm filament). My printer uses 100.5steps/mm in X and Y and 801steps/mm for the extruder, so in step unit this means:
print move length = 58.592 steps
extruded length = 6.184 steps
As the printer can't do fractions of a step, the planner will cut the decimal places. But the fraction isn't lost. If the decimal places accumulates to a full step, it will be executed in one of the next segments. This "rounding" leads to the jitter around the nominal cruising speed. In real numbers, during this arc the extruder speed in terms of steps per second has a variation between the fastest speed and the lowest of impressive 20%!
While this is not even noticeable in normal printings, it jerks around the extruder with LIN_ADVANCE just as the triangle gap fill example above did.
Note that my demonstration arc with 0.583mm segment length is not even a very high resolution one. With increasing resolution, this problem gets worse as we might reach a point where some segments have no extruder moves at all and the extruder does one step in segment 1, no step in segment 2, one in segment 3 and so on.

The way how LIN_ADVANCE calculates the extruder speed as a work around

In fact LIN_ADVANCE as it's implemented today isn't using the real, physical extruder steps/s speed to calculate the needed advance steps because the speed jumps explained above would lead to an extruder jumping back and forth like crazy, maybe even losing steps due to LIN_ADVANCE wants to adopt the nozzle pressure in every single stepper ISR loop. Instead, it calculates the ratio between length of extruded filament and distance traveled based on the numbers given from the gcode (see planner.cpp, near the end of Planner::_buffer_line).

block->abs_adv_steps_multiplier8 = lround(
        extruder_advance_k
        * (UNEAR_ZERO(advance_ed_ratio) ? de_float / mm_D_float : advance_ed_ratio) // Use the fixed ratio, if set
        * (block->nominal_speed / (float)block->nominal_rate)
        * axis_steps_per_mm[E_AXIS_N] * 256.0
      );

Inside the step execution code, it then uses this ratio together with the ratio from nominal speed and nominal rate to recalculate the extruder speed from the current step rate (see stepper.cpp, inside the main stepper ISR). This way, LIN_ADVANCE has more something like the intended stepper speed in mind and not the jumping real extruder speed.

current_estep_rate[TOOL_E_INDEX] = ((uint32_t)acc_step_rate * current_block->abs_adv_steps_multiplier8) >> 17;

While this solves the jitter problem in arcs, it's not a solution for variable gap fill which will still lead to speed jumps!

Goals for a LIN_ADVANCE v2

My goals for a version two are as follows:

  • Use the real extruder step rate for the calculation to get rid of the need for the gcode float numbers. This will also make LIN_ADVANCE usable for kinematic printers.
  • Find a way to smooth out the extruder speed from one segment to the next one. Sudden speed changes may happen in reality, but LIN_ADVANCE isn't allowed to calculate with them to avoid extruder jumps. This should solve the issues with bowden printers.
  • Maybe in a second step, but highly needed: Implement a way to limit the resulting extruder speed due to advance steps executed. While this will lead to not-optimal print results, it's better to execute some extra steps later than to have the extruder skipping a step on a bowden printer which may need extremly high K values.

Current status of my v2 ideas and implementation

As @thinkyhead pointed out, the actual extrusion speed can always be calculated by step_rate * block->steps[E_AXIS] / block->step_event_count. Beside the before described fact that the calculated speed will be off in short print segments, this works fine and requires even much less cycle-consuming math operations.
The second point, finding a smooth way from one extruder speed to the next, is the real challenge. Any help is welcome.
Up to now I have created a working draft version, but it's not handling all real world cases and I even met my good old friend again, called lack of calculation power on the ATMega. I will not write down every idea I had in the last days which wasn't working in the end, instead here are two possibly working ones for you to give a start point for thinking:

Smoothing the extruder speed, as implemented in my local branch

To avoid junction extruder speed jumps, only use the final extruder speed of the last segment as a reference. My first idea was to even say the extruder speed can only change if segment has an acceleration or deceleration part, therefore this statement changes to: Keep track of the last extruder speed that we had at the end of the last acceleration or deceleration. This way, we can avoid two problems:

  • Jumping extruder speeds at segment junctions are not longer a problem as we are not looking at the speed at segment start at all.
  • Due to the fact we only watch on extruder speeds at acceleration or deceleration, short segment with jumping speeds as in the arc example above are not longer a problem. As they don't have accel / decel parts LIN_ADVANCE would ignore them, as if the extruder speed would be constant.

To avoid writing acceleration or deceleration 100 times more, in the next part I will only use acceleration. Deceleration works in the same way:
For each acceleration ramp we can now calculate an extruder acceleration so we reach final extruder speed at the end of acceleration starting from extruder speed at end of last deceleration within the time we have for that acceleration section given by the planner. In a graph, this would mean we take the last extruder speed from segment before and draw a straight line to the extruder speed at the end of the acceleration part, ignoring a possible different extruder speed at the actual segment start.

Within the stepper ISR, we can now use that extruder acceleration to calculate the smoothened extruder speed for every loop we have and from that calculate the needed advance steps.

Easy at first glance, but problematic if you think about all the possible details:

  • As we are only watching acceleration / deceleration parts (to avoid unnecessary adjustments within arcs), we will also miss intentionaly extruder speed changes as they happen during our variable gap fill example from above. They also have no acceleration or deceleration part but will change the extruder speed in a significant way.
  • The most intresting event happens when we have two print lines in L-shape, where the first has a normal extrusion width (high extrusion speed) and the second one has a low width (slow extrusion speed). While the planner will decelerate for cornering and accelerate again after that, in this acceleration of the thin line the smoothened extruder speed may actualy result in deceleration.
    As acceleration and deceleration are handled slightly different in the code for two reasons
  • We use mostly unsigned integer values, meaning a negativ acceleration isn't existing
  • An acceleration is calculated initial_step_rate + acceleration_rate * acceleration_time, while a deceleration is calculated as cruising_step_rate - acceleration_rate * acceleration_time
    this is something which has to be handled with care while coding.

To handle variable extrusion widths, it would be possible to roll back watching extrusion speeds at end of accelerations / decelerations only, resulting in watching extrusion speed at end of each segment again. This will lead to some unnecessary extruder moves during arcs, but they should be smooth enough (hopefuly).
Furthermore if there is no acceleration part at the beginning of a segment, we would have to adjust the advance step pretension during the cruising part. Should be possible, but something to keep in mind.

Another idea using variable block->steps[E_AXIS]

As I'm already seeing some slow down under certain circumstances, I'm thinking about a way to get rid of all or most of the extra calculations due to LIN_ADVANCE. One might be to alter the executed stepper speed during acceleration and deceleration by overwriting block->steps[E_AXIS] value. But up to now, I'm not sure if this would result in the wanted effect, at least it will create a bunch of new challanges. Some of my points where this idea seems to stall:

  • During deceleration, the extruder speed can become negative (resulting in a retraction movement). By altering block->steps[E_AXIS], the extruder speed will always stay positive.
  • While I see a relation between needed extruder speed offset, extrusion speed and k factor, up to now I have no equation to get the needed speed without try and error (which I used for Excel demonstrations).
  • If there is no acceleration / deceleration phase, there is no way to adjust the pretension for LIN_ADVANCE for example for gap fill moves.
  • Even if there is an acceleration or deceleration phase, as stated in the example with the L-shaped print moves with two extrusion widths, we might have decelerations within acceleration parts and vice versa.
  • Both above points would need severe changes to the planner and / or stepper step execution code.

If you got up to this point, thanks a lot for your patience! If you even understood everything that's amazing, if not and you are still intrested just ask questions.
Finaly, every proposal is welcome!

@mylife4aiurr
Copy link

Just wanna express support. And hope to see farther improvements in lin_advance. Its really has helped over all print quality. I think its a great improvement.
(Had a much higher k factor for my delta in 1.1.7 but it did work, once calibrated. Hope to see it back for delta's in the future)

@Sineos
Copy link

Sineos commented Jan 5, 2018

Ok, I will by no means pretend that I have understood everything but anyway, thanks a lot for this extensive write up.
For me the topic sounds a bit like a oil or gas filled damper. They simplified have following characteristics:

  • The total force is the sum of the forces of the spring and the damper
  • Spring force = Spring constant (k) * Displacement (X)
  • Damper force = damping constant (d) * Velocity (v)

In such a system the damper force goes towards 0 for low velocity and for high velocities may even kind of block the system. Solving this is some differential equation tho.

But as an analogy to the topic here, it may be a way to split the k-factor in two components. Maybe a constant one similar to the spring force (i.e. number of steps) and some portion depending on the acceleration.

@Sebastianv650
Copy link
Contributor Author

I don't think we need another factor, I don't see a damper as you described it in our extruder system.
The force needed to push the filament through the nozzle is linear proportional to the extrusion speed, therefore we need twice the force when we double the extrusion speed. While I wasn't sure if this statement is true for a long time in the past, I'm now "99.9%" sure it's true due to the following points:

  • I did numerical flow simulations which gave me a linear result.
  • I found measurements from a guy on the internet who has attached a scale gauge onto his extruder assembly to measure the extrusion force. His results also show something linear.
  • LIN_ADVANCE, built with this assumption in mind, produces quite perfect results on my printers which shouldn't be if there would be a highly non-linear correlation.

Therefore, the spring model to calculate the needed filament compression which will result in the needed extrusion force seems to be valid.

@psavva
Copy link
Contributor

psavva commented Jan 5, 2018

Any chance to have Cura's variable extrusion widths mixed in there?

@iosonopersia
Copy link

Hi everyone. I think that the spring model is simple and effective enough. I believe introducing a more complex model won't give any appreciable improvement, while it would slow down computation.

I didn't understand why actually LINEAR_ADVANCE is not supported by non-cartesian printers. As far as I know, kinematics machines split every movement in many little movements which are approximately linear. We could calculate the real length of those tiny movements by applying Pythagorean theorem to their start and end positions. Am I wrong?

I really would like to help, but I feel I didn't understand 100% the problem.

Bye

@Sineos
Copy link

Sineos commented Jan 5, 2018

@Sebastianv650
Copy link
Contributor Author

Any chance to have Cura's variable extrusion widths mixed in there?

@psavva well, variable extrusion widths are basicaly supported by LIN_ADVANCE so there is no need to think about Cura in special. What was a problem with Cura in the past wasn't variable extrusion widths but wrong ones, spikes at incredible magnitude that occur randomly. So that's something up to Cura developers, I guess it's already fixed as I had a Cura gcode some times ago and it was fine.
Beside that, v2 will work nicer with variable widths as it tries to smooth out speed jumps - if I get it to work.

I didn't understand why actually LINEAR_ADVANCE is not supported by non-cartesian printers.

@iosonopersia in fact I wasn't thinking about that in detail. @thinkyhead made that statement a short while ago during a change we discussed for 1.1.7. As he is way better in coding and knowing the Marlin details, I just accepted it. And it makes sense due to the way I calculate the extrusion speed and how I'm checking for print moves. I also wrote about that in the long text.
But feel free to try it, just remove the sanity check which prevents you from building Marlin in this case. @mylife4aiurr seems to had it working in his delta also.

@Sineos yes, that's the one I was reffering to when I wrote about the extrusion force measurement :)

@mylife4aiurr
Copy link

mylife4aiurr commented Jan 6, 2018

But feel free to try it, just remove the sanity check which prevents you from building Marlin in this case. @mylife4aiurr seems to had it working in his delta also.

Have 4 printers (mk3 on the way when they get powdered metal pei sheets in). But the cheap Chinese Delta was my first. So between delta auto calibration, unified bed leveling, linear advance and skew correction it has never printed this well. Print quality is truly amazing. (I'm afraid to install the tmc2130 drivers I bought for it because its super loud but I dont wanna mess up a good thing)

Linear Advance made corners sharper and top layers better looking, less retraction necessary too. Plus i could bump up speeds. I'll have to try and figure how to disable the sanity check for delta's concerning linear advance.

@iosonopersia
Copy link

iosonopersia commented Jan 6, 2018

@mylife4aiurr , you simply need to find in sanitycheck.h these lines and delete them:

// Linear Advance
#if ENABLED(LIN_ADVANCE) && !IS_CARTESIAN
  #error "DEPENDENCY ERROR: Sorry! LIN_ADVANCE is only compatible with Cartesian."
#endif

If LIN_ADVANCE V1 works well with non cartesian machines, that would be one less problem to solve... We need someone to test it on a Core machine too.

@CCS86
Copy link

CCS86 commented Jan 6, 2018

Awesome @Sebastianv650, I'm glad to hear that you are still fired up to develop advance!

I won't likely be much use in the actual coding changes, but have a solid grasp on the physics involved and can help work through conceptual stuff. In addition to testing on my well-tuned bowden printer.

It sure seems like an overhaul of the actual motion planner, which did away with jerk (at least in its current form), instead using a "maximum path deviation" parameter to allow a smoother path, which did not "hit" every coordinate exactly, better leveraging linear acceleration; would solve many of the advance challenges (among others). Easier said than done! ;)

Is the current version of LIN ADVANCE bounded by the E max acceleration setting, or is it operating outside of its control?

Regarding the mention of dampers: I agree that there isn't a useful place for damping in the physical model of the advance engine. The linear spring model will work very well to link flow rate with head speed. But, perhaps adding a 'damping' to the addition/subtraction of advance E steps would help smooth out the advance moves. This kind of ties back in to bounding the moves with max E acceleration.

It might be even better to look ahead and filter / average the inputs to the advance engine. This could help on the arc jitter situation you described. I think this could also help in the issues I see with the current LIN ADVANCE. Even with modest K values, well below what I need to truly equalize flow, the extruder is pretty spastic and starts to skip steps. For example, with simple "line" infill from Cura:

image

I find that this gives a better printed result, compared to "zig zag" which connects passes with a print move (and inadvertently over-extrudes these direction changes). "Line" infill uses small rapid moves to move between passes. Even though each of these moves is executed in a small fraction of a second (0.002 s for one that I calculated), advance seems to look at them as extrusion rate = 0; making corrections for the start and stop of every pass.

As I look closer, there is an additional move that Cura makes, which could be contributing to (some of) my issues with advance, called "infill wipe". It is just a small G1 move, without extrusion, in the same direction as the infill pass. It is meant to give better adhesion between infill and walls, which it does well. It's possible that this is what is tricking advance into becoming active where it is not needed, in this case:

image

The same principle applies though. There is a realistic time required to change pressure at the nozzle through advance moves. Reacting to pressure changes in the code which take less than this amount of time to execute, is not productive, and contributes to issues. I understand that the implementation may not be simple. Some moves are physically very long, while others are incredibly short. So you can't just look-ahead some number of moves, but must instead look at distances and speeds to make time based decisions.

@Sineos
Copy link

Sineos commented Jan 6, 2018

Regarding the mention of dampers: I agree that there isn't a useful place for damping in the physical model of the advance engine. The linear spring model will work very well to link flow rate with head speed. But, perhaps adding a 'damping' to the addition/subtraction of advance E steps would help smooth out the advance moves. This kind of ties back in to bounding the moves with max E acceleration.

Maybe the analogy was badly chosen and I couldn't bring over my point. As far as I understood:

  • Usually you have a direct proportional relationship between force / extrusion / acceleration
  • Certain gcode constellations disturb this, e.g. arcs, width changes, slicer infill optimizations etc.

The first one is already being represented by the k-factor while the second one actually might change E steps without any acceleration or deceleration being involved.
So the algorithm would have to look ahead and realize "hey, something is changing steps without any head speed changes so I need to adapt". This is what I meant with the dampening factor because it would kind of work against the previously calculated acceleration correction.

yes, that's the one I was reffering to when I wrote about the extrusion force measurement

I wonder how these measurements would look like with LIN_ADVANCE

@thinkyhead thinkyhead added T: Design Concept Technical ideas about ways and methods. T: Development Makefiles, PlatformIO, Python scripts, etc. labels Jan 7, 2018
@thinkyhead
Copy link
Member

@Sebastianv650 — I just reading the OP so here are my first random thoughts…

Generally, when the slicer outputs G-code, I assume that it basically just outputs some linear motion and then a proportional amount of extrusion to fill up the line. So for each individual segment you can always calculate the extrusion-to-length ratio, and when wall widths are all the same this value shouldn't change. But if the slicer is using variable wall thickness, then this should manifest as an obvious change in the E-to-length ratio.

Since this can be figured ahead of segments, perhaps this changing ratio can be utilized as part of the trapezoid generation and block-joining procedure to ensure that the linear advance flow is slightly increased or reduced ahead of the block where it changes.

@Sebastianv650
Copy link
Contributor Author

Sebastianv650 commented Jan 7, 2018

Is the current version of LIN ADVANCE bounded by the E max acceleration setting, or is it operating outside of its control?

At the moment it's ignoring every limit. That's due to the fact I had no idea how to limit the esteps easily (=with acceptable calculation power) on the one side and on the other side it should never hit a limit as long as we have a smooth extrusion speed path.

As I look closer, there is an additional move that Cura makes, which could be contributing to (some of) my issues with advance, called "infill wipe".

Non-extrusion moves are not a problem as they don't alter the extruder pressure.

@thinkyhead this might be possible and something to keep in mind. At the moment I'm stuck some steps before that.

So what's my status:
I think I have a quite fast and working way of calculating the needed advance steps now, including some smoothing by ignoring junction speed jumps due to extrusion width changes. But up to now I'm not testing with variable extrusion widths at all.

All my different approaches share one behaviour which realy puzzled me: As soon as the code works great for print moves with some significant length, meaning each move will take at least some fractions of a second, I start a simple test circle. Nothing with incredible high resolution, but short segments. And in all cases, it starts rattling like crazy.
Therefore I stepped back once more, disabling LIN_ADVANCE, and created a test code only to dump some (extruder) speed values.

As long as the block buffer isn't drained the speeds are straight as you would expect them.
As soon as I give it some more load so the buffer drains from time to time, the speeds go absolutely crazy. Have a look at the speed graph, we see here extruder speed along step loops:

tmp

I circled some examples. Two kinds of strange things happens here, maybe due to the same underlying thing, or maybe not:

  • The second-from-left and rightmost effect is quite easy to explain: The buffer drains to 0, the deceleration we see here is within the last block. Therefore the planner decelerates to MINIMUM_PLANNER_SPEED. But the next block is then started instantly at a quite high speed which even seems to exceed XY jerk speed by some amount. I wasn't able to understand why up to now. As we always want to connect exit and entry speeds, the next segment should start at MINIMUM_PLANNER_SPEED and accelerating from there. Clearly, the planner does something different.
  • The first and third circle from left are examples for blocks where the exit / entry speeds are not linked together, but the buffer isn't empty (but very likely not full) at this point. Therefore the speed inside this block jumps to some high speed and down again at it's end without acceleration.

I excluded two possible reasons that came into my mind:

  • It's not due to the stepper ISR calling blocks with not jet calculated trapezoids. I added a blocking check so only blocks can be executed with trapezoid calculated, no change.
  • It's also looking this way with Marlin 1.1, so it's not a problem with some recent changes.
  • As said before, this test was done with disabled LIN_ADVANCE, just checking for speeds.

I hope @thinkyhead might bring some light into this, as this part of the motion planner with forward / reverse pass is still a "greay box" for me. I understand what they do in theory, but not exactly what the code is doing.

Edit: Please ignore the stroke through part for the moment, investigation is ongoing and the error might be on my side!

@Sebastianv650
Copy link
Contributor Author

Sebastianv650 commented Jan 7, 2018

Sorted out some bugs, increased resolution of speed calculations etc.
The spike after each buffer drain is the remaining "problem". I know it's by intention that a move starts at jerk speed, but I'm no fan of it. I think I will try to change that..
I also think that these start speeds are way above jerk setting, but I'm not sure how the planner handles jerk speed when the move happens in X and Y direction. If it's only one axis involed it's easy: Start speed = jerk speed.

Here is how the extruder speed graph over step loop looks like now. No wired jumps without accel. any more, except the ones when starting from an empty buffer:
tmp

@Beherith
Copy link

Does lin advance thus benefit from a higher step per mm on the extruder, which would artificially limit speed on it as well? E.g. im running a direct extruder at 95 steps per mm, with 1/16th microstepping, but since i have tmc2130s with up to 1/256th microstepping, could i theoretically just increase the microstepping on E to get rid of the extruder jitter caused by lin advance? Also, is the K value dependant on steps per mm?

@CCS86
Copy link

CCS86 commented Jan 10, 2018

The K value should not have any dependence on steps/mm. It represents a physical spring rate of the combined compression of filament and elongation of the bowden tube.

@Sebastianv650 would have to confirm whether lin advance would benefit in any way. My gut says no.

@mylife4aiurr
Copy link

mylife4aiurr commented Jan 10, 2018

LIN_ADVANCE does not work with DELTA #7521

Why? Who tested and found No GO?
Cant use the K factor gcode generator?

Just use a thingiverse object designed to calibrate lin_advance
https://www.thingiverse.com/thing:2693748
https://www.thingiverse.com/thing:2497674

Disabled sanity check for Delta's working fine (higher K factor) but it works....

@aaulick
Copy link

aaulick commented Jan 11, 2018

Pressure changes don't just come from rounding jitter and variable width, also there is the filament width sensor to play nice with. How does filament width correction work, just adjusting extruder step count in the segment (appears identical to slight width variation per segment), or some other way?

@Sebastianv650
Copy link
Contributor Author

@Beherith K isn't dependant to steps/mm setting, at least it shouldn't. The step amount / mm on e axis is quite unimportant for LIN_ADVANCE as it's not using block step amount for speed calculation. By the way a higher espep/mm value shouldn't slow down your maximum print speed. I'm using 801/mm and my max espeed is 40mm/s - way more than any print move will ever use.

@mylife4aiurr the person in your linked issue did ;) thinkyhead also recognised it (independetly from this) in the last days. It might work to some degree, but the math behind is definitly not right for delta printers. This will be fixed in v2.

@aaulick the filament sensor works by adjusting the extruder length per block. Inside the planner it is identicaly to increasing flow rate per hand, it's combined in one factor.
In fact that's a complicated one. Technicaly, the filament width sensor will never change extruder pressure. It compensates for diameter changes, therefore it changes the extruder speed but the extruded filament speed is kept constant. So based on the filament width sensor, LIN_ADVANCE would have to ignore adaptions. But what if somebody changes the flow rate? Usualy you would do that to compensate for a faulty esteps/mm setting, so changing the rate means you realy have a higher or lower espeed. So this one would have to be covered by LIN_ADVANCE.
For real world application, I guess it's not worth investing too much time with that. If you use normal filament, your width shouldn't change more than maybe +-2%. That's nothing you will recognise in LIN_ADVANCE world, it's like adjusting the K factor +-2%. You will not see the diference.

@aaulick
Copy link

aaulick commented Jan 11, 2018

@Sebastianv650 A useful invariant for debugging is that total steps extruded between retraction moves should never be different for lin_advance enabled/disabled cases. Individual segments will have wildly different step counts in order to prepare the right pressure for starting the next segment, but the total filament in one extrusion stream starting from 0 pressure before last advance and ending at 0 pressure after last retract has to be the same number of steps, extra advance cancelled by extra retract.
Do you have some debugging sanity code to verify this and print errors when total filament pushed out is wrong? This might have caught the original bug #7521 sooner.

@Sebastianv650
Copy link
Contributor Author

That's how I tested LIN_ADVANCE and also the reason why I designed the code in stepper.cpp how it is. It makes debugging easy. But there is no "live check", you would need to add some SERIAL_ECHOs.

@aaulick
Copy link

aaulick commented Jan 12, 2018

@Sebastianv650, I did some math related to modeling the linear advance. This doesn't help at all with the problems of discontinuous extrusion width (still need some smoothing feature there to prevent discontinuities) but it lets us put a unit on the current K constant and suggests a couple ways to calibrate K for a given printer config. Please check my math, let me know if this is correctly modeling the current code that's there in 1.1.18, and point out any mistakes or bad assumptions.

I have some more work on solving the differential equation relating extrude rate decay to feed rate when the two are out-of-sync. That might be useful for smoothing the extruder motions, not sure yet. Also possibly more coming on how to transfer K calibration to different filament or different nozzle temp.

Assumptions and definitions:

  • I am using extruder steps as a unit of filament mass, so we can talk about for example oozing three steps of filament while the extruder is still. 1 step (mass) := 1 step (length) * filament cross-section area * filament cold density
  • Feed (steps) and feed rate (steps/s) refer to cold filament mass pushed into the system.
  • Extrude (steps) and extrude rate (steps/s) refer to hot filament mass leaving the nozzle
  • extra_steps is the momentary amount of filament in the system between hotend and nozzle, over and above the quantity where pressure == 0
  • extra_steps will decay over time as filament comes out unless maintained. I am calling the decay amount ooze_steps.
  • Relationship between extruder input force and extrusion rate is linear (verified by https://airtripper.com/1338/airtripper-extruder-filament-force-sensor-introduction/ )
  • All parts of the system stretch as linear springs (filament, Bowden tube, brackets holding parts together, etc.) Any slop in the feed system (extruder movement that doesn't go into pressure increase but instead to moving loose parts, bending filament into S-curves inside Bowden tube, etc) is taken up by regular retract and can be ignored by linear advance. This assumption could use some validation -- my gut says it's OK for stiff filament, questionable for flexible filaments in direct extruders (S-bends even without Bowden setup), lousy for flexible filaments in Bowden tubes.
  • Friction is negligible or linear; pressure at hotend depends only on current extra_steps and not on the rate of change of extra_steps (probably bad for flexible filament)
  • Filament comes out of hotend only due to pressure; ooze draining out because of gravity / strings dragged out by attachment are neglibible (probably bad for large nozzle e.g. volcano)

Given these assumptions, we can know:

  • The actual spring constant and the constant converting pressure to extrude rate are irrelevant. If F is extruder force and Khooke is the actual spring constant for Hooke's law such that
    (1) F = extra_steps(as length) * Khooke
    and Phi is the actual extrusion constant such that
    (2) extrusion_rate = Phi * F
    we can combine them into one constant Kcombined aka just plain K,
    (3) Kcombined = Khooke * Phi
    Existing code calls this simplified constant just plain K so K := Kcombined and
    (4) extrusion_rate(as length/s) = K * extra_steps(as length)
    or equivalently
    (5) extrusion_rate(as mass/s) = K * extra_steps(as mass)
    K as used in this code has unit 1/s, "per second".

Calibrate K with a filament force sensor using equation (5):

  1. Pick a feed rate R. Park nozzle in empty space, heat to temp, and set up a long, steady extrusion at R extruder steps/s. Wait for pressure to stabilize, then take the extruder force reading during steady extrusion.
  2. Stop extrusion, wait for oozing to stop or nearly stop (extra_steps ≈ 0). May help to cut the extrudate with scissors when it gets thin to prevent gravity pulling out extra ooze (would be extra_steps < 0).
  3. Cool hotend. I am assuming that this freezes the filament in place at the hotend, staying at extra_steps ≈ 0. This should be true even with filaments that expand/contract with temperature change (ABS) if the change in size happens by oozing in or out the nearby nozzle. This should be true even with gravity oozing out the nozzle if there is no siphoning that creates negative pressure in the hotend. If anybody can validate or dispute these assumptions please do so.
  4. Advance extruder carefully 1 step at a time (Nozzle is frozen, so this directly sets extra_steps), counting extra_steps until filament pressure sensor matches steady-state extrusion pressure at this rate.
  5. Solve equation (5) for K, K = R / extra_steps
  6. Repeat for a couple different extrusion rates and take an average. Sanity check: Experimental K values should not vary too much from each other.

Estimate K by weighing ooze using equation (5):

This way of estimating is only good if gravity does not cause your filament to ooze out of your hotend even at 0 pressure. Maybe OK for small nozzles, but if you have a volcano nozzle that oozes until the melt chamber is empty, you will only be measuring your melt chamber volume.

  1. Pick a feed rate R (steps/s). Precision will be best if R is high to maximize ooze, but not so high there is any worry of janky extruder tricks like slipping or stalling. Calculate the mass feed rate
    Mr (mass/s) = filament density (mass/volume) * step volume (volume/step) * R (steps/s)
  2. Set up a vertical divider on the print bed creating two areas A and B. You could do this by printing a razor blade holder with side supports for steadiness, and taping it to a known location on the print bed (or just leave the holder stuck to the bed after printing and insert the razor blade in-place)
  3. Park nozzle in empty space off in a corner of the print bed, just a bit higher than the divider. Heat to printing temp, feed out enough filament to get steady flow, then stop extruding with no retraction at all. Wait for ooze to stop or nearly stop (extra_steps ≈ 0). May help to cut the extrudate with scissors when it gets thin to prevent gravity pulling out extra ooze (would be extra_steps < 0). User pushes button when ooze is negligible to continue. (This warm-up filament is not used, discard it).
  4. Record ooze time T from stop feeding to user button-push.
  5. Move nozzle to empty space over area A, near the divider, and extrude for at least time T at constant R steps/s waiting for pressure to equalize. (Probably using time much shorter than T will give nearly identical results, I am doing more math to put numbers to this.)
  6. Stop extruding, move nozzle quickly over the divider to area B, and let it ooze again for time T. Sanity check: should stop oozing by T, same as in step 2 when user was timing the ooze. Divider should cut the extrudate into two piles, but if it doesn't, cut it yourself where it crosses the divider.
  7. You now have two piles of filament, A and B. Pile A weighs R * T - extra_steps. Pile C weighs extra_steps.
  8. Using formula (5) calculate K
    K = Mr * pile B weight
    Sanity check:
    Mr * T = pile A weight + pile B weight
  9. If your scale is not sensitive enough to measure pile C weight accurately, you can repeat steps 5-6 in a loop to get:
    K = Mr * pile B weight / loop count
    Sanity check:
    Mr * T = (pile A weight + pile B weight) / loop count

@Sebastianv650
Copy link
Contributor Author

You wanted to write something even longer than my first text, isn't it? :-D

  • "Assumptions and definitions" - I agree with them.
  • "Given these assumptions, we can know" - also true.
  • "Calibrate K with a filament force sensor using equation (5)"
    True in theory, but I'm not sure if it will work or be useful in reality. First this force measuring extruder will not fit on a direct drive system just due to space restrictions. Then the nozzle pressure at feed rate x in free air will be always lower than during printing because the back-pressure from the solid layer beyond is missing. That can be solved by printing a long line instead of free air extrusion. My last point is that when you add the steps in cold nozzle status, you will have a slightly different springiness than in hot state: The "free filemant length" now end at the heat brake. In hot condition, it should be somewhat longer.
  • Estimate K by weighing ooze using equation (5)
    Like the one above, and you need a good scale. While both methods might be good for experiments, the end user most likely will prefer a test pattern as existing today and just look what value works best.

But I also found a not jet tested way to determine K. I will write it down as it fits to the topic:
By chance I found out that if you extrude some filament using the Marlin LCD screen, as soon as the extrusion is done Marlin disables the extruder stepper. This means it's jumping back some degrees or mm filament as pressure is released. It should be possible to get a (rough) K value by using this.

  • Mark the filament some mm above a reference point of the extruder.
  • Print a line at test speed which will use exactly as much mm of filament as marked before. If esteps/mm calibration is done before and the extruder stepper isn't disabled as soon as the line is done, the marking should be exactly in line with the reference now.
  • If the extruder stepper is disabled just after printing the line, the filament will jump back a fraction of a mm: K = measured lentgh in steps / extrusion speed.

@BillyQuiet
Copy link

Hi,

This speaks of preload in kisslicer slicer but may possibly be giving ideas :
http://www.kisslicertalk.com/viewtopic.php?f=5&t=2025

Yoann

@Sebastianv650
Copy link
Contributor Author

@BillyQuiet maybe you can give me a short hint what they are talking about. While I understand it's about preloading, which is nothing else than LIN_ADVANCE does, I have no clue how Kisslicer wants to do this in gcode. The gcode as defined in Marlin only allowes synchronised moves, meaning a linear movement between all 4 axis. With this basic moves, there is no way of incorporating a smooth preload.
Is this related to a special firmware / printer?

@BillyQuiet
Copy link

@Sebastianv650
Sorry but I can not help more than that, and I do not speak English well ^^
I'm just trying to help a little bit by sharing the information.
I think it is a function close to linear advance but on the side of the slicer, with the same difficulty to achieve perfect result for everyone.
This is not related to a special firmware or printer.

@aaulick
Copy link

aaulick commented Jan 15, 2018

@Sebastianv650 @BillyQuiet
Looks like the Kisslicer is implementing acceleration ramps in the gcode output by splitting linear moves into lots of smaller pieces with speed ramping up/down?

@Beefeater on the kisslicer forum thread is characterizing the actual flow rates at constant extruder velocity as an exponential system with time constant tau.

Looks like Beefeater has actually taken some relevant math courses (unlike me) as their terminology is matching the wikipedia page... Their tau is the same info as our K (tau = 1/K) and it looks like they have a wizard somewhere similar to our calibration generator to estimate the value. They are assuming the whole extruder system is rigid and calculating Tau from viscoelasticity of the filament only, which their wizard is nominally measuring. But I think in the end it comes to the same thing -- both our wizards are doing an experiment to measure total stretch in the system by comparing ooze/blob sizes at different extrusion rates.

Lots of detailed analysis in that page which are relevant to us, some main bits which are relevant to Marlin:

  • The Wizard will give a better measurement if it measures ooze over the first few seconds instead of 2 minutes. ... But as a general matter, a measurement of an exponential process with time constant tau is most accurate when made over a time on the order of a few tau.
    -- We are at least roughly doing this already, in that we use seconds not minutes to test each K val. Not sure what kind of wizard they have that can run for minutes unless they are weighing ooze. Actionable refinement suggested by Beefeater is to have the K configurator template calculate fast printer speed and fast speed length that vary with K, instead of having the user specify one value for all K, so that the duration of fast print is "a few" tau. Assuming "a few" is 5, that gives like 1/6s fast print time for testing at K=30. The idea is to be sure we are measuring ooze due to spring tension in the system (quick response which we control) and not ooze due to melt zone slowly inching up the filament at rest (slow response which we don't control, acts as noise in the measurement).
    Edit: For small direct drive printers we are already at "a few" tau. But for large, high-K printers this would be a change; for K=300/s (Bowden), fast print = 40mm/s, fast print length = 10cm, test time is 2.5s, tau is .003s, that's 833 tau, definitely more than "a few". Don't know if it would actually be a meaningful change....
  • Even with synchronization corrected, the (parabolic?) ramp functions implemented in Kisslicer are not the best ones to use because they are sensitive to mis-estimation of viscoelasticity. I found other ramp functions that are less sensitive. The best performer, believe it or not, is a simple constant.
    -- I read this as, "parabolic acceleration curve is not great because it exaggerates errors due to miscalibrated K, simple constant acceleration is less sensitive to error" which we are already doing in Marlin.
  • The best turned out to be the one that does not reverse the extruder at all, but continues forward at low speed. [lots of detail about exactly how summarized below]
    -- Beefeater is suggesting in their analysis that we can best minimize errors from K-misestimation by using this acceleration strategy at the end of a path:
    • Pick a flow rate H that's slow enough to ignore linear advance
    • Near the end of a path, stop extrusion early and set extruder rate for H/2
    • actual flow rate decays exponentially to H according to log formula, plan the movement so that printhead reaches the end of the path at the same time
    • when it gets there, take up remaining pressure with normal quick retract
      -- I was actually going to make almost the same recommendation just to reduce extruder movement on width change (but not for coming to a stop): quit extruding early and plan the timing so we reach actual desired new width and segment end at the same time. Seems like a solid strategy to me!
      Edit: Although, I'm really confused why Beefeater would extrude at a positive slow rate instead of 0 while doing the oozedown at path end.

@aaulick
Copy link

aaulick commented Jan 15, 2018

By my calculation, time to ooze down from one real extrude rate to another with stopped extruder is:
(6) log(initial_extrusion_rate/end_extrusion_rate)/K
Generally to go from one extrude rate to another with any constant extruder velocity feed_rate is
(7) log(initial_extrusion_rate/(end_extrusion_rate - feed_rate) - feed_rate/(end_extrusion_rate - feed_rate))/K

Using equation (5) we can track extrusion_rate as extra_steps (current linear advance) instead, which may fit better in the code.

Using either one of these facts will break the invariant that we always extrude exactly the correct total stepcount of filament -- we can still count the change as extra_steps and track exactly how much filament left the nozzle, but it will be subject to floating point error now.

All these log functions are very expensive, but we can cache or precompute them as we will be seeing the same extrusion rates over and over again in the gcode.

@Sebastianv650
Copy link
Contributor Author

OK so I would say Kisslicer is more or less guessing. While the math can be fine, the slicer just hasn't the needed informations. All we have in gcode is a maximum execution speed. No real achieved speed, no junction speeds, no information about planner buffer state.
Don't get me wrong, a good guess can work pretty fine. But I saw Slic3r failing with some tries to get a slicer side pressure correction to work. It's just not the right place to do it in my opinion.

@aaulick
Copy link

aaulick commented Jan 15, 2018

Agreed, firmware is better to put something so tied-in to the physics. Lots of complaints in the slicer thread that they never know just how the firmware does acceleration. I think we can benefit from Beefeater's analysis of the math though. Picking an acceleration profile to minimize error in K is good and not something I thought to try.

@aaulick
Copy link

aaulick commented Jan 21, 2018

@Sebastianv650 , any more on this?

You have said already that you have a solution in mind for resolving jitter.
The change in width is amenable to a solution inserting a minimum width ramp at the discontinuity where you:

  1. solve (7) for segment time, using some feed rate value, max feed, max retract, or zero:
    (7) equalization_time = log(initial_extrusion_rate/(end_extrusion_rate - feed_rate_e) - feed_rate_e/(end_extrusion_rate - feed_rate))/K
  2. compute the distance traveled in that equalization time as a weighted average of old segment velocity so that the halfway point in equalization time occurs at the segment boundary
  3. shave the segments appropriately to add two new equalization segments covering the equalization distance with same old xyz velocity and new e velocity.

Is this a workable plan for the discontinuous width problem?

@Sebastianv650
Copy link
Contributor Author

Sebastianv650 commented Jan 21, 2018

I paused this due to research and work on the planner and stepper, as a perfectly working planner and a deep understanding of both planner and stepper is needed for a LIN_ADVANCE integration.
I'm now at a stage where I would state I'm understanding planner and stepper procedure and math almost to 100%. This knowledge led to some disillusion as there is not a lot of room to play:

  • We don't know the final speed after an acceleration or deceleration due to iteration effects. We also can't tell the time acceleration / deceleration will need. This renders some initial ideas partialy described in this thread impossible.
  • For everything that happens inside the stepper ISR, we have to keep math as basic as possible. With the low powered boards we use, we can't allow the loop to become slower any more. To say it clear, we can only use +, -, * and bitshift operations. Forget about divisions or even square roots, they are way too slow.
  • Same is true for the planner. It's basicaly too slow even as it is today. Logs and sqr is no good idea there also.

One positive thing about all my research is that I also recognised something basicaly obvious, that as long as the extruder acceleration is constant, we just need to overlay the extruder speed with a fixed speed offset for advance during acceleration and deceleration. That might be helpful for a faster implementation, but I'm not realy sure because for the stepper we need time intervalls, so finding an implementation that makes use of adding a speed offset is not available now. With this, it would be also easy to prevent the printer from loosing steps: All we have to make sure is that the speed offset is not bigger then extruder jerk speed..

So I think I have to adjust my goal "a bit":

  • Make LIN_ADVANCE compatible to kinematic printers.
  • Don't slow down execution speed even further, maybe make it a bit faster.
  • Respect extruder jerk speed at block junctions / find a way to tell the user when K is too high for this printer and react to this. Maybe just by setting K=0 until reset by the user. I'm afraid this might result in limitations for bowden users, but I can't change reality. Better than having issue threads why bowden printers do strange things with LIN_ADVANCE.

@CCS86
Copy link

CCS86 commented Jan 21, 2018

Any thoughts on a way to filter LIN_ADVANCE response in the time domain? If there was a lightweight way to identify the duration of a new extruder speed, you could avoid unnecessary corrections.

@aaulick
Copy link

aaulick commented Jan 22, 2018

@CCS86 I don't know if it's even true that we can safely ignore short-duration changes in speed. I've been looking at the output of Slic3r (1.38.5 Prusa) on one model, and it's putting little squirts of fill in a variety of different tiny thicknesses to fill small holes in my thinnish-wall model.

@Sebastianv650 the existing linear math works fine for constant extrusions, right? All the funny different width stuff seems to come in the fill, where it's much harder to do right with odd-size fill, but also we care less about small blobs.

Can we make an M-code for the slicer to tell us when we're doing fill, and with help from slicers that uptake this idea alternate between LIN_ADVANCE for perimeters and extra retract for fill?

@Sebastianv650
Copy link
Contributor Author

Any thoughts on a way to filter LIN_ADVANCE response in the time domain? If there was a lightweight way to identify the duration of a new extruder speed, you could avoid unnecessary corrections.

I'm also thinking that's not a good way and it solves the problem only in a small area of all possible combinations. If the extruder is basicaly able to go from pressure release speed to pressure adding speed without skipping, it can do that also during short blocks. Might sound bad on geared extruders, but it will to it's job.

@Sebastianv650 the existing linear math works fine for constant extrusions, right? All the funny different width stuff seems to come in the fill, where it's much harder to do right with odd-size fill, but also we care less about small blobs.

That's true. My hope is we don't need another M code by comparing to jerk speed. If we check that at the first step of a new block and it's OK, it's very likely OK for the complete block. So we can avoid rechecking again each loop.

Time to get another branch and start once more.

@Sineos
Copy link

Sineos commented Jan 22, 2018

Does it make sense to look at #8348, which might provide a smoother acceleration transition?

The code seems to be already there: https://github.com/MarlinFirmware/Marlin/blob/bugfix-1.1.x/Marlin/planner.cpp#L1212-L1259 though with my limited knowledge I could not get something useful from it.

@CCS86
Copy link

CCS86 commented Jan 22, 2018

On the time filtering:

Take Cura's normal method of infill, which functionally works quite well:

  1. Straight line infill pass
  2. Overshoot move to connect infill well to perimeter (G1 move without extrusion)
  3. Very short rapid move to position for the next infill pass

1: G1 F3000 X151.007 Y95.815 E660.40405
2: G1 X151.082 Y95.89
3: G0 F11400 X151.007 Y95.206

LIN_ADVANCE seems to see the flow rate as zero between these passes, but that does not accurately reflect reality. The overshoot move takes around 0.002 seconds to execute. I'm not sure how long the rapid move takes with acceleration, but it is also extremely short.

I think it is counter productive to use advance here. I don't think it will provide a functional benefit to the print, but will beat up the filament at the drive gear (like excessive retracts can), add heat to the extruder motor, noise, etc. Long and narrow areas of this infill can contain a huge number of these successive reversals.

If advance even used an oversimplified calculation to look ahead (even a few moves), see that the "zero" extrusion rate will be over in milliseconds, then back to higher flow rate, it could defer any correction.

@Sebastianv650
Copy link
Contributor Author

@Sineos it's not important how jerk is calculated for LIN_ADVANCE. Only thing that would be helpful is if we would know the max. and final speeds from a block. Junctions share the identical end/start speed and while the planner does this, the way how the stepper loop is calculating it's way along the trapezoid leads to never-reached final or max. speeds especialy at lower step rates.
Simple example: K at a fixed acceleration means a fixed extruder speed delta. So if this speed delta is is 10 and the actual final extruder speed is 2, the absolute final speed will be -8. The next block starts at final speed of last block, 2. But for acceleration, the speed delta has to be added this time: 2+10=12. So the extruder has to jerk from -8 to 12, which requires it to have a working jerk value of 10. That's the hard thing a printer with advance has to do at every deceleration - acceleration junction. That's why there is some rattling on arcs with segments where jerk speed forces the planner to accelerate and decelerate for each single one.

@CCS86 So your proposed solution would be to ignore the slowdown at the end of the infill line and keep the filament pressure, so we can also ignore the next acceleration part from next infill line.
Personaly, I wouldn't like that because it would mean I need more top solid infill layers and even another perimeter loop to prevent the blob from beeing seen in the final print.
And it's a very Cura-specific filter. Slic3r for example keeps its infill lines connected so from a planners point of view infill is not different from perimeters. If some filter is needed (which I'm not sure at all), I would prefer general ones.

@Sineos
Copy link

Sineos commented Jan 23, 2018

@Sebastianv650 Thanks for the explanations and insights. Appreciated.

@Itox001
Copy link

Itox001 commented Jan 24, 2018

Sometimes the K needed for bowden systems is above the physical limit of the extruder assembly, and in this cases perhaps a more rudimentary form of pressure control could be used, which should be much more simple to program and while not giving the full advantages of a proper physically correct pressure control, could give quite decent results in systems where lin_advance can't be implemented.

My idea is a form of adaptive "coast at end" (a feature that stops extruding some distance before a line ends to relieve the pressure in the extruder before starting the next move, for those who don't know), like the one in simplify 3d, but smarter. The difference would be that instead of having a fixed value for the coast, it could be adapted depending on the delta speed. For example, if you were printing an inner perimeter at 60 mm/s and then got to the outside perimeter at 30 mm/s, the delta speed would be 30 mm/s, which could mean (for example) a coast of 0.3 mm just before the speed change. If you were printing at 60 mm/s and then came to a stop (0 mm/s) the delta speed would be 60 mm/s, which could be a 0.6 mm coast. The coast amount would be controlled by a single constant (which would be 0.01 in this example).

This approach I believe could give good results, because if I understood correctly from the discussion above, "The force needed to push the filament through the nozzle is linear proportional to the extrusion speed", which suits well the proportional coast to delta speed I described above.

Hope the coding/printing gurus can get something useful from this idea. Cheers!

@Sebastianv650
Copy link
Contributor Author

@Itox001 this approach would not always work as expected. When I understand it correctly, "at end" means a move followed by a non-extrusion move (travel, z jump, etc). The problem is that in some situations Marlin will not see the end until it's too late:

  • Working situation: A gcode segment is long enough so all or most of deceleration fits into it. With a block buffer of 16, this means the deceleration length is not alowed to go over more than 14 blocks as the first block is already in execution and the last one is the travel move. In this case the planner can go over all blocks in the buffer in reverse order and find a place for starting extrusion cutoff.
  • Not working: We are decelerating along an arc or circle. In this case, the segment length will be very small. While the planner always expects the last block to end at near-zero speed, this doesn't mean that there is a line end at its end. So Marlin would start decelerating anyway, but without cutting off the extruder. Then, a line end may be indicated at a fraction of the needed cutoff length away. Even if Marlin will now stop the extrusion, you will not even notice it because it's just too late.

With a hughe buffer, which is not possible on the ATMega, it should be possible to implement such a smart coast at end. But it wouldn't be a pressure advance feature anyway, as it's only bleeding pressure away, never building it up.

@Itox001
Copy link

Itox001 commented Jan 24, 2018

Ah, I see. The difference with the simplify 3d implementation would be that the coast would not only be at the end of lines, but rather on every deceleration, so marlin wouldn't need to know if a line is ending, only that the print head is slowing down in order to start coasting. If I understand correctly, on the advanced configuration file on marlin there's a constant called MIN_STEPS_PER_SEGMENT which is 6 by default. This gives us a lower limit on how far ahead we can peek. With 1/16 microstepping and the most common pulley-motor config which results of 80 steps per mm, 14 6-step-blocks would be a length of 1.05 mm, which would effectively be the higher limit of how we can look ahead and how long we can coast. Reductions in the drivetrain or 400 steps per revolution motors would effectively cut this distance, but if I understand correctly, the coast that simplify 3d folks use is in the order of 0.2-0.3 mm and seems to give good results, so there would be a bit of play here.

You're right that this isn't a proper pressure control, but it seems to give very good results in simplify 3d to make z scar less visible and other parts where pressure buildup results in undesired blobbing. It doesn't build up pressure (could a reverse mechanism be applied to help with that?), but compromises have to be made in order to get a decent result in otherwise not working configs. Perhaps this feature would be better implemented in the slicer side of things?

Anyway I hope that if this isn't a viable idea, it can at least inspire someone to come up with something that can help us bowden folks with our extruder pressure problems.

@Sebastianv650
Copy link
Contributor Author

If someone wants to do some testing, there is a new version in development here: #9379

@github-actions
Copy link

github-actions bot commented Jul 5, 2020

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.

@github-actions github-actions bot locked and limited conversation to collaborators Jul 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
T: Design Concept Technical ideas about ways and methods. T: Development Makefiles, PlatformIO, Python scripts, etc.
Projects
None yet
Development

No branches or pull requests