Skip to content

Query ACAM directly for guide state in "put on slit" routing#450

Open
cfremling wants to merge 1 commit into
mainfrom
fix/guiding-state-freshness
Open

Query ACAM directly for guide state in "put on slit" routing#450
cfremling wants to merge 1 commit into
mainfrom
fix/guiding-state-freshness

Conversation

@cfremling
Copy link
Copy Markdown
Collaborator

@cfremling cfremling commented Jun 8, 2026

Problem

"Put on slit" intermittently fails when guiding is off — the telescope doesn't move and the command silently does nothing.

The decision is made inside the daemon: putonslit.sh only reads ds9 coordinates and sends one scam putonslit. slicecam's offset_acam_goal() then routes between updating ACAM's guide goal (guiding) and sending a PT offset directly to the TCS (not guiding), based on a cached is_acam_guiding flag populated from ACAM's pub/sub status.

Root cause — the cached guide state can be wrong

ACAM publishes its status only on change, and the frame loop skips frames between solves (if (_skipframes-- > 0) continue;). So the cached flag can read "guiding" while stale, or lag a state change. Trusting it for this decision is unsafe in both directions:

  • a wrong "not guiding" → sends a PT offset and moves the telescope while ACAM is actively guiding (fights the guider);
  • a wrong "guiding" → sends a no-op offsetgoal and never moves ("put on slit didn't work").

Fix (minimal)

Query acamd directly for its guide state at decision time instead of trusting the cache. ACAMD_ACQUIRE with no args returns the current mode { stopped | acquiring | guiding } — authoritative and current — so the routing no longer depends on pub/sub freshness.

Single-file change in slicecam_interface.cpp::offset_acam_goal.

Note: an earlier version of this PR added a per-frame ACAM heartbeat plus a freshness guard. Codex correctly pointed out that a freshness cache fundamentally cannot distinguish "guiding but stale" from "not guiding" (skipframes, long exposures, solver/pub-sub delays all lapse freshness while guiding), so it could still move the telescope during active guiding. That approach was dropped in favor of the direct query.

Not compiled locally (no local build available).

🤖 Generated with Claude Code

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd449fb900

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread slicecamd/slicecam_interface.cpp Outdated
// offsetgoal -- a no-op when ACAM isn't guiding -- and the telescope never
// moves ("put on slit didn't work").
//
bool is_guiding = this->is_acam_status_fresh() && this->is_acam_guiding.load();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not treat stale ACAM telemetry as not guiding

When ACAM is still guiding but no heartbeat arrives within 10 seconds, this expression makes is_guiding false and the code below sends the offset directly to the TCS instead of updating ACAM's guide goal. This can occur without ACAM stopping: the frame loop skips do_acquire() entirely for each configured nskip_before_acquire frame (acamd/acam_interface.cpp:2767-2771), and skipframes accepts any nonnegative value, so a normal 1-second exposure with skipframes 10 is enough to exceed the freshness window while guiding remains active. Pub/sub interruptions or slow solver processing have the same effect. A stale status should cause the operation to wait, query ACAM, or fail safely rather than assume guiding is off and move the telescope.

Useful? React with 👍 / 👎.

"Put on slit" intermittently failed when guiding was off. slicecam's
offset_acam_goal() decides between updating ACAM's guide goal (guiding) and
sending a PT offset directly to the TCS (not guiding) from a cached pub/sub
flag (is_acam_guiding), populated from ACAM's status broadcasts.

ACAM publishes its status only on change and skips frames between solves, so
the cached flag can read "guiding" while stale, or lag a state change. Trusting
it for this decision is unsafe in both directions: a wrong "not guiding" sends
a PT offset and moves the telescope while ACAM is actively guiding (fighting
the guider); a wrong "guiding" sends a no-op offsetgoal and never moves.

Query acamd directly instead. ACAMD_ACQUIRE with no args returns the current
mode { stopped | acquiring | guiding }, which is authoritative and current, so
the routing decision no longer depends on pub/sub freshness.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cfremling cfremling force-pushed the fix/guiding-state-freshness branch from dd449fb to 754ca53 Compare June 8, 2026 06:05
@cfremling cfremling changed the title Route "put on slit" on a fresh guide state; heartbeat ACAM status Query ACAM directly for guide state in "put on slit" routing Jun 8, 2026
@cfremling
Copy link
Copy Markdown
Collaborator Author

Thanks Codex — this was correct and it changed the approach. The earlier version added a per-frame ACAM heartbeat plus a freshness guard, but as you noted a freshness cache fundamentally cannot distinguish "guiding but stale" from "not guiding": do_acquire is skipped on skipframes, and long exposures / solver stalls / pub-sub interruptions all lapse freshness while guiding remains active — so it could still send a PT offset and move the telescope during active guiding.

Reworked (force-push 754ca53a) to query acamd directly at decision time — ACAMD_ACQUIRE with no args returns { stopped | acquiring | guiding }, which is authoritative and current — and the heartbeat + freshness guard were removed. The PR is now a single-file change in offset_acam_goal.

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.

1 participant