# Specific 3D Printers, Scanners, & Hardware > RepRap Format Printer Forum >  Auto Bed Leveling Solutions

## paradiddle65

Hello Everyone,

I'm in the process of designing my own Reprap, and I've been pondering over whether or not implementing auto bed leveling is worth it. The idea of having an auto leveling feature is amazing, consistent print quality and bed adhesion, less preprint rituals, etc. In practice its another story. I tried auto leveling when it was implemented into Marlin a few updates ago, and it just didn't work for me. It was a manual process using paper as a spacer and frankly took much longer than just adjusting the Z-axis rods on the fly. 

With this new design in the works, I thought I'd give it another shot. After some research I've come across some interesting ideas (some better and more practical than others). I wanted to ask the community if you had any experience with auto bed leveling and what your opinions are.

Are you currently using an auto bed leveling feature? Which one and what's your overall opinion of it? What's your opinion of some of the solutions out there (Commercial and Reprap)?

Thanks for your help,

Brian

----------


## Roxy

If you tried the 3-Point Bed Leveling that was the first version of Auto Bed Leveling.  It was very useful to prove the concept but it had some weaknesses.  In particular, any measurement error in the 3 points got magnified as you went out in the direction of the unmeasured corner.   If you haven't tried the n x n grid based Auto Leveling, you will want to retry that.  It works very well.

----------


## paradiddle65

> If you tried the 3-Point Bed Leveling that was the first version of Auto Bed Leveling.  It was very useful to prove the concept but it had some weaknesses.  In particular, any measurement error in the 3 points got magnified as you went out in the direction of the unmeasured corner.   If you haven't tried the n x n grid based Auto Leveling, you will want to retry that.  It works very well.


 Thanks for the tip! I'm guessing this method uses an endstop to detect the print bed?

----------


## Roxy

> Thanks for the tip! I'm guessing this method uses an endstop to detect the print bed?


The typical implementation uses a servo to kick down a probe leg with a switch mounted on it.   With that down, measurements are taken.   But people are going in all kinds of new directions.  Some have sensors built into the nozzle so they can tell when that touches.   Others have wired up the metal nozzle and if they have a metal bed can detect when it touches.  Etc.  Etc.

----------


## maar1201

Hi,

Is possible to change Marlin to do manual bed leveling? I don't want to use the servo.

My ideia is to acouple to x-carriage a switch and using G29 measure many points on the bed. This give-me the equation coefficients and the matrix.

I need help to find a way to store this information on configuration.h and use it in normal printing doing axis Z compensate the lite diferences. Can someone tell me what code on marlin_main.cpp i have to change?

Thanks

----------


## Roxy

The Enhanced G29 code will print out a topography map of your bed (normalized to the mean height).  That is very helpful for manually leveling the bed.   But other than that, you could connect up the probe with no way to retract or engage it...  And just let the G29 do its thing.   (and print out the desired information).

----------


## maar1201

Thanks for the reply. 

So, i have the topography map of bed collected using fixed switch near extrude nozzle which i know the offset.

Now, i want to change Marlin modules (i don't know where to start) in order to use the topographic map created by The Enhanced G29 previous stored.

Thanks for your help,
Mario

----------


## Roxy

Marlin doesn't store the topographical map.   What it does is it uses those data points to generate a 'Bed Level Correction Matrix'.   And when it needs to map a coordinate from the GCode to the 'corrected' coordinate system, it just does a matrix multiply of the coordinate and the correction matrix.  

What I think you want to do is expand the M500, M501 and M502 commands to save, restore and load the Bed Level Correction Matrix from EEPROM.

----------


## maar1201

Yes, expanding the Gcodes M500, M501 and M502 commands and save, restore and load the Bed Level Correction Matrix from EEPROM are a solution to me, but how to do this?

Can you give me some clues on Marlin code to find the function where as You said: "it just does a matrix multiply of the coordinate and the correction matrix."

Thanks

----------


## Roxy

> Yes, expanding the Gcodes M500, M501 and M502 commands and save, restore and load the Bed Level Correction Matrix from EEPROM are a solution to me, but how to do this?


In configurationstore.cpp there are 3 functions:  void Config_StoreSettings(), void Config_PrintSettings(), void Config_RetrieveSettings()

In the store function...  I would change:

  EEPROM_WRITE_VAR(i,zprobe_zoffset);

to

  EEPROM_WRITE_VAR(i,zprobe_zoffset);

  EEPROM_WRITE_VAR(i,plan_bed_level_matrix[0][0]);
 EEPROM_WRITE_VAR(i,plan_bed_level_matrix[0][1]);
 EEPROM_WRITE_VAR(i,plan_bed_level_matrix[0][2]);

 EEPROM_WRITE_VAR(i, plan_bed_level_matrix[1][0] );
 EEPROM_WRITE_VAR(i, plan_bed_level_matrix[1][1] );
 EEPROM_WRITE_VAR(i, plan_bed_level_matrix[1][2]);

 EEPROM_WRITE_VAR(i, plan_bed_level_matrix[2][0] );
 EEPROM_WRITE_VAR(i, plan_bed_level_matrix[2][1] );
 EEPROM_WRITE_VAR(i, plan_bed_level_matrix[2][2] );

Corresponding changes would need to be made to the Config and Retrieve functions.





> Can you give me some clues on Marlin code to find the function where as You said: "it just does a matrix multiply of the coordinate and the correction matrix."
> 
> Thanks


The matrix name with the correction matrix is called:   plan_bed_level_matrix

You can find references to it in Marlin_main.cpp, Planner.cpp and Planner.h     The Planner code is where Marlin 'Plans' its moves.  That is where the coordinates are actually 'corrected'.    It does this by doing:   apply_rotation_xyz(plan_bed_level_matrix, x, y, z);

This function is defined in vector_3.cpp     It looks like this:


void vector_3::apply_rotation(matrix_3x3 matrix)
{
    float resultX = x * matrix.matrix[3*0+0] + y * matrix.matrix[3*1+0] + z * matrix.matrix[3*2+0];
    float resultY = x * matrix.matrix[3*0+1] + y * matrix.matrix[3*1+1] + z * matrix.matrix[3*2+1];
    float resultZ = x * matrix.matrix[3*0+2] + y * matrix.matrix[3*1+2] + z * matrix.matrix[3*2+2];

    x = resultX;
    y = resultY;
    z = resultZ;
}

That would be a [1x3] matrix multiplied by a [3x3] matrix.   [x,y,z] * [bed level correction matrix]

----------


## Fri

I am trying the same thing I think. I would like to store the matrix in eeprom so I don't have to run a g29 with every print.

If I enter the "EEPROM_WRITE_VAR(i,plan_bed_level_matrix[0][0]);", I get an error compiling.

----------


## Roxy

My mistake...  They take a one dimensional array and effectively turn it into a 2 dimensional array by doing this to the sub-scripts:


```
void vector_3::apply_rotation(matrix_3x3 matrix)
{
    float resultX = x * matrix.matrix[3*0+0] + y * matrix.matrix[3*1+0] + z * matrix.matrix[3*2+0];
    float resultY = x * matrix.matrix[3*0+1] + y * matrix.matrix[3*1+1] + z * matrix.matrix[3*2+1];
    float resultZ = x * matrix.matrix[3*0+2] + y * matrix.matrix[3*1+2] + z * matrix.matrix[3*2+2];

    x = resultX;
    y = resultY;
    z = resultZ;
}
```

EEPROM_WRITE_VAR(i, plan_bed_level_matrix[2][1] ); 

becomes:

EEPROM_WRITE_VAR(i, plan_bed_level_matrix[2*3 + 1] );

----------


## Fri

Thanks Roxy.

Does anyone have all the necessary changes to the FW to get this to work?

Also, are there any changes to the gcode necessary? M500/M501?

----------


## Roxy

The EEPROM (if enabled) is automatically read when the Arduino board is reset.  Any important value in it is read and stored in the local variables for use.   If you add the code to save and restore the plan_bed_level_matrix[] it will happen automatically.    

At that point, you would just need to do a little bit more.  You still want to use and have available the G28 command.   I would delete the line of code at the start of it that sets the plan_bed_level_matrix[] to unity.   You don't want that changing anymore from what the EEPROM says it is.

And the other operational difference is you would have to manually do a G29, and save the results with a M500.

You also might want to move that line of code that sets the plan_bed_level_matrix[] to unity in the G28 command into the M502 code block.   I don't know.  That one could be argued.   The reason I'm suggesting this is you need a way to get the plan_bed_level_matrix[] reset to something usable when 'restoration of default settings' is requested.

----------

