From 7ceb9aa76dfe6a533df4cd9fe9dffdf0f356aa4a Mon Sep 17 00:00:00 2001 From: Zach Rutman Date: Wed, 14 Feb 2024 16:31:22 -0800 Subject: [PATCH] Add LEDs (#34) * feat: LED Framework * refactor: clean up modifiers, loops * feat: add wave pattern * refactor: change led pattern structure * feat: add alternating group sizes * feat: Fire and breathing LED patterns :D * feat: RSL LEDs * feat: allow hue selection based on Color * refactor: clean up pattern files * feat: add triaging * feat: fix bindings, add led tuning mode --------- Co-authored-by: David :D --- .../org/team1540/robot2024/Constants.java | 5 +- .../java/org/team1540/robot2024/Robot.java | 20 ++++- .../team1540/robot2024/RobotContainer.java | 17 ++++ .../robot2024/subsystems/led/LedTriager.java | 38 +++++++++ .../robot2024/subsystems/led/Leds.java | 80 ++++++++++++++++++ .../led/ZonedAddressableLEDBuffer.java | 63 ++++++++++++++ .../subsystems/led/patterns/LedPattern.java | 47 +++++++++++ .../led/patterns/LedPatternBreathing.java | 41 +++++++++ .../led/patterns/LedPatternFlame.java | 83 +++++++++++++++++++ .../led/patterns/LedPatternRSLState.java | 28 +++++++ .../led/patterns/LedPatternRainbow.java | 24 ++++++ .../led/patterns/LedPatternWave.java | 39 +++++++++ .../led/patterns/SimpleLedPattern.java | 32 +++++++ 13 files changed, 515 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/LedTriager.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/Leds.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/ZonedAddressableLEDBuffer.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPattern.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternBreathing.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternFlame.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRSLState.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRainbow.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternWave.java create mode 100644 src/main/java/org/team1540/robot2024/subsystems/led/patterns/SimpleLedPattern.java diff --git a/src/main/java/org/team1540/robot2024/Constants.java b/src/main/java/org/team1540/robot2024/Constants.java index c6362d9a..13f2a4cd 100644 --- a/src/main/java/org/team1540/robot2024/Constants.java +++ b/src/main/java/org/team1540/robot2024/Constants.java @@ -23,7 +23,10 @@ public final class Constants { private static final Mode simMode = Mode.SIM; // Can also be Mode.REPLAY public static final Mode currentMode = Robot.isReal() ? Mode.REAL : simMode; - + public static final class Leds { + public static final int LED_STRIP_PORT_PWM = 9; + public static final int LED_STRIP_LENGTH= 80; + } public enum Mode { /** * Running on a real robot. diff --git a/src/main/java/org/team1540/robot2024/Robot.java b/src/main/java/org/team1540/robot2024/Robot.java index 0872c1b6..e7486d27 100644 --- a/src/main/java/org/team1540/robot2024/Robot.java +++ b/src/main/java/org/team1540/robot2024/Robot.java @@ -1,6 +1,7 @@ package org.team1540.robot2024; import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj.util.Color; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import org.littletonrobotics.junction.LogFileUtil; @@ -9,6 +10,12 @@ import org.littletonrobotics.junction.networktables.NT4Publisher; import org.littletonrobotics.junction.wpilog.WPILOGReader; import org.littletonrobotics.junction.wpilog.WPILOGWriter; +import org.team1540.robot2024.subsystems.led.*; +import org.team1540.robot2024.subsystems.led.patterns.LedPatternFlame; +import org.team1540.robot2024.subsystems.led.patterns.LedPatternRSLState; +import org.team1540.robot2024.subsystems.led.patterns.LedPatternRainbow; +import org.team1540.robot2024.subsystems.led.patterns.SimpleLedPattern; +import org.team1540.robot2024.util.LoggedTunableNumber; import org.team1540.robot2024.util.MechanismVisualiser; /** @@ -21,6 +28,10 @@ public class Robot extends LoggedRobot { private Command autonomousCommand; private RobotContainer robotContainer; + LoggedTunableNumber led_r = new LoggedTunableNumber("led/r", 0); + LoggedTunableNumber led_g = new LoggedTunableNumber("led/g", 0); + LoggedTunableNumber led_b = new LoggedTunableNumber("led/b", 0); + /** * This function is run when the robot is first started up and should be used for any * initialization code. @@ -49,7 +60,7 @@ public void robotInit() { switch (Constants.currentMode) { case REAL: // Running on a real robot, log to a USB stick ("/U/logs") - Logger.addDataReceiver(new WPILOGWriter()); +// Logger.addDataReceiver(new WPILOGWriter()); Logger.addDataReceiver(new NT4Publisher()); break; @@ -94,6 +105,7 @@ public void robotPeriodic() { // Update mechanism visualiser in sim if (Robot.isSimulation()) MechanismVisualiser.periodic(); +// robotContainer.leds.setPattern(Leds.Zone.ZONE1, SimpleLedPattern.alternating(Color.kBlueViolet, Color.kGreen)); } /** @@ -101,6 +113,7 @@ public void robotPeriodic() { */ @Override public void disabledInit() { + robotContainer.leds.setPattern(Leds.Zone.ELEVATOR_BACK, new LedPatternRainbow(1)); } /** @@ -115,6 +128,7 @@ public void disabledPeriodic() { */ @Override public void autonomousInit() { + robotContainer.leds.setPattern(Leds.Zone.ELEVATOR_BACK,LedPatternRSLState.matchingColors()); autonomousCommand = robotContainer.getAutonomousCommand(); // schedule the autonomous command (example) if (autonomousCommand != null) { @@ -138,6 +152,8 @@ public void teleopInit() { // teleop starts running. If you want the autonomous to // continue until interrupted by another command, remove // this line or comment it out. + + robotContainer.leds.setPattern(Leds.Zone.ELEVATOR_BACK, LedPatternRSLState.matchingColors()); if (autonomousCommand != null) { autonomousCommand.cancel(); } @@ -155,6 +171,7 @@ public void teleopPeriodic() { */ @Override public void testInit() { + robotContainer.leds.setPattern(Leds.Zone.ELEVATOR_BACK,new LedPatternRainbow(1)); // Cancels all running commands at the start of test mode. CommandScheduler.getInstance().cancelAll(); } @@ -164,6 +181,7 @@ public void testInit() { */ @Override public void testPeriodic() { + robotContainer.leds.setPattern(Leds.Zone.ELEVATOR_BACK,SimpleLedPattern.solid(new Color(led_r.get(), led_g.get(), led_b.get()))); } /** diff --git a/src/main/java/org/team1540/robot2024/RobotContainer.java b/src/main/java/org/team1540/robot2024/RobotContainer.java index 4e0ea102..bb5fb209 100644 --- a/src/main/java/org/team1540/robot2024/RobotContainer.java +++ b/src/main/java/org/team1540/robot2024/RobotContainer.java @@ -3,13 +3,18 @@ import com.pathplanner.lib.util.PathPlannerLogging; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; + +import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.math.trajectory.Trajectory; import edu.wpi.first.math.trajectory.TrajectoryGenerator; + import edu.wpi.first.wpilibj.GenericHID; import edu.wpi.first.wpilibj.XboxController; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import edu.wpi.first.wpilibj2.command.button.Trigger; + import org.littletonrobotics.junction.Logger; import org.littletonrobotics.junction.networktables.LoggedDashboardChooser; import org.team1540.robot2024.Constants.Elevator.ElevatorState; @@ -30,6 +35,8 @@ import org.team1540.robot2024.subsystems.indexer.IndexerIO; import org.team1540.robot2024.subsystems.indexer.IndexerIOSim; import org.team1540.robot2024.subsystems.indexer.IndexerIOSparkMax; +import org.team1540.robot2024.subsystems.led.Leds; +import org.team1540.robot2024.subsystems.led.patterns.LedPatternFlame; import org.team1540.robot2024.subsystems.shooter.*; import org.team1540.robot2024.subsystems.tramp.Tramp; import org.team1540.robot2024.subsystems.tramp.TrampIO; @@ -61,6 +68,7 @@ public class RobotContainer { public final Elevator elevator; public final Indexer indexer; public final AprilTagVision aprilTagVision; + public final Leds leds = new Leds(); private int currentPathHash = Integer.MAX_VALUE; private Trajectory currentPathTrajectory = new Trajectory(); @@ -208,8 +216,17 @@ public RobotContainer() { // Configure the button bindings configureButtonBindings(); + configureLedBindings(); } + private void configureLedBindings() { + leds.setFatalPattern(LedPatternFlame::new); + new Trigger(DriverStation::isDSAttached) + .onTrue(Commands.runOnce(leds::clearFatalPattern) + .ignoringDisable(true)) + .onFalse(Commands.runOnce(() -> leds.setFatalPattern(LedPatternFlame::new)) + .ignoringDisable(true)); + } /** * Use this method to define your button->command mappings. Buttons can be created by * instantiating a {@link GenericHID} or one of its subclasses ({@link diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/LedTriager.java b/src/main/java/org/team1540/robot2024/subsystems/led/LedTriager.java new file mode 100644 index 00000000..4cacde1c --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/LedTriager.java @@ -0,0 +1,38 @@ +package org.team1540.robot2024.subsystems.led; + +import org.team1540.robot2024.subsystems.led.patterns.LedPattern; +import org.team1540.robot2024.subsystems.led.patterns.LedPatternFlame; +import org.team1540.robot2024.subsystems.led.patterns.LedPatternRainbow; + + +public class LedTriager { + private final LedPattern[] patterns = new LedPattern[Leds.CRITICALITY_COUNT]; + private final LedPattern defaultPattern = new LedPatternRainbow(1); + private boolean isNew = true; + public LedPattern getPattern() { + for (int i = patterns.length -1; i >= 0; i--) { + if (patterns[i] != null) { + return patterns[i]; + } + } + return defaultPattern; + } + + public boolean shouldRefresh() { + final boolean val = isNew || getPattern().isDynamic(); + isNew = false; + return val; + } + + public void clearPattern(Leds.PatternCriticality criticality) { + patterns[criticality.ordinal()] = null; + isNew = true; + } + + public boolean addPattern(LedPattern pattern, Leds.PatternCriticality criticality) { + patterns[criticality.ordinal()] = pattern; + isNew = true; + return getPattern() == pattern; + } + +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/Leds.java b/src/main/java/org/team1540/robot2024/subsystems/led/Leds.java new file mode 100644 index 00000000..f4746aa3 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/Leds.java @@ -0,0 +1,80 @@ +package org.team1540.robot2024.subsystems.led; + +import edu.wpi.first.wpilibj.AddressableLED; +import edu.wpi.first.wpilibj.AddressableLEDBuffer; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +import org.team1540.robot2024.subsystems.led.patterns.LedPattern; + +import java.util.function.Supplier; + +import static org.team1540.robot2024.Constants.Leds.*; + +public class Leds extends SubsystemBase { + private final AddressableLEDBuffer ledBuffer = new AddressableLEDBuffer(LED_STRIP_LENGTH); + private final AddressableLED strip = new AddressableLED(LED_STRIP_PORT_PWM); + private final ZonedAddressableLEDBuffer[] buffers = new ZonedAddressableLEDBuffer[ZONE_COUNT]; + private final LedTriager[] patterns = new LedTriager[ZONE_COUNT]; + + public Leds() { + strip.setLength(ledBuffer.getLength()); + strip.setData(ledBuffer); + strip.start(); + + buffers[Zone.ELEVATOR_BACK.ordinal()] = new ZonedAddressableLEDBuffer(ledBuffer, 1, 41, false); + for (int i = 0; i < ZONE_COUNT;i++) { + patterns[i] = new LedTriager(); + } + } + + @Override + public void periodic() { + for (int i = 0; i < ZONE_COUNT;i++) { + if (patterns[i].shouldRefresh()) { + patterns[i].getPattern().apply(buffers[i]); + } + } + strip.setData(ledBuffer); + } + + public void setPattern(Zone zone, LedPattern pattern, PatternCriticality criticality) { + patterns[zone.ordinal()].addPattern(pattern, criticality); + pattern.setLength(buffers[zone.ordinal()].getLength()); + } + + public void setPattern(Zone zone, LedPattern pattern) { + setPattern(zone, pattern, PatternCriticality.INFO); + } + + public void clearPattern(Zone zone, PatternCriticality criticality) { + patterns[zone.ordinal()].clearPattern(criticality); + } + + public void setFatalPattern(Supplier patternSupplier) { + for (int i = 0; i end) { + throw new IllegalArgumentException("start must be less than end"); + } + this.buffer = buffer; + this.isInverted = isInverted; + this.start = start; + this.length = end - start; + } + + public void setRGB(int index, int r, int g, int b) { + buffer.setRGB(this.getAbsoluteIndex(index), r, g, b); + } + + public void setHSV(int index, int h, int s, int v) { + buffer.setHSV(this.getAbsoluteIndex(index), h, s, v); + } + + public void setLED(int index, Color color) { + buffer.setLED(this.getAbsoluteIndex(index), color); + } + + public void setLED(int index, Color8Bit color) { + buffer.setLED(this.getAbsoluteIndex(index), color); + } + + public Color getLED(int index) { + return buffer.getLED(this.getAbsoluteIndex(index)); + } + + public Color8Bit getLED8Bit(int index) { + return buffer.getLED8Bit(this.getAbsoluteIndex(index)); + } + + public int getLength() { + return this.length; + } + + private int getAbsoluteIndex(int index) { + if (index >= length) { + DriverStation.reportWarning("led index out of bounds", false); + return 0; + } + if (this.isInverted) { + return this.start + length - 1 - index; + } else { + return this.start + index; + } + } +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPattern.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPattern.java new file mode 100644 index 00000000..1328f009 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPattern.java @@ -0,0 +1,47 @@ +package org.team1540.robot2024.subsystems.led.patterns; + +import edu.wpi.first.wpilibj.util.Color; +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +public abstract class LedPattern { + private final boolean isDynamic; + + protected LedPattern(boolean isDynamic) { + this.isDynamic = isDynamic; + } + + public final boolean isDynamic() { + return isDynamic; + } + + public abstract void apply(ZonedAddressableLEDBuffer buffer); + public void setLength(int length) {} + + protected static int getHue(Color color) { + final int red = (int) color.red * 255; + final int green = (int) color.green * 255; + final int blue = (int) color.blue * 255; + float min = Math.min(Math.min(red, green), blue); + float max = Math.max(Math.max(red, green), blue); + + if (min == max) { + return 0; + } + + float hue = 0f; + if (max == red) { + hue = (green - blue) / (max - min); + + } else if (max == green) { + hue = 2f + (blue - red) / (max - min); + + } else { + hue = 4f + (red - green) / (max - min); + } + + hue = hue * 60; + if (hue < 0) hue = hue + 360; + + return Math.round(hue); + } +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternBreathing.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternBreathing.java new file mode 100644 index 00000000..57a0de3c --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternBreathing.java @@ -0,0 +1,41 @@ +package org.team1540.robot2024.subsystems.led.patterns; + +import edu.wpi.first.wpilibj.util.Color; +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +public class LedPatternBreathing extends LedPattern { + private final int speed; + private final int hue; + private int saturation; + private boolean isReversed = false; + + public LedPatternBreathing(int speed, Color color) { + super(true); + this.speed = speed; + this.hue = getHue(color); + } + + @Override + public void apply(ZonedAddressableLEDBuffer buffer) { + if (saturation > 255) { + saturation = 255; + isReversed = !isReversed; + } + + if (saturation < 0) { + saturation = 0; + isReversed = !isReversed; + } + for (int i = 0; i < buffer.getLength(); i++) { + buffer.setHSV(i, hue, saturation, 255); + } + + if (!isReversed) { + saturation = saturation + speed; + } else { + saturation = saturation - speed; + } + } + + +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternFlame.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternFlame.java new file mode 100644 index 00000000..4ebd6c15 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternFlame.java @@ -0,0 +1,83 @@ +package org.team1540.robot2024.subsystems.led.patterns; + + +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +import java.awt.*; +import java.util.Random; + +public class LedPatternFlame extends LedPattern { + private static final Random generator = new Random(); + private static final boolean reverseDirection = false; + + private final int cooling; + private final int sparking = 123; + + private int[] temperatures; + + + public LedPatternFlame(int cooling) { + super(true); + this.cooling = cooling; + } + + public LedPatternFlame() { + this(62); + } + + @Override + public void setLength(int length) { + this.temperatures = new int[length]; + } + + @Override + public void apply(ZonedAddressableLEDBuffer buffer) { + + for (int i = 0; i < buffer.getLength(); i++) { + temperatures[i] = bit8Subtraction(temperatures[i], getRandomInt(0, ((cooling * 10) / buffer.getLength()) + 2)); + } + + for (int k = buffer.getLength() - 1; k >= 2; k--) { + temperatures[k] = (temperatures[k - 1] + temperatures[k - 2] + temperatures[k - 2]) / 3; + } + + if (getRandomInt(0, 255) < sparking) { + int y = getRandomInt(0, 6); + temperatures[y] = bit8Addition(temperatures[y], getRandomInt(160, 255)); + } + + for (int j = 0; j < buffer.getLength(); j++) { + int temperature = temperatures[j]; + Color color = getHeatColor(temperature); + int pixelnumber = reverseDirection ? (buffer.getLength() - 1) - j : j; + buffer.setRGB(pixelnumber, color.getRed(), color.getGreen(), color.getBlue()); + } + } + + private Color getHeatColor(int temperature) { + Color finalColor; + int scaledTemperature = (temperature * 191) / 255; + int theHeat = scaledTemperature & 0x3F; + theHeat <<= 2; + if ((scaledTemperature & 0x80) != 0) { + finalColor = new Color(255, 255, theHeat); + } else if (((scaledTemperature & 0x40) != 0)) { + finalColor = new Color(255, theHeat, 0); + } else { + finalColor = new Color(theHeat, 0, 0); + } + return finalColor; + } + + private int getRandomInt(int min, int max) { + return generator.nextInt(max - min + 1) + min; + } + + private int bit8Subtraction(int a, int b) { + return (a < b) ? 0 : (a - b); + } + + private int bit8Addition(int a, int b) { + return Math.min((a + b), 255); + } +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRSLState.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRSLState.java new file mode 100644 index 00000000..b212c315 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRSLState.java @@ -0,0 +1,28 @@ +package org.team1540.robot2024.subsystems.led.patterns; + +import edu.wpi.first.wpilibj.RobotController; +import edu.wpi.first.wpilibj.util.Color; +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +public class LedPatternRSLState extends LedPattern { + private final LedPattern a; + private final LedPattern b; + public LedPatternRSLState(LedPattern a, LedPattern b) { + super(true); + this.a = a; + this.b = b; + } + + @Override + public void apply(ZonedAddressableLEDBuffer buffer) { + if (RobotController.getRSLState()) { + a.apply(buffer); + } else { + b.apply(buffer); + } + } + + public static LedPattern matchingColors() { + return new LedPatternRSLState(SimpleLedPattern.solid(new Color(1, 0.1, 0)), SimpleLedPattern.solid(Color.kBlack)); + } +} \ No newline at end of file diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRainbow.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRainbow.java new file mode 100644 index 00000000..83abeab9 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternRainbow.java @@ -0,0 +1,24 @@ +package org.team1540.robot2024.subsystems.led.patterns; + +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +public class LedPatternRainbow extends LedPattern { + private final int speed; + private int initialHue = 0; + + public LedPatternRainbow(int speed) { + super(true); + this.speed = speed; + } + + @Override + public void apply(ZonedAddressableLEDBuffer buffer) { + for (int i = 0; i < buffer.getLength(); i++) { + int hue = (initialHue + (i * 182 / buffer.getLength())) % 180; + buffer.setHSV(i, hue, 255, 128); + } + initialHue += speed; + initialHue %= 180; + } + +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternWave.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternWave.java new file mode 100644 index 00000000..41f45c94 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/LedPatternWave.java @@ -0,0 +1,39 @@ +package org.team1540.robot2024.subsystems.led.patterns; + +import edu.wpi.first.wpilibj.util.Color; +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +public class LedPatternWave extends LedPattern { + private static final double degradation = 0.7; + private static final int delay = 5; + private final int hue; + private int location = 0; + private int ticker = 0; + + public LedPatternWave(Color color) { + super(true); + this.hue = getHue(color); + } + + @Override + public void apply(ZonedAddressableLEDBuffer buffer) { + for (int i = 0; i < buffer.getLength(); i++) { + int distance = Math.abs(location - i); + if (distance > buffer.getLength() / 2) { + if (location > i) { + distance = buffer.getLength() - location + i; + } else { + distance = buffer.getLength() - i + location; + } + } + buffer.setHSV(i, hue, 255, (int) Math.max(255.0 - distance * distance * degradation, 0)); + } + ticker++; + if (ticker % delay == 0) { + location++; + } + location %= buffer.getLength(); + } + + +} diff --git a/src/main/java/org/team1540/robot2024/subsystems/led/patterns/SimpleLedPattern.java b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/SimpleLedPattern.java new file mode 100644 index 00000000..7ff0a952 --- /dev/null +++ b/src/main/java/org/team1540/robot2024/subsystems/led/patterns/SimpleLedPattern.java @@ -0,0 +1,32 @@ +package org.team1540.robot2024.subsystems.led.patterns; + +import edu.wpi.first.wpilibj.util.Color; +import org.team1540.robot2024.subsystems.led.ZonedAddressableLEDBuffer; + +import java.util.function.BiConsumer; + +public class SimpleLedPattern extends LedPattern{ + private final BiConsumer applier; + private SimpleLedPattern(BiConsumer applier) { + super(false); + this.applier = applier; + } + + public void apply(ZonedAddressableLEDBuffer buffer) { + for (int i = 0; i < buffer.getLength(); i++) { + this.applier.accept(buffer, i); + } + } + + public static LedPattern solid(Color color) { + return new SimpleLedPattern((buffer, i) -> buffer.setLED(i, color)); + } + public static LedPattern alternating(Color... colors) { + final int colorCount = colors.length; + return new SimpleLedPattern((buffer, i) -> buffer.setLED(i, colors[i%colorCount])); + } + public static LedPattern alternating(int groupSize, Color... colors) { + final int colorCount = colors.length; + return new SimpleLedPattern((buffer, i) -> buffer.setLED(i, colors[(i/groupSize)%colorCount])); + } +}