M2 Platform Alignment and Nozzle Height Check: Z Offset Confusion

A set of five calibration boxes will check both platform alignment and extruder settings:

Calibration Squares - rectified
Calibration Squares – rectified

Those boxes have three threads in their walls and stand 3.0 mm tall:

Calibration Boxes - alignment layout - corner detail - Slic3r preview
Calibration Boxes – alignment layout – corner detail – Slic3r preview

The first pass measurements:

Calibration Boxes - initial measurements - 2018-02-07
Calibration Boxes – initial measurements – 2018-02-07

The skirt is scant at 0.20 mm, the boxes are 0.15 mm short at 2.85 mm, and the walls are 0.03 mm too thin. Some Z offset adjustment seems in order, as the first few layers (on the left) came out grossly squished:

Calibration box - 2.85 - detail
Calibration box – 2.85 – detail

However, the box heights came out sufficiently uniform to show the platform alignment remains just fine.

Long ago, I moved the Z endstop switch to the X axis gantry, where it can directly sense the platform position:

M2 - V4 hot end - Z endstop switch
M2 – V4 hot end – Z endstop switch

Putting it there replaces all the mechanical putzing and adjusting cute little screws / bolts / nuts / spacers / suchlike with a simple offset in the startup G-Code:

G28 Z-2.15				; home Z to platform switch, with measured offset

So I changed the startup G-Code in Slic3r to use G28 Z-2.30, sliced a single box in the middle of the platform, printed it, and … it came out exactly the same height: 2.85 mm.


To make a very long story short, it turns out Marlin 1.1 ignores the numeric parameter in G28. When I updated the firmware to that version, I had changed the Configuration.h file to include the homing offsets:

  #define MANUAL_X_HOME_POS -100
  #define MANUAL_Y_HOME_POS -127
  #define MANUAL_Z_HOME_POS -2.15

So, with the same offset burned into the firmware, it looked like the startup G-Code was Doing The Right Thing. I never deleted the offset from the startup G-Code and, at some point, Marlin stopped supporting the numeric parameter.


However, the X and Y homing offsets must be hardcoded, because I want the XY origin in the middle of the platform to match my original OpenSCAD part designs. Everybody else prefers the XY origin in the front-left corner. FWIW, in Marlin 1.1-RC5 (two years old by now), the #define BED_CENTER_AT_0_0 constant appears only in that line and nowhere else in the source code. Maybe it was a change in progress back then?

Anyhow, rather than hardcode the Z offset again, I set it to 0.00:

  #define MANUAL_X_HOME_POS -100
  #define MANUAL_Y_HOME_POS -127
  #define MANUAL_Z_HOME_POS  0.0

Recompile and reload the firmware, then change the startup G-Code to use G28 Z without the offset.

Doing so means I can measure and adjust the actual Z offset with M206, then store the value in EEPROM with M500:

M206 Z-2.25

I went a little short at -2.25, for reasons I cannot explain now.

Measuring the offset goes like this:

  • Zero the offset: M206 Z0
  • Move the extruder off to the right: G0 X135
  • Home Z: G28 Z
  • Get some air under the nozzle: G0 Z4.0
  • Measure the actual clearance, perhaps using your taper gauge, at (let’s say) 1.7 mm
  • Set (1.7 – 4.0) as the offset: M206 Z-2.3
  • Print a box and adjust the offset accordingly

Using my actual measurement, not the for-instance example, I resliced the box, printed it, and it came out at 2.94 mm, just slightly short, so I re-tweaked the offset to Z-3.28 and re-stored it.

Embiggening the wall thickness turned out to be a matter of updating the filament diameter. I measured the start of the current spool of orange PETG at 1.75 mm, the same as the previous natural PETG spool, but the current section is 1.70 mm. Plugging that into Slic3r, reslicing, and reprinting produced a dead-on square: 3.00 mm tall with 1.20 mm walls:

Calibration Square series
Calibration Square series

The skirt now comes out at 0.25 mm, the way it should, too. The difference between the original 0.20 mm skirt and 0.25 mm suggests the squashed center thread (of the three in the skirt around the first set of five boxes) forced the two adjacent threads to become a bit taller, for lack of somewhere for the excess plastic to go on one side of each thread, and the nozzle rode higher than you’d (well, I’d) expect from the bare numbers.

The picture is missing a few squares in the middle, because I couldn’t believe changing the G28 Z-2.15 offset had no effect. It was easier to believe I’d inadvertently loaded the wrong file than the software / firmware was doing something wrong.

However, during the course of the adventure, I established M851 does exactly nothing in this context, perhaps because it applies to some different type of homing / probing / mesh leveling / whatever. You can set the Z offset with several other G-Code and M-Code commands, but the documentation isn’t always forthcoming about how the various methods interact and different firmware uses identical codes for completely different functions, so proceed with Exceedingly Great Caution.

In any event, it’s much easier and faster to adjust the printer & slicing parameters by measuring test boxes than by puzzling over actual prints, so …

The OpenSCAD source code as a GitHub Gist:

// Simple calibration boxes
// Thin wall open box - verify Extrusion Multiplier
// Solid box - verify infill settings
// Ed Nisley - KE4ZNU
// https://softsolder.com/
Layout = "Open"; // Open Solid
Texting = ""; // text message on solid box or empty string to suppress
//- Extrusion parameters must match reality!
ThreadThick = 0.25;
ThreadWidth = 0.40;
Protrusion = 0.1; // make holes end cleanly
function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit);
// Dimensions
WallThick = 3.0 * ThreadWidth;
echo(str("Wall thickness: ",WallThick));
BoxSize = 40.0;
echo(str("Overall size: ",BoxSize));
NominalHeight = 3.0;
echo(str("Nominal height: ",NominalHeight));
Height = IntegerMultiple(NominalHeight,ThreadThick);
echo(str("Actual height: ",Height));
Rotation = 0; // 45 to exercise X and Y axis motors at same time
CornerRadius = max(2.0, 2.0 + WallThick);
CornerSides = 8*4;
module Solid() {
difference() {
for (i=[-1,1], j=[-1,1])
translate([i*(BoxSize - 2*CornerRadius)/2,j*(BoxSize - 2*CornerRadius)/2,0])
if (len(Texting))
linear_extrude(height=3*ThreadThick + Protrusion)
text(text=Texting,size=6,spacing=1.05,font="ITC Zapf Chancery:style=Italic",halign="center",valign="center");
module Thinwall() {
difference() {
for (i=[-1,1], j=[-1,1])
translate([i*(BoxSize - 2*CornerRadius)/2,j*(BoxSize - 2*CornerRadius)/2,-Protrusion])
cylinder(r=(CornerRadius - WallThick),h=(Height + 2*Protrusion),$fn=CornerSides);
if (Layout == "Open")

2 thoughts on “M2 Platform Alignment and Nozzle Height Check: Z Offset Confusion

  1. Simpler still, you can set the offset via LCD controller if you have one on your machine, just remember to actually store it to eeprom afterwards. On a triple extruder machine I’m building hotends are dovetailed to the actuator so I simply chose the offset I wanted and tweaked each head to match it. M3 screw plays a leadscrew to my small dovetails so I can get fairly close without much trouble. Somewhat more anal me might devise a dial indicator jig in the future to make sure all 3 nozzles are exactly equal, but that’s really taking it too far :)

    1. I think the LCD just tweaks the M220 offset, so we’re doing the same thing.

      In any event, I never bothered with an LCD, having seen too many bug reports about one of the infinite LCD code tweaks producing bizarre motion control problems. The little netbook running Pronterface does everything I need: load the G-Code file, preheat the machinery, and start the print.

      I like the M3 leadscrew idea: make it mechanically right, rather than fiddling with offsets!

Comments are closed.