From 7a92fae690b812548e6f6c34160b3b4c039a7b56 Mon Sep 17 00:00:00 2001
From: hc-45 <223769218+hc-45@users.noreply.github.com>
Date: Wed, 29 Jul 2026 14:43:52 -0400
Subject: [PATCH 1/4] Add Template Command Stuyle Robot Project for 2027
---
.gitignore | 25 +
.vscode/settings.json | 34 +-
.wpilib/wpilib_preferences.json | 2 +-
LICENSE.txt | 21 +
README.md | 3 +-
WPILib-License.md | 2 +-
assets/.gitkeep | 0
build.gradle | 108 ++--
gradle/wrapper/gradle-wrapper.properties | 2 +-
gradlew | 12 +-
gradlew.bat | 3 +-
settings.gradle | 18 +-
src/main/deploy/example.txt | 3 +
src/main/java/com/stuypulse/robot/Main.java | 19 +-
src/main/java/com/stuypulse/robot/Robot.java | 70 ++-
.../com/stuypulse/robot/RobotContainer.java | 39 +-
.../commands/auton/AutonomousRoutines.java | 13 +
.../com/stuypulse/robot/constants/Motors.java | 493 +++++++++++++-----
.../com/stuypulse/robot/constants/Ports.java | 3 +-
.../stuypulse/robot/constants/Settings.java | 8 +-
vendordeps/AdvantageKit.json | 35 ++
vendordeps/CommandsV3.json | 25 +
vendordeps/DogLog.json | 6 +-
vendordeps/Phoenix6-26.50.0-alpha-1.json | 449 ++++++++++++++++
24 files changed, 1148 insertions(+), 245 deletions(-)
create mode 100644 LICENSE.txt
create mode 100644 assets/.gitkeep
create mode 100644 src/main/deploy/example.txt
create mode 100644 src/main/java/com/stuypulse/robot/commands/auton/AutonomousRoutines.java
create mode 100644 vendordeps/AdvantageKit.json
create mode 100644 vendordeps/CommandsV3.json
create mode 100644 vendordeps/Phoenix6-26.50.0-alpha-1.json
diff --git a/.gitignore b/.gitignore
index 11d4e4f..3145f39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -158,9 +158,34 @@ gradle-app.setting
.settings/
bin/
+# IntelliJ
+*.iml
+*.ipr
+*.iws
+.idea/
+out/
+
+# Fleet
+.fleet
+
# Simulation GUI and other tools window save file
+networktables.json
+simgui.json
*-window.json
+# Simulation data log directory
+logs/
+
# Logs
*.wpilog
*.log
+
+# Folder that has CTRE Phoenix Sim device config storage
+ctre_sim/
+
+# clangd
+/.cache
+compile_commands.json
+
+# Eclipse generated file for annotation processors
+.factorypath
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 4ed293b..3c5c2e6 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -25,5 +25,37 @@
}
},
],
- "java.test.defaultConfig": "WPIlibUnitTests"
+ "java.test.defaultConfig": "WPIlibUnitTests",
+ "java.import.gradle.annotationProcessing.enabled": false,
+ "java.completion.favoriteStaticMembers": [
+ "org.junit.Assert.*",
+ "org.junit.Assume.*",
+ "org.junit.jupiter.api.Assertions.*",
+ "org.junit.jupiter.api.Assumptions.*",
+ "org.junit.jupiter.api.DynamicContainer.*",
+ "org.junit.jupiter.api.DynamicTest.*",
+ "org.mockito.Mockito.*",
+ "org.mockito.ArgumentMatchers.*",
+ "org.mockito.Answers.*",
+ "org.wpilib.units.Units.*"
+ ],
+ "java.completion.filteredTypes": [
+ "java.awt.*",
+ "com.sun.*",
+ "sun.*",
+ "jdk.*",
+ "org.graalvm.*",
+ "io.micrometer.shaded.*",
+ "java.beans.*",
+ "java.util.Base64.*",
+ "java.util.Timer",
+ "java.sql.*",
+ "javax.swing.*",
+ "javax.management.*",
+ "javax.smartcardio.*",
+ "org.wpilib.math.proto.*",
+ "org.wpilib.math.**.proto.*",
+ "org.wpilib.math.**.struct.*",
+ ],
+ "java.dependency.enableDependencyCheckup": false
}
diff --git a/.wpilib/wpilib_preferences.json b/.wpilib/wpilib_preferences.json
index 1775a01..aed4426 100644
--- a/.wpilib/wpilib_preferences.json
+++ b/.wpilib/wpilib_preferences.json
@@ -1,6 +1,6 @@
{
"enableCppIntellisense": false,
"currentLanguage": "java",
- "projectYear": "2026",
+ "projectYear": "2027_alpha5",
"teamNumber": 694
}
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..10fb5b1
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 StuyPulse
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index d70ff1f..84c0e3a 100644
--- a/README.md
+++ b/README.md
@@ -13,5 +13,4 @@ Do *not* use the automatic import project tool. Instead,
- Change the 'frcYear' to the current year in `settings.gradle`.
- Check that the `GradleRIO` version is up to date in `./build.gradle`.
- Check the latest version of [StuyLib here](https://github.com/StuyPulse/StuyLib/releases) and update the version in `./build.gradle`.
-- Manually update the files ('frcYear', 'version', URLS) in `./venderdeps` with their latest version, checking their respective websites, or import new versions using WPILib vendor dependencies.
-
+- Manually update the files ('frcYear', 'version', URLS) in `./vendordeps` with their latest version, checking their respective websites, or import new versions using WPILib vendor dependencies.
diff --git a/WPILib-License.md b/WPILib-License.md
index 645e542..eb3061b 100644
--- a/WPILib-License.md
+++ b/WPILib-License.md
@@ -1,4 +1,4 @@
-Copyright (c) 2009-2024 FIRST and other WPILib contributors
+Copyright (c) 2009-2026 FIRST and other WPILib contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/assets/.gitkeep b/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/build.gradle b/build.gradle
index 1ff6551..5b8764c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,68 +1,72 @@
plugins {
id "java"
- id "edu.wpi.first.GradleRIO" version "2026.2.1"
- id "com.diffplug.spotless" version "6.22.0"
+ id "org.wpilib.GradleRIO" version "2027.0.0-alpha-6"
+ id "com.gradleup.shadow" version "9.3.0"
+ id "com.diffplug.spotless" version "8.9.0"
}
-allprojects {
- repositories {
- maven { url 'https://jitpack.io' }
- }
+java {
+ sourceCompatibility = JavaVersion.VERSION_25
+ targetCompatibility = JavaVersion.VERSION_25
}
def ROBOT_MAIN_CLASS = "com.stuypulse.robot.Main"
-sourceCompatibility = JavaVersion.VERSION_17
-targetCompatibility = JavaVersion.VERSION_17
-
-// Define my targets (RoboRIO) and artifacts (deployable files)
+// Define my targets (SystemCore) and artifacts (deployable files)
// This is added by GradleRIO's backing project DeployUtils.
deploy {
targets {
- roborio(getTargetTypeClass('RoboRIO')) {
+ systemcore(getTargetTypeClass('SystemCore')) {
// Team number is loaded either from the .wpilib/wpilib_preferences.json
// or from command line. If not found an exception will be thrown.
// You can use getTeamOrDefault(team) instead of getTeamNumber if you
// want to store a team number in this file.
- team = project.frc.getTeamNumber()
- debug = project.frc.getDebugOrDefault(false)
+ team = project.wpilib.getTeamNumber()
+ // Use the default systemcore host name. This must be called after setting team
+ // as happens on the line above
+ useDefaultSystemcoreHostName()
+ debug = project.wpilib.getDebugOrDefault(false)
artifacts {
// First part is artifact name, 2nd is artifact type
// getTargetTypeClass is a shortcut to get the class type using a string
- frcJava(getArtifactTypeClass('FRCJavaArtifact')) {
+ wpilibJava(getArtifactTypeClass('WPILibJavaArtifact')) {
}
// Static files artifact
- frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) {
+ wpilibStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) {
files = project.fileTree('src/main/deploy')
- directory = '/home/lvuser/deploy'
+ directory = '/home/systemcore/deploy'
+ deleteOldFiles = false // Change to true to delete files on systemcore that no
+ // longer exist in deploy directory of this project
}
}
}
}
}
-def deployArtifact = deploy.targets.roborio.artifacts.frcJava
+def deployArtifact = deploy.targets.systemcore.artifacts.wpilibJava
-// Set to true to use debug for JNI.
+// Set to true to use debug for all targets including JNI, which will drastically impact
+// performance.
wpi.java.debugJni = false
// Set this to true to enable desktop support.
-def includeDesktopSupport = false
+def includeDesktopSupport = true
// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
// Also defines JUnit 5.
dependencies {
+ annotationProcessor wpi.java.deps.wpilibAnnotations()
implementation wpi.java.deps.wpilib()
implementation wpi.java.vendor.java()
- roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio)
- roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio)
+ systemcoreDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.systemcore)
+ systemcoreDebug wpi.java.vendor.jniDebug(wpi.platforms.systemcore)
- roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio)
- roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio)
+ systemcoreRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.systemcore)
+ systemcoreRelease wpi.java.vendor.jniRelease(wpi.platforms.systemcore)
nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
@@ -72,18 +76,51 @@ dependencies {
nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
simulationRelease wpi.sim.enableRelease()
- testImplementation 'junit:junit:4.13.1'
+ testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
+ testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+}
+
+test {
+ useJUnitPlatform()
+ systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
}
// Simulation configuration (e.g. environment variables).
wpi.sim.addGui().defaultEnabled = true
wpi.sim.addDriverstation()
+// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat/shaded jar')
+// in order to make them all available at runtime and merging service files to make JSON work.
+// Also adding the manifest so WPILib knows where to look for our Robot Class.
+shadowJar {
+ mergeServiceFiles()
+ from('src') { into 'backup/src' }
+ from('vendordeps') { into 'backup/vendordeps' }
+ from('build.gradle') { into 'backup' }
+ manifest org.wpilib.gradlerio.GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS)
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+}
+
+// Configure jar and deploy tasks
+deployArtifact.jarTask = shadowJar
+wpi.java.configureExecutableTasks(shadowJar)
+wpi.java.configureTestTasks(test)
+
+// Configure string concat to always inline compile
+tasks.withType(JavaCompile) {
+ options.compilerArgs.add '-XDstringConcat=inline'
+}
+
spotless {
enforceCheck = false
java {
targetExclude("src/main/java/com/stuypulse/robot/commands/autons/*.java")
- licenseHeaderFile "LICENSE"
+
+ licenseHeader("""/************************ PROJECT PHIL ************************/
+/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
+/* This work is licensed under the terms of the MIT license. */
+/**************************************************************/
+""").updateYearWithLatest(false)
googleJavaFormat().aosp()
@@ -97,28 +134,9 @@ spotless {
'com.stuypulse.commands.auton',
'com.stuypulse.util',
'com.stuypulse',
- 'edu.wpi',
+ 'org.wpilib',
'com.revrobotics'
)
removeUnusedImports()
}
}
-
-// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat jar')
-// in order to make them all available at runtime. Also adding the manifest so WPILib
-// knows where to look for our Robot Class.
-jar {
- from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
- manifest edu.wpi.first.gradlerio.GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS)
- duplicatesStrategy = DuplicatesStrategy.INCLUDE
-}
-
-// Configure jar and deploy tasks
-deployArtifact.jarTask = jar
-wpi.java.configureExecutableTasks(jar)
-wpi.java.configureTestTasks(test)
-
-// Configure string concat to always inline compile
-tasks.withType(JavaCompile) {
- options.compilerArgs.add '-XDstringConcat=inline'
-}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 34bd9ce..42bb5ac 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=permwrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index f5feea6..0c908af 100755
--- a/gradlew
+++ b/gradlew
@@ -57,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/2d6327017519d23b96af35865dc997fcb544fb40/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -86,8 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
-' "$PWD" ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -115,7 +114,6 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
-CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -173,7 +171,6 @@ fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
- CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
@@ -206,15 +203,14 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
- -classpath "$CLASSPATH" \
- org.gradle.wrapper.GradleWrapperMain \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.
diff --git a/gradlew.bat b/gradlew.bat
index 9d21a21..c4bdd3a 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -70,11 +70,10 @@ goto fail
:execute
@rem Setup the command line
-set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
-"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell
diff --git a/settings.gradle b/settings.gradle
index 486702a..e2626a8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -2,27 +2,27 @@ import org.gradle.internal.os.OperatingSystem
pluginManagement {
repositories {
- mavenLocal()
- gradlePluginPortal()
- String frcYear = '2026'
- File frcHome
+ String wpilibYear = '2027_alpha5'
+ File wpilibHome
if (OperatingSystem.current().isWindows()) {
String publicFolder = System.getenv('PUBLIC')
if (publicFolder == null) {
publicFolder = "C:\\Users\\Public"
}
def homeRoot = new File(publicFolder, "wpilib")
- frcHome = new File(homeRoot, frcYear)
+ wpilibHome = new File(homeRoot, wpilibYear)
} else {
def userFolder = System.getProperty("user.home")
def homeRoot = new File(userFolder, "wpilib")
- frcHome = new File(homeRoot, frcYear)
+ wpilibHome = new File(homeRoot, wpilibYear)
}
- def frcHomeMaven = new File(frcHome, 'maven')
+ def wpilibHomeMaven = new File(wpilibHome, 'maven')
maven {
- name 'frcHome'
- url frcHomeMaven
+ name = 'wpilibHome'
+ url = wpilibHomeMaven
}
+ mavenLocal()
+ gradlePluginPortal()
}
}
diff --git a/src/main/deploy/example.txt b/src/main/deploy/example.txt
new file mode 100644
index 0000000..c9bc6a2
--- /dev/null
+++ b/src/main/deploy/example.txt
@@ -0,0 +1,3 @@
+Files placed in this directory will be deployed to the Systemcore into the
+'deploy' directory in the home folder. Use the 'Filesystem.getDeployDirectory' wpilib function
+to get a proper path relative to the deploy directory.
\ No newline at end of file
diff --git a/src/main/java/com/stuypulse/robot/Main.java b/src/main/java/com/stuypulse/robot/Main.java
index a4f5843..bca0ed6 100644
--- a/src/main/java/com/stuypulse/robot/Main.java
+++ b/src/main/java/com/stuypulse/robot/Main.java
@@ -2,15 +2,28 @@
/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
/* This work is licensed under the terms of the MIT license. */
/**************************************************************/
-
package com.stuypulse.robot;
-import edu.wpi.first.wpilibj.RobotBase;
+import org.wpilib.framework.RobotBase;
+/**
+ *
+ *
+ *
There is no need to edit this file, and it should not be edited unless you know what you are
+ * doing.
+ */
public final class Main {
private Main() {}
+ /**
+ * The main method that starts the robot code. This should not be edited unless you know what
+ * you are doing.
+ */
public static void main(String... args) {
- RobotBase.startRobot(Robot::new);
+ RobotBase.startRobot(Robot.class);
}
}
diff --git a/src/main/java/com/stuypulse/robot/Robot.java b/src/main/java/com/stuypulse/robot/Robot.java
index e0f788d..979da16 100644
--- a/src/main/java/com/stuypulse/robot/Robot.java
+++ b/src/main/java/com/stuypulse/robot/Robot.java
@@ -2,30 +2,56 @@
/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
/* This work is licensed under the terms of the MIT license. */
/**************************************************************/
-
package com.stuypulse.robot;
-import edu.wpi.first.wpilibj.TimedRobot;
-import edu.wpi.first.wpilibj2.command.Command;
-import edu.wpi.first.wpilibj2.command.CommandScheduler;
-
+import org.wpilib.command3.Command;
+import org.wpilib.command3.Scheduler;
+import org.wpilib.driverstation.Alliance;
+import org.wpilib.driverstation.MatchState;
+import org.wpilib.framework.TimedRobot;
+
+import java.util.Optional;
+
+/**
+ *
+ *
+ *
alliance = MatchState.getAlliance();
+ if (alliance.isPresent()) {
+ return alliance.get() == Alliance.BLUE;
+ }
+ return false;
+ }
- private RobotContainer robot;
+ private final RobotContainer robot;
+ private final Scheduler defaultScheduler;
private Command auto;
+ public Robot() {
+ robot = new RobotContainer();
+ defaultScheduler = Scheduler.getDefault();
+ }
+
/*************************/
/*** ROBOT SCHEDULEING ***/
/*************************/
- @Override
- public void robotInit() {
- robot = new RobotContainer();
- }
-
@Override
public void robotPeriodic() {
- CommandScheduler.getInstance().run();
+ defaultScheduler.run();
}
/*********************/
@@ -40,14 +66,14 @@ public void disabledPeriodic() {}
/***********************/
/*** AUTONOMOUS MODE ***/
- /***********************/
+ /***********************/
@Override
public void autonomousInit() {
auto = robot.getAutonomousCommand();
if (auto != null) {
- auto.schedule();
+ defaultScheduler.schedule(auto);
}
}
@@ -64,7 +90,7 @@ public void autonomousExit() {}
@Override
public void teleopInit() {
if (auto != null) {
- auto.cancel();
+ defaultScheduler.cancel(auto);
}
}
@@ -74,18 +100,18 @@ public void teleopPeriodic() {}
@Override
public void teleopExit() {}
- /*****************/
- /*** TEST MODE ***/
- /*****************/
+ /*************************/
+ /*** UTILITY/TEST MODE ***/
+ /*************************/
@Override
- public void testInit() {
- CommandScheduler.getInstance().cancelAll();
+ public void utilityInit() {
+ defaultScheduler.cancelAll();
}
@Override
- public void testPeriodic() {}
+ public void utilityPeriodic() {}
@Override
- public void testExit() {}
+ public void utilityExit() {}
}
diff --git a/src/main/java/com/stuypulse/robot/RobotContainer.java b/src/main/java/com/stuypulse/robot/RobotContainer.java
index c48fa38..de6f71c 100644
--- a/src/main/java/com/stuypulse/robot/RobotContainer.java
+++ b/src/main/java/com/stuypulse/robot/RobotContainer.java
@@ -2,23 +2,27 @@
/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
/* This work is licensed under the terms of the MIT license. */
/**************************************************************/
-
package com.stuypulse.robot;
-import com.stuypulse.robot.commands.auton.DoNothingAuton;
+import com.stuypulse.robot.commands.auton.AutonomousRoutines;
import com.stuypulse.robot.constants.Ports;
-import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
-import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
-import edu.wpi.first.wpilibj2.command.Command;
-import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
+import org.wpilib.command3.Command;
+import org.wpilib.command3.button.CommandNiDsXboxController;
+import org.wpilib.smartdashboard.SendableChooser;
+import org.wpilib.smartdashboard.SmartDashboard;
+
+import dev.doglog.DogLog;
+import dev.doglog.DogLogOptions;
public class RobotContainer {
// Gamepads
- public final CommandXboxController driver = new CommandXboxController(Ports.Gamepad.DRIVER);
- public final CommandXboxController operator = new CommandXboxController(Ports.Gamepad.OPERATOR);
-
+ public final CommandNiDsXboxController driver =
+ new CommandNiDsXboxController(Ports.Gamepad.DRIVER);
+ public final CommandNiDsXboxController operator =
+ new CommandNiDsXboxController(Ports.Gamepad.OPERATOR);
+
// Subsystem
// Autons
@@ -27,11 +31,21 @@ public class RobotContainer {
// Robot container
public RobotContainer() {
+ configureLogging();
configureDefaultCommands();
configureButtonBindings();
configureAutons();
}
+ /***************/
+ /*** LOGGING ***/
+ /***************/
+
+ private void configureLogging() {
+ DogLog.setOptions(
+ new DogLogOptions().withCaptureDs(true).withNtTunables(true).withLogExtras(true));
+ }
+
/****************/
/*** DEFAULTS ***/
/****************/
@@ -49,11 +63,16 @@ private void configureButtonBindings() {}
/**************/
public void configureAutons() {
- autonChooser.setDefaultOption("Do Nothing", new DoNothingAuton());
+ autonChooser.setDefaultOption("Do Nothing", AutonomousRoutines.doNothingAuton());
SmartDashboard.putData("Autonomous", autonChooser);
}
+ /**
+ * Use this to pass the autonomous command to the main {@link Robot} class.
+ *
+ * @return The command to run in autonomous
+ */
public Command getAutonomousCommand() {
return autonChooser.getSelected();
}
diff --git a/src/main/java/com/stuypulse/robot/commands/auton/AutonomousRoutines.java b/src/main/java/com/stuypulse/robot/commands/auton/AutonomousRoutines.java
new file mode 100644
index 0000000..efa8245
--- /dev/null
+++ b/src/main/java/com/stuypulse/robot/commands/auton/AutonomousRoutines.java
@@ -0,0 +1,13 @@
+/************************ PROJECT PHIL ************************/
+/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
+/* This work is licensed under the terms of the MIT license. */
+/**************************************************************/
+package com.stuypulse.robot.commands.auton;
+
+import org.wpilib.command3.Command;
+
+public interface AutonomousRoutines {
+ public static Command doNothingAuton() {
+ return Command.sequence().named("Do Nothing");
+ }
+}
diff --git a/src/main/java/com/stuypulse/robot/constants/Motors.java b/src/main/java/com/stuypulse/robot/constants/Motors.java
index dc36e23..c3df175 100644
--- a/src/main/java/com/stuypulse/robot/constants/Motors.java
+++ b/src/main/java/com/stuypulse/robot/constants/Motors.java
@@ -2,31 +2,15 @@
/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
/* This work is licensed under the terms of the MIT license. */
/**************************************************************/
-
package com.stuypulse.robot.constants;
-import com.ctre.phoenix6.configs.ClosedLoopGeneralConfigs;
-import com.ctre.phoenix6.configs.ClosedLoopRampsConfigs;
-import com.ctre.phoenix6.configs.CurrentLimitsConfigs;
-import com.ctre.phoenix6.configs.FeedbackConfigs;
-import com.ctre.phoenix6.configs.MotionMagicConfigs;
-import com.ctre.phoenix6.configs.MotorOutputConfigs;
-import com.ctre.phoenix6.configs.OpenLoopRampsConfigs;
-import com.ctre.phoenix6.configs.Slot0Configs;
-import com.ctre.phoenix6.configs.Slot1Configs;
-import com.ctre.phoenix6.configs.Slot2Configs;
-import com.ctre.phoenix6.configs.SlotConfigs;
-import com.ctre.phoenix6.configs.SoftwareLimitSwitchConfigs;
-import com.ctre.phoenix6.configs.TalonFXConfiguration;
-import com.ctre.phoenix6.configs.TorqueCurrentConfigs;
-import com.ctre.phoenix6.configs.VoltageConfigs;
+import static org.wpilib.units.Units.*;
+
+import org.wpilib.units.measure.*;
+
+import com.ctre.phoenix6.configs.*;
import com.ctre.phoenix6.hardware.TalonFX;
-import com.ctre.phoenix6.signals.FeedbackSensorSourceValue;
-import com.ctre.phoenix6.signals.GainSchedBehaviorValue;
-import com.ctre.phoenix6.signals.GravityTypeValue;
-import com.ctre.phoenix6.signals.InvertedValue;
-import com.ctre.phoenix6.signals.NeutralModeValue;
-import com.ctre.phoenix6.signals.StaticFeedforwardSignValue;
+import com.ctre.phoenix6.signals.*;
/*-
* File containing all of the configurations that different motors require.
@@ -40,9 +24,7 @@
public interface Motors {
/** Classes to store all of the values a motor needs */
- /**
- * Wrapper class for configuring TalonFX motors
- */
+ /** Wrapper class for configuring TalonFX motors */
public static class TalonFXConfig {
private final TalonFXConfiguration configuration = new TalonFXConfiguration();
private final Slot0Configs slot0Configs = new Slot0Configs();
@@ -54,8 +36,10 @@ public static class TalonFXConfig {
private final CurrentLimitsConfigs currentLimitsConfigs = new CurrentLimitsConfigs();
private final FeedbackConfigs feedbackConfigs = new FeedbackConfigs();
private final MotionMagicConfigs motionMagicConfigs = new MotionMagicConfigs();
- private final SoftwareLimitSwitchConfigs softwareLimitSwitchConfigs = new SoftwareLimitSwitchConfigs();
- private final ClosedLoopGeneralConfigs closedLoopGeneralConfigs = new ClosedLoopGeneralConfigs();
+ private final SoftwareLimitSwitchConfigs softwareLimitSwitchConfigs =
+ new SoftwareLimitSwitchConfigs();
+ private final ClosedLoopGeneralConfigs closedLoopGeneralConfigs =
+ new ClosedLoopGeneralConfigs();
private final VoltageConfigs voltageConfigs = new VoltageConfigs();
private final TorqueCurrentConfigs torqueCurrentConfigs = new TorqueCurrentConfigs();
@@ -77,30 +61,39 @@ public TalonFXConfiguration getConfiguration() {
return this.configuration;
}
- public void updateGainsConfig(TalonFX motor, int slot, double kP, double kI, double kD, double kS, double kV, double kA) {
+ public void updateGainsConfig(
+ TalonFX motor,
+ int slot,
+ double kP,
+ double kI,
+ double kD,
+ double kS,
+ double kV,
+ double kA) {
if (slot != 0 && slot != 1 && slot != 2) {
return;
}
- boolean changed =
- kP != lastKP[slot] ||
- kI != lastKI[slot] ||
- kD != lastKD[slot] ||
- kS != lastKS[slot] ||
- kV != lastKV[slot] ||
- kA != lastKA[slot];
+ final boolean changed =
+ kP != lastKP[slot]
+ || kI != lastKI[slot]
+ || kD != lastKD[slot]
+ || kS != lastKS[slot]
+ || kV != lastKV[slot]
+ || kA != lastKA[slot];
if (!changed) {
return;
}
- SlotConfigs gainConfig = new SlotConfigs()
- .withKP(kP)
- .withKI(kI)
- .withKD(kD)
- .withKS(kS)
- .withKV(kV)
- .withKA(kA);
+ final SlotConfigs gainConfig =
+ new SlotConfigs()
+ .withKP(kP)
+ .withKI(kI)
+ .withKD(kD)
+ .withKS(kS)
+ .withKV(kV)
+ .withKA(kA);
gainConfig.SlotNumber = slot;
@@ -131,21 +124,15 @@ public void updateGainsConfig(TalonFX motor, int slot, double kP, double kI, dou
public TalonFXConfig withPIDConstants(double kP, double kI, double kD, int slot) {
switch (slot) {
case 0:
- slot0Configs.kP = kP;
- slot0Configs.kI = kI;
- slot0Configs.kD = kD;
+ slot0Configs.withKP(kP).withKI(kI).withKD(kD);
configuration.withSlot0(slot0Configs);
break;
case 1:
- slot1Configs.kP = kP;
- slot1Configs.kI = kI;
- slot1Configs.kD = kD;
+ slot1Configs.withKP(kP).withKI(kI).withKD(kD);
configuration.withSlot1(slot1Configs);
break;
case 2:
- slot2Configs.kP = kP;
- slot2Configs.kI = kI;
- slot2Configs.kD = kD;
+ slot2Configs.withKP(kP).withKI(kI).withKD(kD);
configuration.withSlot2(slot2Configs);
break;
}
@@ -159,42 +146,34 @@ public TalonFXConfig withFFConstants(double kS, double kV, double kA, int slot)
public TalonFXConfig withFFConstants(double kS, double kV, double kA, double kG, int slot) {
switch (slot) {
case 0:
- slot0Configs.kS = kS;
- slot0Configs.kV = kV;
- slot0Configs.kA = kA;
- slot0Configs.kG = kG;
+ slot0Configs.withKS(kS).withKV(kV).withKA(kA).withKG(kG);
configuration.withSlot0(slot0Configs);
break;
case 1:
- slot1Configs.kS = kS;
- slot1Configs.kV = kV;
- slot1Configs.kA = kA;
- slot1Configs.kG = kG;
+ slot1Configs.withKS(kS).withKV(kV).withKA(kA).withKG(kG);
configuration.withSlot1(slot1Configs);
break;
case 2:
- slot2Configs.kS = kS;
- slot2Configs.kV = kV;
- slot2Configs.kA = kA;
- slot2Configs.kG = kG;
+ slot2Configs.withKS(kS).withKV(kV).withKA(kA).withKG(kG);
configuration.withSlot2(slot2Configs);
break;
}
return this;
}
- public TalonFXConfig withStaticFeedforwardSign(StaticFeedforwardSignValue staticFeedforwardSign, int slot) {
+ public TalonFXConfig withStaticFeedforwardSign(
+ StaticFeedforwardSignValue staticFeedforwardSign, int slot) {
switch (slot) {
case 0:
- slot0Configs.StaticFeedforwardSign = staticFeedforwardSign;
+ slot0Configs.withStaticFeedforwardSign(staticFeedforwardSign);
configuration.withSlot0(slot0Configs);
break;
case 1:
- slot1Configs.StaticFeedforwardSign = staticFeedforwardSign;
+ slot1Configs.withStaticFeedforwardSign(staticFeedforwardSign);
configuration.withSlot1(slot1Configs);
break;
case 2:
- slot2Configs.StaticFeedforwardSign = staticFeedforwardSign;
+ slot2Configs.withStaticFeedforwardSign(staticFeedforwardSign);
configuration.withSlot2(slot2Configs);
break;
}
@@ -203,9 +182,9 @@ public TalonFXConfig withStaticFeedforwardSign(StaticFeedforwardSignValue static
}
public TalonFXConfig withGravityType(GravityTypeValue gravityType) {
- slot0Configs.GravityType = gravityType;
- slot1Configs.GravityType = gravityType;
- slot2Configs.GravityType = gravityType;
+ slot0Configs.withGravityType(gravityType);
+ slot1Configs.withGravityType(gravityType);
+ slot2Configs.withGravityType(gravityType);
configuration.withSlot0(slot0Configs);
configuration.withSlot1(slot1Configs);
@@ -214,26 +193,56 @@ public TalonFXConfig withGravityType(GravityTypeValue gravityType) {
return this;
}
- public TalonFXConfig withGainSchedBehavior(GainSchedBehaviorValue value, double threshold, int slot) {
- closedLoopGeneralConfigs.GainSchedErrorThreshold = threshold;
+ /**
+ * Modifies this configuration's GainSchedErrorThreshold parameter, which is the position
+ * closed-loop error threshold to apply gains scheduling.
+ *
+ * @param value Gains scheduling behavior, see {@link
+ * com.ctre.phoenix6.signals.GainSchedBehaviorValue}.
+ * @param thresholdRotations The position closed-loop error threshold for gain scheduling in
+ * rotations.
+ * @param slot Slot to apply gains scheduling behavior to.
+ * @return Itself for method-chaining.
+ */
+ public TalonFXConfig withGainSchedBehavior(
+ GainSchedBehaviorValue value, double thresholdRotations, int slot) {
+ return this.withGainSchedBehavior(value, Rotations.of(thresholdRotations), slot);
+ }
+
+ /**
+ * Modifies this configuration's GainSchedErrorThreshold parameter, which is the position
+ * closed-loop error threshold to apply gains scheduling.
+ *
+ * @param value Gains scheduling behavior, see {@link
+ * com.ctre.phoenix6.signals.GainSchedBehaviorValue}.
+ * @param thresholdRotations The position closed-loop error threshold for gain scheduling.
+ * @param slot Slot to apply gains scheduling behavior to.
+ * @return Itself for method-chaining.
+ */
+ public TalonFXConfig withGainSchedBehavior(
+ GainSchedBehaviorValue value, Angle threshold, int slot) {
+ closedLoopGeneralConfigs.withGainSchedErrorThreshold(threshold);
configuration.withClosedLoopGeneral(closedLoopGeneralConfigs);
-
- switch(slot) {
- case 0: {
- slot0Configs.GainSchedBehavior = value;
- configuration.withSlot0(slot0Configs);
- }
- break;
- case 1: {
- slot1Configs.GainSchedBehavior = value;
- configuration.withSlot1(slot1Configs);
- }
- break;
- case 2: {
- slot2Configs.GainSchedBehavior = value;
- configuration.withSlot2(slot2Configs);
- }
- break;
+
+ switch (slot) {
+ case 0:
+ {
+ slot0Configs.withGainSchedBehavior(value);
+ configuration.withSlot0(slot0Configs);
+ }
+ break;
+ case 1:
+ {
+ slot1Configs.withGainSchedBehavior(value);
+ configuration.withSlot1(slot1Configs);
+ }
+ break;
+ case 2:
+ {
+ slot2Configs.withGainSchedBehavior(value);
+ configuration.withSlot2(slot2Configs);
+ }
+ break;
}
return this;
@@ -242,7 +251,7 @@ public TalonFXConfig withGainSchedBehavior(GainSchedBehaviorValue value, double
// MOTOR OUTPUT CONFIGS
public TalonFXConfig withInvertedValue(InvertedValue invertedValue) {
- motorOutputConfigs.Inverted = invertedValue;
+ motorOutputConfigs.withInverted(invertedValue);
configuration.withMotorOutput(motorOutputConfigs);
@@ -250,15 +259,32 @@ public TalonFXConfig withInvertedValue(InvertedValue invertedValue) {
}
public TalonFXConfig withNeutralMode(NeutralModeValue neutralMode) {
- motorOutputConfigs.NeutralMode = neutralMode;
+ motorOutputConfigs.withNeutralMode(neutralMode);
configuration.withMotorOutput(motorOutputConfigs);
return this;
}
- public TalonFXConfig withVelocityTimeFilter(double filterInSeconds) {
- feedbackConfigs.withVelocityFilterTimeConstant(filterInSeconds);
+ /**
+ * Modifies this configuration's velocity filter's time constant.
+ *
+ * @param filterTime The configurable time constant in seconds of the Kalman velocity
+ * filter.
+ * @return Itself for easier method-chaining
+ */
+ public TalonFXConfig withVelocityTimeFilter(double filterTimeSeconds) {
+ return this.withVelocityTimeFilter(Seconds.of(filterTimeSeconds));
+ }
+
+ /**
+ * Modifies this configuration's velocity filter's time constant.
+ *
+ * @param filterTime The configurable time constant of the Kalman velocity filter.
+ * @return Itself for easier method-chaining
+ */
+ public TalonFXConfig withVelocityTimeFilter(Time filterTime) {
+ feedbackConfigs.withVelocityFilterTimeConstant(filterTime);
configuration.withFeedback(feedbackConfigs);
@@ -267,14 +293,48 @@ public TalonFXConfig withVelocityTimeFilter(double filterInSeconds) {
// RAMP RATE CONFIGS
- public TalonFXConfig withRampRate(double rampRate) {
- closedLoopRampsConfigs.DutyCycleClosedLoopRampPeriod = rampRate;
- closedLoopRampsConfigs.TorqueClosedLoopRampPeriod = rampRate;
- closedLoopRampsConfigs.VoltageClosedLoopRampPeriod = rampRate;
+ /**
+ * Modifies this configuration's open and closed loop ramp periods for the following control
+ * types:
+ *
+ *
+ * - DutyCycle
+ *
- TorqueCurrent
+ *
- Voltage
+ *
+ *
+ *
+ *
+ * @param rampRateSeconds Seconds for the motor to reach peak output from 0
+ * @return Itself for method-chaining
+ */
+ public TalonFXConfig withRampRate(double rampRateSeconds) {
+ return this.withRampRate(Seconds.of(rampRateSeconds));
+ }
- openLoopRampsConfigs.DutyCycleOpenLoopRampPeriod = rampRate;
- openLoopRampsConfigs.TorqueOpenLoopRampPeriod = rampRate;
- openLoopRampsConfigs.VoltageOpenLoopRampPeriod = rampRate;
+ /**
+ * Modifies this configuration's open and closed loop ramp periods for the following control
+ * types:
+ *
+ *
+ * - DutyCycle
+ *
- TorqueCurrent
+ *
- Voltage
+ *
+ *
+ *
+ *
+ * @param rampRateSeconds Time for the motor to reach peak output from 0
+ * @return Itself for easy method chaining
+ */
+ public TalonFXConfig withRampRate(Time rampRate) {
+ closedLoopRampsConfigs.withDutyCycleClosedLoopRampPeriod(rampRate);
+ closedLoopRampsConfigs.withTorqueClosedLoopRampPeriod(rampRate);
+ closedLoopRampsConfigs.withVoltageClosedLoopRampPeriod(rampRate);
+
+ openLoopRampsConfigs.withDutyCycleOpenLoopRampPeriod(rampRate);
+ openLoopRampsConfigs.withTorqueOpenLoopRampPeriod(rampRate);
+ openLoopRampsConfigs.withVoltageOpenLoopRampPeriod(rampRate);
configuration.withClosedLoopRamps(closedLoopRampsConfigs);
configuration.withOpenLoopRamps(openLoopRampsConfigs);
@@ -283,19 +343,62 @@ public TalonFXConfig withRampRate(double rampRate) {
}
// CURRENT LIMIT CONFIGS
+ /**
+ * Modifies this configuration's supply current lower limit.
+ *
+ * @param currentLowerLimit The amount of supply current in amperes allowed after the
+ * regular {@link CurrentLimitsConfigs#SupplyCurrentLimit} is active for longer than the
+ * time parameter.
+ * @param time The amount of time in seconds that the regular {@link
+ * CurrentLimitsConfigs#SupplyCurrentLimit} can be active before lowring it to the
+ * currentLowerLimit parameter.
+ * @return
+ */
+ public TalonFXConfig withLowerLimitSupplyCurrent(
+ double currentLowerLimitAmps, double timeSeconds) {
+ return this.withLowerLimitSupplyCurrent(
+ Amps.of(currentLowerLimitAmps), Seconds.of(timeSeconds));
+ }
- public TalonFXConfig withLowerLimitSupplyCurrent(double currentLowerLimitAmps, double time) {
- currentLimitsConfigs.SupplyCurrentLowerLimit = currentLowerLimitAmps;
- currentLimitsConfigs.SupplyCurrentLowerTime = time;
+ /**
+ * Modifies this configuration's supply current lower limit.
+ *
+ * @param currentLowerLimit The amount of supply current allowed after the regular {@link
+ * CurrentLimitsConfigs#SupplyCurrentLimit} is active for longer than the time
+ * parameter.
+ * @param time The amount of time that the regular {@link
+ * CurrentLimitsConfigs#SupplyCurrentLimit} can be active before lowring it to the
+ * currentLowerLimit parameter.
+ * @return
+ */
+ public TalonFXConfig withLowerLimitSupplyCurrent(Current currentLowerLimit, Time time) {
+ currentLimitsConfigs.withSupplyCurrentLowerLimit(currentLowerLimit);
+ currentLimitsConfigs.withSupplyCurrentLowerTime(time);
configuration.withCurrentLimits(currentLimitsConfigs);
return this;
}
- public TalonFXConfig withSupplyCurrentLimitAmps(double currentLimitAmps) {
- currentLimitsConfigs.SupplyCurrentLimit = currentLimitAmps;
- currentLimitsConfigs.SupplyCurrentLimitEnable = true;
+ /**
+ * Modifies this configuration's supply current limit and enables it.
+ *
+ * @param currentLimit Maximum allowed current in amperes drawn from the battery.
+ * @return Itself for easier method-chaining.
+ */
+ public TalonFXConfig withSupplyCurrentLimit(double currentLimitAmps) {
+ return this.withSupplyCurrentLimit(Amps.of(currentLimitAmps));
+ }
+
+ /**
+ * Modifies this configuration's supply current limit and enables it.
+ *
+ * @param currentLimit Maximum allowed current drawn from the battery.
+ * @return Itself for easier method-chaining.
+ */
+ public TalonFXConfig withSupplyCurrentLimit(Current currentLimit) {
+ currentLimitsConfigs.withSupplyCurrentLimit(currentLimit);
+ currentLimitsConfigs.withSupplyCurrentLimitEnable(true);
configuration.withCurrentLimits(currentLimitsConfigs);
@@ -303,16 +406,33 @@ public TalonFXConfig withSupplyCurrentLimitAmps(double currentLimitAmps) {
}
public TalonFXConfig withSupplyCurrentLimitEnabled(boolean enabled) {
- currentLimitsConfigs.SupplyCurrentLimitEnable = enabled;
+ currentLimitsConfigs.withSupplyCurrentLimitEnable(enabled);
configuration.withCurrentLimits(currentLimitsConfigs);
return this;
}
- public TalonFXConfig withStatorCurrentLimitAmps(double currentLimitAmps) {
- currentLimitsConfigs.StatorCurrentLimit = currentLimitAmps;
- currentLimitsConfigs.StatorCurrentLimitEnable = true;
+ /**
+ * Modifies this configuration's stator current limit and enables it.
+ *
+ * @param currentLimit Amount of current in amperes allowed in the motor (motoring and regen
+ * current).
+ * @return Itself for easier method chaining.
+ */
+ public TalonFXConfig withStatorCurrentLimit(double currentLimitAmps) {
+ return this.withStatorCurrentLimit(Amps.of(currentLimitAmps));
+ }
+
+ /**
+ * Modifies this configuration's stator current limit and enables it.
+ *
+ * @param currentLimit Amount of current allowed in the motor (motoring and regen current).
+ * @return Itself for easier method chaining.
+ */
+ public TalonFXConfig withStatorCurrentLimit(Current currentLimit) {
+ currentLimitsConfigs.withStatorCurrentLimit(currentLimit);
+ currentLimitsConfigs.withStatorCurrentLimitEnable(true);
configuration.withCurrentLimits(currentLimitsConfigs);
@@ -320,17 +440,50 @@ public TalonFXConfig withStatorCurrentLimitAmps(double currentLimitAmps) {
}
public TalonFXConfig withStatorCurrentLimitEnabled(boolean enabled) {
- currentLimitsConfigs.StatorCurrentLimitEnable = enabled;
+ currentLimitsConfigs.withStatorCurrentLimitEnable(enabled);
configuration.withCurrentLimits(currentLimitsConfigs);
return this;
}
- public TalonFXConfig withTorqueCurrentLimits(double peakForwardTorqueCurrent, double peakReverseTorqueCurrent, double neutralTolerance) {
- torqueCurrentConfigs.PeakForwardTorqueCurrent = peakForwardTorqueCurrent;
- torqueCurrentConfigs.PeakReverseTorqueCurrent = peakReverseTorqueCurrent;
- torqueCurrentConfigs.TorqueNeutralDeadband = neutralTolerance;
+ /**
+ * Modifies this configuration's torque current limits. Limits apply during torque current
+ * control modes.
+ *
+ * @param peakForwardTorqueCurrent Maximum forward torque current output in amperes.
+ * @param peakReverseTorqueCurrent Maximum reverse torque current output in amperes.
+ * @param neutralTolerance Current range in amperes where requested torque current will
+ * result in zero bridge output.
+ * @return Itself for easier method-chaining.
+ */
+ public TalonFXConfig withTorqueCurrentLimits(
+ double peakForwardTorqueCurrentAmps,
+ double peakReverseTorqueCurrentAmps,
+ double neutralToleranceAmps) {
+ return this.withTorqueCurrentLimits(
+ Amps.of(peakForwardTorqueCurrentAmps),
+ Amps.of(peakReverseTorqueCurrentAmps),
+ Amps.of(neutralToleranceAmps));
+ }
+
+ /**
+ * Modifies this configuration's torque current limits. Limits apply during torque current
+ * control modes.
+ *
+ * @param peakForwardTorqueCurrent Maximum forward torque current output.
+ * @param peakReverseTorqueCurrent Maximum reverse torque current output.
+ * @param neutralTolerance Current range where requested torque current will result in zero
+ * bridge output.
+ * @return Itself for easier method-chaining.
+ */
+ public TalonFXConfig withTorqueCurrentLimits(
+ Current peakForwardTorqueCurrent,
+ Current peakReverseTorqueCurrent,
+ Current neutralTolerance) {
+ torqueCurrentConfigs.withPeakForwardTorqueCurrent(peakForwardTorqueCurrent);
+ torqueCurrentConfigs.withPeakReverseTorqueCurrent(peakReverseTorqueCurrent);
+ torqueCurrentConfigs.withTorqueNeutralDeadband(neutralTolerance);
configuration.withTorqueCurrent(torqueCurrentConfigs);
@@ -339,9 +492,28 @@ public TalonFXConfig withTorqueCurrentLimits(double peakForwardTorqueCurrent, do
// VOLTAGE LIMIT CONFIGS
- public TalonFXConfig withVoltageLimits(double peakForwardVoltage, double peakReverseVoltage) {
- voltageConfigs.PeakForwardVoltage = peakForwardVoltage;
- voltageConfigs.PeakReverseVoltage = peakReverseVoltage;
+ /**
+ * Modifies this configuration's voltage limits. Limits apply during voltage control modes.
+ *
+ * @param peakForwardVoltage Maximum forward voltage output in volts.
+ * @param peakReverseVoltage Maximum reverse voltage output in volts.
+ * @return Itself for easier method chaining.
+ */
+ public TalonFXConfig withVoltageLimits(double peakForwardVolts, double peakReverseVolts) {
+ return this.withVoltageLimits(Volts.of(peakForwardVolts), Volts.of(peakReverseVolts));
+ }
+
+ /**
+ * Modifies this configuration's voltage limits. Limits apply during voltage control modes.
+ *
+ * @param peakForwardVoltage Maximum forward voltage output.
+ * @param peakReverseVoltage Maximum reverse voltage output.
+ * @return Itself for easier method chaining.
+ */
+ public TalonFXConfig withVoltageLimits(
+ Voltage peakForwardVoltage, Voltage peakReverseVoltage) {
+ voltageConfigs.withPeakForwardVoltage(peakForwardVoltage);
+ voltageConfigs.withPeakReverseVoltage(peakReverseVoltage);
configuration.withVoltage(voltageConfigs);
@@ -349,12 +521,51 @@ public TalonFXConfig withVoltageLimits(double peakForwardVoltage, double peakRev
}
// SOFTWARE LIMIT CONFIGS
+ /**
+ * Modifies this configuration's software limit switch.
+ *
+ * @param forwardEnable Whether to set the motor output to neutral if its position exceeds
+ * the forward threshold.
+ * @param reverseEnable Whether to set the motor output to neutral if its position exceeds
+ * the reverse threshold.
+ * @param forwardThreshold The threshold angle in rotations for the application of the
+ * forward limit.
+ * @param reverseThreshold The threshold angle in rotations for the application of the
+ * reverse limit.
+ * @return Itself for easier method-chaining.
+ */
+ public TalonFXConfig withSoftLimits(
+ boolean forwardEnable,
+ boolean reverseEnable,
+ double forwardThresholdRotations,
+ double reverseThresholdRotations) {
+ return this.withSoftLimits(
+ forwardEnable,
+ reverseEnable,
+ Rotations.of(forwardThresholdRotations),
+ Rotations.of(reverseThresholdRotations));
+ }
- public TalonFXConfig withSoftLimits(boolean forwardEnable, boolean reverseEnable, double forwardThreshold, double reverseThreshold) {
- softwareLimitSwitchConfigs.ForwardSoftLimitEnable = forwardEnable;
- softwareLimitSwitchConfigs.ReverseSoftLimitEnable = reverseEnable;
- softwareLimitSwitchConfigs.ForwardSoftLimitThreshold = forwardThreshold;
- softwareLimitSwitchConfigs.ReverseSoftLimitThreshold = reverseThreshold;
+ /**
+ * Modifies this configuration's software limit switch.
+ *
+ * @param forwardEnable Whether to set the motor output to neutral if its position exceeds
+ * the forward threshold.
+ * @param reverseEnable Whether to set the motor output to neutral if its position exceeds
+ * the reverse threshold.
+ * @param forwardThreshold The threshold angle for the application of the forward limit.
+ * @param reverseThreshold The threshold angle for the application of the reverse limit.
+ * @return Itself for easier method-chaining.
+ */
+ public TalonFXConfig withSoftLimits(
+ boolean forwardEnable,
+ boolean reverseEnable,
+ Angle forwardThreshold,
+ Angle reverseThreshold) {
+ softwareLimitSwitchConfigs.withForwardSoftLimitEnable(forwardEnable);
+ softwareLimitSwitchConfigs.withReverseSoftLimitEnable(reverseEnable);
+ softwareLimitSwitchConfigs.withForwardSoftLimitThreshold(forwardThreshold);
+ softwareLimitSwitchConfigs.withReverseSoftLimitThreshold(reverseThreshold);
configuration.withSoftwareLimitSwitch(softwareLimitSwitchConfigs);
@@ -362,10 +573,32 @@ public TalonFXConfig withSoftLimits(boolean forwardEnable, boolean reverseEnable
}
// MOTION MAGIC CONFIGS
+ /**
+ * Modifies this configuration's motion magic profile.
+ *
+ * @param maxVelocity Maximum/cruise velocity of the motion profile in rotations per second.
+ * @param maxAcceleration Maximum acceleration of the motion profile in rotations per second
+ * squared.
+ * @return Itself for method-chaining.
+ */
+ public TalonFXConfig withMotionProfile(
+ double maxVelocityRotPerSec, double maxAccelerationRotPerSecSquared) {
+ return this.withMotionProfile(
+ RotationsPerSecond.of(maxVelocityRotPerSec),
+ RotationsPerSecondPerSecond.of(maxAccelerationRotPerSecSquared));
+ }
- public TalonFXConfig withMotionProfile(double maxVelocity, double maxAcceleration) {
- motionMagicConfigs.MotionMagicCruiseVelocity = maxVelocity;
- motionMagicConfigs.MotionMagicAcceleration = maxAcceleration;
+ /**
+ * Modifies this configuration's motion magic profile.
+ *
+ * @param maxVelocity Maximum/cruise velocity of the motion profile.
+ * @param maxAcceleration Maximum acceleration of the motion profile.
+ * @return Itself for method-chaining.
+ */
+ public TalonFXConfig withMotionProfile(
+ AngularVelocity maxVelocity, AngularAcceleration maxAcceleration) {
+ motionMagicConfigs.withMotionMagicCruiseVelocity(maxVelocity);
+ motionMagicConfigs.withMotionMagicAcceleration(maxAcceleration);
configuration.withMotionMagic(motionMagicConfigs);
@@ -376,9 +609,9 @@ public TalonFXConfig withMotionProfile(double maxVelocity, double maxAcceleratio
public TalonFXConfig withRemoteSensor(
int ID, FeedbackSensorSourceValue source, double rotorToSensorRatio) {
- feedbackConfigs.FeedbackRemoteSensorID = ID;
- feedbackConfigs.FeedbackSensorSource = source;
- feedbackConfigs.RotorToSensorRatio = rotorToSensorRatio;
+ feedbackConfigs.withFeedbackRemoteSensorID(ID);
+ feedbackConfigs.withFeedbackSensorSource(source);
+ feedbackConfigs.withRotorToSensorRatio(rotorToSensorRatio);
configuration.withFeedback(feedbackConfigs);
@@ -386,7 +619,7 @@ public TalonFXConfig withRemoteSensor(
}
public TalonFXConfig withSensorToMechanismRatio(double sensorToMechanismRatio) {
- feedbackConfigs.SensorToMechanismRatio = sensorToMechanismRatio;
+ feedbackConfigs.withSensorToMechanismRatio(sensorToMechanismRatio);
configuration.withFeedback(feedbackConfigs);
diff --git a/src/main/java/com/stuypulse/robot/constants/Ports.java b/src/main/java/com/stuypulse/robot/constants/Ports.java
index 1a2106d..c53ccb2 100644
--- a/src/main/java/com/stuypulse/robot/constants/Ports.java
+++ b/src/main/java/com/stuypulse/robot/constants/Ports.java
@@ -2,11 +2,10 @@
/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
/* This work is licensed under the terms of the MIT license. */
/**************************************************************/
-
package com.stuypulse.robot.constants;
/** This file contains the different ports of motors, solenoids and sensors */
-public interface Ports {
+public class Ports {
public interface Gamepad {
int DRIVER = 0;
int OPERATOR = 1;
diff --git a/src/main/java/com/stuypulse/robot/constants/Settings.java b/src/main/java/com/stuypulse/robot/constants/Settings.java
index a1b4525..ad19904 100644
--- a/src/main/java/com/stuypulse/robot/constants/Settings.java
+++ b/src/main/java/com/stuypulse/robot/constants/Settings.java
@@ -2,14 +2,12 @@
/* Copyright (c) 2024 StuyPulse Robotics. All rights reserved.*/
/* This work is licensed under the terms of the MIT license. */
/**************************************************************/
-
package com.stuypulse.robot.constants;
-
-/*-
+/**
* File containing tunable settings for every subsystem on the robot.
*
- * We use DogLog's tunables in order to have tunable
- * values that we can edit on Shuffleboard.
+ * We use DogLog's tunables in order to have tunable values that we can edit from external
+ * dashboards.
*/
public interface Settings {}
diff --git a/vendordeps/AdvantageKit.json b/vendordeps/AdvantageKit.json
new file mode 100644
index 0000000..0573d11
--- /dev/null
+++ b/vendordeps/AdvantageKit.json
@@ -0,0 +1,35 @@
+{
+ "fileName": "AdvantageKit.json",
+ "name": "AdvantageKit",
+ "version": "27.0.0-alpha-4",
+ "uuid": "d820cc26-74e3-11ec-90d6-0242ac120003",
+ "wpilibYear": "2027_alpha5",
+ "mavenUrls": [
+ "https://frcmaven.wpi.org/artifactory/littletonrobotics-mvn-release/"
+ ],
+ "jsonUrl": "https://github.com/Mechanical-Advantage/AdvantageKit/releases/latest/download/AdvantageKit.json",
+ "javaDependencies": [
+ {
+ "groupId": "org.littletonrobotics.akit",
+ "artifactId": "akit-java",
+ "version": "27.0.0-alpha-4"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "org.littletonrobotics.akit",
+ "artifactId": "akit-wpilibio",
+ "version": "27.0.0-alpha-4",
+ "skipInvalidPlatforms": false,
+ "isJar": false,
+ "validPlatforms": [
+ "linuxsystemcore",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal",
+ "windowsx86-64"
+ ]
+ }
+ ],
+ "cppDependencies": []
+}
\ No newline at end of file
diff --git a/vendordeps/CommandsV3.json b/vendordeps/CommandsV3.json
new file mode 100644
index 0000000..cf494f9
--- /dev/null
+++ b/vendordeps/CommandsV3.json
@@ -0,0 +1,25 @@
+{
+ "fileName": "CommandsV3.json",
+ "name": "Commands v3",
+ "version": "1.0.0",
+ "uuid": "4decdc05-a056-46cf-9561-39449bbb0130",
+ "wpilibYear": "2027_alpha5",
+ "mavenUrls": [],
+ "jsonUrl": "",
+ "conflictsWith": [
+ {
+ "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
+ "errorMessage": "Users can not have both Commands v2 and Commands v3 vendordeps in their robot program.",
+ "offlineFileName": "CommandsV2.json"
+ }
+ ],
+ "javaDependencies": [
+ {
+ "groupId": "org.wpilib",
+ "artifactId": "commands3-java",
+ "version": "wpilib"
+ }
+ ],
+ "jniDependencies": [],
+ "cppDependencies": []
+}
\ No newline at end of file
diff --git a/vendordeps/DogLog.json b/vendordeps/DogLog.json
index 7201ed0..608dc30 100644
--- a/vendordeps/DogLog.json
+++ b/vendordeps/DogLog.json
@@ -3,11 +3,11 @@
{
"groupId": "com.github.jonahsnider",
"artifactId": "doglog",
- "version": "2026.5.0"
+ "version": "2027.1.0"
}
],
"fileName": "DogLog.json",
- "frcYear": "2026",
+ "wpilibYear": "2027_alpha5",
"jsonUrl": "https://doglog.dev/vendordep.json",
"name": "DogLog",
"jniDependencies": [],
@@ -15,6 +15,6 @@
"https://jitpack.io"
],
"cppDependencies": [],
- "version": "2026.5.0",
+ "version": "2027.1.0",
"uuid": "65592ce1-2251-4a31-8e4b-2df20dacebe4"
}
\ No newline at end of file
diff --git a/vendordeps/Phoenix6-26.50.0-alpha-1.json b/vendordeps/Phoenix6-26.50.0-alpha-1.json
new file mode 100644
index 0000000..f7db60a
--- /dev/null
+++ b/vendordeps/Phoenix6-26.50.0-alpha-1.json
@@ -0,0 +1,449 @@
+{
+ "fileName": "Phoenix6-26.50.0-alpha-1.json",
+ "name": "CTRE-Phoenix (v6)",
+ "version": "26.50.0-alpha-1",
+ "wpilibYear": "2027_alpha5",
+ "uuid": "e995de00-2c64-4df5-8831-c1441420ff19",
+ "mavenUrls": [
+ "https://maven.ctr-electronics.com/release/"
+ ],
+ "jsonUrl": "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/latest/Phoenix6-frc2027-latest.json",
+ "conflictsWith": [
+ {
+ "uuid": "e7900d8d-826f-4dca-a1ff-182f658e98af",
+ "errorMessage": "Users cannot have both the replay and regular Phoenix 6 vendordeps in their robot program.",
+ "offlineFileName": "Phoenix6-replay-frc2027-latest.json"
+ }
+ ],
+ "javaDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "wpiapi-java",
+ "version": "26.50.0-alpha-1"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "api-cpp",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "linuxsystemcore"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "tools",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "linuxsystemcore"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "api-cpp-sim",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "tools-sim",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonSRX",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simVictorSPX",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFX",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFXS",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANcoder",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProPigeon2",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANrange",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANdi",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANdle",
+ "version": "26.50.0-alpha-1",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "wpiapi-cpp",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_Phoenix6_WPI",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "linuxsystemcore"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "tools",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_PhoenixTools",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "linuxsystemcore"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "wpiapi-cpp-sim",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_Phoenix6_WPISim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "tools-sim",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_PhoenixTools_Sim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonSRX",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimTalonSRX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simVictorSPX",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimVictorSPX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimPigeonIMU",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFX",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProTalonFX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFXS",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProTalonFXS",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANcoder",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProCANcoder",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProPigeon2",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProPigeon2",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANrange",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProCANrange",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANdi",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProCANdi",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANdle",
+ "version": "26.50.0-alpha-1",
+ "libName": "CTRE_SimProCANdle",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxarm64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ }
+ ]
+}
\ No newline at end of file
From 3788b4e23e455abcf8f8aa360100de5a77a562ad Mon Sep 17 00:00:00 2001
From: hc-45 <223769218+hc-45@users.noreply.github.com>
Date: Wed, 29 Jul 2026 15:05:52 -0400
Subject: [PATCH 2/4] CHORE: change vendordep and gradle versions. Uses gradle
9.4.1
---
gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 48966 bytes
.../robot/commands/DoNothingCommand.java | 25 -
.../robot/commands/auton/DoNothingAuton.java | 22 -
vendordeps/PathplannerLib.json | 38 --
vendordeps/Phoenix6-frc2026-latest.json | 449 ------------------
vendordeps/WPILibNewCommands.json | 39 --
6 files changed, 573 deletions(-)
delete mode 100644 src/main/java/com/stuypulse/robot/commands/DoNothingCommand.java
delete mode 100644 src/main/java/com/stuypulse/robot/commands/auton/DoNothingAuton.java
delete mode 100644 vendordeps/PathplannerLib.json
delete mode 100644 vendordeps/Phoenix6-frc2026-latest.json
delete mode 100644 vendordeps/WPILibNewCommands.json
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index a4b76b9530d66f5e68d973ea569d8e19de379189..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644
GIT binary patch
delta 40682
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Ðt5p(LLtXn?pxm3OZHd|13r);5)1uCW40m{;j
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
A;{X5v
delta 35496
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