Files
firmware/docs/calibration.md
Oleksandr ShyshatskyiandClaude Opus 5 65a7528e09 The manual assumed a printer that arrives broken. It arrives calibrated.
The pages written on top of the old README inherited its premise: that after
flashing you face a gauntlet -- go/no-go checks, a safety net, a mandatory
calibration -- before the machine can be trusted with a model. That is not
what happens. The factory numbers import themselves on the first boot, a bed
mesh loads at the start of every print, and the mod is built to run the files
the stock firmware ran. A printer that printed before the flash prints after
it. "Your first print" now says so in its first line, and everything under it
is optional, ordered by what you would actually reach for: check the offsets
are applied, and calibrate only if that disagrees with the machine.

Three audiences now, because owner and contributor was not the real split.
"For experienced users" sits between them: How a print runs, and How
calibration works. Someone who knows Klipper and wants to change what happens
around their file has a place to go that is neither a walkthrough nor the
build system.

What was cut is most of what changed. Pages that were cryptic to the reader
they were aimed at -- Printing, Upgrading -- are out of the nav and kept on
disk to be rewritten rather than deleted. Within the pages that stayed:
Expected output, Probe sampling, What is being measured, the symptom table,
the dark-screen diagnosis, TOOL_Z_ADJUST, PLATE_CHECK, the ff-*.cfg
inventory, [ff_legacy] and SAVE_CONFIG in a paragraph about factory
calibration. Filenames and internals earn their place on an owner page only
when the reader has to type them or look at them; the rest moved to the
experienced pages or to Internals, where the audience wants them.

Calibration became a section rather than a page, because tool offsets are not
the only calibration: bed mesh has its own page now, and its own gotcha
written down -- BED_MESH_CALIBRATE writes `default`, a print loads
`MESH_DATA`, so a mesh probed by hand is a mesh no print will use. Input
shaping is described but has no procedure page yet.

Several claims came out because they were not true. "Is this for you" listed
calibration and input shaping as things the mod gives you; both are the
touchscreen's own sequences, recovered and reimplemented, and the notes say
so plainly. What the mod actually gives you is that anything speaking
Moonraker can drive the machine -- on stock, FlashForge's Klipper does not
toolchange at all, it raises a flag and waits for an application that is not
watching a Mainsail print, and the print hangs at the first T2. The page now
opens by telling most owners not to flash it.

Contributors are still deferred. Their pages are regrouped, not rewritten.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S3XZh4SqPdXAowVndz6tMr
2026-08-28 23:33:29 +03:00

6.8 KiB

XYZ tool calibration

How to calibrate nozzle offsets on a Creator 5 / 5 Pro running Reforge, what each command prints, and what every refusal means.

Measuring one tool does not disturb the others: if T2 drifts, recalibrate T2 and leave the rest alone. What the machine is measuring while it does this, and how those numbers reach a first layer, is How calibration works.


Before you start

  1. Take the PEI build plate off. The station is below the bed plane; with the sheet on, the Z probe stops on the sheet. You are not asked to promise this — the plate check measures it, and refuses.
  2. Clean every nozzle. The calibration is exactly as good as the nozzles are clean. A blob of filament on a nozzle is measured as part of the nozzle.
  3. Tools cold and docked. Nothing here heats; there is no purge.
  4. Klipper up, no print running.

The sequence

G28                      ; all three axes
CALIBRATE_TOOL_OFFSETS   ; the whole thing
SAVE_CONFIG              ; persists it, restarts Klipper

CALIBRATE_TOOL_OFFSETS is klipper-toolchanger's documented entry point, so it is the name HelixScreen's wizard and other UIs look for. It expands to:

TOOL_LOCATE_SENSOR                ; the reference, empty carriage
{% for tool in printer.toolchanger.tool_numbers %}
    SELECT_TOOL T={tool}
    TOOL_CALIBRATE_TOOL_OFFSET    ; measures whatever is mounted
{% endfor %}

Run those by hand instead when you only want one tool:

G28
TOOL_LOCATE_SENSOR       ; only if the station or bed was disturbed
SELECT_TOOL T=2
TOOL_CALIBRATE_TOOL_OFFSET
SAVE_CONFIG

Order is not optional. TOOL_LOCATE_SENSOR must have run at least once (now or in an earlier session) before a tool pass can be sanity-checked: the gap guard that catches a mis-triggered Z needs station_z to compare against. Without it the tool pass still runs, with one fewer guard.

The last tool stays mounted when CALIBRATE_TOOL_OFFSETS finishes, so a SHAPER_CALIBRATE afterwards has mass on the carriage.


Verifying

Calibration writes numbers; this is how you check they are the numbers you meant. Run it straight after SAVE_CONFIG, and again any time a tool starts printing at a different height from the others.

TOOL_OFFSET_STATUS lists what is saved for each tool and warns if anything was measured but not yet saved:

TOOL_OFFSET_STATUS
station start (cylinder_x/y): 28.500, 214.500
[ff_tool 0] nozzle 16.5051, 212.7750, 1.4726
[ff_tool 1] nozzle 16.2104, 212.8399, 1.5013
[ff_tool 2] nozzle NOT CALIBRATED
[ff_tool 3] nozzle 16.4415, 212.6902, 1.4488
[ff_tool_offset] station 28.7918, 212.6393, -1.6788
! unsaved calibration pending -- run SAVE_CONFIG

Every tool should show a nozzle triple, and nothing should say NOT CALIBRATED. TOOLCHANGE_STATUS covers the same ground from the toolchanger's side.

Then put the plate back and print a first layer.


Errors

Every refusal below happens before anything is saved, and most before any nozzle descends. A failed run leaves the previous calibration intact.

You are holding it wrong

Message What happened
home all axes first (homed: '') Run G28.
no tool is mounted. SELECT_TOOL T=<0..3> first You ran the tool pass with an empty carriage. It would have measured the bare carriage and saved it as a nozzle — ~3.2 mm out, in the direction that crashes. TOOL_LOCATE_SENSOR is the one that wants an empty carriage.
carriage is not verifiably empty (<reason>) -- the station pass must run with no tool mounted TOOL_LOCATE_SENSOR with a tool still on, or the dock and grab sensors disagree. <reason> names which.
[ff_toolchange] not loaded Config problem, not an operator one: ff-toolchange.cfg is not included.

The build plate is still on

Message What happened
plate check: station Z probe failed (...) -- is the build plate still on? The Z probe never triggered. Nothing has moved with a nozzle.
plate check: station Z <z> is <d> mm above the calibrated <z0> The probe stopped high — on the sheet. The check is one-sided on purpose: a plate can only hold the probe high, so a low reading is never a plate.
plate check: no circle edge within 14 mm of the start point The sideways probe found no bore. Either the plate is on, or the start point is far enough off that the bore is out of reach.

All three mean the same thing in practice: take the plate off and run it again.

The probe misbehaved

Message What happened
ESTOP <axis> ... : Probe triggered prior to movement The station read as triggered before the move started. Usually a dirty or shorted sensor; QUERY_ESTOP <axis> shows the pin state.
ESTOP <axis> ... : No trigger on probe after full movement Travelled the full distance without touching. The start point is off, or the tool is not where the toolchanger thinks.
ESTOP <axis> ...: sample spread <s> over samples_tolerance <t> after <n> retries (...) Repeated touches at one point disagreed. The individual samples are printed — read them: a slow drift is a loose tool, alternating values are backlash.
ESTOP <axis> ...: probe move failed The move itself was rejected. Check printer.log.

The result was implausible

Nothing is saved in any of these.

Message What happened
fit residual <r> exceeds max_residual 0.05 -- a probe mis-triggered One of the four points is off the fitted circle. With four symmetric points, one bad point of error e shows up as a residual of only ~e/4 while moving the centre by e/2 — so this threshold catches centre errors of about 0.1 mm.
circle fit failed: circle fit is singular (points collinear?) The four points do not describe a circle at all. Usually two probes returned the same value.
fitted radius <r> below min_radius / above max_radius Off by default; set them if you want a hard window on the bore size.
T<n> nozzle_z <z> is <g> above station_z <s>, outside gap_min/gap_max [1.50, 5.00] -- probe mis-trigger suspected The last guard before a bad nozzle_z becomes a first layer driven into the plate. Checked only once station_z exists — another reason to run TOOL_LOCATE_SENSOR first.

When to re-run

Event Re-run
Nozzle changed or removed on one tool that tool only
Tool disassembled or re-seated that tool only
Station, bed or bed mounts disturbed TOOL_LOCATE_SENSOR, then every tool
Firmware reinstall nothing — the values live in printer.cfg
First install from stock FF_IMPORT_FIRMWARE_CONFIG copies the factory numbers; calibrate when you want better ones

Because every value is absolute, a single tool can be recalibrated on its own at any time without touching the others.