nu_e Situation — what the EE-twist variables are, how they
flow, and what is actually deadGenerated: 2026-06-23 (EDT) · structural trace via
ast-grep (not text grep) · branch
speed-derate. Reads:
GNC/breve_controller.py,
GNC/breve_core_controller.py,
GNC/com_controller.py,
GNC/guidance/ee_guidance.py,
GNC/guidance/analytic_feedforward.py,
GNC/guidance/guidance_rollout.py,
utils/robot.py, utils/data_classes.py,
YAMLs_by_domain/metrics.yaml.
If you read one paragraph.
nu_eis the end-effector reduced twist — a load-bearing physical signal that drives the EE wrench’s damping term and therefore the joint torques. It is not dead code. The only genuinely deadnu_e-adjacent items are tiny: one vestigial state field (nu_e.local.prev, written twice and read nowhere) and one diagnostic log line that is excluded from serialization (nu_e_oplus_des,include:false). A third thing — the loggednu_etracking metric — is not dead but ill-posed: it compares the realized and desired EE twists across boresight-rolled frames (R_tevsR_ed, ~52° apart), so its famous “54°” is a frame artifact. The earlier “dead-code cleanup” note bundled these and got compressed into the false claim “nu_e is dead.” It is not.
A handoff said the 54° nu_e error was “an irrelevant red
herring” and that “nu_e was dead code.” The second half is
wrong and worth correcting precisely, because nu_e is the
camera’s end-effector twist — remove it and EE damping dies. This
document traces the actual flow of the EE-twist
variables through the Breve guidance→control system and classifies each
as load-bearing, conditionally live,
or dead, with ast-grep evidence (a
write-vs-read question is structural, so the AST answers it
cleanly).
nu/nu_e variable| name | where it lives | meaning |
|---|---|---|
motion.nu_e / motion_cache.nu_e |
utils/robot.py:162
(twist("cam","local")) |
measured EE twist, EE-local frame
R_te |
des.nu_e |
Desired record field |
desired EE local twist (a side-copy for logging + guidance rollout) |
self.nu_e.local.des |
breve_controller.py |
desired local twist used by control (the
load-bearing twin of des.nu_e) |
self.nu_e.local.prev |
breve_controller.py:106,122 |
previous desired local twist — vestige |
self.nu_e.oplus.des |
breve_controller.py |
desired twist in the reduced (⊕/circumcentroidal) frame |
self.nu_e.oplus.dot |
breve_controller.py |
desired reduced acceleration (RHS feedforward) |
self.nu_e.oplus.prev |
breve_controller.py:607,648 |
previous reduced desired (for the FD acceleration) |
st.nu_e_oplus |
com_controller.py,
breve_core_controller.py |
the EE reduced-twist state (integrated) |
nu_e_oplus_des (local var) |
breve_controller.py:619–648 |
the reduced desired twist, computed in-method |
nu_e_oplus_des (diag field) |
breve_controller.py:521 |
a logged copy — include:false |
nu_local, nu_oplus,
nu_oplus_dot, nu_des |
guidance functions | transient locals (FF construction) |
GUIDANCE (EEGuidance / analytic_feedforward) CONTROL (BreveController)
──────────────────────────────────────────── ─────────────────────────────────────────────
desired EE pose des.p_e, des.R_e ───────────────► build_desired_for_step (breve_controller.py:69–130)
├─ analytic ON: analytic_desired_nu_e_feedforward(st,des) :94
desired EE twist, TWO constructions: │ → (nu_local, nu_oplus, nu_oplus_dot) in R_ed
• analytic (ideal standoff, R_ed) ee_guidance.py:267 │ → _set_analytic_oplus_feedforward(...) :107
• FD (committed-pose d/dt, R_te) ee_guidance.py:225 └─ analytic OFF: desired_nu_e_feedforward_consistent(des,des_prev) :110
→ update_desired_nu_e_oplus_feedforward(...) :123
stores: self.nu_e.local.des (LOAD-BEARING) :105/117
self.nu_e.oplus.{des,dot} (LOAD-BEARING) :605/647
des.nu_e (log + rollout) :104/116/120
measured twist motion.nu_e = twist("cam","local") (R_te) ─────────────────────────────────────────┐
▼
WRENCH: nu_e_tilde() = motion.nu_e − nu_e.local.des (local error) :258 ───► D-term in compute_omega_e_oplus :293
nu_e_oplus_tilde() = ⊕(motion) − nu_e.oplus.des (reduced error) :609
→ nu_e_damping_error() :242 → v_breve_damping_error() (breve_core_controller.py:78)
→ RHS34b D_breve term :410 → v_breve_dot :463 → integrate
ACCEL FF: nu_e.oplus.dot ───► rhs_feedforward() :351 (M_breve · [0; nu_e.oplus.dot])
STATE: st.nu_e_oplus ← integrate nu_e_oplus_dot (breve_core_controller.py:115)
→ reconstruct_generalized_velocity :486 → Γ-solve → full generalized velocity → joint torques
LOG: (motion.nu_e, des.nu_e) pair (utils/data_classes.py:280) → key tracking_error.arm.nu_e [ILL-POSED METRIC]
nu_e_oplus_des (diag) (breve_controller.py:521) → include:false [DEAD LOG]
The two frames are the crux. The measured twist
motion.nu_e lives in the realized EE frame
R_te; the analytic desired twist lives in
the desired standoff frame R_ed. Because
axis_only_attitude zeros the commanded roll rate
w_z (the camera is axisymmetric — boresight roll is
irrelevant to what it sees), R_te and R_ed
roll freely apart (~52°). The control path is fine — the D-term
works in the local frame R_te (nu_e_tilde,
line 258) and the reduced damping uses a consistent ⊕ map — but any
metric that differences motion.nu_e
against the analytic des.nu_e is comparing across those
rolled frames. That is the ill-posedness (see §5).
ast-grep caller traces ($_.fn($$$) and
attribute-access patterns) confirm a live consumer for each:
| symbol | consumed by | evidence |
|---|---|---|
motion.nu_e |
nu_e_tilde (D-term), nu_e_oplus_tilde
(reduced error) |
breve_controller.py:260,612 |
nu_e_tilde() |
D-term in compute_omega_e_oplus;
x_e_tilde_dot |
:283, :252 |
nu_e_oplus_tilde() |
nu_e_damping_error |
:244 |
nu_e_damping_error() |
v_breve_damping_error → RHS34b |
breve_core_controller.py:78 →
breve_controller.py:410 |
nu_e_local_to_oplus() |
reduced error, realized floor | :611, :543, :621, :630 |
nu_e.local.des |
nu_e_tilde (260), ⊕ desired (622/631) |
read at :260,622,631 |
nu_e.oplus.des |
cruise-lag floor input (366), reduced error (619) | read at :366,619 |
nu_e.oplus.dot |
RHS acceleration feedforward | read at :351 |
st.nu_e_oplus |
integration + reconstruction | breve_core_controller.py:115;
com_controller.py:240,321;
breve_controller.py:488 |
| analytic FF / FD FF / both ⊕ updaters | one control path each | called at :94/110/107/123 |
des.nu_e (the field) |
guidance rollout + logging | guidance_rollout.py:68 (des_prev.nu_e),
ee_guidance.py:337 (fake_kinematics),
data_classes.py:280,289 |
Takeaway: the EE twist nu_e, in all its
working forms (measured, desired-local, desired-⊕, the state, the
errors, the feedforward), is load-bearing. None of it is a deletion
candidate.
self.nu_e.local.prev — genuinely DEADast-grep run --pattern '$_.nu_e.local.prev' over
GNC utils analysis validation returns only two
nodes, both assignment LHS (writes), and zero
reads:
GNC/breve_controller.py:106: self.nu_e.local.prev = nu_local.copy()
GNC/breve_controller.py:122: self.nu_e.local.prev = self.nu_e.local.des.copy()
It is a fossil from when the desired-twist finite-difference
derivative was taken in the local frame. The design
moved that derivative to the reduced (⊕) frame, where
it now reads nu_e.oplus.prev at
breve_controller.py:640. nu_e.local.prev was
left behind, written but never consumed. Removable.
nu_e_oplus_des diagnostic log line — DEAD LOGcontroller_diagnostics logs
nu_e_oplus_des=self.nu_e.oplus.des
(breve_controller.py:521), but the catalog marks it
include: false (metrics.yaml), so it is
never serialized to the NPZ and no report/scoreboard
reads it. (The same name nu_e_oplus_des as a local
variable at :619–648 is load-bearing — different
scope; only the line-521 diagnostic copy is dead.)
Removable.
self.nu_e.oplus.prev write at line 607 — conditionally
vestigial (KEEP)oplus.prev is read at :640
(the FD acceleration (des − prev)/dt), so the field is live
in FD runs. But in the analytic path,
_set_analytic_oplus_feedforward sets oplus.dot
directly (:606) and the write at :607 is never
read (the FD branch is not taken). It is harmless field-consistency, not
cleanly removable (the FD path needs the field). Keep; note the
asymmetry.
nu_e tracking metric — ILL-POSED, not deadThe logged pair (motion.nu_e, des.nu_e)
(data_classes.py:280) becomes the catalog key
tracking_error.arm.nu_e, reduced to a per-step error
actual − desired by data_analyzer. It is
never read back by the controller (purely diagnostic),
so it is not load-bearing — but it is not “dead” either; reports and
plots consume it. The problem is that it is ill-posed in
analytic runs:
motion.nu_e is in the realized EE frame
R_te;des.nu_e is in the desired standoff frame
R_ed;R_te and R_ed are rolled ~52° about the
boresight (axis_only_attitude leaves roll free), so the
metric differences two vectors expressed in different
bases.This is exactly the “54°” — the geodesic frame angle
‖so3_log(R_ed^T R_te)‖ ≈ 53.8° (measured by the
frame_angle_diag run) re-expresses the same world
velocity in a 54°-rotated x–y split. The boresight
pointing error over the same window is only ~2.2°
(ratio 24.6×). The right way to judge EE tracking is the
world-frame p_e and the
pointing versine — both frame-invariant — not this
metric. So the metric should be re-posed (point reports
at p_e/pointing) or dropped; either way the EE twist
nu_e itself stays.
The floor formula (eq 4.14, cruise_lag_floor,
analytic_feedforward.py:144) is fed
v_breve_des = [omega_b; nu_e.oplus.des] and computes
C_breve · v_breve_des as the Coriolis forcing. The
analytic floor feeds nu_e.oplus.des built in
R_ed; the realized floor feeds the measured twist
mapped from R_te
(breve_controller.py:540–548). Those are the same
two rolled frames that make the nu_e metric
ill-posed. So the boresight roll is not only a metric nuisance — it sits
inside the floor’s forcing term and is part of why the “floor” reads
0.044 (analytic), 0.055 (realized), or 0.123 (FD/consistent, cross-run).
The honest, frame-consistent number — eq 4.14 fed the committed-pose
velocity d/dt(p_ed) the EE actually tracks, within
one run — is the follow-up computed via the new
floor_pe_consistent diagnostic. (Full floor narrative:
cruise_lag_floor.md.)
nu_e is the end-effector twist and is
load-bearing. Not dead. Not a deletion candidate.nu_e.local.prev
(vestige, removable) and the nu_e_oplus_des diagnostic log
line (include:false, removable).
nu_e.oplus.prev’s analytic-path write is vestigial but the
field stays.nu_e tracking
metric — re-pose to world-frame p_e/pointing.