2424import edu .wpi .first .math .geometry .Translation2d ;
2525import java .util .List ;
2626import org .curtinfrc .frc2026 .util .Repulsor .Constants ;
27- import org .curtinfrc .frc2026 .util .Repulsor .ExtraPathing ;
2827import org .curtinfrc .frc2026 .util .Repulsor .FieldPlanner .Obstacle ;
2928import org .curtinfrc .frc2026 .util .Repulsor .FieldPlanner .Obstacles .GatedAttractorObstacle ;
29+ import org .littletonrobotics .junction .Logger ;
3030
3131public final class FieldPlannerGoalManager {
3232 private static final double STAGED_CENTER_BAND_M = 3.648981 ;
@@ -36,6 +36,7 @@ public final class FieldPlannerGoalManager {
3636
3737 private static final double STAGED_REACH_ENTER_M = 0.35 ;
3838 private static final double STAGED_REACH_EXIT_M = 0.55 ;
39+ private static final double STAGED_GATE_CLEAR_EXIT_M = 0.40 ;
3940 private static final int STAGED_REACH_TICKS = 3 ;
4041 private static final int STAGED_GATE_CLEAR_TICKS = 2 ;
4142
@@ -48,10 +49,14 @@ public final class FieldPlannerGoalManager {
4849
4950 private static final double STAGED_GATE_PAD_M = 0.25 ;
5051 private static final double STAGED_PASSED_X_HYST_M = 0.35 ;
52+ private static final double STAGED_PASSED_TARGET_PROJ_M = 0.16 ;
5153 private static final double STAGED_GOAL_SIDE_PROJ_M = 0.05 ;
54+ private static final double STAGED_LEAD_THROUGH_SCALE = 0.28 ;
55+ private static final double STAGED_LEAD_THROUGH_MIN_M = 0.45 ;
56+ private static final double STAGED_LEAD_THROUGH_MAX_M = 1.05 ;
5257 private static final double STAGED_DEEP_CENTER_BAND_M = 1.40 ;
53- private static final double STAGED_CENTER_RETURN_STAGE_TRIGGER_M = 2.2 ;
54- private static final double STAGED_CENTER_RETURN_INTERSECTION_TRIGGER_M = 3.0 ;
58+ private static final double STAGED_CENTER_RETURN_STAGE_TRIGGER_M = 3.0 ;
59+ private static final double STAGED_CENTER_RETURN_INTERSECTION_TRIGGER_M = 4.2 ;
5560 private static final double STAGED_CENTER_RETURN_EXIT_MIN_M = 0.70 ;
5661 private static final double STAGED_CENTER_RETURN_EXIT_MAX_M = 2.40 ;
5762 private static final double STAGED_CENTER_RETURN_GATE_MIN_OFFSET_M = 2.0 ;
@@ -105,6 +110,7 @@ public void setRequestedGoal(Pose2d requested) {
105110
106111 public void setActiveGoal (Pose2d active ) {
107112 this .goal = active ;
113+ Logger .recordOutput ("ActiveGoal" , this .goal );
108114 }
109115
110116 public boolean updateStagedGoal (Translation2d curPos , List <? extends Obstacle > obstacles ) {
@@ -128,14 +134,14 @@ public boolean updateStagedGoal(Translation2d curPos, List<? extends Obstacle> o
128134 }
129135
130136 Translation2d reqT = requestedGoal .getTranslation ();
131- GatedAttractorObstacle firstBlock = firstOccludingGateAlongSegment (curPos , reqT , obstacles );
137+ GatedAttractorObstacle firstBlock = firstOccludingGateAlongSegment (curPos , reqT );
132138
133139 boolean stageForOccludingGate =
134140 firstBlock != null && !shouldDeferCenterReturnStage (curPos , reqT , firstBlock );
135141 boolean shouldStage = shouldStageThroughAttractor (curPos , reqT ) || stageForOccludingGate ;
136142 if (stagedComplete && lastStagedPoint != null ) {
137143 double d = curPos .getDistance (lastStagedPoint );
138- if (d < STAGED_RESTAGE_DIST_M ) {
144+ if (d < STAGED_RESTAGE_DIST_M && ! stageForOccludingGate ) {
139145 shouldStage = false ;
140146 } else {
141147 stagedComplete = false ;
@@ -202,6 +208,8 @@ public boolean updateStagedGoal(Translation2d curPos, List<? extends Obstacle> o
202208 Translation2d liveTarget =
203209 (stagedGate != null ) ? stagingPullPoint (stagedGate , curPos , reqT ) : stagedAttractor ;
204210 if (liveTarget == null ) liveTarget = stagedAttractor ;
211+ boolean passedLiveTargetTowardGoal =
212+ hasPassedPointTowardGoal (curPos , liveTarget , reqT , STAGED_PASSED_TARGET_PROJ_M );
205213
206214 double d = curPos .getDistance (liveTarget );
207215
@@ -219,19 +227,24 @@ public boolean updateStagedGoal(Translation2d curPos, List<? extends Obstacle> o
219227 stagedGatePassed
220228 || gateIsBehind (curPos , reqT , stagedGate )
221229 || gateOnGoalSide (curPos , reqT , stagedGate )
222- || !gateOccludingNow ;
230+ || !gateOccludingNow
231+ || passedLiveTargetTowardGoal ;
223232 }
224233
225234 boolean gateCleared = (stagedGate == null ) || stagedGatePassed ;
226235 if (gateCleared ) stagedGateClearTicks ++;
227236 else stagedGateClearTicks = 0 ;
228237
229- if (!reached && stagedGate != null && stagedGateClearTicks >= STAGED_GATE_CLEAR_TICKS )
238+ if (!reached
239+ && stagedGate != null
240+ && stagedGateClearTicks >= STAGED_GATE_CLEAR_TICKS
241+ && (passedLiveTargetTowardGoal || d <= STAGED_GATE_CLEAR_EXIT_M )) {
230242 reached = true ;
231- if (!reached && stagedGate != null && gateCleared && d <= STAGED_REACH_EXIT_M ) reached = true ;
243+ }
244+ if (!reached && stagedGate == null && passedLiveTargetTowardGoal ) reached = true ;
232245
233246 if (stagedModeTicks >= STAGED_MAX_TICKS ) {
234- GatedAttractorObstacle nowFirst = firstOccludingGateAlongSegment (curPos , reqT , obstacles );
247+ GatedAttractorObstacle nowFirst = firstOccludingGateAlongSegment (curPos , reqT );
235248 if (nowFirst == null || stagedGatePassed ) {
236249 reached = true ;
237250 gateCleared = true ;
@@ -408,7 +421,7 @@ private static boolean gateOnGoalSide(
408421 }
409422
410423 private GatedAttractorObstacle firstOccludingGateAlongSegment (
411- Translation2d pos , Translation2d target , List <? extends Obstacle > obstacles ) {
424+ Translation2d pos , Translation2d target ) {
412425 if (gatedAttractors .isEmpty () || pos == null || target == null ) return null ;
413426
414427 GatedAttractorObstacle best = null ;
@@ -424,14 +437,6 @@ private GatedAttractorObstacle firstOccludingGateAlongSegment(
424437 Translation2d [] poly = expandPoly (gate .gatePoly , STAGED_GATE_PAD_M );
425438
426439 if (!FieldPlannerGeometry .segmentIntersectsPolygonOuter (pos , target , poly )) continue ;
427- if (!ExtraPathing .isClearPath (
428- "WaypointByp" ,
429- pos ,
430- target ,
431- obstacles ,
432- org .curtinfrc .frc2026 .Constants .ROBOT_X ,
433- org .curtinfrc .frc2026 .Constants .ROBOT_Y ,
434- false )) continue ;
435440 double t = firstIntersectionT (pos , target , poly );
436441 if (t < bestT - tieEps ) {
437442 bestT = t ;
@@ -570,10 +575,53 @@ private Translation2d stagingPullPoint(
570575 : (insideOnRight ? outside : inside ))
571576 : center ;
572577
578+ pick = extendPullPointThroughGate (pick , center , target );
579+
573580 if (gate == stagedGate ) stagedLatchedPull = pick ;
574581 return pick ;
575582 }
576583
584+ private static boolean hasPassedPointTowardGoal (
585+ Translation2d pos , Translation2d point , Translation2d goal , double projMeters ) {
586+ if (pos == null || point == null || goal == null ) return false ;
587+
588+ Translation2d toGoal = goal .minus (point );
589+ double n = toGoal .getNorm ();
590+ if (n <= 1e-6 ) return pos .getDistance (point ) <= Math .max (0.0 , projMeters );
591+
592+ Translation2d dir = toGoal .div (n );
593+ Translation2d toPos = pos .minus (point );
594+ double proj = toPos .getX () * dir .getX () + toPos .getY () * dir .getY ();
595+ return proj >= Math .max (0.0 , projMeters );
596+ }
597+
598+ private static Translation2d extendPullPointThroughGate (
599+ Translation2d pullPoint , Translation2d gateCenter , Translation2d target ) {
600+ if (pullPoint == null || gateCenter == null || target == null ) return pullPoint ;
601+
602+ double dx = target .getX () - gateCenter .getX ();
603+ double sign = Math .signum (dx );
604+ if (Math .abs (sign ) < 1e-9 ) return pullPoint ;
605+
606+ double lead =
607+ MathUtil .clamp (
608+ Math .abs (dx ) * STAGED_LEAD_THROUGH_SCALE ,
609+ STAGED_LEAD_THROUGH_MIN_M ,
610+ STAGED_LEAD_THROUGH_MAX_M );
611+
612+ double x =
613+ MathUtil .clamp (
614+ pullPoint .getX () + sign * lead ,
615+ STAGED_FIELD_EDGE_MARGIN_M ,
616+ Constants .FIELD_LENGTH - STAGED_FIELD_EDGE_MARGIN_M );
617+ double y =
618+ MathUtil .clamp (
619+ pullPoint .getY (),
620+ STAGED_FIELD_EDGE_MARGIN_M ,
621+ Constants .FIELD_WIDTH - STAGED_FIELD_EDGE_MARGIN_M );
622+ return new Translation2d (x , y );
623+ }
624+
577625 private GatedAttractorObstacle chooseBestGateByScore (
578626 Translation2d pos , Translation2d target , GatedAttractorObstacle preferredGate ) {
579627
0 commit comments