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

Mission 1 Success — full-coverage inspection within the tracking budget

Jun 10, 2026 · branch base-wobble · verdict commit ac1e3dd · figure generated_reports/GNC/c4_chain5_verdict_Jun10.png

Headline: area coverage 0.9990 AND p_e p99 0.1654 m in ONE configuration, at orbit-progress completion (t = 1064.5 s). This is the first configuration to pass both mission gates (coverage ≥ 0.99, p_e p99 < 0.2) simultaneously — the reactive scorer gave 0.998 / 0.404, the original orbit-path gave 0.168 / 0.822. The winning configuration: orbit-synced EE aim driven by achieved orbit progress, camera aiming from t = 0 (through the startup window), arm joints clipped to an engineered envelope, and a full-arm posture pull toward q0 during INITIAL. Chain records: daily_log/Jun10_26/CHAIN_{3,4,5}.md; decision log: high_level_plans/decisions.md.


1 · Model flaws to address (for the weekly report)

  1. Joint limits were never enforced. The XML declared ranges but no mechanism applied them — the integrator (pin.integrate) ran unconstrained. Now fixed by simple clipping (CC_Controller._enforce_arm_joint_limits, gated). Caveat: clipping is an inelastic stop, not contact dynamics; the NLOPT/capsule paradigm remains the high-fidelity successor.
  2. The XML ranges themselves are artifacts. ur3_box_limited_with_capsules.xml carries task-restricted values from its source (asymmetric, e.g. wrist_1 [−3.665, 0.524]) — the real UR3 is ±360°/joint. The nominal GNC exceeded them constantly (wrist_1 out-of-range 75% of path-mode steps; reactive shoulder 39–42%). Replaced by a data-derived engineered envelope (healthy-regime support ± 0.15 rad, ∩ ±2π, singularity fences) — defensible as a software joint envelope, but the thesis should state the provenance plainly.
  3. shoulder_pan WINDS. Tracking the 30-rev helix turns the pan continuously (up to ~3 revs in the unconstrained census; 0.89 net revs in the mission run). A real UR3 (±2π) cannot wind indefinitely — clipping is the wrong mechanism for a winding joint (it would break tracking at a known orbit phase). Pan is EXEMPT from the envelope; an unwind strategy or base-yaw allocation is an open design item.
  4. The derate-singularity lock-in (now fixed, worth documenting). The conditioning derate can trap the arm ON a singular family: singular → gains derated → arm can’t move → stays singular. It pinned the elbow at q3 = −π for entire runs and slowed the whole vehicle ~3.6× through the regularized, velocity-clipped Γ-reconstruction. Fix = envelope fences (elbow cannot reach the sinθ₃ = 0 family) + the INITIAL posture pull (keeps it off the fence entirely: wall contact 0.000 in the mission run).
  5. The residual reach/shoulder singular factor (open, structural). With the elbow healthy, s_min_J still spends 0.64–0.80 of the mission below the derate floor (the reference itself runs 0.32) — the R(θ) factor of det(J_arm) = R·sinθ₃·sinθ₅. Tracking is excellent despite it (the derate does load-bearing work), but the robustness margin is thin. Next levers: operational weak full-arm posture, the reach-margin corridor, or kinematic redundancy (7-DOF — a formulation change). This is the number a committee will poke.
  6. The 12 s structural mode. ω ≈ 0.52 rad/s underdamped base-arm eigenmode (TASK_8), only attenuated (integral off since Jun 6). Note: CHAIN_4’s apparent “4× damping from aiming” was a measurement confound (a derate-frozen arm cannot excite the base); with a healthy arm, aiming is wobble-neutral (mission run: 12 s amplitude 0.55° vs reference 0.81°).

2 · Code changes (all gated-OFF at introduction; adoption flips defaults — see §4)

CHAIN_3 — progress-synced aim (commits 804bf9b…627dce8, ee02a64): - GNC/guidance/orbit_path.pyapply_aim_override hook (unused; detour-planner era). - GNC/guidance/ee_guidance.pyorbit_path_pose evaluates at _current_progress() · sample_spacing when orbit_path.progress_sync (the open-loop step·dt·v_des clock skipped the 90 s startup band and outran the derated COM by up to 118 m — the entire 0.822 coverage story; appendage-standoff was a correlate, not a mechanism). - GNC/breve_controller.py — coverage-marking gate relaxed during INITIAL (path mode). - GNC/guidance/detour_planner.py — visibility predictor (the offline coverage oracle; its calibration falsified the detour premise and survives as reusable infrastructure).

CHAIN_4 — aim during INITIAL (commits 8f43e6e, 8eadd39, a053f46, 62c4a2e): - GNC/guidance/ee_guidance.pyaim_during_initial knob; the INITIAL aim branch in set_ee_target (step ≥ 1; step 0 seeds the pose filter at the true EE pose → t = 0 continuity with NO new blend code — the existing filter caps do the slew); orbit_path_pose(mode=…) kwarg + kinematic R_prev fallback; mark_during_initial retied to “mark iff aiming”.

CHAIN_5 — joint limits + posture (commits 804bcef, cccb283, 82f96f7, ac1e3dd): - GNC/com_controller.py_enforce_arm_joint_limits (clip + outward-velocity zeroing) called after pin.integrate, knob constraints.arm.joint_limits.enforce; _resolve_arm_joint_limits (config lower/upper override with fail-loud validation, model-tail fallback). One real bug found post-commit and fixed: st.v is a column in the Breve loop — stub-TDD had assumed flat. - GNC/breve_controller.pyposture.initial_full_arm: lifts the joint6-only mask during INITIAL (full-arm pull toward q_arm_ref = q0) with initial_gain_scale. - YAMLs_by_domain/parameters.yaml — the engineered envelope (joint_limits.lower/upper): elbow [−2.891, −0.250] (sinθ₃ fences δ = 0.25; trades 19% of unconstrained excursions), pan exempt (±1e6, winding), wrist_3 widened to ±π (no singularity role).

Validation infrastructure added (validation/): test_progress_sync.py, test_initial_aim.py, test_joint_limits.py (16 unit tests total), detour_predict_calibration.py (offline oracle), d1_marking_instrumented.py, d2_full_helix_setdiff.py, d3_branch_probe.py (diagnostics), p2_progress_sync_diag.py, g1_progress_sync_verdict.py, k1_initial_aim_predict.py, k3_initial_aim_stability.py, c3a_clip_census.py, c3b_lockin_retest.py, c3c_envelope_derivation.py, c4_chain5_verdict.py, wobble_pe_correlation.py (CHAIN_2 gate).

3 · Decisions made along the way (and their evidence)

4 · Adopted configuration (this commit — defaults now ON)

YAMLs_by_domain/parameters.yaml: camera_guidance.trajectory.orbit_path.enable: true, orbit_path.progress_sync: true, orbit_path.aim_during_initial: true, constraints.arm.joint_limits.enforce: true, controller.base.posture.initial_full_arm: true, and simulation.time.duration: 1100 (the mission completes orbit progress at ~1064.5 s; runs should be sized by progress-to-completion, not wall time). The five pinned baselines were deliberately re-pinned at the adopted defaults. Historical note: pre-adoption reference numbers (0.404/0.168/0.822/0.874 etc.) were measured under the old defaults; the verdict scripts that set their own knobs remain reproducible.

5 · Decisions still open (yours)

  1. Reach/shoulder singular factor strategy — operational weak full-arm posture vs reach-margin corridor vs 7-DOF. The derate residual (0.64–0.80) is the thesis-defense soft spot.
  2. Pan unwind / base-yaw allocation design (model-fidelity item #3).
  3. NLOPT + capsule avoidance paradigm — when (if) to supersede simple clipping.
  4. Knob consolidation — five booleans → one mode enum (PIN_IT_FOR_LATER).
  5. wrist_2 (θ₅) fence — report-only finding: its envelope lower edge overlaps the sinθ₅ = 0 fence but the data never approaches it; cut it formally or leave documented.
  6. p_e ambition — the gate passes at 0.165; the “ideal < 0.1” target would need the reselect/ lag architecture work (p_e median is velocity-lag; p99 0.165 is the new shape to study).
  7. Log-directory dedupetasks/daily_log/{Jun08,Jun09,Jun10}_26/* duplicate the canonical root daily_log/; daily_log/Jun09_26 copy/ should fold into daily_log/Jun09_26/ (deferred twice, awaiting your OK to delete).