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.34k stars 19.26k forks source link

G29 set_bed_level_equation_lsq #3417

Closed TechMasterJoe closed 8 years ago

TechMasterJoe commented 8 years ago

"set_bed_level_equation_lsq" is doing some bad math problem im have is X and Y pos this is giving me a headache.

first here is log data

G29 Auto Bed Leveling
setup_for_endstop_move > enable_endstops(true)
z_before = (before) 10.00
probe_pt >>>
  > ProbeAction:1
  > current_position: (0.00, 0.00, 0.60)
  Z Raise to z_before 10.00
  > do_blocking_move_to_z 10.00
  do_blocking_move_to: (0.00, 0.00, 10.00)
  > do_blocking_move_to_xy 49.00, 49.00
  do_blocking_move_to: (49.00, 49.00, 10.00)
  > ProbeDeploy
  deploy_z_probe > current_position: (49.00, 49.00, 10.00)
  run_z_probe > current_position: (49.00, 49.00, 0.97)
  Bed X: 50.000 Y: 50.000 Z: 0.968
<<< probe_pt
z_before = (between) 2.97
probe_pt >>>
  > ProbeAction:0
  > current_position: (49.00, 49.00, 0.97)
  Z Raise to z_before 2.97
  > do_blocking_move_to_z 2.97
  do_blocking_move_to: (49.00, 49.00, 2.97)
  > do_blocking_move_to_xy 124.00, 49.00
  do_blocking_move_to: (124.00, 49.00, 2.97)
  run_z_probe > current_position: (124.00, 49.00, 1.27)
  Bed X: 125.000 Y: 50.000 Z: 1.270
<<< probe_pt
z_before = (between) 3.27
probe_pt >>>
  > ProbeAction:0
  > current_position: (124.00, 49.00, 1.27)
  Z Raise to z_before 3.27
  > do_blocking_move_to_z 3.27
  do_blocking_move_to: (124.00, 49.00, 3.27)
  > do_blocking_move_to_xy 199.00, 49.00
  do_blocking_move_to: (199.00, 49.00, 3.27)
  run_z_probe > current_position: (199.00, 49.00, 1.43)
  Bed X: 200.000 Y: 50.000 Z: 1.426
<<< probe_pt
z_before = (between) 3.43
probe_pt >>>
  > ProbeAction:0
  > current_position: (199.00, 49.00, 1.43)
  Z Raise to z_before 3.43
  > do_blocking_move_to_z 3.43
  do_blocking_move_to: (199.00, 49.00, 3.43)
  > do_blocking_move_to_xy 199.00, 149.00
  do_blocking_move_to: (199.00, 149.00, 3.43)
  run_z_probe > current_position: (199.00, 149.00, 1.64)
  Bed X: 200.000 Y: 150.000 Z: 1.641
<<< probe_pt
z_before = (between) 3.64
probe_pt >>>
  > ProbeAction:0
  > current_position: (199.00, 149.00, 1.64)
  Z Raise to z_before 3.64
  > do_blocking_move_to_z 3.64
  do_blocking_move_to: (199.00, 149.00, 3.64)
  > do_blocking_move_to_xy 124.00, 149.00
  do_blocking_move_to: (124.00, 149.00, 3.64)
  run_z_probe > current_position: (124.00, 149.00, 1.51)
  Bed X: 125.000 Y: 150.000 Z: 1.513
<<< probe_pt
z_before = (between) 3.51
probe_pt >>>
  > ProbeAction:0
  > current_position: (124.00, 149.00, 1.51)
  Z Raise to z_before 3.51
  > do_blocking_move_to_z 3.51
  do_blocking_move_to: (124.00, 149.00, 3.51)
  > do_blocking_move_to_xy 49.00, 149.00
  do_blocking_move_to: (49.00, 149.00, 3.51)
  run_z_probe > current_position: (49.00, 149.00, 1.29)
  Bed X: 50.000 Y: 150.000 Z: 1.289
<<< probe_pt
z_before = (between) 3.29
probe_pt >>>
  > ProbeAction:0
  > current_position: (49.00, 149.00, 1.29)
  Z Raise to z_before 3.29
  > do_blocking_move_to_z 3.29
  do_blocking_move_to: (49.00, 149.00, 3.29)
  > do_blocking_move_to_xy 49.00, 249.00
  do_blocking_move_to: (49.00, 249.00, 3.29)
  run_z_probe > current_position: (49.00, 249.00, 1.56)
  Bed X: 50.000 Y: 250.000 Z: 1.560
<<< probe_pt
z_before = (between) 3.56
probe_pt >>>
  > ProbeAction:0
  > current_position: (49.00, 249.00, 1.56)
  Z Raise to z_before 3.56
  > do_blocking_move_to_z 3.56
  do_blocking_move_to: (49.00, 249.00, 3.56)
  > do_blocking_move_to_xy 124.00, 249.00
  do_blocking_move_to: (124.00, 249.00, 3.56)
  run_z_probe > current_position: (124.00, 249.00, 1.68)
  Bed X: 125.000 Y: 250.000 Z: 1.683
<<< probe_pt
z_before = (between) 3.68
probe_pt >>>
  > ProbeAction:2
  > current_position: (124.00, 249.00, 1.68)
  Z Raise to z_before 3.68
  > do_blocking_move_to_z 3.68
  do_blocking_move_to: (124.00, 249.00, 3.68)
  > do_blocking_move_to_xy 199.00, 249.00
  do_blocking_move_to: (199.00, 249.00, 3.68)
  run_z_probe > current_position: (199.00, 249.00, 1.95)
  > ProbeStow (stow_z_probe will do Z Raise)
  stow_z_probe > current_position: (199.00, 249.00, 1.95)
  Bed X: 200.000 Y: 250.000 Z: 1.945
<<< probe_pt
> probing complete > current_position: (199.00, 249.00, 1.95)
clean_up_after_endstop_move > ENDSTOPS_ONLY_FOR_HOMING > enable_endstops(false)
> after cleaning up endstops > current_position: (199.00, 249.00, 1.95)
Eqn coefficients: a: 0.00265474 b: 0.00253997 d: 0.76443166
Mean of sampled points: 1.47726974
before set_bed_level_equation_lsq > current_position : (199.00, 249.00, 1.95)
position after x: 224.011459 y: -24.996490 z: 1.413970
after set_bed_level_equation_lsq > current_position: (224.01, -25.00, 1.41)

Bed Height Topography:
+--- BACK --+
|           |
L |    (+)    | R
E |           | I
F | (-) N (+) | G
T |           | H
|    (-)    | T
|           |
O-- FRONT --+
(0,0)
+0.08313 +0.20549 +0.46789
-0.18857 +0.03558 +0.16396
-0.50888 -0.20705 -0.05154

Bed Level Correction Matrix:
+0.999997 +0.000000 +0.002655
-0.000007 +0.999997 +0.002540
-0.002655 -0.002540 +0.999993
> BEFORE apply_rotation_xyz > z_tmp  = 1.41
> BEFORE apply_rotation_xyz > real_z = 1.95
> AFTER apply_rotation_xyz > z_tmp  = 1.95
> corrected Z in G29: (224.01, -25.00, 0.61)
do_blocking_move_to: (224.01, -25.00, 2.61)
<<< gcode_G29
ok

i did edit in a debug line to track it down here is my edited section

 static void set_bed_level_equation_lsq(double* plane_equation_coefficients) {

        #if ENABLED(DEBUG_LEVELING_FEATURE)
          if (marlin_debug_flags & DEBUG_LEVELING) {
            print_xyz("before set_bed_level_equation_lsq > current_position ", current_position);
          }
        #endif

        vector_3 planeNormal = vector_3(-plane_equation_coefficients[0], -plane_equation_coefficients[1], 1);
        //planeNormal.debug("planeNormal");
        plan_bed_level_matrix = matrix_3x3::create_look_at(planeNormal);
        //bedLevel.debug("bedLevel");

        //plan_bed_level_matrix.debug("bed level before");
       // vector_3 uncorrected_position = plan_get_position_mm();
       // uncorrected_position.debug("position before");

        vector_3 corrected_position = plan_get_position();
        corrected_position.debug("position after");
        current_position[X_AXIS] = corrected_position.x;
        current_position[Y_AXIS] = corrected_position.y;
        current_position[Z_AXIS] = corrected_position.z;

        #if ENABLED(DEBUG_LEVELING_FEATURE)
          if (marlin_debug_flags & DEBUG_LEVELING) {
            print_xyz("after set_bed_level_equation_lsq > current_position", current_position);
          }
        #endif

        sync_plan_position();
      }

this is the current RC bug fix my printer IS Core-XY and it's massive servo driven monster(x,y,z, 1650,850,850 print zone) i have a custom made top board sitting on top of a mega the sheild has hardware pulse extenders in it and all the junk i needed to run 6 drivers for extruders (XYZ are Nema 23 sized brushless servos) Z rides on 3 3/4-8 ball screws belt driven by a 11:1 gearbox on the servo total Z rez is 2000 steps and can lift 2000lbs, my probe is a fixed induction setup bed is a stainless steel conveyor belt wrapped in buildtak just trying to get it going been building it for months but this bug has me stump atm please help me fix this fast don't need a full patch just point me in a direction to check im adding debug line to vector3 atm

thinkyhead commented 8 years ago

Thanks for bringing this up! I'm looking at a similar issue with #3311, and just now added some additional leveling debug code to help diagnose this sort of thing. Once #3434 is merged we'll have additional output from set_bed_level_equation_lsq and a couple other key points.

Historically speaking, the set_bed_level_equation_lsq function used to store the "corrected_position" in X and Y, but leave Z unchanged. To my thinking, this is because the Z position is known to be the correct distance from the nozzle to the bed at the last-probed point at the end of leveling. But with the addition of probe deployment and stowage, this seems no longer to be the case, because XY might change between finishing the last point and the calling of set_bed_level_equation_lsq. It might be enough to make sure that set_bed_level_equation_lsq is called before stowing the probe. But this comes with complications, because of course once the matrix is set, something like a "Docking Sled" probe might miss its target point. So ideally, we need a way to get the matrix before stowing, but only activate it after stowing.

Anyway, let me merge that added debug output so you (and others) can try some more tests.

Very cool sounding printer you've got there….

thinkyhead commented 8 years ago

@Roxy-3DPrintBoard Can the lsq matrix be "messed up" in the way we're seeing here by "ridiculous" values? And, are these probe points in any way "ridiculous"? The opposite corners are a full millimeter different…

X:  50 Y:  50 Z: 0.968
X: 125 Y:  50 Z: 1.270
X: 200 Y:  50 Z: 1.426
X: 200 Y: 150 Z: 1.641
X: 125 Y: 150 Z: 1.513
X:  50 Y: 150 Z: 1.289
X:  50 Y: 250 Z: 1.560
X: 125 Y: 250 Z: 1.683
X: 200 Y: 250 Z: 1.945
TechMasterJoe commented 8 years ago

yes it really was off 1mm but the problem that was bugging me is here

> probing complete > current_position: (199.00, 249.00, 1.95)
clean_up_after_endstop_move > ENDSTOPS_ONLY_FOR_HOMING > enable_endstops(false)
> after cleaning up endstops > current_position: (199.00, 249.00, 1.95)
Eqn coefficients: a: 0.00265474 b: 0.00253997 d: 0.76443166
Mean of sampled points: 1.47726974
before set_bed_level_equation_lsq > current_position : (199.00, 249.00, 1.95)
position after x: 224.011459 y: -24.996490 z: 1.413970
after set_bed_level_equation_lsq > current_position: (224.01, -25.00, 1.41) 

the odd shift in both Y & X axis pos to "224.01, -25.00, 1.41" my probe offsets are all zero even Z so getting a negative value is just shocking my home is XY0 front left so i don't expect any negative numbers. thanks for looking at this Scott if you want me to run anything and log it just ask. having the debugging compared to a year ago makes a world of deference in tracking this stuff down.

Roxy-3D commented 8 years ago

Can the lsq matrix be "messed up" in the way we're seeing here by "ridiculous" values? And, are these probe points in any way "ridiculous"? The opposite corners are a full millimeter different…

@thinkyhead I'm sorry for the delay in answering.... For some reason, I don't always see things when sorting on 'Least Recently Updated'. This thread never showed up. But because you said @Roxy I got it in my email. I don't understand why this happens again and again.

But the Least Squares convergence does get some flaky results when the data points diverge too far. 1mm corner to corner should be fine. But as the number of points start increasing off of the plane's mean, and the magnitude of the points error starts to increase, what happens is there are more and more equally good solutions to the problem. And what happens is you will get a 'good solution' mathematically, but it doesn't really work when you try to print.

TechMasterJoe commented 8 years ago

i have worked the math out by hand on paper using just "made up data " and the equations are sound i think ram might have a part to play in this with ever increasing "good solutions" and the poor 8bit cpu's limits i do think this implementation is a bit out of date adding some type of Gain to this, is next to impossible and really like mesh but (until) mesh is automated it's useless for me. Anyways you're both doing amazing work. I will have a new probe setup (industrial laser sensor) installed soon then i will know for sure how the bed is doing. also starting build on new small machine atm using Duet board and reprappro fw

TechMasterJoe commented 8 years ago

After doing the mathematics problems start around 15% error and up. But this error remains even after bringing the bed to within 0.3mm of level i

thinkyhead commented 8 years ago

the odd shift in both Y & X axis pos to "224.01, -25.00, 1.41"

Sorry all. The matrix functions are just fine. The problem was that the plan_set_position function did not yet support COREXY and COREXZ. I've patched it up at #3466 which is merged now.

@TechMasterJoe Please give the latest code a test at your earliest convenience.

thinkyhead commented 8 years ago

i think ram might have a part to play in this with ever increasing "good solutions" and the poor 8bit cpu's limits

Dynamic RAM usage is non-existent in Marlin, so the only place a collision is possible is with the stack growing too large. Most local (auto) variables are small single-value containers, but there are one or two functions (M23) where a string could use 100 characters or more of the stack. Even so, as long as there's 1K or more of space on your AVR, the stack should be quite safe.

Blue-Marlin commented 8 years ago

Extending array indices, or casting incompatible types, or shifting enums, might be a reason for corrupted memory. But, until now, we have no concrete hint about this. What @AnHardt tried to fix in MarlinSerial might be only one of several cases where pointers, or array indices, might be corrupted. Moving Z instead of E, or the other way around, when more than one extruder is involved, might be a hint on this, but until now, we have no idea when, where, or what happens.

The data @thinkyhead offers in https://github.com/MarlinFirmware/Marlin/issues/3417#issuecomment-207676353 is in no way ridiculous. It describes a bed measured as with a high slope of about 1mm from [50.50] to [200,250], nearly level from [200,50] to [50,250] (+-0.1mm). Every other point fits in, if you assume an error of about +-0.1mm. That's not a good set of data, but in no way ridiculous.

With a that high z-error of the measurements I'd recommend ether improving the probe (for example reducing the speed) or taking more measurements (to get more data, levelling out each other).

Roxy-3D commented 8 years ago

If there is a concern about memory corruption because of the stack or heap growing too large... M100 will help you put that issue to bed. It initializes all free memory and you can see the foot prints of what has been going on in RAM memory. You can literally see how much (and where) the free memory is in the system.

It will also catch bad pointers that de-reference into the free memory area.

jbrazio commented 8 years ago

I believe if we have issues it may more due the reasons @Blue-Marlin explain rather than stack/heap fragmentation, maybe we could easily check this by compiling a version with all local buffers[] static ?

Roxy-3D commented 8 years ago

I agree. With that said, it only costs a few hundred bytes of flash space to compile in the M100 code. You initialize it, and if you see the bad behavior you can dump the free memory and know for sure the issue is not caused by running out of RAM. At which point, we probably are looking for a bad pointer.

Blue-Marlin commented 8 years ago

And now something completely different. Did you ever thought about incorrect printer geometry, causing probing results what show high errors, where the error during printing is small. Let's assume a twisted x axis at a i3. Lest assume the angle between the left tower and the bed in y direction is 85° and for the right tower 95°. (ok that are ridicules high values - just to illustrate) That means the nozzle will be tilt back and forth when printing in x direction. That will cause a bit of error for the angle between x and y and a even smaller one in the z-height (correct in the middle of the bed, but somewhat lifted at the ends) And now the interesting part. If the probe is mounted with a y-offset of 0, it will measure exactly the same height differences the nozzle has. If mounted with a big y-offset the twist is amplified by the y-offset-lever. We get very high values at one end, and very low at the other and the correct one in the middle. Our bed correction sees a highly sloped bed and tries to correct for that, where the real error is small.

With a twisted y-axis and x-offsets you'll get similar effects.

Conclusion: "If your printers geometry is off enough - ABL can make things worse".

Blue-Marlin commented 8 years ago

OpenSCAD

//Animate with FPS = 20, Steps = 200

// left tower
translate([-100,0,0]) rotate([-5,0,0]) cylinder(d=5, h=200, center= true, $fn=32);
// right tower
translate([+100,0,0]) rotate([+5,0,0]) cylinder(d=5, h=200, center= true, $fn=32);

// nozzle
translate([200*$t-100,0,0]) rotate([(10)*$t-5,0,0]) translate([0,0,-50]) color("red") cylinder(r1=0,r2=5,h=10);
// probe
translate([200*$t-100,0,0]) rotate([(10)*$t-5,0,0]) translate([0,50,-50]) color("blue") cylinder(r1=0,r2=5,h=10);
//bed
translate([0,0,-50]) cube([200,200,0.1],center=true);
// ideal zero line
color("black") translate([0,0,-50]) rotate([0,90,0]) cylinder(r=0.2, h=200, $fn=64, center=true);
// twist zylinder nozzle
color([0.1,0.1,0.1,0.1]) rotate([0,90,0]) cylinder(r=50, h=200, $fn=64, center=true);
thinkyhead commented 8 years ago

2049 may be apropos to that.

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.