Skip to content

Automatic Fisrt Layer Z Height Adjustment#28460

Open
narno2202 wants to merge 29 commits into
MarlinFirmware:bugfix-2.1.xfrom
narno2202:Auto_First_Layer
Open

Automatic Fisrt Layer Z Height Adjustment#28460
narno2202 wants to merge 29 commits into
MarlinFirmware:bugfix-2.1.xfrom
narno2202:Auto_First_Layer

Conversation

@narno2202

Copy link
Copy Markdown
Contributor

Description

When you tune your printer for a perfect first layer, it's for a certain printing layer height. If you tune at a layer height of 0.4mm, and after you print at 0.2mm height, your first layer will have a bad bed adhesion because the nozzle is too high, and you'll have to play with babystepping to fix the issue.

This PR adapts only the first layer nozzle height for the current print based upon the tuned layer height.

In the gcode parser, we catch the first gcode with G0 or G1 and Z alone (without X, Y, E): this gcode sets the first layer height. A delta is computed and a safety margin of 0.05mm is added to avoid a too squished first layer.

An option is added in Configuration.h, AUTO_FIRST_LAYER_Z_ADJUST and the tuned first layer height CALIBRATED_FIRST_LAYER_Z_HEIGHT (the delta is computed against this value).

GCode M429 S0 disable auto adjustment, M429 S1 enable the function, M429 H <float> set the calibrated first layer heightin millimeters. There is also a menu entry.

Settings are stored in the EEPROM.

Requirements

Benefits

  • Keep a good first layer regardless of the layer height
  • Avoid playing with babystepping

Configurations

Related Issues

@oliof

oliof commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

I don't know if I follow this logic. The amount of required squish for example is material dependent. PLA likes some squish, PETG not at all.

In my experience with various firmwares, a properly zeroed head (i.e., nozzle touches bed just so at Z=0) with either flat surfaces (i.e. shimmed and calibrated at print temp) or a bed mesh compensation with high enough resolution, don't care about the commanded height of the first layer.

@Nuck-TH

Nuck-TH commented Jun 13, 2026

Copy link
Copy Markdown

I also don't follow the logic behind this and want to add that relying on gcode analysis is imho futile and potentially dangerous endeavor, because there is start gcode that for example can contain purge line with higher or lower Z height than first layer of actual print and taking it as "first layer height" will lead to print failure. Also different slicers may do things differently.

@narno2202

Copy link
Copy Markdown
Contributor Author

I have some problems while printing with a 0.6mm nozzle. I tuned the first layer for 0.4mm layer height: adhesion was ok with a good first layer but when I changed the layer height to 0.2mm for another print it was a total mess.
In my start gcode, there is a prime line and ths PR works fine. The PR just change the computed distance of the Z motion for the first layer, ther is no other change.

First layer detection is based upon the finding of an isolated gcode G0 or G1 with only Z without any X, Y, or E. I never see a gcode file with for example a G1 Z0.3 alone which is not the first layer start, but I'm perhaps wrong.
After all, I'm not sure that this PR is useful if you print at the same layer height (sure it's useless) or with a little delta from one print to another.

@oliof

oliof commented Jun 13, 2026 via email

Copy link
Copy Markdown
Contributor

@narno2202

Copy link
Copy Markdown
Contributor Author

I just looked at Orcaslicer gcode files (I use Prusaslcer and before Cura), Orcaslicer adds a Z hop (whatever the Z hop value is) just before the first layer height so there are two consecutive G1 Z. If some users find this PR potentially useful , I'll try to find a solution in Marlin or with SoftFever (if it's possible the put Z hop in the previous command).

@classicrocker883

Copy link
Copy Markdown
Contributor

so how does this work? if I understand: regardless of what the first layer height is set as in the Slicer (G-code) this bypasses it and uses a preset value??

@narno2202

Copy link
Copy Markdown
Contributor Author

Suppose you tune your first layer to be perfect for 0.4mm layer height. If you print at 0.2 layer height, your nozzle is 0.2mm higher so your first layer adhesion could be really messy (my own experience).
With this PR you set the value of the tuned layer height, in this case 0.4mm. When you launch a print, the gcode parser scans the gcode for a G1 or G0 with a Z alone, which means this is the Z move for the beginning of the first layer. In this case, the delta between the tuned value and the current layer height is calculated (with a 0.05 margin). In thIne planner, the travelled distance of the Z move is modified with the delta. This is done only for the first layer.

@thinkyhead thinkyhead changed the title Automatic Fisrt Layer Z Height Adjustement Automatic Fisrt Layer Z Height Adjustment Jun 26, 2026
Comment thread Marlin/src/feature/runout.h Outdated
@thinkyhead

Copy link
Copy Markdown
Member

When you launch a print, the gcode parser scans the gcode for a G1 or G0 with a Z alone, which means this is the Z move for the beginning of the first layer…

Note that "Start G-code" added by printer-specific and custom slicer profiles may move Z earlier.

This feature does seem to "interfere" with the printing process at a level where babystepping and/or calibration and/or slicer tuning and/or global mesh offset adjustment could probably accomplish, and a printer with this feature installed is going to be confusing to a new user approaching the machine for the first time after picking it up on eBay. So it seems important that the feature not be enabled and active by default, so the user must send G-code specifically to enable it.

Being a very niche feature, it will need to be well documented. You can create an article page for the feature in the Marlin Documentation website repo for integration into the new site design under development.

@narno2202

Copy link
Copy Markdown
Contributor Author

The idea came as I was tired of playing with babystepping with my 0.6mm nozzle. For a commercial printer with a 0.4 mm nozzle and a user printing at 0.2 to 0.3 mm layer height, this PR is probable not relevant. But if he changes the nozzle ... On the slicer side, if the user adds a custom start gcode with only G0 or G1 Z (why ?) detection will fail. The first layer always begins with a Z motion alone, only Orca and derivatives (I imagine) send a Z hop just before the first alone Z motion (if the Z hop is set to 0, the Z hop code is still present).
I totally agree that this feature has to be optional and not enabled by default.
I'll try to write a doc

@narno2202

Copy link
Copy Markdown
Contributor Author

Looking at QidiTech repository, there is a PR for QidiStudio to add the same functionality on the slicer side.

@Nuck-TH

Nuck-TH commented Jul 3, 2026

Copy link
Copy Markdown

I'm of opinion that this should be handled on slicer side(in start gcode or by whatever other means).

@narno2202

Copy link
Copy Markdown
Contributor Author

I'm in favor of the firmware side (fire and forget style). But I'm not the owner of the divine truth :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants