159159 <v-spacer />
160160 <span class =" text-caption text-medium-emphasis" >{{ autoStatus }}</span >
161161 </div >
162+ <div v-if =" autoRunning || tuneSession" class =" d-flex flex-wrap ga-1 mt-2" >
163+ <v-chip v-for =" s in STAGE_ORDER" :key =" s.id" size =" small"
164+ :color =" stageColor(stageStates[s.id])"
165+ :variant =" stageStates[s.id] === 'pending' ? 'outlined' : 'flat'"
166+ :prepend-icon =" stageIcon(stageStates[s.id])" >{{ s.label }}</v-chip >
167+ </div >
162168 <div class =" d-flex flex-wrap ga-1 mt-2" >
163169 <v-chip v-for =" t in pidSummary" :key =" t.term" size =" small"
164170 :color =" autoRunning && wizardStep.term === t.term ? 'primary' : undefined"
@@ -436,6 +442,7 @@ import CaptureChart from "./CaptureChart.vue";
436442import { evaluateTune , gradeColor , severityColor , severityIcon , type Term , type TuneEvaluation } from " ../model/evaluate" ;
437443import { CAPTURE_DIR , CONFIG_FILE , DOCS , LS_STATE , PLUGIN_ID } from " ../model/constants" ;
438444import { upsertTuneBlock } from " ../model/config" ;
445+ import { stepJumpDistanceMm , stepJumpFeedMmPerMin } from " ../model/scale" ;
439446import {
440447 buildCalibrationCommand , buildCaptureCommand , buildModeCommand , buildPidCommand ,
441448 CALIBRATION_MOVES , CAPTURE_VARIABLES , DEFAULT_MODE_D , ENCODER_TYPES , MODE_LABELS ,
@@ -449,7 +456,7 @@ import {
449456} from " ../model/limits" ;
450457import { WIZARD_STEPS , type Recommendation } from " ../model/wizard" ;
451458import { computeTuneSignal , type TuneSignal } from " ../model/signal" ;
452- import { runAutoTune as runAutoTuneCore , type TuneEffects } from " ../model/autorun" ;
459+ import { runAutoTune as runAutoTuneCore , type AutoRunResult , type StageId , type StageState , type TuneEffects } from " ../model/autorun" ;
453460import { applying , applyUpdateNow , checking , dismissCurrentUpdate , pendingReload , runUpdateCheck , setUpdateChecksEnabled , updateChecksEnabled , updateState } from " ../model/updateCheck" ;
454461
455462/* eslint-disable @typescript-eslint/no-explicit-any */
@@ -529,6 +536,30 @@ const autoRunning = ref(false);
529536const autoCancel = ref (false );
530537const autoStatus = ref (" " );
531538const autoLog = ref <Array <string >>([]);
539+
540+ // Stage-status timeline: preflight → P → D → I → A → V → verify (P–V repeat every cycle).
541+ const STAGE_ORDER: Array <{ id: StageId ; label: string }> = [
542+ { id: " preflight" , label: " Preflight" }, { id: " p" , label: " P" }, { id: " d" , label: " D" },
543+ { id: " i" , label: " I" }, { id: " a" , label: " A" }, { id: " v" , label: " V" }, { id: " verify" , label: " Verify" },
544+ ];
545+ const stageStates = reactive <Record <StageId , StageState >>({ preflight: " pending" , p: " pending" , d: " pending" , i: " pending" , a: " pending" , v: " pending" , verify: " pending" });
546+ function resetStageStates(): void { for (const s of STAGE_ORDER ) { stageStates [s .id ] = " pending" ; } }
547+ function stageColor(state : StageState ): string | undefined {
548+ switch (state ) {
549+ case " running" : return " primary" ;
550+ case " done" : return " success" ;
551+ case " failed" : return " error" ;
552+ default : return undefined ;
553+ }
554+ }
555+ function stageIcon(state : StageState ): string {
556+ switch (state ) {
557+ case " running" : return " mdi-progress-clock" ;
558+ case " done" : return " mdi-check-circle" ;
559+ case " failed" : return " mdi-close-circle" ;
560+ default : return " mdi-circle-outline" ;
561+ }
562+ }
532563const avDistance = ref (saved .avDistance ?? 50 ); // mm — A/V test move length
533564const avFeed = ref (saved .avFeed ?? 6000 ); // mm/min — A/V test move feedrate
534565const cycles = ref (saved .cycles ?? 3 ); // how many times to iterate P→D→I
@@ -578,6 +609,12 @@ interface TuneSession {
578609 startedAt: string ; finishedAt? : string ; driver: string | null ; mode: LoopMode | null ;
579610 encoderType: EncoderType ; cycles: number ; finalPid? : PidConfig ; log: Array <string >;
580611 captures: Array <SessionCapture >; evaluation? : TuneEvaluation | null ;
612+ /** Ultimate gain/period found during Ku/Tu seeding, when it succeeded. */
613+ ku? : number ; tu? : number ;
614+ /** Calibration moves (M569.6 V-ids) actually run during preflight. */
615+ preflightActions? : Array <string >;
616+ /** True if the run failed/was cancelled and the pre-run PID snapshot was restored. */
617+ restored? : boolean ;
581618}
582619const tuneSession = ref <TuneSession | null >(null );
583620function recordSessionCapture(phase : string , value : number | undefined , metrics : unknown ): void {
@@ -893,9 +930,7 @@ async function captureStep(): Promise<StepMetrics | null> {
893930 const stepVars = varIds ([" measuredMotorSteps" , " targetMotorSteps" , " currentError" , " pidPTerm" ]);
894931 let c: ParsedCapture | null ;
895932 if (ax ?.letter ) {
896- const stepsPerMm = Number (ax .stepsPerMm ) || 80 ;
897- const micro = Number (ax .microstepping ?.value ) || 16 ;
898- const desired = Math .max (0.1 , (micro / stepsPerMm ) * 16 ); // ~16 full steps ≈ a step jump
933+ const desired = stepJumpDistanceMm ({ stepsPerMm: Number (ax .stepsPerMm ), microstepping: Number (ax .microstepping ?.value ) });
899934 let dist = desired ;
900935 let sign: 1 | -1 = 1 ;
901936 if (limits ) {
@@ -904,9 +939,10 @@ async function captureStep(): Promise<StepMetrics | null> {
904939 dist = plan .distance ; sign = plan .sign ;
905940 }
906941 const signedDist = sign * dist ;
907- const move = ` G91 G1 H2 ${ax .letter }${signedDist .toFixed (3 )} F18000 G90 ` ;
942+ const feed = stepJumpFeedMmPerMin (dist ).toFixed (0 );
943+ const move = ` G91 G1 H2 ${ax .letter }${signedDist .toFixed (3 )} F${feed } G90 ` ;
908944 c = await runCapture ({ driver: selectedDriver .value ?? " " , samples: samples .value , activate: 1 , rate: sampleRate .value , variables: stepVars , manoeuvre: 0 , move });
909- try { await machineStore .sendCode (` G91 G1 H2 ${ax .letter }${(- signedDist ).toFixed (3 )} F18000 G90 ` , false , false ); } catch { /* return move */ }
945+ try { await machineStore .sendCode (` G91 G1 H2 ${ax .letter }${(- signedDist ).toFixed (3 )} F${ feed } G90 ` , false , false ); } catch { /* return move */ }
910946 } else {
911947 c = await runCapture ({ driver: selectedDriver .value ?? " " , samples: samples .value , activate: 0 , rate: sampleRate .value , variables: stepVars , manoeuvre: 64 });
912948 }
@@ -993,6 +1029,7 @@ function buildTuneEffects(): TuneEffects {
9931029 wizardIndex .value = WIZARD_STEPS .findIndex ((s ) => s .term === term );
9941030 recordSessionCapture (term , value , metric );
9951031 },
1032+ onStage : (stage , state ) => { stageStates [stage ] = state ; },
9961033 isCancelled : () => autoCancel .value ,
9971034 delay ,
9981035 };
@@ -1017,15 +1054,17 @@ async function runAutoTune(): Promise<void> {
10171054 autoRunning .value = true ;
10181055 autoCancel .value = false ;
10191056 autoLog .value = [];
1057+ resetStageStates ();
10201058 viewKeys .value = [" measuredMotorSteps" , " targetMotorSteps" , " currentError" ];
10211059 const totalCycles = Math .max (1 , Math .round (cycles .value || 1 ));
10221060 const hasAxis = !! axisLetterForDriver ();
10231061 tuneSession .value = {
10241062 startedAt: new Date ().toISOString (), driver: selectedDriver .value , mode: currentMode .value ,
10251063 encoderType: encoderType .value , cycles: totalCycles , log: [], captures: [],
10261064 };
1065+ let result: AutoRunResult | undefined ;
10271066 try {
1028- const result = await runAutoTuneCore (buildTuneEffects (), { ... pid }, { cycles: totalCycles , hasAxis , calibrationMoveIds: requiredMoveIds .value });
1067+ result = await runAutoTuneCore (buildTuneEffects (), { ... pid }, { cycles: totalCycles , hasAxis , calibrationMoveIds: requiredMoveIds .value });
10291068 Object .assign (pid , result .pid );
10301069 if (result .ok ) {
10311070 const gradeNote = result .evaluation ? ` Final grade: ${result .evaluation .grade } (${result .evaluation .score }/100). ` : " " ;
@@ -1045,7 +1084,11 @@ async function runAutoTune(): Promise<void> {
10451084 tuneSession .value .finishedAt = new Date ().toISOString ();
10461085 tuneSession .value .finalPid = { ... pid };
10471086 tuneSession .value .log = [... autoLog .value ];
1048- tuneSession .value .evaluation = evaluation .value ;
1087+ tuneSession .value .evaluation = result ?.evaluation ?? evaluation .value ;
1088+ tuneSession .value .ku = result ?.ku ;
1089+ tuneSession .value .tu = result ?.tu ;
1090+ tuneSession .value .preflightActions = result ?.preflightActions ;
1091+ tuneSession .value .restored = result ?.restored ;
10491092 }
10501093 }
10511094}
0 commit comments