Purpose. This is the single digest chapter for the 7-DOF redundant extension of the Giordano circumcentroidal coordinated controller. It supersedes the four scattered source documents as the entry point and links each one for depth: -
generated_reports/math/derivation_7dof_eli5.md— beginner tutorial with a 1-D toy. -generated_reports/math/derivation_7dof.md— annotated derivation + intuition layer. -generated_reports/math/dynamics_modifications_7dof.md— formal ledger (M1–M5, Props 1–4, Theorem 1, Lemma 1). -GNC/Framing_Paper_coordinated_control/seven_dof_redundant_extension.md— roadmap of augmentation strategies + the four proof obligations. -generated_reports/math/review_7dof.md— external referee review carrying the blocking issue R1.Equation numbers in parentheses (e.g. eq. 19) refer to the base paper
GNC/Framing_Paper_coordinated_control/coordinated_control.md(the corrected n=6 Giordano circumcentroidal reference). Every equation inline below is quoted verbatim from those documents; nothing has been invented.
The whole project rests on a single change of coordinates. The controller does not steer the motors directly; it steers a mission description of the motion and then translates back to motor commands. Write what the motors do as the native (motor-space) velocity vector
\[\boldsymbol{x} = \begin{bmatrix} \boldsymbol{v}_b \\ \boldsymbol{\omega}_b \\ \dot{\boldsymbol{q}} \end{bmatrix}\]
where \(\boldsymbol{v}_b \in \mathbb{R}^3\) is the base linear velocity, \(\boldsymbol{\omega}_b \in \mathbb{R}^3\) is the base angular velocity (spin), and \(\dot{\boldsymbol{q}} \in \mathbb{R}^n\) are the joint rates. Write what the mission cares about as
\[\boldsymbol{z} = \begin{bmatrix} \boldsymbol{v}_c \\ \boldsymbol{\omega}_b \\ \boldsymbol{\nu}_e^\oplus \end{bmatrix}\]
where \(\boldsymbol{v}_c \in \mathbb{R}^3\) is the velocity of the robot-system center of mass (CoM), \(\boldsymbol{\omega}_b \in \mathbb{R}^3\) is again the base spin, and \(\boldsymbol{\nu}_e^\oplus \in \mathbb{R}^6\) is the end-effector (EE) motion expressed about the CoM (the circumcentroidal twist). The translator between them is the velocity transform (eq. 19),
\[\boldsymbol{z} = \boldsymbol{\Gamma}\boldsymbol{x}, \qquad \boldsymbol{x} = [\boldsymbol v_b; \boldsymbol\omega_b; \dot{\boldsymbol q}] \in \mathbb R^{6+n}, \quad \boldsymbol z = [\boldsymbol v_c; \boldsymbol\omega_b; \boldsymbol\nu_e^\oplus] \in \mathbb R^{12}, \quad \boldsymbol\Gamma \in \mathbb R^{12\times(6+n)}.\]
For a non-redundant 6-joint arm (\(n=6\)), \(\boldsymbol{x}\) has 12 entries and \(\boldsymbol{\Gamma}\) is square \(12\times 12\) and invertible: there are 12 knobs and 12 dials, so each mission demand \(\boldsymbol{z}\) maps to exactly one motor command \(\boldsymbol{x}\). Adding a 7th joint (\(n=7\)) gives 13 knobs but still only 12 dials. The map \(\boldsymbol{\Gamma} \in \mathbb{R}^{12\times 13}\) is wide, “invert” is no longer well-posed, and infinitely many \(\boldsymbol{x}\) produce the same \(\boldsymbol{z}\) — they differ by a one-dimensional self-motion.
The toy intuition (1-D rail). Strip the system to a base mass \(M\) on a frictionless rail with two point-mass links \(m_1, m_2\). The transform collapses to a \(2\times 3\) matrix (here \(m_t = M + m_1 + m_2\)):
\[\underbrace{\begin{bmatrix} v_c \\ \nu_e \end{bmatrix}}_{\boldsymbol z}=\underbrace{\begin{bmatrix} 1 & \tfrac{m_1+m_2}{m_t} & \tfrac{m_2}{m_t} \\ 1 & 1 & 1 \end{bmatrix}}_{\boldsymbol\Gamma\ (2\times 3)}\underbrace{\begin{bmatrix} v_b \\ \dot q_1 \\ \dot q_2 \end{bmatrix}}_{\boldsymbol x}.\]
Two outputs, three inputs: one spare knob. Solving \(\boldsymbol{\Gamma}\boldsymbol{x} = \boldsymbol{0}\) (move the motors while keeping both mission outputs at zero) gives the self-motion
\[\boxed{\ \dot q_1 = M+m_1, \qquad \dot q_2 = -M, \qquad v_b = -m_1\ }\]
Read it physically: the arm reconfigures (\(\dot q_1, \dot q_2 \neq 0\)) while the base counter-translates at \(v_b = -m_1\) — proportional to the mass that is swinging — so the system CoM never moves and the EE stays put. The arm shuffles internally; the world sees nothing.
Moral. A 7th joint buys exactly one self-motion: the arm swings along a Jacobian null direction while the base counter-translates to freeze the CoM (and attitude and EE), at zero primary-task cost. The 7-DOF project is to (1) find that self-motion, (2) give it a speedometer, and (3) damp it.
The EE-about-CoM block of \(\boldsymbol{\Gamma}\) is the
circumcentroidal Jacobian (eq. 14), in code dyn.J_plus, a
\(6\times 7\) matrix for \(n=7\). Take its full singular value
decomposition,
\[\boldsymbol{J}_{\nu_e}^\oplus = \boldsymbol{U}\,\boldsymbol\Sigma\,\boldsymbol{V}^T,\]
with \(\boldsymbol{U}\in\mathbb{R}^{6\times 6}\), \(\boldsymbol{V}\in\mathbb{R}^{7\times 7}\), singular values \(\sigma_1 \geq \dots \geq \sigma_6 \geq 0\). The arm null direction is the last column of \(\boldsymbol{V}\):
\[\hat{\boldsymbol n} \;=\; \boldsymbol V\text{'s last column}, \qquad \boldsymbol{J}_{\nu_e}^\oplus\,\hat{\boldsymbol n} = \boldsymbol 0, \qquad \|\hat{\boldsymbol n}\| = 1.\]
Here \(\hat{\boldsymbol
n}\in\mathbb{R}^7\) is the joint-rate direction that produces
no EE motion about the CoM. The smallest singular value \(\sigma_6\) (code s[5]) becomes
the redundant arm’s new distance to singularity: \(\sigma_6 > 0\) means the arm still spans
all six EE directions while having the spare self-motion.
Economy-SVD trap (verbatim caveat).
np.linalg.svd(J, full_matrices=False)returns only the first six columns of \(\boldsymbol{V}\) and silently omits the kernel; you must usefull_matrices=Trueto obtain \(\hat{\boldsymbol n}\). This trap was hit in code.
To lift \(\hat{\boldsymbol n}\) from the arm to the whole 13-dimensional system, solve \(\boldsymbol{\Gamma}\hat{\boldsymbol k}=\boldsymbol 0\) row-block by row-block against the structure of eq. 19:
\[\boldsymbol{\Gamma} =\begin{bmatrix}\boldsymbol{R}_{cb} & -\boldsymbol{R}_{cb}[\boldsymbol{p}_{bc}]^\wedge & \boldsymbol{R}_{cb}\bar{\boldsymbol{J}}_v \\ \boldsymbol{0} & \boldsymbol{E} & \boldsymbol{0} \\ \boldsymbol{0} & \boldsymbol{G}_{\omega_b} & \boldsymbol{J}_{\nu_e}^\oplus\end{bmatrix} \begin{matrix} \leftarrow v_c \text{ row} \\ \leftarrow \omega_b \text{ row} \\ \leftarrow \nu_e^\oplus \text{ row} \end{matrix}\]
The \(\boldsymbol{\omega}_b\) row forces \(\boldsymbol{\omega}_b = \boldsymbol 0\); the \(\boldsymbol{\nu}_e^\oplus\) row forces \(\dot{\boldsymbol q} = \alpha\,\hat{\boldsymbol n}\); the \(\boldsymbol{v}_c\) row then forces \(\boldsymbol{v}_b = -\bar{\boldsymbol J}_v\,\dot{\boldsymbol q}\). The result is the full-system kernel basis:
\[\boxed{\;\hat{\boldsymbol k} \;=\; \begin{bmatrix} -\bar{\boldsymbol J}_v\,\hat{\boldsymbol n} \\ \boldsymbol 0_3 \\ \hat{\boldsymbol n} \end{bmatrix} \in \mathbb{R}^{13}, \qquad \boldsymbol\Gamma\,\hat{\boldsymbol k} = \boldsymbol 0\;}\]
where \(\bar{\boldsymbol J}_v \in \mathbb{R}^{3\times 7}\) (eq. 7) is the mass-weighted average linear Jacobian. The top block \(\boldsymbol{v}_b = -\bar{\boldsymbol J}_v\hat{\boldsymbol n}\) is the toy’s \(v_b = -m_1\) generalized: the base counter-translates by exactly the mass-weighted arm motion, so the CoM stays frozen.
Moral. \(\hat{\boldsymbol k}\) is the elbow orbit written in system coordinates: arm along \(\hat{\boldsymbol n}\), base counter-translating, attitude and EE untouched.
To reuse the existing inversion machinery we append one row \(\boldsymbol z_a^T\) to \(\boldsymbol\Gamma\), making it square. The new row defines a null-space velocity coordinate \(v_n\), and the augmented map is invertible iff that row “sees” the self-motion:
\[\begin{bmatrix} \boldsymbol{v}_c \\ \boldsymbol{\omega}_b \\ \boldsymbol{\nu}_e^\oplus \\ v_n \end{bmatrix} = \underbrace{\begin{bmatrix} \boldsymbol{\Gamma} \\ \boldsymbol{z}_a^T \end{bmatrix}}_{\boldsymbol{\Gamma}_a \in \mathbb{R}^{13\times 13}} \boldsymbol{x}, \qquad \boldsymbol{\Gamma}_a \text{ invertible} \iff \boldsymbol{z}_a^T\hat{\boldsymbol{k}} \neq 0 .\]
The roadmap (seven_dof_redundant_extension.md)
considered three choices for \(\boldsymbol
z_a^T = [\boldsymbol 0\ \ \boldsymbol 0\ \ \boldsymbol Z]\) with
\(\boldsymbol Z\in\mathbb{R}^{1\times
7}\):
\[\boxed{\;\boldsymbol z_a^T = \frac{\hat{\boldsymbol k}^T\boldsymbol M}{\hat{\boldsymbol k}^T\boldsymbol M\hat{\boldsymbol k}}\;}\]
where \(\boldsymbol M \in \mathbb{R}^{13\times 13}\) is the generalized inertia matrix (eq. 4). This is normalized so the row reads unity on one unit of pure self-motion:
\[v_n = \boldsymbol z_a^T\boldsymbol x, \qquad \boldsymbol z_a^T\hat{\boldsymbol k} = 1.\]
Why the inertia-weighted row wins. Because \(\boldsymbol M\) is symmetric positive definite (SPD) and \(\hat{\boldsymbol k}\neq\boldsymbol 0\), the denominator
\[\hat m_n = \hat{\boldsymbol k}^T\boldsymbol M\hat{\boldsymbol k} \;(>0)\]
is twice the kinetic energy of the self-motion at unit amplitude — strictly positive everywhere \(\boldsymbol{J}_{\nu_e}^\oplus\) has full row rank. So \(\boldsymbol z_a^T\hat{\boldsymbol k} = 1 > 0\) always: no algorithmic singularity, unlike the extended-Jacobian choice. This is the dynamically-consistent construction of the Khatib (1987) / Ott (2008) lineage; geometrically, the section \(\{v_n = 0\}\) is the horizontal subspace of the mechanical connection (Marsden–Montgomery).
Moral. Three valid ways to pick the 13th row; only the inertia-weighted one never breaks on \(\Omega\) and decouples the self-motion’s kinetic energy from the task. It is the speedometer that reads the system’s energy, not an arbitrary joint combination.
The full posture-regulating null law proposed in the roadmap and ledger is
\[u_n = -k_n\tilde x_n - d_n v_n, \qquad V \mathrel{+}= \tfrac12\hat{m}_n v_n^2 + \tfrac12 k_n\tilde{x}_n^2\]
where \(u_n\) is the scalar generalized force dual to \(v_n\), \(k_n>0\) a posture stiffness, \(\tilde x_n\) a null-coordinate error, \(d_n>0\) a damping gain, and \(V\) the Lyapunov function. The currently studied special case sets the stiffness to zero — damping only — to merely suppress the self-motion:
\[\hat m_n\dot v_n + c(\cdot) = u_n,\quad \hat m_n = (\hat{\boldsymbol k}^T\boldsymbol M\hat{\boldsymbol k})^{-1} > 0,\quad u_n = -d\,v_n,\quad |v_n| = O(1/d),\quad d\to\infty \Rightarrow \{v_n=0\}.\]
As the damping \(d\to\infty\), the closed loop collapses onto the invariant manifold \(\{v_n=0\}\), on which reconstruction equals the augmented solve.
Moral. Suppression is the high-damping limit of the full posture law. The damper \(d_n>0\) is precisely what was missing in hardware (see S4) — without it the self-motion does not decay.
The ledger (dynamics_modifications_7dof.md) records what
changed and what stayed byte-identical. The headline discipline:
everything is gated behind a knob, and the 6-DOF path is a
structural no-op (when the robot has 6 joints the kernel
objects \(\hat{\boldsymbol n},
\hat{\boldsymbol k}, \boldsymbol z_a\) are
None).
| ID | What changed | Status |
|---|---|---|
| M1 | \(\boldsymbol\Gamma\) becomes \(12\times 13\). Dimension-generic
(dyn.Gamma, built with self.n). |
Implemented; “no code change” oversold — an audit (R9) found two
hardcoded 12s → self.nv. |
| M2 | Singularity-free region \(\Omega =
\{\,\sigma_{\min}(\boldsymbol J_{\nu_e}^\oplus) > 0\,\}\);
smallest SV is now \(\sigma_6\) of a
wide matrix. Maps to dyn.s_min_J. |
Implemented. |
| M3 | damped_inverse wide branch = Moore–Penrose
pseudoinverse \(\boldsymbol{J}^{+} =
\boldsymbol{V}_6\,\boldsymbol\Sigma^{-1}\boldsymbol{U}^T \in
\mathbb{R}^{7\times 6}\) from economy-SVD factors; square branch
bit-for-bit unchanged. |
Implemented (healthy branch). |
| M4 | Augmented reconstruction (eq. 34d replacement): \(\begin{bmatrix} \boldsymbol\Gamma \\ \hat{\boldsymbol z}_a^T \end{bmatrix}\boldsymbol x = \begin{bmatrix} \boldsymbol y \\ 0 \end{bmatrix}\), with \(\hat{\boldsymbol z}_a = \boldsymbol z_a/\|\boldsymbol z_a\|\) (row-normalized for numerical hygiene; RHS is zero). | Implemented in reconstruct_generalized_velocity. |
| M5 | Kernel objects exposed: dyn.k_hat,
dyn.z_a, plus reduced matrices dyn.M_breve,
dyn.C_breve. |
Implemented. |
What stayed: the force map \(\boldsymbol F = \boldsymbol\Gamma^T \boldsymbol
G\) (eq. 20) is untouched — no null-space force is
injected (consistent with operating on the \(v_n=0\) section, where there is no ghost
state to actuate). All five pinned 6-DOF baselines reproduce at \(0.000\mathrm{e}{+}00\). A later mitigation
knob, null_space.freeze_floor (default \(0.025\)), freezes the basis \((\hat{\boldsymbol n}, \hat{\boldsymbol k},
\boldsymbol z_a)\) at the last healthy value below the floor (see
S5).
Each is stated here with proof status; full proofs
live in dynamics_modifications_7dof.md.
Proposition 1 (self-motion basis). On \(\Omega\), \(\ker(\boldsymbol\Gamma)\) is one-dimensional, spanned by \(\hat{\boldsymbol k} = [-\bar{\boldsymbol J}_v\hat{\boldsymbol n};\ \boldsymbol 0_3;\ \hat{\boldsymbol n}]\). PROVED (block-row substitution both directions; rank-nullity closes it). Numerically verified \(\|\boldsymbol\Gamma\hat{\boldsymbol k}\| < 10^{-10}\) across random configs.
Proposition 2 (block right-inverse). The block formula \[\boldsymbol\Gamma^{-R} = \begin{bmatrix} \boldsymbol R_{bc} & [\boldsymbol p_{bc}]^\wedge + \bar{\boldsymbol J}_v\boldsymbol J^{+}\boldsymbol G_{\omega_b} & -\bar{\boldsymbol J}_v\boldsymbol J^{+} \\ \boldsymbol 0 & \boldsymbol E & \boldsymbol 0 \\ \boldsymbol 0 & -\boldsymbol J^{+}\boldsymbol G_{\omega_b} & \boldsymbol J^{+} \end{bmatrix} \in \mathbb R^{13\times 12}\] satisfies \(\boldsymbol\Gamma\,\boldsymbol\Gamma^{-R} = \boldsymbol E_{12}\). It is a right inverse, not a left inverse: \(\boldsymbol\Gamma^{-R}\boldsymbol\Gamma\) is the projector along \(\mathrm{span}\{\hat{\boldsymbol k}\}\), with arm block \(\boldsymbol J^{+}\boldsymbol J_{\nu_e}^\oplus = \boldsymbol E_7 - \hat{\boldsymbol n}\hat{\boldsymbol n}^T\). PROVED; verified \(\|\boldsymbol\Gamma\boldsymbol\Gamma^{-R} - \boldsymbol E_{12}\| < 10^{-8}\).
Proposition 3 (well-posedness). On \(\Omega\), \(\boldsymbol\Gamma_a = [\boldsymbol\Gamma;\ \hat{\boldsymbol z}_a^T]\) is invertible. PROVED: if \(\boldsymbol\Gamma_a\boldsymbol x = \boldsymbol 0\), the first 12 rows + Prop 1 give \(\boldsymbol x = \alpha\hat{\boldsymbol k}\); the last row forces \(\alpha = 0\) since \(\hat{\boldsymbol z}_a^T\hat{\boldsymbol k} = 1/\|\boldsymbol z_a\| > 0\).
Theorem 1 (inertial decoupling — the hard half of P1). Writing \(\boldsymbol\Gamma_a^{-1} = [\boldsymbol c_1 \cdots \boldsymbol c_{12} \mid \boldsymbol c_{13}]\), every task basis velocity is M-orthogonal to the self-motion: \[\boldsymbol z_a^T\boldsymbol c_i = 0 \quad\Longrightarrow\quad \hat{\boldsymbol k}^T\boldsymbol M\,\boldsymbol c_i = 0 \quad (i\le 12), \qquad \boldsymbol c_{13} = \|\boldsymbol z_a\|\,\hat{\boldsymbol k}.\] Consequently the transformed inertia \(\hat{\boldsymbol M} = \boldsymbol\Gamma_a^{-T}\boldsymbol M\boldsymbol\Gamma_a^{-1}\) is block-diagonal: \[\hat{\boldsymbol M} = \begin{bmatrix} \hat{\boldsymbol M}_{\text{task}} & \boldsymbol 0 \\ \boldsymbol 0^T & \hat m_n \end{bmatrix},\qquad \hat m_n = \hat{\boldsymbol k}^T\boldsymbol M\hat{\boldsymbol k} \;(>0).\] PROVED (read off \(\boldsymbol\Gamma_a\boldsymbol\Gamma_a^{-1} = \boldsymbol E_{13}\), plus congruence). Note the errata flagged in review (R2): the document statement read \(\boldsymbol c_{13} = \|\boldsymbol z_a\|^{-1}\hat{\boldsymbol k}\), but the proof correctly derives \(\boldsymbol c_{13} = \|\boldsymbol z_a\|\,\hat{\boldsymbol k}\); nothing downstream depends on the constant since only proportionality \(\boldsymbol c_{13}\propto\hat{\boldsymbol k}\) is used.
Moral of P1. The self-motion’s kinetic energy does not leak into the task coordinates — the speedometer is energetically clean. This is the hard half of P1; the soft half (relating \(\hat{\boldsymbol M}_{\text{task}}\) to the original \(\breve{\boldsymbol M}\)) is unfinished bookkeeping.
Moral of Lemma 1. Energy bookkeeping is indifferent to which 13th row we append — even a bad \(\boldsymbol z_a\) preserves passivity. The project risk never lived in the Lyapunov function; it lives in the structure (S5).
The remaining proof obligations, none of which block correctness (Lemma 1 guarantees passivity regardless):
A prior-art note dated Jun 11 records that, after these
documents were written, the author read Giordano’s PhD thesis
(giordano2020wholebody, TUM 2020), §5.2 + Appendix
C.4. The redundant coordinated formulation is already
there. This work is therefore a convergent
re-derivation offered as cross-validation, not a novel
formulation. The specific equivalences supported by the
extracts:
| This work | Giordano 2020 thesis | Meaning |
|---|---|---|
| Inertia-weighted covector \(\boldsymbol z_a^T = \dfrac{\hat{\boldsymbol k}^T\boldsymbol M}{\hat{\boldsymbol k}^T\boldsymbol M\hat{\boldsymbol k}}\) (S2.2) | dynamically-consistent condition eq. (5.22), there imposed as \([\boldsymbol J_{\omega_b}^\oplus; \boldsymbol J_e^\oplus]\,\boldsymbol M^{-1}\,\boldsymbol J_n^{\oplus T} = 0\) | the same dynamically-consistent device |
| Damping suppression \(u_n = -d\,v_n\) (S2.3) | null-space force law eq. (5.8c), \(\varsigma_n = -D_n\tilde v_n\) | ours is the high-damping (finite-\(d\)) limit of his force law |
| P3 “expect coupled internal Coriolis” | thesis remark: internal Coriolis is “fully coupled” | confirms P3’s expectation in print |
What is claimed as original here: (1) the fiber-reconstruction implementation (the \(v_n=0\) section reconstruction in code); (2) the explicit kernel basis \(\hat{\boldsymbol k} = [-\bar{\boldsymbol J}_v\hat{\boldsymbol n};\ \boldsymbol 0;\ \hat{\boldsymbol n}]\) with its base-counter-translation reading; (3) the inspection-mission singularity application (using the spare DOF to hold \(\sigma_6\) away from zero while tracking); (4) the singularity-margin payoff analysis.
Broader attributions from the extracts: dynamically-consistent inverse / inertial decoupling — Khatib (1987); redundant-arm impedance template — Ott (2008); the M-orthogonal section as the horizontal space of the mechanical connection — Marsden–Montgomery (and Kelly & Murray for locomotion); kinetic-energy split for P2 — Koenig’s theorem; the same non-decaying self-motion observed on hardware and parked on joint friction — Giordano RA-L (2021).
One structural caveat to reconcile in P1 (from the prior-art note): the thesis attitude block uses the circumcentroidal \(\boldsymbol\omega_b^\oplus\) (his eq. 5.20), whereas eq. (19) / our \(\boldsymbol\Gamma\) uses plain \(\boldsymbol\omega_b\). This difference must be resolved within P1.
Nomenclature warning — do NOT call this an RNS. Do not call this a Reaction Null-Space in front of the committee. Free-floating literature gets reactionless motion from momentum conservation (the base is unactuated and stays still). Here the base MOVES, and the combined motion only registers as zero because of the chosen coordinates. Same algebra family, different physics. Call it “the kinematic self-motion of the coordinated coordinates.”
Every kernel construction lives on \(\Omega\) (full row rank), but the mission spends ~1/3 of its steps at or below the derate floor — the edge of \(\Omega\) — where the kernel is ill-conditioned and nothing monitors it.
The honest statement of the gap (review_7dof.md):
The documents flag the sign non-smoothness of \(\hat{\boldsymbol n}\) (uses are sign-invariant) but not the subspace ill-conditioning. That is the gap.
Mitigation (cheap, one study, already partly in
code). Log the per-step inter-step kernel angle \(\angle(\hat{\boldsymbol n}_k, \hat{\boldsymbol
n}_{k-1})\) alongside \(\sigma_6\); if it spikes in derated
windows, freeze \(\boldsymbol
z_a\) below the floor, mirroring the
damped_inverse last-inverse reuse. This is implemented as
null_space.freeze_floor (default \(0.025\)): the basis \((\hat{\boldsymbol n}, \hat{\boldsymbol k},
\boldsymbol z_a)\) freezes at its last healthy value with
sign-continuity alignment (TDD 6/6, baselines byte-identical). The
kernel-continuity study
(validation/r1_kernel_continuity.py) measured: healthy
windows rotate \(\hat{\boldsymbol n}\)
by median 0.03 deg/step (p99 ~1.3–1.5 deg); derated
windows reach 69 deg/step at \(\sigma_6\sim 10^{-3}\); a
matched-pace run momentarily touches \(\sigma_6 = 0.0000\) (a momentary rank-2
kernel).
Moral. The math is correct on \(\Omega\). The blocker is that the mission lives partly off \(\Omega\), and until inter-step kernel angle is monitored, the suppression averages may hide exactly the windows that matter.
Secondary findings:
reconstruct_generalized_velocity exists
twice: the exact-lstsq path
(CC_Controller) that the unit tests exercise, and the
regularized-normal-equations Breve override that the
mission uses. These are not the same
algorithm. The Breve variant biases off the \(v_n=0\) section by \(O(\lambda/\sigma^2)\), and keys its \(\lambda\) floor to \(\sigma_{\min}\) of the
unaugmented \(\boldsymbol\Gamma\) while solving the
augmented system — a quiet conditioning-signal mismatch
and a DRY violation. In-loop residual \(v_n\sim1.7\times10^{-6}\) in the unit test
is the \(\lambda\)-regularization
footprint.validation/run_7dof_mission.py),
not with the robot definition — it is the 6-DOF data-derived values with
a \(\pm2\pi\) roll placeholder
inserted, baking in the elbow-fence misfit. (Tail-conditioning analysis:
the \(p_e\) tail is derate-enriched and
fence-neutral, so the envelope is not the
tail’s owner.)The knob is OFF by default:
null_space.enable = false. The augmented
reconstruction is gated on this flag; when the robot has 6 joints the
kernel objects (\(\hat{\boldsymbol n},
\hat{\boldsymbol k}, \boldsymbol z_a\)) are None and
the code path is untouched, so all five pinned 6-DOF baselines reproduce
byte-identically. (The formal ledger names the flag verbatim,
controller.arm.null_space.enable, read at
com_controller.py:49, default false; the
intuition/roadmap/review docs describe the gating as the
n>6 guard plus a config-model consistency assert.)
Where the speedometer lives in code:
lstsq reconstruction path:
com_controller.py:232
(reconstruct_generalized_velocity,
CC_Controller).breve_controller.py:505
(BreveController).damped_inverse wide branch (Moore–Penrose \(\boldsymbol J^+\)); hard-floor branch
reuses the last inverse (the freeze idiom R1 mirrors).full_matrices=True), gated on \(n>6\).null_space.freeze_floor (default \(0.025\)): freezes \((\hat{\boldsymbol n}, \hat{\boldsymbol k},
\boldsymbol z_a)\) below the floor with sign-continuity
alignment.Implemented & verified: M1, M2, M3
(healthy-branch pseudoinverse), M4 (augmented reconstruction), M5
(kernel objects), the M-orthogonal speedometer \(v_n\), the right-inverse reconstruction,
the R1 freeze mitigation. Numeric checks:
validation/test_robot7_nullspace.py (\(\|\boldsymbol\Gamma\hat{\boldsymbol k}\| <
10^{-10}\) at 9 random configs), test_wide_gamma.py,
test_null_space_suppression.py,
validation/r1_kernel_continuity.py,
validation/r4_mbreve_inconsistency.py.
Proof-obligations / NOT yet implemented as closed loop:
The “before” picture (measured Jun 10). Running the unchanged controller on the 7-DOF arm (minimum-norm reconstruction, self-motion unregulated): tracking held (EE error \(\le 0.191\) m), full row rank held (\(\sigma_6 \in [0.054, 0.077]\)), and the self-motion coordinate \(\max|v_n| = 0.23\) rad/s, NON-DECAYING — the same phenomenon Giordano’s RA-L 2021 hardware reported and parked on joint friction. The sim has no friction, hence the measured ringing. This is exactly the “before” that P4’s damper \(d_n>0\) exists to fix.
The allocation problem (one ghost, three chores). The null space is one-dimensional, but three secondary objectives compete for it: (1) singular-value maximization (pull \(\sigma_6\) away from zero), (2) envelope clearance, (3) pan-centering / yaw allocation. These conflict at some orbit phases. The weighting/scheduling is an explicit design decision to be made in the open, with data — it hides behind P4, not inside it.
Two things, in order:
Close R1 (the blocking item). Add the per-step
kernel-angle monitor \(\angle(\hat{\boldsymbol
n}_k, \hat{\boldsymbol n}_{k-1})\) logged alongside \(\sigma_6\), confirm where it spikes, and
demonstrate the freeze_floor mitigation holds the basis
steady through the derated windows (the freeze-enabled mission run is
queued). Until inter-step kernel angle is measured in the derated
windows, the suppression averages cannot be trusted, because the
theory’s \(\Omega\) premise is violated
for ~1/3 of the mission.
Run a pace-matched comparison. Re-run at the matched pace (0.45 m/s) so the §8 confounders (pace, envelope, \(\breve{\boldsymbol M}/\breve{\boldsymbol C}\) approximation) are removed, and report the controlled metrics. The current same-speed column (\(p_e^{p99} = 0.2217\)) fails the \(<0.2\) gate and is feasibility-only. The named next lever toward the unmet \(p_e^{p99} < 0.1\) objective — owned by the derated windows — is the null-space posture pull toward larger \(\sigma_6\), i.e. the P4 objective, of which the current damping-only suppression is the zero-stiffness special case.
Supporting items (not adoption blockers): size the \(\breve{\boldsymbol M}/\breve{\boldsymbol C}\) inconsistency with the R4 relative-error study and finish P1 to remove it; P3 Coriolis-cross-coupling bounds; solver unification (R7) so the mission and the unit tests run the same algorithm; envelope re-derivation (R8) for the 7-joint posture family (including the \(\pm2\pi\) roll joint); and the explicit, data-driven allocation decision among the three secondary objectives.
Bottom line. The mathematics is sound where proven (Props 1–3, Theorem 1, Lemma 1 verified by hand; Prop 4 honestly a sketch), the model addition is good engineering, passivity is guaranteed for any invertible augmentation (Lemma 1) — so nothing blocks correctness. What blocks adoption is R1 (the theory lives on \(\Omega\); the mission does not) and the fact that the headline empirical claim is not yet a controlled comparison. Close R1 and run pace-matched, and the case for the 7th joint stands on its own.