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

[FR] Axis Backlash / Hysteresis Compensation (Code is Ready) #7579

Closed Phaelz closed 6 years ago

Phaelz commented 7 years ago

First of all, I am immensely grateful for everyone that works for this community. I really wish I had the skills to program like you! I develop some 3D printers and Marlin was present from the beginning. I try my best to help this thing go forward! Here we go:

This was referenced in issue #3664 .

Why doesn't official Marlin have backlash compensation?

Lawsy from soolidoodle forums uploaded this to their fw.

I think Neil Martin was the guy who wrote these lines back in 2013.

http://www.soliforum.com/topic/313/hysteresis-fix/

The idea is that we have hysteresis on the movements of X and Y axis on printers based on belts and a little play/backlash in the nut on Z axis.

It's very visible when printing an object that is smooth on several layers and then have lots of artifacts on a layer. After lots of retractions and jumps, the rest of the layer become misaligned.

This backlash/hysteresis compensation would add movement to the planner ONLY if there is direction change on the axis. This would compensate belt stretching and play on pulleys. On the Z axis, it would be the same thing. When there is change in direction, a few steps are only used to compensate for this hysteresis and the movement would be made with real moving steps.

I think the code is ready for implementation. It's only necessary to adapt to the new variable names.

There are some topics on other forums about play, backlash, hysteresis and wobble on axis movement.

http://www.soliforum.com/topic/2342/backlash-hysterisis-and-wobble-an-exploration-of-the-topic/

Some members measured the positioning accuracy and they stated that this backlash is somewhat constant (there is a standard deviation around a fixed number). The code would always add a fixed distance on the planner in moves with direction change from the previous one. This distance would be in Configuration.h so the user could compensate for X, Y, Z and E axis (if the extruder is geared).

Edit: I've just found this https://github.com/MarlinFirmware/Marlin/pull/247 It seems that Neil stopped working on the code, but Rincewind from soliforum debugged it and perfected it. It is working flawlessly since 2013.

Phaelz commented 7 years ago

I'm trying to update my marlin with this new code...

Edit: after a few hours of work... I was massacred by the code hahahaha it seems a lot of functions and variables changed since that code was written. I could get nothing done.

Since this topic is kinda old, I know some people will come and say 3D printers don't suffer from backlash on belt systems, etc... BUT, several components of positioning systems have inherent backlash, even the stepper motors. When you add everything together, even a very well built machine will present some slight layer misalignment. I checked A LOT of 3D printers, from several manufacturers and all of theose from the desktop segment have backlash. The only printers I didn't see layer misaligment were from Stratasys and cost more than 80k USD.

If we could compensante, even a little bit of the hysteresis caused by backlash it would improve repeatability and print quality significantly!

thinkyhead commented 6 years ago

Why doesn't official Marlin have backlash compensation?

No one has implemented it yet, and demand is very low.

The implementation would need to be done in a way that is transparent to the high-level movement system. Essentially, anytime an axis reverses direction, extra steps are added in the new direction. This must be done at a very low level, somewhere between the Planner and the Stepper code. It would apply to steppers (A, B, C), not to cartesian axes (X, Y, Z).

hectori4502 commented 6 years ago

I test the code from: (for the version 1.1.5) marcio-ao commented on 14 Nov 2017

Here is an update on the backlash compensation code:

#define AXIS_BACKLASH {0.00, 0.00, 0.35, 0}

#if defined(AXIS_BACKLASH)
    #define SIGN(v) ((v < 0) ? -1.0 : 1.0)
    #define AXIS_BACKLASH_CORRECTION \
        { \
            static const float backlash[NUM_AXIS] = AXIS_BACKLASH; \
            static uint8_t last_direction_bits; \
            static bool is_correction = false; \
            if(!is_correction) { \
                uint8_t changed_dir = last_direction_bits ^ dm; \
                /* Ignore direction change if no steps are taken in that direction */ \
                if(da == 0) CBI(changed_dir, X_AXIS); \
                if(db == 0) CBI(changed_dir, Y_AXIS); \
                if(dc == 0) CBI(changed_dir, Z_AXIS); \
                if(de == 0) CBI(changed_dir, E_AXIS); \
                last_direction_bits ^= changed_dir; \
                /* When there is motion in an opposing direction, apply the backlash correction */ \
                if(changed_dir) { \
                    long saved_position[NUM_AXIS] = { 0 }; \
                    COPY(saved_position, position); \
                    const long x_backlash = TEST(changed_dir, X_AXIS) ? backlash[X_AXIS] * axis_steps_per_mm[X_AXIS] * SIGN(da) : 0; \
                    const long y_backlash = TEST(changed_dir, Y_AXIS) ? backlash[Y_AXIS] * axis_steps_per_mm[Y_AXIS] * SIGN(db) : 0; \
                    const long z_backlash = TEST(changed_dir, Z_AXIS) ? backlash[Z_AXIS] * axis_steps_per_mm[Z_AXIS] * SIGN(dc) : 0; \
                    const long e_backlash = TEST(changed_dir, E_AXIS) ? backlash[E_AXIS] * axis_steps_per_mm[E_AXIS] * SIGN(de) : 0; \
                    is_correction = true; /* Avoid infinite recursion */ \
                    _buffer_line( \
                        (position[X_AXIS] + x_backlash)/axis_steps_per_mm[X_AXIS], \
                        (position[Y_AXIS] + y_backlash)/axis_steps_per_mm[Y_AXIS], \
                        (position[Z_AXIS] + z_backlash)/axis_steps_per_mm[Z_AXIS], \
                        (position[E_AXIS] + e_backlash)/axis_steps_per_mm[E_AXIS_N], \
                        fr_mm_s, extruder \
                    ); \
                    is_correction = false; \
                    COPY(position, saved_position); \
                } \
            } \
        }
#else
    #define AXIS_BACKLASH_CORRECTION
#endif
Then in "planner.cpp", insert as such:

void Planner::_buffer_line(const float &a, const float &b, const float &c, const float &e, float fr_mm_s, const uint8_t extruder) {
  ...
  if (de < 0) SBI(dm, E_AXIS);

  AXIS_BACKLASH_CORRECTION

  const float esteps_float = de * volumetric_multiplier[extruder] * flow_percentage[extruder] * 0.01;
  ...
}
hectori4502 commented 6 years ago

And I make it work for the marlin v 1.1.8 in my Delta Rostock Max V2.

I only change this part:

_buffer_line( \

by

buffer_segment( \

Then in "planner.cpp", insert as such:

void Planner::_buffer_steps(const int32_t (&target)[XYZE], float fr_mm_s, const uint8_t extruder) {
...
if (de < 0) SBI(dm, E_AXIS);

AXIS_BACKLASH_CORRECTION

  const float esteps_float = de * e_factor[extruder];
  const int32_t esteps = abs(esteps_float) + 0.5;

But I need help to fix this:

  1. M98 and M99

Hectori

thinkyhead commented 6 years ago

I recommend against calling _buffer_line (or buffer_segment) as the solution. Although this may accomplish something, it also modifies stepper.count_position[], so it is not transparent to the stepper code, and it breaks Stepper::get_axis_position_mm(...).

Mike8-I commented 6 years ago

I would like to support the issue of implementing backlash compensation in Marlin. I know that it has been discussed before. When a machine is optimised as good as possible with a given design, software backlash compensation is the way to go. Even professional CNC milling machines use it. It was the only way to compensate the last some hundreds of a millimeter on my CNC mill (done with Eding CNC), and I would like to do the same on my 3d printer. I Have even considerated to intercept the stepper direction and step lines in hardware and inject some steps on edge of direction signal. My machine would need rouhly 8/16th steps (one half step on the 400 steps per revolution stepper motors I used).

thinkyhead commented 6 years ago

Hi @Mike8-I — Welcome to Github!

I would like to support the issue of implementing backlash compensation in Marlin.

We do accept cash, paypal, and certified check.

But all kidding aside, I think "inserting steps on edge of direction signal" is a bit too low-level for what we can accomplish in our AVR-based firmware.

What we can do is determine in planner.buffer_steps how many extra steps need to be added. For this it will use an extra field in the block. The stepper ISR can then execute that block like any other, doing the sum of those steps, but only counting the normal steps.

I'm certain this next problem is already solved by some PhD. out there: where to place those extra steps in relation to the synchronized motions of multiple axes. But I'm at a loss how that would work.

Each axis at the stepper level is independent, with its own drive. If only one axis is reversing, but another isn't, Marlin will already be doing a deceleration for the reversing axis, and this leads to commensurate slowing of all the other axes. Since we can't have the non-reversing axis just stop and wait for the reversing axis to finish its anti-backlash motion we have to allow it to be minimally out of sync with the reversing axis as they both continuously move. So, there are some trade-offs.

hectori4502 commented 6 years ago

But I need help to fix this:

  1. M98 and M99

When I compensated what my caliper showed me 0.20mm (the test was not good) then compensate 0.10mm (I improve but something was missing) when I did the test with 0.06mm (everything looks perfect) dsc_0030

thinkyhead commented 6 years ago

It seems to me that this kind of problem could be better solved by the slicer than by the firmware.

SimonSolar2C commented 6 years ago

If we are talking backlash in the [geared] extruder, this reversing of direction is a retraction. Therefore doesn't the s3d 'Extra restart distance' provide the same effect? Or is the maths more complex than, be less than the retraction amount? Or could be add something to the retraction script box? In robot arms its always been required for each axis - they include a backlash routine which automagically finds the backlash amount.

hectori4502 commented 6 years ago

I am happy with #define AXIS_BACKLASH_STEPS correction. which update in my marlin v1.1.8

Marlin v1.1.9 has many changes in planner.cpp and it does not work with the code

#define AXIS_BACKLASH_STEPS {0.13, 0.10, 0.08, 0}

check this video. https://www.youtube.com/watch?v=4ZaTx0hO4XM

thinkyhead commented 6 years ago

Marlin v1.1.9 has many changes in planner.ccp and it does not work with the code

The video is inspiring!

The AXIS_BACKLASH_STEPS feature will need to be updated to be compatible with the latest code. There's another implementation under development for Marlin 2.0.x that may have crossover with AXIS_BACKLASH_STEPS. We'll know more about that once a PR has been submitted for it.

hectori4502 commented 6 years ago

Hi backlash

marcio-ao commented 6 years ago

It's been a while since I've visited this thread and I am pleased to learn that at least one of you is getting good results with the backlash compensation code I had posted here. That said, this is a very early version of the code and we've spent quite a bit of time tweaking it.

I guess I need to get a new PR together with our updated code.

hectori4502 commented 6 years ago

hello marcio-ao, I have tried the code and it seems to work very well.

#define CONFIGURATION_H_VERSION 010107 compile and work perfect.

but the version #define CONFIGURATION_H_VERSION 010108 when I try to compile this is arduino returning

sketch \ Configuration.h: 653: 0: warning: "SIGN" redefined
      #define SIGN (v) ((v <0)? -1.0: 1.0)

Now I am working with my Delta Rostock max V2 with MKS Gen V1.4 TMC 2208 spreadCycle(Marlin 2.0 works very smoothly). but without:

// #define AXIS_BACKLASH_STEPS {5.13, 0.10, 0.08, 0}

I'm ready to try new code about it.

marcio-ao commented 6 years ago

@hectori4502, @thinkyhead: I have created a PR with the new backlash compensation code (PR#11061)

thinkyhead commented 6 years ago

Thanks Marcio! I will check it out tomorrow night. Flying to ERRF in the morning…

kostyansd commented 6 years ago

Where i must insert this code?

thinkyhead commented 6 years ago

Discussion moved to #11061.

inventabuild commented 5 years ago

Is BACKLASH_COMPENSATION best used primarily on the first layer and then tapered off over the next few layers OR can it be used with significant benefits throughout the whole print?

thinkyhead commented 5 years ago

Backlash exists at all times and so compensation has to be left on at all times for it to have the proper effect. It is not something you would want to taper off.

marcio-ao commented 5 years ago

Backlash exists at all times and so compensation has to be left on at all times for it to have the proper effect. It is not something you would want to taper off.

In an ideal world. But backlash compensation can introduce some defects in the surface quality. So I added the fading parameter so that it can be tapered off. We found backlash compensation is vital for the first layer to stick on a .25 mm nozzle, but tapering it off improves the surface finish at the expense of dimensional accuracy.

  1. So, in summary, for best dimensional accuracy, use backlash compensation at 100% on all layers.
  2. For best surface quality, do not use backlash compensation.
  3. For best bed adhesion and improved surface quality, enable backlash compensation at 100% on first layer and fade it out over the first few layers.
inventabuild commented 5 years ago

marcio-ao, I'm tapping the bed in a 6 point grid, 3(x-axis) x 2(y-axis), using copper strips as the electrical contacts as shown here: https://photos.app.goo.gl/Xv7vapDzZm8B9tYW9

I noticed the latest Lulzbot TAZ Marlin firmware has a backlash formula that assumes 4 points will be tapped:

/ Average the backlash from all four corners / \ z_backlash_measured_mm += 0.25 * (current_position[Z_AXIS] - start_height); \

Does this formula always get applied when backlash is active? If I'm tapping 6 points instead of 4 points s/ I change 0.25 to 0.167 (i.e. 1/6) in the above formula? Is there anyplace else I will need to take into account 6 points instead of 4 points?

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.