8000 Rel 4159 by hstecher · Pull Request #2904 · gemini-hlsw/seqexec · GitHub
[go: up one dir, main page]

Skip to content

Rel 4159 - #2904

Open
hstecher wants to merge 11 commits into
gemini-hlsw:mainfrom
hstecher:REL-4159
Open

hstecher wants to merge 11 commits into
gemini-hlsw:mainfrom
hstecher:REL-4159

Conversation

@hstecher
@hstecher hstecher commented Nov 4, 2026
Copy link
Copy Markdown

Add support for LGS+P1

Just a fair warning, this was mostly claude written. The latest version has been tested in operations for several weeks. We've completed LGS+P1 ENTs and real science.

In plain LGS mode hasTarget returned true only when STRAP or SFO loops
were currently closed (st || sf). An NGS target is always present in
LGS mode regardless of which loops are running, so this conflated
target presence with loops-currently-closed and caused two symptoms:

1. Starting a sequence with STRAP/SFO open propagated hasTarget=false
   into buildTcsAoConfig, which built the AOWFS guider with
   ProbeTrackingConfig.Off. setAltairProbe then wrote aoFollow=Off to
   the TCS aoFollow CAD, freezing the probe. Closing loops later from
   the TCC didn't recover because seqexec had already committed the
   demand.

2. With the AOWFS guider inactive, calcAoPauseConditions injected
   GaosGuideOff on every offset and GaosGuideOn never appeared on
   resume, so corrections were torn down between offsets and not
   restored.

Changes:
- Altair.hasTarget for Lgs(_, _, _) now returns true unconditionally.
- ttgsOn: checkStrapLoopState is now guarded by .whenA(strap), so the
  new Lgs(false, false) path doesn't raise on STRAP hardware-status
  faults when STRAP isn't being started.
- resumeLgsMode: resume action gated by && (strap || sfo) to avoid a
  no-op setCorrectionsOn + ttgsOn(false, false) cycle when there's
  nothing to resume.
Two debug lines tagged "REL-4159" so the on-sky logs can be grepped
to confirm the fix is taking effect and to diagnose any remaining
issue:

- TcsNorth.configure: logs the AltairConfig demand (aog) and the
  resulting AOWFS guider tracking/detector state at the seqexec → TCS
  handoff. Shows whether hasTarget produced the expected
  ProbeTrackingConfig.

- AltairControllerEpics.pauseResume: logs the input AltairConfig, the
  live EpicsAltairConfig snapshot, pause/resume reasons, and the
  computed forceFreeze, pauseTargetFilter, and guide capabilities for
  each offset cycle.

Together they capture the full input/output of every AO step. No
behavior change.
The earlier hasTarget fix only covered the plain Lgs branch; the on-sky
test ran in LgsWithP1, where hasTarget still returned false and the same
bug recurred.

In every Altair LGS mode the AOWFS runs the laser spot and must keep
following its target — the tip-tilt/focus reference simply lives on a
different guider (P1 for LgsWithP1, OI for LgsWithOi, STRAP/SFO for plain
Lgs). Returning false built the AOWFS guider with ProbeTrackingConfig.Off,
which:

1. made setAltairProbe write aoFollow=Off to the TCS, freezing the probe
   when seqexec configured the TCS, and
2. left demand.gds.aoguide.isActive=false, so calcAoPauseConditions
   injected GaosGuideOff on every step and calcAoResumeConditions never
   added GaosGuideOn, tearing down corrections and flattening the DM
   between offsets and not restoring them.

Make hasTarget return true for LgsWithP1 and LgsWithOi, symmetric with the
plain Lgs case.
To verify on-sky whether the LgsWithP1/LgsWithOi fix takes effect, log the
two places that decide whether seqexec opens the AO loops:

- pauseResumeGaos: logs the AltairConfig demand, the AOWFS guider's
  isActive (with follow/nodChop), the current aowfs follow state, and the
  resulting pause/resume condition sets. This shows whether hasTarget now
  produces an active AOWFS guider and, crucially, whether GaosGuideOff is
  still being injected (it should not be on guided steps) and GaosGuideOn
  reappears on resume.

- setAltairProbe: logs every aoFollow write (old -> new) just before it is
  sent to the TCS. An "On -> Off" line is the smoking gun for the probe
  freeze; with the fix there should be no such write on a guided LGS step.

Grep the logs for "REL-4159" to get the full input/output of each AO step.
No behavior change.
In LgsWithP1 (and LgsWithOi) mode seqexec demands PWFS1 tracking as
On(NodChopTrackingConfig.Normal). On the TCS config step, the shared
setGuideProbe issues a PWFS1 nod/chop command whenever demanded =!=
current nod/chop. The TCS forbids setting nod/chop on P1 in P1+LGS mode
and rejects it, which aborts the whole TCS-config batch (single
epicsSys.post) -- which is also why the AOWFS did not reach position.

Fix, local to the AO north controller: PWFS1 now routes through a new
setPwfs1ProbeAo(demand.gaos). For LgsWithP1/LgsWithOi it calls
setGuideProbe with a PWFS1 GuideControl whose nodChopGuideCmd = none, so
the nod/chop EPICS write is skipped while the follow command still fires
and PWFS1 stays On(Normal). All other modes delegate unchanged to
commonController.setPwfs1Probe.

Safe because follow and nod/chop are independent writes in setGuideProbe;
dropping nod/chop leaves probe following intact. Tracking stays On(Normal)
so isActive remains true -- M1/M2 sourcing and the P1On/P1Off pause-resume
conditions are unaffected. Deliberately NOT done by demanding Frozen/AllOff,
which would flip isActive false and break the tip-tilt reference.

Pre-existing bug, not a regression from the probe-freeze fix (809587c):
that fix does not touch PWFS1 config, it just let a LGS+P1 guided step run
far enough to reach this command for the first time.

LgsWithOi included by analogy (same tip-tilt-relay structure); only
LgsWithP1 was reproduced on-sky.
…ject)

The previous commit gated PWFS1's nod/chop, but the rejected command
actually comes from the AOWFS. On-sky (2026-07-17, LgsWithP1) PWFS1 was
Parked (nod/chop AllOff, nothing sent) while the AOWFS demanded On(Normal);
the "Can not set nod/chop in P1+LGS mode" reject came from setAltairProbe,
which writes AOWFS nod/chop through the PWFS2 probe guide channel.

Gate the AOWFS nod/chop write with suppressNodChop = gaos is LgsWithP1 or
LgsWithOi. aoFollow is still driven and tracking is unchanged, so guiding
is unaffected; only the EPICS nod/chop write is skipped.

The PWFS1 gating from 29112bd is retained (harmless; covers the OI probe
analogue), but the AOWFS is the write the TCS was rejecting.
809587c flipped hasTarget to true for LgsWithP1/LgsWithOi by analogy with
the plain-Lgs fix. That was wrong: in those modes the tip-tilt reference is
on P1 / the OIWFS and the AOWFS/FSM is not put into follow (confirmed by
testing 2026-07-28).

With hasTarget true, buildTcsAoConfig built the AOWFS guider from
guideWithAO as On(Normal), so setAltairProbe drove aoFollow on and the AOWFS
probe was commanded on every offset. On a 30" offset the TCS never reached
in-position and the step aborted with "Timeout while waiting for TCS
inposition flag".

Plain Lgs stays true -- that is the original probe-freeze fix (verified
on-sky 2026-07-17) and is unaffected.

Note: with LgsWithP1/LgsWithOi back to false the AOWFS guider is inactive,
so calcAoPauseConditions still injects GaosGuideOff on every step and
GaosGuideOn never appears on resume. That is the remaining half of the
original loop-opening report for these modes and needs a separate fix on the
pause/resume side, not in hasTarget.
…modes

Reworks LgsWithP1/LgsWithOi against the tcl/tk seqexec (RealTcs.itcl),
which configures LGS mode correctly. Replaces the hasTarget special cases
from 93648e2/809587ce9/cb4a017ae and the two nod/chop workarounds from
29112bd/53cb1daf1.

Root cause: hasTarget was the wrong question. It is a Boolean choosing
between the step's demand and ProbeTrackingConfig.Off, so it could not
express "keep following, don't nod/chop" -- the state the relay modes
need. Off wrote aoFollow=Off and froze the probe; true sent AOWFS nod/chop,
which the TCS rejects in P1+LGS mode, aborting the whole TCS-config batch
so the offset never reached in-position. Neither value is right, which is
why the flag was flipped three times without landing.

tcl/tk never derives AO state from the Altair mode at all; it inherits it
from the TCC (RealTcs.itcl:1112: "the default is not always ON for
M2aoGuide and aoFollowing! Solution: use the values from the original tcs
configuration"), drives the AOWFS nod/chop channel to all-Off when lgsp1
or lgsoi is set, keeps P1 nod/chop On, and holds the AO loop closed across
offsets because the laser moves with the telescope.

Changes:
- Altair.hasTarget -> Altair.aoProbeTracking, returning the AOWFS probe
  tracking demand. LgsWithP1/LgsWithOi now demand ProbeTrackingConfig.Frozen
  (follow On + nod/chop AllOff). Ngs and plain Lgs pass the step's demand
  through unchanged, preserving the on-sky-verified 93648e2 behaviour;
  AltairOff is unchanged.
- buildTcsAoConfig takes the detector from the step and lets only the
  tracking be overridden. Both old branches used the same detector
  expression, so this is equivalent apart from the new tracking value.
- Revert 29112bd: PWFS1 goes back through commonController.setPwfs1Probe,
  so P1 nod/chop is written On Off Off On as tcl/tk beamconfig does. P1
  carries the tip-tilt star and must nod with the target; 53cb1da had
  already found P1 was not the rejected write.
- Revert 53cb1da's suppressNodChop: the Frozen demand drives AOWFS
  nod/chop to AllOff through the ordinary difference check, which also
  covers the case the suppression missed, where a previous step left
  nod/chop On.
- New aoGuideActive (probe follow + detector) replaces aoguide.isActive in
  calcAoPauseConditions/calcAoResumeConditions. isActive also requires
  nod/chop, so it reports Frozen as inactive; without this the Frozen
  demand would inject GaosGuideOff on every step, tearing the corrections
  down between offsets and never resuming. This is the remaining half of
  the original report that cb4a017 flagged.

Net effect on a guided LGS+P1 step: aoFollow is written On->On (i.e. not at
all) instead of Off, AOWFS nod/chop goes AllOff instead of being rejected,
P1 keeps its nod/chop, no GaosGuideOff is injected, and GaosGuideOn appears
on resume for the first time.

Not yet addressed: setAltairProbe can still write follow Off, and the
forceFreeze path maps the probe to ProbeTrackingConfig.Off (FollowOff)
despite its name, where tcl/tk's freeze keeps following. Both affect
Ngs/plain Lgs only and are left for a follow-up.

Not compiled locally (no sbt/nix on the dev host); built via
dockerfiles/build_test.sh.

Claude-Session: https://claude.ai/code/session_01YAAnKN8apvE8D1i4SVx5Mo
… resume

Review of the on-sky logs (2026-06-26, 07-15, 07-28, 08-12) against
fdfb439a5 found two problems.

1. fdfb439a5 demanded ProbeTrackingConfig.Frozen (follow On) for the LGS
   relay modes. Every LGS+P1 log shows aowfs.follow(current)=FollowOff,
   including after the loops were fully configured from the TCC (08-12
   08:41): the TCC does not put the AOWFS/FSM into follow in these modes.
   Frozen would therefore have written aoFollow On on the first step --
   exactly what cb4a017 found on-sky on 07-28 to drive the probe on every
   offset and abort 30" offsets with "Timeout while waiting for TCS
   inposition flag".

   tcl/tk inherits AO follow from the TCC rather than deciding it. So:
   - LgsWithP1/LgsWithOi demand ProbeTrackingConfig.Off (FollowOff + AllOff),
     the state the TCC leaves the AOWFS in.
   - setAltairProbe never writes aoFollow in the relay modes, in either
     direction, so seqexec can neither start nor freeze the probe there.
     AOWFS nod/chop is still driven to AllOff, as tcl/tk beamconfig does.
   - aoGuideActive is mode-aware: relay modes use the detector demand alone
     (the AO loop guides on the laser even though the AOWFS is not
     following); Ngs and plain Lgs keep GuiderConfig.isActive exactly as
     before, so the verified plain-LGS path is unchanged. This keeps
     GaosGuideOff off guided relay-mode steps -- the fix cb4a017 said was
     still needed on the pause/resume side.

2. resumeLgsMode's alreadyThere was
     (sfoOn && sfo) && (strapOn && strap)
   which can only be true when both loops are requested. In
   Lgs(strap = true, sfo = false) every guided step therefore "resumed" a
   STRAP loop that was never paused, re-running setCorrectionsOn and the
   STRAP hardware-status checks. On 07-15 that failed the step with "Cannot
   start Altair STRAP loop, RT Control status is bad" while the STRAP loop
   was running (currCfg strapLoop = true). Now
     (!sfo || sfoOn) && (!strap || strapOn)
   After a real pause the config passed in has the loops marked off, so the
   resume still happens when it should.
tcl/tk seqexec ran these modes correctly; replicate it (RealTcs.itcl).

Altair loop (AltairControllerEpics, LgsWithP1 | LgsWithOi):
- Never opened for offsets or because the tip-tilt guider (P1/OI) goes
  off. tcl/tk sets aoduringmove unconditionally in lgsp1/lgsoi ("the laser
  moves with the telescope"). 25b4cfa (2022) had added corrections-off
  whenever P1/OI went off; that is removed.
- Opened only when the step's AOWFS guide is park/freeze (GaosGuideOff),
  as tcl/tk telconfig does (RealTcs.itcl:1351/1355).
- Closed again on an AOWFS-guided step if it is open.
- After the move M1 and the GAOS M2 source follow the AOWFS guide state,
  as tcl/tk telconfig does; P1/OI M2 sources come from their own demand.

Guide loops while moving (TcsNorthControllerEpicsAo.calcGuideOff):
- If P1 (LgsWithP1) / OI (LgsWithOi) cannot keep guiding through the move
  (offset over its threshold, or not active before/after), all M2 guiding
  goes off, GAOS included, mount guiding with it, and that guider stops
  integrating. M1 is left alone. guideOn restores them after the TCS is in
  position. This is tcl/tk's LGS branch of move (RealTcs.itcl:837-866).

aoFollow: documented at its only write site why it must never be written
in these modes (2026-07-28 the Altair stage was driven into its limit when
it was commanded to follow with no target).

Tests: AltairSpec asserts LgsWithP1/LgsWithOi never demand AO follow On for
any step tracking. AltairControllerEpicsSpec covers the relay-mode Altair
loop: stays closed through a large offset with P1/OI off, opens on
AOWFS park/freeze, closes on an AOWFS-guided step when open.

Not done: tcl/tk also re-closes the BTO FSA loop and sends an aoFlatten
when it closes the Altair loop in LGS; seqexec has the BTO command defined
but has never sent it. Needs confirmation before adding.
Scope REL-4159 changes to LGS+P1/LGS+OI. Plain LGS behaviour is back to
what 93648e2 left it (the ticket's original probe-freeze fix, tested
on-sky); the alreadyThere logic is restored to its production form.
@jluhrs jluhrs left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@mergify
mergify Bot commented Nov 5, 2026
Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0