From 99a18c347d205e01bafac73c2c4f04e2a61e0b1d Mon Sep 17 00:00:00 2001 From: Richard Elmore Date: Mon, 27 Feb 2023 16:27:46 -0800 Subject: [PATCH 1/8] Add led prototype project --- .../main/java/frc/robot/RobotContainer.java | 34 ++++++-------- .../main/java/frc/robot/commands/Autos.java | 20 -------- .../frc/robot/commands/ExampleCommand.java | 43 ----------------- .../robot/subsystems/ExampleSubsystem.java | 47 ------------------- .../frc/robot/subsystems/LedSubsystem.java | 35 ++++++++++++++ 5 files changed, 50 insertions(+), 129 deletions(-) delete mode 100644 Prototypes/src/main/java/frc/robot/commands/Autos.java delete mode 100644 Prototypes/src/main/java/frc/robot/commands/ExampleCommand.java delete mode 100644 Prototypes/src/main/java/frc/robot/subsystems/ExampleSubsystem.java create mode 100644 Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java diff --git a/Prototypes/src/main/java/frc/robot/RobotContainer.java b/Prototypes/src/main/java/frc/robot/RobotContainer.java index 3824a8b..3341582 100644 --- a/Prototypes/src/main/java/frc/robot/RobotContainer.java +++ b/Prototypes/src/main/java/frc/robot/RobotContainer.java @@ -1,16 +1,11 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - package frc.robot; import frc.robot.Constants.OperatorConstants; -import frc.robot.commands.Autos; -import frc.robot.commands.ExampleCommand; -import frc.robot.subsystems.ExampleSubsystem; +import frc.robot.subsystems.LedSubsystem; +import edu.wpi.first.wpilibj.util.Color8Bit; import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; -import edu.wpi.first.wpilibj2.command.button.Trigger; /** * This class is where the bulk of the robot should be declared. @@ -18,11 +13,16 @@ public class RobotContainer { // The robot's subsystems and commands are defined here... - private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem(); + private final LedSubsystem ledSubsystem = new LedSubsystem(0, 1, 2); - private final CommandXboxController m_driverController = new CommandXboxController( + private final CommandXboxController driveController = new CommandXboxController( OperatorConstants.DRIVE_CONTROLLER_PORT); + private final Color8Bit red = new Color8Bit(255, 0, 0); + private final Color8Bit green = new Color8Bit(0, 255, 0); + private final Color8Bit blue = new Color8Bit(0, 0, 255); + private final Color8Bit yellow = new Color8Bit(255, 255, 0); + /** * The container for the robot. Contains subsystems, OI devices, and commands. */ @@ -37,21 +37,17 @@ public void createSubsystems() { } public void createCommands() { - } /** * Use this method to define your trigger->command mappings. */ private void configureBindings() { - // Schedule `ExampleCommand` when `exampleCondition` changes to `true` - new Trigger(m_exampleSubsystem::exampleCondition) - .onTrue(new ExampleCommand(m_exampleSubsystem)); - // Schedule `exampleMethodCommand` when the Xbox controller's B button is - // pressed, - // cancelling on release. - m_driverController.b().whileTrue(m_exampleSubsystem.exampleMethodCommand()); + driveController.b().onTrue(new InstantCommand(() -> ledSubsystem.setColor(red))); + driveController.a().onTrue(new InstantCommand(() -> ledSubsystem.setColor(green))); + driveController.x().onTrue(new InstantCommand(() -> ledSubsystem.setColor(blue))); + driveController.y().onTrue(new InstantCommand(() -> ledSubsystem.setColor(yellow))); } /** @@ -61,6 +57,6 @@ private void configureBindings() { */ public Command getAutonomousCommand() { // An example command will be run in autonomous - return Autos.exampleAuto(m_exampleSubsystem); + return null; } } diff --git a/Prototypes/src/main/java/frc/robot/commands/Autos.java b/Prototypes/src/main/java/frc/robot/commands/Autos.java deleted file mode 100644 index 38345b5..0000000 --- a/Prototypes/src/main/java/frc/robot/commands/Autos.java +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package frc.robot.commands; - -import frc.robot.subsystems.ExampleSubsystem; -import edu.wpi.first.wpilibj2.command.CommandBase; -import edu.wpi.first.wpilibj2.command.Commands; - -public final class Autos { - /** Example static factory for an autonomous command. */ - public static CommandBase exampleAuto(ExampleSubsystem subsystem) { - return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); - } - - private Autos() { - throw new UnsupportedOperationException("This is a utility class!"); - } -} diff --git a/Prototypes/src/main/java/frc/robot/commands/ExampleCommand.java b/Prototypes/src/main/java/frc/robot/commands/ExampleCommand.java deleted file mode 100644 index 029b6f9..0000000 --- a/Prototypes/src/main/java/frc/robot/commands/ExampleCommand.java +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package frc.robot.commands; - -import frc.robot.subsystems.ExampleSubsystem; -import edu.wpi.first.wpilibj2.command.CommandBase; - -/** An example command that uses an example subsystem. */ -public class ExampleCommand extends CommandBase { - @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField", "unused"}) - private final ExampleSubsystem m_subsystem; - - /** - * Creates a new ExampleCommand. - * - * @param subsystem The subsystem used by this command. - */ - public ExampleCommand(ExampleSubsystem subsystem) { - m_subsystem = subsystem; - // Use addRequirements() here to declare subsystem dependencies. - addRequirements(subsystem); - } - - // Called when the command is initially scheduled. - @Override - public void initialize() {} - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - return false; - } -} diff --git a/Prototypes/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/Prototypes/src/main/java/frc/robot/subsystems/ExampleSubsystem.java deleted file mode 100644 index 3057963..0000000 --- a/Prototypes/src/main/java/frc/robot/subsystems/ExampleSubsystem.java +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) FIRST and other WPILib contributors. -// Open Source Software; you can modify and/or share it under the terms of -// the WPILib BSD license file in the root directory of this project. - -package frc.robot.subsystems; - -import edu.wpi.first.wpilibj2.command.CommandBase; -import edu.wpi.first.wpilibj2.command.SubsystemBase; - -public class ExampleSubsystem extends SubsystemBase { - /** Creates a new ExampleSubsystem. */ - public ExampleSubsystem() {} - - /** - * Example command factory method. - * - * @return a command - */ - public CommandBase exampleMethodCommand() { - // Inline construction of command goes here. - // Subsystem::RunOnce implicitly requires `this` subsystem. - return runOnce( - () -> { - /* one-time action goes here */ - }); - } - - /** - * An example method querying a boolean state of the subsystem (for example, a digital sensor). - * - * @return value of some boolean subsystem state, such as a digital sensor. - */ - public boolean exampleCondition() { - // Query some boolean state, such as a digital sensor. - return false; - } - - @Override - public void periodic() { - // This method will be called once per scheduler run - } - - @Override - public void simulationPeriodic() { - // This method will be called once per scheduler run during simulation - } -} diff --git a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java new file mode 100644 index 0000000..08e113c --- /dev/null +++ b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java @@ -0,0 +1,35 @@ +package frc.robot.subsystems; + +import edu.wpi.first.wpilibj.PWM; +import edu.wpi.first.wpilibj.util.Color8Bit; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + + +public class LedSubsystem extends SubsystemBase { + + // We are targeting a PWM frequency of 500Hz so there is not too much flicker. + private final double maxPulseWidthMs = 2.0; + private final double minPulseWidthMs = 0.0; + private final double centerPulseWidthMs = minPulseWidthMs + ((maxPulseWidthMs - minPulseWidthMs) / 2); + + private PWM red; + private PWM green; + private PWM blue; + + public LedSubsystem(int redChannel, int greenChannel, int blueChannel) { + + red = new PWM(redChannel); + green = new PWM(greenChannel); + blue = new PWM(blueChannel); + + red.setBounds(maxPulseWidthMs, 0.0, centerPulseWidthMs, 0.0, minPulseWidthMs); + green.setBounds(maxPulseWidthMs, 0.0, centerPulseWidthMs, 0.0, minPulseWidthMs); + blue.setBounds(maxPulseWidthMs, 0.0, centerPulseWidthMs, 0.0, minPulseWidthMs); + } + + public void setColor(Color8Bit color) { + red.setRaw(color.red); + green.setRaw(color.green); + blue.setRaw(color.blue); + } +} From 48e87a6f6452732a9c89012019c531b02e96b12b Mon Sep 17 00:00:00 2001 From: Richard Elmore Date: Mon, 27 Feb 2023 16:45:05 -0800 Subject: [PATCH 2/8] Add some comments --- .../src/main/java/frc/robot/subsystems/LedSubsystem.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java index 08e113c..0c81e88 100644 --- a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java +++ b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java @@ -7,7 +7,8 @@ public class LedSubsystem extends SubsystemBase { - // We are targeting a PWM frequency of 500Hz so there is not too much flicker. + // RoboRio PWM ports have a max output frequency of 150kHz + // We are targeting a PWM frequency of 500Hz to reduce flicker private final double maxPulseWidthMs = 2.0; private final double minPulseWidthMs = 0.0; private final double centerPulseWidthMs = minPulseWidthMs + ((maxPulseWidthMs - minPulseWidthMs) / 2); From 2d826319a4f5a78ecb0c06395d0307f535cac222 Mon Sep 17 00:00:00 2001 From: Richard Elmore Date: Mon, 27 Feb 2023 16:52:26 -0800 Subject: [PATCH 3/8] A couple more comments to make code clearer. --- .../main/java/frc/robot/subsystems/LedSubsystem.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java index 0c81e88..ce5be9a 100644 --- a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java +++ b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java @@ -13,6 +13,10 @@ public class LedSubsystem extends SubsystemBase { private final double minPulseWidthMs = 0.0; private final double centerPulseWidthMs = minPulseWidthMs + ((maxPulseWidthMs - minPulseWidthMs) / 2); + // We are not driving an H-bridge so we don't need to worry about shoot-through, no deadband is needed. + private final double deadbandMin = 0.0; + private final double deadbandMax = 0.0; + private PWM red; private PWM green; private PWM blue; @@ -23,9 +27,9 @@ public LedSubsystem(int redChannel, int greenChannel, int blueChannel) { green = new PWM(greenChannel); blue = new PWM(blueChannel); - red.setBounds(maxPulseWidthMs, 0.0, centerPulseWidthMs, 0.0, minPulseWidthMs); - green.setBounds(maxPulseWidthMs, 0.0, centerPulseWidthMs, 0.0, minPulseWidthMs); - blue.setBounds(maxPulseWidthMs, 0.0, centerPulseWidthMs, 0.0, minPulseWidthMs); + red.setBounds(maxPulseWidthMs, deadbandMax, centerPulseWidthMs, deadbandMin, minPulseWidthMs); + green.setBounds(maxPulseWidthMs, deadbandMax, centerPulseWidthMs, deadbandMin, minPulseWidthMs); + blue.setBounds(maxPulseWidthMs, deadbandMax, centerPulseWidthMs, deadbandMin, minPulseWidthMs); } public void setColor(Color8Bit color) { From d10ec4bb233b1354dba745a3c0f1756b346820c2 Mon Sep 17 00:00:00 2001 From: Richard Elmore Date: Mon, 27 Feb 2023 17:12:43 -0800 Subject: [PATCH 4/8] A little more cleanup. --- .../main/java/frc/robot/subsystems/LedSubsystem.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java index ce5be9a..7a6c936 100644 --- a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java +++ b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java @@ -14,8 +14,8 @@ public class LedSubsystem extends SubsystemBase { private final double centerPulseWidthMs = minPulseWidthMs + ((maxPulseWidthMs - minPulseWidthMs) / 2); // We are not driving an H-bridge so we don't need to worry about shoot-through, no deadband is needed. - private final double deadbandMin = 0.0; - private final double deadbandMax = 0.0; + private final double deadbandMaxMs = 0.0; + private final double deadbandMinMs = 0.0; private PWM red; private PWM green; @@ -27,9 +27,9 @@ public LedSubsystem(int redChannel, int greenChannel, int blueChannel) { green = new PWM(greenChannel); blue = new PWM(blueChannel); - red.setBounds(maxPulseWidthMs, deadbandMax, centerPulseWidthMs, deadbandMin, minPulseWidthMs); - green.setBounds(maxPulseWidthMs, deadbandMax, centerPulseWidthMs, deadbandMin, minPulseWidthMs); - blue.setBounds(maxPulseWidthMs, deadbandMax, centerPulseWidthMs, deadbandMin, minPulseWidthMs); + red.setBounds(maxPulseWidthMs, deadbandMaxMs, centerPulseWidthMs, deadbandMinMs, minPulseWidthMs); + green.setBounds(maxPulseWidthMs, deadbandMaxMs, centerPulseWidthMs, deadbandMinMs, minPulseWidthMs); + blue.setBounds(maxPulseWidthMs, deadbandMaxMs, centerPulseWidthMs, deadbandMinMs, minPulseWidthMs); } public void setColor(Color8Bit color) { From 0c37ee617543148260e079554f196cd385941690 Mon Sep 17 00:00:00 2001 From: Richard Elmore Date: Mon, 27 Feb 2023 19:57:35 -0800 Subject: [PATCH 5/8] FIx build --- Prototypes/build.gradle | 6 +++--- Prototypes/src/main/java/frc/robot/Robot.java | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Prototypes/build.gradle b/Prototypes/build.gradle index 7d5cd54..2352c8b 100644 --- a/Prototypes/build.gradle +++ b/Prototypes/build.gradle @@ -110,6 +110,6 @@ repositories { } // AdvantageKit docs say to include this but it breaks the build. -//configurations.all { -// exclude group: "edu.wpi.first.wpilibj" -//} +configurations.all { + exclude group: "edu.wpi.first.wpilibj" +} diff --git a/Prototypes/src/main/java/frc/robot/Robot.java b/Prototypes/src/main/java/frc/robot/Robot.java index 687a0a0..a7fce0d 100644 --- a/Prototypes/src/main/java/frc/robot/Robot.java +++ b/Prototypes/src/main/java/frc/robot/Robot.java @@ -4,9 +4,10 @@ package frc.robot; -import edu.wpi.first.wpilibj.TimedRobot; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; +import org.littletonrobotics.junction.LoggedRobot; +import org.littletonrobotics.junction.Logger; /** * The VM is configured to automatically run this class, and to call the functions corresponding to @@ -14,7 +15,7 @@ * the package after creating this project, you must also update the build.gradle file in the * project. */ -public class Robot extends TimedRobot { +public class Robot extends LoggedRobot { private Command m_autonomousCommand; private RobotContainer m_robotContainer; From bf20c7516b5dec7c75824da19311814509455192 Mon Sep 17 00:00:00 2001 From: joshuarus <97773720+joshuarus@users.noreply.github.com> Date: Mon, 27 Feb 2023 20:56:16 -0800 Subject: [PATCH 6/8] Added new colors for the LED's and binded the buttons to them --- Prototypes/src/main/java/frc/robot/RobotContainer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Prototypes/src/main/java/frc/robot/RobotContainer.java b/Prototypes/src/main/java/frc/robot/RobotContainer.java index 3341582..9bfae12 100644 --- a/Prototypes/src/main/java/frc/robot/RobotContainer.java +++ b/Prototypes/src/main/java/frc/robot/RobotContainer.java @@ -2,6 +2,7 @@ import frc.robot.Constants.OperatorConstants; import frc.robot.subsystems.LedSubsystem; +import edu.wpi.first.wpilibj.util.Color; import edu.wpi.first.wpilibj.util.Color8Bit; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.InstantCommand; @@ -22,6 +23,8 @@ public class RobotContainer { private final Color8Bit green = new Color8Bit(0, 255, 0); private final Color8Bit blue = new Color8Bit(0, 0, 255); private final Color8Bit yellow = new Color8Bit(255, 255, 0); + private final Color8Bit cubeColor = new Color8Bit(170, 0, 255); + private final Color8Bit coneColor = new Color8Bit(255, 234, 0); /** * The container for the robot. Contains subsystems, OI devices, and commands. @@ -48,6 +51,8 @@ private void configureBindings() { driveController.a().onTrue(new InstantCommand(() -> ledSubsystem.setColor(green))); driveController.x().onTrue(new InstantCommand(() -> ledSubsystem.setColor(blue))); driveController.y().onTrue(new InstantCommand(() -> ledSubsystem.setColor(yellow))); + driveController.rightBumper().onTrue(new InstantCommand(() -> ledSubsystem.setColor(cubeColor))); + driveController.leftBumper().onTrue(new InstantCommand(() -> ledSubsystem.setColor(coneColor))); } /** From 9335f40a63e3909e30005400fcf5eb1ddd5efac3 Mon Sep 17 00:00:00 2001 From: Richard Elmore Date: Tue, 28 Feb 2023 15:42:59 -0800 Subject: [PATCH 7/8] Get PWM working with DigitalOutput class --- .../main/java/frc/robot/RobotContainer.java | 4 ++ .../frc/robot/subsystems/LedSubsystem.java | 41 ++++++++----------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/Prototypes/src/main/java/frc/robot/RobotContainer.java b/Prototypes/src/main/java/frc/robot/RobotContainer.java index 9bfae12..ef22ea2 100644 --- a/Prototypes/src/main/java/frc/robot/RobotContainer.java +++ b/Prototypes/src/main/java/frc/robot/RobotContainer.java @@ -25,6 +25,7 @@ public class RobotContainer { private final Color8Bit yellow = new Color8Bit(255, 255, 0); private final Color8Bit cubeColor = new Color8Bit(170, 0, 255); private final Color8Bit coneColor = new Color8Bit(255, 234, 0); + private final Color8Bit darkRed = new Color8Bit(128,0,0); /** * The container for the robot. Contains subsystems, OI devices, and commands. @@ -53,6 +54,9 @@ private void configureBindings() { driveController.y().onTrue(new InstantCommand(() -> ledSubsystem.setColor(yellow))); driveController.rightBumper().onTrue(new InstantCommand(() -> ledSubsystem.setColor(cubeColor))); driveController.leftBumper().onTrue(new InstantCommand(() -> ledSubsystem.setColor(coneColor))); + + driveController.povLeft().onTrue(new InstantCommand(() -> ledSubsystem.setColor(darkRed))); + driveController.povRight().onTrue(new InstantCommand(() -> ledSubsystem.setColor(red))); } /** diff --git a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java index 7a6c936..9671b1e 100644 --- a/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java +++ b/Prototypes/src/main/java/frc/robot/subsystems/LedSubsystem.java @@ -1,40 +1,35 @@ package frc.robot.subsystems; -import edu.wpi.first.wpilibj.PWM; +import edu.wpi.first.wpilibj.DigitalOutput; import edu.wpi.first.wpilibj.util.Color8Bit; import edu.wpi.first.wpilibj2.command.SubsystemBase; public class LedSubsystem extends SubsystemBase { - // RoboRio PWM ports have a max output frequency of 150kHz - // We are targeting a PWM frequency of 500Hz to reduce flicker - private final double maxPulseWidthMs = 2.0; - private final double minPulseWidthMs = 0.0; - private final double centerPulseWidthMs = minPulseWidthMs + ((maxPulseWidthMs - minPulseWidthMs) / 2); + private final double pwmRateHz = 100.0; - // We are not driving an H-bridge so we don't need to worry about shoot-through, no deadband is needed. - private final double deadbandMaxMs = 0.0; - private final double deadbandMinMs = 0.0; - - private PWM red; - private PWM green; - private PWM blue; + private DigitalOutput red; + private DigitalOutput green; + private DigitalOutput blue; public LedSubsystem(int redChannel, int greenChannel, int blueChannel) { - red = new PWM(redChannel); - green = new PWM(greenChannel); - blue = new PWM(blueChannel); + red = new DigitalOutput(redChannel); + red.setPWMRate(pwmRateHz); + red.enablePWM(0); + + green = new DigitalOutput(greenChannel); + green.enablePWM(0); - red.setBounds(maxPulseWidthMs, deadbandMaxMs, centerPulseWidthMs, deadbandMinMs, minPulseWidthMs); - green.setBounds(maxPulseWidthMs, deadbandMaxMs, centerPulseWidthMs, deadbandMinMs, minPulseWidthMs); - blue.setBounds(maxPulseWidthMs, deadbandMaxMs, centerPulseWidthMs, deadbandMinMs, minPulseWidthMs); + blue = new DigitalOutput(blueChannel); + blue.enablePWM(0); } public void setColor(Color8Bit color) { - red.setRaw(color.red); - green.setRaw(color.green); - blue.setRaw(color.blue); - } + + red.updateDutyCycle((double)color.red / 255.0); + green.updateDutyCycle((double)color.green / 255.0); + blue.updateDutyCycle((double)color.blue / 255.0); + } } From 48f77b2e31a34e9521ee934818022176c668f984 Mon Sep 17 00:00:00 2001 From: frankwyang Date: Wed, 1 Mar 2023 10:48:08 -0800 Subject: [PATCH 8/8] update wpilib to 2023.4.2 --- Prototypes/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Prototypes/build.gradle b/Prototypes/build.gradle index 2352c8b..e0ae565 100644 --- a/Prototypes/build.gradle +++ b/Prototypes/build.gradle @@ -1,6 +1,6 @@ plugins { id "java" - id "edu.wpi.first.GradleRIO" version "2023.4.1" + id "edu.wpi.first.GradleRIO" version "2023.4.2" } sourceCompatibility = JavaVersion.VERSION_11