guidance_rollout — guidance-only rollout (no controller dynamics)

Purpose

Roll the guidance tower forward over the orbit windows without running the controller or robot
dynamics: a cheap coverage/selection oracle. A fake motion state stands in for the plant —
desired CoM/base motion plus the previous step’s desired EE command — so the loop never asks for a
wrench, an integration, or a dynamics cache.

Role in the system

  • Module-level functions, not a class — drives an ee_guidance instance (EEGuidancebase_guidancecom_guidance) directly.
  • Called by analysis/runner.py, which orchestrates BOTH this fast path and the full dynamics path through breve_controller.
  • Counterpart to breve_controller’s per-step loop: same add_ee_goal / FOV-marking calls, but the plant is faked instead of integrated.
  • Runs the live candidate selection + FOV-marking each step (no offline schedule sweep).

Inputs / Outputs

  • In: a traj (EEGuidance) with a target_finder enabled, cfg, an orbit-window range (start_idx/end_idx), and optional step / time caps (steps, debug_time_limit).
  • Out: a Package(logger=…, log_path=None) — the per-step StepLogs carrying desired pose, guidance diagnostics, and inspection.area_coverage_frac. No NPZ is written.

Key methods

  • build_guidance_only_rollout — the loop: resolve windows → walk arclength at desired_speed → sample CoM/base/EE goal → mark FOV every stride → log — GNC/guidance/guidance_rollout.py:90
  • guidance_fake_motion_state — fake plant: desired base motion carrying the previous desired EE command — :60
  • append_guidance_payload — assemble + append the StepLog (desired + guidance + coverage) — :72
  • _sample_nominal_com — desired CoM (p, v, a) from arclength progress; v = speed·t̂, a = speed²·κ:45
  • _resolve_guidance_windows — slice the assembled orbit windows; raises if none / out of range — :16
  • VISIBILITY_MARK_STRIDE = 5 — FOV-marking stride (module constant, :13).

Footguns

The motion state is faked, not simulated

The EE pose comes from the previous desired command (guidance_fake_motion_state copies
des_prev’s p_e/z_e/R_e/nu_e), never from a dynamics solve. This path studies selection and
coverage in isolation
— it is NOT a controller validation and says nothing about tracking error or
the derate stack. (GNC/INSIGHTS.md guidance_rollout)

Warning

Marking raycast cost is dominated by ~6–14 ms per-call overhead (not ray count), so a short
VISIBILITY_MARK_STRIDE is the real speedup — the camera moves negligibly across a few 100 Hz steps,
so coverage still reaches ~1.0 (legacy used 10). Marking resolution is a separate, orthogonal knob
(camera.resolution, independent of scoring.pixel_distance_max). (GNC/INSIGHTS.md guidance_rollout)

Coverage is a traversal artifact, not a tuning knob

area_coverage_frac is driven by how far the CoM sweeps the helix, not by selection. A short run only
covers the southern cap (~0.47) and looks like a plateau; the full helix reaches 1.0. Size the rollout
by progress-to-completion, not step count. (GNC/INSIGHTS.md Coverage marking)

Pseudocode (one rollout)

windows = resolve(traj, start_idx, end_idx)      # raise if none
reset progress to window start; n_steps from orbit_duration / dt (capped)
for k in range(n_steps):
    s        = min(k·dt · desired_speed, s_end)  # arclength clock
    progress = interp(s) over the window
    des_com  = sample CoM (p, v=speed·t̂, a=speed²·κ)
    des_base = sample_base_goal_on_interval(des_com)
    fake     = guidance_fake_motion_state(des_base, des_prev)   # carry prev EE command
    des      = traj.add_ee_goal(fake, des_base, des_prev)
    if k % VISIBILITY_MARK_STRIDE == 0 and pose valid:
        target_finder.compute_triangle_camera_visibility(CameraPose(des))
    append_guidance_payload(logger, des)
    des_prev = des.copy()
return Package(logger, log_path=None)

Equations & references

Key equation mirrored from current_sota — the math source of truth; see there for derivations.

Nominal CoM kinematics at step (tangent + centripetal) — §5.2, eq (5.3):

References:

  • CoM reference kinematics (v = speed·t̂, a = speed²·κ) and the arclength clock follow the guidance sheet — see current_sota §5 and com_guidance.
  • Coverage / pointing metrics (§7): the per-triangle FOV marking it drives lives in target_finder; the versine metric lives in the measurement layer, not here.

ee_guidance · base_guidance · com_guidance · target_finder · breve_controller · guidance_classes · terminology · orbit_com_path