feat: update float ESP-NOW runtime flow#5
Open
Skeitt wants to merge 19 commits into
Open
Conversation
- add runtime profile, PID, balance and motor settings with persisted ESPA config and ESPB parser support - log and stream normalized syringe position alongside pressure and float depth - require acknowledged command handling, centralize LED states and clean obsolete espA_pool/build artifacts - update firmware docs and protocol/parser/storage tests for the current command contract
home (motor_pos=0) pushes water out → floats; negative positions move toward the TOF and take on water → sinks. Simplify uToMotorPos to map u in [0,1] onto negative travel, dropping the unused MOTOR_INVERT_LOGICAL flag, and update balance() comments accordingly.
Mission log survives a power-cycle (cleared only at the start of a new mission, no longer at boot), so a failed pool test can be read afterwards over USB. Add a DUMP_LOG serial command to re-read it on demand without clearing — solves the case where the monitor connects after boot. emergencyStop() records reason + TOF distance to the flash log the instant it fires (idempotent single write) instead of a posteriori in loop(), where it was missed when measure() exited on phase timeout. Expose lastStopReason()/lastStopTofMm(). TOF safety now debounces with TOF_SAFETY_STOP_SAMPLES consecutive out-of-range reads to ignore single glitches (bubbles, reflections) in water, and clamps the PID output to [PID_U_MIN, PID_U_MAX] so the syringe never reaches the TOF safety limits. Enable monitor echo + LF EOL so serial commands are visible and terminated as the parser expects.
Default PID gains iterated against pool tests: Kp 0.17 was too weak (the float barely moved), Kp 2.0 / Kd 0.13 oscillated (±15cm pumping). Settle on Kp 1.0 / Ki 0 / Kd 0.5 as a damped starting point; fine-tune further at runtime via PID_CONFIG_SET. Reduce the descent kick-start from u=0.979 (near-full syringe, which drove the float straight to the bottom before the PID could brake, ~26cm overshoot) to PID_DESCENT_KICK_U=0.30, so the descent starts gently and the PID takes over before overshooting the target.
Validated in the pool: the float converges on the target depth with ~±1cm final oscillation. Ki vinces the buoyancy offset (recovery), Kd damps the overshoot. Replaces the previous 1.0/0/0.5 starting point.
Il manual keyboard serve a riallineare un pistone disallineato, quindi deve poter uscire dal range nominale (±MAX-margin) in entrambi i versi. - motor: nuovo startJogStepsUnclamped() che bypassa volutamente il clamp software dei fine corsa (startMoveTo/startMoveSteps restano clampati per il firmware di missione). - manual keyboard: startHoldMove() ora fa un jog relativo di ~2 mm (MANUAL_JOG_STEPS) rinnovato mentre il tasto è tenuto premuto, con stop manuale (space/x). - rimosso l'auto-stop su distanza TOF: usava una costante rimossa e la vecchia convenzione geometrica (estensione=positivo), incoerente con l'homing attuale.
…iscina Soglie tarate sulla distanza TOF reale (corretta dell'offset 6 mm): pistone esteso ~29 mm, retratto ~79 mm, pendenza ~1.1 mm TOF/mm motore. - TOF_SAFE_RANGE_MIN 40->32 mm: ~3 mm sopra il fondo corsa esteso (29); oltre si apre il tappo ed entra acqua. - TOF_SAFE_RANGE_MAX 85->82 mm: ~3 mm sopra il retratto (79); oltre = anomalia (passi persi / verso sbagliato). - TOF_HOMING_THRESHOLD 75->70 mm: lo stop reale cade qualche mm sopra per polling + conferma + risoluzione grezza, restando sotto MAX. - nuovo TOF_HOMING_CONFIRM_SAMPLES=2: conferma il trigger di homing per ignorare campioni rumorosi singoli (stesso pattern di SAFETY_STOP_SAMPLES).
Sostituisce tofMaxExtensionStopReached() con tofGuard() che ritorna un
enum TofGuard {Ok, ExtendLimit, Emergency}, perché i due estremi fisici
richiedono azioni diverse:
- limite inferiore (siringa estesa, vicina al TOF): oltre si apre il
tappo -> ExtendLimit, il chiamante fa uno STOP PULITO senza abortire.
- limite superiore (retratta, lontana): oltre = anomalia -> Emergency.
waitForMotor/moveToMax/_balanceStrokeTo passano tutti dalla guardia
unificata (moveToMax non duplica più la logica TOF inline).
Aggiunge logHomingEvent(): scrive su flash (sopravvive al power-cycle,
in piscina la USB e scollegata) ogni tappa dell'homing - start, timeout,
no-approach/no-detect, settle, backoff, complete - per ricostruire a
posteriori dove l'homing ha sbagliato.
Le fasi di approach e home richiedono ora TOF_HOMING_CONFIRM_SAMPLES
letture consecutive sopra soglia prima di accettare il trigger.
Le routine runSyringeSet/runPidHold/runPidStep ora chiamano tofGuard() a ogni movimento: - Emergency -> abort della routine. - ExtendLimit (saturazione a piena estensione): ferma il pistone e, nelle routine PID, inibisce ulteriori comandi di estensione (riaprirebbero il tappo) finche il PID non chiede di RISALIRE verso home.
…scent/ascent) I nomi precedenti (deepTargetM, shallowTopTargetM, pidTimeoutS, surfaceOffsetM) erano poco chiari e confondevano durante i test. Rinominati in inglese con schema orientato alla fase di missione: deepTargetM -> descentTargetM (target discesa, rif. fondo) shallowTopTargetM -> ascentTargetM (target risalita, rif. top) pidTimeoutS -> descentTimeoutS surfaceOffsetM -> surfaceRestOffsetM shallowBottomTargetM()-> ascentTargetBottomM() depthToleranceM, holdTimeS, ascentTimeoutS, profileCount invariati. Chiavi JSON di formatConfigJson e comando USB PROFILE_SET allineati. Refactor di soli nomi: ordine/tipi dei campi di ProfileSetPayload e RuntimeProfileConfig invariati, quindi layout binario e config NVS restano compatibili (PROFILE_CONFIG_VERSION non incrementato). Nessuna modifica a logica di controllo, range di validazione o protocollo. Aggiunti commenti che marcano i 4 parametri essenziali vs i 4 avanzati/safety.
Rinominata la repo da Float_2025 a Float: badge CI e comando cd nel README, URL repository in lib/DebugSerial/library.json.
La callback di ricezione ESPNOW gira nel task WiFi mentre lastCommand() viene letto dal loop principale: l'accesso non sincronizzato a _received poteva restituire una struct lacerata. - _received ora protetto da portMUX: scrittura in callback e lettura/clear in sezione critica - lastCommand() ritorna uno snapshot per valore; aggiornati i call site in espA che vi legavano un riferimento per evitare dangling sul temporaneo - sendMessage(): null-termination esplicita dopo strncpy - estratto runPidLoop() condiviso da runPidHold/runPidStep (logica TOF guard, deadband e saturazione fondo corsa ora in un solo punto)
…) e README tabella GUI a 4 colonne
…lash Dal test in piscina del 10/06: un descent timeout di 10 s memorizzato in NVS troncava ogni fase qualunque fosse l'hold richiesto, senza alcuna traccia diagnostica (i Debug.println si perdono sott'acqua). - validateConfig richiede timeout >= hold + 30 s (discesa e risalita): una config che non lascia spazio all'hold viene rifiutata; al boot una NVS invalida torna automaticamente ai default di config.h. - measure() scrive su flash un record phase_start con hold/timeout effettivi e un record exit_remote_stop/exit_timeout/exit_hold_ok al break che chiude la fase: il dump post-missione dice quale config ha girato e perche'.
…ta dalla pressione - _leggi_csv: i .txt salvati dalla GUI (celle con unita' tipo "0.53 m", nessun header) mandavano pandas in errore; ora ricade sul parser testo che gia' gestisce tab, unita' e virgole decimali. - la colonna depth del log di missione cambia riferimento fondo/top al cambio fase (salto fittizio ~0,5 m): se c'e' la pressione la profondita' viene ricostruita dal dato grezzo su riferimento FONDO (originale in depth_log). - stima_u_neutral esclude i campioni a galla: prima il fallback prendeva il float in superficie e stimava ~0,74 invece del neutro reale ~0,60. - esempio_log.csv sostituito da esempio_gui_dump.txt (dump GUI reale del test in piscina); fallback e URL d'esempio aggiornati.
…o automatico delle fasi Il notebook segmenta il log da solo (colonna phase del firmware o forma della traiettoria): solo discesa, solo salita o profilo completo, con metriche e diagnosi per fase e fase forzabile da parametro. Due target come nella GUI (discesa rif. FONDO, salita rif. TOP convertito +0,51 m come ascentTargetBottomM), u_neutral stimato su entrambe le quote, riemersione finale esclusa dalla salita e consigli PID combinati in un unico set (kp prudente, kd/ki incisivi) come richiede il firmware.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
add runtime profile, PID, balance and motor settings with persisted ESPA config and ESPB parser support
log and stream normalized syringe position alongside pressure and float depth
require acknowledged command handling, centralize LED states and clean obsolete espA_pool/build artifacts
update firmware docs and protocol/parser/storage tests for the current command contract