diff --git a/src/main/java/org/team2342/lib/leds/LedIO.java b/src/main/java/org/team2342/lib/leds/LedIO.java index 3252197..af8f0ba 100644 --- a/src/main/java/org/team2342/lib/leds/LedIO.java +++ b/src/main/java/org/team2342/lib/leds/LedIO.java @@ -6,4 +6,58 @@ package org.team2342.lib.leds; -public interface LedIO {} +public interface LedIO { + + public enum Half { + FIRST, + SECOND, + ALL + } + + + public enum LedEffect { + SOLID, + FLASHING, + RAINBOW, + OFF + } + + public static class LedColor { + public int red; + public int green; + public int blue; + + public LedColor(int red, int green, int blue) { + this.red = red; + this.green = green; + this.blue = blue; + } + + public static LedColor off() { + return new LedColor(0, 0, 0); + } + } + + public static class LedIOInputs { + public LedColor firstHalfColor = LedColor.off(); + public LedColor secondHalfColor = LedColor.off(); + public LedEffect firstHalfEffect = LedEffect.OFF; + public LedEffect secondHalfEffect = LedEffect.OFF; + } + + public default void updateInputs(LedIOInputs inputs) {} + + public default void setColor(Half half, LedColor color) {} + + public default void setEffect(Half half, LedEffect effect, LedColor color) {} + + public default void setAllColor(LedColor color) { + setColor(Half.FIRST, color); + setColor(Half.SECOND, color); + } + + public default void setAllEffect(LedEffect effect, LedColor color) { + setEffect(Half.FIRST, effect, color); + setEffect(Half.SECOND, effect, color); + } +} diff --git a/src/main/java/org/team2342/lib/leds/LedIOCANdle.java b/src/main/java/org/team2342/lib/leds/LedIOCANdle.java index e3e27c8..41169fc 100644 --- a/src/main/java/org/team2342/lib/leds/LedIOCANdle.java +++ b/src/main/java/org/team2342/lib/leds/LedIOCANdle.java @@ -6,4 +6,127 @@ package org.team2342.lib.leds; -public class LedIOCANdle implements LedIO {} +import com.ctre.phoenix6.hardware.CANdle; +import com.ctre.phoenix6.configs.CANdleConfiguration; +import com.ctre.phoenix6.controls.SolidColor; +import com.ctre.phoenix6.controls.RainbowAnimation; +import com.ctre.phoenix6.signals.RGBWColor; +import com.ctre.phoenix6.signals.StripTypeValue; + + +public class LedIOCANdle implements LedIO { + private CANdle candle; + private int totalLeds; + private int firstHalfLength; + private int secondHalfLength; + + private LedColor lastFirstColor = LedColor.off(); + private LedColor lastSecondColor = LedColor.off(); + private LedEffect lastFirstEffect = LedEffect.OFF; + private LedEffect lastSecondEffect = LedEffect.OFF; + + public LedIOCANdle(int canID, int ledCount){ + this.candle = new CANdle(canID); + this.totalLeds = ledCount; + this.firstHalfLength = totalLeds / 2; + this.secondHalfLength = totalLeds - firstHalfLength; + + CANdleConfiguration config = new CANdleConfiguration(); + config.LED.StripType = StripTypeValue.RGB; + candle.getConfigurator().apply(config); + } + + @Override + public void updateInputs(LedIOInputs inputs){ + inputs.firstHalfColor = lastFirstColor; + inputs.secondHalfColor = lastSecondColor; + inputs.firstHalfEffect = lastFirstEffect; + inputs.secondHalfEffect = lastSecondEffect; + } + + @Override + public void setColor(Half half, LedColor color) { + switch (half) { + case FIRST: + sendSolidColor(0, firstHalfLength, color); + lastFirstColor = color; + lastFirstEffect = LedEffect.SOLID; + break; + case SECOND: + sendSolidColor(firstHalfLength, secondHalfLength, color); + lastSecondColor = color; + lastSecondEffect = LedEffect.SOLID; + break; + case ALL: + sendSolidColor(0, totalLeds, color); + lastFirstColor = color; + lastSecondColor = color; + lastFirstEffect = LedEffect.SOLID; + lastSecondEffect = LedEffect.SOLID; + break; + } + + } + + @Override + public void setEffect(Half half, LedEffect effect, LedColor color) { + if (color == null){ + color = LedColor.off(); + } + + int start = 0; + int length = 0; + + switch (half) { + case FIRST: + start = 0; + length = firstHalfLength; + lastFirstColor = color; + lastFirstEffect = effect; + break; + case SECOND: + start = firstHalfLength; + length = secondHalfLength; + lastSecondColor = color; + lastSecondEffect = effect; + break; + case ALL: + start = 0; + length = totalLeds; + lastFirstEffect = effect; + lastSecondEffect = effect; + lastFirstColor = color; + lastSecondColor = color; + break; + } + + switch (effect) { + case SOLID: + sendSolidColor(start, length, color); + break; + case RAINBOW: + RainbowAnimation rainbow = new RainbowAnimation(start, length); + candle.setControl(rainbow); + break; + case FLASHING: + sendSolidColor(start, length, color); + break; + case OFF: + sendSolidColor(start, length, LedColor.off()); + break; + } + } + + private RGBWColor toCTRE(LedColor c) { + if (c == null){ + return new RGBWColor(0,0,0,0); + } + return new RGBWColor(c.red, c.green, c.blue,0); + } + + private void sendSolidColor(int start, int length, LedColor color) { + SolidColor request = new SolidColor(start, length); + request.withColor(toCTRE(color)); + candle.setControl(request); + } +} \ No newline at end of file diff --git a/src/main/java/org/team2342/lib/leds/LedIOSim.java b/src/main/java/org/team2342/lib/leds/LedIOSim.java new file mode 100644 index 0000000..137d6b4 --- /dev/null +++ b/src/main/java/org/team2342/lib/leds/LedIOSim.java @@ -0,0 +1,82 @@ +// Copyright (c) 2025 Team 2342 +// https://github.com/FRCTeamPhoenix +// +// This source code is licensed under the MIT License. +// See the LICENSE file in the root directory of this project. + +package org.team2342.lib.leds; + +import org.littletonrobotics.junction.Logger; + +public class LedIOSim implements LedIO { + private LedColor firstColor = LedColor.off(); + private LedColor secondColor = LedColor.off(); + private LedEffect firstEffect = LedEffect.OFF; + private LedEffect secondEffect = LedEffect.OFF; + + @Override + public void setColor(Half half, LedColor color) { + if (color == null) { + color = LedColor.off(); + } + + switch (half) { + case FIRST: + firstColor = color; + firstEffect = LedEffect.SOLID; + break; + case SECOND: + secondColor = color; + secondEffect = LedEffect.SOLID; + break; + case ALL: + firstColor = color; + secondColor = color; + firstEffect = LedEffect.SOLID; + secondEffect = LedEffect.SOLID; + break; + } + } + + @Override + public void setEffect(Half half, LedEffect effect, LedColor color){ + if (color == null) { + color = LedColor.off(); + } + + switch (half) { + case FIRST: + firstColor = color; + firstEffect = effect; + break; + case SECOND: + secondColor = color; + secondEffect = effect; + break; + case ALL: + firstColor = color; + secondColor = color; + firstEffect = effect; + secondEffect = effect; + break; + } + } + + @Override + public void updateInputs(LedIOInputs inputs){ + inputs.firstHalfColor = firstColor; + inputs.secondHalfColor = secondColor; + inputs.firstHalfEffect = firstEffect; + inputs.secondHalfEffect = secondEffect; + + Logger.recordOutput("LED/FirstHalf/Red", firstColor.red); + Logger.recordOutput("LED/FirstHalf/Green", firstColor.green); + Logger.recordOutput("LED/FirstHalf/Blue", firstColor.blue); + Logger.recordOutput("LED/FirstHalf/Effect", firstEffect.toString()); + + Logger.recordOutput("LED/SecondHalf/Red", secondColor.red); + Logger.recordOutput("LED/SecondHalf/Green", secondColor.green); + Logger.recordOutput("LED/SecondHalf/Blue", secondColor.blue); + Logger.recordOutput("LED/SecondHalf/Effect", secondEffect.toString()); + } +} \ No newline at end of file diff --git a/src/main/java/org/team2342/lib/leds/LedStrip.java b/src/main/java/org/team2342/lib/leds/LedStrip.java new file mode 100644 index 0000000..df971f7 --- /dev/null +++ b/src/main/java/org/team2342/lib/leds/LedStrip.java @@ -0,0 +1,68 @@ +// Copyright (c) 2025 Team 2342 +// https://github.com/FRCTeamPhoenix +// +// This source code is licensed under the MIT License. +// See the LICENSE file in the root directory of this project. + +package org.team2342.lib.leds; + +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class LedStrip extends SubsystemBase { + private final LedIO io; + private LedIO.LedColor firstColor = LedIO.LedColor.off(); + private LedIO.LedEffect firstEffect = LedIO.LedEffect.OFF; + private LedIO.LedColor secondColor = LedIO.LedColor.off(); + private LedIO.LedEffect secondEffect = LedIO.LedEffect.OFF; + + private boolean flashing = false; + private double lastFlashTime = 0.0; + private static final double FLASH_PERIOD_SEC = 0.5; + + public LedStrip(LedIO io){ + this.io = io; + } + + public void setFirst(LedIO.LedEffect effect, LedIO.LedColor color){ + firstEffect = effect; + firstColor = color; + } + + public void setSecond(LedIO.LedEffect effect, LedIO.LedColor color){ + secondEffect = effect; + secondColor = color; + } + + @Override + public void periodic() { + updateFlashing(); + applyEffect(LedIO.Half.FIRST, firstEffect, firstColor); + applyEffect(LedIO.Half.SECOND, secondEffect, secondColor); + } + + private void updateFlashing() { + double now = Timer.getFPGATimestamp(); + if (now - lastFlashTime >= FLASH_PERIOD_SEC) { + flashing = !flashing; + lastFlashTime = now; + } + } + + private void applyEffect(LedIO.Half half, LedIO.LedEffect effect, LedIO.LedColor color){ + switch (effect) { + case SOLID: + io.setColor(half, color); + break; + case FLASHING: + io.setColor(half, (flashing ? color : LedIO.LedColor.off())); + break; + case RAINBOW: + io.setEffect(half, LedIO.LedEffect.RAINBOW, color); + break; + case OFF: + io.setColor(half, LedIO.LedColor.off()); + break; + } + } +} \ No newline at end of file diff --git a/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIO.java b/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIO.java index d5e8531..6fac1e8 100644 --- a/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIO.java +++ b/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIO.java @@ -8,7 +8,16 @@ import org.littletonrobotics.junction.AutoLog; +/* + * Interface for dumb motor input/output + * Lets simulation, real hardware, and different motor types to use same structure + */ + public interface DumbMotorIO { + /** + * Container class for motor inputs - used for logging and data updates. The @AutoLog annotation + * automatically generates code for logging with the AdvantageKit framework. + */ @AutoLog public static class DumbMotorIOInputs { public boolean connected = false; @@ -16,7 +25,18 @@ public static class DumbMotorIOInputs { public double currentAmps = 0.0; } + /** + * Called periodically to update the motor input data. + * + * @param inputs The object that stores motor readings to be logged or used somewhere else. + */ public default void updateInputs(DumbMotorIOInputs inputs) {} + /** + * Runs the motor at a specified voltage. This method is intended to be overridden by + * implementations to control the motor. + * + * @param voltage The voltage to apply to the motor. + */ public default void runVoltage(double voltage) {} } diff --git a/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOSim.java b/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOSim.java index 574b99c..37191d5 100644 --- a/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOSim.java +++ b/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOSim.java @@ -11,15 +11,27 @@ import edu.wpi.first.math.system.plant.DCMotor; import edu.wpi.first.wpilibj.simulation.LinearSystemSim; +/** Simulation implementation of DumbMotorIO Uses a LinearSystemSim to simulate */ public class DumbMotorIOSim implements DumbMotorIO { private final LinearSystemSim sim; private final DCMotor motor; + /** + * Constructs a new DumbMotorIOSim instance. + * + * @param motor The DC motor model to simulate + * @param sim The linear system simulation representing the motor's behavior + */ public DumbMotorIOSim(DCMotor motor, LinearSystemSim sim) { this.motor = motor; this.sim = sim; } + /** + * Updates the inputs for the motor controller + * + * @param inputs The inputs object to update with current values + */ @Override public void updateInputs(DumbMotorIOInputs inputs) { sim.update(0.02); @@ -31,6 +43,11 @@ public void updateInputs(DumbMotorIOInputs inputs) { inputs.currentAmps = current; } + /** + * Sets the motor to run at the specified voltage + * + * @param voltage The desired voltage to apply to the motor + */ @Override public void runVoltage(double voltage) { sim.setInput(voltage); diff --git a/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOTalonFX.java b/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOTalonFX.java index 7d31d25..a256757 100644 --- a/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOTalonFX.java +++ b/src/main/java/org/team2342/lib/motors/dumb/DumbMotorIOTalonFX.java @@ -20,6 +20,10 @@ import org.team2342.frc.util.PhoenixUtils; import org.team2342.lib.motors.MotorConfig; +/** + * Implementation of DumbMotorIO for a TalonFX motor controller Handles configuration, input + * updates, and voltage control for the motor + */ public class DumbMotorIOTalonFX implements DumbMotorIO { private final TalonFX talon; @@ -29,6 +33,12 @@ public class DumbMotorIOTalonFX implements DumbMotorIO { private final VoltageOut voltageRequest = new VoltageOut(0); private final Debouncer connectedDebouncer = new Debouncer(0.5); + /** + * Constructor to configure the TalonFX motor controller + * + * @param canID The CAN ID of the TalonFX motor controller + * @param config The configuration settings for the motor + */ public DumbMotorIOTalonFX(int canID, MotorConfig config) { talon = new TalonFX(canID); @@ -58,6 +68,11 @@ public DumbMotorIOTalonFX(int canID, MotorConfig config) { PhoenixUtils.tryUntilOk(5, () -> ParentDevice.optimizeBusUtilizationForAll(talon)); } + /** + * Updates the inputs for the motor controller + * + * @param inputs The inputs object to update with current values + */ @Override public void updateInputs(DumbMotorIOInputs inputs) { inputs.connected = @@ -66,6 +81,11 @@ public void updateInputs(DumbMotorIOInputs inputs) { inputs.currentAmps = current.getValueAsDouble(); } + /** + * Sets the motor to run at the specified voltage + * + * @param voltage The desired voltage to apply to the motor + */ @Override public void runVoltage(double voltage) { talon.setControl(voltageRequest.withOutput(voltage)); diff --git a/vendordeps/Phoenix6-25.3.2.json b/vendordeps/Phoenix6-frc2025-latest.json similarity index 86% rename from vendordeps/Phoenix6-25.3.2.json rename to vendordeps/Phoenix6-frc2025-latest.json index 368e61c..ce44ce4 100644 --- a/vendordeps/Phoenix6-25.3.2.json +++ b/vendordeps/Phoenix6-frc2025-latest.json @@ -1,7 +1,7 @@ { - "fileName": "Phoenix6-25.3.2.json", + "fileName": "Phoenix6-frc2025-latest.json", "name": "CTRE-Phoenix (v6)", - "version": "25.3.2", + "version": "25.4.0", "frcYear": "2025", "uuid": "e995de00-2c64-4df5-8831-c1441420ff19", "mavenUrls": [ @@ -19,14 +19,14 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "wpiapi-java", - "version": "25.3.2" + "version": "25.4.0" } ], "jniDependencies": [ { "groupId": "com.ctre.phoenix6", "artifactId": "api-cpp", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -40,7 +40,7 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "tools", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -54,7 +54,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "api-cpp-sim", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -68,7 +68,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "tools-sim", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -82,7 +82,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simTalonSRX", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -96,7 +96,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simVictorSPX", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -110,7 +110,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simPigeonIMU", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -124,7 +124,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simCANCoder", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -138,7 +138,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFX", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -152,7 +152,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFXS", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -166,7 +166,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANcoder", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -180,7 +180,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProPigeon2", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -194,7 +194,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANrange", - "version": "25.3.2", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -208,7 +208,21 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANdi", - "version": "25.3.2", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -224,7 +238,7 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "wpiapi-cpp", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_Phoenix6_WPI", "headerClassifier": "headers", "sharedLibrary": true, @@ -240,7 +254,7 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "tools", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_PhoenixTools", "headerClassifier": "headers", "sharedLibrary": true, @@ -256,7 +270,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "wpiapi-cpp-sim", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_Phoenix6_WPISim", "headerClassifier": "headers", "sharedLibrary": true, @@ -272,7 +286,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "tools-sim", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_PhoenixTools_Sim", "headerClassifier": "headers", "sharedLibrary": true, @@ -288,7 +302,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simTalonSRX", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimTalonSRX", "headerClassifier": "headers", "sharedLibrary": true, @@ -304,7 +318,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simVictorSPX", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimVictorSPX", "headerClassifier": "headers", "sharedLibrary": true, @@ -320,7 +334,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simPigeonIMU", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimPigeonIMU", "headerClassifier": "headers", "sharedLibrary": true, @@ -336,7 +350,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simCANCoder", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimCANCoder", "headerClassifier": "headers", "sharedLibrary": true, @@ -352,7 +366,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFX", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimProTalonFX", "headerClassifier": "headers", "sharedLibrary": true, @@ -368,7 +382,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFXS", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimProTalonFXS", "headerClassifier": "headers", "sharedLibrary": true, @@ -384,7 +398,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANcoder", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimProCANcoder", "headerClassifier": "headers", "sharedLibrary": true, @@ -400,7 +414,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProPigeon2", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimProPigeon2", "headerClassifier": "headers", "sharedLibrary": true, @@ -416,7 +430,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANrange", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimProCANrange", "headerClassifier": "headers", "sharedLibrary": true, @@ -432,7 +446,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANdi", - "version": "25.3.2", + "version": "25.4.0", "libName": "CTRE_SimProCANdi", "headerClassifier": "headers", "sharedLibrary": true, @@ -444,6 +458,22 @@ "osxuniversal" ], "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "25.4.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" } ] }