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

Sizing the σ₆ floor — a derivation of 0.025 and an audit of the four-layer spread

Date: Jun 12, 2026 (CHAIN_13 task D4; pre-registered bar: tasks/chain13_criteria.md §D4). Question: the controller’s singularity-protection stack uses four thresholds — 0.005, 0.02, 0.025, 0.05 — on one signal, the smallest singular value σ₆ of the arm’s task map. Until now the defense of these numbers was “they worked.” This document replaces that with arithmetic a committee can audit: where 0.025 comes from, which thresholds follow from a single stated budget, which one does not, and what the layer ordering should be.

regen: /Users/antoniahoffman/miniforge3/envs/new-pin-env/bin/python validation/threshold_sizing.py (every number below is printed by that script; constants are commented there with file:line sources).

Verdict up front (against the D4 bar): PASS on both prongs. (i) 0.025 reproduces within stated assumptions — but only against the simulation’s own joint-rate budget (the controller’s explicit ±50 rad/s velocity clip), at the 0.90 m/s cruise demand, with an identified margin of 1.39 ≈ √2. Against the real UR3 datasheet limits the same derivation gives a floor of 0.14–0.57, so 0.025 is a numerics floor, not a hardware floor — stated plainly in §5. (ii) The four-threshold spread reproduces as a family from that one budget — except the Γ-Tikhonov ε = 0.05, the single misfit — so §7 proposes a harmonized set (ε_Γ: 0.05 → 0.025) with the migration cost named, adoption explicitly gated on D2’s attribution verdict.

Vocabulary (derate, DLS, singularity-consistent handling, σ engagement bands) is in wiki/terminology.md; everything else is defined where it appears.


1. The object under study: four layers, one signal

All four layers key on σ₆ — the smallest singular value of the arm’s task map J⁺ (or of the full coordinated map Γ; the two are statistically interchangeable here, Spearman ≥ 0.997 and identical derate decisions, sming_vs_sminj_study.md). Sorted by engagement threshold, descending:

σ₆ threshold layer mechanism source
0.049 Γ-velocity-solve Tikhonov ramps up damping (DLS) GNC/breve_controller.py:498-516; parameters.yaml:75-80
0.025 derate ramp starts (1.0 → 0.25 at 0.005) slowdown (SC) utils/sampling.py:70-78 via GNC/base_guidance.py:124; parameters.yaml:84-87
0.025 kernel freeze (7-DOF only) hard switch utils/robot.py:312-323; parameters.yaml:125
0.02 damped J⁺ inverse starts damping (DLS) utils/robot.py:188-194; parameters.yaml:132-137
0.005 derate saturates at scale 0.25 slowdown floor utils/sampling.py:74-75
0.005 hold-last-healthy J⁺ inverse hard switch utils/robot.py:185-186

Two notational facts verified against the code (they matter for the math):

2. The joint-rate amplification argument (Chiaverini 1997)

Write the task map’s singular value decomposition J = Σᵢ σᵢ uvᵢᵀ. The exact (pseudo-)inverse solution to J q̇ = ẋ is

\[\dot{q} \;=\; \sum_{i} \frac{u_i^{T}\dot{x}}{\sigma_i}\, v_i ,\]

so the component of the commanded task velocity that lies along the weakest output direction u₆ (the “dying direction”) is amplified by 1/σ₆ into joint rate. Worst case — the demand fully aligned with the dying direction —

\[\|\dot{q}\| \;\le\; \frac{v}{\sigma_6}, \qquad v = \text{commanded task speed [m/s]}.\]

Chiaverini’s sizing recipe inverts this: pick the joint rate you can tolerate, q̇_tol, and size the singular-region threshold

\[\boxed{\;\varepsilon \;=\; \frac{v}{\dot{q}_{\text{tol}}}\;}\]

His own worked example (“for the sake of argument”, §VI of the paper): ε = 0.01 means a 0.1 m/s command along the dying direction gives a 10 rad/s joint-velocity norm — i.e., he accepted q̇_tol = 10 rad/s and sized ε accordingly. Holt & Desrochers state the identical principle as prose: “The selection of σ_min should be based on the desired upper bound on the norm of Δθ_d, which in turn is dictated by the saturation limits of the joint-level controller” (NASA N94-26281, §6.1; note this report is staged under the citekey torres1992minimizing — cite it as Holt & Desrochers, never as Torres–Dubowsky, per the study’s §7 source-hygiene alert).

Units: σ₆ of our task map carries m/rad on its translation rows, so v [m/s] / σ₆ [m/rad] = rad/s is dimensionally consistent. We use the translational reading throughout (the conservative one for this arm: the extension wall kills a translation direction).

3. Which joint-rate limit binds — sim vs hardware

The simulation enforces no joint rate limits. Verified in both MuJoCo models: there are no joint velocity limits, and every arm actuator is declared ctrllimited="false" (models/ur3/ur3_box_limited_with_capsules.xml:124-129, models/ur3/ur3_7dof_with_capsules.xml:141-147). The only rate bounds in the loop are the controller’s own guards: the ±50 rad/s clip on the solved generalized velocity (breve_controller.py:511-513, parameters.yaml:78) and the inverse-norm cap ‖J⁻¹‖ ≤ 1000 (parameters.yaml:137).

The real UR3 does enforce limits (Universal Robots datasheet): base, shoulder and elbow at 180°/s = π rad/s; the three wrists at 360°/s = 2π rad/s. At the singularity that actually binds us — the full-extension wall (the reach factor of det J, mission_1_success.md) — the dying direction is radial end-effector translation, which is produced by the shoulder-lift and elbow joints. Those are the slow joints, so π rad/s is the binding hardware number.

So the honest statement, for the defense: in simulation the budget the thresholds must respect is Q = 50 rad/s (the code’s own clip — chosen, not physical); on hardware the budget would be π rad/s, sixteen times tighter, and the answer changes by an order of magnitude (§5).

4. The ε table and the amplification at our floor

ε_min = v / q̇_max, worst-case alignment. Mission speeds: 0.90 m/s is both the orbit cruise speed (parameters.yaml:153, the Phase 00 matched point) and the cap on the commanded end-effector twist (parameters.yaml:116); 0.45 m/s is the 7-DOF record-run speed.

v [m/s] limit q̇_max [rad/s] ε_min ε with margin 2 0.025 / ε_min
0.90 UR3 slow joints π = 3.14 0.286 0.573 0.09× (floor 11.5× too low)
0.90 UR3 wrists 2π = 6.28 0.143 0.286 0.17×
0.90 sim clip Q 50 0.018 0.036 1.39× (floor sits inside [1×, 2×])
0.90 Chiaverini’s q̇_tol 10 0.090 0.180 0.28×
0.45 UR3 slow joints π 0.143 0.286 0.17×
0.45 UR3 wrists 0.072 0.143 0.35×
0.45 sim clip Q 50 0.009 0.018 2.78× (conservative)
0.45 Chiaverini’s q̇_tol 10 0.045 0.090 0.56×

Amplification admitted at our floor (undamped 1/σ at σ₆ = 0.025):

5. Reproducing 0.025 — and the rest of the family — from one stated budget

Assumption set (stated): budget Q = 50 rad/s (the controller’s own clip — the only rate bound that exists in the sim); reference demand v_ref = 0.90 m/s (cruise = twist cap); worst-case alignment of the demand with the dying direction.

Under those assumptions the thresholds fall out of the single inequality v·g(σ) ≤ Q, where g is each layer’s dying-direction gain:

  1. J⁺ soft floor 0.02 — exact. The undamped gain is 1/σ; per unit demand it reaches Q at σ = 1/Q = 0.0200. Damping engages exactly where the raw inverse would exhaust the budget.
  2. Derate onset 0.025 — reproduced with an identified √2 margin. The full-speed demand exhausts the budget at σ_crit = v_ref/Q = 0.90/50 = 0.0180. The configured onset is 0.025/0.0180 = 1.39 ≈ √2 above the critical point: the slowdown begins one conventional rate-headroom factor before saturation, and above the damping onset (0.02), so on the J⁺ side the demand is reduced before the inverse is corrupted. Honesty note: the √2 was identified from the configured value, not pre-registered; the derivation constrains the onset to [σ_crit, 2σ_crit] = [0.018, 0.036] and 0.025 sits mid-band. For the 0.45 m/s runs the same floor carries margin 2.78 — conservative, consistent with the 7-DOF being marginal rather than rate-violating.
  3. Ramp bottom 0.005 — within 10%. At the bottom the derate delivers scale f = 0.25, so the residual demand is f·v_ref; the budget then requires σ_lo ≥ f·v_ref/Q = 0.25·0.90/50 = 0.0045 (configured: 0.005). Below it the hold-last switch freezes the inverse so the gain stops growing — the bottom edge is where the ramp hands off to the hold.
  4. Whole-stack check (script section [5]). Sweeping σ with the derate applied then each inversion: worst case 36.6 rad/s on the J⁺ path (just under the soft floor) and 17.6 rad/s on the Γ path — both inside Q, so the ±50 clip is a true backstop that never engages in the worst case. Remove the derate and the J⁺ path peaks at 54.3 rad/s — over budget: the slowdown layer is load-bearing for the budget, not decorative.
  5. The one misfit: Γ ε = 0.05. The Γ layer’s gain on its engaged branch is g(σ) = σ/(σ² + lam) = σ/ε² ≤ 1/ε = 20 rad/s per m/s. The budget only requires ε ≥ 1/Q = 0.02; the configured 0.05 is 2.5× more conservative than the budget demands, and it starts paying tracking error far above every other layer (§6).

Hardware read-across (the thesis-defense sentence). Against the real UR3’s π rad/s with a factor-2 margin, the floor that protects 0.90 m/s is ε = 0.57 and for 0.45 m/s it is 0.29 — an order of magnitude above 0.025. Conversely, the speed that 0.025 protects on hardware is v ≤ 0.025·π/2 ≈ 0.04 m/s (0.08 m/s with no margin). So: 0.025 is a simulation-numerics floor, sized (consistently) to the solver’s internal 50 rad/s budget; it is not a hardware joint-rate floor. If this controller ever drives a physical UR3, either the floor rises to ~0.14–0.57 or the near-wall speed falls to centimeters per second — the floor and the cruise speed are co-designed quantities, which is exactly Holt & Desrochers’ point in §2. One mitigating unknown, stated rather than assumed away: these are worst-case alignment numbers. The actual fraction of the demand along the dying direction during our entries is measurable offline from the logs (a D2-adjacent follow-up) and would relax the hardware numbers proportionally.

6. The ordering question (required by the bar): who acts first as σ falls?

The pre-registered concern: the Γ-Tikhonov engages at σ ≈ 0.049, above the derate’s 0.025 — in the band [0.025, 0.049) the velocity solve is already damped while the vehicle has not slowed.

How bad is the band, quantitatively? On the engaged branch, lam = 0.05² − σ², so the Tikhonov filter factor (the fraction of the dying-direction demand the solve keeps) is

\[f(\sigma) \;=\; \frac{\sigma^2}{\sigma^2 + \text{lam}} \;=\; \Big(\frac{\sigma}{0.05}\Big)^{2},\]

i.e. the discarded fraction is 1 − (σ/0.05)²: 4% at 0.049, 36% at 0.040, 64% at 0.030, and 75% at 0.025 — the solve is throwing away three quarters of the dying-direction demand at the very moment the derate first begins to slow the vehicle. Discarded demand is not free: by Chiaverini’s eq. (14) the damping injects reconstruction error λ²/(σᵢ² + λ²) into every direction, and a demand component the solve cannot realize becomes tracking error in task space. (Identification worth recording: our Γ schedule lam = max(10⁻⁴, 0.05² − σ²) is exactly Chiaverini’s variable-damping law, his eq. (15), with ε = λ_max = 0.05, plus a constant β² = 10⁻⁴ isotropic floor as in his eq. (20). The layer is textbook — only its ε is out of family.)

The principle says: predictive slowdown first, damping as backstop. The published cost taxonomy (Sone & Nenchev’s SC-vs-DLS comparison, study §4.3) is one sentence: slowing the demand costs only time (schedule lag — the demand stays exactly realizable); damping costs tracking error in task space (speed and direction corrupted). A predictive layer should therefore spend the cheap currency first. The stack already does this on the J⁺ side (derate 0.025 > soft floor 0.02 — and §5.4 showed the derate is precisely what keeps the J⁺ layer inside budget). The Γ layer is the inversion of that ordering.

The case for the current ordering, stated fairly:

Resolution: this is an empirical question we have already pre-registered. D2’s “damping-implicated” rule (tasks/chain13_criteria.md) tests precisely whether band B1 (Tikhonov active, nothing else) carries an outsized share of in-window pointing-error mass. The derivation’s contribution is the prior: the band’s suppression is large near its bottom (75%), textbook-shaped, and 2.5× more conservative than the rate budget requires — so if D2 fires, the fix is principled and already sized (§7); if D2 does not fire, the band is empirically harmless and the current ordering stands at zero cost.

7. The harmonized set — and its migration cost, named

If a change is ever warranted, the family that makes all four layers consistent with the one budget (Q = 50 rad/s, v_ref = 0.90 m/s) is:

knob current harmonized rationale
Γ-Tikhonov ε (gamma_regularization.floor) 0.05 0.025 onset drops to √(0.025² − 10⁻⁴) ≈ 0.023: nothing damps before the vehicle has begun to slow; gain cap becomes 1/ε = 40 ≤ Q; ordering becomes monotone slow → damp → hold
derate high 0.025 0.025 (keep) = √2 · v_ref/Q (§5.2)
J⁺ soft floor 0.02 0.02 (keep) = 1/Q exactly (§5.1)
derate low / J⁺ hard floor 0.005 0.005 (keep) = f·v_ref/Q within 10% (§5.3)
freeze floor (7-DOF) 0.025 0.025 (keep) rides the derate onset; it is a basis-continuity guard, conditioning-neutral

Migration cost (real, and why we do not move now). Changing ε_Γ alters the velocity solve on every step with σ₆ < 0.049 — for the saturated 6-DOF incumbent that is most of the mission. Every trajectory diverges from the first affected step, so all five byte-identical validators break by construction, forcing a deliberate re-pin of the pinned baselines (m7_on_s45_freeze.npz, the 8 Phase 00 npz as comparison points) — and the standing rule is at most ONE deliberate re-pin per chain (pre_risk.md §3b), each requiring full-helix A/B plus ±2% probes first. The D2 band definitions (the B0/B1 edge at 0.049) move with it, breaking cross-chain comparability of every band statistic, and the CHAIN_10 forensics tables become historical record. That is a large bill to pay against an unquantified harm. Recommendation: record the harmonized set here as the principled target; adopt only if D2’s damping-implicated rule fires, riding the already-registered directional-filtering follow-up with its own A/B and the chain’s single re-pin. No code or config changes in this chain (per the D4 bar).

8. Placing 0.025 on Holt & Desrochers’ two-sided trade-off

Their warning is two-sided: a threshold too small lets the commanded step drive the arm through the singularity and oscillate between configuration branches (“chattering”, their §8); too large wastes tracking and speed — at their σ_min = 0.1 the control near the workspace boundary went weak a full 30° from the singular point, and their conclusion 3 concedes “unavoidable tracking error in the forbidden directions.” (Absolute σ values do not transfer between robots — different scales, different units — so we place ourselves by measured behavior, not by comparing 0.025 to their 0.1.)

Placement, in one sentence: 0.025 sits at the budget-consistent point for the simulation (§5), pays its “too-large” cost only where geometry forces it, and exhibits the “too-small” risk only as switch transients at the band edges — which is an argument about switch smoothness (L4), not about the value 0.025.

9. Assumptions and limitations (read before citing)

  1. Worst-case alignment (demand fully along the dying direction) throughout. The measured alignment fraction during real entries is not in the phase00 npz; computing it offline from logged q and the demand vector is the natural D2-adjacent follow-up and can only relax these numbers.
  2. σ units are mixed (m/rad translation rows, dimensionless rotation rows); the translational reading is used, which is the relevant one for the extension wall.
  3. The √2 margin in §5.2 was identified, not pre-registered — the honest claim is “0.025 is consistent with the stated budget, mid-band in [0.018, 0.036]”, not “0.025 is uniquely derived.”
  4. Q = 50 rad/s is itself a chosen constant (parameters.yaml:78), not physics. The family is internally consistent with it; the hardware columns of §4 show what physics would say.
  5. Demand bound v_ref = 0.90 m/s rests on the cruise speed (parameters.yaml:153) and the commanded-twist cap (parameters.yaml:116) sharing that value.

10. References

regen: /Users/antoniahoffman/miniforge3/envs/new-pin-env/bin/python validation/threshold_sizing.py