Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
c5364d8
swerve bring-up: x-lock in drive test, tunable zero-power behavior
AXAStudio Aug 12, 2026
022af44
Baseline: uncommitted heading-tuning work, recorded as found
AXAStudio Aug 12, 2026
7292126
swerve pods: continuous static-friction term, usable integral, loop-r…
AXAStudio Aug 12, 2026
dd45c9b
teleop loop rate 30.7 -> 75.8 Hz; measure pod dead zone
AXAStudio Aug 12, 2026
9f4bd82
phase 4: delay budget, PWM and derivative-on-measurement negative res…
AXAStudio Aug 12, 2026
e5fc03a
per-pod split, corrected delay budget, pulsed final approach (partly …
AXAStudio Aug 12, 2026
b75aedc
randomised grids, bimodality confirmed, pulsed approach blocked by pu…
AXAStudio Aug 12, 2026
9d5f5f1
INTERIM turn gains: kP 0.20 kD 0.014 kS 0.035, off-ground only, not f…
AXAStudio Aug 12, 2026
0a39d6b
interim turn kD 0.014 -> 0.022, selected on P(loose)=0 at n=60
AXAStudio Aug 12, 2026
aec8ef2
pulse calibration: archive traces, separate within- from between-cond…
AXAStudio Aug 12, 2026
734bd29
PositionalPod: servo-internal position loop as an alternative to CR +…
AXAStudio Aug 12, 2026
74fa35e
criterion 8 as holding current; A/B fixed to within-pod on pod 0
AXAStudio Aug 12, 2026
d2325e1
make the positional A/B executable: mixed pod types, Servo ports, per…
AXAStudio Aug 12, 2026
0a3d15f
positional: 190 deg travel, end-stop clamp, coverage proof, clamp probe
AXAStudio Aug 12, 2026
9bcebe4
positional A/B gates: uncalibrated pods cannot drive, band reproducib…
AXAStudio Aug 12, 2026
4731042
config endpoint: report what was activated, and verify it
AXAStudio Aug 12, 2026
d4745ee
persist the positional calibration; it was silently reverting on restart
AXAStudio Aug 12, 2026
bba2595
guard PodCal persistence by reflection; sweep the rest of the same shape
AXAStudio Aug 12, 2026
9cef14a
README: document what persists, what does not, and why
AXAStudio Aug 12, 2026
4c6b35a
cross-reference the heading gains so the bring-up copy cannot silentl…
AXAStudio Aug 12, 2026
daa0f3c
270 deg travel; harden the boot encoder read
AXAStudio Aug 12, 2026
dc39702
restore the Servo fallback in acquireHardware; it was lost to a silen…
AXAStudio Aug 12, 2026
de7c054
calHome: the first commanded move is the one the walk cannot protect
AXAStudio Aug 13, 2026
729019b
shelve positional steering: gated off at source, documented, CR path …
AXAStudio Aug 13, 2026
a241b97
surface tool-vs-shipped gain divergence instead of assuming they agree
AXAStudio Aug 13, 2026
24d5264
Phase 5 carpet validation: interim gains fail criterion 5 on carpet b…
AXAStudio Aug 13, 2026
2f93358
carpet kS refit: 0.045 halves the residual, but the diagnosis that mo…
AXAStudio Aug 13, 2026
d81d473
off-ground check: kS 0.045 is better on the game surface and much wor…
AXAStudio Aug 13, 2026
2e95e2f
record the kS surface inversion; hold at 0.035 through the mechanical…
AXAStudio Aug 13, 2026
fcc698b
expose every turn tunable in the dashboard; capture pod data while dr…
AXAStudio Aug 13, 2026
461c2bd
loop rate above ~48 Hz buys nothing; correct the inflated rate figures
AXAStudio Aug 13, 2026
1ba3007
measure servo current; it cannot resolve torque at breakaway
AXAStudio Aug 13, 2026
1f2fa86
retune on the game tiles after the pod repair and lubrication
AXAStudio Aug 13, 2026
c6b155d
score the gate against criterion 1 as re-spec'd, and stop asserting t…
AXAStudio Aug 13, 2026
06b0a97
fix the drive-mode bug pile: publish bus reads, stale-command paths, …
AXAStudio Aug 14, 2026
897b317
per-pod turn gains: the pods are different plants, and kS is what fee…
AXAStudio Aug 14, 2026
ca2065a
re-zero after the first real drive; heading PIDF off by default
AXAStudio Aug 14, 2026
c52bcf2
X-lock waits for the chassis to stop; a drive-cycle harness that meas…
AXAStudio Aug 14, 2026
53df00d
heading hold: hysteresis instead of the epsilon relay, kD retuned for…
AXAStudio Aug 14, 2026
2f18104
heading release: coast, snap to the IMU, hand the hold to the X-lock
AXAStudio Aug 14, 2026
b6f93eb
field pose, an operator-drawn bounding box as a hard fence, and hones…
AXAStudio Aug 14, 2026
26a08de
a Pedro follower bench behind the fence, and the crab that was really…
AXAStudio Aug 15, 2026
788d546
follower tuning through the bench: translational 2x faster, the braki…
AXAStudio Aug 15, 2026
37ddf9d
the rolling plant: gain-schedule the turn loop, because a moving whee…
AXAStudio Aug 15, 2026
243d695
soft heading lock past the epsilon shadow; error-gate the schedule so…
AXAStudio Aug 15, 2026
d4e8f90
precision pass: schedule knobs at runtime, floor 0.32 confirmed, vibr…
AXAStudio Aug 15, 2026
e4fe60c
soft heading lock, actually strong enough to feel: speed-scaled floor…
AXAStudio Aug 15, 2026
037e937
flip hysteresis: the diagonal wobble was the flip decision chattering…
AXAStudio Aug 15, 2026
6b72ef9
record the driver: heading, pose and applied commands join the loop-r…
AXAStudio Aug 15, 2026
c3f55a9
tune where the driver actually drives: the schedule re-fit to a recor…
AXAStudio Aug 15, 2026
cd6d6dd
pulsed final approach, revived with a stall ladder: the pod finds its…
AXAStudio Aug 15, 2026
75d2d88
pulse bench: rest/step A-B harness, travel recalibration, and the ses…
AXAStudio Aug 15, 2026
e637d91
the heading lock was the wobble: epsilon bypass instead of a floor, a…
AXAStudio Aug 15, 2026
858ba7c
adopt the pulsed approach for competition: silent parked pods, tie or…
AXAStudio Aug 15, 2026
f76446a
field-oriented drive: a per-command flag, a captured forward, and a l…
AXAStudio Aug 15, 2026
63c24e4
pulses yield to the PD while rolling: a drive-power gate closes the a…
AXAStudio Aug 15, 2026
140e913
sync constants to the 2026-08-15 re-zero, from the hub - not the stal…
AXAStudio Aug 15, 2026
8041719
the export was right: zeros from the cal file, and a crab check that …
AXAStudio Aug 16, 2026
254ae21
the crawl wobble was the heading bypass: turn geometry gates it on tr…
AXAStudio Aug 16, 2026
d05bd32
the epsilon wall was the whole story: rotation gets 0.015 and the PID…
AXAStudio Aug 16, 2026
b90a7b4
handling corrupts the fence: impossible odometry speed discards the box
AXAStudio Aug 16, 2026
5ebd570
the demand is what shakes: wheel path over commanded path is 1.01
AXAStudio Aug 16, 2026
858952d
instrument what ships: the competition loop gets a recorder, publish …
AXAStudio Aug 16, 2026
b9bb553
four per-axis distortions and a rate limit: the demand stops snapping
AXAStudio Aug 16, 2026
9817aa1
untrack the session transcript and __pycache__: git add -A swept them in
AXAStudio Aug 16, 2026
6ff4b58
amend the record: the pods were never the problem
AXAStudio Aug 16, 2026
68959c9
the competition path had no heading loop at all: build one, then meas…
AXAStudio Aug 16, 2026
6afe271
findings: Task 3 design, the fix simulation, and the criteria table a…
AXAStudio Aug 16, 2026
9f57d95
String.format was the whole publish cost: 61 us a call, 193 calls, 11…
AXAStudio Aug 16, 2026
69c32dc
34.6 -> 95.6 Hz true: the formatter was the loop
AXAStudio Aug 16, 2026
478b12d
starting DriveTeleOp silently moved the fence 20 inches
AXAStudio Aug 16, 2026
a6edf00
criterion 3 is met on three pods; the cache hypothesis is not supported
AXAStudio Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,8 @@ lint/intermediates/
lint/generated/
lint/outputs/
lint/tmp/
# lint/reports/
# lint/reports/
# Session artifacts and Python bytecode - not project state.
my-session-transcript.md
__pycache__/
*.pyc
39 changes: 39 additions & 0 deletions ASSUMPTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Assumptions taken this session

Every default taken from Survey 0 without an answer, plus anything else assumed rather than
measured. Each says how to overturn it.

## From Survey 0 (defaults taken, work proceeded)

| # | Item | Assumed | Consequence if wrong |
|---|---|---|---|
| Q1 | Robot time / surface | >2 h on FTC tiles, robot on the floor. All drive commands still gated behind a confirmed OPS REQUEST. | Captures get rescheduled; nothing else changes. |
| Q2 | Drive path under study | Both: reproduce through the dashboard, confirm on `DriveTeleOp`. | If dashboard-only, the shipped-path findings (§2.3) stay unverified. |
| Q3 | Criterion 7, heading error translating | < 3.0° | Threshold only. |
| Q4 | Criterion 8, heading error at rest | < 1.0° | Threshold only. |
| Q5 | Criterion 9, cross-track | < 2.0 in | Threshold only; drives how much clearance the Task 3 path needs. |
| Q6 | Editing vendored Pedro | Yes — `third_party/PedroPathing` is treated as our source, as prior commits already do. | Fixes in `Swerve.java` / `CustomDrivetrain.java` would have to be worked around. |
| Q7 | Lubrication pass | **Self-answered from the code, not assumed.** It happened before 2026-08-13; gains were re-fitted after it. CLAUDE.md's "pending" is stale. | — |
| Q8 | Recorder columns | Yes, add columns and report the cost. Added `p{i}_ctgt`; `tgt` kept so the archive stays comparable. | Revert the column; `steerqual.py` falls back to `tgt`. |
| Q9 | Task 3 path shape | Closed loop that returns to start, so it can be repeated for statistics. | Path gets redesigned; the profile and validation method do not change. |
| Q10 | Heading interpolation | Tangential on traverses, constant on the approach; a constant-heading variant also generated because it isolates Task 2. | Path variant selection only. |

## Assumed rather than measured

1. **`String.format` is the bulk of the 36.7 ms publish cost.** Arithmetic fit (~1000 calls ×
~35 µs), not yet a measurement. The deployed per-section timers and the `setFastFmt` A/B
settle it. Until then it stays a hypothesis in FINDINGS.md.
2. **Teleop centripetal correction is dead code and cannot NPE** (FINDINGS §2.5). Derived from
`Vector` not overriding `equals`. Predicted safe; unverified on hardware. First
`DriveTeleOp` run is the test, and the operator has been warned.
3. **The saved box survives a redeploy.** `swerve_field_box.txt` is reloaded at init and the
Pinpoint pose is not reset by configuration. `/state` is re-read to confirm `box.valid`
before any motion, so this assumption is checked rather than trusted.
4. **`p{i}_ctgt` costs nothing measurable in the loop.** One field read and a normalise per pod
per loop. Will be confirmed against the loop-dt distribution before/after.
5. **The archived runs were taken on FTC tiles.** The runs carry battery voltage but not
surface. Inferred from the session logs that produced them; if any were on blocks the
friction-dependent numbers (pod error, path ratio) would not compare.
6. **`mydrive-001` is representative of human driving.** One 71.9 s session, one driver. The
attribution percentages in FINDINGS §2.2 are from that run; the mechanisms are structural,
but their shares are not a population estimate.
346 changes: 346 additions & 0 deletions CLAUDE.md

Large diffs are not rendered by default.

456 changes: 456 additions & 0 deletions FINDINGS.md

Large diffs are not rendered by default.

1,058 changes: 1,058 additions & 0 deletions PROMPT_REVIEW.md

Large diffs are not rendered by default.

673 changes: 673 additions & 0 deletions SWERVE_TASK.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.firstinspires.ftc.teamcode.diagnostics;

import com.acmerobotics.dashboard.FtcDashboard;
import com.acmerobotics.dashboard.config.Config;
import com.acmerobotics.dashboard.telemetry.MultipleTelemetry;
import com.pedropathing.follower.Follower;
import com.pedropathing.geometry.Pose;
import com.qualcomm.hardware.lynx.LynxModule;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.util.ElapsedTime;

import org.firstinspires.ftc.teamcode.pedroPathing.Constants;

@TeleOp(name = "motorbreakin", group = "TeleOp")
@Config
public class motorbreakin extends OpMode {
private static final double NORMAL_SPEED = 1.0;
private Follower follower;


@Override
public void init() {
follower = Constants.createFollower(hardwareMap);
}


@Override
public void loop() {
follower.setTeleOpDrive(1,0,0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,37 @@ private void beginKfReverse(double wheelDeg) {
}

private void finishKf(PodCal cal, double wheelDeg) {
cal.kF = (kfForward + kfReverse) / 2.0;
log.add(String.format(Locale.US, "kF = %.4f", cal.kF));
// The measured breakaway goes into kS, the continuous tanh feed-forward, NOT into kF.
// CoaxialPod feeds the PIDF's F term a bare sign, so kF at breakaway magnitude is a
// relay - the configuration measured at 15.8 sign changes per step and 42.5 deg of
// post-settle peak-to-peak, and the reason kF ships at 0. Writing kF here re-introduced
// exactly that, and persisted it to the calibration file.
cal.kS = (kfForward + kfReverse) / 2.0;
cal.kF = 0;
log.add(String.format(Locale.US, "breakaway = %.4f -> kS (kF stays 0)", cal.kS));
rebuildRequested = true;

cal.kP = baseKp * KP_STEPS[0];
cal.kD = baseKd;
beginTrial(cal, wheelDeg);
}

/**
* Stops the tuner mid-run, leaving the calibration exactly as the last completed phase set
* it. Without this, leaving AUTOTUNE mode stranded {@code isRunning()} true forever - the
* dashboard showed "Tuning pod N" for the rest of the session and a fresh start() was the
* only way out.
*/
public void abort(String reason) {
if (phase == Phase.DONE) {
return;
}
phase = Phase.DONE;
rawServoPower = 0;
status = "aborted: " + reason;
log.add("Aborted mid-run: " + reason);
}

// ---- trials -----------------------------------------------------------------------

private void beginTrial(PodCal cal, double wheelDeg) {
Expand Down
Loading
Loading