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

153 lines
6.8 KiB
Markdown

# 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](how-calibration-works.md).
---
## 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
```gcode
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:
```gcode
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:
```gcode
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:
```gcode
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.