Skip to content

Commit 2d54f13

Browse files
Expose waypoint diagnostics and clean ranking defaults
1 parent 6db2ff3 commit 2d54f13

6 files changed

Lines changed: 87 additions & 26 deletions

File tree

src/main/java/org/curtinfrc/frc2026/util/Repulsor/FieldPlanner/FieldPlanner.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Helpers.FieldPlannerGeometry;
4242
import org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Helpers.FieldPlannerGoalManager;
4343
import org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Helpers.FieldPlannerWaypointConfig;
44+
import org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Helpers.FieldPlannerWaypointStatus;
4445
import org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Helpers.FieldPlannerWaypointStrategy;
4546
import org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Obstacles.GatedAttractorObstacle;
4647
import org.curtinfrc.frc2026.util.Repulsor.Fields.FieldGeometry;
@@ -376,6 +377,10 @@ public FieldPlannerWaypointConfig getWaypointConfig() {
376377
return goalManager.getWaypointConfig();
377378
}
378379

380+
public FieldPlannerWaypointStatus getWaypointStatus() {
381+
return goalManager.getWaypointStatus();
382+
}
383+
379384
/**
380385
* Returns the get requested goal pose value maintained by this Repulsor component.
381386
*

src/main/java/org/curtinfrc/frc2026/util/Repulsor/FieldPlanner/Helpers/FieldPlannerGoalManager.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ public final class FieldPlannerGoalManager {
9696
private boolean stagedCenterReturn = false;
9797
private boolean stagedExitPhase = false;
9898
private Translation2d stagedExitPoint = null;
99+
private FieldPlannerWaypointDecision lastStrategyDecision =
100+
FieldPlannerWaypointDecision.useDefault();
99101

100102
private final List<GatedAttractorObstacle> gatedAttractors;
101103
private final double fieldLengthMeters;
@@ -219,6 +221,22 @@ public FieldPlannerWaypointConfig getWaypointConfig() {
219221
return waypointConfig;
220222
}
221223

224+
public FieldPlannerWaypointStatus getWaypointStatus() {
225+
return new FieldPlannerWaypointStatus(
226+
requestedGoal,
227+
goal,
228+
lastStrategyDecision,
229+
stagedAttractor != null,
230+
stagedAttractor,
231+
stagedExitPoint,
232+
stagedGate == null ? null : stagedGate.center,
233+
stagedExitPhase,
234+
stagedComplete,
235+
stagedUsingBypass,
236+
stagedCenterReturn,
237+
stagedModeTicks);
238+
}
239+
222240
/**
223241
* Updates set requested goal state or telemetry as part of the Repulsor runtime loop. This may
224242
* mutate local state, NetworkTables output, planner caches, or command-side runtime state
@@ -281,6 +299,7 @@ public boolean updateStagedGoal(Translation2d curPos, List<? extends Obstacle> o
281299
stagedExitPhase);
282300
FieldPlannerWaypointDecision decision = waypointStrategy.decide(context);
283301
if (decision == null) decision = FieldPlannerWaypointDecision.useDefault();
302+
lastStrategyDecision = decision;
284303
if (decision.goesDirectlyToRequestedGoal()) {
285304
clearStagedState(false);
286305
goal = requestedGoal;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.curtinfrc.frc2026.util.Repulsor.FieldPlanner.Helpers;
2+
3+
import edu.wpi.first.math.geometry.Pose2d;
4+
import edu.wpi.first.math.geometry.Translation2d;
5+
6+
/** Structured snapshot of the goal manager's waypoint/staging state for tests and telemetry. */
7+
public record FieldPlannerWaypointStatus(
8+
Pose2d requestedGoal,
9+
Pose2d activeGoal,
10+
FieldPlannerWaypointDecision lastStrategyDecision,
11+
boolean activeStage,
12+
Translation2d stagedAttractor,
13+
Translation2d stagedExitPoint,
14+
Translation2d stagedGateCenter,
15+
boolean exitPhase,
16+
boolean stagedComplete,
17+
boolean usingBypass,
18+
boolean centerReturn,
19+
int stagedModeTicks) {
20+
public FieldPlannerWaypointStatus {
21+
if (lastStrategyDecision == null)
22+
lastStrategyDecision = FieldPlannerWaypointDecision.useDefault();
23+
}
24+
}

src/main/java/org/curtinfrc/frc2026/util/Repulsor/Predictive/Model/PredictiveRankingConfig.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.curtinfrc.frc2026.util.Repulsor.Predictive.Model;
22

3-
import org.curtinfrc.frc2026.util.Repulsor.Predictive.PredictiveFieldStateOps;
4-
53
/** Tunable weights used when ranking field-object setpoints. */
64
public record PredictiveRankingConfig(
75
double advantageGain,
@@ -12,28 +10,37 @@ public record PredictiveRankingConfig(
1210
double headingGain,
1311
double hysteresisBonus,
1412
double hysteresisPersistSeconds) {
13+
public static final double DEFAULT_ADVANTAGE_GAIN = 1.1;
14+
public static final double DEFAULT_DISTANCE_COST = 0.10;
15+
public static final double DEFAULT_PRESSURE_COST = 0.72;
16+
public static final double DEFAULT_CONGESTION_COST = 0.95;
17+
public static final double DEFAULT_CAPACITY_GAIN = 0.45;
18+
public static final double DEFAULT_HEADING_GAIN = 0.18;
19+
public static final double DEFAULT_HYSTERESIS_BONUS = 0.22;
20+
public static final double DEFAULT_HYSTERESIS_PERSIST_SECONDS = 0.8;
21+
1522
public static PredictiveRankingConfig defaults() {
1623
return new PredictiveRankingConfig(
17-
PredictiveFieldStateOps.ADV_GAIN,
18-
PredictiveFieldStateOps.DIST_COST,
19-
PredictiveFieldStateOps.PRESSURE_GAIN,
20-
PredictiveFieldStateOps.CONGEST_COST,
21-
PredictiveFieldStateOps.CAPACITY_GAIN,
22-
PredictiveFieldStateOps.HEADING_GAIN,
23-
PredictiveFieldStateOps.HYST_BONUS,
24-
PredictiveFieldStateOps.HYST_PERSIST_S);
24+
DEFAULT_ADVANTAGE_GAIN,
25+
DEFAULT_DISTANCE_COST,
26+
DEFAULT_PRESSURE_COST,
27+
DEFAULT_CONGESTION_COST,
28+
DEFAULT_CAPACITY_GAIN,
29+
DEFAULT_HEADING_GAIN,
30+
DEFAULT_HYSTERESIS_BONUS,
31+
DEFAULT_HYSTERESIS_PERSIST_SECONDS);
2532
}
2633

2734
public PredictiveRankingConfig {
28-
advantageGain = finiteNonNegative(advantageGain, PredictiveFieldStateOps.ADV_GAIN);
29-
distanceCost = finiteNonNegative(distanceCost, PredictiveFieldStateOps.DIST_COST);
30-
pressureCost = finiteNonNegative(pressureCost, PredictiveFieldStateOps.PRESSURE_GAIN);
31-
congestionCost = finiteNonNegative(congestionCost, PredictiveFieldStateOps.CONGEST_COST);
32-
capacityGain = finiteNonNegative(capacityGain, PredictiveFieldStateOps.CAPACITY_GAIN);
33-
headingGain = finiteNonNegative(headingGain, PredictiveFieldStateOps.HEADING_GAIN);
34-
hysteresisBonus = finiteNonNegative(hysteresisBonus, PredictiveFieldStateOps.HYST_BONUS);
35+
advantageGain = finiteNonNegative(advantageGain, DEFAULT_ADVANTAGE_GAIN);
36+
distanceCost = finiteNonNegative(distanceCost, DEFAULT_DISTANCE_COST);
37+
pressureCost = finiteNonNegative(pressureCost, DEFAULT_PRESSURE_COST);
38+
congestionCost = finiteNonNegative(congestionCost, DEFAULT_CONGESTION_COST);
39+
capacityGain = finiteNonNegative(capacityGain, DEFAULT_CAPACITY_GAIN);
40+
headingGain = finiteNonNegative(headingGain, DEFAULT_HEADING_GAIN);
41+
hysteresisBonus = finiteNonNegative(hysteresisBonus, DEFAULT_HYSTERESIS_BONUS);
3542
hysteresisPersistSeconds =
36-
finiteNonNegative(hysteresisPersistSeconds, PredictiveFieldStateOps.HYST_PERSIST_S);
43+
finiteNonNegative(hysteresisPersistSeconds, DEFAULT_HYSTERESIS_PERSIST_SECONDS);
3744
}
3845

3946
public PredictiveRankingConfig withDistanceCost(double value) {

src/main/java/org/curtinfrc/frc2026/util/Repulsor/Predictive/PredictiveFieldStateOps.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -244,49 +244,50 @@ public void markCollectDepleted(Translation2d p, double cellM, double strength)
244244
* Configuration value for hyst persist s. The valid range and tuning source are defined by the
245245
* owning subsystem or field profile.
246246
*/
247-
public static final double HYST_PERSIST_S = 0.8;
247+
public static final double HYST_PERSIST_S =
248+
PredictiveRankingConfig.DEFAULT_HYSTERESIS_PERSIST_SECONDS;
248249

249250
/**
250251
* Configuration value for hyst bonus. The valid range and tuning source are defined by the owning
251252
* subsystem or field profile.
252253
*/
253-
public static final double HYST_BONUS = 0.22;
254+
public static final double HYST_BONUS = PredictiveRankingConfig.DEFAULT_HYSTERESIS_BONUS;
254255

255256
/**
256257
* Configuration value for adv gain. The valid range and tuning source are defined by the owning
257258
* subsystem or field profile.
258259
*/
259-
public static final double ADV_GAIN = 1.1;
260+
public static final double ADV_GAIN = PredictiveRankingConfig.DEFAULT_ADVANTAGE_GAIN;
260261

261262
/**
262263
* Configuration value for dist cost. The valid range and tuning source are defined by the owning
263264
* subsystem or field profile.
264265
*/
265-
public static final double DIST_COST = 0.10;
266+
public static final double DIST_COST = PredictiveRankingConfig.DEFAULT_DISTANCE_COST;
266267

267268
/**
268269
* Configuration value for pressure gain. The valid range and tuning source are defined by the
269270
* owning subsystem or field profile.
270271
*/
271-
public static final double PRESSURE_GAIN = 0.72;
272+
public static final double PRESSURE_GAIN = PredictiveRankingConfig.DEFAULT_PRESSURE_COST;
272273

273274
/**
274275
* Configuration value for congest cost. The valid range and tuning source are defined by the
275276
* owning subsystem or field profile.
276277
*/
277-
public static final double CONGEST_COST = 0.95;
278+
public static final double CONGEST_COST = PredictiveRankingConfig.DEFAULT_CONGESTION_COST;
278279

279280
/**
280281
* Configuration value for capacity gain. The valid range and tuning source are defined by the
281282
* owning subsystem or field profile.
282283
*/
283-
public static final double CAPACITY_GAIN = 0.45;
284+
public static final double CAPACITY_GAIN = PredictiveRankingConfig.DEFAULT_CAPACITY_GAIN;
284285

285286
/**
286287
* Configuration value for heading gain. The valid range and tuning source are defined by the
287288
* owning subsystem or field profile.
288289
*/
289-
public static final double HEADING_GAIN = 0.18;
290+
public static final double HEADING_GAIN = PredictiveRankingConfig.DEFAULT_HEADING_GAIN;
290291

291292
/**
292293
* Configuration value for collect value gain. The valid range and tuning source are defined by

src/test/java/org/curtinfrc/frc2026/util/Repulsor/FieldPlanner/Helpers/FieldPlannerGoalManagerTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,11 @@ void customStrategyCanDefineNonCorridorWaypointingWithoutGates() {
386386
assertFalse(manager.updateStagedGoal(new Translation2d(2.0, 2.0), List.of()));
387387
assertEquals(4.0, manager.getGoalTranslation().getX(), EPS);
388388
assertEquals(6.0, manager.getGoalTranslation().getY(), EPS);
389+
FieldPlannerWaypointStatus status = manager.getWaypointStatus();
390+
assertEquals(FieldPlannerWaypointDecision.Mode.STAGE, status.lastStrategyDecision().mode());
391+
assertTrue(status.activeStage());
392+
assertEquals(4.0, status.stagedAttractor().getX(), EPS);
393+
assertEquals(requested.getX(), status.requestedGoal().getX(), EPS);
389394

390395
assertFalse(manager.updateStagedGoal(new Translation2d(3.0, 5.0), List.of()));
391396
assertEquals(4.0, manager.getGoalTranslation().getX(), EPS);

0 commit comments

Comments
 (0)