Skip to content

Commit ae680ed

Browse files
j0shuaSaidnemgodmar
authored
54 add shift detection (#58)
* (#54) Add basic shift detection prototype * Match shift tracking and added to CoordinationLayer * change some of match state logic and added strategy constants for shift timing * remove json save * add constants to json * Add manual override functionality for match state in CoordinationLayer and MatchState * Add match state override button for blue * change match time to start as negative infinity so that when it init's it doesnt think its auto * almost finished. bug with red and blue override not changing the alliance that won auto * fix auto winner bug * auto winner changed to use Optional * (#54) Fix various review comments and clean up code (will resolve comments later) * (#54) Add strategy constants to CI checker and fix extra fields * (#54) Add button bindings for red/blue winning auto * (#54) Actually call bindings setup method and clean up getTimeLeftInCurrentShift by using a switch expression * (#54) Allow for user correction if auto winner is incorrectly selected; Protect against null game data; log auto winner * (#54) Remove old unused action keys * (#54) Document temporary code, remove unused volatile designation, remove old comment --------- Co-authored-by: aidnem <99768676+aidnem@users.noreply.github.com> Co-authored-by: gback <gback@vt.edu> Co-authored-by: Godmar Back <godmar@gmail.com>
1 parent d345478 commit ae680ed

11 files changed

Lines changed: 448 additions & 3 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,5 @@
7575
"Coppercore",
7676
"Tunables"
7777
],
78-
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx2G -Xms100m -Xlog:disable"
78+
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable"
7979
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"shiftStartGracePeriod": {
3+
"value": 2.0,
4+
"unit": "Second"
5+
},
6+
"shiftEndGracePeriod": {
7+
"value": 2.0,
8+
"unit": "Second"
9+
}
10+
}

src/main/deploy/constants/comp/controllers-xbox.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,28 @@
6363
}
6464
}
6565
]
66+
},
67+
{
68+
"port": 1,
69+
"type": "xbox",
70+
"controlElements": [
71+
{
72+
"command": "redWonAuto",
73+
"commandType": "button",
74+
"hapticControlElement": {
75+
"elementType": "button",
76+
"id": "b"
77+
}
78+
},
79+
{
80+
"command": "blueWonAuto",
81+
"commandType": "button",
82+
"hapticControlElement": {
83+
"elementType": "button",
84+
"id": "x"
85+
}
86+
}
87+
]
6688
}
6789
]
6890
}

src/main/java/frc/robot/ControllerSetup.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,16 @@ public static void initIntakeBindings(IntakeSubsystem intakeSubsystem) {
8686
() -> intakeSubsystem.runRollers(JsonConstants.intakeConstants.intakeRollerSpeed)))
8787
.onFalse(new InstantCommand(intakeSubsystem::stopRollers));
8888
}
89+
90+
public static void initMatchStateBindings(CoordinationLayer coordinationLayer) {
91+
var controllers = getControllers();
92+
controllers
93+
.getButton("redWonAuto")
94+
.getTrigger()
95+
.onTrue(new InstantCommand(coordinationLayer::overrideMatchStateRed));
96+
controllers
97+
.getButton("blueWonAuto")
98+
.getTrigger()
99+
.onTrue(new InstantCommand(coordinationLayer::overrideMatchStateBlue));
100+
}
89101
}

src/main/java/frc/robot/CoordinationLayer.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@
1414
import edu.wpi.first.math.geometry.Translation3d;
1515
import edu.wpi.first.math.kinematics.ChassisSpeeds;
1616
import edu.wpi.first.math.numbers.N3;
17+
import edu.wpi.first.wpilibj.DriverStation;
1718
import frc.robot.DependencyOrderedExecutor.ActionKey;
1819
import frc.robot.ShotCalculations.MapBasedShotInfo;
1920
import frc.robot.ShotCalculations.ShotInfo;
2021
import frc.robot.ShotCalculations.ShotTarget;
2122
import frc.robot.constants.FieldConstants;
2223
import frc.robot.constants.JsonConstants;
24+
import frc.robot.coordination.MatchState;
2325
import frc.robot.subsystems.HomingSwitch;
2426
import frc.robot.subsystems.drive.Drive;
2527
import frc.robot.subsystems.drive.DriveCoordinator;
@@ -30,6 +32,7 @@
3032
import frc.robot.subsystems.shooter.ShooterSubsystem;
3133
import frc.robot.subsystems.turret.TurretSubsystem;
3234
import java.util.Optional;
35+
import org.littletonrobotics.junction.Logger;
3336

3437
/**
3538
* The coordination layer is responsible for updating subsystem dependencies, running the shot
@@ -61,14 +64,25 @@ public class CoordinationLayer {
6164
new ActionKey("CoordinationLayer::runShotCalculator");
6265
public static final ActionKey RUN_DEMO_MODES =
6366
new ActionKey("CoordinationLayer::runSubsystemDemoModes");
67+
public static final ActionKey UPDATE_MATCH_STATE =
68+
new ActionKey("CoordinationLayer::updateMatchState");
6469

6570
// State variables (these will be updated by various methods and then their values will be passed
6671
// to subsystems during the execution of a cycle)
72+
private final MatchState matchState = new MatchState();
73+
// Manual override requests set by controller bindings. These are cleared once consumed in
74+
// updateMatchState and forwarded to MatchState.enabledPeriodic as booleans.
75+
private boolean manualRedOverrideRequest = false;
76+
private boolean manualBlueOverrideRequest = false;
77+
6778
public CoordinationLayer(DependencyOrderedExecutor dependencyOrderedExecutor) {
6879
this.dependencyOrderedExecutor = dependencyOrderedExecutor;
6980

81+
dependencyOrderedExecutor.registerAction(UPDATE_MATCH_STATE, this::updateMatchState);
7082
dependencyOrderedExecutor.registerAction(RUN_SHOT_CALCULATOR, this::runShotCalculator);
7183
dependencyOrderedExecutor.registerAction(RUN_DEMO_MODES, this::runSubsystemDemoModes);
84+
85+
dependencyOrderedExecutor.addDependencies(RUN_SHOT_CALCULATOR, UPDATE_MATCH_STATE);
7286
}
7387

7488
/**
@@ -211,6 +225,9 @@ private void updateIntakeDependencies(IntakeSubsystem intake) {
211225
}
212226

213227
// Coordination and processing
228+
/** Coordinates subsystem actions based on the desired action and subsystem inputs */
229+
public void coordinateSubsystemActions() {}
230+
214231
/**
215232
* Runs the shot calculator and logs the resulting trajectories for debugging. Eventually, this
216233
* method should also command the subsystems to take their actinos.
@@ -331,6 +348,35 @@ private void runSubsystemDemoModes() {
331348
}
332349
}
333350

351+
/** Update the MatchState each periodic loop */
352+
private void updateMatchState() {
353+
if (DriverStation.isEnabled()) {
354+
matchState.enabledPeriodic(manualRedOverrideRequest, manualBlueOverrideRequest);
355+
}
356+
357+
// This is temporary code left here to make it easy to integrate the time left functionality
358+
// with LEDs and superstructure coordination later.
359+
double timeLeft = matchState.getTimeLeftInCurrentShift();
360+
361+
boolean hasFiveSecondsLeft = timeLeft >= 5.0;
362+
Logger.recordOutput("MatchState/has5sLeft", hasFiveSecondsLeft);
363+
}
364+
365+
/**
366+
* Called by a controller binding or DOE action to request that the match state be overridden to
367+
* red for the next enabledPeriodic call. This sets a one-shot request which is consumed by
368+
* updateMatchState.
369+
*/
370+
public void overrideMatchStateRed() {
371+
manualRedOverrideRequest = true;
372+
manualBlueOverrideRequest = false;
373+
}
374+
375+
public void overrideMatchStateBlue() {
376+
manualBlueOverrideRequest = true;
377+
manualRedOverrideRequest = false;
378+
}
379+
334380
/**
335381
* Given an "ideal" shot, command the scoring subsystems to target it
336382
*

src/main/java/frc/robot/DependencyOrderedExecutor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public DependencyOrderedExecutor(Time period) {
6666
}
6767

6868
/**
69-
* Register an action, setting the Runnable associated with an ActionKey
69+
* Register an action to run in each periodic, setting the Runnable associated with an ActionKey
7070
*
7171
* @param key The key of the action to register
7272
* @param action The Runnable to run in order to execute this action

src/main/java/frc/robot/RobotContainer.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ private void configureButtonBindings() {
191191
drive.ifPresent(
192192
(drive) -> {
193193
ControllerSetup.initDriveBindings(driveCoordinator, drive);
194+
ControllerSetup.initMatchStateBindings(coordinationLayer);
194195
});
195196
});
196197

src/main/java/frc/robot/constants/JsonConstants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public static void loadConstants() {
7777
jsonHandler.getObject(new FieldLocationInstance(), "RedFieldLocations.json");
7878
blueFieldLocations =
7979
jsonHandler.getObject(new FieldLocationInstance(), "BlueFieldLocations.json");
80+
strategyConstants = jsonHandler.getObject(new StrategyConstants(), "StrategyConstants.json");
8081

8182
if (featureFlags.useTuningServer) {
8283
// do not crash Robot if routes could not be added for any reason
@@ -128,6 +129,7 @@ public static void loadConstants() {
128129
public static ShotMaps shotMaps;
129130
public static FieldLocationInstance redFieldLocations;
130131
public static FieldLocationInstance blueFieldLocations;
132+
public static StrategyConstants strategyConstants;
131133

132134
public static Controllers controllers;
133135
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package frc.robot.constants;
2+
3+
import static edu.wpi.first.units.Units.Seconds;
4+
5+
import edu.wpi.first.units.measure.Time;
6+
7+
public class StrategyConstants {
8+
// Due to the presence of these constants, it is necessary for the driver(s) to play an active
9+
// role in deciding when to score.
10+
11+
/**
12+
* How much grace period to "add" to the start of each shooting shift.
13+
*
14+
* <p>For example, a value of 5 seconds means that the robot will enable shooting features 5
15+
* seconds before it estimates that an active shift begins
16+
*
17+
* <p>This constant is necessary because getMatchTime does not return an exact match result, and
18+
* so the match time is simply an estimate.
19+
*/
20+
public final Time shiftStartGracePeriod = Seconds.of(2.0);
21+
22+
/**
23+
* How much grace period to "add" to the end of each shooting shift.
24+
*
25+
* <p>For example, a value of 5 seconds means that the robot will only disable shooting features 5
26+
* seconds after it estimates that an active shift has ended
27+
*
28+
* <p>This constant is necessary because getMatchTime does not return an exact match result, and
29+
* so the match time is simply an estimate.
30+
*/
31+
public final Time shiftEndGracePeriod = Seconds.of(2.0);
32+
33+
// list of shift start times in seconds from the start of the match
34+
// 2:20
35+
public static final Double transitionStart = 2 * 60 + 20.0; // 140
36+
37+
// 2:10
38+
public static final Double shift1Start = 2 * 60 + 10.0; // 130
39+
40+
// 1:45
41+
public static final Double shift2Start = 60 + 45.0; // 105
42+
43+
// 1:20
44+
public static final Double shift3Start = 60 + 20.0; // 80
45+
46+
// 0:55
47+
public static final Double shift4Start = 55.0;
48+
49+
// 0:30
50+
public static final Double endgameStart = 30.0;
51+
52+
// 0:00
53+
public static final Double matchEnd = 0.0;
54+
}

0 commit comments

Comments
 (0)