Merge branch 'Timer' into gurt

This commit is contained in:
Shikhar
2026-03-19 16:06:31 -06:00
5 changed files with 172 additions and 12 deletions
-5
View File
@@ -1,9 +1,4 @@
{ {
"System Joysticks": {
"window": {
"enabled": false
}
},
"keyboardJoysticks": [ "keyboardJoysticks": [
{ {
"axisConfig": [ "axisConfig": [
+4
View File
@@ -20,6 +20,8 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler;
import frc4388.robot.constants.BuildConstants; import frc4388.robot.constants.BuildConstants;
import frc4388.robot.constants.Constants.SimConstants; import frc4388.robot.constants.Constants.SimConstants;
import frc4388.utility.DeferredBlock; import frc4388.utility.DeferredBlock;
import frc4388.utility.compute.HubShiftTimer;
import frc4388.utility.compute.HubShiftTimer.ShiftInfo;
import frc4388.utility.compute.RobotTime; import frc4388.utility.compute.RobotTime;
import frc4388.utility.compute.Trim; import frc4388.utility.compute.Trim;
import frc4388.utility.status.FaultReporter; import frc4388.utility.status.FaultReporter;
@@ -113,6 +115,7 @@ public class Robot extends LoggedRobot {
m_autonomousCommand.schedule(); m_autonomousCommand.schedule();
} }
m_robotTime.startMatchTime(); m_robotTime.startMatchTime();
HubShiftTimer.initializeAuto();
} }
/** /**
@@ -138,6 +141,7 @@ public class Robot extends LoggedRobot {
} }
m_robotTime.startMatchTime(); m_robotTime.startMatchTime();
HubShiftTimer.initializeTeleop();
} }
/** /**
@@ -7,12 +7,12 @@ public final class BuildConstants {
public static final String MAVEN_GROUP = ""; public static final String MAVEN_GROUP = "";
public static final String MAVEN_NAME = "2026KPopRobotHunters"; public static final String MAVEN_NAME = "2026KPopRobotHunters";
public static final String VERSION = "unspecified"; public static final String VERSION = "unspecified";
public static final int GIT_REVISION = 167; public static final int GIT_REVISION = 149;
public static final String GIT_SHA = "85fe11c8bdd51d8671e98047f88a2d42276f7094"; public static final String GIT_SHA = "ed7d0907b189f1b732408164152aca99f1ca5b81";
public static final String GIT_DATE = "2026-03-18 13:39:27 MDT"; public static final String GIT_DATE = "2026-03-17 00:31:53 MDT";
public static final String GIT_BRANCH = "MiraOrg"; public static final String GIT_BRANCH = "Timer";
public static final String BUILD_DATE = "2026-03-18 16:02:33 MDT"; public static final String BUILD_DATE = "2026-03-17 12:46:28 MDT";
public static final long BUILD_UNIX_TIME = 1773871353359L; public static final long BUILD_UNIX_TIME = 1773773188939L;
public static final int DIRTY = 1; public static final int DIRTY = 1;
private BuildConstants(){} private BuildConstants(){}
@@ -19,6 +19,8 @@ import frc4388.robot.subsystems.intake.Intake;
import frc4388.robot.subsystems.led.LED; import frc4388.robot.subsystems.led.LED;
import frc4388.robot.subsystems.swerve.SwerveDrive; import frc4388.robot.subsystems.swerve.SwerveDrive;
import frc4388.utility.compute.FieldPositions; import frc4388.utility.compute.FieldPositions;
import frc4388.utility.compute.HubShiftTimer;
import frc4388.utility.compute.HubShiftTimer.ShiftInfo;
public class Shooter extends SubsystemBase { public class Shooter extends SubsystemBase {
public ShooterIO io; public ShooterIO io;
@@ -114,8 +116,13 @@ public class Shooter extends SubsystemBase {
@Override @Override
public void periodic() { public void periodic() {
// FaultReporter.register(this); // TODO Implement fault reporter // FaultReporter.register(this); // TODO Implement fault reporter
//Hub Shift logs
ShiftInfo info = HubShiftTimer.getShiftInfo();
Logger.recordOutput("HubShift/IsActive", info.isActive());
Logger.recordOutput("HubShift/RemainingInShift", info.remainingInShift());
Logger.recordOutput("HubShift/Phase", info.phase().name());
Logger.processInputs("Shooter", state); Logger.processInputs("Shooter", state);
io.updateInputs(state); io.updateInputs(state);
@@ -0,0 +1,154 @@
package frc4388.utility.compute;
import edu.wpi.first.wpilibj.DriverStation;
import edu.wpi.first.wpilibj.DriverStation.Alliance;
import edu.wpi.first.wpilibj.Timer;
public class HubShiftTimer {
public enum ShiftPhase {
DISABLED,
AUTO,
TRANSITION, // 0 10 s
SHIFT1, // 10 35 s
SHIFT2, // 35 60 s
SHIFT3, // 60 85 s
SHIFT4, // 85 110 s
ENDGAME // 110 140 s
}
public record ShiftInfo(
ShiftPhase phase,
double elapsedInShift,
double remainingInShift,
boolean isActive) {}
//total teleop time
public static final double TELEOP_DURATION = 140.0;
//total auto time
public static final double AUTO_DURATION = 20.0;
//shift start and end times for calculations
private static final double[] SHIFT_STARTS = {0.0, 10.0, 35.0, 60.0, 85.0, 110.0};
private static final double[] SHIFT_ENDS = {10.0, 35.0, 60.0, 85.0, 110.0, 140.0};
//hub active schedule, true is active and false is inactive
//starts always as active becasue transition is first and is active, but then is inactive for winner or active for loser
private static final boolean[] WINNER_SCHEDULE = {true, false, true, false, true, true};
private static final boolean[] LOSER_SCHEDULE = {true, true, false, true, false, true};
//shift phase names during teleop
private static final ShiftPhase[] SHIFT_PHASES = {
ShiftPhase.TRANSITION,
ShiftPhase.SHIFT1,
ShiftPhase.SHIFT2,
ShiftPhase.SHIFT3,
ShiftPhase.SHIFT4,
ShiftPhase.ENDGAME
};
//timer to track time
private static final Timer teleopTimer = new Timer();
private static double timerOffset = 0.0;
//fms syncing idk other team did it too
private static final double RESYNC_THRESHOLD = 3.0;
//call at start of auto to start timer
public static void initializeAuto() {
teleopTimer.restart();
}
//call at start of teleop to start timer again because sometimes delay between auto and telop
public static void initializeTeleop() {
timerOffset = 0.0;
teleopTimer.restart();
}
//returns the updated shift info based on the winner of auto
public static ShiftInfo getShiftInfo() {
if (!DriverStation.isEnabled()) {
return new ShiftInfo(ShiftPhase.DISABLED, 0.0, 0.0, false);
}
if (DriverStation.isAutonomousEnabled()) {
double autoElapsed = teleopTimer.get(); // timer restarts in initialize()
return new ShiftInfo(
ShiftPhase.AUTO,
autoElapsed,
Math.max(0.0, AUTO_DURATION - teleopTimer.get()),
true);
}
return computeTeleopShift();
}
//find auto winner, R = red wins, B = blue wins
public static Alliance autoWinnerAlliance() {
String msg = DriverStation.getGameSpecificMessage();
if (msg != null && msg.length() > 0) {
char c = msg.charAt(0);
if (c == 'R') return Alliance.Red;
if (c == 'B') return Alliance.Blue;
}
// backup if no msg, returns auto winner as opposite of our alliance. if we red -> blue wins auto
Alliance ours = DriverStation.getAlliance().orElse(Alliance.Blue);
return (ours == Alliance.Blue) ? Alliance.Red : Alliance.Blue;
}
//return our schedule for the shifts
private static boolean[] getSchedule() {
Alliance ours = DriverStation.getAlliance().orElse(Alliance.Blue);
Alliance winner = autoWinnerAlliance();
return (ours == winner) ? WINNER_SCHEDULE : LOSER_SCHEDULE;
}
//time since start of teleop
private static double getTeleopElapsed() {
double localTime = teleopTimer.get() - timerOffset;
// Re-sync to FMS time if we drift too far (only when FMS is attached)
if (DriverStation.isFMSAttached()) {
double fmsElapsed = TELEOP_DURATION - DriverStation.getMatchTime();
if (fmsElapsed <= TELEOP_DURATION - 5.0 // ignore the first few seconds of jitter
&& Math.abs(localTime - fmsElapsed) >= RESYNC_THRESHOLD) {
timerOffset += localTime - fmsElapsed;
localTime = fmsElapsed;
}
}
return Math.max(0.0, Math.min(TELEOP_DURATION, localTime));
}
private static ShiftInfo computeTeleopShift() {
boolean[] schedule = getSchedule();
double elapsed = getTeleopElapsed();
// Find which shift we're in
int phaseIndex = SHIFT_STARTS.length - 1; // default to last shift if past all bounds
for (int i = 0; i < SHIFT_STARTS.length; i++) {
if (elapsed >= SHIFT_STARTS[i] && elapsed < SHIFT_ENDS[i]) {
phaseIndex = i;
break;
}
}
double shiftElapsed = elapsed - SHIFT_STARTS[phaseIndex];
double shiftRemaining = SHIFT_ENDS[phaseIndex] - elapsed;
// merge time for elapsed if same active/inactive
if (phaseIndex > 0 && schedule[phaseIndex] == schedule[phaseIndex - 1]) {
shiftElapsed = elapsed - SHIFT_STARTS[phaseIndex - 1];
}
// merge time for remaining time if same active/inactive status
if (phaseIndex < SHIFT_ENDS.length - 1 && schedule[phaseIndex] == schedule[phaseIndex + 1]) {
shiftRemaining = SHIFT_ENDS[phaseIndex + 1] - elapsed;
}
return new ShiftInfo(
SHIFT_PHASES[phaseIndex],
shiftElapsed,
shiftRemaining,
schedule[phaseIndex]);
}
}