Skip to content

Commit 4cdba21

Browse files
committed
feat: Add initial robot structure with AdvantageKit, battery monitoring and a comprehensive LED system.
1 parent 1b857f6 commit 4cdba21

11 files changed

Lines changed: 761 additions & 118 deletions

File tree

src/main/java/frc/robot/Constants.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
package frc.robot;
1515

16+
import static edu.wpi.first.units.Units.Meters;
17+
18+
import edu.wpi.first.units.measure.Distance;
1619
import edu.wpi.first.wpilibj.RobotBase;
1720

1821
/**
@@ -24,6 +27,12 @@ public final class Constants {
2427
public static final Mode currentMode = RobotBase.isReal() ? Mode.REAL : simMode;
2528
public static final int PDH_ID = 1;
2629

30+
public static class LedConstants {
31+
public static final int kLedPort = 9;
32+
public static final int kLedLength = 60;
33+
public static final Distance kLedSpacing = Meters.of(0.05);
34+
}
35+
2736
public static enum Mode {
2837
/** Running on a real robot. */
2938
REAL,

src/main/java/frc/robot/Robot.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import edu.wpi.first.wpilibj2.command.Command;
1717
import edu.wpi.first.wpilibj2.command.CommandScheduler;
1818
import frc.robot.util.battery.BatteryUtils;
19-
2019
import org.littletonrobotics.junction.LogFileUtil;
2120
import org.littletonrobotics.junction.LoggedRobot;
2221
import org.littletonrobotics.junction.Logger;
@@ -111,13 +110,11 @@ public void robotPeriodic() {
111110

112111
/** This function is called once when the robot is disabled. */
113112
@Override
114-
public void disabledInit() {
115-
}
113+
public void disabledInit() {}
116114

117115
/** This function is called periodically when disabled. */
118116
@Override
119-
public void disabledPeriodic() {
120-
}
117+
public void disabledPeriodic() {}
121118

122119
/** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */
123120
@Override
Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
package frc.robot.subsystems;
22

3+
import edu.wpi.first.wpilibj.util.Color;
34
import edu.wpi.first.wpilibj2.command.SubsystemBase;
4-
import frc.robot.util.motors.MotorIO.Motor;
5-
import frc.robot.util.motors.controllers.SparkBaseController;
5+
import frc.robot.util.led.Led;
6+
import frc.robot.util.led.patterns.LedPattern;
67

78
public class exampleSubsystem extends SubsystemBase {
89

9-
private final SparkBaseController motor;
10-
11-
public exampleSubsystem(Motor motor) {
12-
13-
this.motor = new SparkBaseController(motor);
14-
10+
public exampleSubsystem(Led led) {
11+
led.setAnimation(
12+
new LedPattern.ColorFlow(Color.kAliceBlue, LedPattern.ColorFlow.Direction.FORWARD, 1.0), 0, 11);
1513
}
16-
1714
}
Lines changed: 57 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,72 @@
11
package frc.robot.util;
22

3-
43
import edu.wpi.first.networktables.GenericEntry;
54
import edu.wpi.first.wpilibj.shuffleboard.BuiltInWidgets;
65
import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
76
import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab;
87
import edu.wpi.first.wpilibj2.command.button.Trigger;
98

10-
119
/**
12-
* AutoResetDashboardTrigger
13-
* -------------------------
14-
* A dashboard-backed one-shot trigger designed to behave like
15-
* a gamepad "onTrue" button.
16-
*
17-
* Behavior:
18-
* - Exposes a Shuffleboard Toggle Button
19-
* - Detects a FALSE -> TRUE transition (rising edge)
20-
* - Fires TRUE for exactly one scheduler loop
21-
* - Automatically resets the dashboard value back to FALSE
22-
*
23-
* Intended use cases:
24-
* - Single-action commands (reset, zeroing, shoot-once, test actions)
25-
* - Debug and pit utilities where holding a button is unsafe
26-
*
27-
* Not intended for:
28-
* - whileTrue / continuous commands
29-
* - toggle or latch-style behaviors
30-
*/
10+
* AutoResetDashboardTrigger ------------------------- A dashboard-backed one-shot trigger designed to behave like a
11+
* gamepad "onTrue" button.
12+
*
13+
* <p>Behavior: - Exposes a Shuffleboard Toggle Button - Detects a FALSE -> TRUE transition (rising edge) - Fires TRUE
14+
* for exactly one scheduler loop - Automatically resets the dashboard value back to FALSE
15+
*
16+
* <p>Intended use cases: - Single-action commands (reset, zeroing, shoot-once, test actions) - Debug and pit utilities
17+
* where holding a button is unsafe
18+
*
19+
* <p>Not intended for: - whileTrue / continuous commands - toggle or latch-style behaviors
20+
*/
3121
public final class DashboardTrigger {
3222

33-
34-
/** NetworkTables-backed boolean entry shown on Shuffleboard */
35-
private final GenericEntry buttonEntry;
36-
37-
38-
/** Cached previous value for edge detection */
39-
private boolean previousValue = false;
40-
41-
42-
/**
43-
* Creates an auto-resetting dashboard trigger.
44-
*
45-
* @param tabName Shuffleboard tab name
46-
* @param buttonName Label displayed on the dashboard
47-
*/
48-
public DashboardTrigger(String tabName, String buttonName) {
49-
ShuffleboardTab tab = Shuffleboard.getTab(tabName);
50-
51-
52-
this.buttonEntry = tab.add(buttonName, false)
53-
.withWidget(BuiltInWidgets.kToggleButton)
54-
.getEntry();
55-
}
56-
57-
58-
/**
59-
* Returns a WPILib Trigger that fires exactly once
60-
* when the dashboard button is pressed.
61-
*
62-
* @return one-shot Trigger (rising-edge based)
63-
*/
64-
public Trigger trigger() {
65-
return new Trigger(() -> {
66-
boolean currentValue = buttonEntry.getBoolean(false);
67-
68-
69-
// Rising edge detection
70-
if (currentValue && !previousValue) {
71-
buttonEntry.setBoolean(false); // auto-reset immediately
72-
previousValue = true;
73-
return true;
23+
/** NetworkTables-backed boolean entry shown on Shuffleboard */
24+
private final GenericEntry buttonEntry;
25+
26+
/** Cached previous value for edge detection */
27+
private boolean previousValue = false;
28+
29+
/**
30+
* Creates an auto-resetting dashboard trigger.
31+
*
32+
* @param tabName Shuffleboard tab name
33+
* @param buttonName Label displayed on the dashboard
34+
*/
35+
public DashboardTrigger(String tabName, String buttonName) {
36+
ShuffleboardTab tab = Shuffleboard.getTab(tabName);
37+
38+
this.buttonEntry = tab.add(buttonName, false)
39+
.withWidget(BuiltInWidgets.kToggleButton)
40+
.getEntry();
41+
}
42+
43+
/**
44+
* Returns a WPILib Trigger that fires exactly once when the dashboard button is pressed.
45+
*
46+
* @return one-shot Trigger (rising-edge based)
47+
*/
48+
public Trigger trigger() {
49+
return new Trigger(() -> {
50+
boolean currentValue = buttonEntry.getBoolean(false);
51+
52+
// Rising edge detection
53+
if (currentValue && !previousValue) {
54+
buttonEntry.setBoolean(false); // auto-reset immediately
55+
previousValue = true;
56+
return true;
57+
}
58+
59+
previousValue = currentValue;
60+
return false;
61+
});
62+
}
63+
64+
/** Programmatically fires the trigger once. Useful for tests or internal control logic. */
65+
public void fireOnce() {
66+
buttonEntry.setBoolean(true);
67+
}
7468
}
7569

76-
77-
previousValue = currentValue;
78-
return false;
79-
});
80-
}
81-
82-
83-
/**
84-
* Programmatically fires the trigger once.
85-
* Useful for tests or internal control logic.
86-
*/
87-
public void fireOnce() {
88-
buttonEntry.setBoolean(true);
89-
}
90-
}
91-
92-
9370
/*
9471
========================
9572
Example usage (RobotContainer)
@@ -106,4 +83,4 @@ Example usage (RobotContainer)
10683
10784
// Designed for onTrue only
10885
// whileTrue / toggle usage is intentionally unsupported
109-
*/
86+
*/

src/main/java/frc/robot/util/battery/BatteryMonitor.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package frc.robot.util.battery;
22

3-
import org.littletonrobotics.junction.networktables.LoggedNetworkBoolean;
4-
import org.littletonrobotics.junction.networktables.LoggedNetworkNumber;
5-
import org.littletonrobotics.junction.networktables.LoggedNetworkString;
6-
73
import edu.wpi.first.math.filter.LinearFilter;
4+
import edu.wpi.first.wpilibj.Alert;
5+
import edu.wpi.first.wpilibj.Alert.AlertType;
86
import edu.wpi.first.wpilibj.DriverStation;
97
import edu.wpi.first.wpilibj2.command.Command;
8+
import org.littletonrobotics.junction.networktables.LoggedNetworkBoolean;
109

1110
public class BatteryMonitor extends Command {
1211

@@ -16,13 +15,13 @@ public class BatteryMonitor extends Command {
1615

1716
private final LinearFilter filter;
1817
private final LoggedNetworkBoolean lowBattery;
19-
private final LoggedNetworkNumber voltage;
18+
private final Alert alert;
2019
private double avgVoltage;
2120

2221
public BatteryMonitor() {
2322
filter = LinearFilter.movingAverage(SAMPLE_COUNT);
2423
lowBattery = new LoggedNetworkBoolean(NT_TOPIC + "Low");
25-
voltage = new LoggedNetworkNumber(NT_TOPIC + "Voltage");
24+
alert = new Alert("Battery is too low for the match", AlertType.kWarning);
2625

2726
avgVoltage = BatteryUtils.getCurrentVoltage();
2827
}
@@ -42,9 +41,11 @@ public void execute() {
4241

4342
if (isLow && !DriverStation.isEnabled()) {
4443
lowBattery.set(true);
45-
voltage.set(avgVoltage);
44+
alert.setText(String.format("Battery is too low for the match : %2fV", avgVoltage));
45+
alert.set(true);
4646
} else {
4747
lowBattery.set(false);
48+
alert.set(false);
4849
}
4950
}
5051
}
Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package frc.robot.util.battery;
22

3-
import edu.wpi.first.wpilibj.Alert;
43
import edu.wpi.first.wpilibj.PowerDistribution;
54
import edu.wpi.first.wpilibj.PowerDistribution.ModuleType;
65
import edu.wpi.first.wpilibj.RobotController;
@@ -9,24 +8,23 @@
98

109
public class BatteryUtils {
1110

12-
public static final double DEFAULT_VOLTAGE = 12.35;
11+
public static final double DEFAULT_VOLTAGE = 12.35;
1312

14-
private static final PowerDistribution powerDistribution = new PowerDistribution(Constants.PDH_ID, ModuleType.kRev);
13+
private static final PowerDistribution powerDistribution = new PowerDistribution(Constants.PDH_ID, ModuleType.kRev);
1514

16-
private static final Command monitor = new BatteryMonitor().ignoringDisable(true);
15+
private static final Command monitor = new BatteryMonitor().ignoringDisable(true);
1716

18-
public static double getTotalCurrent() {
19-
return powerDistribution.getTotalCurrent();
20-
}
17+
public static double getTotalCurrent() {
18+
return powerDistribution.getTotalCurrent();
19+
}
2120

22-
public static double getCurrentVoltage() {
23-
return RobotController.getBatteryVoltage();
24-
}
21+
public static double getCurrentVoltage() {
22+
return RobotController.getBatteryVoltage();
23+
}
2524

26-
public static void scheduleMonitor() {
27-
if (!monitor.isScheduled()) {
28-
monitor.schedule();
29-
}
30-
}
31-
32-
}
25+
public static void scheduleMonitor() {
26+
if (!monitor.isScheduled()) {
27+
monitor.schedule();
28+
}
29+
}
30+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package frc.robot.util.led;
2+
3+
import edu.wpi.first.wpilibj.AddressableLEDBuffer;
4+
import edu.wpi.first.wpilibj.Timer;
5+
import frc.robot.util.led.patterns.LedPattern;
6+
7+
/** Manages the active LED pattern and handles timing logic. Ensures consistent animation updates based on time. */
8+
public class AnimationController {
9+
private LedPattern activePattern;
10+
private int startIndex = 0;
11+
private final Timer timer = new Timer();
12+
13+
/**
14+
* Sets a new pattern to be active. This resets the animation timer.
15+
*
16+
* @param pattern The pattern to display.
17+
* @param startIndex The index in the LED buffer where the pattern starts.
18+
*/
19+
public void setPattern(LedPattern pattern, int startIndex) {
20+
this.activePattern = pattern;
21+
this.startIndex = startIndex;
22+
timer.restart();
23+
if (pattern != null) {
24+
pattern.initialize();
25+
}
26+
}
27+
28+
/** Clears the current pattern. */
29+
public void clear() {
30+
this.activePattern = null;
31+
timer.stop();
32+
timer.reset();
33+
}
34+
35+
/**
36+
* Updates the active pattern if one exists.
37+
*
38+
* @param buffer The LED buffer to write to.
39+
*/
40+
public void update(AddressableLEDBuffer buffer) {
41+
if (activePattern != null) {
42+
activePattern.update(buffer, startIndex, timer.get());
43+
}
44+
}
45+
46+
/**
47+
* Returns the name of the active pattern for logging.
48+
*
49+
* @return Name of the pattern class or "None".
50+
*/
51+
public String getActivePatternName() {
52+
if (activePattern != null) {
53+
return activePattern.getClass().getSimpleName();
54+
}
55+
return "None";
56+
}
57+
}

0 commit comments

Comments
 (0)