This guide is a complete, field-usable procedure for tuning the robot targeting stack in this repo.
It is written against the current architecture:
- On-RIO shot solve in
TurretSubsystem(LUT + Newton solver, optional model fallback) - Lookup data from
src/main/deploy/turret_data.json - Runtime debug/tuning controls under NetworkTables
Debug/*andTurretAssembly/*
If you follow the order in this document, you will avoid most tuning loops that burn hours.
The shot quality depends on 5 layers. Tune in this order only:
- Mechanism health and homing
- Actuator control loops (turret, hood, flywheel)
- Static shot map (
turret_data.json) at zero robot motion - Shoot-on-the-fly compensation (latency + range latency + rotation FF)
- Optional MODEL mode calibration and LUT-vs-model fallback behavior
If an earlier layer is unstable, do not tune later layers.
- Put robot on a known field coordinate frame (or at least consistent origin/heading).
- Verify hood homing runs successfully.
- Hood commands are ignored when hood is not homed (
hoodLimitSet == false).
- Hood commands are ignored when hood is not homed (
- Confirm all turret motors report connected.
Motor Comm Statustelemetry should be true.
- Confirm pose estimate and alliance are sane.
- Wrong alliance or bad pose causes wrong target selection even if turret code is correct.
- Start in LUT mode, no overrides.
Debug/Turret Targeting Mode = LUTDebug/Override RPM Enabled = falseDebug/Override Hood Angle Enabled = falseDebug/Turret Target Override = AUTO(or set explicit target for controlled tests)
Before changing gains/offsets, validate the solver inputs published every loop:
Under TurretAssembly/targetting (sic):
robot_x,robot_y,robot_angletarget_x,target_y,target_heighttarget_distancehas_valid_shot
Expected behavior:
target_distancechanges smoothly as robot moves.has_valid_shotis true when target exists and solve succeeds.target_x/target_ymatch selected target and alliance.robot_*values match field display/odometry.
If these are wrong, do not tune shooter values yet.
- Run hood homing command.
- Confirm hood reaches stall, zeros encoder, and becomes homed.
- Command min and max hood angles and verify physical endpoints match constants:
MIN_HOOD_ANGLEMAX_HOOD_ANGLE
- If hood does not hit setpoint repeatably, fix mechanism first (binding, backlash, slipping coupler, brownout).
- Command known turret angles (for example 0, +/-30, +/-90 deg).
- Verify measured
Turret Angletracks command with low overshoot. - Verify limits are respected (
MIN_TURRET_ANGLE,MAX_TURRET_ANGLE).
- Command a few fixed RPM values.
- Verify settle time and steady-state error.
- Confirm feed trigger behavior: kicker/indexer should only run when at speed and hood safe.
Tune these before static shot map collection. Otherwise you are recording compensation for bad control.
Parameters:
SHOOTER_KP,SHOOTER_KI,SHOOTER_KD,SHOOTER_KV- Runtime mirror in
TurretAssembly/flywheel/*
Procedure:
- Set
kI = 0,kD = 0initially. - Increase
kPuntil response is fast but not oscillatory. - Add
kVfor better tracking and reduced steady-state error at high RPM. - Add small
kDonly if needed for overshoot damping. - Keep
kInear zero unless a persistent bias remains.
Pass criteria:
- Settles quickly to commanded RPM.
- Error band comfortably within
FLYWHEEL_READY_TOLERANCE_RPS.
Parameters:
TURRET_KP,TURRET_KI,TURRET_KD,TURRET_KS
Procedure:
- Start with
kI = 0. - Raise
kPuntil near-critical response. - Add
kDfor damping. - Use
kSonly to overcome static friction/deadband, not to force aggressive motion.
Pass criteria:
- Tracks moving target without chatter.
- Holds angle without drift.
Parameters:
HOOD_KP,HOOD_KI,HOOD_KD
Procedure:
- Tune for no oscillation and consistent final angle.
- Validate repeatability after repeated up/down moves.
Pass criteria:
- Angle repeatability better than hood tolerance in practical shooting.
This is the most important calibration for stationary accuracy.
Current data file:
src/main/deploy/turret_data.json
- Robot stationary (vpar = 0).
- Use fixed target and known distances.
- Tune hood+RPM at each distance until repeatable makes.
- Record realistic
flight_timefor each point (critical for moving-shot lead). - Collect 4 to 8 points spanning full intended shot envelope.
- Keep denser points where curve bends most (mid/far range transitions).
- Avoid giant distance gaps; interpolation across big gaps causes weak midpoints.
- If using python helper from
pythonUtils/, generate/updateturret_data.json. - Copy to deploy path:
cp turret_data.json ../src/main/deploy/turret_data.json
- Redeploy robot code (
./gradlew deploy). - Reboot robot program to ensure fresh table load.
Goal: prove stationary shots are good before dynamic tuning.
- Set
Debug/Turret Targeting Mode = LUT. - Keep RPM/hood overrides disabled.
- Test each calibration distance.
- Record hit rate, left/right miss, short/long miss.
If misses are mostly short/long while stationary:
- LUT data points (hood/rpm) are wrong or too sparse.
If misses are mostly left/right while stationary:
- turret aiming frame/zero/heading convention issue or mechanical slop.
Do not proceed until this phase is stable.
Now tune motion compensation.
Purpose:
- Projects robot/turret position forward to account for perception + control + feed delay.
Test method:
- Drive perpendicular to target at constant speed.
- Fire repeated shots.
- Observe whether impacts lag or lead travel direction.
Adjustment:
- Shots land behind path: increase value.
- Shots land ahead of path: decrease value.
Notes:
- Start with small increments (around 0.01 s).
- Re-test at multiple speeds.
Purpose:
- Correct toward/away motion error without disturbing lateral lead.
Test method:
- Drive directly toward target and fire.
- Drive directly away and fire.
Adjustment:
- Toward = long, away = short: decrease value.
- Toward = short, away = long: increase value.
Purpose:
- Reduce turret lag while robot yaws.
Test method:
- Rotate chassis while maintaining target lock.
- Watch turret lag/overshoot.
Adjustment:
- Still lagging: increase FF.
- Overshooting/leading too much: decrease FF.
Use only after LUT mode is reliable.
Relevant debug entries:
Debug/Turret Targeting Mode:LUT,MODEL,AUTO_FALLBACKDebug/Model RPM OffsetDebug/Model Distance Bias InchesDebug/Model TOF ScaleDebug/Model Latency Offset SDebug/Model Range Latency Offset S
Telemetry to compare:
Turret/Selected SolverTurret/LUT-Model Hood Delta DegTurret/LUT-Model RPM Delta
Procedure:
- Set mode to
AUTO_FALLBACKfirst. - Observe delta telemetry across distances and speeds.
- Bring model close to LUT behavior in known-good zones:
- Use
Model Distance Bias Inchesfor broad range shift. - Use
Model RPM Offsetfor energy shift. - Use
Model TOF Scaleand latency offsets for lead timing.
- Use
- Test pure
MODELmode only after fallback behavior is predictable.
Use overrides to find a good point quickly while preserving solver telemetry.
- Set target override to fixed target (
RED_HUBorBLUE_HUBetc.). - Enable
Override RPM Enabledand/orOverride Hood Angle Enabled. - Sweep values until hit quality is good at that distance.
- Log the winning tuple into
turret_data.jsonas a static point. - Disable overrides after testing.
Important:
- Overrides affect actuation but the solver solution is still published for comparison.
Likely causes:
- Flywheel not inside
FLYWHEEL_READY_TOLERANCE_RPS. - Hood not homed.
- Hood safety zones suppressing feed.
has_valid_shotfalse due to missing target/solver output.
Checks:
- Flywheel RPM vs target RPM.
- Hood homed state.
has_valid_shotand selected target.- Safety-zone position.
Likely causes:
- Incorrect
flight_timevalues in LUT points. - Latency constants not tuned.
- Pose velocity estimate noisy.
Actions:
- Re-measure flight times.
- Re-tune lateral and radial latency constants.
- Validate odometry/velocity quality.
Likely causes:
- Turret zero sign/convention mismatch.
- Robot heading bias or gyro drift.
- Rotation FF too high/low in spin.
Actions:
- Verify commanded vs actual turret angle conventions.
- Verify heading reference and pose alignment.
- Re-tune
TURRET_ROTATION_FF.
Likely causes:
- Bad LUT hood/rpm points.
- Wrong target height assumption.
- Radial latency compensation sign/magnitude wrong.
Actions:
- Refresh points at affected ranges.
- Confirm target height constants and field dimensions.
- Re-tune range latency.
Likely causes:
- Target selection/alliance logic mismatch.
- Pose mirror/field frame mismatch.
Actions:
- Validate alliance detection.
- Compare
target_x/yagainst expected field points.
Likely causes:
- Sparse LUT points with abrupt interpolation slope changes.
- Noisy velocity input.
- Mechanical backlash in turret/hood.
Actions:
- Add intermediate LUT points.
- Reduce noise at source (pose filtering, wiring, CAN health).
- Tighten mechanism.
- 10 min: safety checks, homing, telemetry verification.
- 20 min: control-loop validation (no table edits).
- 25 min: static point collection/refresh for LUT.
- 20 min: moving-shot latency tuning (lateral then radial).
- 10 min: model/fallback comparison checks.
- 5 min: capture final constants and table snapshot in git.
- Commit every meaningful tuning change with notes:
- Distances tested
- Speeds tested
- Hit rates and miss pattern
- Keep old
turret_data.jsonsnapshots (git handles this). - Avoid changing more than one compensation variable at a time.
Primary:
src/main/deploy/turret_data.jsonpoints (distance,angle,rpm,flight_time)TURRET_KP/KD/KS,HOOD_KP/KD,SHOOTER_KP/KVSOTF_LATENCY_COMPENSATION_SSOTF_RANGE_LATENCY_COMPENSATION_STURRET_ROTATION_FF
Debug-only runtime knobs:
- Target override chooser
- Mode chooser (
LUT,MODEL,AUTO_FALLBACK) - RPM/hood override toggles and values
- Model bias/offset/scale entries
If you hit a state where nothing makes sense, reset to this baseline:
- LUT mode
- Overrides off
- Fresh hood homing
- Confirm pose + target telemetry
- Re-test one known-good static distance
That sequence isolates 90% of integration failures quickly.