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.28k stars 19.24k forks source link

Extrusion confusion: LIN_ADVANCE is leaving me behind #4896

Closed VanessaE closed 8 years ago

VanessaE commented 8 years ago

(Hope you like the creative title :wink:)

This is Marlin RCBugFix branch, git commit da1644313d38f02fc90e2bb0fc01a4511cdbda29 plus my settings (below).

I've been having a small argument with my printer and Marlin regarding actual extrusion rates and how LIN_ADVANCE interacts with my E steps/mm setting. If I enable LIN_ADVANCE, sharp corners start to get rounded off, even with a K-value as small as 5. I find this confusing because mine is a bowden setup, which the documentation says should require especially large values, or at least larger than a direct-drive/non-bowden setup.

The extruder consists of a common NEMA17 stepper, a B'Struder drive block assembly, and a generic 12mm (effective diameter) drive gear from eBay, pushing Inland white PLA down a 55 cm PTFE tube into a hotend originally made as part of a clone of Makerbot's Stepstruder assembly (effectively, I separated the motor/drive block from the hotend/heatbreak, to reduce the mass on the X carriage).

They say a picture is worth a thousand words, so below is a composite I made from several of my better print attempts. Along the vertical, my extrusion steps/mm (78.0 is deliberately too low, while 87.9 is measured-correct for my gear/motor). Along the horizontal, my LIN_ADVANCE value (where "off" means I commented out the entry in Configuration_adv.h to disable it entirely). Where a spot is empty, I just didn't bother testing that combo. The numbers written on the parts are just a reminder to myself where to put the object in the image.

All prints done at 30 mm/sec max speed. When LIN_ADVANCE is enabled, there are some skipped steps here and there even at that speed (big drive gear, low torque), but they're not enough to invalidate these tests as they're mostly in internal layers/infill, and anyway you can easily see how the setting affects the part:

untitled (Open it in a new tab to see the full detail, it's 3500x2500)

Test object: large gear, caliper.STL.zip (This is the "large gear" from angry_monk's dial calipers, scaled up in Slic3r's plater) G-code output: large gear, caliper.gcode.zip (as produced by Slic3r. This file used for all of the prints in the picture) Configuration.h: Configuration.h.zip Configuration_adv.h: Configuration_adv.h.zip Configs as a git patch: 0001-my-settings.patch.zip Slic3r config bundle, in case it's helpful: Slic3r_config_bundle_1.3.0-dev-2016-09-25.ini.zip

Note that the config files above have changed since this Issue went out, to reflect my having settled on a LIN_ADVANCE setting of 15 and E-steps of 87.9, for now.

thinkyhead commented 8 years ago

@Sebastianv650 I noticed in the Prusa MK2 branch they have an additional trick, which doubles the values given to the Bresenham algorithm. This is done just ahead of the jerk calculation.

#if 1
  // Oversample diagonal movements by a power of 2 up to 8x
  // to achieve more accurate diagonal movements.
  uint8_t bresenham_oversample = 1;
  for (uint8_t i = X_AXIS; i <= Z_AXIS; ++ i) {
    if (block->nominal_rate >= 5000) break; // 5kHz
    block->nominal_rate << 1;
    bresenham_oversample << 1;
    block->step_event_count << 1;
  }
  if (bresenham_oversample > 1)
    // Lower the acceleration steps/sec^2 to account for the oversampling.
    block->acceleration_steps_per_s2 = (block->acceleration_steps_per_s2 + (bresenham_oversample >> 1)) / bresenham_oversample;
#endif

I wonder if this approach helps with the issue at hand.

VanessaE commented 8 years ago

I now have some damping in place. Helps with the rattling noise a bit, but not as much as I'd like.

Meanwhile, regarding the under-extrusion comment I made, it seems that linear advance doesn't play well with "normal" amounts of acceleration. I remembered that I had turned X/Y accel up to 2000 (from 500) after solving a ringing problem. That's when the under-extrusion started - when I turned acceleration back down, the under-extrusion went away. The extruder's "max" accel is set to 10'000 (the default), and I'm not sure if the "default" accel for it ever gets altered during a print.

Surely my extruder, with 5.22:1 gearing, isn't skipping steps due to excessive torque? And I quite sure now that the hob has a good grip on the filament. I can sit there and pull quite hard (enough to hurt my fingers) without any evidence of slipping or skipping, or any effect on the print.

@thinkyhead is this acceleration glitch connected to your preceding comment?

Sebastianv650 commented 8 years ago

@VanessaE as long as the ratio between extrusion speed and master axis speed is only valid to around 10-20% there is the possibility of lost steps. For the E-stepper on a block junction, this is like shifting into the reverse gear at the highway - your cars engine also will have "skipped steps" after that :smile:

The intention with the ratio between extrusion speed and master axis speed calculated in the planner was to keep track of variable extrusion rates, especialy when using Slic3rs variable gap fill. Now I know this isn't working with small segments, in fact for printers with small esteps/mm value the segment length has to be quite long (several mm). Therefore I plan to implement parameters into M905 to set extrusion width, layer height and filament diameter at the start of the print. This parameters should be available on most slicers, so they can be created automaticaly in the start gcode. Given this values, Marlin can calculate a fixed ratio that will be used for all blocks of the print. This means if there are variable width elements in the print, the LIN_ADVANCE correction will be a little bit of. But it's a lot better to have a not-perfect result in a few places that usualy are placed even inside the printed part than to have no pressure control for the hole part or a LIN_ADVANCE that is not working in circles (=short segments).

@thinkyhead intresting approach, but when I understand it right it will not help in this case. The resultion of the nozzle position isn't increased. What makes the problem is the following: Let's take a short segment. It may have 55 steps to move in XY plane, but only one step for E (always rounded to full steps as the planner does). A longer move with 90 XY steps has also 1 E step. The ratio for the extruder speed is calculated from (Esteps / XY steps). So the block with 55 steps has another ratio the one with 90 steps, but only due to the numerical rounding of the Estep, which might be 0.6 in the first case and 1,4 in the second case. For normal printing that's always corrected in the next step, if the first is rounded upward, the E position is higher on the start of the next block so it will be rounded down. But it breaks the neck of LIN_ADVANCE.

VanessaE commented 8 years ago

your cars engine also will have "skipped steps" after that

Not to mention lost teeth in the transmission gears :smiley:

Therefore I plan to implement parameters into M905 to set extrusion width, layer height and filament diameter at the start of the print

This won't work for Slic3r, as there is no custom start g-code to go with either print/style/speed profiles or with filament profiles, at least not at present (the only custom g-code that is offered is attached to the printer hardware profile, and can't adapt to the print/style/speed settings).

This means if there are variable width elements in the print, the LIN_ADVANCE correction will be a little bit of.

There indeed will be, as Slic3r has several extrusion widths it chooses from during the print, most of which aren't anywhere close to the nozzle diameter, in addition to variable gap fill. Not sure if your idea will work in practice, at least with Slic3r feeding gcode to it.

Sebastianv650 commented 8 years ago

It's working with Slic3r regarding start gcode, try this one: M905 K75 H[layer_height] W[extrusion_width] D[filament_diameter]

Only the K value has to be set according to the chosen material, thats true. In theory you are right about Slic3rs ability to use different extrusion widths for nearly anything. But according to my experience, it's best to stick to a fixed extrusion width (expect gap fill). Very different widths (say 0.5 for perimeters and 0.8 for infill) will increase pressure changes in the nozzle which can lead to less print quality also without LIN_ADVANCE. But don't wory, at the moment it's all in a draft state. I have one last idea how it could work with variable widths: Work with the original float X, Y and E positions. It will require some extra variables to track them, but the error might be small enough. <= Works! No need for the extended M905 thing.

I just got it to report constant extruder speeds at the junctions! Not ready to print with it yet, but now I can see some light at the end of the tunnel :)

Sebastianv650 commented 8 years ago

@VanessaE thanks for being that persistent about your rattling extruder. I guess without that I would have never checked the junctions speeds and found this error.. Nice side effect is, I can now say I finally understand nearly 100% of the planner code due to all that research.

VanessaE commented 8 years ago

Very different widths (say 0.5 for perimeters and 0.8 for infill) will increase pressure changes in the nozzle which can lead to less print quality also without LIN_ADVANCE

Indeed it does. For some time now, I've explicitly set external and internal perimeters to 0.4mm (my nozzle diameter), because having thicker internal perimeters always leads to a blobby seam. At that point, whatever blob I'd get from an infill-to-internal-perimeters transition is small enough that it hides within that area's infill anyway.

@VanessaE thanks for being that persistent about your rattling extruder.

Heh. I actually didn't intend to be especially persistent about it at all, I just wanted to make sure I didn't leave out some important detail. Let's hope that light at the end of the tunnel isn't the headlight of an oncoming train: :stuck_out_tongue_winking_eye:

Sebastianv650 commented 8 years ago

Nope, it's finished and quality is noticeable better. I will do some test prints and then there will be a PR on Monday or Tuesday. As long as the buffer isn't running dry it should be smooth.

VanessaE commented 8 years ago

Sounds great!

thinkyhead commented 8 years ago

@Sebastianv650 Looking forward to your PR. I will hold off on releasing RC8 till it's ready.

Sebastianv650 commented 8 years ago

@thinkyhead I'm preparing it at the moment - it's a fight with git every time for me. You might be also interested in my solution for the buffer underruns I mentioned in #5092. I can now print circles with small segments and full speed without a jerking printer due to a dry buffer. But it might be not a desirable solution for everyone: It blocks lcd_update if the executed block is a very short one, which means the chance is high that the buffer runs dry as soon as we try to call lcd_update.

thinkyhead commented 8 years ago

it's a fight with git every time for me.

@Sebastianv650 Want to play a game? http://learngitbranching.js.org/

thinkyhead commented 8 years ago

You might be also interested in my solution for the buffer underruns

I definitely am. I can check it out later on this evening or tomorrow.

Sebastianv650 commented 8 years ago

Here they are, #5124 to fix the jerky extruder movements (as long as the buffer isn't draining) and #5125 that prevents the block buffer from running dry very good.

@VanessaE looking forward to hear if it works for you :-) @thinkyhead I know the "git simulator", but the problem is I'm not using it regulary so I always forget the commands from one time to the next..

VanessaE commented 8 years ago

I've updated and applied both of those PR's. The extruder is much quieter now. The under-extrusion problem from before has also been solved. It is NOT a Marlin problem (mostly it was the small/drive gear slipping, and oddly I was printing too cold, AND my E-steps were still a bit low. All of these have been fixed.)

However, I've found a new problem (say it ain't so!), or rather an old problem with a new twist...

Remember those blobs that would occur when using firmware retract? It would seem I've found another way to trigger them: In Slic3r, turn off "firmware retract" but leave it enabled in Marlin (actually, it doesn't matter), configure Slic3r for the same retract speed/length/Z-hop, turn on Slic3r's "wipe while retracting" feature, disable Marlin's auto-retract feature by way of M209 S0, and print something appropriate.

In the past, I had found this wipe feature to be useful for avoiding those little dots that get left on the print from the nozzle standing in one place while the retract is performed.

Sebastianv650 commented 8 years ago

Yes, that's why I wrote in the documentation:

I also strongly recommend to disable further features like wipe while retract.

I never used wipe while retracting, I have to see which movements it does and maybe we can add another rule in the planner that recognises a wipe move and therefore don't trigger advance movements. I think wipe shouldn't make a big difference when LIN_ADVANCE is enabled as the nozzle will not ooze that much in short stops.

Sebastianv650 commented 8 years ago

Try this one. In planner.cpp search this line:

if (!block->steps[E_AXIS] || (!block->steps[X_AXIS] && !block->steps[Y_AXIS]) || extruder_advance_k == 0.0 || (uint32_t) block->steps[E_AXIS] == block->step_event_count) {

and replace it by:

if (!block->steps[E_AXIS] || (!block->steps[X_AXIS] && !block->steps[Y_AXIS]) || extruder_advance_k == 0.0 || (uint32_t) block->steps[E_AXIS] == block->step_event_count || de_float <= 0.0) {

It checks if the extruder is running in reverse, and if yes set block->use_advance_lead to false.

VanessaE commented 8 years ago

It's not so much that ooze is a problem, but rather if your hardware just can't handle high amounts of linear advance, you can't do short retracts, so the end of the just-printed line is kept hot and melty by the nozzle while the retract is done. It's just as well, Slic3r does wipes/coasted paths so quickly as to re-introduce my old nemesis, ringing, in certain cases, so I can't use it anyway. Go figure.

That aside, I don't find that exact line anywhere in the source, but it looks like planner.cpp line 1259 (in my copy) is what you're referring to:

if (!esteps || (!block->steps[X_AXIS] && !block->steps[Y_AXIS]) || extruder_advance_k == 0.0 || (uint32_t)esteps == block->step_event_count) {

I changed it thus:

if (!esteps || (!block->steps[X_AXIS] && !block->steps[Y_AXIS]) || extruder_advance_k == 0.0 || (uint32_t)esteps == block->step_event_count || de_float <= 0.0) {

This seems to fix the blobbing and makes wipe behave as expected. Note that I didn't do a thorough test.

Sebastianv650 commented 8 years ago

OK, I will create a small PR to update the rules. I hope we have filtered out all bad situations then.

VanessaE commented 8 years ago

I believe that's the last of it, yeah.

github-actions[bot] commented 2 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.