feat: autotune pipeline — structured bring-up sweep for gain, follower bias, and comparator threshold #3

Open
opened 2026-04-06 23:14:43 -07:00 by pyr0ball · 0 comments
Owner

Summary

The EasyPiezi firmware already contains the core tuning primitives (adjustFollow, adjustComp, adjustGain, readVcc, readVin) but relies on the operator to arrive at correct values through manual trial-and-error. This issue tracks adding a structured autotune sequence that sweeps those same controls in a defined order to converge on reliable trigger behavior automatically.

Motivation

The bring-up process today requires the user to:

  1. Watch serial output while tapping the probe tip
  2. Manually adjust trim values until the LED flashes reliably
  3. Re-tune if print surface, temperature, or probe mounting changes

This is a barrier for non-technical users and introduces inconsistency across machines. An autotune sequence — modeled on Marlin's M303 heater PID autotune — would reduce bring-up to a single command.

Algorithm (proposed)

Step 1 — Baseline capture

  • With no mechanical input, sample A0 (follower sense) and A1 (comparator sense) at 100Hz for 500ms
  • Record vFollow_idle and vComp_idle (mean + stddev)
  • This establishes the electrical noise floor without any piezo activity

Step 2 — Trigger floor detection (binary search on GAIN)

  • Apply a known mechanical impulse (firmware taps a test sequence or prompts user to tap)
  • Binary-search GAIN register from 0 to max until the comparator output (INT0 / D7) fires
  • Record GAIN_min = lowest gain that produces a clean trigger
  • Set working gain to GAIN_min + 1 step as headroom

Step 3 — Follower bias (VFOL) margin

  • With gain locked, sweep VFOL (OCR2B) downward from mid-rail
  • Find the highest VFOL value where the follower output still tracks the idle piezo signal without false-triggering
  • Set VFOL = that value + one step margin
  • This sets the adaptive bias that the follower output centers around at idle

Step 4 — Comparator threshold (VCOMP) margin

  • Sweep VCOMP (OC1A) upward from the follower idle output
  • Find the lowest VCOMP value that suppresses all false triggers during a quiet 500ms window
  • Set VCOMP = that value + HYST margin (default: 10 ADC counts or configurable)

Step 5 — Validation pass

  • Run 5 taps, verify all 5 produce exactly one INT0 trigger each with no double-fires
  • If validation fails, widen margins by one step and retry (up to 3 iterations)
  • Report final GAIN, VFOL, VCOMP, HYST over serial

Integration options

Option A — Standalone firmware autotune mode

Add an AUTOTUNE build flag or serial command (AT\n) that runs the sequence on boot or on demand, writes results to EEPROM, and resumes normal operation.

Option B — Marlin G-code integration

Expose as a custom G-code (e.g. M710 or G38.9) via Marlin's Z-probe plugin interface. Marlin sends the command, EasyPiezi runs the sweep and responds with ok GAIN=n VFOL=n VCOMP=n HYST=n. Marlin stores these in EEPROM via M500.

Option C — Host-side tuning script

Python script (or Klipper macro) that communicates with EasyPiezi over serial, drives the sweep externally, and writes final values back via serial commands. Lowest firmware complexity, most portable.

Option A should ship first; B and C can follow.

Technical notes

  • The "26 nanoseconds" figure is oscilloscope-measured hardware latency: time from piezo output to actuation pin logic transition (the analog comparator sub-chain only). This is a real, verified number for that specific path.
  • v2 AVR runs at 8MHz (internal oscillator — no external crystal). INT0 ISR entry overhead at 8MHz is ~500ns-1.25us (4-10 cycles). Full system latency = 26ns hardware + ~500-1250ns firmware.
  • v3 prototype (Cortex M0 @ 24MHz) substantially reduces firmware response time. M0 interrupt entry is ~16 cycles minimum = ~667ns worst-case at 24MHz, with no AVR-style pipeline stall. Autotune algorithm and timing constants should be parameterized by MCU clock so the same code targets both platforms.
  • readVcc() uses the internal 1.1V bandgap reference trick — this is accurate to ~1-2% and is sufficient for autotune convergence. No external reference needed.
  • Switched-resistor gain ladder is discrete; step resolution is fixed by resistor values. The autotune must work within those discrete steps, not assume continuous gain.
  • Autotune should abort and report failure if vComp_idle stddev > threshold (indicates electrical noise problem that tuning cannot solve — check grounding and cable routing).

Deliverables

  • autotune.cpp / autotune.h — sweep logic, decoupled from main loop
  • Serial command parser addition (AT command)
  • EEPROM read/write for persisting tuned values across power cycles
  • Serial output format compatible with Marlin M710 response convention
  • Documentation update: correct "26 nanoseconds" claim, add autotune bring-up guide
  • (stretch) Python host-side tuning script for Klipper/OctoPrint users
  • #2 — PID / autotune firmware integration
## Summary The EasyPiezi firmware already contains the core tuning primitives (`adjustFollow`, `adjustComp`, `adjustGain`, `readVcc`, `readVin`) but relies on the operator to arrive at correct values through manual trial-and-error. This issue tracks adding a structured autotune sequence that sweeps those same controls in a defined order to converge on reliable trigger behavior automatically. ## Motivation The bring-up process today requires the user to: 1. Watch serial output while tapping the probe tip 2. Manually adjust trim values until the LED flashes reliably 3. Re-tune if print surface, temperature, or probe mounting changes This is a barrier for non-technical users and introduces inconsistency across machines. An autotune sequence — modeled on Marlin's `M303` heater PID autotune — would reduce bring-up to a single command. ## Algorithm (proposed) ### Step 1 — Baseline capture - With no mechanical input, sample `A0` (follower sense) and `A1` (comparator sense) at 100Hz for 500ms - Record `vFollow_idle` and `vComp_idle` (mean + stddev) - This establishes the electrical noise floor without any piezo activity ### Step 2 — Trigger floor detection (binary search on GAIN) - Apply a known mechanical impulse (firmware taps a test sequence or prompts user to tap) - Binary-search `GAIN` register from 0 to max until the comparator output (`INT0` / D7) fires - Record `GAIN_min` = lowest gain that produces a clean trigger - Set working gain to `GAIN_min + 1` step as headroom ### Step 3 — Follower bias (VFOL) margin - With gain locked, sweep `VFOL` (OCR2B) downward from mid-rail - Find the highest `VFOL` value where the follower output still tracks the idle piezo signal without false-triggering - Set `VFOL` = that value + one step margin - This sets the adaptive bias that the follower output centers around at idle ### Step 4 — Comparator threshold (VCOMP) margin - Sweep `VCOMP` (OC1A) upward from the follower idle output - Find the lowest `VCOMP` value that suppresses all false triggers during a quiet 500ms window - Set `VCOMP` = that value + `HYST` margin (default: 10 ADC counts or configurable) ### Step 5 — Validation pass - Run 5 taps, verify all 5 produce exactly one INT0 trigger each with no double-fires - If validation fails, widen margins by one step and retry (up to 3 iterations) - Report final `GAIN`, `VFOL`, `VCOMP`, `HYST` over serial ## Integration options ### Option A — Standalone firmware autotune mode Add an `AUTOTUNE` build flag or serial command (`AT\n`) that runs the sequence on boot or on demand, writes results to EEPROM, and resumes normal operation. ### Option B — Marlin G-code integration Expose as a custom G-code (e.g. `M710` or `G38.9`) via Marlin's Z-probe plugin interface. Marlin sends the command, EasyPiezi runs the sweep and responds with `ok GAIN=n VFOL=n VCOMP=n HYST=n`. Marlin stores these in EEPROM via `M500`. ### Option C — Host-side tuning script Python script (or Klipper macro) that communicates with EasyPiezi over serial, drives the sweep externally, and writes final values back via serial commands. Lowest firmware complexity, most portable. Option A should ship first; B and C can follow. ## Technical notes - The "26 nanoseconds" figure is oscilloscope-measured hardware latency: time from piezo output to actuation pin logic transition (the analog comparator sub-chain only). This is a real, verified number for that specific path. - v2 AVR runs at 8MHz (internal oscillator — no external crystal). INT0 ISR entry overhead at 8MHz is ~500ns-1.25us (4-10 cycles). Full system latency = 26ns hardware + ~500-1250ns firmware. - v3 prototype (Cortex M0 @ 24MHz) substantially reduces firmware response time. M0 interrupt entry is ~16 cycles minimum = ~667ns worst-case at 24MHz, with no AVR-style pipeline stall. Autotune algorithm and timing constants should be parameterized by MCU clock so the same code targets both platforms. - `readVcc()` uses the internal 1.1V bandgap reference trick — this is accurate to ~1-2% and is sufficient for autotune convergence. No external reference needed. - Switched-resistor gain ladder is discrete; step resolution is fixed by resistor values. The autotune must work within those discrete steps, not assume continuous gain. - Autotune should abort and report failure if `vComp_idle` stddev > threshold (indicates electrical noise problem that tuning cannot solve — check grounding and cable routing). ## Deliverables - [ ] `autotune.cpp` / `autotune.h` — sweep logic, decoupled from main loop - [ ] Serial command parser addition (`AT` command) - [ ] EEPROM read/write for persisting tuned values across power cycles - [ ] Serial output format compatible with Marlin `M710` response convention - [ ] Documentation update: correct "26 nanoseconds" claim, add autotune bring-up guide - [ ] (stretch) Python host-side tuning script for Klipper/OctoPrint users ## Related - #2 — PID / autotune firmware integration
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Circuit-Forge/easypiezi#3
No description provided.