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

TASK A — EE velocity residual: feedback symptom, or something else?

Generated: 2026-06-23 (EDT) · Runs: logs/logs_Jun23_26/full_control_floor_{an,fd}/run/npz/run_PM0523/*.npz Script: validation/nu_e_residual_diagnostic.py (world-frame FD of the logged p_e pair, over _op; both runs) Builds on: nu_e_orthogonality_Jun23.md (the EE-local nu_e error = ~54°, matched magnitude) Question: Is the EE velocity residual Δ = actual − desired a feedback symptom of the p_e lag (a), a velocity deficiency (b), reference FD-noise (c), or dynamic phase-lag (d)?


Answer first

Measured (operational window, medians)

metric analytic (an) FD (fd) reading
n_op 9060 7430 window size
world ‖Δ‖ (m/s) 0.0135 0.0120 velocity residual — tiny both
angle(Δ, p_e) (deg) 90.4 90.9 Δ orthogonal to the lag
along-track Δ (m/s) 0.0002 −0.0002 ~zero speed error
cross-track Δ (m/s) 0.0134 0.0119 residual is heading-only
cross-track fraction 0.994 0.993
‖p_e‖ (m) 0.107 0.106 the standing offset
v_fd / v_log (m/s) 0.8475 / 0.8475 0.846 / 0.846 FD validated (exact)
EE-local nu_e error (m/s) 0.772 0.0135 the A/B that locks it
EE-local nu_e angle (deg) 53.6 0.91 analytic FF mis-aim
Pearson(‖Δ‖,‖p_e‖) 0.45 0.45 weak; not the symptom signature

Why this is airtight (frame-invariant transitivity)

‖Δ‖ is frame-invariant — it cannot be both 0.77 (EE-local) and 0.0135 (world). The reconciliation:

  1. v_fd = v_log to 4 dp ⇒ FD(actual.p_e) and the logged actual.nu_e linear block are the same vector (world vs EE-local view; utils/robot.py:162 nu_e = twist("cam","local")).
  2. ‖FD(actual.p_e) − FD(desired.p_e)‖ = 0.0135FD(desired.p_e) is within 1.6% of FD(actual.p_e) ≈ actual.nu_e.
  3. EE-local: ‖actual.nu_e − desired.nu_e‖ = 0.772 at 53.6°.

desired.nu_e is 54° from actual.nu_e ≈ FD(desired.p_e), i.e. desired.nu_e ≠ d/dt(desired.p_e). ∎

Independent confirmation: in the fd run, desired_nu_e_feedforward_consistent defines desired.nu_e = (p_now − p_prev)/dt (GNC/guidance/ee_guidance.py:225-261). There the nu_e error collapses to 0.91° / 0.0135 — exactly the world-frame Δ. Only the analytic path (ee_guidance.py:267-306) produces the 54° mis-aim.


Decision tree (measured branch marked ✓)

✓ world ‖Δ‖/v < 5%  AND  angle(Δ,p_e) ≈ 90°  AND  EE-local nu_e error ≫ world Δ
      -> (e) HEALTHY tracking + FF INCONSISTENCY: desired.nu_e ≠ d/dt(desired.p_e).
         LEVER: analytic-FF <-> pose-schedule consistency; secondary EE stiffness K_e.
  angle(Δ,p_e) small AND corr(‖Δ‖,‖p_e‖) high AND p_e leads Δ -> (a) feedback symptom
  cross ≫ along AND corr(‖Δ‖,accel-demand) high          -> (d) dynamic phase-lag
  along dominates AND magnitude mismatch                  -> (b) speed deficiency
  Δ larger & corr weaker on fd, accel p99/median huge     -> (c) reference FD-noise
  1. ruled out: angle is 90° not 0°, and Pearson(‖Δ‖,‖p_e‖)=0.45 with Spearman 0.10 — no monotone symptom link. (d) ruled out: cross-track is dominant but corr(‖Δ‖,accel-demand)=0.26 and accel-demand p99/median=1.4 (smooth, not curvature-driven). (c) ruled out: analytic FF (smoother) does not shrink Δ (−12.6%, both ~0.013). (b) ruled out: along-track ≈ 0.

Findings

F1 — EE velocity tracking is healthy (~1.6% residual, cross-track only). Evidence: ‖Δ‖=0.0135, along≈0, v_fd=v_log exact. Impact: the EE follows the commanded pose trajectory’s velocity well; the velocity loop is not the problem.

F2 — p_e is a quasi-static offset, not a dynamic lag. Evidence: Δ ⊥ p_e (90°), ‖Δ‖ ≪ demand. Impact: closing the 2.46×-above-floor p_e gap is a steady-offset problem (stiffness / forcing balance), not a tracking-bandwidth problem.

F3 — The 54° nu_e error is a feedforward inconsistency (the A/B locks it). Evidence: EE-local nu_e error 0.772@53.6° (an) vs 0.0135@0.91° (fd); only desired.nu_e differs between runs; transitivity proof above. Impact: the Jun-23 “heading error” does not measure tracking — it measures desired.nu_e ≠ d/dt(desired.p_e). The earlier framing (“EE-twist tracking is the lever”) is corrected.


Proposed next task

TASK A1 — Why does the analytic FF twist disagree with the pose schedule by 54°? (guidance investigation)

BODY: Trace whether analytic_desired_nu_e_feedforward (ee_guidance.py:267, built from the orbit/standoff geometry via reduced_desired_twist) and the commanded pose trajectory (set_ee_target / consistent_finalize_pose, which sets desired.p_e) reference the same trajectory. The 54° mis-aim means the feedforward velocity and the position schedule are derived from different references. Determine whether desired.nu_e should equal d/dt(desired.p_e) (and is buggy) or is intentionally a different quantity (and the nu_e metric is mis-posed). Modify: none (investigation). Inspect: ee_guidance.py (analytic FF + pose finalize), analytic_feedforward.py (reduced_desired_twist), current_sota.md §3 (POSE guidance). Validation: from-NPZ — overlay d/dt(desired.p_e) vs desired.nu_e per axis; the existing nu_e_residual_diagnostic.py already isolates the gap.

TASK A2 (parallel) — Quantify how much of the p_e-above-floor gap is the FF mis-aim vs stiffness

BODY: With velocity tracking healthy and p_e quasi-static, test whether feeding a consistent FF (the fd definition) lowers p_e toward floor, and/or whether raising K_e does. A/B an vs fd p_e is already logged; compare. Modify: none yet (diagnostic A/B). Validation: analytic_ff_floor_report.py already reports pe_med per run — compare an vs fd.


Provenance