From 049c290eea59f52bbdc42fc77b515c2e416295dd Mon Sep 17 00:00:00 2001 From: Theta Back Date: Sun, 6 Sep 2026 17:56:23 -0400 Subject: [PATCH 1/8] (#1) Updated to wpilib 27 alpha in order to build --- .gitignore | 10 +- .vscode/launch.json | 8 +- .vscode/settings.json | 15 +- .wpilib/wpilib_preferences.json | 10 +- WPILib-License.md | 19 +- build.gradle | 209 ++------ gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 48966 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 15 +- gradlew.bat | 25 +- settings.gradle | 18 +- src/main/java/first/Main.java | 25 + src/main/java/frc/robot/Constants.java | 2 +- .../java/frc/robot/CoordinationLayer.java | 104 ++-- .../frc/robot/DependencyOrderedExecutor.java | 10 +- src/main/java/frc/robot/InitSubsystems.java | 4 +- src/main/java/frc/robot/Main.java | 5 +- src/main/java/frc/robot/Robot.java | 51 +- src/main/java/frc/robot/RobotContainer.java | 41 +- src/main/java/frc/robot/ShotCalculations.java | 45 +- src/main/java/frc/robot/auto/Auto.java | 2 +- src/main/java/frc/robot/auto/AutoAction.java | 2 +- src/main/java/frc/robot/auto/Autos.java | 8 +- .../coordinationLayer/ClimbHangAction.java | 4 +- .../coordinationLayer/ClimbSearchAction.java | 2 +- .../coordinationLayer/DeployIntakeAction.java | 4 +- .../auto/coordinationLayer/StartShooting.java | 4 +- .../auto/coordinationLayer/StopShooting.java | 4 +- .../coordinationLayer/StowIntakeAction.java | 4 +- .../frc/robot/auto/drive/AutoPilotAction.java | 4 +- .../auto/drive/FollowPathPlannerPath.java | 6 +- .../frc/robot/auto/drive/StopDriveAction.java | 2 +- .../auto/drive/XBasedAutoPilotAction.java | 2 +- .../frc/robot/auto/general/AutoReference.java | 2 +- .../java/frc/robot/auto/general/Deadline.java | 2 +- .../auto/general/NetworkConfigurableWait.java | 10 +- .../java/frc/robot/auto/general/Parallel.java | 4 +- .../java/frc/robot/auto/general/Print.java | 4 +- .../java/frc/robot/auto/general/Race.java | 4 +- .../java/frc/robot/auto/general/Sequence.java | 4 +- .../java/frc/robot/auto/general/Wait.java | 6 +- src/main/java/frc/robot/autogen/Dsl.java | 20 +- src/main/java/frc/robot/autogen/Field.java | 10 +- .../java/frc/robot/autogen/GenerateAutos.java | 4 +- .../frc/robot/commands/DriveCommands.java | 54 +-- .../AllianceBasedFieldConstants.java | 16 +- .../robot/constants/AprilTagConstants.java | 4 +- .../frc/robot/constants/ClimberConstants.java | 40 +- .../frc/robot/constants/FieldConstants.java | 8 +- .../constants/FieldLocationInstance.java | 2 +- .../frc/robot/constants/FieldLocations.java | 2 +- .../frc/robot/constants/HoodConstants.java | 44 +- .../frc/robot/constants/HopperConstants.java | 42 +- .../frc/robot/constants/IndexerConstants.java | 36 +- .../frc/robot/constants/IntakeConstants.java | 52 +- .../frc/robot/constants/JsonConstants.java | 18 +- .../robot/constants/ManualModeConstants.java | 6 +- .../java/frc/robot/constants/RobotInfo.java | 22 +- .../frc/robot/constants/ShooterConstants.java | 40 +- .../java/frc/robot/constants/ShotMaps.java | 26 +- .../robot/constants/StrategyConstants.java | 4 +- .../constants/TransferRollerConstants.java | 36 +- .../frc/robot/constants/TurretConstants.java | 32 +- .../frc/robot/constants/VisionConstants.java | 10 +- .../robot/constants/drive/DriveConstants.java | 24 +- .../robot/constants/drive/ModuleConfig.java | 4 +- .../drive/PhysicalDriveConstants.java | 22 +- .../frc/robot/coordination/MatchState.java | 39 +- .../frc/robot/generated/TunerConstants.java | 10 +- .../subsystems/climber/ClimberState.java | 4 +- .../subsystems/climber/ClimberSubsystem.java | 43 +- .../frc/robot/subsystems/drive/Drive.java | 133 +++--- .../subsystems/drive/DriveCoordinator.java | 14 +- .../drive/DriveCoordinatorCommands.java | 14 +- .../frc/robot/subsystems/drive/GyroIO.java | 2 +- .../robot/subsystems/drive/GyroIONavX.java | 4 +- .../robot/subsystems/drive/GyroIOPigeon2.java | 8 +- .../frc/robot/subsystems/drive/Module.java | 34 +- .../frc/robot/subsystems/drive/ModuleIO.java | 4 +- .../robot/subsystems/drive/ModuleIOSim.java | 43 +- .../subsystems/drive/ModuleIOTalonFX.java | 14 +- .../subsystems/drive/ModuleIOTalonFXS.java | 14 +- .../drive/PhoenixOdometryThread.java | 6 +- .../frc/robot/subsystems/hood/HoodState.java | 4 +- .../robot/subsystems/hood/HoodSubsystem.java | 50 +- .../subsystems/hopper/HopperSubsystem.java | 28 +- .../subsystems/indexer/IndexerSubsystem.java | 18 +- .../robot/subsystems/intake/IntakeState.java | 8 +- .../subsystems/intake/IntakeSubsystem.java | 30 +- .../subsystems/shooter/ShooterSubsystem.java | 41 +- .../TransferRollerSubsystem.java | 22 +- .../robot/subsystems/turret/TurretState.java | 6 +- .../subsystems/turret/TurretSubsystem.java | 70 +-- .../java/frc/robot/util/CommandState.java | 2 +- src/main/java/frc/robot/util/Elastic.java | 33 +- .../java/frc/robot/util/LocalADStarAK.java | 4 +- .../frc/robot/util/json/JSONAPTarget.java | 6 +- .../util/json/JSONMotionProfileConfig.java | 14 +- .../robot/util/littletonUtil/GeomUtil.java | 28 +- .../util/littletonUtil/PoseEstimator.java | 26 +- vendordeps/AdvantageKit.json | 68 +-- vendordeps/Autopilot.json | 20 - vendordeps/CommandsV2.json | 46 ++ vendordeps/PathplannerLib.json | 38 -- vendordeps/PathplannerLibSystemCoreAlpha.json | 37 ++ vendordeps/Phoenix6-26.1.2.json | 449 ------------------ vendordeps/Phoenix6-26.50.0-alpha-1.json | 449 ++++++++++++++++++ vendordeps/REVLib.json | 257 +++++----- vendordeps/WPILibNewCommands.json | 38 -- vendordeps/photonlib.json | 140 +++--- 110 files changed, 1729 insertions(+), 1869 deletions(-) create mode 100644 src/main/java/first/Main.java delete mode 100644 vendordeps/Autopilot.json create mode 100644 vendordeps/CommandsV2.json delete mode 100644 vendordeps/PathplannerLib.json create mode 100644 vendordeps/PathplannerLibSystemCoreAlpha.json delete mode 100644 vendordeps/Phoenix6-26.1.2.json create mode 100644 vendordeps/Phoenix6-26.50.0-alpha-1.json delete mode 100644 vendordeps/WPILibNewCommands.json diff --git a/.gitignore b/.gitignore index 38a40cca..34cbaac1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ # This gitignore has been specially created by the WPILib team. # If you remove items from this file, intellisense might break. -### Python ### -__pycache__/ -*.pyc - ### C++ ### # Prerequisites *.d @@ -174,7 +170,7 @@ out/ # Simulation GUI and other tools window save file networktables.json -simgui*.json +simgui.json *-window.json # Simulation data log directory @@ -187,5 +183,5 @@ ctre_sim/ /.cache compile_commands.json -# Version file -src/main/java/frc/robot/BuildConstants.java \ No newline at end of file +# Eclipse generated file for annotation processors +.factorypath diff --git a/.vscode/launch.json b/.vscode/launch.json index b8c19206..c9c9713d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,17 +1,21 @@ { + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { "type": "wpilib", "name": "WPILib Desktop Debug", "request": "launch", - "desktop": true + "desktop": true, }, { "type": "wpilib", "name": "WPILib roboRIO Debug", "request": "launch", - "desktop": false + "desktop": false, } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 1e73416d..6ea00dae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,15 +18,12 @@ { "name": "WPIlibUnitTests", "workingDirectory": "${workspaceFolder}/build/jni/release", - "vmargs": [ - "-Djava.library.path=${workspaceFolder}/build/jni/release" - ], + "vmargs": [ "-Djava.library.path=${workspaceFolder}/build/jni/release" ], "env": { - "LD_LIBRARY_PATH": "${workspaceFolder}/build/jni/release", + "LD_LIBRARY_PATH": "${workspaceFolder}/build/jni/release" , "DYLD_LIBRARY_PATH": "${workspaceFolder}/build/jni/release" } }, - null ], "java.test.defaultConfig": "WPIlibUnitTests", "spotlessGradle.format.enable": true, @@ -42,7 +39,7 @@ "org.mockito.Mockito.*", "org.mockito.ArgumentMatchers.*", "org.mockito.Answers.*", - "edu.wpi.first.units.Units.*" + "org.wpilib.units.Units.*" ], "java.completion.filteredTypes": [ "java.awt.*", @@ -58,9 +55,9 @@ "javax.swing.*", "javax.management.*", "javax.smartcardio.*", - "edu.wpi.first.math.proto.*", - "edu.wpi.first.math.**.proto.*", - "edu.wpi.first.math.**.struct.*" + "org.wpilib.math.proto.*", + "org.wpilib.math.**.proto.*", + "org.wpilib.math.**.struct.*", ], "java.dependency.enableDependencyCheckup": false, "editor.defaultFormatter": "richardwillis.vscode-spotless-gradle", diff --git a/.wpilib/wpilib_preferences.json b/.wpilib/wpilib_preferences.json index 9c99fd8c..ad433eca 100644 --- a/.wpilib/wpilib_preferences.json +++ b/.wpilib/wpilib_preferences.json @@ -1,6 +1,6 @@ { - "enableCppIntellisense": false, - "currentLanguage": "java", - "projectYear": "2026", - "teamNumber": 401 -} + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2027_alpha5", + "teamNumber": 401 +} \ No newline at end of file diff --git a/WPILib-License.md b/WPILib-License.md index 051080d8..eb3061b0 100644 --- a/WPILib-License.md +++ b/WPILib-License.md @@ -1,17 +1,16 @@ -Copyright (c) 2009-2025 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 modification, are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -- Neither the name of FIRST, WPILib, nor the names of other WPILib - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED diff --git a/build.gradle b/build.gradle index 0c44f574..1e9f37df 100644 --- a/build.gradle +++ b/build.gradle @@ -1,112 +1,78 @@ plugins { id "java" - id "edu.wpi.first.GradleRIO" version "2026.2.1" + id "org.wpilib.GradleRIO" version "2027.0.0-alpha-6" + id "com.gradleup.shadow" version "9.3.0" id "com.peterabeles.gversion" version "1.10" id "com.diffplug.spotless" version "8.1.0" } java { - sourceCompatibility = JavaVersion.VERSION_17 - targetCompatibility = JavaVersion.VERSION_17 + sourceCompatibility = JavaVersion.VERSION_25 + targetCompatibility = JavaVersion.VERSION_25 } repositories { + mavenLocal() mavenCentral() - // mavenLocal() } -def ROBOT_MAIN_CLASS = "frc.robot.Main" +def ROBOT_MAIN_CLASS = "first.Main" -// 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')) { - // 422 2025 arguments - // gcType = 'Other' - // jvmArgs.add("-XX:GCTimeRatio=5") - // jvmArgs.add("-XX:+UseG1GC") - // jvmArgs.add("-XX:MaxGCPauseMillis=20") - - // 401 arguments - jvmArgs.add("-XX:+UnlockExperimentalVMOptions") - jvmArgs.add("-XX:GCTimeRatio=5") - jvmArgs.add("-XX:+UseSerialGC") - jvmArgs.add("-XX:MaxGCPauseMillis=20") - - // The options below may improve performance, but should only be enabled on the RIO 2 - // - final MAX_JAVA_HEAP_SIZE_MB = 100; - jvmArgs.add("-Xmx" + MAX_JAVA_HEAP_SIZE_MB + "M") - jvmArgs.add("-Xms" + MAX_JAVA_HEAP_SIZE_MB + "M") - jvmArgs.add("-XX:+AlwaysPreTouch") - - // Enable VisualVM connection - // jvmArgs.add("-Dcom.sun.management.jmxremote=true") - // jvmArgs.add("-Dcom.sun.management.jmxremote.port=1198") - // jvmArgs.add("-Dcom.sun.management.jmxremote.local.only=false") - // jvmArgs.add("-Dcom.sun.management.jmxremote.ssl=false") - // jvmArgs.add("-Dcom.sun.management.jmxremote.authenticate=false") - // jvmArgs.add("-Djava.rmi.server.hostname=10.04.01.2") - - // Cause code hotspots to be compiled after 50 runs rather than the default of 1500 (C1) - // /10000 (C2). This option is potentially ignored anyway when tiered - // compilation is enabled. - // jvmArgs.add("-XX:CompileThreshold=50") + wpilibJava(getArtifactTypeClass('WPILibJavaArtifact')) { } // Static files artifact - frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) { + wpilibStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) { files = project.fileTree('src/main/deploy') - directory = '/home/lvuser/deploy' - // Change to true to delete files on roboRIO that no - // longer exist in deploy directory on roboRIO - deleteOldFiles = true + 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 all targets including JNI, which will drastically impact // performance. wpi.java.debugJni = false // Set this to true to enable desktop support. -def includeDesktopSupport = true - -// Configuration for AdvantageKit -task(replayWatch, type: JavaExec) { - mainClass = "org.littletonrobotics.junction.ReplayWatch" - classpath = sourceSets.main.runtimeClasspath -} +def includeDesktopSupport = false // Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. -// Also defines JUnit 4. +// 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) @@ -122,9 +88,11 @@ dependencies { def akitJson = new groovy.json.JsonSlurper().parseText(new File(projectDir.getAbsolutePath() + "/vendordeps/AdvantageKit.json").text) annotationProcessor "org.littletonrobotics.akit:akit-autolog:$akitJson.version" - def coppercoreVersion = "2026.2.23" + def coppercoreVersion = "2026.3.1" implementation "com.google.code.gson:gson:2.11.0" + implementation "io.avaje:avaje-jsonb:3.14" + annotationProcessor "io.avaje:avaje-jsonb-generator:3.14" implementation "io.github.team401.coppercore:controls:$coppercoreVersion" implementation "io.github.team401.coppercore:geometry:$coppercoreVersion" @@ -134,6 +102,7 @@ dependencies { implementation "io.github.team401.coppercore:vision:$coppercoreVersion" implementation "io.github.team401.coppercore:wpilib_interface:$coppercoreVersion" implementation "io.github.team401.coppercore:metadata:$coppercoreVersion" + implementation "com.github.therekrab:autopilot:1.7.0-alpha-7" } test { @@ -142,123 +111,27 @@ test { } // Simulation configuration (e.g. environment variables). -// -// The sim GUI is *disabled* by default to support running -// AdvantageKit log replay, which requires that all HAL -// sim extensions be disabled. -wpi.sim.addGui().defaultEnabled = false +wpi.sim.addGui().defaultEnabled = true wpi.sim.addDriverstation() -// 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) - } - } - from sourceSets.main.allSource - manifest edu.wpi.first.gradlerio.GradleRIOPlugin.javaManifest(ROBOT_MAIN_CLASS) +// 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 = jar -wpi.java.configureExecutableTasks(jar) +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' } - -// Create version file -project.compileJava.dependsOn(createVersionFile) -gversion { - srcDir = "src/main/java/" - classPackage = "frc.robot" - className = "BuildConstants" - dateFormat = "yyyy-MM-dd HH:mm:ss z" - timeZone = "America/New_York" - indent = " " -} - -// Create commit with working changes on event branches -task(eventDeploy) { - doLast { - if (project.gradle.startParameter.taskNames.any({ it.toLowerCase().contains("deploy") })) { - def branchPrefix = "2026-" - def branch = 'git branch --show-current'.execute().text.trim() - def commitMessage = "Update at '${new Date().toString()}'" - - if (branch.startsWith(branchPrefix)) { - exec { - workingDir(projectDir) - executable 'git' - args 'add', '-A' - } - exec { - workingDir(projectDir) - executable 'git' - args 'commit', '-m', commitMessage - ignoreExitValue = true - } - - println "Committed to branch: '$branch'" - println "Commit message: '$commitMessage'" - } else { - println "Not on an event branch, skipping commit" - } - } else { - println "Not running deploy task, skipping commit" - } - } -} -createVersionFile.dependsOn(eventDeploy) - -// Spotless formatting -project.compileJava.dependsOn(spotlessApply) -spotless { - java { - // Restrict formatting to files under the workspace 'src' directory. - // Using '.' can sometimes pick up files mounted from other filesystems - // (e.g. WSL mounts) which Spotless rejects. Targeting 'src' keeps the - // formatter inside the project directory. - target fileTree('src') { - include "**/*.java" - exclude "**/build/**", "**/build-*/**", "settings_gui/**" - } - toggleOffOn() - googleJavaFormat() - removeUnusedImports() - trimTrailingWhitespace() - endWithNewline() - } - groovyGradle { - target fileTree(".") { - include "**/*.gradle" - exclude "**/build/**", "**/build-*/**", "settings_gui/**" - } - greclipse() - leadingTabsToSpaces(4) - trimTrailingWhitespace() - endWithNewline() - } - json { - target fileTree(".") { - include "**/*.json" - exclude "**/build/**", "**/build-*/**", "elastic_layouts/*.json", "settings_gui/**", "auto_generator/**", "src/main/deploy/constants/comp/Autos.json" - } - gson().indentWithSpaces(2) - } - format "misc", { - target fileTree(".") { - include "**/*.md", "**/.gitignore" - exclude "**/build/**", "**/build-*/**", "settings_gui/**" - } - trimTrailingWhitespace() - leadingTabsToSpaces(2) - endWithNewline() - } -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..d997cfc60f4cff0e7451d19d49a82fa986695d07 100644 GIT binary patch delta 40682 zcmXVXQ(#@~_jHrSIk8TX#h6q_jr&!KZyHfgAhk~gL{kKw_qV9n@#EwH$Y|rhso2C9ZfaAn4kou(K2uE zNJCrjH8XL$UKL3PMJk+zhGkd;Sx7v9Q{3S&Pp>08h0u^ZE?>WU3u+ap)6!nMv)J5D zgE-0k3aKmy3uiMmu9NcR%a^t<;2ErM;00t!(DLe{4hn(+|6y_Sn#6p&I$H5@MHzNy z*@`t@mRXuv3!DkjK+6@m*A;{xwKFzmPGI1r<%i(!O`$K_01sei^%8hLawTr(B{}JdA`eIu5D0OP~v`EdG-dqkIqHl!loE;fc-AvmNnlFSNHm z=w?lbDVBtkUffL-HD?xi#8>>|!p|vh3`=_cSOWD%tidd7Bv#-KSwOv&At&9uEUfVb~$PxVB zf1T&9qi(5BxZ#-(t!r;3nkC{d4(ef~utTp7Qc03+60<_#q=vv7-r!mecz2#JcM$%I z|KBg$evua^1q+~RfYjC$F;p=1!(*sZEo=+Iv5xy`sa$Y>ItiE+kQ>&H%@9z&^d-zjvH;KOS zGj*%j=xt!6mL_AmOO4W0Zdl<_J_6Rpxa<^^H_=MBYxCpXK^KP$?aGhqn*AEGeCuu! ziq@ykFph^vM5YDJBTa)8mF`i0KXOv7Rr_jg-{?d8W|8FJhU?wNE)a()7{_od4=tj+ z70&4#UweQi8XX7ayNSjKVKQqoi0%CxYMAPC)YZ$eFfEM;BsE;`#uOpAVII$dOzG>h zh-Xdu1wQCLAY5|3awps{IuVg^wm*Fs7mHPWbZjH*GrCB|-uQJ{;wj~B%9`>Q?ds@D zAyvGRKl&5SE6aU8B+AJv`8=xH%)Q*hHqHB4J7LAsFHEX|wOW&QtRb@*3b?`21H>dU zF*v13%;;hWGPwQ`l4!jYVS&gerS?|nL%4nTYg2?{pw=KS%rs{W$v=;z=?N@OtK2es z9(Y;;J6D-B7r-RHpIP&^71vfgH}UwoCNcVn%_evfUIMy|d65 z`qI4-VyXV`B0j~j8%;Q(xgx!F9lj2>Wj3;{QdW9%K-H7zF2QkrY`;M4lZ@j&T}LKv z_Y1-t5LUR>F%9dTmVnP++s?L~=pRrgWHXnjl<{tq@z0Pjnvy~*AxvZ|gku1ch)Hw_ z-(!i0^SzVvhjB6hNXq6Ft|%P%8e<#Y`XSWq977W}cE@r9xMa?ya7^8yI$Z2FqJPAa z(gk~_0w5+89{t@PZmU3RhfF5^6JPW*ZwN9g%MXVJqI9#$xRL+|4*eM9( z?w=Kw)v}Y|N5_){CV>{=Lwc$6;HLxE%KDOll7tYluklyQAW$!*u zpdH*p7_90YJTaZlcuYez#c>=~gp-f<3f;srti|NrS97iyS(^2p38-4rIO9qb;ox4> zy=H%lFPv2!eNk3lRMUrp;?`QlzBVb=#Ta+$4@i#JA>2o42?WaE(Z+7_lEqrYG;*Kt zCN)}EaYX~eq^&4jQYmq8_+pK0^tq6@DV&MfqPmmpU~Z=@vt=B<%^YsErbs zkbZJ{hKw8X^89LyOOW@tG3;F+q*)rzoYaVLj?jI+)b?}jn;GSk_X#3D3n3CcXZo+| z7Uf7}b^ldeGdPfp0K7#^0jA0$2Q_KfI?idM3baft);OQodNb4)m$KWVa|x3u;HQ@S zy-^((3#mya4Rpv}8<>wD@mSR-c_O;XAo_xCr{(7DC$=laz}Kv1FGqBNgT4|uCBWu6 z`Dgt)4YcL|#R-B7*MQ&GqwY$)#>xNtvWC0tLfU+FC7)(LbDJY~vjvZa2&k1#zE?mb z+Wo@XNB?--VD4tVg2KUvw2IRva}Ylh?Wt9J^wuUIsMW!^KcK=o6UxiIHm69+cnP2j zw^VN%QVX|K)CI>B6C01!SgEa&=Mls*LQ!^dx|{hADLeNTT{zOT6cXnY$hgk5v0JKc z_fHr-1$K}pA}EF_n$Mm~Ko%uUj3m9xXtus(XvaAQ2M&ld&+9noyg=T!_8p`gbLFGG zb<9Zr(R!p$*8clMua}k>)LMsKEGZmJx56q!Az>Bby&nL0Slo7kEK;|3YKO4F#OGnZ z&?9+=B^L@IX?tfrRy=%FIi61s^Di5z*5Mv(tn6MV)bCNoteg$H=PhoB)cp|e zpbzA~ZCzQIW(j`_LCCYf0Y$8+d(k{|ePNMJ%A|HM?zZ{%3-X3WyXm=eCZ<=#5_z6NJ*#F^tE*S+lGmiq4qxoGIe+f4LHUxHH8QJUWTBN!6R}zuV0ZQSGFV5(&5VgI^ zJPt`Byb&y9vHWb1V0Mp33Yiu+3WY32#dUUvvtoJ=uhqj!oG!;tVc!*^1WtuxUrF>4 zVw}0G4A<^khRc@R+qC$tSF#_b+R9g_DRh>)c_?wm*UpKGP-{V;>lq_%V2dhl|Ga*` ztdy#zXo3Tx+Hu_WPWpxTt|_VDg_)XSy}ddY0UEMJQetv$Bv5r&jBNOR;2LAUNf+^^ z==&UbFYX*!cpKJ9aUymf=d6q>Rmk6I?30=asVrSGcosCj0`w@z&mSpGd%G2Na4xC2O)JcW$Jz3YKnbXb&H`jT{*lQ_|Z!V?U}oL_?K&6FEZVM(maI zzY}`*q-bL`ieIWIDdy|w#djw39KuPWg=co$*{ShV%JVicA8rw~X1>f;*1!C|p3So8Jp zSqC;kbaS$vtD|wCtpyYNNTEodk1ob#^xC;0Crbc7Ey%9VhKxf4YJy?y>c(a~01&hzr(8C_Alr zWP4DLKBT=#G!Lzy{lbWjzp+Og{4t!kvmQ*scf_U$-?LCStJ%Kc2?l}#!d}1#nHP-T zrF$#JofG3#jtB@3@+*!tr)M&dBh-g-5HLl7>GL@t;h|>Am=I|wNd~@z%kBu7jX=FU z7-Rw`WDc!eOjFU+>B>jY%{kAX9QDXcAPl{;4!g#rj6i!J!Fe=MO)6Pw%s&`H4N*XV>Wx z{x_RaYVb(gxVbf%!*0g1@t^_{ zB*yDzw2t*s=^Zjh`&s4nJyn`?#+p^?9!UbBgJF)G*86>w@Qt!tBi3f2BECkL!r6Hj9w-=wzaGgt)02MdLzZFPMcG%98qJLf6WbE#^UeyrvToj;ckqOsnZ zibp4RPa1F9qTaC+^)GsZO1SWXPzPS1nJc#JnxV5No_A?*{ZE&)q!&3ou%9D!x$LSY zC)=O61t$TVVZ$0)0;bg84}12Jg-Q2&8;6==r3nDbX4QPpRU z+U+P5=vte7w%*s<#O?QI@v9F%Rj=$A;^r&g=nk^v+U-vxYL6Y!XZ~iUe8xq#c>RL! z>s##60z2Q&WB-^Kb~$3hZbI-Yz&cYieUg@pKM4_K_HN>eZw@AMIaOOD*UXi}4_cI) zArthwdhH)Vwwvs)&h5Q^C5)8-jsKg;;yE_@z_-WmYLUM_`f!`lb~u0ID?d0wdF}|* z+U}4+4nDl9#ClW%M&4NTBls-LP zC>YB5m&I=!E*^YT1mk~s;}h_MIh!%pl>L`>=zcd8tEA-H5~}dm1fU~=bZqy1Ny{p# zGm?>hpwlg~w}w27qV8eTbWQ7$6wOh6)%f`Hqb}zUq8IPtVb(AkTg31x?MKY1kD>qI zx1@fB1}F07Uz=Rv^TL8j1wf3SOtROwdZ#6BhI0VQe;>Q!uh$jIbd7(8l=#pz0x)Qg zy-YS5$Csp1R()B>rGa)ElG;vfrF*jNW*bT##$Z77N}=z{FrM6{N1Y>ZT4 z@N6C8v+wI?U|vUj{Z-+3YWl*k46cb|TmzqiW)FpjCAN!>?)-|@ux{>3g5#2|m{nHQkClZfs)AH)z!{k^@>Lwq$869Oa*_8M%Sjg=NJ2E)$Y`%kl1esT#ysI}V#`SBefe)d25#uuUb zO!Jzat@u%uiw#Keo&c)F*0oyKs&3Kce3tD?H~qA4JB(ZoGb+++iK0+(jiVh*K?x>_ zzZ={vD~z>G41M#ynvS%*IT%Gz#nAyz1B{l=f9TehXVj|cJ_^LkRmsRsd80-dePm#S zk+-cxs)2yZH4##xz0_i$dufNQ;uw0dMJ07$YL=ACD+CHnHQHw`S* z%cXo%#JDt!2(k|H;xEh%qqR^T+oPXkk$<{jdj3mtBLDRV1-s>oYr@62fDl=PbeeNSFNn2}566YP9 znP?_tB$$dVCaHw?Td^g~nAOA4t*aT%;HH_5Szw zfxdgvufJkU3sXpÐt5p(LLtXn?pxm3OZHd|13r);5)1uCW40m{;j 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 A;{X5v delta 35496 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 34bd9ce9..42bb5ac9 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 1aa94a42..739907df 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/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/. @@ -84,7 +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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || 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 @@ -112,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. @@ -170,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" ) @@ -203,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 93e3f59f..c4bdd3ab 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,21 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 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 486702ac..e2626a81 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/java/first/Main.java b/src/main/java/first/Main.java new file mode 100644 index 00000000..8fd1dabb --- /dev/null +++ b/src/main/java/first/Main.java @@ -0,0 +1,25 @@ +// 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 first; + +import org.wpilib.framework.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(frc.robot.Robot.class); + } +} diff --git a/src/main/java/frc/robot/Constants.java b/src/main/java/frc/robot/Constants.java index c7eefb17..12a0e48c 100644 --- a/src/main/java/frc/robot/Constants.java +++ b/src/main/java/frc/robot/Constants.java @@ -7,7 +7,7 @@ package frc.robot; -import edu.wpi.first.wpilibj.RobotBase; +import org.wpilib.framework.RobotBase; /** * This class defines the runtime mode used by AdvantageKit. The mode is always "real" when running diff --git a/src/main/java/frc/robot/CoordinationLayer.java b/src/main/java/frc/robot/CoordinationLayer.java index 5c27951c..855be4a4 100644 --- a/src/main/java/frc/robot/CoordinationLayer.java +++ b/src/main/java/frc/robot/CoordinationLayer.java @@ -1,12 +1,12 @@ package frc.robot; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.MetersPerSecond; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.Seconds; import coppercore.geometry.EnhancedLine2d; import coppercore.geometry.Rectangle; @@ -19,27 +19,25 @@ import coppercore.wpilib_interface.controllers.Controller.Button; import coppercore.wpilib_interface.controllers.Controllers; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.math.MathUtil; -import edu.wpi.first.math.Vector; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.Alert; -import edu.wpi.first.wpilibj.Alert.AlertType; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj.event.EventLoop; -import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.button.Trigger; +import org.wpilib.math.linalg.Vector; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.filter.Debouncer.DebounceType; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Pose3d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Rotation3d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.geometry.Translation3d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.math.numbers.N3; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Time; +import org.wpilib.driverstation.Alert; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; +import org.wpilib.event.EventLoop; +import org.wpilib.command2.InstantCommand; +import org.wpilib.command2.button.Trigger; import frc.robot.DependencyOrderedExecutor.ActionKey; import frc.robot.ShotCalculations.MapBasedShotInfo; import frc.robot.ShotCalculations.ShotInfo; @@ -220,10 +218,10 @@ public enum PassGoalZone { // Logging private final Alert autonomyOverriddenAlert = new Alert( - "Autonomy level forced to manual due to disconnected coprocessor.", AlertType.kWarning); + "Autonomy level forced to manual due to disconnected coprocessor.", Alert.Level.MEDIUM); private final Alert visionDisconnectedAlert = - new Alert("Coprocessor disconnected", AlertType.kError); - private final Alert lowBatteryAlert = new Alert("Battery voltage low", AlertType.kWarning); + new Alert("Coprocessor disconnected", Alert.Level.HIGH); + private final Alert lowBatteryAlert = new Alert("Battery voltage low", Alert.Level.MEDIUM); // These constants will give a burst of two low battery voltage alerts, then one every second. private final TokenBucket lowBatteryAlertRateLimiter = new TokenBucket(200, 2); @@ -272,7 +270,7 @@ private void initializePositionBasedStrategyTriggers() { .onTrue( new InstantCommand( () -> { - if (DriverStation.isTeleopEnabled() + if (DriverStationBackend.isTeleopEnabled() && effectiveAutonomyLevel == AutonomyLevel.Smart) { shotMode = ShotMode.Hub; } @@ -280,7 +278,7 @@ private void initializePositionBasedStrategyTriggers() { .onFalse( new InstantCommand( () -> { - if (DriverStation.isTeleopEnabled() + if (DriverStationBackend.isTeleopEnabled() && effectiveAutonomyLevel == AutonomyLevel.Smart) { shotMode = ShotMode.Pass; } @@ -770,7 +768,7 @@ private void updateTurretDependencies(TurretSubsystem turret) { turret.setRobotHeading(drive.getRotation()); }); - boolean shouldStopForShootingDisabled = !shootingEnabled && !DriverStation.isTest(); + boolean shouldStopForShootingDisabled = !shootingEnabled && !DriverStationBackend.isUtility(); // Piggyback off of the intake stopping logic to save power during defense turret.setShouldStopMoving( @@ -813,7 +811,7 @@ private void updateIntakeDependencies(IntakeSubsystem intake) { * methods run. */ public void coordinateRobotActions() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); updateMatchState(); @@ -828,7 +826,7 @@ public void coordinateRobotActions() { if (isIntakeBoosted) { rollerSpeed = JsonConstants.intakeConstants.intakeTeleOpBoostedRollerSpeed; } - if (DriverStation.isAutonomous()) { + if (DriverStationBackend.isAutonomous()) { rollerSpeed = JsonConstants.intakeConstants.intakeAutoRollerSpeed; } intake.runRollers(rollerSpeed); @@ -865,7 +863,7 @@ public void coordinateRobotActions() { autonomyOverriddenAlert.set(effectiveAutonomyLevel != autonomyLevel); - if (DriverStation.isDisabled()) { + if (DriverStationBackend.isDisabled()) { boolean lowVoltage = JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( RobotController.getBatteryVoltage()); @@ -873,7 +871,7 @@ public void coordinateRobotActions() { lowBatteryAlertRateLimiter.increment(); if (lowVoltage && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) - && !(DriverStation.isFMSAttached())) { + && !(DriverStationBackend.isFMSAttached())) { Elastic.sendNotification( new Elastic.Notification( Elastic.NotificationLevel.WARNING, @@ -900,7 +898,7 @@ public void coordinateRobotActions() { drive .map(drive -> AllianceBasedFieldConstants.isInAllianceZone(drive.getPose())) .orElse(true) - || !DriverStation.isAutonomous(); + || !DriverStationBackend.isAutonomous(); // canPassPastNet is true when either: // - We are not in passing mode (so net isn't a concern) @@ -968,7 +966,7 @@ public void coordinateRobotActions() { transferRoller -> transferRoller.setTargetVelocity(RadiansPerSecond.zero())); } - long shotCalculationStartTimeUs = RobotController.getFPGATime(); + long shotCalculationStartTimeUs = RobotController.getTime(); // Select a passing target based on where we are if (drive @@ -994,7 +992,7 @@ public void coordinateRobotActions() { case Manual -> drive.map(this::aimForManualShot).orElse(false); }; } - long shotCalculationEndTimeUs = RobotController.getFPGATime(); + long shotCalculationEndTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput( "PeriodicTime/CoordinateRobotActions/shotCalculationMs", @@ -1025,7 +1023,7 @@ public void coordinateRobotActions() { shooter.ifPresent(shooter -> shooter.stopShooter()); } - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput( "PeriodicTime/CoordinateRobotActions/totalMs", (endTimeUs - startTimeUs) / 1000.0); @@ -1180,10 +1178,10 @@ private void aimForTestModeShot(Drive driveInstance) { private boolean shouldStowHoodBasedOnMovement(Drive drive, HoodSubsystem hood) { Pose2d robotPose = drive.getPose(); - ChassisSpeeds robotRelativeSpeeds = drive.getChassisSpeeds(); + ChassisVelocities robotRelativeSpeeds = drive.getChassisVelocities(); Translation2d fieldCentricSpeeds = new Translation2d( - robotRelativeSpeeds.vxMetersPerSecond, robotRelativeSpeeds.vyMetersPerSecond) + robotRelativeSpeeds.vx, robotRelativeSpeeds.vy) .rotateBy(robotPose.getRotation()); Translation2d shooterPose = @@ -1320,10 +1318,10 @@ private boolean runShotCalculatorWithDrive(Drive driveInstance) { ShotTarget target = getShotTargetFromPose(robotPose); - ChassisSpeeds robotRelativeSpeeds = driveInstance.getChassisSpeeds(); - ChassisSpeeds fieldCentricSpeeds = - ChassisSpeeds.fromRobotRelativeSpeeds( - driveInstance.getChassisSpeeds(), robotPose.getRotation()); + ChassisVelocities robotRelativeSpeeds = driveInstance.getChassisVelocities(); + ChassisVelocities fieldCentricSpeeds = + driveInstance.getChassisVelocities().toFieldRelative( + robotPose.getRotation()); /* Calculate the additional velocity caused by the rotation of the robot @@ -1344,7 +1342,7 @@ private boolean runShotCalculatorWithDrive(Drive driveInstance) { However, we can accomplish this math using Translation3d.cross instead: */ - double omega = robotRelativeSpeeds.omegaRadiansPerSecond; + double omega = robotRelativeSpeeds.omega; Translation3d omega_vec = new Translation3d(0, 0, omega); Translation3d robotToShooterTranslation = @@ -1362,8 +1360,8 @@ private boolean runShotCalculatorWithDrive(Drive driveInstance) { // in the air in the same way as the shooter curves on the ground. Translation2d shooterVelocity = new Translation2d( - fieldCentricSpeeds.vxMetersPerSecond + vRot.get(0), - fieldCentricSpeeds.vyMetersPerSecond + vRot.get(1)); + fieldCentricSpeeds.vx + vRot.get(0), + fieldCentricSpeeds.vy + vRot.get(1)); MapBasedShotInfo shot = ShotCalculations.calculateShotFromMap( @@ -1389,7 +1387,7 @@ private boolean runShotCalculatorWithDrive(Drive driveInstance) { /** Update the MatchState each periodic loop */ private void updateMatchState() { - if (DriverStation.isEnabled()) { + if (DriverStationBackend.isEnabled()) { matchState.enabledPeriodic(isWonAutoPressed.getAsBoolean(), isLostAutoPressed.getAsBoolean()); } else { matchState.disabledPeriodic(); @@ -1433,7 +1431,7 @@ private ShotInfo getCurrentShot(ShotInfo idealShot) { return new ShotInfo( hood.map(hood -> hood.getCurrentExitPitch().in(Radians)) .orElse( - MathUtil.clamp( + Math.clamp( idealShot.pitchRadians(), Math.toRadians(90 - JsonConstants.hoodConstants.maxHoodAngle.in(Degrees)), Math.toRadians(90 - JsonConstants.hoodConstants.minHoodAngle.in(Degrees)))), diff --git a/src/main/java/frc/robot/DependencyOrderedExecutor.java b/src/main/java/frc/robot/DependencyOrderedExecutor.java index 68f5e628..bcbcb55a 100644 --- a/src/main/java/frc/robot/DependencyOrderedExecutor.java +++ b/src/main/java/frc/robot/DependencyOrderedExecutor.java @@ -1,10 +1,10 @@ package frc.robot; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Seconds; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.TimedRobot; -import edu.wpi.first.wpilibj.Watchdog; +import org.wpilib.units.measure.Time; +import org.wpilib.framework.TimedRobot; +import org.wpilib.system.Watchdog; import java.io.PrintWriter; import java.util.HashMap; import java.util.List; @@ -53,7 +53,7 @@ private record NamedAction(String name, Runnable action) {} * period. */ public DependencyOrderedExecutor() { - watchdog = new Watchdog(Seconds.of(TimedRobot.kDefaultPeriod), () -> {}); + watchdog = new Watchdog(Seconds.of(TimedRobot.DEFAULT_PERIOD), () -> {}); } /** diff --git a/src/main/java/frc/robot/InitSubsystems.java b/src/main/java/frc/robot/InitSubsystems.java index a75726ef..becd9e00 100644 --- a/src/main/java/frc/robot/InitSubsystems.java +++ b/src/main/java/frc/robot/InitSubsystems.java @@ -13,8 +13,8 @@ import coppercore.wpilib_interface.subsystems.motors.talonfx.MotorIOTalonFX; import coppercore.wpilib_interface.subsystems.motors.talonfx.MotorIOTalonFXSim; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; -import edu.wpi.first.apriltag.AprilTagFieldLayout; -import edu.wpi.first.math.geometry.Transform3d; +import org.wpilib.vision.apriltag.AprilTagFieldLayout; +import org.wpilib.math.geometry.Transform3d; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.climber.ClimberSubsystem; import frc.robot.subsystems.drive.Drive; diff --git a/src/main/java/frc/robot/Main.java b/src/main/java/frc/robot/Main.java index 15d87e93..b5169129 100644 --- a/src/main/java/frc/robot/Main.java +++ b/src/main/java/frc/robot/Main.java @@ -7,7 +7,8 @@ package frc.robot; -import edu.wpi.first.wpilibj.RobotBase; +import org.wpilib.framework.RobotBase; +import org.wpilib.framework.TimedRobot; /** * Do NOT add any static variables to this class, or any initialization at all. Unless you know what @@ -23,6 +24,6 @@ private Main() {} *

If you change your main robot class, change the parameter type. */ public static void main(String... args) { - RobotBase.startRobot(Robot::new); + RobotBase.startRobot(TimedRobot.class); } } diff --git a/src/main/java/frc/robot/Robot.java b/src/main/java/frc/robot/Robot.java index 878ee0b9..f6c4b99d 100644 --- a/src/main/java/frc/robot/Robot.java +++ b/src/main/java/frc/robot/Robot.java @@ -11,15 +11,16 @@ import com.ctre.phoenix6.unmanaged.Unmanaged; import coppercore.monitors.TotalCurrentCalculator; import coppercore.wpilib_interface.subsystems.StatusSignalRefresher; -import edu.wpi.first.hal.AllianceStationID; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj.simulation.DriverStationSim; -import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; +import org.wpilib.hardware.hal.AllianceStationID; +import org.wpilib.hardware.hal.RobotMode; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; +import org.wpilib.simulation.DriverStationSim; +import org.wpilib.smartdashboard.SmartDashboard; +import org.wpilib.command2.Command; +import org.wpilib.command2.CommandScheduler; import frc.robot.constants.FeatureFlags; import frc.robot.constants.JsonConstants; import org.littletonrobotics.junction.LogFileUtil; @@ -88,7 +89,7 @@ public Robot() { // This got our mean cycle time (admittedly while not seeing any tags) down to 15ms } - DriverStation.silenceJoystickConnectionWarning(true); + DriverStationBackend.silenceJoystickConnectionWarning(true); // Start AdvantageKit logger Logger.start(); @@ -110,9 +111,9 @@ public void robotPeriodic() { // Threads.setCurrentThreadPriority(true, 99); // Refresh all status signals, must be done before any IOs run updateInputs - long refresherStartTimeUs = RobotController.getFPGATime(); + long refresherStartTimeUs = RobotController.getTime(); StatusSignalRefresher.refreshAll(); - long refresherEndTimeUs = RobotController.getFPGATime(); + long refresherEndTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput( "PeriodicTime/statusSignalRefresherMs", @@ -189,14 +190,14 @@ public void teleopPeriodic() {} /** This function is called once when test mode is enabled. */ @Override - public void testInit() { + public void utilityInit() { // Cancels all running commands at the start of test mode. CommandScheduler.getInstance().cancelAll(); } /** This function is called periodically during test mode. */ @Override - public void testPeriodic() {} + public void utilityPeriodic() {} /** This function is called once when the robot is first started up. */ @Override @@ -227,13 +228,13 @@ public AutoTestingSimulation(Robot robot) { // Initialize the auto testing simulation, set up network table listeners, etc. allianceStationChooser = new LoggedDashboardChooser<>(AUTO_TESTING_PREFIX + "AllianceStation"); - allianceStationChooser.addDefaultOption("Unknown", AllianceStationID.Unknown); - allianceStationChooser.addOption("Red 1", AllianceStationID.Red1); - allianceStationChooser.addOption("Red 2", AllianceStationID.Red2); - allianceStationChooser.addOption("Red 3", AllianceStationID.Red3); - allianceStationChooser.addOption("Blue 1", AllianceStationID.Blue1); - allianceStationChooser.addOption("Blue 2", AllianceStationID.Blue2); - allianceStationChooser.addOption("Blue 3", AllianceStationID.Blue3); + allianceStationChooser.addDefaultOption("Unknown", AllianceStationID.UNKNOWN); + allianceStationChooser.addOption("Red 1", AllianceStationID.RED_1); + allianceStationChooser.addOption("Red 2", AllianceStationID.RED_2); + allianceStationChooser.addOption("Red 3", AllianceStationID.RED_3); + allianceStationChooser.addOption("Blue 1", AllianceStationID.BLUE_1); + allianceStationChooser.addOption("Blue 2", AllianceStationID.BLUE_2); + allianceStationChooser.addOption("Blue 3", AllianceStationID.BLUE_3); SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "RobotEnabled", false); SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "AutoEnabled", false); @@ -255,13 +256,13 @@ public void update() { DriverStationSim.notifyNewData(); if (SmartDashboard.getBoolean(AUTO_TESTING_PREFIX + "StartAuto", false)) { - DriverStationSim.setAutonomous(true); + DriverStationSim.setRobotMode(RobotMode.AUTONOMOUS); DriverStationSim.setEnabled(true); SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "StartAuto", false); } if (SmartDashboard.getBoolean(AUTO_TESTING_PREFIX + "StopAuto", false)) { - DriverStationSim.setAutonomous(false); + DriverStationSim.setRobotMode(RobotMode.TELEOPERATED); DriverStationSim.setEnabled(false); SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "StopAuto", false); } @@ -279,8 +280,8 @@ public void update() { DriverStationSim.notifyNewData(); - SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "RobotEnabled", DriverStation.isEnabled()); - SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "AutoEnabled", DriverStation.isAutonomous()); + SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "RobotEnabled", DriverStationBackend.isEnabled()); + SmartDashboard.putBoolean(AUTO_TESTING_PREFIX + "AutoEnabled", DriverStationBackend.isAutonomous()); } } } diff --git a/src/main/java/frc/robot/RobotContainer.java b/src/main/java/frc/robot/RobotContainer.java index 35af51d8..224e0272 100644 --- a/src/main/java/frc/robot/RobotContainer.java +++ b/src/main/java/frc/robot/RobotContainer.java @@ -7,27 +7,26 @@ package frc.robot; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.Radians; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.Radians; import coppercore.metadata.CopperCoreMetadata; import coppercore.monitors.TotalCurrentCalculator; import coppercore.parameter_tools.json.JSONHandler; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.GenericHID; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj.XboxController; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.sysid.SysIdRoutine; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Pose3d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Rotation3d; +import org.wpilib.math.geometry.Transform3d; +import org.wpilib.math.geometry.Translation3d; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.Time; +import org.wpilib.driverstation.GenericHID; +import org.wpilib.system.RobotController; +import org.wpilib.command2.Command; +import org.wpilib.command2.CommandScheduler; +import org.wpilib.command2.sysid.SysIdRoutine; import frc.robot.Constants.Mode; import frc.robot.DependencyOrderedExecutor.ActionKey; import frc.robot.commands.DriveCommands; @@ -273,11 +272,11 @@ public void updateRobotModel() { */ void processHTTPRequests() { if (JsonConstants.featureFlags.useTuningServer) { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); jsonHandler.drainQueuedHttpActions(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/httpRequestsMs", (endTimeUs - startTimeUs) / 1000.0); } @@ -328,8 +327,8 @@ private void createAutoChooser(Drive drive) { /** * Use this method to define your button->command mappings. Buttons can be created by * instantiating a {@link GenericHID} or one of its subclasses ({@link - * edu.wpi.first.wpilibj.Joystick} or {@link XboxController}), and then passing it to a {@link - * edu.wpi.first.wpilibj2.command.button.JoystickButton}. + * org.wpilib.driverstation.Joystick} or {@link XboxController}), and then passing it to a {@link + * org.wpilib.command2.button.JoystickButton}. */ private void configureButtonBindings() { coordinationLayer.initBindings(); diff --git a/src/main/java/frc/robot/ShotCalculations.java b/src/main/java/frc/robot/ShotCalculations.java index f6cbdd0a..9ca13330 100644 --- a/src/main/java/frc/robot/ShotCalculations.java +++ b/src/main/java/frc/robot/ShotCalculations.java @@ -1,16 +1,15 @@ package frc.robot; -import static edu.wpi.first.units.Units.MetersPerSecond; -import static edu.wpi.first.units.Units.Seconds; - -import edu.wpi.first.math.MathUtil; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.math.geometry.Twist2d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.units.measure.LinearVelocity; +import static org.wpilib.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.Seconds; + +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.geometry.Translation3d; +import org.wpilib.math.geometry.Twist2d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.units.measure.LinearVelocity; import frc.robot.constants.AllianceBasedFieldConstants; import frc.robot.constants.FieldLocations; import frc.robot.constants.JsonConstants; @@ -34,14 +33,14 @@ public static record ShotInfo(double pitchRadians, double yawRadians, double tim public Translation3d[] projectMotion( double shooterVelocityMps, Translation3d initialPosition, - ChassisSpeeds fieldRelativeRobotVel, + ChassisVelocities fieldRelativeRobotVel, double pointsPerMeter) { List trajectory = new ArrayList<>(); double vxy = shooterVelocityMps * Math.cos(pitchRadians()); - double vx = vxy * Math.cos(yawRadians()) + fieldRelativeRobotVel.vxMetersPerSecond; - double vy = vxy * Math.sin(yawRadians()) + fieldRelativeRobotVel.vyMetersPerSecond; + double vx = vxy * Math.cos(yawRadians()) + fieldRelativeRobotVel.vx; + double vy = vxy * Math.sin(yawRadians()) + fieldRelativeRobotVel.vy; double vz = shooterVelocityMps * Math.sin(pitchRadians()); Translation3d position = initialPosition; @@ -130,7 +129,7 @@ public static Optional calculateStationaryShot( public static Optional calculateMovingShot( Translation3d shooterPosition, Translation3d goalPosition, - ChassisSpeeds robotVelocity, + ChassisVelocities robotVelocity, LinearVelocity shooterVelocity, ShotType shotType, Optional lastShot) { @@ -157,7 +156,7 @@ public static Optional calculateMovingShot( t = solution.timeSeconds; var vRobot = - new Translation3d(robotVelocity.vxMetersPerSecond, robotVelocity.vyMetersPerSecond, 0); + new Translation3d(robotVelocity.vx, robotVelocity.vy, 0); Translation3d effectiveGoal = goalPosition.minus(vRobot.times(t)); @@ -247,7 +246,7 @@ public record MapBasedShotInfo( */ public static MapBasedShotInfo calculateShotFromMap( Pose2d robotPose, - ChassisSpeeds robotRelativeChassisSpeeds, + ChassisVelocities robotRelativeChassisSpeeds, Translation2d fieldRelativeShooterVelocity, ShotTarget target) { Translation2d targetPosition = target.getTranslation(); @@ -255,11 +254,11 @@ public static MapBasedShotInfo calculateShotFromMap( double lookaheadTimeSeconds = JsonConstants.shotMaps.mechanismCompensationDelay.in(Seconds); Pose2d lookaheadPose = - robotPose.exp( + robotPose.plus( new Twist2d( - robotRelativeChassisSpeeds.vxMetersPerSecond * lookaheadTimeSeconds, - robotRelativeChassisSpeeds.vyMetersPerSecond * lookaheadTimeSeconds, - robotRelativeChassisSpeeds.omegaRadiansPerSecond * lookaheadTimeSeconds)); + robotRelativeChassisSpeeds.vx * lookaheadTimeSeconds, + robotRelativeChassisSpeeds.vy * lookaheadTimeSeconds, + robotRelativeChassisSpeeds.omega * lookaheadTimeSeconds).exp()); Logger.recordOutput("ShotCalculations/MapBased/lookaheadPose", lookaheadPose); @@ -290,7 +289,7 @@ public static MapBasedShotInfo calculateShotFromMap( if (distanceXYMeters < minDistanceMeters || distanceXYMeters > maxDistanceMeters) { // When clamping, the shot is no longer real. isShotReal = false; - distanceXYMeters = MathUtil.clamp(distanceXYMeters, minDistanceMeters, maxDistanceMeters); + distanceXYMeters = Math.clamp(distanceXYMeters, minDistanceMeters, maxDistanceMeters); } Logger.recordOutput("ShotCalculations/MapBased/ClampedShotDistanceMeters", distanceXYMeters); @@ -400,7 +399,7 @@ public static MapBasedShotInfo calculateShotFromMap( // When clamping, the shot is no longer real. isShotReal = false; virtualDistanceXYMeters = - MathUtil.clamp(virtualDistanceXYMeters, minDistanceMeters, maxDistanceMeters); + Math.clamp(virtualDistanceXYMeters, minDistanceMeters, maxDistanceMeters); } Logger.recordOutput( "ShotCalculations/MapBased/ClampedVirtualDistanceMeters", virtualDistanceXYMeters); diff --git a/src/main/java/frc/robot/auto/Auto.java b/src/main/java/frc/robot/auto/Auto.java index 6b5a6ff2..52bea6f6 100644 --- a/src/main/java/frc/robot/auto/Auto.java +++ b/src/main/java/frc/robot/auto/Auto.java @@ -1,6 +1,6 @@ package frc.robot.auto; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.auto.AutoAction.AutoActionContext; public class Auto { diff --git a/src/main/java/frc/robot/auto/AutoAction.java b/src/main/java/frc/robot/auto/AutoAction.java index bbbc4662..a7eaf7ef 100644 --- a/src/main/java/frc/robot/auto/AutoAction.java +++ b/src/main/java/frc/robot/auto/AutoAction.java @@ -2,7 +2,7 @@ import coppercore.parameter_tools.json.annotations.JsonSubtype; import coppercore.parameter_tools.json.annotations.JsonType; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.CoordinationLayer; import frc.robot.auto.coordinationLayer.ClimbHangAction; import frc.robot.auto.coordinationLayer.ClimbSearchAction; diff --git a/src/main/java/frc/robot/auto/Autos.java b/src/main/java/frc/robot/auto/Autos.java index cc3bb25d..51e661ff 100644 --- a/src/main/java/frc/robot/auto/Autos.java +++ b/src/main/java/frc/robot/auto/Autos.java @@ -4,10 +4,10 @@ import com.pathplanner.lib.util.FileVersionException; import com.pathplanner.lib.util.FlippingUtil; import coppercore.parameter_tools.json.annotations.JSONExclude; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.wpilibj.Filesystem; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.system.Filesystem; +import org.wpilib.command2.Command; import frc.robot.CoordinationLayer; import frc.robot.constants.FieldConstants; import frc.robot.subsystems.drive.DriveCoordinator; diff --git a/src/main/java/frc/robot/auto/coordinationLayer/ClimbHangAction.java b/src/main/java/frc/robot/auto/coordinationLayer/ClimbHangAction.java index 8c6df7bd..6a955c34 100644 --- a/src/main/java/frc/robot/auto/coordinationLayer/ClimbHangAction.java +++ b/src/main/java/frc/robot/auto/coordinationLayer/ClimbHangAction.java @@ -1,7 +1,7 @@ package frc.robot.auto.coordinationLayer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import frc.robot.auto.AutoAction; public class ClimbHangAction extends AutoAction { diff --git a/src/main/java/frc/robot/auto/coordinationLayer/ClimbSearchAction.java b/src/main/java/frc/robot/auto/coordinationLayer/ClimbSearchAction.java index 01e95860..4b078135 100644 --- a/src/main/java/frc/robot/auto/coordinationLayer/ClimbSearchAction.java +++ b/src/main/java/frc/robot/auto/coordinationLayer/ClimbSearchAction.java @@ -1,6 +1,6 @@ package frc.robot.auto.coordinationLayer; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.auto.AutoAction; public class ClimbSearchAction extends AutoAction { diff --git a/src/main/java/frc/robot/auto/coordinationLayer/DeployIntakeAction.java b/src/main/java/frc/robot/auto/coordinationLayer/DeployIntakeAction.java index 8df640ed..868ec98b 100644 --- a/src/main/java/frc/robot/auto/coordinationLayer/DeployIntakeAction.java +++ b/src/main/java/frc/robot/auto/coordinationLayer/DeployIntakeAction.java @@ -1,7 +1,7 @@ package frc.robot.auto.coordinationLayer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import frc.robot.auto.AutoAction; public class DeployIntakeAction extends AutoAction { diff --git a/src/main/java/frc/robot/auto/coordinationLayer/StartShooting.java b/src/main/java/frc/robot/auto/coordinationLayer/StartShooting.java index d445e529..9e747b2b 100644 --- a/src/main/java/frc/robot/auto/coordinationLayer/StartShooting.java +++ b/src/main/java/frc/robot/auto/coordinationLayer/StartShooting.java @@ -1,7 +1,7 @@ package frc.robot.auto.coordinationLayer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import frc.robot.auto.AutoAction; public class StartShooting extends AutoAction { diff --git a/src/main/java/frc/robot/auto/coordinationLayer/StopShooting.java b/src/main/java/frc/robot/auto/coordinationLayer/StopShooting.java index b87a3a91..1de727d7 100644 --- a/src/main/java/frc/robot/auto/coordinationLayer/StopShooting.java +++ b/src/main/java/frc/robot/auto/coordinationLayer/StopShooting.java @@ -1,7 +1,7 @@ package frc.robot.auto.coordinationLayer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import frc.robot.auto.AutoAction; public class StopShooting extends AutoAction { diff --git a/src/main/java/frc/robot/auto/coordinationLayer/StowIntakeAction.java b/src/main/java/frc/robot/auto/coordinationLayer/StowIntakeAction.java index 8575968d..b7daec7a 100644 --- a/src/main/java/frc/robot/auto/coordinationLayer/StowIntakeAction.java +++ b/src/main/java/frc/robot/auto/coordinationLayer/StowIntakeAction.java @@ -1,7 +1,7 @@ package frc.robot.auto.coordinationLayer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import frc.robot.auto.AutoAction; public class StowIntakeAction extends AutoAction { diff --git a/src/main/java/frc/robot/auto/drive/AutoPilotAction.java b/src/main/java/frc/robot/auto/drive/AutoPilotAction.java index d0a95526..c4365341 100644 --- a/src/main/java/frc/robot/auto/drive/AutoPilotAction.java +++ b/src/main/java/frc/robot/auto/drive/AutoPilotAction.java @@ -5,8 +5,8 @@ import com.therekrab.autopilot.APTarget; import com.therekrab.autopilot.Autopilot; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.controller.PIDController; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.math.controller.PIDController; +import org.wpilib.command2.Command; import frc.robot.auto.Autos; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.drive.DriveCoordinatorCommands; diff --git a/src/main/java/frc/robot/auto/drive/FollowPathPlannerPath.java b/src/main/java/frc/robot/auto/drive/FollowPathPlannerPath.java index 87a5bed5..aaa3e50d 100644 --- a/src/main/java/frc/robot/auto/drive/FollowPathPlannerPath.java +++ b/src/main/java/frc/robot/auto/drive/FollowPathPlannerPath.java @@ -5,7 +5,7 @@ import com.pathplanner.lib.config.RobotConfig; import com.pathplanner.lib.controllers.PPHolonomicDriveController; import com.pathplanner.lib.controllers.PathFollowingController; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.subsystems.drive.DriveCoordinatorCommands; import java.io.IOException; import java.util.function.BooleanSupplier; @@ -49,8 +49,8 @@ public Command toCommand(AutoActionContext context) { new FollowPathCommand( path, drive::getPose, - drive::getChassisSpeeds, - (speeds, feedforwards) -> drive.setGoalSpeeds(speeds, false), + drive::getChassisVelocities, + (speeds, feedforwards) -> drive.setGoalVelocities(speeds, false), controller, config, FALSE)); diff --git a/src/main/java/frc/robot/auto/drive/StopDriveAction.java b/src/main/java/frc/robot/auto/drive/StopDriveAction.java index 6bdbabd9..9fa27e0a 100644 --- a/src/main/java/frc/robot/auto/drive/StopDriveAction.java +++ b/src/main/java/frc/robot/auto/drive/StopDriveAction.java @@ -1,6 +1,6 @@ package frc.robot.auto.drive; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.subsystems.drive.DriveCoordinatorCommands; public class StopDriveAction extends DriveAutoAction { diff --git a/src/main/java/frc/robot/auto/drive/XBasedAutoPilotAction.java b/src/main/java/frc/robot/auto/drive/XBasedAutoPilotAction.java index c5d726ce..53183ec4 100644 --- a/src/main/java/frc/robot/auto/drive/XBasedAutoPilotAction.java +++ b/src/main/java/frc/robot/auto/drive/XBasedAutoPilotAction.java @@ -5,7 +5,7 @@ import com.therekrab.autopilot.APTarget; import com.therekrab.autopilot.Autopilot; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.subsystems.drive.DriveCoordinatorCommands; public class XBasedAutoPilotAction extends AutoPilotAction { diff --git a/src/main/java/frc/robot/auto/general/AutoReference.java b/src/main/java/frc/robot/auto/general/AutoReference.java index efad573b..8c0e4b2b 100644 --- a/src/main/java/frc/robot/auto/general/AutoReference.java +++ b/src/main/java/frc/robot/auto/general/AutoReference.java @@ -1,6 +1,6 @@ package frc.robot.auto.general; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.auto.AutoAction; public class AutoReference extends AutoAction { diff --git a/src/main/java/frc/robot/auto/general/Deadline.java b/src/main/java/frc/robot/auto/general/Deadline.java index 09da4111..1a45eaa9 100644 --- a/src/main/java/frc/robot/auto/general/Deadline.java +++ b/src/main/java/frc/robot/auto/general/Deadline.java @@ -1,6 +1,6 @@ package frc.robot.auto.general; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; import frc.robot.auto.AutoAction; import java.util.Objects; import java.util.stream.Stream; diff --git a/src/main/java/frc/robot/auto/general/NetworkConfigurableWait.java b/src/main/java/frc/robot/auto/general/NetworkConfigurableWait.java index 24654a61..53b42d72 100644 --- a/src/main/java/frc/robot/auto/general/NetworkConfigurableWait.java +++ b/src/main/java/frc/robot/auto/general/NetworkConfigurableWait.java @@ -1,13 +1,13 @@ package frc.robot.auto.general; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Seconds; import coppercore.parameter_tools.json.annotations.AfterJsonLoad; import coppercore.parameter_tools.json.annotations.JSONExclude; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.DeferredCommand; -import edu.wpi.first.wpilibj2.command.WaitCommand; +import org.wpilib.units.measure.Time; +import org.wpilib.command2.Command; +import org.wpilib.command2.DeferredCommand; +import org.wpilib.command2.WaitCommand; import frc.robot.auto.AutoAction; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/frc/robot/auto/general/Parallel.java b/src/main/java/frc/robot/auto/general/Parallel.java index 17b672bb..771ad05c 100644 --- a/src/main/java/frc/robot/auto/general/Parallel.java +++ b/src/main/java/frc/robot/auto/general/Parallel.java @@ -1,7 +1,7 @@ package frc.robot.auto.general; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; +import org.wpilib.command2.Command; +import org.wpilib.command2.ParallelCommandGroup; import frc.robot.auto.AutoAction; import java.util.List; import java.util.Objects; diff --git a/src/main/java/frc/robot/auto/general/Print.java b/src/main/java/frc/robot/auto/general/Print.java index 27817f1c..c088ffdd 100644 --- a/src/main/java/frc/robot/auto/general/Print.java +++ b/src/main/java/frc/robot/auto/general/Print.java @@ -1,7 +1,7 @@ package frc.robot.auto.general; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import frc.robot.auto.AutoAction; // This will allow us to print messages to the console during auto to help with debugging diff --git a/src/main/java/frc/robot/auto/general/Race.java b/src/main/java/frc/robot/auto/general/Race.java index 77e0331d..9b297dc7 100644 --- a/src/main/java/frc/robot/auto/general/Race.java +++ b/src/main/java/frc/robot/auto/general/Race.java @@ -1,7 +1,7 @@ package frc.robot.auto.general; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.ParallelRaceGroup; +import org.wpilib.command2.Command; +import org.wpilib.command2.ParallelRaceGroup; import frc.robot.auto.AutoAction; import java.util.List; import java.util.Objects; diff --git a/src/main/java/frc/robot/auto/general/Sequence.java b/src/main/java/frc/robot/auto/general/Sequence.java index baa9e762..3959afad 100644 --- a/src/main/java/frc/robot/auto/general/Sequence.java +++ b/src/main/java/frc/robot/auto/general/Sequence.java @@ -1,7 +1,7 @@ package frc.robot.auto.general; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; +import org.wpilib.command2.Command; +import org.wpilib.command2.SequentialCommandGroup; import frc.robot.auto.AutoAction; import java.util.List; import java.util.Objects; diff --git a/src/main/java/frc/robot/auto/general/Wait.java b/src/main/java/frc/robot/auto/general/Wait.java index 6153d86b..ec789b0d 100644 --- a/src/main/java/frc/robot/auto/general/Wait.java +++ b/src/main/java/frc/robot/auto/general/Wait.java @@ -1,8 +1,8 @@ package frc.robot.auto.general; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.WaitCommand; +import org.wpilib.units.measure.Time; +import org.wpilib.command2.Command; +import org.wpilib.command2.WaitCommand; import frc.robot.auto.AutoAction; public class Wait extends AutoAction { diff --git a/src/main/java/frc/robot/autogen/Dsl.java b/src/main/java/frc/robot/autogen/Dsl.java index 28a05a00..28d5f3d7 100644 --- a/src/main/java/frc/robot/autogen/Dsl.java +++ b/src/main/java/frc/robot/autogen/Dsl.java @@ -1,20 +1,20 @@ package frc.robot.autogen; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.Seconds; import com.therekrab.autopilot.APConstraints; import com.therekrab.autopilot.APProfile; import com.therekrab.autopilot.APTarget; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Transform2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Time; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Transform2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.Time; import frc.robot.auto.AutoAction; import frc.robot.auto.coordinationLayer.ClimbHangAction; import frc.robot.auto.coordinationLayer.ClimbSearchAction; diff --git a/src/main/java/frc/robot/autogen/Field.java b/src/main/java/frc/robot/autogen/Field.java index 0bb07462..bd1e96c9 100644 --- a/src/main/java/frc/robot/autogen/Field.java +++ b/src/main/java/frc/robot/autogen/Field.java @@ -1,10 +1,10 @@ package frc.robot.autogen; -import edu.wpi.first.hal.HAL; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Transform2d; -import edu.wpi.first.math.geometry.Translation2d; +import org.wpilib.hardware.hal.HAL; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Transform2d; +import org.wpilib.math.geometry.Translation2d; import frc.robot.constants.FieldConstants; import frc.robot.constants.JsonConstants; diff --git a/src/main/java/frc/robot/autogen/GenerateAutos.java b/src/main/java/frc/robot/autogen/GenerateAutos.java index 5c9ae57d..ade6401f 100644 --- a/src/main/java/frc/robot/autogen/GenerateAutos.java +++ b/src/main/java/frc/robot/autogen/GenerateAutos.java @@ -27,8 +27,8 @@ import coppercore.parameter_tools.json.JSONSyncConfig; import coppercore.parameter_tools.json.JSONSyncConfigBuilder; import coppercore.parameter_tools.json.helpers.JSONConverter; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; import frc.robot.auto.Auto; import frc.robot.auto.AutoAction; import frc.robot.auto.Autos; diff --git a/src/main/java/frc/robot/commands/DriveCommands.java b/src/main/java/frc/robot/commands/DriveCommands.java index 80b02f14..816c4a65 100644 --- a/src/main/java/frc/robot/commands/DriveCommands.java +++ b/src/main/java/frc/robot/commands/DriveCommands.java @@ -7,21 +7,21 @@ package frc.robot.commands; -import edu.wpi.first.math.MathUtil; -import edu.wpi.first.math.controller.ProfiledPIDController; -import edu.wpi.first.math.filter.SlewRateLimiter; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Transform2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.math.trajectory.TrapezoidProfile; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.DriverStation.Alliance; -import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.Commands; +import org.wpilib.math.util.MathUtil; +import org.wpilib.math.controller.ProfiledPIDController; +import org.wpilib.math.filter.SlewRateLimiter; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Transform2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.math.trajectory.TrapezoidProfile; +import org.wpilib.math.util.Units; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.driverstation.Alliance; +import org.wpilib.system.Timer; +import org.wpilib.command2.Command; +import org.wpilib.command2.Commands; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.drive.Drive; import java.text.DecimalFormat; @@ -79,17 +79,16 @@ public static Command joystickDrive( omega = Math.copySign(omega * omega, omega); // Convert to field relative speeds & send command - ChassisSpeeds speeds = - new ChassisSpeeds( + ChassisVelocities speeds = + new ChassisVelocities( linearVelocity.getX() * drive.getMaxLinearSpeedMetersPerSec(), linearVelocity.getY() * drive.getMaxLinearSpeedMetersPerSec(), omega * drive.getMaxAngularSpeedRadPerSec()); boolean isFlipped = - DriverStation.getAlliance().isPresent() - && DriverStation.getAlliance().get() == Alliance.Red; + DriverStationBackend.getAlliance().isPresent() + && DriverStationBackend.getAlliance().get() == Alliance.RED; drive.runVelocity( - ChassisSpeeds.fromFieldRelativeSpeeds( - speeds, + speeds.toRobotRelative( isFlipped ? drive.getRotation().plus(new Rotation2d(Math.PI)) : drive.getRotation())); @@ -130,17 +129,16 @@ public static Command joystickDriveAtAngle( drive.getRotation().getRadians(), rotationSupplier.get().getRadians()); // Convert to field relative speeds & send command - ChassisSpeeds speeds = - new ChassisSpeeds( + ChassisVelocities speeds = + new ChassisVelocities( linearVelocity.getX() * drive.getMaxLinearSpeedMetersPerSec(), linearVelocity.getY() * drive.getMaxLinearSpeedMetersPerSec(), omega); boolean isFlipped = - DriverStation.getAlliance().isPresent() - && DriverStation.getAlliance().get() == Alliance.Red; + DriverStationBackend.getAlliance().isPresent() + && DriverStationBackend.getAlliance().get() == Alliance.RED; drive.runVelocity( - ChassisSpeeds.fromFieldRelativeSpeeds( - speeds, + speeds.toRobotRelative( isFlipped ? drive.getRotation().plus(new Rotation2d(Math.PI)) : drive.getRotation())); @@ -232,7 +230,7 @@ public static Command wheelRadiusCharacterization(Drive drive) { Commands.run( () -> { double speed = limiter.calculate(WHEEL_RADIUS_MAX_VELOCITY); - drive.runVelocity(new ChassisSpeeds(0.0, 0.0, speed)); + drive.runVelocity(new ChassisVelocities(0.0, 0.0, speed)); }, drive)), diff --git a/src/main/java/frc/robot/constants/AllianceBasedFieldConstants.java b/src/main/java/frc/robot/constants/AllianceBasedFieldConstants.java index 3926253f..91d5cda7 100644 --- a/src/main/java/frc/robot/constants/AllianceBasedFieldConstants.java +++ b/src/main/java/frc/robot/constants/AllianceBasedFieldConstants.java @@ -2,10 +2,10 @@ import coppercore.wpilib_interface.alliance_util.AllianceUtil; import coppercore.wpilib_interface.alliance_util.AllianceUtil.AllianceBasedValue; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.wpilibj.DriverStation.Alliance; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.geometry.Translation3d; +import org.wpilib.driverstation.Alliance; /** * The AllianceBasedFieldConstants class provides methods for getting relevant field locations from @@ -36,8 +36,8 @@ public static final boolean isInAllianceZone(Pose2d robotPose) { Alliance alliance = AllianceUtil.getAlliance(); return switch (alliance) { - case Red -> robotPose.getX() > FieldConstants.LinesVertical.oppAllianceZone(); - case Blue -> robotPose.getX() < FieldConstants.LinesVertical.allianceZone(); + case RED -> robotPose.getX() > FieldConstants.LinesVertical.oppAllianceZone(); + case BLUE -> robotPose.getX() < FieldConstants.LinesVertical.allianceZone(); }; } @@ -52,8 +52,8 @@ public static final boolean isInOppAllianceZone(Pose2d robotPose) { Alliance alliance = AllianceUtil.getAlliance(); return switch (alliance) { - case Red -> robotPose.getX() < FieldConstants.LinesVertical.allianceZone(); - case Blue -> robotPose.getX() > FieldConstants.LinesVertical.oppAllianceZone(); + case RED -> robotPose.getX() < FieldConstants.LinesVertical.allianceZone(); + case BLUE -> robotPose.getX() > FieldConstants.LinesVertical.oppAllianceZone(); }; } } diff --git a/src/main/java/frc/robot/constants/AprilTagConstants.java b/src/main/java/frc/robot/constants/AprilTagConstants.java index 65299861..c5258f36 100644 --- a/src/main/java/frc/robot/constants/AprilTagConstants.java +++ b/src/main/java/frc/robot/constants/AprilTagConstants.java @@ -1,8 +1,8 @@ package frc.robot.constants; import coppercore.parameter_tools.json.annotations.JSONExclude; -import edu.wpi.first.apriltag.AprilTagFieldLayout; -import edu.wpi.first.wpilibj.Filesystem; +import org.wpilib.vision.apriltag.AprilTagFieldLayout; +import org.wpilib.system.Filesystem; import java.io.IOException; import java.nio.file.Path; diff --git a/src/main/java/frc/robot/constants/ClimberConstants.java b/src/main/java/frc/robot/constants/ClimberConstants.java index 9d5a6c3d..1acf313e 100644 --- a/src/main/java/frc/robot/constants/ClimberConstants.java +++ b/src/main/java/frc/robot/constants/ClimberConstants.java @@ -1,14 +1,14 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.DegreesPerSecond; -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.Kilograms; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.Rotations; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.DegreesPerSecond; +import static org.wpilib.units.Units.Inches; +import static org.wpilib.units.Units.Kilograms; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.Rotations; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; import com.ctre.phoenix6.configs.FeedbackConfigs; @@ -23,16 +23,16 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; import coppercore.wpilib_interface.subsystems.sim.ElevatorSimAdapter; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Mass; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.simulation.ElevatorSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.Mass; +import org.wpilib.units.measure.Time; +import org.wpilib.units.measure.Voltage; +import org.wpilib.simulation.ElevatorSim; // Copilot was used to help write this file public class ClimberConstants { @@ -136,7 +136,7 @@ public CoppercoreSimAdapter buildClimberSim() { return new ElevatorSimAdapter( buildMechanismConfig(), new ElevatorSim( - LinearSystemId.createElevatorSystem( + Models.elevatorFromPhysicalConstants( DCMotor.getKrakenX60Foc(1), simClimberWeight.in(Kilograms), simClimberRadius.in(Meters), diff --git a/src/main/java/frc/robot/constants/FieldConstants.java b/src/main/java/frc/robot/constants/FieldConstants.java index 12101007..9bfdd32a 100644 --- a/src/main/java/frc/robot/constants/FieldConstants.java +++ b/src/main/java/frc/robot/constants/FieldConstants.java @@ -12,10 +12,10 @@ package frc.robot.constants; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Translation3d; -import edu.wpi.first.math.util.Units; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.geometry.Translation3d; +import org.wpilib.math.util.Units; // TODO: Replace "opp" references with a good way to get constants for whatever alliance we're on diff --git a/src/main/java/frc/robot/constants/FieldLocationInstance.java b/src/main/java/frc/robot/constants/FieldLocationInstance.java index 07d223c0..ab399310 100644 --- a/src/main/java/frc/robot/constants/FieldLocationInstance.java +++ b/src/main/java/frc/robot/constants/FieldLocationInstance.java @@ -1,6 +1,6 @@ package frc.robot.constants; -import edu.wpi.first.math.geometry.Translation2d; +import org.wpilib.math.geometry.Translation2d; /** * Contains "field locations" (e.g. passing targets, locations for autonomous or semi-autonomous diff --git a/src/main/java/frc/robot/constants/FieldLocations.java b/src/main/java/frc/robot/constants/FieldLocations.java index dcc63135..3c13e544 100644 --- a/src/main/java/frc/robot/constants/FieldLocations.java +++ b/src/main/java/frc/robot/constants/FieldLocations.java @@ -1,7 +1,7 @@ package frc.robot.constants; import coppercore.wpilib_interface.alliance_util.AllianceUtil; -import edu.wpi.first.math.geometry.Translation2d; +import org.wpilib.math.geometry.Translation2d; /** * The FieldLocations class provides static methods to get field locations for the current alliance. diff --git a/src/main/java/frc/robot/constants/HoodConstants.java b/src/main/java/frc/robot/constants/HoodConstants.java index 2e90cbfd..cdaaf790 100644 --- a/src/main/java/frc/robot/constants/HoodConstants.java +++ b/src/main/java/frc/robot/constants/HoodConstants.java @@ -1,16 +1,16 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.DegreesPerSecond; -import static edu.wpi.first.units.Units.Hertz; -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.MetersPerSecond; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.DegreesPerSecond; +import static org.wpilib.units.Units.Hertz; +import static org.wpilib.units.Units.Inches; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; import com.ctre.phoenix6.configs.FeedbackConfigs; @@ -26,17 +26,17 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.sim.ArmSimAdapter; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Frequency; -import edu.wpi.first.units.measure.LinearVelocity; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.simulation.SingleJointedArmSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.Frequency; +import org.wpilib.units.measure.LinearVelocity; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.units.measure.Voltage; +import org.wpilib.simulation.SingleJointedArmSim; import frc.robot.Constants; import frc.robot.Constants.Mode; diff --git a/src/main/java/frc/robot/constants/HopperConstants.java b/src/main/java/frc/robot/constants/HopperConstants.java index b15cde9f..e79f1d08 100644 --- a/src/main/java/frc/robot/constants/HopperConstants.java +++ b/src/main/java/frc/robot/constants/HopperConstants.java @@ -1,14 +1,14 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -// import static edu.wpi.first.units.Units.DegreesPerSecond; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +// import static org.wpilib.units.Units.DegreesPerSecond; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RotationsPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; import com.ctre.phoenix6.configs.MotorOutputConfigs; @@ -19,16 +19,16 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; -import coppercore.wpilib_interface.subsystems.sim.DCMotorSimAdapter; +import coppercore.wpilib_interface.subsystems.sim.FlywheelSimAdapter; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.units.measure.Voltage; +import org.wpilib.simulation.FlywheelSim; public class HopperConstants { @@ -99,10 +99,10 @@ public TalonFXConfiguration buildTalonFXConfigs() { } public CoppercoreSimAdapter buildHopperSim() { - return new DCMotorSimAdapter( + return new FlywheelSimAdapter( buildMechanismConfig(), - new DCMotorSim( - LinearSystemId.createDCMotorSystem( + new FlywheelSim( + Models.flywheelFromPhysicalConstants( DCMotor.getKrakenX60(1), simHopperMOI.in(KilogramSquareMeters), 1 / hopperReduction), diff --git a/src/main/java/frc/robot/constants/IndexerConstants.java b/src/main/java/frc/robot/constants/IndexerConstants.java index 25e3b462..346af71b 100644 --- a/src/main/java/frc/robot/constants/IndexerConstants.java +++ b/src/main/java/frc/robot/constants/IndexerConstants.java @@ -1,12 +1,12 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RotationsPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; import com.ctre.phoenix6.configs.FeedbackConfigs; @@ -18,15 +18,15 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; -import coppercore.wpilib_interface.subsystems.sim.DCMotorSimAdapter; +import coppercore.wpilib_interface.subsystems.sim.FlywheelSimAdapter; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.simulation.FlywheelSim; public class IndexerConstants { @@ -87,10 +87,10 @@ public TalonFXConfiguration buildTalonFXConfigs() { } public CoppercoreSimAdapter buildIndexerSim() { - return new DCMotorSimAdapter( + return new FlywheelSimAdapter( buildMechanismConfig(), - new DCMotorSim( - LinearSystemId.createDCMotorSystem( + new FlywheelSim( + Models.flywheelFromPhysicalConstants( DCMotor.getKrakenX44Foc(1), simIndexerMOI.in(KilogramSquareMeters), 1 / indexerReduction), diff --git a/src/main/java/frc/robot/constants/IntakeConstants.java b/src/main/java/frc/robot/constants/IntakeConstants.java index 64c0f2d3..cdb76474 100644 --- a/src/main/java/frc/robot/constants/IntakeConstants.java +++ b/src/main/java/frc/robot/constants/IntakeConstants.java @@ -1,14 +1,14 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; import com.ctre.phoenix6.configs.FeedbackConfigs; @@ -25,21 +25,21 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.sim.ArmSimAdapter; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; -import coppercore.wpilib_interface.subsystems.sim.DCMotorSimAdapter; +import coppercore.wpilib_interface.subsystems.sim.FlywheelSimAdapter; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; -import edu.wpi.first.wpilibj.simulation.SingleJointedArmSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.Units; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularAcceleration; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.units.measure.Voltage; +import org.wpilib.simulation.FlywheelSim; +import org.wpilib.simulation.SingleJointedArmSim; public class IntakeConstants { @@ -193,10 +193,10 @@ public MechanismConfig buildRollersMechanismConfig() { public CoppercoreSimAdapter buildRollersSim() { DCMotor motor = DCMotor.getKrakenX60Foc(2); - return new DCMotorSimAdapter( + return new FlywheelSimAdapter( buildRollersMechanismConfig(), - new DCMotorSim( - LinearSystemId.createDCMotorSystem(motor, rollersInertia.in(KilogramSquareMeters), 1.0), + new FlywheelSim( + Models.flywheelFromPhysicalConstants(motor, rollersInertia.in(KilogramSquareMeters), 1.0), motor)); } } diff --git a/src/main/java/frc/robot/constants/JsonConstants.java b/src/main/java/frc/robot/constants/JsonConstants.java index 097adc97..8eaa5aa5 100644 --- a/src/main/java/frc/robot/constants/JsonConstants.java +++ b/src/main/java/frc/robot/constants/JsonConstants.java @@ -1,9 +1,9 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amp; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Second; +import static org.wpilib.units.Units.Amp; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Second; import com.therekrab.autopilot.APTarget; import coppercore.parameter_tools.json.JSONHandler; @@ -18,11 +18,11 @@ import coppercore.parameter_tools.path_provider.EnvironmentHandler; import coppercore.wpilib_interface.controllers.Controllers; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform2d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.wpilibj.Filesystem; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Rotation3d; +import org.wpilib.math.geometry.Transform2d; +import org.wpilib.math.geometry.Transform3d; +import org.wpilib.system.Filesystem; import frc.robot.RobotContainer; import frc.robot.auto.Autos; import frc.robot.constants.drive.DriveConstants; diff --git a/src/main/java/frc/robot/constants/ManualModeConstants.java b/src/main/java/frc/robot/constants/ManualModeConstants.java index c9f174f4..f81dfe07 100644 --- a/src/main/java/frc/robot/constants/ManualModeConstants.java +++ b/src/main/java/frc/robot/constants/ManualModeConstants.java @@ -1,9 +1,9 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Meters; +import static org.wpilib.units.Units.Meters; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.units.measure.Distance; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.units.measure.Distance; /** ManualModeConstants contains constants that define how to shoot when vision isn't used */ public class ManualModeConstants { diff --git a/src/main/java/frc/robot/constants/RobotInfo.java b/src/main/java/frc/robot/constants/RobotInfo.java index b4012993..ac7e6640 100644 --- a/src/main/java/frc/robot/constants/RobotInfo.java +++ b/src/main/java/frc/robot/constants/RobotInfo.java @@ -1,9 +1,9 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Hertz; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Kilograms; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Hertz; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.Kilograms; +import static org.wpilib.units.Units.Seconds; import com.ctre.phoenix6.CANBus; import com.ctre.phoenix6.configs.CANdiConfiguration; @@ -16,13 +16,13 @@ import coppercore.parameter_tools.json.annotations.JSONExclude; import coppercore.wpilib_interface.subsystems.dio_switch.DigitalInputIOCANdi.CANdiSignal; import coppercore.wpilib_interface.subsystems.motors.talonfx.MotorIOTalonFX.SignalRefreshRates; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform2d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Mass; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; +import org.wpilib.math.geometry.Rotation3d; +import org.wpilib.math.geometry.Transform2d; +import org.wpilib.math.geometry.Transform3d; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Mass; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; public class RobotInfo { diff --git a/src/main/java/frc/robot/constants/ShooterConstants.java b/src/main/java/frc/robot/constants/ShooterConstants.java index 01f1c8d3..a0d952aa 100644 --- a/src/main/java/frc/robot/constants/ShooterConstants.java +++ b/src/main/java/frc/robot/constants/ShooterConstants.java @@ -1,12 +1,12 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Hertz; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.Second; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Hertz; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.Second; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.CANBus; import com.ctre.phoenix6.configs.ClosedLoopRampsConfigs; @@ -29,18 +29,18 @@ import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; import coppercore.wpilib_interface.subsystems.sim.FlywheelSimAdapter; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.VoltageUnit; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Frequency; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.units.measure.Velocity; -import edu.wpi.first.wpilibj.simulation.FlywheelSim; +import org.wpilib.math.interpolation.InterpolatingDoubleTreeMap; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.VoltageUnit; +import org.wpilib.units.measure.AngularAcceleration; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Frequency; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.units.measure.Velocity; +import org.wpilib.simulation.FlywheelSim; public class ShooterConstants { public final Double[] distanceToViDistancesMeters = {1.8, 2.0, 3.5}; @@ -212,7 +212,7 @@ public CoppercoreSimAdapter buildShooterSim() { return new FlywheelSimAdapter( buildMechanismConfig(), new FlywheelSim( - LinearSystemId.createFlywheelSystem( + Models.flywheelFromPhysicalConstants( DCMotor.getKrakenX60Foc(3), shooterMOI.in(KilogramSquareMeters), 1.0), DCMotor.getKrakenX60Foc(3))); } diff --git a/src/main/java/frc/robot/constants/ShotMaps.java b/src/main/java/frc/robot/constants/ShotMaps.java index 9f6597d8..53da2e0e 100644 --- a/src/main/java/frc/robot/constants/ShotMaps.java +++ b/src/main/java/frc/robot/constants/ShotMaps.java @@ -1,22 +1,22 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.Seconds; import coppercore.parameter_tools.LoggedTunableNumber; import coppercore.parameter_tools.json.annotations.AfterJsonLoad; import coppercore.parameter_tools.json.annotations.JSONExclude; -import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import org.wpilib.math.interpolation.InterpolatingDoubleTreeMap; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.Time; +import org.wpilib.smartdashboard.SmartDashboard; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; import java.util.Arrays; import java.util.Comparator; import java.util.function.Function; diff --git a/src/main/java/frc/robot/constants/StrategyConstants.java b/src/main/java/frc/robot/constants/StrategyConstants.java index 2f25eca1..3661a031 100644 --- a/src/main/java/frc/robot/constants/StrategyConstants.java +++ b/src/main/java/frc/robot/constants/StrategyConstants.java @@ -1,8 +1,8 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Seconds; -import edu.wpi.first.units.measure.Time; +import org.wpilib.units.measure.Time; public class StrategyConstants { // Due to the presence of these constants, it is necessary for the driver(s) to play an active diff --git a/src/main/java/frc/robot/constants/TransferRollerConstants.java b/src/main/java/frc/robot/constants/TransferRollerConstants.java index 4d67b3f4..e8f1c1c7 100644 --- a/src/main/java/frc/robot/constants/TransferRollerConstants.java +++ b/src/main/java/frc/robot/constants/TransferRollerConstants.java @@ -1,12 +1,12 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RotationsPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; import com.ctre.phoenix6.configs.FeedbackConfigs; @@ -18,15 +18,15 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; -import coppercore.wpilib_interface.subsystems.sim.DCMotorSimAdapter; +import coppercore.wpilib_interface.subsystems.sim.FlywheelSimAdapter; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.simulation.FlywheelSim; public class TransferRollerConstants { @@ -85,10 +85,10 @@ public TalonFXConfiguration buildTalonFXConfigs() { } public CoppercoreSimAdapter buildTransferRollerSim() { - return new DCMotorSimAdapter( + return new FlywheelSimAdapter( buildMechanismConfig(), - new DCMotorSim( - LinearSystemId.createDCMotorSystem( + new FlywheelSim( + Models.flywheelFromPhysicalConstants( DCMotor.getKrakenX44Foc(1), simTransferRollerMOI.in(KilogramSquareMeters), 1 / transferRollerReduction), diff --git a/src/main/java/frc/robot/constants/TurretConstants.java b/src/main/java/frc/robot/constants/TurretConstants.java index cf1eb719..e8a82fc2 100644 --- a/src/main/java/frc/robot/constants/TurretConstants.java +++ b/src/main/java/frc/robot/constants/TurretConstants.java @@ -1,11 +1,11 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.DegreesPerSecond; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.DegreesPerSecond; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.AudioConfigs; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; @@ -24,15 +24,15 @@ import coppercore.wpilib_interface.subsystems.configs.MechanismConfig.GravityFeedforwardType; import coppercore.wpilib_interface.subsystems.sim.CoppercoreSimAdapter; import coppercore.wpilib_interface.subsystems.sim.HardstoppedDCMotorSimAdapter; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Time; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Time; +import org.wpilib.units.measure.Voltage; +import org.wpilib.simulation.DCMotorSim; public class TurretConstants { public final Boolean wearInTurret = false; @@ -163,7 +163,7 @@ public CoppercoreSimAdapter buildTurretSim() { return new HardstoppedDCMotorSimAdapter( buildMechanismConfig(), new DCMotorSim( - LinearSystemId.createDCMotorSystem( + Models.singleJointedArmFromPhysicalConstants( DCMotor.getKrakenX44Foc(1), simTurretMOI.in(KilogramSquareMeters), 1 / turretReduction), diff --git a/src/main/java/frc/robot/constants/VisionConstants.java b/src/main/java/frc/robot/constants/VisionConstants.java index a720d891..edd3ada4 100644 --- a/src/main/java/frc/robot/constants/VisionConstants.java +++ b/src/main/java/frc/robot/constants/VisionConstants.java @@ -1,12 +1,12 @@ package frc.robot.constants; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Seconds; import coppercore.vision.VisionGainConstants; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Time; +import org.wpilib.math.geometry.Rotation3d; +import org.wpilib.math.geometry.Transform3d; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Time; public class VisionConstants { // Placeholder values for camera configs diff --git a/src/main/java/frc/robot/constants/drive/DriveConstants.java b/src/main/java/frc/robot/constants/drive/DriveConstants.java index 0f19d629..ca68defc 100644 --- a/src/main/java/frc/robot/constants/drive/DriveConstants.java +++ b/src/main/java/frc/robot/constants/drive/DriveConstants.java @@ -1,19 +1,19 @@ package frc.robot.constants.drive; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.MetersPerSecond; -import static edu.wpi.first.units.Units.MetersPerSecondPerSecond; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.RadiansPerSecondPerSecond; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.MetersPerSecondPerSecond; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RadiansPerSecondPerSecond; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.LinearAcceleration; -import edu.wpi.first.units.measure.LinearVelocity; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularAcceleration; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.LinearAcceleration; +import org.wpilib.units.measure.LinearVelocity; /** * Constants for the drivetrain subsystem related to driving performance and control. diff --git a/src/main/java/frc/robot/constants/drive/ModuleConfig.java b/src/main/java/frc/robot/constants/drive/ModuleConfig.java index 37d1a440..d35e91f6 100644 --- a/src/main/java/frc/robot/constants/drive/ModuleConfig.java +++ b/src/main/java/frc/robot/constants/drive/ModuleConfig.java @@ -5,8 +5,8 @@ import com.ctre.phoenix6.swerve.SwerveModuleConstants; import com.ctre.phoenix6.swerve.SwerveModuleConstantsFactory; import coppercore.parameter_tools.json.annotations.JSONExclude; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.Distance; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.Distance; public class ModuleConfig { @JSONExclude public Integer driveMotorId; diff --git a/src/main/java/frc/robot/constants/drive/PhysicalDriveConstants.java b/src/main/java/frc/robot/constants/drive/PhysicalDriveConstants.java index 8bf9c0f7..7bed9728 100644 --- a/src/main/java/frc/robot/constants/drive/PhysicalDriveConstants.java +++ b/src/main/java/frc/robot/constants/drive/PhysicalDriveConstants.java @@ -1,11 +1,11 @@ package frc.robot.constants.drive; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Inches; -import static edu.wpi.first.units.Units.KilogramSquareMeters; -import static edu.wpi.first.units.Units.MetersPerSecond; -import static edu.wpi.first.units.Units.Rotations; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Inches; +import static org.wpilib.units.Units.KilogramSquareMeters; +import static org.wpilib.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.Rotations; +import static org.wpilib.units.Units.Volts; import com.ctre.phoenix6.configs.CANcoderConfiguration; import com.ctre.phoenix6.configs.CurrentLimitsConfigs; @@ -22,11 +22,11 @@ import com.ctre.phoenix6.swerve.SwerveModuleConstantsFactory; import coppercore.parameter_tools.json.annotations.AfterJsonLoad; import coppercore.parameter_tools.json.annotations.JSONExclude; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.LinearVelocity; -import edu.wpi.first.units.measure.MomentOfInertia; -import edu.wpi.first.units.measure.Voltage; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.LinearVelocity; +import org.wpilib.units.measure.MomentOfInertia; +import org.wpilib.units.measure.Voltage; import frc.robot.constants.JsonConstants; import java.util.function.Supplier; diff --git a/src/main/java/frc/robot/coordination/MatchState.java b/src/main/java/frc/robot/coordination/MatchState.java index 9186ff1f..41d26d3c 100644 --- a/src/main/java/frc/robot/coordination/MatchState.java +++ b/src/main/java/frc/robot/coordination/MatchState.java @@ -1,14 +1,14 @@ package frc.robot.coordination; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Seconds; import coppercore.wpilib_interface.alliance_util.AllianceUtil; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.DriverStation.Alliance; -import edu.wpi.first.wpilibj.DriverStation.MatchType; -import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj.simulation.DriverStationSim; -import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import org.wpilib.driverstation.Alliance; +import org.wpilib.driverstation.MatchType; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.Timer; +import org.wpilib.simulation.DriverStationSim; +import org.wpilib.smartdashboard.SmartDashboard; import frc.robot.Constants; import frc.robot.Constants.Mode; import frc.robot.constants.JsonConstants; @@ -47,7 +47,7 @@ public class MatchState { */ @AutoLogOutput(key = "MatchState/isInMatch") public boolean isInMatch() { - Logger.recordOutput("MatchState/matchType", DriverStation.getMatchType()); + Logger.recordOutput("MatchState/matchType", DriverStationBackend.getMatchType()); // Hardcode true for shop testing; getMatchType doesn't return a correct value here return true; // || DriverStation.getMatchType() == DriverStation.MatchType.Practice @@ -130,7 +130,7 @@ public MatchState() { matchTypeChooser = new LoggedDashboardChooser<>("MatchState/MatchType"); for (var matchType : MatchType.values()) { - if (matchType == MatchType.None) { + if (matchType == MatchType.NONE) { matchTypeChooser.addDefaultOption(matchType.name(), matchType); } else { matchTypeChooser.addOption(matchType.name(), matchType); @@ -156,7 +156,7 @@ public void disabledPeriodic() { private double getPreciseMatchTime() { double timerTime = preciseMatchTimer.get(); - if (DriverStation.isAutonomous()) { + if (DriverStationBackend.isAutonomous()) { return StrategyConstants.autoStart - timerTime; } else { return StrategyConstants.transitionStart - timerTime; @@ -164,7 +164,7 @@ private double getPreciseMatchTime() { } private double getMatchTime() { - double dsMatchTime = DriverStation.getMatchTime(); + double dsMatchTime = DriverStationBackend.getMatchTime(); double preciseMatchTime = getPreciseMatchTime(); if (Math.abs(dsMatchTime - preciseMatchTime) @@ -181,7 +181,7 @@ public void enabledPeriodic(boolean weWonAutoOverridePressed, boolean weLostAuto DriverStationSim.setMatchType(matchTypeChooser.get()); } - if (DriverStation.isTeleop()) { + if (DriverStationBackend.isTeleop()) { hasTeleopEnabled = true; } @@ -227,21 +227,18 @@ public void enabledPeriodic(boolean weWonAutoOverridePressed, boolean weLostAuto } private void checkGameDataForAutoWinner() { - String gameData = DriverStation.getGameSpecificMessage(); - - if (gameData == null) { - return; - } + DriverStationBackend.getGameData().ifPresent((gameData) -> { if (gameData.length() > 0) { if (gameData.startsWith("R")) { - wonAuto = Optional.of(Alliance.Red); + wonAuto = Optional.of(Alliance.RED); receivedAutoWinnerFromFMS = true; } else if (gameData.startsWith("B")) { - wonAuto = Optional.of(Alliance.Blue); + wonAuto = Optional.of(Alliance.BLUE); receivedAutoWinnerFromFMS = true; } } + }); } public Optional getAutoWinner() { @@ -251,9 +248,9 @@ public Optional getAutoWinner() { public MatchShift getCurrentShift(double currentMatchTime) { // The behavior of this method is determined largely by the docs here - // https://github.wpilib.org/allwpilib/docs/release/java/edu/wpi/first/wpilibj/DriverStation.html#getMatchTime() + // https://github.wpilib.org/allwpilib/docs/release/java/org.wpilib.driverstation.DriverStation.html#getMatchTime() if (isInMatch()) { - if (DriverStation.isAutonomous()) { + if (DriverStationBackend.isAutonomous()) { return MatchShift.Auto; } else { return getTeleopShiftFromMatchTime(currentMatchTime); diff --git a/src/main/java/frc/robot/generated/TunerConstants.java b/src/main/java/frc/robot/generated/TunerConstants.java index 326ee90b..651984b8 100644 --- a/src/main/java/frc/robot/generated/TunerConstants.java +++ b/src/main/java/frc/robot/generated/TunerConstants.java @@ -1,6 +1,6 @@ package frc.robot.generated; -import static edu.wpi.first.units.Units.*; +import static org.wpilib.units.Units.*; import com.ctre.phoenix6.CANBus; import com.ctre.phoenix6.configs.*; @@ -8,10 +8,10 @@ import com.ctre.phoenix6.signals.*; import com.ctre.phoenix6.swerve.*; import com.ctre.phoenix6.swerve.SwerveModuleConstants.*; -import edu.wpi.first.math.Matrix; -import edu.wpi.first.math.numbers.N1; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.units.measure.*; +import org.wpilib.math.linalg.Matrix; +import org.wpilib.math.numbers.N1; +import org.wpilib.math.numbers.N3; +import org.wpilib.units.measure.*; // 2025 B BOT CONSTANTS!!!!! (dont remove put somewhere else please) diff --git a/src/main/java/frc/robot/subsystems/climber/ClimberState.java b/src/main/java/frc/robot/subsystems/climber/ClimberState.java index d92f3eb2..51b68852 100644 --- a/src/main/java/frc/robot/subsystems/climber/ClimberState.java +++ b/src/main/java/frc/robot/subsystems/climber/ClimberState.java @@ -1,10 +1,10 @@ package frc.robot.subsystems.climber; -import static edu.wpi.first.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RadiansPerSecond; import coppercore.controls.state_machine.State; import coppercore.controls.state_machine.StateMachine; -import edu.wpi.first.units.AngularVelocityUnit; +import org.wpilib.units.AngularVelocityUnit; import frc.robot.constants.JsonConstants; // Copilot autocomplete was used to help write this file diff --git a/src/main/java/frc/robot/subsystems/climber/ClimberSubsystem.java b/src/main/java/frc/robot/subsystems/climber/ClimberSubsystem.java index 4cc7f131..51a46d2a 100644 --- a/src/main/java/frc/robot/subsystems/climber/ClimberSubsystem.java +++ b/src/main/java/frc/robot/subsystems/climber/ClimberSubsystem.java @@ -1,14 +1,14 @@ package frc.robot.subsystems.climber; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Meters; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RotationsPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import coppercore.controls.state_machine.StateMachine; import coppercore.math.Lazy; @@ -20,14 +20,13 @@ import coppercore.wpilib_interface.subsystems.motors.MotorInputsAutoLogged; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.units.VoltageUnit; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Distance; -import edu.wpi.first.units.measure.MutVoltage; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.units.VoltageUnit; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Distance; +import org.wpilib.units.measure.Voltage; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.climber.ClimberState.HomingWaitForMovementState; import frc.robot.subsystems.climber.ClimberState.HomingWaitForStoppingState; @@ -83,10 +82,10 @@ private enum ClimberAction { Lazy climberTuningAmps; Lazy climberTuningVolts; - LoggedTunableMeasure hangVoltage = + LoggedTunableMeasure hangVoltage = new LoggedTunableMeasure<>( "ClimberTunables/hangVoltage", - JsonConstants.climberConstants.hangClimbVoltage.mutableCopy(), + JsonConstants.climberConstants.hangClimbVoltage, Volts, true); @@ -108,7 +107,7 @@ public ClimberSubsystem(MotorIO motor) { waitForHomingState .when( - climber -> DriverStation.isEnabled() && climber.isClimberTestMode(), + climber -> DriverStationBackend.isEnabled() && climber.isClimberTestMode(), "In climber test mode (must home first)") .transitionTo(homingWaitForMovementState); waitForHomingState.whenFinished("Should home").transitionTo(homingWaitForMovementState); @@ -208,7 +207,7 @@ public ClimberSubsystem(MotorIO motor) { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); motor.updateInputs(inputs); Logger.processInputs("Climber/inputs", inputs); @@ -218,7 +217,7 @@ public void monitoredPeriodic() { Logger.recordOutput("Climber/State", stateMachine.getCurrentState().getName()); stateMachine.periodic(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/climberMs", (endTimeUs - startTimeUs) / 1000.0); } diff --git a/src/main/java/frc/robot/subsystems/drive/Drive.java b/src/main/java/frc/robot/subsystems/drive/Drive.java index cfe7ccce..643b83e7 100644 --- a/src/main/java/frc/robot/subsystems/drive/Drive.java +++ b/src/main/java/frc/robot/subsystems/drive/Drive.java @@ -7,7 +7,7 @@ package frc.robot.subsystems.drive; -import static edu.wpi.first.units.Units.*; +import static org.wpilib.units.Units.*; import com.pathplanner.lib.util.PathPlannerLogging; import coppercore.controls.ServiceThread; @@ -15,35 +15,33 @@ import coppercore.wpilib_interface.DriveTemplate; import coppercore.wpilib_interface.alliance_util.AllianceUtil; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.hal.FRCNetComm.tInstances; -import edu.wpi.first.hal.FRCNetComm.tResourceType; -import edu.wpi.first.hal.HAL; -import edu.wpi.first.math.Matrix; -import edu.wpi.first.math.VecBuilder; -import edu.wpi.first.math.estimator.SwerveDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Twist2d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.math.kinematics.SwerveDriveKinematics; -import edu.wpi.first.math.kinematics.SwerveModulePosition; -import edu.wpi.first.math.kinematics.SwerveModuleState; -import edu.wpi.first.math.numbers.N1; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.wpilibj.Alert; -import edu.wpi.first.wpilibj.Alert.AlertType; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.DriverStation.Alliance; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj.smartdashboard.Field2d; -import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj2.command.sysid.SysIdRoutine; +import org.wpilib.hardware.hal.HAL; +import org.wpilib.math.linalg.Matrix; +import org.wpilib.math.linalg.VecBuilder; +import org.wpilib.math.estimator.SwerveDrivePoseEstimator; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.geometry.Twist2d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.math.kinematics.SwerveDriveKinematics; +import org.wpilib.math.kinematics.SwerveModulePosition; +import org.wpilib.math.kinematics.SwerveModuleVelocity; +import org.wpilib.math.numbers.N1; +import org.wpilib.math.numbers.N3; +import org.wpilib.units.measure.Current; +import org.wpilib.driverstation.Alert; +import org.wpilib.driverstation.DriverStation; +import org.wpilib.driverstation.Alliance; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; +import org.wpilib.system.Timer; +import org.wpilib.smartdashboard.Field2d; +import org.wpilib.smartdashboard.SmartDashboard; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; +import org.wpilib.command2.SubsystemBase; +import org.wpilib.command2.sysid.SysIdRoutine; import frc.robot.Constants; import frc.robot.Constants.Mode; import frc.robot.constants.JsonConstants; @@ -83,7 +81,7 @@ public class Drive extends SubsystemBase implements DriveTemplate { private final Module[] modules = new Module[4]; // FL, FR, BL, BR private final SysIdRoutine sysId; private final Alert gyroDisconnectedAlert = - new Alert("Disconnected gyro, using kinematics as fallback.", AlertType.kError); + new Alert("Disconnected gyro, using kinematics as fallback.", Alert.Level.HIGH); private SwerveDriveKinematics kinematics = new SwerveDriveKinematics(getModuleTranslations()); private Rotation2d rawGyroRotation = Rotation2d.kZero; @@ -138,7 +136,7 @@ public Drive( SmartDashboard.putData("ResetToAutoCurrentLimits", resetToAutoLimitsCommand); // Usage reporting for swerve template - HAL.report(tResourceType.kResourceType_RobotDrive, tInstances.kRobotDriveSwerve_AdvantageKit); + HAL.reportUsage("RobotDrive", "Swerve_AdvantageKit"); // Start odometry thread PhoenixOdometryThread.getInstance().start(); @@ -184,7 +182,7 @@ public Drive( @Override public void periodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); odometryLock.lock(); // Prevents odometry updates while reading data gyroIO.updateInputs(gyroInputs); Logger.processInputs("Drive/Gyro", gyroInputs); @@ -198,16 +196,16 @@ public void periodic() { TotalCurrentCalculator.recordCurrent(hashCode(), supplyCurrentSum); // Stop moving when disabled - if (DriverStation.isDisabled()) { + if (DriverStationBackend.isDisabled()) { for (var module : modules) { module.stop(); } } // Log empty setpoint states when disabled - if (DriverStation.isDisabled()) { - Logger.recordOutput("SwerveStates/Setpoints", new SwerveModuleState[] {}); - Logger.recordOutput("SwerveStates/SetpointsOptimized", new SwerveModuleState[] {}); + if (DriverStationBackend.isDisabled()) { + Logger.recordOutput("SwerveStates/Setpoints", new SwerveModuleVelocity[] {}); + Logger.recordOutput("SwerveStates/SetpointsOptimized", new SwerveModuleVelocity[] {}); } // Update odometry @@ -224,8 +222,8 @@ public void periodic() { modulePositions[moduleIndex] = modules[moduleIndex].getOdometryPositions()[i]; moduleDeltas[moduleIndex] = new SwerveModulePosition( - modulePositions[moduleIndex].distanceMeters - - lastModulePositions[moduleIndex].distanceMeters, + modulePositions[moduleIndex].distance + - lastModulePositions[moduleIndex].distance, modulePositions[moduleIndex].angle); lastModulePositions[moduleIndex] = modulePositions[moduleIndex]; } @@ -256,7 +254,8 @@ public void periodic() { } twist = new Twist2d(twist.dx, twist.dy, deltaYaw.getRadians()); - totalDeltaPose = totalDeltaPose.exp(twist); + totalDeltaPose = totalDeltaPose.plus(twist.exp()); + } else { poseEstimator.updateWithTime(sampleTimestamps[i], rawGyroRotation, modulePositions); } @@ -264,7 +263,7 @@ public void periodic() { // Apply update if (JsonConstants.featureFlags.useMAPoseEstimator) { - Twist2d totalTwist = Pose2d.kZero.log(totalDeltaPose); + Twist2d totalTwist = totalDeltaPose.minus(Pose2d.kZero).log(); lastGyroYaw = gyroInputs.connected ? gyroInputs.yawPosition : rawGyroRotation; maPoseEstimator.addDriveData(Timer.getTimestamp(), totalTwist); } @@ -274,7 +273,7 @@ public void periodic() { field2d.setRobotPose(getPose()); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/driveMs", (endTimeUs - startTimeUs) / 1000.0); } @@ -285,11 +284,11 @@ public void periodic() { * * @param speeds Speeds in meters/sec */ - public void runVelocity(ChassisSpeeds speeds) { + public void runVelocity(ChassisVelocities speeds) { // Calculate module setpoints - ChassisSpeeds discreteSpeeds = ChassisSpeeds.discretize(speeds, 0.02); - SwerveModuleState[] setpointStates = kinematics.toSwerveModuleStates(discreteSpeeds); - SwerveDriveKinematics.desaturateWheelSpeeds( + ChassisVelocities discreteSpeeds = speeds.discretize(0.02); + SwerveModuleVelocity[] setpointStates = kinematics.toSwerveModuleVelocities(discreteSpeeds); + setpointStates = SwerveDriveKinematics.desaturateWheelVelocities( setpointStates, JsonConstants.physicalDriveConstants.kSpeedAt12Volts); // Log unoptimized setpoints and setpoint speeds @@ -305,26 +304,26 @@ public void runVelocity(ChassisSpeeds speeds) { Logger.recordOutput("SwerveStates/SetpointsOptimized", setpointStates); } - public void setGoalSpeedsBlueOrigins(ChassisSpeeds goalSpeeds) { + public void setGoalSpeedsBlueOrigins(ChassisVelocities goalSpeeds) { Rotation2d robotRotation = getRotation(); - runVelocity(ChassisSpeeds.fromFieldRelativeSpeeds(goalSpeeds, robotRotation)); + runVelocity(goalSpeeds.toRobotRelative(robotRotation)); } @Override - public void setGoalSpeeds(ChassisSpeeds goalSpeeds, boolean isFieldCentric) { + public void setGoalVelocities(ChassisVelocities goalSpeeds, boolean isFieldCentric) { Logger.recordOutput("drive/goalSpeeds", goalSpeeds); - ChassisSpeeds speeds = getChassisSpeeds(); + ChassisVelocities speeds = getChassisVelocities(); if ((xLockPressed || inDefenseMode) - && Math.abs(goalSpeeds.vxMetersPerSecond) <= 1e-3 - && Math.abs(goalSpeeds.vyMetersPerSecond) <= 1e-3 - && Math.abs(goalSpeeds.omegaRadiansPerSecond) <= 1e-3 + && Math.abs(goalSpeeds.vx) <= 1e-3 + && Math.abs(goalSpeeds.vy) <= 1e-3 + && Math.abs(goalSpeeds.omega) <= 1e-3 && Math.sqrt( - speeds.vxMetersPerSecond * speeds.vxMetersPerSecond - + speeds.vyMetersPerSecond * speeds.vyMetersPerSecond) + speeds.vx * speeds.vx + + speeds.vy * speeds.vy) <= JsonConstants.driveConstants.xLockMaxVelocityMetersPerSecond - && Math.abs(speeds.omegaRadiansPerSecond) + && Math.abs(speeds.omega) <= JsonConstants.driveConstants.xLockMaxVelocityRadiansPerSecond) { stopWithX(); return; @@ -333,15 +332,15 @@ public void setGoalSpeeds(ChassisSpeeds goalSpeeds, boolean isFieldCentric) { if (isFieldCentric) { // Adjust for field-centric control boolean isFlipped = - DriverStation.getAlliance().isPresent() - && DriverStation.getAlliance().get() == Alliance.Red; + DriverStationBackend.getAlliance().isPresent() + && DriverStationBackend.getAlliance().get() == Alliance.RED; Rotation2d robotRotation = isFlipped ? getRotation().plus(new Rotation2d(Math.PI)) // Flip orientation for Red Alliance : getRotation(); - runVelocity(ChassisSpeeds.fromFieldRelativeSpeeds(goalSpeeds, robotRotation)); + runVelocity(goalSpeeds.toRobotRelative(robotRotation)); } else { Logger.recordOutput("Drive/DesiredRobotCentricSpeeds", goalSpeeds); @@ -358,7 +357,7 @@ public void runCharacterization(double output) { /** Stops the drive. */ public void stop() { - runVelocity(new ChassisSpeeds()); + runVelocity(new ChassisVelocities()); } /** @@ -388,8 +387,8 @@ public Command sysIdDynamic(SysIdRoutine.Direction direction) { /** Returns the module states (turn angles and drive velocities) for all of the modules. */ @AutoLogOutput(key = "SwerveStates/Measured") - private SwerveModuleState[] getModuleStates() { - SwerveModuleState[] states = new SwerveModuleState[4]; + private SwerveModuleVelocity[] getModuleStates() { + SwerveModuleVelocity[] states = new SwerveModuleVelocity[4]; for (int i = 0; i < 4; i++) { states[i] = modules[i].getState(); } @@ -406,9 +405,9 @@ private SwerveModulePosition[] getModulePositions() { } /** Returns the measured chassis speeds of the robot. */ - @AutoLogOutput(key = "SwerveChassisSpeeds/Measured") - public ChassisSpeeds getChassisSpeeds() { - return kinematics.toChassisSpeeds(getModuleStates()); + @AutoLogOutput(key = "SwerveChassisVelocities/Measured") + public ChassisVelocities getChassisVelocities() { + return kinematics.toChassisVelocities(getModuleStates()); } /** Returns the position of each module in radians. */ @@ -531,9 +530,9 @@ public void seedHeadingForward() { Rotation2d heading = switch (AllianceUtil.getAlliance()) { // Red alliance is "flipped" (forward is -x) - case Red -> Rotation2d.k180deg; + case RED -> Rotation2d.k180deg; // Blue alliance is +x forward - case Blue -> Rotation2d.kZero; + case BLUE -> Rotation2d.kZero; }; setPose(new Pose2d(currentPose.getX(), currentPose.getY(), heading)); diff --git a/src/main/java/frc/robot/subsystems/drive/DriveCoordinator.java b/src/main/java/frc/robot/subsystems/drive/DriveCoordinator.java index dbd68865..33628152 100644 --- a/src/main/java/frc/robot/subsystems/drive/DriveCoordinator.java +++ b/src/main/java/frc/robot/subsystems/drive/DriveCoordinator.java @@ -3,11 +3,11 @@ import coppercore.wpilib_interface.DriveWithJoysticks; import coppercore.wpilib_interface.tuning.LoggedTunablePIDGains; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.SubsystemBase; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.system.RobotController; +import org.wpilib.command2.Command; +import org.wpilib.command2.InstantCommand; +import org.wpilib.command2.SubsystemBase; import frc.robot.constants.JsonConstants; import org.littletonrobotics.junction.Logger; @@ -174,7 +174,7 @@ public void autoPilotToPose(Pose2d pose) { @Override public void periodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); if (testModeManager.isInTestMode()) { testPeriodic(); @@ -196,7 +196,7 @@ public void periodic() { "DriveCoordinator/CurrentCommand", activeCommand == null ? "None" : activeCommand.getName()); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/driveCoordinatorMs", (endTimeUs - startTimeUs) / 1000.0); } diff --git a/src/main/java/frc/robot/subsystems/drive/DriveCoordinatorCommands.java b/src/main/java/frc/robot/subsystems/drive/DriveCoordinatorCommands.java index 6ec57ed5..9550171f 100644 --- a/src/main/java/frc/robot/subsystems/drive/DriveCoordinatorCommands.java +++ b/src/main/java/frc/robot/subsystems/drive/DriveCoordinatorCommands.java @@ -1,16 +1,16 @@ package frc.robot.subsystems.drive; -import static edu.wpi.first.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.MetersPerSecond; import com.therekrab.autopilot.APConstraints; import com.therekrab.autopilot.APProfile; import com.therekrab.autopilot.APTarget; import com.therekrab.autopilot.Autopilot; import com.therekrab.autopilot.Autopilot.APResult; -import edu.wpi.first.math.controller.PIDController; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.math.controller.PIDController; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.command2.Command; import frc.robot.constants.JsonConstants; import java.security.InvalidParameterException; import org.littletonrobotics.junction.Logger; @@ -66,7 +66,7 @@ public void initialize() { @Override public void execute() { - var chassisSpeeds = driveCoordinator.drive.getChassisSpeeds(); + var chassisSpeeds = driveCoordinator.drive.getChassisVelocities(); var currentPose = driveCoordinator.drive.getPose(); APResult output = autoPilot.calculate(currentPose, chassisSpeeds, target); @@ -79,7 +79,7 @@ public void execute() { headingController.calculate(currentHeading.getRadians(), desiredHeading.getRadians()); var speeds = - new ChassisSpeeds( + new ChassisVelocities( output.vx().in(MetersPerSecond), output.vy().in(MetersPerSecond), omega); driveCoordinator.drive.setGoalSpeedsBlueOrigins(speeds); diff --git a/src/main/java/frc/robot/subsystems/drive/GyroIO.java b/src/main/java/frc/robot/subsystems/drive/GyroIO.java index 4e9754f9..be3b1ccb 100644 --- a/src/main/java/frc/robot/subsystems/drive/GyroIO.java +++ b/src/main/java/frc/robot/subsystems/drive/GyroIO.java @@ -7,7 +7,7 @@ package frc.robot.subsystems.drive; -import edu.wpi.first.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Rotation2d; import org.littletonrobotics.junction.AutoLog; public interface GyroIO { diff --git a/src/main/java/frc/robot/subsystems/drive/GyroIONavX.java b/src/main/java/frc/robot/subsystems/drive/GyroIONavX.java index 45e6f44a..6504b457 100644 --- a/src/main/java/frc/robot/subsystems/drive/GyroIONavX.java +++ b/src/main/java/frc/robot/subsystems/drive/GyroIONavX.java @@ -15,8 +15,8 @@ // import com.studica.frc.AHRS; // import com.studica.frc.AHRS.NavXComType; -// import edu.wpi.first.math.geometry.Rotation2d; -// import edu.wpi.first.math.util.Units; +// import org.wpilib.math.geometry.Rotation2d; +// import org.wpilib.math.util.Units; // import java.util.Queue; /** IO implementation for NavX. */ diff --git a/src/main/java/frc/robot/subsystems/drive/GyroIOPigeon2.java b/src/main/java/frc/robot/subsystems/drive/GyroIOPigeon2.java index 8a20b908..5bc875c0 100644 --- a/src/main/java/frc/robot/subsystems/drive/GyroIOPigeon2.java +++ b/src/main/java/frc/robot/subsystems/drive/GyroIOPigeon2.java @@ -12,10 +12,10 @@ import com.ctre.phoenix6.configs.Pigeon2Configuration; import com.ctre.phoenix6.hardware.Pigeon2; import coppercore.wpilib_interface.subsystems.StatusSignalRefresher; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; import frc.robot.constants.JsonConstants; import java.util.Queue; diff --git a/src/main/java/frc/robot/subsystems/drive/Module.java b/src/main/java/frc/robot/subsystems/drive/Module.java index 83c03a3d..c429a8e0 100644 --- a/src/main/java/frc/robot/subsystems/drive/Module.java +++ b/src/main/java/frc/robot/subsystems/drive/Module.java @@ -11,14 +11,14 @@ import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.swerve.SwerveModuleConstants; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.kinematics.SwerveModulePosition; -import edu.wpi.first.math.kinematics.SwerveModuleState; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.wpilibj.Alert; -import edu.wpi.first.wpilibj.Alert.AlertType; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.kinematics.SwerveModulePosition; +import org.wpilib.math.kinematics.SwerveModuleVelocity; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Current; +import org.wpilib.annotation.NoDiscard; +import org.wpilib.driverstation.Alert; +import org.wpilib.system.RobotController; import frc.robot.Constants; import frc.robot.Constants.Mode; import org.littletonrobotics.junction.Logger; @@ -49,14 +49,14 @@ public Module( driveDisconnectedAlert = new Alert( "Disconnected drive motor on module " + Integer.toString(index) + ".", - AlertType.kError); + Alert.Level.HIGH); turnDisconnectedAlert = new Alert( - "Disconnected turn motor on module " + Integer.toString(index) + ".", AlertType.kError); + "Disconnected turn motor on module " + Integer.toString(index) + ".", Alert.Level.HIGH); turnEncoderDisconnectedAlert = new Alert( "Disconnected turn encoder on module " + Integer.toString(index) + ".", - AlertType.kError); + Alert.Level.HIGH); loggerKey = "Drive/Module" + Integer.toString(index); } @@ -99,13 +99,13 @@ public double getSupplyCurrentAmps() { } /** Runs the module with the specified setpoint state. Mutates the state to optimize it. */ - public void runSetpoint(SwerveModuleState state) { + public void runSetpoint(SwerveModuleVelocity state) { // Optimize velocity setpoint - state.optimize(getAngle()); - state.cosineScale(inputs.turnPosition); + state = state.optimize(getAngle()); + state = state.cosineScale(inputs.turnPosition); // Apply setpoints - io.setDriveVelocity(state.speedMetersPerSecond / constants.WheelRadius); + io.setDriveVelocity(state.velocity / constants.WheelRadius); io.setTurnPosition(state.angle); } @@ -142,8 +142,8 @@ public SwerveModulePosition getPosition() { } /** Returns the module state (turn angle and drive velocity). */ - public SwerveModuleState getState() { - return new SwerveModuleState(getVelocityMetersPerSec(), getAngle()); + public SwerveModuleVelocity getState() { + return new SwerveModuleVelocity(getVelocityMetersPerSec(), getAngle()); } /** Returns the module positions received this cycle. */ diff --git a/src/main/java/frc/robot/subsystems/drive/ModuleIO.java b/src/main/java/frc/robot/subsystems/drive/ModuleIO.java index 962761c2..4eb70685 100644 --- a/src/main/java/frc/robot/subsystems/drive/ModuleIO.java +++ b/src/main/java/frc/robot/subsystems/drive/ModuleIO.java @@ -8,8 +8,8 @@ package frc.robot.subsystems.drive; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.units.measure.Current; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.units.measure.Current; import org.littletonrobotics.junction.AutoLog; public interface ModuleIO { diff --git a/src/main/java/frc/robot/subsystems/drive/ModuleIOSim.java b/src/main/java/frc/robot/subsystems/drive/ModuleIOSim.java index c9870d68..3725c426 100644 --- a/src/main/java/frc/robot/subsystems/drive/ModuleIOSim.java +++ b/src/main/java/frc/robot/subsystems/drive/ModuleIOSim.java @@ -11,14 +11,13 @@ import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.swerve.SwerveModuleConstants; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.MathUtil; -import edu.wpi.first.math.controller.PIDController; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.system.plant.DCMotor; -import edu.wpi.first.math.system.plant.LinearSystemId; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import org.wpilib.math.controller.PIDController; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.system.DCMotor; +import org.wpilib.math.system.Models; +import org.wpilib.math.util.Units; +import org.wpilib.system.Timer; +import org.wpilib.simulation.DCMotorSim; /** * Physics sim implementation of module IO. The sim models are configured using a set of module @@ -55,12 +54,12 @@ public ModuleIOSim( // Create drive and turn sim models driveSim = new DCMotorSim( - LinearSystemId.createDCMotorSystem( + Models.singleJointedArmFromPhysicalConstants( DRIVE_GEARBOX, constants.DriveInertia, constants.DriveMotorGearRatio), DRIVE_GEARBOX); turnSim = new DCMotorSim( - LinearSystemId.createDCMotorSystem( + Models.singleJointedArmFromPhysicalConstants( TURN_GEARBOX, constants.SteerInertia, constants.SteerMotorGearRatio), TURN_GEARBOX); @@ -73,41 +72,41 @@ public void updateInputs(ModuleIOInputs inputs) { // Run closed-loop control if (driveClosedLoop) { driveAppliedVolts = - driveFFVolts + driveController.calculate(driveSim.getAngularVelocityRadPerSec()); + driveFFVolts + driveController.calculate(driveSim.getAngularVelocity()); } else { driveController.reset(); } if (turnClosedLoop) { - turnAppliedVolts = turnController.calculate(turnSim.getAngularPositionRad()); + turnAppliedVolts = turnController.calculate(turnSim.getAngularPosition()); } else { turnController.reset(); } // Update simulation state - driveSim.setInputVoltage(MathUtil.clamp(driveAppliedVolts, -12.0, 12.0)); - turnSim.setInputVoltage(MathUtil.clamp(turnAppliedVolts, -12.0, 12.0)); + driveSim.setInputVoltage(Math.clamp(driveAppliedVolts, -12.0, 12.0)); + turnSim.setInputVoltage(Math.clamp(turnAppliedVolts, -12.0, 12.0)); driveSim.update(0.02); turnSim.update(0.02); // Update drive inputs inputs.driveConnected = true; - inputs.drivePositionRad = driveSim.getAngularPositionRad(); - inputs.driveVelocityRadPerSec = driveSim.getAngularVelocityRadPerSec(); + inputs.drivePositionRad = driveSim.getAngularPosition(); + inputs.driveVelocityRadPerSec = driveSim.getAngularVelocity(); inputs.driveAppliedVolts = driveAppliedVolts; - inputs.driveCurrentAmps = Math.abs(driveSim.getCurrentDrawAmps()); + inputs.driveCurrentAmps = Math.abs(driveSim.getCurrentDraw()); // Update turn inputs inputs.turnConnected = true; inputs.turnEncoderConnected = true; - inputs.turnAbsolutePosition = new Rotation2d(turnSim.getAngularPositionRad()); - inputs.turnPosition = new Rotation2d(turnSim.getAngularPositionRad()); - inputs.turnVelocityRadPerSec = turnSim.getAngularVelocityRadPerSec(); + inputs.turnAbsolutePosition = new Rotation2d(turnSim.getAngularPosition()); + inputs.turnPosition = new Rotation2d(turnSim.getAngularPosition()); + inputs.turnVelocityRadPerSec = turnSim.getAngularVelocity(); inputs.turnAppliedVolts = turnAppliedVolts; - inputs.turnCurrentAmps = Math.abs(turnSim.getCurrentDrawAmps()); + inputs.turnCurrentAmps = Math.abs(turnSim.getCurrentDraw()); // Update odometry inputs (50Hz because high-frequency odometry in sim doesn't // matter) - inputs.odometryTimestamps = new double[] {Timer.getFPGATimestamp()}; + inputs.odometryTimestamps = new double[] {Timer.getTimestamp()}; inputs.odometryDrivePositionsRad = new double[] {inputs.drivePositionRad}; inputs.odometryTurnPositions = new Rotation2d[] {inputs.turnPosition}; } diff --git a/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFX.java b/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFX.java index d412eefa..65723c9f 100644 --- a/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFX.java +++ b/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFX.java @@ -31,13 +31,13 @@ import coppercore.wpilib_interface.subsystems.StatusSignalRefresher; import coppercore.wpilib_interface.subsystems.configs.CANDeviceID; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Voltage; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Voltage; import frc.robot.constants.JsonConstants; import java.util.Queue; diff --git a/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFXS.java b/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFXS.java index 46a56565..bddb582a 100644 --- a/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFXS.java +++ b/src/main/java/frc/robot/subsystems/drive/ModuleIOTalonFXS.java @@ -26,13 +26,13 @@ import com.ctre.phoenix6.signals.NeutralModeValue; import com.ctre.phoenix6.swerve.SwerveModuleConstants; import coppercore.wpilib_interface.tuning.PIDGains; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Current; -import edu.wpi.first.units.measure.Voltage; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Current; +import org.wpilib.units.measure.Voltage; import frc.robot.constants.JsonConstants; import java.util.Queue; diff --git a/src/main/java/frc/robot/subsystems/drive/PhoenixOdometryThread.java b/src/main/java/frc/robot/subsystems/drive/PhoenixOdometryThread.java index 60390e4f..8e4335ca 100644 --- a/src/main/java/frc/robot/subsystems/drive/PhoenixOdometryThread.java +++ b/src/main/java/frc/robot/subsystems/drive/PhoenixOdometryThread.java @@ -9,8 +9,8 @@ import com.ctre.phoenix6.BaseStatusSignal; import com.ctre.phoenix6.StatusSignal; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.units.measure.Angle; +import org.wpilib.system.RobotController; import frc.robot.constants.JsonConstants; import java.util.ArrayList; import java.util.List; @@ -131,7 +131,7 @@ public void run() { // Sample timestamp is current FPGA time minus average CAN latency // Default timestamps from Phoenix are NOT compatible with // FPGA timestamps, this solution is imperfect but close - double timestamp = RobotController.getFPGATime() / 1e6; + double timestamp = RobotController.getTime() / 1e6; double totalLatency = 0.0; for (BaseStatusSignal signal : phoenixSignals) { totalLatency += signal.getTimestamp().getLatency(); diff --git a/src/main/java/frc/robot/subsystems/hood/HoodState.java b/src/main/java/frc/robot/subsystems/hood/HoodState.java index 8fd147b8..7dcc00a8 100644 --- a/src/main/java/frc/robot/subsystems/hood/HoodState.java +++ b/src/main/java/frc/robot/subsystems/hood/HoodState.java @@ -1,10 +1,10 @@ package frc.robot.subsystems.hood; -import static edu.wpi.first.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RadiansPerSecond; import coppercore.controls.state_machine.State; import coppercore.controls.state_machine.StateMachine; -import edu.wpi.first.units.AngularVelocityUnit; +import org.wpilib.units.AngularVelocityUnit; import frc.robot.constants.JsonConstants; /** diff --git a/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java b/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java index 2cb9b533..d5f14f9b 100644 --- a/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java +++ b/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java @@ -1,13 +1,13 @@ package frc.robot.subsystems.hood; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RotationsPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import coppercore.controls.state_machine.StateMachine; import coppercore.math.Lazy; @@ -20,13 +20,12 @@ import coppercore.wpilib_interface.subsystems.motors.MotorInputsAutoLogged; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.units.AngularVelocityUnit; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.MutAngle; -import edu.wpi.first.wpilibj.Alert.AlertType; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.units.AngularVelocityUnit; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.driverstation.Alert; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; import frc.robot.CoordinationLayer.ShotMode; import frc.robot.DependencyOrderedExecutor; import frc.robot.DependencyOrderedExecutor.ActionKey; @@ -108,13 +107,12 @@ private enum HoodAction { @AutoLogOutput(key = "Hood/action") private HoodAction requestedAction = HoodAction.Idle; - private MutAngle goalExitPitch = + private Angle goalExitPitch = JsonConstants.hoodConstants .minHoodAngle - .plus(JsonConstants.hoodConstants.mechanismAngleToExitAngle) - .mutableCopy(); + .plus(JsonConstants.hoodConstants.mechanismAngleToExitAngle); - private MutAngle goalAngle = JsonConstants.hoodConstants.minHoodAngle.mutableCopy(); + private Angle goalAngle = JsonConstants.hoodConstants.minHoodAngle; // Dependencies (values from other subsystems/coordination layer passed in by the coordination // layer via setters) @@ -145,7 +143,7 @@ public HoodSubsystem(DependencyOrderedExecutor dependencyOrderedExecutor, MotorI new MonitorWithAlertBuilder() .withName("HoodMotorDisconnected") .withAlertText("Hood motor disconnected") - .withAlertType(AlertType.kError) + .withAlertType(Alert.Level.HIGH) .withTimeToFault(JsonConstants.hoodConstants.disconnectedDebounceTimeSeconds) .withLoggingEnabled(true) .withStickyness(false) @@ -168,7 +166,7 @@ public HoodSubsystem(DependencyOrderedExecutor dependencyOrderedExecutor, MotorI .when(hood -> hood.isHomingSwitchPressed(), "Homing switch is pressed") .transitionTo(idleState); homingWaitForButtonState - .when(() -> DriverStation.isEnabled(), "Robot is enabled") + .when(() -> DriverStationBackend.isEnabled(), "Robot is enabled") .transitionTo(homingWaitForMovementState); homingWaitForMovementState @@ -281,12 +279,12 @@ private void updateInputs() { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); Logger.recordOutput("Hood/state", stateMachine.getCurrentState().getName()); stateMachine.periodic(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/hoodMs", (endTimeUs - startTimeUs) / 1000.0); } @@ -488,7 +486,7 @@ protected void controlToGoalAngle() { * @param goalAngle The Angle to target */ private void clampAndControlToAngle(Angle goalAngle) { - boolean shouldStowForShootingDisabled = !shootingEnabled && !DriverStation.isTest(); + boolean shouldStowForShootingDisabled = !shootingEnabled && !DriverStationBackend.isUtility(); boolean shouldStow = shouldStowForShootingDisabled || shouldStowForTrench || shouldStowForIntakeOrDefense; @@ -581,7 +579,7 @@ public boolean isAimedCorrectly(ShotMode shotMode) { */ public void targetExitPitch(Angle goalPitch) { this.requestedAction = HoodAction.TargetExitPitch; - this.goalExitPitch.mut_replace(goalPitch); + this.goalExitPitch = goalPitch; } /** @@ -596,6 +594,6 @@ public void targetExitPitch(Angle goalPitch) { */ public void targetAngleRadians(double angleRadians) { this.requestedAction = HoodAction.TargetAngle; - this.goalAngle.mut_replace(angleRadians, Radians); + this.goalAngle = new Angle(angleRadians, 1.0, Radians); } } diff --git a/src/main/java/frc/robot/subsystems/hopper/HopperSubsystem.java b/src/main/java/frc/robot/subsystems/hopper/HopperSubsystem.java index 3ab661dd..2584dcfc 100644 --- a/src/main/java/frc/robot/subsystems/hopper/HopperSubsystem.java +++ b/src/main/java/frc/robot/subsystems/hopper/HopperSubsystem.java @@ -1,10 +1,10 @@ package frc.robot.subsystems.hopper; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import coppercore.controls.state_machine.StateMachine; import coppercore.math.Lazy; @@ -18,13 +18,13 @@ import coppercore.wpilib_interface.tuning.TuningModeHelper.MotorTuningMode; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotor; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotorConfiguration; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.units.AngularVelocityUnit; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj.Timer; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.filter.Debouncer.DebounceType; +import org.wpilib.units.AngularVelocityUnit; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Voltage; +import org.wpilib.system.RobotController; +import org.wpilib.system.Timer; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.hopper.HopperState.DejamState; import frc.robot.subsystems.hopper.HopperState.IdleState; @@ -116,7 +116,7 @@ public HopperSubsystem(MotorIO motor) { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); motor.updateInputs(inputs); @@ -126,7 +126,7 @@ public void monitoredPeriodic() { Logger.recordOutput("Hopper/State", stateMachine.getCurrentState().getName()); stateMachine.periodic(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/hopperMs", (endTimeUs - startTimeUs) / 1000.0); } diff --git a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java index 0f827cec..adfa8a9b 100644 --- a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java @@ -1,8 +1,8 @@ package frc.robot.subsystems.indexer; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.Seconds; import coppercore.controls.state_machine.StateMachine; import coppercore.math.Lazy; @@ -16,10 +16,10 @@ import coppercore.wpilib_interface.tuning.TuningModeHelper.MotorTuningMode; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotor; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotorConfiguration; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.filter.Debouncer.DebounceType; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.system.RobotController; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.indexer.IndexerState.IdleState; import frc.robot.subsystems.indexer.IndexerState.ShootingState; @@ -132,7 +132,7 @@ public IndexerSubsystem(MotorIO motor) { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); motor.updateInputs(inputs); Logger.processInputs("Indexer/inputs", inputs); @@ -142,7 +142,7 @@ public void monitoredPeriodic() { Logger.recordOutput("Indexer/State", stateMachine.getCurrentState().getName()); stateMachine.periodic(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/indexerMs", (endTimeUs - startTimeUs) / 1000.0); } diff --git a/src/main/java/frc/robot/subsystems/intake/IntakeState.java b/src/main/java/frc/robot/subsystems/intake/IntakeState.java index 5fecab8a..77094e08 100644 --- a/src/main/java/frc/robot/subsystems/intake/IntakeState.java +++ b/src/main/java/frc/robot/subsystems/intake/IntakeState.java @@ -1,8 +1,8 @@ package frc.robot.subsystems.intake; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.Radians; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.Radians; import coppercore.controls.state_machine.State; import coppercore.controls.state_machine.StateMachine; @@ -12,7 +12,7 @@ import coppercore.wpilib_interface.tuning.TuningModeHelper.MotorTuningMode; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotor; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotorConfiguration; -import edu.wpi.first.units.Units; +import org.wpilib.units.Units; import frc.robot.constants.JsonConstants; import java.util.function.Supplier; diff --git a/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java index bec8fc28..c951352b 100644 --- a/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java @@ -1,9 +1,9 @@ package frc.robot.subsystems.intake; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Hertz; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.Radians; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Hertz; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.Radians; import coppercore.controls.state_machine.StateMachine; import coppercore.monitors.TotalCurrentCalculator; @@ -12,12 +12,12 @@ import coppercore.wpilib_interface.subsystems.motors.MotorIO; import coppercore.wpilib_interface.subsystems.motors.MotorInputsAutoLogged; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Voltage; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; import frc.robot.constants.JsonConstants; import frc.robot.util.StateMachineDump; import java.util.List; @@ -124,7 +124,7 @@ public IntakeSubsystem( // ### Homing Button Transitions IntakeState.waitForButtonState.whenFinished().transitionTo(IntakeState.controlToPositionState); IntakeState.waitForButtonState - .when(DriverStation::isEnabled, "When robot is enabled and button has not been pressed") + .when(DriverStationBackend::isEnabled, "When robot is enabled and button has not been pressed") .transitionTo(IntakeState.homingWaitForMovementState); // ### Wait for movement transitions @@ -132,7 +132,7 @@ public IntakeSubsystem( // the wait for button state to wait for the operator to re-enable the robot // and restart the homing process. IntakeState.homingWaitForMovementState - .when(DriverStation::isDisabled, "When robot is disabled during homing") + .when(DriverStationBackend::isDisabled, "When robot is disabled during homing") .transitionTo(IntakeState.waitForButtonState); // If the mechanism starts moving, we assume that it is has started the homing // process properly and we transition to the homing wait for stop moving state @@ -151,7 +151,7 @@ public IntakeSubsystem( // the wait for button state to wait for the operator to re-enable the robot // and restart the homing process. IntakeState.homingWaitForStopMovingState - .when(DriverStation::isDisabled, "When robot is disabled during homing") + .when(DriverStationBackend::isDisabled, "When robot is disabled during homing") .transitionTo(IntakeState.waitForButtonState); // If the mechanism starts moving, we assume that we have started the homing // process properly and so we wait for it to stop moving by hitting a hard @@ -216,7 +216,7 @@ public void applyHoldVoltage() { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); pivotMotorIO.updateInputs(pivotInputs); rollersLeadMotorIO.updateInputs(rollerLeadMotorInputs); @@ -251,7 +251,7 @@ public void monitoredPeriodic() { // at the end of the periodic rollersFollowerMotorIO.follow(JsonConstants.canBusAssignment.intakeRollersLeadMotorId, false); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/IntakeMs", (endTimeUs - startTimeUs) / 1000.0); } diff --git a/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java b/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java index f077683d..836776e6 100644 --- a/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java +++ b/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java @@ -1,12 +1,12 @@ package frc.robot.subsystems.shooter; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Second; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Second; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import coppercore.controls.state_machine.StateMachine; import coppercore.math.Lazy; @@ -19,15 +19,14 @@ import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.tuning.LoggedTunablePIDGains; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.math.util.Units; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.MutAngularVelocity; -import edu.wpi.first.units.measure.Voltage; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; -import edu.wpi.first.wpilibj.Timer; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.filter.Debouncer.DebounceType; +import org.wpilib.math.util.Units; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Voltage; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; +import org.wpilib.system.Timer; import frc.robot.CoordinationLayer.ShotMode; import frc.robot.DependencyOrderedExecutor; import frc.robot.DependencyOrderedExecutor.ActionKey; @@ -97,7 +96,7 @@ private enum ShooterAction { Lazy shooterTuningVolts; // State variables - private final MutAngularVelocity targetVelocity = RPM.mutable(0.0); + private AngularVelocity targetVelocity = RPM.of(0.0); @AutoLogOutput(key = "Shooter/requestedAction") private ShooterAction requestedAction = ShooterAction.Coast; @@ -206,7 +205,7 @@ private void updateInputs() { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); Logger.recordOutput("Shooter/TargetVelocityRadPerSec", targetVelocity.in(RadiansPerSecond)); @@ -228,7 +227,7 @@ public void monitoredPeriodic() { JsonConstants.shooterConstants.invertFollower); } - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/ShooterMs", (endTimeUs - startTimeUs) / 1000.0); } @@ -319,7 +318,7 @@ protected void testPeriodic() { leadMotor.controlOpenLoopVoltage(Volts.of(shooterTuningVolts.get().getAsDouble())); } case ShooterFFCharacterization -> { - if (DriverStation.isEnabled()) { + if (DriverStationBackend.isEnabled()) { Voltage characterizationVoltage = (Voltage) JsonConstants.shooterConstants.characterizationRampRate.times( @@ -364,7 +363,7 @@ protected void coast() { * @param velocityRPM A double containing target velocity, in RPM */ public void setTargetVelocityRPM(double velocityRPM) { - targetVelocity.mut_replace(velocityRPM, RPM); + targetVelocity = new AngularVelocity(velocityRPM, 1, RPM); requestedAction = ShooterAction.ControlVelocity; } diff --git a/src/main/java/frc/robot/subsystems/transferroller/TransferRollerSubsystem.java b/src/main/java/frc/robot/subsystems/transferroller/TransferRollerSubsystem.java index 859c70a7..cdd8acf3 100644 --- a/src/main/java/frc/robot/subsystems/transferroller/TransferRollerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/transferroller/TransferRollerSubsystem.java @@ -1,9 +1,9 @@ package frc.robot.subsystems.transferroller; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.RPM; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.Seconds; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.RPM; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.Seconds; import coppercore.controls.state_machine.StateMachine; import coppercore.math.Lazy; @@ -16,11 +16,11 @@ import coppercore.wpilib_interface.tuning.TuningModeHelper.MotorTuningMode; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotor; import coppercore.wpilib_interface.tuning.TuningModeHelper.TunableMotorConfiguration; -import edu.wpi.first.math.filter.Debouncer; -import edu.wpi.first.math.filter.Debouncer.DebounceType; -import edu.wpi.first.units.Units; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.math.filter.Debouncer; +import org.wpilib.math.filter.Debouncer.DebounceType; +import org.wpilib.units.Units; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.system.RobotController; import frc.robot.constants.JsonConstants; import frc.robot.subsystems.transferroller.TransferRollerState.DeJamState; import frc.robot.subsystems.transferroller.TransferRollerState.IdleState; @@ -138,7 +138,7 @@ public TransferRollerSubsystem(MotorIO motor) { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); motor.updateInputs(inputs); Logger.processInputs("TransferRoller/inputs", inputs); @@ -146,7 +146,7 @@ public void monitoredPeriodic() { Logger.recordOutput("TransferRoller/State", stateMachine.getCurrentState().getName()); stateMachine.periodic(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/TransferRollerMs", (endTimeUs - startTimeUs) / 1000.0); } diff --git a/src/main/java/frc/robot/subsystems/turret/TurretState.java b/src/main/java/frc/robot/subsystems/turret/TurretState.java index c09d0644..b9b457b8 100644 --- a/src/main/java/frc/robot/subsystems/turret/TurretState.java +++ b/src/main/java/frc/robot/subsystems/turret/TurretState.java @@ -1,11 +1,11 @@ package frc.robot.subsystems.turret; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.RadiansPerSecond; import coppercore.controls.state_machine.State; import coppercore.controls.state_machine.StateMachine; -import edu.wpi.first.units.AngularVelocityUnit; +import org.wpilib.units.AngularVelocityUnit; import frc.robot.constants.JsonConstants; /** diff --git a/src/main/java/frc/robot/subsystems/turret/TurretSubsystem.java b/src/main/java/frc/robot/subsystems/turret/TurretSubsystem.java index 498eccba..1cb41e6c 100644 --- a/src/main/java/frc/robot/subsystems/turret/TurretSubsystem.java +++ b/src/main/java/frc/robot/subsystems/turret/TurretSubsystem.java @@ -1,14 +1,14 @@ package frc.robot.subsystems.turret; -import static edu.wpi.first.units.Units.Amps; -import static edu.wpi.first.units.Units.Degrees; -import static edu.wpi.first.units.Units.Hertz; -import static edu.wpi.first.units.Units.Radians; -import static edu.wpi.first.units.Units.RadiansPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecond; -import static edu.wpi.first.units.Units.RotationsPerSecondPerSecond; -import static edu.wpi.first.units.Units.Seconds; -import static edu.wpi.first.units.Units.Volts; +import static org.wpilib.units.Units.Amps; +import static org.wpilib.units.Units.Degrees; +import static org.wpilib.units.Units.Hertz; +import static org.wpilib.units.Units.Radians; +import static org.wpilib.units.Units.RadiansPerSecond; +import static org.wpilib.units.Units.RotationsPerSecond; +import static org.wpilib.units.Units.RotationsPerSecondPerSecond; +import static org.wpilib.units.Units.Seconds; +import static org.wpilib.units.Units.Volts; import coppercore.controls.state_machine.StateMachine; import coppercore.math.AngleUtil; @@ -21,12 +21,13 @@ import coppercore.wpilib_interface.subsystems.motors.MotorInputsAutoLogged; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.tuning.TestModeManager; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.interpolation.InterpolatingDoubleTreeMap; -import edu.wpi.first.units.measure.Angle; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.RobotController; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.interpolation.InterpolatingDoubleTreeMap; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.driverstation.DriverStation; +import org.wpilib.driverstation.internal.DriverStationBackend; +import org.wpilib.system.RobotController; import frc.robot.Constants; import frc.robot.CoordinationLayer.ShotMode; import frc.robot.DependencyOrderedExecutor; @@ -164,7 +165,7 @@ public TurretSubsystem(DependencyOrderedExecutor dependencyOrderedExecutor, Moto .whenTimeout(Seconds.of(1.0)) .transitionTo(homingWaitForButtonChirpState); homingWaitForButtonState - .when(turret -> DriverStation.isEnabled(), "Robot is enabled") + .when(turret -> DriverStationBackend.isEnabled(), "Robot is enabled") .transitionTo(homingWaitForMovementState); homingWaitForButtonChirpState.whenFinished().transitionTo(idleState); @@ -172,7 +173,7 @@ public TurretSubsystem(DependencyOrderedExecutor dependencyOrderedExecutor, Moto .whenTimeout(Seconds.of(0.5)) .transitionTo(homingWaitForButtonState); homingWaitForButtonChirpState - .when(turret -> DriverStation.isEnabled(), "Robot is enabled") + .when(turret -> DriverStationBackend.isEnabled(), "Robot is enabled") .transitionTo(homingWaitForMovementState); homingWaitForMovementState.whenFinished().transitionTo(homingWaitForStoppingState); @@ -301,12 +302,12 @@ public void updateInputs() { @Override public void monitoredPeriodic() { - long startTimeUs = RobotController.getFPGATime(); + long startTimeUs = RobotController.getTime(); Logger.recordOutput("Turret/State", stateMachine.getCurrentState().getName()); stateMachine.periodic(); - long endTimeUs = RobotController.getFPGATime(); + long endTimeUs = RobotController.getTime(); if (JsonConstants.featureFlags.logPeriodicTiming) { Logger.recordOutput("PeriodicTime/TurretMs", (endTimeUs - startTimeUs) / 1000.0); } @@ -508,13 +509,13 @@ private void controlToTurretCentricPositionRaw(Angle goalAngleTurretCentric) { */ protected void controlToGoalHeading() { Rotation2d robotRelativeHeading = goalTurretHeading.minus(dependencies.robotHeading); - Rotation2d turretRelativeHeading = - AngleUtil.normalizeHeading( - robotRelativeHeading.plus( - new Rotation2d(JsonConstants.turretConstants.headingToTurretAngle))); + // Rotation2d turretRelativeHeading = + // AngleUtil.normalizeHeading( + // robotRelativeHeading.plus( + // new Rotation2d(JsonConstants.turretConstants.headingToTurretAngle))); - Angle adjustedGoalAngle = applyGoalAngleOffset(turretRelativeHeading.getMeasure()); - controlToTurretCentricPositionRaw(adjustedGoalAngle); + // Angle adjustedGoalAngle = applyGoalAngleOffset(turretRelativeHeading.getMeasure()); + // controlToTurretCentricPositionRaw(adjustedGoalAngle); } private Angle getGoalAngleOffset(Angle goalAngleTurretCentric) { @@ -533,15 +534,16 @@ private Angle applyGoalAngleOffset(Angle goalAngleTurretCentric) { private Rotation2d getAdjustedGoalTurretHeadingFieldCentric() { Rotation2d robotRelativeHeading = goalTurretHeading.minus(dependencies.robotHeading); - Rotation2d turretRelativeHeading = - AngleUtil.normalizeHeading( - robotRelativeHeading.plus( - new Rotation2d(JsonConstants.turretConstants.headingToTurretAngle))); - - Angle adjustedTurretAngle = applyGoalAngleOffset(turretRelativeHeading.getMeasure()); - return new Rotation2d( - adjustedTurretAngle.minus(JsonConstants.turretConstants.headingToTurretAngle)) - .plus(dependencies.robotHeading); + // Rotation2d turretRelativeHeading = + // AngleUtil.normalizeHeading( + // robotRelativeHeading.plus( + // new Rotation2d(JsonConstants.turretConstants.headingToTurretAngle))); + + // Angle adjustedTurretAngle = applyGoalAngleOffset(turretRelativeHeading.getMeasure()); + // return new Rotation2d( + // adjustedTurretAngle.minus(JsonConstants.turretConstants.headingToTurretAngle)) + // .plus(dependencies.robotHeading); + return new Rotation2d(); // TO BE REMOVED } /** diff --git a/src/main/java/frc/robot/util/CommandState.java b/src/main/java/frc/robot/util/CommandState.java index f45968b1..f304a18e 100644 --- a/src/main/java/frc/robot/util/CommandState.java +++ b/src/main/java/frc/robot/util/CommandState.java @@ -2,7 +2,7 @@ import coppercore.controls.state_machine.State; import coppercore.controls.state_machine.StateMachine; -import edu.wpi.first.wpilibj2.command.Command; +import org.wpilib.command2.Command; // Copilot used to help write the docs for this class diff --git a/src/main/java/frc/robot/util/Elastic.java b/src/main/java/frc/robot/util/Elastic.java index 9e5c07bc..102558eb 100644 --- a/src/main/java/frc/robot/util/Elastic.java +++ b/src/main/java/frc/robot/util/Elastic.java @@ -8,24 +8,25 @@ package frc.robot.util; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import edu.wpi.first.networktables.NetworkTableInstance; -import edu.wpi.first.networktables.PubSubOption; -import edu.wpi.first.networktables.StringPublisher; -import edu.wpi.first.networktables.StringTopic; +import io.avaje.jsonb.Json; +import io.avaje.jsonb.JsonType; +import io.avaje.jsonb.Jsonb; +import org.wpilib.networktables.NetworkTableInstance; +import org.wpilib.networktables.PubSubOption; +import org.wpilib.networktables.StringPublisher; +import org.wpilib.networktables.StringTopic; public final class Elastic { private static final StringTopic notificationTopic = NetworkTableInstance.getDefault().getStringTopic("/Elastic/RobotNotifications"); private static final StringPublisher notificationPublisher = - notificationTopic.publish(PubSubOption.sendAll(true), PubSubOption.keepDuplicates(true)); + notificationTopic.publish(new PubSubOption.SendAll(true), new PubSubOption.KeepDuplicates(true)); private static final StringTopic selectedTabTopic = NetworkTableInstance.getDefault().getStringTopic("/Elastic/SelectedTab"); private static final StringPublisher selectedTabPublisher = - selectedTabTopic.publish(PubSubOption.keepDuplicates(true)); - private static final ObjectMapper objectMapper = new ObjectMapper(); + selectedTabTopic.publish(new PubSubOption.KeepDuplicates(true)); + private static final Jsonb jsonb = Jsonb.builder().serializeNulls(true).build(); + private static final JsonType notificationJson = jsonb.type(Notification.class); /** * Represents the possible levels of notifications for the Elastic dashboard. These levels are @@ -48,8 +49,8 @@ public enum NotificationLevel { */ public static void sendNotification(Notification notification) { try { - notificationPublisher.set(objectMapper.writeValueAsString(notification)); - } catch (JsonProcessingException e) { + notificationPublisher.set(notificationJson.toJson(notification)); + } catch (RuntimeException e) { e.printStackTrace(); } } @@ -82,23 +83,19 @@ public static void selectTab(int tabIndex) { * properties such as level, title, description, display time, and dimensions to control how the * notification is displayed on the dashboard. */ + @Json public static class Notification { - @JsonProperty("level") private NotificationLevel level; - @JsonProperty("title") private String title; - @JsonProperty("description") private String description; - @JsonProperty("displayTime") + @Json.Property("displayTime") private int displayTimeMillis; - @JsonProperty("width") private double width; - @JsonProperty("height") private double height; /** diff --git a/src/main/java/frc/robot/util/LocalADStarAK.java b/src/main/java/frc/robot/util/LocalADStarAK.java index 846dd043..82a51a07 100644 --- a/src/main/java/frc/robot/util/LocalADStarAK.java +++ b/src/main/java/frc/robot/util/LocalADStarAK.java @@ -13,8 +13,8 @@ import com.pathplanner.lib.path.PathPoint; import com.pathplanner.lib.pathfinding.LocalADStar; import com.pathplanner.lib.pathfinding.Pathfinder; -import edu.wpi.first.math.Pair; -import edu.wpi.first.math.geometry.Translation2d; +import org.wpilib.math.util.Pair; +import org.wpilib.math.geometry.Translation2d; import java.util.ArrayList; import java.util.Collections; import java.util.List; diff --git a/src/main/java/frc/robot/util/json/JSONAPTarget.java b/src/main/java/frc/robot/util/json/JSONAPTarget.java index 5ab6d8d5..05251512 100644 --- a/src/main/java/frc/robot/util/json/JSONAPTarget.java +++ b/src/main/java/frc/robot/util/json/JSONAPTarget.java @@ -2,9 +2,9 @@ import com.therekrab.autopilot.APTarget; import coppercore.parameter_tools.json.helpers.JSONObject; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.units.measure.Distance; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.units.measure.Distance; import java.lang.reflect.Constructor; public class JSONAPTarget extends JSONObject { diff --git a/src/main/java/frc/robot/util/json/JSONMotionProfileConfig.java b/src/main/java/frc/robot/util/json/JSONMotionProfileConfig.java index e9670742..1c44cbdd 100644 --- a/src/main/java/frc/robot/util/json/JSONMotionProfileConfig.java +++ b/src/main/java/frc/robot/util/json/JSONMotionProfileConfig.java @@ -3,13 +3,13 @@ import coppercore.parameter_tools.json.helpers.JSONObject; import coppercore.wpilib_interface.subsystems.motors.profile.MotionProfileConfig; import coppercore.wpilib_interface.subsystems.motors.profile.MutableMotionProfileConfig; -import edu.wpi.first.units.AngularAccelerationUnit; -import edu.wpi.first.units.AngularVelocityUnit; -import edu.wpi.first.units.VoltageUnit; -import edu.wpi.first.units.measure.AngularAcceleration; -import edu.wpi.first.units.measure.AngularVelocity; -import edu.wpi.first.units.measure.Per; -import edu.wpi.first.units.measure.Velocity; +import org.wpilib.units.AngularAccelerationUnit; +import org.wpilib.units.AngularVelocityUnit; +import org.wpilib.units.VoltageUnit; +import org.wpilib.units.measure.AngularAcceleration; +import org.wpilib.units.measure.AngularVelocity; +import org.wpilib.units.measure.Per; +import org.wpilib.units.measure.Velocity; import java.lang.reflect.Constructor; public class JSONMotionProfileConfig extends JSONObject { diff --git a/src/main/java/frc/robot/util/littletonUtil/GeomUtil.java b/src/main/java/frc/robot/util/littletonUtil/GeomUtil.java index a64630ca..159a88a5 100644 --- a/src/main/java/frc/robot/util/littletonUtil/GeomUtil.java +++ b/src/main/java/frc/robot/util/littletonUtil/GeomUtil.java @@ -9,18 +9,18 @@ // license that can be found in the LICENSE file at // the root directory of this project. -import static edu.wpi.first.units.Units.Degrees; - -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Pose3d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Rotation3d; -import edu.wpi.first.math.geometry.Transform2d; -import edu.wpi.first.math.geometry.Transform3d; -import edu.wpi.first.math.geometry.Translation2d; -import edu.wpi.first.math.geometry.Twist2d; -import edu.wpi.first.math.kinematics.ChassisSpeeds; -import edu.wpi.first.units.measure.Angle; +import static org.wpilib.units.Units.Degrees; + +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Pose3d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Rotation3d; +import org.wpilib.math.geometry.Transform2d; +import org.wpilib.math.geometry.Transform3d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.geometry.Twist2d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.units.measure.Angle; /** Geometry utilities for working with translations, rotations, transforms, and poses. */ public class GeomUtil { @@ -129,9 +129,9 @@ public static Pose3d toPose3d(Transform3d transform) { * @param speeds The original translation * @return The resulting translation */ - public static Twist2d toTwist2d(ChassisSpeeds speeds) { + public static Twist2d toTwist2d(ChassisVelocities speeds) { return new Twist2d( - speeds.vxMetersPerSecond, speeds.vyMetersPerSecond, speeds.omegaRadiansPerSecond); + speeds.vx, speeds.vy, speeds.omega); } /** diff --git a/src/main/java/frc/robot/util/littletonUtil/PoseEstimator.java b/src/main/java/frc/robot/util/littletonUtil/PoseEstimator.java index dd2fe7eb..61db60da 100644 --- a/src/main/java/frc/robot/util/littletonUtil/PoseEstimator.java +++ b/src/main/java/frc/robot/util/littletonUtil/PoseEstimator.java @@ -10,14 +10,14 @@ package frc.robot.util.littletonUtil; -import edu.wpi.first.math.Matrix; -import edu.wpi.first.math.Nat; -import edu.wpi.first.math.VecBuilder; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Twist2d; -import edu.wpi.first.math.numbers.N1; -import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.wpilibj.Timer; +import org.wpilib.math.linalg.Matrix; +import org.wpilib.math.util.Nat; +import org.wpilib.math.linalg.VecBuilder; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Twist2d; +import org.wpilib.math.numbers.N1; +import org.wpilib.math.numbers.N3; +import org.wpilib.system.Timer; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -124,12 +124,12 @@ private void update() { private static record PoseUpdate(Twist2d twist, ArrayList visionUpdates) { public Pose2d apply(Pose2d lastPose, Matrix q) { // Apply drive twist - var pose = lastPose.exp(twist); + var pose = lastPose.plus(twist.exp()); // Apply vision updates for (VisionUpdate visionUpdate : visionUpdates) { // Calculate Kalman gains based on std devs - // (https://github.com/wpilibsuite/allwpilib/blob/main/wpimath/src/main/java/edu/wpi/first/math/estimator/) + // (https://github.com/wpilibsuite/allwpilib/blob/main/wpimath/src/main/java/org.wpilib.math/estimator/) Matrix visionK = new Matrix<>(Nat.N3(), Nat.N3()); var r = new double[3]; for (int i = 0; i < 3; ++i) { @@ -145,7 +145,7 @@ public Pose2d apply(Pose2d lastPose, Matrix q) { } // Calculate twist between current and vision pose - var visionTwist = pose.log(visionUpdate.pose()); + var visionTwist = visionUpdate.pose().minus(pose).log(); // Multiply by Kalman gain matrix var twistMatrix = @@ -153,8 +153,8 @@ public Pose2d apply(Pose2d lastPose, Matrix q) { // Apply twist pose = - pose.exp( - new Twist2d(twistMatrix.get(0, 0), twistMatrix.get(1, 0), twistMatrix.get(2, 0))); + pose.plus( + new Twist2d(twistMatrix.get(0, 0), twistMatrix.get(1, 0), twistMatrix.get(2, 0)).exp()); } return pose; diff --git a/vendordeps/AdvantageKit.json b/vendordeps/AdvantageKit.json index 469ae542..177ee85c 100644 --- a/vendordeps/AdvantageKit.json +++ b/vendordeps/AdvantageKit.json @@ -1,35 +1,35 @@ { - "fileName": "AdvantageKit.json", - "name": "AdvantageKit", - "version": "26.0.2", - "uuid": "d820cc26-74e3-11ec-90d6-0242ac120003", - "frcYear": "2026", - "mavenUrls": [ - "https://frcmaven.wpi.edu/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": "26.0.2" - } - ], - "jniDependencies": [ - { - "groupId": "org.littletonrobotics.akit", - "artifactId": "akit-wpilibio", - "version": "26.0.2", - "skipInvalidPlatforms": false, - "isJar": false, - "validPlatforms": [ - "linuxathena", - "linuxx86-64", - "linuxarm64", - "osxuniversal", - "windowsx86-64" - ] - } - ], - "cppDependencies": [] -} + "fileName": "AdvantageKit.json", + "name": "AdvantageKit", + "version": "27.0.0-alpha-4", + "uuid": "d820cc26-74e3-11ec-90d6-0242ac120003", + "wpilibYear": "2027_alpha5", + "mavenUrls": [ + "https://frcmaven.wpi.edu/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/Autopilot.json b/vendordeps/Autopilot.json deleted file mode 100644 index 3575aeb2..00000000 --- a/vendordeps/Autopilot.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "Autopilot", - "uuid": "4e922d47-9954-4db5-929f-c708cc62e152", - "fileName": "Autopilot.json", - "version": "1.5.0", - "frcYear": "2026", - "jsonUrl": "https://therekrab.github.io/autopilot/vendordep.json", - "mavenUrls": [ - "https://jitpack.io" - ], - "javaDependencies": [ - { - "groupId": "com.github.therekrab", - "artifactId": "autopilot", - "version": "1.5.0" - } - ], - "cppDependencies": [], - "jniDependencies": [] -} diff --git a/vendordeps/CommandsV2.json b/vendordeps/CommandsV2.json new file mode 100644 index 00000000..984c221c --- /dev/null +++ b/vendordeps/CommandsV2.json @@ -0,0 +1,46 @@ +{ + "fileName": "CommandsV2.json", + "name": "Commands V2", + "version": "1.0.0", + "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", + "wpilibYear": "2027_alpha5", + "mavenUrls": [], + "jsonUrl": "", + "conflictsWith": [ + { + "uuid": "4decdc05-a056-46cf-9561-39449bbb01306", + "errorMessage": "Users can not have both Commands v2 and Commands v3 vendordeps in their robot program.", + "offlineFileName": "CommandsV3.json" + } + ], + "javaDependencies": [ + { + "groupId": "org.wpilib.commandsv2", + "artifactId": "commandsv2-java", + "version": "wpilib" + } + ], + "jniDependencies": [], + "cppDependencies": [ + { + "groupId": "org.wpilib.commandsv2", + "artifactId": "commandsv2-cpp", + "version": "wpilib", + "libName": "commandsv2", + "headerClassifier": "headers", + "sourcesClassifier": "sources", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "linuxsystemcore", + "linuxathena", + "linuxarm32", + "linuxarm64", + "windowsx86-64", + "windowsx86", + "linuxx86-64", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/vendordeps/PathplannerLib.json b/vendordeps/PathplannerLib.json deleted file mode 100644 index 5f04ffa7..00000000 --- a/vendordeps/PathplannerLib.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "fileName": "PathplannerLib-2026.1.2.json", - "name": "PathplannerLib", - "version": "2026.1.2", - "uuid": "1b42324f-17c6-4875-8e77-1c312bc8c786", - "frcYear": "2026", - "mavenUrls": [ - "https://3015rangerrobotics.github.io/pathplannerlib/repo" - ], - "jsonUrl": "https://3015rangerrobotics.github.io/pathplannerlib/PathplannerLib.json", - "javaDependencies": [ - { - "groupId": "com.pathplanner.lib", - "artifactId": "PathplannerLib-java", - "version": "2026.1.2" - } - ], - "jniDependencies": [], - "cppDependencies": [ - { - "groupId": "com.pathplanner.lib", - "artifactId": "PathplannerLib-cpp", - "version": "2026.1.2", - "libName": "PathplannerLib", - "headerClassifier": "headers", - "sharedLibrary": false, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "osxuniversal", - "linuxathena", - "linuxarm32", - "linuxarm64" - ] - } - ] -} diff --git a/vendordeps/PathplannerLibSystemCoreAlpha.json b/vendordeps/PathplannerLibSystemCoreAlpha.json new file mode 100644 index 00000000..24d3c8c7 --- /dev/null +++ b/vendordeps/PathplannerLibSystemCoreAlpha.json @@ -0,0 +1,37 @@ +{ + "fileName": "PathplannerLibSystemCoreAlpha.json", + "name": "PathplannerLib", + "version": "2027.0.0-alpha-3", + "uuid": "1b42324f-17c6-4875-8e77-1c312bc8c786", + "wpilibYear": "2027_alpha5", + "mavenUrls": [ + "https://3015rangerrobotics.github.io/pathplannerlib/repo" + ], + "jsonUrl": "https://3015rangerrobotics.github.io/pathplannerlib/PathplannerLibSystemCoreAlpha.json", + "javaDependencies": [ + { + "groupId": "com.pathplanner.lib", + "artifactId": "PathplannerLib-java", + "version": "2027.0.0-alpha-3" + } + ], + "jniDependencies": [], + "cppDependencies": [ + { + "groupId": "com.pathplanner.lib", + "artifactId": "PathplannerLib-cpp", + "version": "2027.0.0-alpha-3", + "libName": "PathplannerLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "osxuniversal", + "linuxsystemcore", + "linuxarm64" + ] + } + ] +} \ No newline at end of file diff --git a/vendordeps/Phoenix6-26.1.2.json b/vendordeps/Phoenix6-26.1.2.json deleted file mode 100644 index d33c02b6..00000000 --- a/vendordeps/Phoenix6-26.1.2.json +++ /dev/null @@ -1,449 +0,0 @@ -{ - "fileName": "Phoenix6-26.1.2.json", - "name": "CTRE-Phoenix (v6)", - "version": "26.1.2", - "frcYear": "2026", - "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-frc2026-latest.json", - "conflictsWith": [ - { - "uuid": "e7900d8d-826f-4dca-a1ff-182f658e98af", - "errorMessage": "Users can not have both the replay and regular Phoenix 6 vendordeps in their robot program.", - "offlineFileName": "Phoenix6-replay-frc2026-latest.json" - } - ], - "javaDependencies": [ - { - "groupId": "com.ctre.phoenix6", - "artifactId": "wpiapi-java", - "version": "26.1.2" - } - ], - "jniDependencies": [ - { - "groupId": "com.ctre.phoenix6", - "artifactId": "api-cpp", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "linuxathena" - ], - "simMode": "hwsim" - }, - { - "groupId": "com.ctre.phoenix6", - "artifactId": "tools", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "linuxathena" - ], - "simMode": "hwsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "api-cpp-sim", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "tools-sim", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simTalonSRX", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simVictorSPX", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simPigeonIMU", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProTalonFX", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProTalonFXS", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProCANcoder", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProPigeon2", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProCANrange", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProCANdi", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "simProCANdle", - "version": "26.1.2", - "isJar": false, - "skipInvalidPlatforms": true, - "validPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - } - ], - "cppDependencies": [ - { - "groupId": "com.ctre.phoenix6", - "artifactId": "wpiapi-cpp", - "version": "26.1.2", - "libName": "CTRE_Phoenix6_WPI", - "headerClassifier": "headers", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "linuxathena" - ], - "simMode": "hwsim" - }, - { - "groupId": "com.ctre.phoenix6", - "artifactId": "tools", - "version": "26.1.2", - "libName": "CTRE_PhoenixTools", - "headerClassifier": "headers", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "linuxathena" - ], - "simMode": "hwsim" - }, - { - "groupId": "com.ctre.phoenix6.sim", - "artifactId": "wpiapi-cpp-sim", - "version": "26.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "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.1.2", - "libName": "CTRE_SimProCANdle", - "headerClassifier": "headers", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxx86-64", - "linuxarm64", - "osxuniversal" - ], - "simMode": "swsim" - } - ] -} 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 00000000..f7db60ad --- /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 diff --git a/vendordeps/REVLib.json b/vendordeps/REVLib.json index 082b01dc..2861f9e2 100644 --- a/vendordeps/REVLib.json +++ b/vendordeps/REVLib.json @@ -1,133 +1,126 @@ { - "fileName": "REVLib.json", - "name": "REVLib", - "version": "2026.0.0", - "frcYear": "2026", - "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", - "mavenUrls": [ - "https://maven.revrobotics.com/" - ], - "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2026.json", - "javaDependencies": [ - { - "groupId": "com.revrobotics.frc", - "artifactId": "REVLib-java", - "version": "2026.0.0" - } - ], - "jniDependencies": [ - { - "groupId": "com.revrobotics.frc", - "artifactId": "REVLib-driver", - "version": "2026.0.0", - "skipInvalidPlatforms": true, - "isJar": false, - "validPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - }, - { - "groupId": "com.revrobotics.frc", - "artifactId": "RevLibBackendDriver", - "version": "2026.0.0", - "skipInvalidPlatforms": true, - "isJar": false, - "validPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - }, - { - "groupId": "com.revrobotics.frc", - "artifactId": "RevLibWpiBackendDriver", - "version": "2026.0.0", - "skipInvalidPlatforms": true, - "isJar": false, - "validPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - } - ], - "cppDependencies": [ - { - "groupId": "com.revrobotics.frc", - "artifactId": "REVLib-cpp", - "version": "2026.0.0", - "libName": "REVLib", - "headerClassifier": "headers", - "sharedLibrary": false, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - }, - { - "groupId": "com.revrobotics.frc", - "artifactId": "REVLib-driver", - "version": "2026.0.0", - "libName": "REVLibDriver", - "headerClassifier": "headers", - "sharedLibrary": false, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - }, - { - "groupId": "com.revrobotics.frc", - "artifactId": "RevLibBackendDriver", - "version": "2026.0.0", - "libName": "BackendDriver", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - }, - { - "groupId": "com.revrobotics.frc", - "artifactId": "RevLibWpiBackendDriver", - "version": "2026.0.0", - "libName": "REVLibWpi", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxarm64", - "linuxx86-64", - "linuxathena", - "linuxarm32", - "osxuniversal" - ] - } - ] -} + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2027.0.0-alpha-6", + "wpilibYear": "2027_alpha5", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2027.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2027.0.0-alpha-6" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2027.0.0-alpha-6", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2027.0.0-alpha-6", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2027.0.0-alpha-6", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2027.0.0-alpha-6", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2027.0.0-alpha-6", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2027.0.0-alpha-6", + "libName": "BackendDriver", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2027.0.0-alpha-6", + "libName": "REVLibWpi", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxsystemcore", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/vendordeps/WPILibNewCommands.json b/vendordeps/WPILibNewCommands.json deleted file mode 100644 index c54ae11f..00000000 --- a/vendordeps/WPILibNewCommands.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "fileName": "WPILibNewCommands.json", - "name": "WPILib-New-Commands", - "version": "1.0.0", - "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", - "frcYear": "2026", - "mavenUrls": [], - "jsonUrl": "", - "javaDependencies": [ - { - "groupId": "edu.wpi.first.wpilibNewCommands", - "artifactId": "wpilibNewCommands-java", - "version": "wpilib" - } - ], - "jniDependencies": [], - "cppDependencies": [ - { - "groupId": "edu.wpi.first.wpilibNewCommands", - "artifactId": "wpilibNewCommands-cpp", - "version": "wpilib", - "libName": "wpilibNewCommands", - "headerClassifier": "headers", - "sourcesClassifier": "sources", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "linuxathena", - "linuxarm32", - "linuxarm64", - "windowsx86-64", - "windowsx86", - "linuxx86-64", - "osxuniversal" - ] - } - ] -} diff --git a/vendordeps/photonlib.json b/vendordeps/photonlib.json index 529f17b5..cb947f85 100644 --- a/vendordeps/photonlib.json +++ b/vendordeps/photonlib.json @@ -1,71 +1,71 @@ { - "fileName": "photonlib.json", - "name": "photonlib", - "version": "v2026.3.2", - "uuid": "515fe07e-bfc6-11fa-b3de-0242ac130004", - "frcYear": "2026", - "mavenUrls": [ - "https://maven.photonvision.org/repository/internal", - "https://maven.photonvision.org/repository/snapshots" - ], - "jsonUrl": "https://maven.photonvision.org/repository/internal/org/photonvision/photonlib-json/1.0/photonlib-json-1.0.json", - "jniDependencies": [ - { - "groupId": "org.photonvision", - "artifactId": "photontargeting-cpp", - "version": "v2026.3.2", - "skipInvalidPlatforms": true, - "isJar": false, - "validPlatforms": [ - "windowsx86-64", - "linuxathena", - "linuxx86-64", - "osxuniversal" - ] - } - ], - "cppDependencies": [ - { - "groupId": "org.photonvision", - "artifactId": "photonlib-cpp", - "version": "v2026.3.2", - "libName": "photonlib", - "headerClassifier": "headers", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxathena", - "linuxx86-64", - "osxuniversal" - ] - }, - { - "groupId": "org.photonvision", - "artifactId": "photontargeting-cpp", - "version": "v2026.3.2", - "libName": "photontargeting", - "headerClassifier": "headers", - "sharedLibrary": true, - "skipInvalidPlatforms": true, - "binaryPlatforms": [ - "windowsx86-64", - "linuxathena", - "linuxx86-64", - "osxuniversal" - ] - } - ], - "javaDependencies": [ - { - "groupId": "org.photonvision", - "artifactId": "photonlib-java", - "version": "v2026.3.2" - }, - { - "groupId": "org.photonvision", - "artifactId": "photontargeting-java", - "version": "v2026.3.2" - } - ] -} + "fileName": "photonlib.json", + "name": "photonlib", + "version": "v2027.0.0-alpha-2", + "uuid": "515fe07e-bfc6-11fa-b3de-0242ac130004", + "wpilibYear": "2027_alpha5", + "mavenUrls": [ + "https://maven.photonvision.org/repository/internal", + "https://maven.photonvision.org/repository/snapshots" + ], + "jsonUrl": "https://maven.photonvision.org/repository/internal/org/photonvision/photonlib-json/1.0/photonlib-json-1.0.json", + "jniDependencies": [ + { + "groupId": "org.photonvision", + "artifactId": "photontargeting-cpp", + "version": "v2027.0.0-alpha-2", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxsystemcore", + "linuxx86-64", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "org.photonvision", + "artifactId": "photonlib-cpp", + "version": "v2027.0.0-alpha-2", + "libName": "photonlib", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxsystemcore", + "linuxx86-64", + "osxuniversal" + ] + }, + { + "groupId": "org.photonvision", + "artifactId": "photontargeting-cpp", + "version": "v2027.0.0-alpha-2", + "libName": "photontargeting", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxsystemcore", + "linuxx86-64", + "osxuniversal" + ] + } + ], + "javaDependencies": [ + { + "groupId": "org.photonvision", + "artifactId": "photonlib-java", + "version": "v2027.0.0-alpha-2" + }, + { + "groupId": "org.photonvision", + "artifactId": "photontargeting-java", + "version": "v2027.0.0-alpha-2" + } + ] +} \ No newline at end of file From 1f55ebf4453af025c0f866057134040023502d10 Mon Sep 17 00:00:00 2001 From: Theta Back Date: Tue, 8 Sep 2026 10:24:29 -0400 Subject: [PATCH 2/8] (#1) added autopilot locally, tried running in sim --- build.gradle | 1 - simgui-ds.json | 56 +++++ .../therekrab/autopilot/APConstraints.java | 122 ++++++++++ .../com/therekrab/autopilot/APProfile.java | 109 +++++++++ .../com/therekrab/autopilot/APTarget.java | 135 +++++++++++ .../com/therekrab/autopilot/Autopilot.java | 217 ++++++++++++++++++ 6 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 simgui-ds.json create mode 100644 src/main/java/com/therekrab/autopilot/APConstraints.java create mode 100644 src/main/java/com/therekrab/autopilot/APProfile.java create mode 100644 src/main/java/com/therekrab/autopilot/APTarget.java create mode 100644 src/main/java/com/therekrab/autopilot/Autopilot.java diff --git a/build.gradle b/build.gradle index 1e9f37df..364b6ed6 100644 --- a/build.gradle +++ b/build.gradle @@ -102,7 +102,6 @@ dependencies { implementation "io.github.team401.coppercore:vision:$coppercoreVersion" implementation "io.github.team401.coppercore:wpilib_interface:$coppercoreVersion" implementation "io.github.team401.coppercore:metadata:$coppercoreVersion" - implementation "com.github.therekrab:autopilot:1.7.0-alpha-7" } test { diff --git a/simgui-ds.json b/simgui-ds.json new file mode 100644 index 00000000..cb2b8b0c --- /dev/null +++ b/simgui-ds.json @@ -0,0 +1,56 @@ +{"keyboardJoysticks": [{ + "axisConfig": [{ + "decKey": 546, + "incKey": 549 + }, { + "decKey": 568, + "incKey": 564 + }, { + "decKey": 550, + "decayRate": 0, + "incKey": 563, + "keyRate": 0.01 + }], + "axisCount": 3, + "buttonCount": 4, + "buttonKeys": [571, 569, 548, 567], + "povConfig": [{ + "keyDown": 614, + "keyDownLeft": 613, + "keyDownRight": 615, + "keyLeft": 616, + "keyRight": 618, + "keyUp": 620, + "keyUpLeft": 619, + "keyUpRight": 621 + }], + "povCount": 1 + }, { + "axisConfig": [{ + "decKey": 555, + "incKey": 557 + }, { + "decKey": 554, + "incKey": 556 + }], + "axisCount": 2, + "buttonCount": 4, + "buttonKeys": [558, 597, 599, 600], + "povCount": 0 + }, { + "axisConfig": [{ + "decKey": 513, + "incKey": 514 + }, { + "decKey": 515, + "incKey": 516 + }], + "axisCount": 2, + "buttonCount": 6, + "buttonKeys": [521, 519, 517, 522, 520, 518], + "povCount": 0 + }, { + "axisCount": 0, + "buttonCount": 0, + "povCount": 0 + }]} diff --git a/src/main/java/com/therekrab/autopilot/APConstraints.java b/src/main/java/com/therekrab/autopilot/APConstraints.java new file mode 100644 index 00000000..48a4d23b --- /dev/null +++ b/src/main/java/com/therekrab/autopilot/APConstraints.java @@ -0,0 +1,122 @@ +package com.therekrab.autopilot; + +/** + * A class that holds constraint information for an Autopilot action. + * + * Constraints are max velocity, acceleration, and jerk. + */ +public class APConstraints { + protected double velocity; + protected double acceleration; + protected double jerk; + + // These values represent the "cutoff" parameters that Autopilot uses to determine what should be + // happening during the end behavior of a path. These are always the same for a constant + // constraint, so to save the most computational time, they're precomputed with the constraint, + // rather than each time Autopilot.calculate is called. + + /** Cutoff distance */ + protected final double x0; + /** Velocity at cutoff distance */ + protected final double v0; + + /** + * Creates a blank APConstraints object. + *

+ * A blank APConstraints will not limit velocity, acceleration, or jerk. + */ + public APConstraints() { + this(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); + } + + /** + * Creates a new APConstraints object with a given max velocity, acceleration, and jerk. + * + * @param velocity The maximum velocity that Autopilot will demand, in m/s + * @param acceleration The maximum acceleration that Autopilot action will use to correct initial + * velocities, in m/s^2 + * @param jerk The maximum jerk that Autopilot will use to decelerate at the end of an action, in + * m/s^3 + */ + + public APConstraints(double velocity, double acceleration, double jerk) { + this.velocity = velocity; + this.acceleration = acceleration; + this.jerk = jerk; + + x0 = Math.pow(acceleration, 3.0) / (18.0 * jerk * jerk); + v0 = jerkConstrainedVelocity(x0); + } + + /** + * Create a new APConstraints object with a given max acceleration and jerk. + *

+ * This constructor defaults the velocity to unlimited. + * + * @param acceleration The maximum acceleration that Autopilot action will use to correct initial + * velocities, in m/s^2 + * @param jerk The maximum jerk that Autopilot will use to decelerate at the end of an action, in + * m/s^3 + * + */ + public APConstraints(double acceleration, double jerk) { + this(Double.POSITIVE_INFINITY, acceleration, jerk); + } + + /** + * Copies this APConstraints object, changes the copy's max velocity, and returns the copy. This + * affects the maximum velocity that Autopilot can demand. + * + * @param newVelocity The maximum velocity that Autopilot will demand, in m/s + */ + public APConstraints withVelocity(double newVelocity) { + return new APConstraints(newVelocity, this.acceleration, this.jerk); + } + + /** + * Copies this APConstraint object, changes the copy's acceleration, and returns the copy. This + * affects the maximum acceleration that Autopilot will use to correct initial velocities. + * + *

+ * Autopilot's acceleration is used at the beginning and end of an action + * + * @param newAcceleration The maximum acceleration that Autopilot will use to start a path, in + * m/s^2 + */ + public APConstraints withAcceleration(double newAcceleration) { + return new APConstraints(this.velocity, newAcceleration, this.jerk); + } + + /** + * Copies this APConstraint object, changes the copy's max jerk, and returns the copy. Higher + * values mean a faster deceleration. + * + * Autopilot's jerk is used at the end of an action (not relevant to Autopilot's start behavior). + * + * @param newJerk The maximum jerk that Autopilot will use to decelerate at the end of an action, + * in m/s^3 + */ + public APConstraints withJerk(double newJerk) { + return new APConstraints(this.velocity, this.acceleration, newJerk); + } + + /** + * Determines the maximum velocity required to travel the given distance and end at 0 m/s. + * + * @param dist The distance to travel, in meters + */ + protected double calculateMaxVelocity(double dist) { + if (dist > x0) { + return accelerationConstrainedVelocity(dist); + } + return jerkConstrainedVelocity(dist); + } + + private double accelerationConstrainedVelocity(double dist) { + return Math.sqrt(v0 * v0 + 2.0 * acceleration * (dist - x0)); + } + + private double jerkConstrainedVelocity(double dist) { + return Math.pow((4.5 * Math.pow(dist, 2.0)) * jerk, 1.0 / 3.0); + } +} diff --git a/src/main/java/com/therekrab/autopilot/APProfile.java b/src/main/java/com/therekrab/autopilot/APProfile.java new file mode 100644 index 00000000..75f9d994 --- /dev/null +++ b/src/main/java/com/therekrab/autopilot/APProfile.java @@ -0,0 +1,109 @@ +package com.therekrab.autopilot; + +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.Rotations; +import org.wpilib.units.measure.Angle; +import org.wpilib.units.measure.Distance; + +/** + * A class representing a profile that determines how Autopilot approaches a target. + * + * The constraints property of the profile limits the robot's behavior. + * + *

Acceptable error for the controller (both translational and rotational) are stored here. + * + *

The "beeline radius" determines the distance at which the robot drives directly at the target and + * no longer respects entry angle. This is helpful because if the robot overshoots by a small + * amount, that error should not cause the robot do completely circle back around. + */ +public class APProfile { + protected APConstraints constraints; + protected Distance errorXY; + protected Angle errorTheta; + protected Distance beelineRadius; + + /** + * Builds an APProfile with the given constraints. Tolerated error and beeline radius are all set + * to zero. + * + * @param constraints The motion constraints for this profile + */ + public APProfile(APConstraints constraints) { + this.constraints = constraints; + errorXY = Meters.of(0); + errorTheta = Rotations.of(0); + beelineRadius = Meters.of(0); + } + + /** + * Modifies this profile's tolerated error in the XY plane and returns itself + * + * @param errorXY The tolerated translation error for this profile + */ + public APProfile withErrorXY(Distance errorXY) { + this.errorXY = errorXY; + return this; + } + + /** + * Modifies this profile's tolerated angular error and returns itself + * + * @param errorTheta The tolerated angular error for this profile + */ + public APProfile withErrorTheta(Angle errorTheta) { + this.errorTheta = errorTheta; + return this; + } + + /** + * Modifies this profile's path generation constraints and returns itself + * + * @param constraints The Autopilot constraints to apply to this profile + */ + public APProfile withConstraints(APConstraints constraints) { + this.constraints = constraints; + return this; + } + + /** + * Modifies this profile's beeline radius and returns itself + * + *

The beeline radius is a distance where, under that range, entry angle is no longer respected. + * This prevents small overshoots from causing the robot to make a full arc and instead correct + * itself. + * + * @param beelineRadius The distance at which the robot will drive directly at the target + */ + public APProfile withBeelineRadius(Distance beelineRadius) { + this.beelineRadius = beelineRadius; + return this; + } + + /** + * Returns the tolerated translation error for this profile. + */ + public Distance getErrorXY() { + return errorXY; + } + + /** + * Returns the tolerated angular error for this profile. + */ + public Angle getErrorTheta() { + return errorTheta; + } + + /** + * Returns the path generation constraints for this profile. + */ + public APConstraints getConstraints() { + return constraints; + } + + /** + * Returns the beeline radius for this profile. + */ + public Distance getBeelineRadius() { + return beelineRadius; + } +} diff --git a/src/main/java/com/therekrab/autopilot/APTarget.java b/src/main/java/com/therekrab/autopilot/APTarget.java new file mode 100644 index 00000000..4ade064e --- /dev/null +++ b/src/main/java/com/therekrab/autopilot/APTarget.java @@ -0,0 +1,135 @@ +package com.therekrab.autopilot; + +import java.util.Optional; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.units.measure.Distance; + +/** + * The APTarget class represents the goal end state of an Autopilot action. + * + * A target needs a reference Pose2d, but can optionally have a specified entry angle and rotation + * radius. + * + * A target may also specify an end velocity or end velocity. + */ +public class APTarget { + protected Pose2d m_reference; + protected Optional m_entryAngle; + protected double m_velocity; + protected Optional m_rotationRadius; + + /** + * Creates a new Autopilot target with the given target pose, no entry angle, and no end velocity. + * + * @param pose The reference pose for this target. + */ + public APTarget(Pose2d pose) { + m_reference = pose; + m_velocity = 0; + m_entryAngle = Optional.empty(); + m_rotationRadius = Optional.empty(); + } + + /** + * Returns a copy of this target with the given reference Pose2d. + * + * @param reference The reference Pose2d for this target. + */ + public APTarget withReference(Pose2d reference) { + APTarget target = this.clone(); + target.m_reference = reference; + return target; + } + + /** + * Returns a copy of this target with the given entry angle. + * + * @param entryAngle The entry angle for the new target. + */ + public APTarget withEntryAngle(Rotation2d entryAngle) { + APTarget target = this.clone(); + target.m_entryAngle = Optional.of(entryAngle); + return target; + } + + /** + * Returns a copy of this target with the given end velocity. Note that if the robot does not + * reach this velocity, no issues will be thrown. Autopilot will only try to reach this target, + * but it will not be affected by whether it does. + * + * @param velocity The desired end velocity when the robot approaches the target + */ + public APTarget withVelocity(double velocity) { + APTarget target = this.clone(); + target.m_velocity = velocity; + return target; + } + + /** + * Returns a copy of this target with the given rotation radius. + * + *

Rotation radius is the distance from the target pose that rotation goals are respected. + * + *

By default, rotation goals are always respected. Adjusting this radius prevents Autopilot from reorienting + * the robot until the robot is within the specified radius of the target. + * + * @param radius The rotation radius for the new target + */ + public APTarget withRotationRadius(Distance radius) { + APTarget copy = this.clone(); + copy.m_rotationRadius = Optional.of(radius); + return copy; + } + + /** + * Returns this target's reference Pose2d. + */ + public Pose2d getReference() { + return m_reference; + } + + /** + * Returns this target's desired entry angle. + */ + public Optional getEntryAngle() { + return m_entryAngle; + } + + /** + * Returns this target's end velocity. + */ + public double getVelocity() { + return m_velocity; + } + + /** + * Returns this target's rotation radius. + */ + public Optional getRotationRadius() { + return m_rotationRadius; + } + + /** + * Creates a copy of this APTarget. + */ + public APTarget clone() { + APTarget target = new APTarget(m_reference); + target.m_velocity = m_velocity; + target.m_entryAngle = m_entryAngle; + target.m_rotationRadius = m_rotationRadius; + return target; + } + + /** + * Retuns a copy of this target, without the entry angle set. + * + *

This is useful if trying to make two different targets with and without entry angle set. + */ + public APTarget withoutEntryAngle() { + APTarget target = new APTarget(m_reference); + target.m_velocity = m_velocity; + target.m_rotationRadius = m_rotationRadius; + return target; + } +} diff --git a/src/main/java/com/therekrab/autopilot/Autopilot.java b/src/main/java/com/therekrab/autopilot/Autopilot.java new file mode 100644 index 00000000..6a80446d --- /dev/null +++ b/src/main/java/com/therekrab/autopilot/Autopilot.java @@ -0,0 +1,217 @@ +package com.therekrab.autopilot; + +import static org.wpilib.units.Units.Meters; +import static org.wpilib.units.Units.MetersPerSecond; +import static org.wpilib.units.Units.Radians; +import org.wpilib.math.geometry.Pose2d; +import org.wpilib.math.geometry.Rotation2d; +import org.wpilib.math.geometry.Translation2d; +import org.wpilib.math.kinematics.ChassisVelocities; +import org.wpilib.units.measure.LinearVelocity; + +/** + * Autopilot is a class that tries to drive a target to a goal in 2-D space. + * + * Autopilot is a stateless algorithm; as such, it does not "think ahead" and cannot avoid + * obstacles. Any math that Autopilot needs is already worked out such that only a small amount of + * computation is necessary on the fly. Autopilot is designed to be used in a drivetrain's control + * loop, where the current state of the robot is passed in, and the next velocity is returned. + * + */ +public class Autopilot { + private APProfile profile; + + private final double dt = 0.020; + + /** + * Constructs an Autopilot from a given profile. This is the profile that the autopilot will use + * for all actions. + */ + public Autopilot(APProfile profile) { + this.profile = profile; + } + + /** + * Returns the next field relative velocity for the trajectory + * + * @param current The robot's current position. + * @param robotRelativeSpeeds The robot's current robot relative ChassisVelocities. + * @param target The target the robot should drive towards. + * + * @return an APResult containing the next velocity and target angle + */ + public APResult calculate(Pose2d current, ChassisVelocities robotRelativeSpeeds, APTarget target) { + Translation2d offset = toTargetCoordinateFrame( + target.m_reference.getTranslation().minus(current.getTranslation()), target); + + if (offset.equals(Translation2d.kZero)) { + return new APResult( + MetersPerSecond.zero(), + MetersPerSecond.zero(), + target.m_reference.getRotation()); + } + + Translation2d fieldRelativeSpeeds = new Translation2d( + robotRelativeSpeeds.vx, + robotRelativeSpeeds.vy).rotateBy(current.getRotation()); + + Translation2d initial = toTargetCoordinateFrame(fieldRelativeSpeeds, target); + double disp = offset.getNorm(); + if (target.m_entryAngle.isEmpty() || disp < profile.beelineRadius.in(Meters)) { + Translation2d towardsTarget = offset.div(disp); + Translation2d goal = + towardsTarget.times(profile.constraints.calculateMaxVelocity(disp) + target.m_velocity); + Translation2d out = correct(initial, goal); + Translation2d velo = toGlobalCoordinateFrame(out, target); + Rotation2d rot = getRotationTarget(current.getRotation(), target, disp); + return new APResult(MetersPerSecond.of(velo.getX()), MetersPerSecond.of(velo.getY()), rot); + } + Translation2d goal = calculateSwirlyVelocity(offset, target); + Translation2d out = correct(initial, goal); + Translation2d velo = toGlobalCoordinateFrame(out, target); + Rotation2d rot = getRotationTarget(current.getRotation(), target, disp); + return new APResult(MetersPerSecond.of(velo.getX()), MetersPerSecond.of(velo.getY()), rot); + } + + /** + * Turns any other coordinate frame into a coordinate frame with positive x meaning in the + * direction of the target's entry angle, if applicable (otherwise no change to angles). + */ + private Translation2d toTargetCoordinateFrame(Translation2d coords, APTarget target) { + Rotation2d entryAngle = target.m_entryAngle.orElse(Rotation2d.kZero); + return coords.rotateBy(entryAngle.unaryMinus()); + } + + /** + * Turns a translation from a target-relative coordinate frame to a global coordinate frame. + */ + private Translation2d toGlobalCoordinateFrame(Translation2d coords, APTarget target) { + Rotation2d entryAngle = target.m_entryAngle.orElse(Rotation2d.kZero); + return coords.rotateBy(entryAngle); + } + + /** + * Attempts to drive the initial translation to the goal translation using the parameters for + * acceleration given in the profile. + * + * @param initial The initial translation to drive from + * @param goal The goal translation to drive to + */ + private Translation2d correct(Translation2d initial, Translation2d goal) { + Rotation2d angleOffset = Rotation2d.kZero; + if (!goal.equals(Translation2d.kZero)) { + angleOffset = new Rotation2d(goal.getX(), goal.getY()); + } + Translation2d adjustedGoal = goal.rotateBy(angleOffset.unaryMinus()); + Translation2d adjustedInitial = initial.rotateBy(angleOffset.unaryMinus()); + double initialI = adjustedInitial.getX(); + double goalI = adjustedGoal.getX(); + // we cap the adjusted I because we'd rather adjust now than overshoot. + if (goalI > profile.constraints.velocity) { + goalI = profile.constraints.velocity; + } + double adjustedI = Math.min(goalI, + push(initialI, goalI, profile.constraints.acceleration)); + return new Translation2d(adjustedI, 0).rotateBy(angleOffset); + } + + /** + * Using the provided acceleration, "pushes" the start point towards the end point. + * + * This is used for ensuring that changes in velocity are withing the acceleration threshold. + */ + private double push(double start, double end, double accel) { + double maxChange = accel * dt; + if (Math.abs(start - end) < maxChange) { + return end; + } + if (start > end) { + return start - maxChange; + } + return start + maxChange; + } + + /** + * Uses the swirly method to calculate the correct velocities for the robot, respecting entry + * angles. + * + * @param offset The offset from the robot to the target, in the target's coordinate frame + * @param target The target that Autopilot is trying to reach + */ + private Translation2d calculateSwirlyVelocity(Translation2d offset, APTarget target) { + double disp = offset.getNorm(); + Rotation2d theta = new Rotation2d(offset.getX(), offset.getY()); + double rads = theta.getRadians(); + double dist = calculateSwirlyLength(rads, disp); + double vx = theta.getCos() - rads * theta.getSin(); + double vy = rads * theta.getCos() + theta.getSin(); + return new Translation2d(vx, vy) + .div(Math.hypot(vx, vy)) // normalize + .times(profile.constraints.calculateMaxVelocity(dist) + target.m_velocity); // and scale to + // new length + } + + /** + * Using a precomputed integral, returns the length of the path that the swirly method generates. + * + *

+ * More specifically, this calculates the arc length of the polar curve r=theta from the given + * angle to zero, then scales it to match the current state. + * + * @param theta The angle of the offset from the robot to the target, in radians + * @param radius The normalized offset from the robot to the target, in meters + */ + private double calculateSwirlyLength(double theta, double radius) { + if (theta == 0) { + return radius; + } + theta = Math.abs(theta); + double hypot = Math.hypot(theta, 1); + double u1 = radius * hypot; + double u2 = radius * Math.log(theta + hypot) / theta; + return 0.5 * (u1 + u2); + } + + /** + * Returns the target's rotation if the robot is within a specified rotation radius; otherwise, + * returns the current rotation of the robot. + * + * @param current The current rotation of the robot. + * @param target The APTarget that Autopilot is trying to reach. + * @param dist The distance from the robot to the target. + */ + private Rotation2d getRotationTarget(Rotation2d current, APTarget target, double dist) { + if (target.m_rotationRadius.isEmpty()) { + return target.m_reference.getRotation(); + } + double radius = target.m_rotationRadius.get().in(Meters); + if (radius > dist) { + return target.m_reference.getRotation(); + } else { + return current; + } + } + + /** + * Return whether the given pose is within the tolerance of the APTarget. + * + * @param current The current pose of the robot. + * @param target The APTarget to check against. + * + * @return Returns true if Autopilot has reached the target. + */ + public boolean atTarget(Pose2d current, APTarget target) { + Pose2d goal = target.m_reference; + boolean okXY = Math.hypot(current.getX() - goal.getX(), + current.getY() - goal.getY()) <= profile.errorXY.in(Meters); + boolean okTheta = Math.abs(current.getRotation().minus(goal.getRotation()) + .getRadians()) <= profile.errorTheta.in(Radians); + return okXY && okTheta; + } + + /** + * The computed motion from a call to Autopilot.calculate(). + */ + public record APResult(LinearVelocity vx, LinearVelocity vy, Rotation2d targetAngle) { + } +} From e32938e7cc65afbcc2d3f96ca5ff68113f4186fc Mon Sep 17 00:00:00 2001 From: gback Date: Wed, 9 Sep 2026 22:40:14 -0400 Subject: [PATCH 3/8] (#1) fixed APConstraints JSON deserialization error Co-Authored-By: Codex 5.6 --- .../autopilot/APConstraintsTypeAdapter.java | 55 +++++++++++++++++++ .../java/frc/robot/autogen/GenerateAutos.java | 6 +- .../frc/robot/constants/JsonConstants.java | 3 + 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/therekrab/autopilot/APConstraintsTypeAdapter.java diff --git a/src/main/java/com/therekrab/autopilot/APConstraintsTypeAdapter.java b/src/main/java/com/therekrab/autopilot/APConstraintsTypeAdapter.java new file mode 100644 index 00000000..9eaa8783 --- /dev/null +++ b/src/main/java/com/therekrab/autopilot/APConstraintsTypeAdapter.java @@ -0,0 +1,55 @@ +package com.therekrab.autopilot; + +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +/** Gson adapter that reconstructs {@link APConstraints} and its derived final fields. */ +public final class APConstraintsTypeAdapter extends TypeAdapter { + @Override + public void write(JsonWriter out, APConstraints constraints) throws IOException { + if (constraints == null) { + out.nullValue(); + return; + } + + out.beginObject(); + out.name("velocity").value(constraints.velocity); + out.name("acceleration").value(constraints.acceleration); + out.name("jerk").value(constraints.jerk); + out.endObject(); + } + + @Override + public APConstraints read(JsonReader in) throws IOException { + if (in.peek() == JsonToken.NULL) { + in.nextNull(); + return null; + } + + Double velocity = null; + Double acceleration = null; + Double jerk = null; + + in.beginObject(); + while (in.hasNext()) { + switch (in.nextName()) { + case "velocity" -> velocity = in.nextDouble(); + case "acceleration" -> acceleration = in.nextDouble(); + case "jerk" -> jerk = in.nextDouble(); + default -> in.skipValue(); + } + } + in.endObject(); + + if (velocity == null || acceleration == null || jerk == null) { + throw new JsonParseException( + "APConstraints requires velocity, acceleration, and jerk fields"); + } + + return new APConstraints(velocity, acceleration, jerk); + } +} diff --git a/src/main/java/frc/robot/autogen/GenerateAutos.java b/src/main/java/frc/robot/autogen/GenerateAutos.java index ade6401f..37d0378d 100644 --- a/src/main/java/frc/robot/autogen/GenerateAutos.java +++ b/src/main/java/frc/robot/autogen/GenerateAutos.java @@ -22,6 +22,7 @@ import static frc.robot.autogen.Dsl.waitSeconds; import com.therekrab.autopilot.APConstraints; +import com.therekrab.autopilot.APConstraintsTypeAdapter; import com.therekrab.autopilot.APTarget; import coppercore.parameter_tools.json.JSONSync; import coppercore.parameter_tools.json.JSONSyncConfig; @@ -75,7 +76,10 @@ public static void main(String[] args) throws java.io.IOException { Autos autos = build(); JSONConverter.addConversion(APTarget.class, JSONAPTarget.class); - JSONSyncConfig config = new JSONSyncConfigBuilder().build(); + JSONSyncConfig config = + new JSONSyncConfigBuilder() + .addJsonTypeAdapter(APConstraints.class, new APConstraintsTypeAdapter()) + .build(); JSONSync sync = new JSONSync<>(autos, "", config); String json = sync.serialize(); diff --git a/src/main/java/frc/robot/constants/JsonConstants.java b/src/main/java/frc/robot/constants/JsonConstants.java index 8eaa5aa5..ca3c67fd 100644 --- a/src/main/java/frc/robot/constants/JsonConstants.java +++ b/src/main/java/frc/robot/constants/JsonConstants.java @@ -5,6 +5,8 @@ import static org.wpilib.units.Units.RotationsPerSecondPerSecond; import static org.wpilib.units.Units.Second; +import com.therekrab.autopilot.APConstraints; +import com.therekrab.autopilot.APConstraintsTypeAdapter; import com.therekrab.autopilot.APTarget; import coppercore.parameter_tools.json.JSONHandler; import coppercore.parameter_tools.json.JSONSyncConfigBuilder; @@ -74,6 +76,7 @@ public static JSONHandler loadConstants() { Controllers.applyControllerConfigToBuilder(jsonSyncSettings); + jsonSyncSettings.addJsonTypeAdapter(APConstraints.class, new APConstraintsTypeAdapter()); jsonSyncSettings.addJsonTypeAdapterFactory(new OptionalTypeAdapterFactory()); var pathProvider = environmentHandler.getEnvironmentPathProvider(); From edbcfa2fb96ce9c84ede76aea269de492ab7287c Mon Sep 17 00:00:00 2001 From: Theta Back Date: Sun, 13 Sep 2026 15:41:30 -0400 Subject: [PATCH 4/8] (#1) removed extra stddevs in flywheelsim --- src/main/java/frc/robot/constants/HopperConstants.java | 1 - src/main/java/frc/robot/constants/IndexerConstants.java | 1 - src/main/java/frc/robot/constants/ShooterConstants.java | 3 ++- src/main/java/frc/robot/constants/TransferRollerConstants.java | 1 - src/main/java/frc/robot/constants/TurretConstants.java | 3 +-- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/frc/robot/constants/HopperConstants.java b/src/main/java/frc/robot/constants/HopperConstants.java index e79f1d08..75a781a8 100644 --- a/src/main/java/frc/robot/constants/HopperConstants.java +++ b/src/main/java/frc/robot/constants/HopperConstants.java @@ -107,7 +107,6 @@ public CoppercoreSimAdapter buildHopperSim() { simHopperMOI.in(KilogramSquareMeters), 1 / hopperReduction), DCMotor.getKrakenX60(1), - hopperReduction, 0.0)); } } diff --git a/src/main/java/frc/robot/constants/IndexerConstants.java b/src/main/java/frc/robot/constants/IndexerConstants.java index 346af71b..16765494 100644 --- a/src/main/java/frc/robot/constants/IndexerConstants.java +++ b/src/main/java/frc/robot/constants/IndexerConstants.java @@ -95,7 +95,6 @@ public CoppercoreSimAdapter buildIndexerSim() { simIndexerMOI.in(KilogramSquareMeters), 1 / indexerReduction), DCMotor.getKrakenX44Foc(1), - 0.0, 0.0)); } } diff --git a/src/main/java/frc/robot/constants/ShooterConstants.java b/src/main/java/frc/robot/constants/ShooterConstants.java index a0d952aa..37be14a0 100644 --- a/src/main/java/frc/robot/constants/ShooterConstants.java +++ b/src/main/java/frc/robot/constants/ShooterConstants.java @@ -214,6 +214,7 @@ public CoppercoreSimAdapter buildShooterSim() { new FlywheelSim( Models.flywheelFromPhysicalConstants( DCMotor.getKrakenX60Foc(3), shooterMOI.in(KilogramSquareMeters), 1.0), - DCMotor.getKrakenX60Foc(3))); + DCMotor.getKrakenX60Foc(3), + 0.0)); } } diff --git a/src/main/java/frc/robot/constants/TransferRollerConstants.java b/src/main/java/frc/robot/constants/TransferRollerConstants.java index e8f1c1c7..e3dc503e 100644 --- a/src/main/java/frc/robot/constants/TransferRollerConstants.java +++ b/src/main/java/frc/robot/constants/TransferRollerConstants.java @@ -93,7 +93,6 @@ public CoppercoreSimAdapter buildTransferRollerSim() { simTransferRollerMOI.in(KilogramSquareMeters), 1 / transferRollerReduction), DCMotor.getKrakenX44Foc(1), - 0.0, 0.0)); } } diff --git a/src/main/java/frc/robot/constants/TurretConstants.java b/src/main/java/frc/robot/constants/TurretConstants.java index e8a82fc2..0bde0464 100644 --- a/src/main/java/frc/robot/constants/TurretConstants.java +++ b/src/main/java/frc/robot/constants/TurretConstants.java @@ -168,8 +168,7 @@ public CoppercoreSimAdapter buildTurretSim() { simTurretMOI.in(KilogramSquareMeters), 1 / turretReduction), DCMotor.getKrakenX44Foc(1), - 0.0, - 0.0), + 0.0, 0.0), minTurretAngle, maxTurretAngle); } From 86d84b295fde51088b377ee87ed501b792962fac Mon Sep 17 00:00:00 2001 From: Theta Back Date: Wed, 16 Sep 2026 13:33:15 -0400 Subject: [PATCH 5/8] (#1) commented out Elastic alert to run in sim --- simgui-ds.json | 107 +++++++++--------- .../java/frc/robot/CoordinationLayer.java | 38 +++---- 2 files changed, 74 insertions(+), 71 deletions(-) diff --git a/simgui-ds.json b/simgui-ds.json index cb2b8b0c..ac74e387 100644 --- a/simgui-ds.json +++ b/simgui-ds.json @@ -1,56 +1,59 @@ -{"keyboardJoysticks": [{ - "axisConfig": [{ - "decKey": 546, - "incKey": 549 +{ + "keyboardJoysticks": [{ + "axisConfig": [{ + "decKey": 546, + "incKey": 549 + }, { + "decKey": 568, + "incKey": 564 + }, { + "decKey": 550, + "decayRate": 0, + "incKey": 563, + "keyRate": 0.01 + }], + "axisCount": 3, + "buttonCount": 4, + "buttonKeys": [571, 569, 548, 567], + "povConfig": [{ + "keyDown": 614, + "keyDownLeft": 613, + "keyDownRight": 615, + "keyLeft": 616, + "keyRight": 618, + "keyUp": 620, + "keyUpLeft": 619, + "keyUpRight": 621 + }], + "povCount": 1 }, { - "decKey": 568, - "incKey": 564 + "axisConfig": [{ + "decKey": 555, + "incKey": 557 + }, { + "decKey": 554, + "incKey": 556 + }], + "axisCount": 2, + "buttonCount": 4, + "buttonKeys": [558, 597, 599, 600], + "povCount": 0 }, { - "decKey": 550, - "decayRate": 0, - "incKey": 563, - "keyRate": 0.01 - }], - "axisCount": 3, - "buttonCount": 4, - "buttonKeys": [571, 569, 548, 567], - "povConfig": [{ - "keyDown": 614, - "keyDownLeft": 613, - "keyDownRight": 615, - "keyLeft": 616, - "keyRight": 618, - "keyUp": 620, - "keyUpLeft": 619, - "keyUpRight": 621 - }], - "povCount": 1 - }, { - "axisConfig": [{ - "decKey": 555, - "incKey": 557 - }, { - "decKey": 554, - "incKey": 556 - }], - "axisCount": 2, - "buttonCount": 4, - "buttonKeys": [558, 597, 599, 600], - "povCount": 0 - }, { - "axisConfig": [{ - "decKey": 513, - "incKey": 514 + "axisConfig": [{ + "decKey": 513, + "incKey": 514 + }, { + "decKey": 515, + "incKey": 516 + }], + "axisCount": 2, + "buttonCount": 6, + "buttonKeys": [521, 519, 517, 522, 520, 518], + "povCount": 0 }, { - "decKey": 515, - "incKey": 516 + "axisCount": 0, + "buttonCount": 0, + "povCount": 0 }], - "axisCount": 2, - "buttonCount": 6, - "buttonKeys": [521, 519, 517, 522, 520, 518], - "povCount": 0 - }, { - "axisCount": 0, - "buttonCount": 0, - "povCount": 0 - }]} + "robotJoysticks": [{"guid": "Keyboard0"}] + } diff --git a/src/main/java/frc/robot/CoordinationLayer.java b/src/main/java/frc/robot/CoordinationLayer.java index 855be4a4..4134018f 100644 --- a/src/main/java/frc/robot/CoordinationLayer.java +++ b/src/main/java/frc/robot/CoordinationLayer.java @@ -863,25 +863,25 @@ public void coordinateRobotActions() { autonomyOverriddenAlert.set(effectiveAutonomyLevel != autonomyLevel); - if (DriverStationBackend.isDisabled()) { - boolean lowVoltage = - JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( - RobotController.getBatteryVoltage()); - lowBatteryAlert.set(lowVoltage); - lowBatteryAlertRateLimiter.increment(); - if (lowVoltage - && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) - && !(DriverStationBackend.isFMSAttached())) { - Elastic.sendNotification( - new Elastic.Notification( - Elastic.NotificationLevel.WARNING, - "Low Battery Voltage", - "Battery Voltage is below threshold.")); - } - } else { - // This alert is only for disabled mode. - lowBatteryAlert.set(false); - } + // if (DriverStationBackend.isDisabled()) { + // boolean lowVoltage = + // JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( + // RobotController.getBatteryVoltage()); + // lowBatteryAlert.set(lowVoltage); + // lowBatteryAlertRateLimiter.increment(); + // if (lowVoltage + // && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) + // && !(DriverStationBackend.isFMSAttached())) { + // Elastic.sendNotification( + // new Elastic.Notification( + // Elastic.NotificationLevel.WARNING, + // "Low Battery Voltage", + // "Battery Voltage is below threshold.")); + // } + // } else { + // // This alert is only for disabled mode. + // lowBatteryAlert.set(false); + // } // Test whether we can shoot BEFORE running the shot calculator so that we can shoot for the // shot we were looking ahead to last cycle. From a0874dadd089d024b06114b9027d62f99a92b2da Mon Sep 17 00:00:00 2001 From: Godmar Back Date: Wed, 16 Sep 2026 16:00:06 -0400 Subject: [PATCH 6/8] enable gradle annotation processing (This allows successful start of the simulator) --- .vscode/settings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6ea00dae..aef013c7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,7 +28,7 @@ "java.test.defaultConfig": "WPIlibUnitTests", "spotlessGradle.format.enable": true, "spotlessGradle.diagnostics.enable": false, - "java.import.gradle.annotationProcessing.enabled": false, + "java.import.gradle.annotationProcessing.enabled": true, "java.completion.favoriteStaticMembers": [ "org.junit.Assert.*", "org.junit.Assume.*", From 688949eff00b76b52671fc3bd0fbf5290a17cb39 Mon Sep 17 00:00:00 2001 From: Godmar Back Date: Wed, 16 Sep 2026 16:31:03 -0400 Subject: [PATCH 7/8] added gradlew build task before launching sim also put Elastic changes back in. --- .vscode/launch.json | 2 + .vscode/settings.json | 2 +- .vscode/tasks.json | 20 ++++++++++ .../java/frc/robot/CoordinationLayer.java | 38 +++++++++---------- 4 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index c9c9713d..d858cc26 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,12 +10,14 @@ "name": "WPILib Desktop Debug", "request": "launch", "desktop": true, + "preLaunchTask": "Gradle Build", }, { "type": "wpilib", "name": "WPILib roboRIO Debug", "request": "launch", "desktop": false, + "preLaunchTask": "Gradle Build", } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index aef013c7..6ea00dae 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -28,7 +28,7 @@ "java.test.defaultConfig": "WPIlibUnitTests", "spotlessGradle.format.enable": true, "spotlessGradle.diagnostics.enable": false, - "java.import.gradle.annotationProcessing.enabled": true, + "java.import.gradle.annotationProcessing.enabled": false, "java.completion.favoriteStaticMembers": [ "org.junit.Assert.*", "org.junit.Assume.*", diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..c65e3f75 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,20 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Gradle Build", + "type": "shell", + "command": "./gradlew", + "args": ["build"], + "group": { + "kind": "build", + "isDefault": true + }, + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [] + } + ] +} diff --git a/src/main/java/frc/robot/CoordinationLayer.java b/src/main/java/frc/robot/CoordinationLayer.java index 4134018f..855be4a4 100644 --- a/src/main/java/frc/robot/CoordinationLayer.java +++ b/src/main/java/frc/robot/CoordinationLayer.java @@ -863,25 +863,25 @@ public void coordinateRobotActions() { autonomyOverriddenAlert.set(effectiveAutonomyLevel != autonomyLevel); - // if (DriverStationBackend.isDisabled()) { - // boolean lowVoltage = - // JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( - // RobotController.getBatteryVoltage()); - // lowBatteryAlert.set(lowVoltage); - // lowBatteryAlertRateLimiter.increment(); - // if (lowVoltage - // && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) - // && !(DriverStationBackend.isFMSAttached())) { - // Elastic.sendNotification( - // new Elastic.Notification( - // Elastic.NotificationLevel.WARNING, - // "Low Battery Voltage", - // "Battery Voltage is below threshold.")); - // } - // } else { - // // This alert is only for disabled mode. - // lowBatteryAlert.set(false); - // } + if (DriverStationBackend.isDisabled()) { + boolean lowVoltage = + JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( + RobotController.getBatteryVoltage()); + lowBatteryAlert.set(lowVoltage); + lowBatteryAlertRateLimiter.increment(); + if (lowVoltage + && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) + && !(DriverStationBackend.isFMSAttached())) { + Elastic.sendNotification( + new Elastic.Notification( + Elastic.NotificationLevel.WARNING, + "Low Battery Voltage", + "Battery Voltage is below threshold.")); + } + } else { + // This alert is only for disabled mode. + lowBatteryAlert.set(false); + } // Test whether we can shoot BEFORE running the shot calculator so that we can shoot for the // shot we were looking ahead to last cycle. From 3115ea67e0b88f50d1bdc20e107dc19c6d605ece Mon Sep 17 00:00:00 2001 From: Theta Back Date: Wed, 16 Sep 2026 19:21:30 -0400 Subject: [PATCH 8/8] (#1) commented out battery alert again --- .../java/frc/robot/CoordinationLayer.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/frc/robot/CoordinationLayer.java b/src/main/java/frc/robot/CoordinationLayer.java index 855be4a4..4134018f 100644 --- a/src/main/java/frc/robot/CoordinationLayer.java +++ b/src/main/java/frc/robot/CoordinationLayer.java @@ -863,25 +863,25 @@ public void coordinateRobotActions() { autonomyOverriddenAlert.set(effectiveAutonomyLevel != autonomyLevel); - if (DriverStationBackend.isDisabled()) { - boolean lowVoltage = - JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( - RobotController.getBatteryVoltage()); - lowBatteryAlert.set(lowVoltage); - lowBatteryAlertRateLimiter.increment(); - if (lowVoltage - && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) - && !(DriverStationBackend.isFMSAttached())) { - Elastic.sendNotification( - new Elastic.Notification( - Elastic.NotificationLevel.WARNING, - "Low Battery Voltage", - "Battery Voltage is below threshold.")); - } - } else { - // This alert is only for disabled mode. - lowBatteryAlert.set(false); - } + // if (DriverStationBackend.isDisabled()) { + // boolean lowVoltage = + // JsonConstants.robotInfo.batteryVoltageAlert.isBatteryBelowThreshold( + // RobotController.getBatteryVoltage()); + // lowBatteryAlert.set(lowVoltage); + // lowBatteryAlertRateLimiter.increment(); + // if (lowVoltage + // && lowBatteryAlertRateLimiter.consumeTokens(TOKENS_PER_ALERT) + // && !(DriverStationBackend.isFMSAttached())) { + // Elastic.sendNotification( + // new Elastic.Notification( + // Elastic.NotificationLevel.WARNING, + // "Low Battery Voltage", + // "Battery Voltage is below threshold.")); + // } + // } else { + // // This alert is only for disabled mode. + // lowBatteryAlert.set(false); + // } // Test whether we can shoot BEFORE running the shot calculator so that we can shoot for the // shot we were looking ahead to last cycle.