Doctoral Research · Space Robotics Inspection with a Free-Flying Space Manipulator
A Doctoral Research Journal Aerospace Engineering

The New Normal — EE Guidance After Mission-1 Adoption

Generated: 2026-06-10 20:20 EDT (investigator skill, report-only — no code modified) Subject: GNC/guidance/ee_guidance.py under the adopted Mission-1 defaults (commit 64c3905). Supersedes the mode-machine picture in current_state_machine_Jun06.md for default-config runs. Companion result: mission_1_success.md (coverage 0.9990, p_e p99 0.165 m).


Answer First


Scope


What is the new normal? (one paragraph)

At every control step the guidance asks one question — where is the vehicle along its orbit? — and aims the camera at the pre-computed surface path point for that progress (x_surf(s_achieved)), from a fixed 0.275 m standoff sphere around the spacecraft’s center of mass. Achieved progress (not wall-clock time) drives the schedule, so the aim never outruns the vehicle. During the first 90 s (INITIAL), the same aim runs while the controller settles — the existing pose filter slews the camera smoothly from its boot posture to the path, the camera marks coverage the whole time, and a posture term keeps the elbow away from its singular configuration. At step 3000 the mode label flips to TARGETING and nothing else changes — the same aim function serves both phases (:625 vs :639, same orbit_path_pose, different mode argument). The mission ends when achieved progress reaches the end of the helix (~1064 s).

The new state machine

stateDiagram-v2
    direction LR
    [*] --> INITIAL : step 0 (q0 pose seeds the filter)
    INITIAL --> TARGETING : step 3000 (90 s settle elapsed)
    TARGETING --> [*] : orbit progress complete (~1064 s)
    INITIAL : steps 1..2999
    INITIAL : aim at x_surf(progress) + mark coverage
    INITIAL : full-arm posture pull toward q0
    TARGETING : steps 3000..end
    TARGETING : same aim function, same marking
    note right of TARGETING
        no HOLD, no FALLBACK,
        no reselect events
    end note

The transition is scheduled, not decidedstep_idx >= startup.steps_effective (:284-286). Compare the Jun-06 diagram: 4 states and 6 event-driven transitions (score margins, forced reselects, feasibility checks). All of those decisions are gone from the live path.

The logic flow inside set_ee_target (:611)

The function is a four-rung ladder of early returns, read top to bottom. Under mission defaults only the green rungs ever fire after step 0:

flowchart TD
    A["compute q0 default pose<br/>(always, keeps the fallback fresh) :616"]
    A --> B{"aiming during INITIAL<br/>and step >= 1<br/>and still settling? :620"}
    B -- yes --> C["return orbit_path_pose(mode=INITIAL) :625"]
    B -- no --> D{"guidance disabled or<br/>still settling (aim off)? :627"}
    D -- yes --> E["return q0 default pose :635"]
    D -- no --> F{"orbit path enabled? :638"}
    F -- yes --> G["return orbit_path_pose(mode=TARGETING) :639"]
    F -- no --> H["external: legacy reactive machine<br/>(HOLD / TARGETING / FALLBACK, Jun-06 report)"]
    classDef live fill:#d4edda,stroke:#28a745,color:#0f3d1e;
    classDef external fill:#fff3cd,stroke:#d39e00,color:#3d2b00;
    class C,G live;
    class H external;

Mission config: steps 1–2999 exit at the first rung (C); step 3000 onward exits at the third (G). The q0 default (A→E) serves exactly one live step — step 0, which seeds the pose filter at the true end-effector pose so the slew toward the path starts continuously.

Through the class — one step, one straight line

flowchart LR
    A["controller calls<br/>add_ee_goal :174"] --> B["set_ee_target<br/>(ladder above)"]
    B --> C["consistent_finalize_pose<br/>filter + reach clamp"]
    C --> D["write Desired<br/>(p_e, R_e, z_e)"]
    D --> E["external: controller marks<br/>camera FOV coverage :156"]
    classDef external fill:#fff3cd,stroke:#d39e00,color:#3d2b00;
    class E external;

Unchanged from Jun 06 and still the design’s best property: every branch’s pose flows through the same single finalizer (low-pass + rate caps + reach clamp). What changed is the marking gate at the end: it now also marks during INITIAL — but only when the path is aiming (breve_controller.py:156; the “mark iff aiming” contract, ee_guidance.py:30,106).


What happened to the old state machine?

Mode Old role (Jun 06, reactive) New role (Mission-1 defaults)
INITIAL 90 s hold at the boot arm pose; camera aimed at nothing; zero coverage 90 s settle while aiming and marking the dense southern revs (~0.59 coverage by t=60 s)
HOLD the sustained inspection state (40,928/50,000 steps): stare at one chosen surface point unreachable (dormant code)
TARGETING 1-step commit pulse when a new target won the score (69 steps) the sustained state: continuous path-following inspection (~32,500 steps)
FALLBACK safety revert when reselect found nothing (3 steps) unreachable (dormant code)

Why it changed: the reactive machine chose where to look by scoring candidate targets each reselect window. The orbit-path schedule answers that question offline — the path is computed once at construction by projecting the orbit onto the target surface — so the run-time machine has nothing left to decide. The scorer’s coverage instinct (0.998) was matched and exceeded (0.9990) by simply flying the whole schedule and looking the whole time, while the reselect jumps that caused the old tracking spikes (p_e p99 0.404) disappeared outright (0.165).

The Jun-06 report is not wrong — it is now conditional. Flip orbit_path.enable: false and its machine, numbers, and diagrams apply again verbatim; that configuration is retained as the A/B reference arm.


Findings

F1 — Mode semantics inverted: TARGETING is now sustained, HOLD never occurs. Evidence: mission mode histogram INITIAL 3,000 / TARGETING ~32,500 / HOLD 0 / FALLBACK 0 (C4 verdict run); old histogram HOLD 40,928 / TARGETING 69 (Jun-06 report). Impact: any script, plot, or mental model keyed on “HOLD = inspection, TARGETING = rare pulse” silently inverts. The Jun-06 report’s F1 lesson now applies in mirror image. Next step: recorded here; see task T1.

F2 — The repo’s front-door diagram is stale. GNC/CLAUDE_README.md (lines 4-22) still shows the old 4-mode/6-edge machine as “the state machine.” Evidence: compared against ee_guidance.py:611-648 under adopted defaults. Impact: the first thing a new reader (or supervisor) meets contradicts the running system. Next step: task T1 (report-only rule: not edited here).

F3 — set_ee_target carries its own follow-up note. The code comment at :610 (“repeated terminal exits should be helpers”) plus five adoption knobs that imply one another suggest the planned knob-consolidation (single mode enum) would also collapse the ladder’s first two rungs into one. Impact: low — clarity debt, not behavior. Next step: already pinned in tasks/PIN_IT_FOR_LATER.md (knob consolidation).


No code was modified during this investigation (report-only).