.
diff --git a/WPILib-License.md b/WPILib-License.md
new file mode 100644
index 0000000..3d5a824
--- /dev/null
+++ b/WPILib-License.md
@@ -0,0 +1,24 @@
+Copyright (c) 2009-2021 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.
+
+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
+WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..e8b37e1
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,142 @@
+plugins {
+ id "java"
+ id "edu.wpi.first.GradleRIO" version "2024.1.1-beta-4"
+ id "com.peterabeles.gversion" version "1.10"
+ id "com.diffplug.spotless" version "6.12.0"
+}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+}
+
+def ROBOT_MAIN_CLASS = "org.team1540.advantagekitdemo.Main"
+
+// Define my targets (RoboRIO) and artifacts (deployable files)
+// This is added by GradleRIO's backing project DeployUtils.
+deploy {
+ targets {
+ roborio(getTargetTypeClass('RoboRIO')) {
+ // 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)
+
+ 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')) {
+ }
+
+ // Static files artifact
+ frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) {
+ files = project.fileTree('src/main/deploy')
+ directory = '/home/lvuser/deploy'
+ }
+ }
+ }
+ }
+}
+
+def deployArtifact = deploy.targets.roborio.artifacts.frcJava
+
+// Set to true to use debug for JNI.
+wpi.java.debugJni = false
+
+// Set this to true to enable desktop support.
+def includeDesktopSupport = true
+
+// Configuration for AdvantageKit
+repositories {
+ maven {
+ url = uri("https://maven.pkg.github.com/Mechanical-Advantage/AdvantageKit")
+ credentials {
+ username = "Mechanical-Advantage-Bot"
+ password = "\u0067\u0068\u0070\u005f\u006e\u0056\u0051\u006a\u0055\u004f\u004c\u0061\u0079\u0066\u006e\u0078\u006e\u0037\u0051\u0049\u0054\u0042\u0032\u004c\u004a\u006d\u0055\u0070\u0073\u0031\u006d\u0037\u004c\u005a\u0030\u0076\u0062\u0070\u0063\u0051"
+ }
+ }
+ mavenLocal()
+}
+
+configurations.all {
+ exclude group: "edu.wpi.first.wpilibj"
+}
+
+task(checkAkitInstall, dependsOn: "classes", type: JavaExec) {
+ mainClass = "org.littletonrobotics.junction.CheckInstall"
+ classpath = sourceSets.main.runtimeClasspath
+}
+compileJava.finalizedBy checkAkitInstall
+
+// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
+// Also defines JUnit 4.
+dependencies {
+ 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)
+
+ roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio)
+ roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio)
+
+ nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
+ nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
+ simulationDebug wpi.sim.enableDebug()
+
+ nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop)
+ nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
+ simulationRelease wpi.sim.enableRelease()
+
+ testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
+ testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.2'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
+
+ implementation "gov.nist.math:jama:1.0.3"
+
+ def akitJson = new groovy.json.JsonSlurper().parseText(new File(projectDir.getAbsolutePath() + "/vendordeps/AdvantageKit.json").text)
+ annotationProcessor "org.littletonrobotics.akit.junction:junction-autolog:$akitJson.version"
+}
+
+test {
+ useJUnitPlatform()
+ systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
+}
+
+// Simulation configuration (e.g. environment variables).
+wpi.sim.addGui()
+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)
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+}
+
+// Configure jar and deploy tasks
+deployArtifact.jarTask = jar
+wpi.java.configureExecutableTasks(jar)
+wpi.java.configureTestTasks(test)
+
+// Configure string concat to always inline compile
+tasks.withType(JavaCompile) {
+ options.compilerArgs.add '-XDstringConcat=inline'
+}
+
+// Create version file
+project.compileJava.dependsOn(createVersionFile)
+gversion {
+ srcDir = "src/main/java/"
+ classPackage = "org.team1540.advantagekitdemo"
+ className = "BuildConstants"
+ dateFormat = "yyyy-MM-dd HH:mm:ss z"
+ timeZone = "America/Los_Angeles"
+ indent = " "
+}
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7f93135
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1058752
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=permwrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=permwrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000..1aa94a4
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 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.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# 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
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# 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
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# 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" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+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,
+# 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 \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..93e3f59
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+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.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+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.
+
+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 %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..e23ea1a
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,30 @@
+import org.gradle.internal.os.OperatingSystem
+
+pluginManagement {
+ repositories {
+ mavenLocal()
+ gradlePluginPortal()
+ String frcYear = '2024'
+ File frcHome
+ 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)
+ } else {
+ def userFolder = System.getProperty("user.home")
+ def homeRoot = new File(userFolder, "wpilib")
+ frcHome = new File(homeRoot, frcYear)
+ }
+ def frcHomeMaven = new File(frcHome, 'maven')
+ maven {
+ name 'frcHome'
+ url frcHomeMaven
+ }
+ }
+}
+
+Properties props = System.getProperties()
+props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true")
diff --git a/src/main/java/org/team1540/advantagekitdemo/BuildConstants.java b/src/main/java/org/team1540/advantagekitdemo/BuildConstants.java
new file mode 100644
index 0000000..2bfbbbf
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/BuildConstants.java
@@ -0,0 +1,19 @@
+package org.team1540.advantagekitdemo;
+
+/**
+ * Automatically generated file containing build version information.
+ */
+public final class BuildConstants {
+ public static final String MAVEN_GROUP = "";
+ public static final String MAVEN_NAME = "advantageKitDemo";
+ public static final String VERSION = "unspecified";
+ public static final int GIT_REVISION = -1;
+ public static final String GIT_SHA = "UNKNOWN";
+ public static final String GIT_DATE = "UNKNOWN";
+ public static final String GIT_BRANCH = "UNKNOWN";
+ public static final String BUILD_DATE = "2024-01-03 22:28:19 PST";
+ public static final long BUILD_UNIX_TIME = 1704349699908L;
+ public static final int DIRTY = 129;
+
+ private BuildConstants(){}
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/Constants.java b/src/main/java/org/team1540/advantagekitdemo/Constants.java
new file mode 100644
index 0000000..c135f96
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/Constants.java
@@ -0,0 +1,87 @@
+// Copyright 2021-2023 FRC 6328
+// http://github.com/Mechanical-Advantage
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 3 as published by the Free Software Foundation or
+// available in the root directory of this project.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+package org.team1540.advantagekitdemo;
+
+import edu.wpi.first.math.controller.SimpleMotorFeedforward;
+import edu.wpi.first.math.kinematics.DifferentialDriveKinematics;
+import edu.wpi.first.math.trajectory.TrapezoidProfile;
+import edu.wpi.first.math.util.Units;
+
+/**
+ * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean
+ * constants. This class should not be used for any other purpose. All constants should be declared
+ * globally (i.e. public static). Do not put anything functional in this class.
+ *
+ * It is advised to statically import this class (or one of its inner classes) wherever the
+ * constants are needed, to reduce verbosity.
+ */
+public final class Constants {
+ public static final SimulationMode simulationMode = SimulationMode.SIM;
+
+ public enum SimulationMode {
+ /**
+ * Running a physics simulator.
+ */
+ SIM,
+
+ /**
+ * Replaying from a log file.
+ */
+ REPLAY
+ }
+
+ public static final class DrivetrainConstants {
+ public static final int FL_ID = 1;
+ public static final int BL_ID = 2;
+ public static final int FR_ID = 3;
+ public static final int BR_ID = 4;
+
+ public static final double CURRENT_LIMIT = 40;
+
+ public static final double GEAR_RATIO = 6.0;
+ public static final double WHEEL_DIAMETER_METERS = Units.inchesToMeters(4.0);
+ public static final double TRACK_WIDTH_METERS = 26.5;
+
+ public static final double ROBOT_WEIGHT_KG = Units.lbsToKilograms(118); // omg its tem 118 teh robnots
+ public static final double ROBOT_MOI = 2.54; // omg its tem 254 teh chezy pofs
+
+ public static final double VELOCITY_KP = 3.2925;
+ public static final double VELOCITY_KI = 0;
+ public static final double VELOCITY_KD = 0;
+
+ public static final double KS = 0.650;
+ public static final double KV = 2.81;
+ public static final double KA = 0.224;
+
+ public static final SimpleMotorFeedforward feedforward = new SimpleMotorFeedforward(KS, KV, KA);
+ public static final DifferentialDriveKinematics driveKinematics =
+ new DifferentialDriveKinematics(TRACK_WIDTH_METERS);
+ }
+
+ public static final class ElevatorConstants {
+ public static final double GEAR_RATIO = 4.21;
+ public static final double DRUM_RADIUS_METERS = Units.inchesToMeters(0.75);
+ public static final double MAX_HEIGHT_METERS = Units.inchesToMeters(86);
+ public static final double CARRIAGE_MASS_KG = 20;
+
+ public static final double KP = 1;
+ public static final double KI = 0;
+ public static final double KD = 0;
+ public static final TrapezoidProfile.Constraints MOTION_CONSTRAINTS = new TrapezoidProfile.Constraints(2.5, 12.5);
+
+ public static final double KS = 0;
+ public static final double KG = 0.38;
+ public static final double KV = 0.19;
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/Main.java b/src/main/java/org/team1540/advantagekitdemo/Main.java
new file mode 100644
index 0000000..2d8b09d
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/Main.java
@@ -0,0 +1,34 @@
+// Copyright 2021-2023 FRC 6328
+// http://github.com/Mechanical-Advantage
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 3 as published by the Free Software Foundation or
+// available in the root directory of this project.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+package org.team1540.advantagekitdemo;
+
+import edu.wpi.first.wpilibj.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(Robot::new);
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/Robot.java b/src/main/java/org/team1540/advantagekitdemo/Robot.java
new file mode 100644
index 0000000..0591314
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/Robot.java
@@ -0,0 +1,188 @@
+// Copyright 2021-2023 FRC 6328
+// http://github.com/Mechanical-Advantage
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 3 as published by the Free Software Foundation or
+// available in the root directory of this project.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+package org.team1540.advantagekitdemo;
+
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.CommandScheduler;
+import org.littletonrobotics.junction.LogFileUtil;
+import org.littletonrobotics.junction.LoggedRobot;
+import org.littletonrobotics.junction.Logger;
+import org.littletonrobotics.junction.networktables.NT4Publisher;
+import org.littletonrobotics.junction.wpilog.WPILOGReader;
+import org.littletonrobotics.junction.wpilog.WPILOGWriter;
+
+/**
+ * The VM is configured to automatically run this class, and to call the functions corresponding to
+ * each mode, as described in the TimedRobot documentation. If you change the name of this class or
+ * the package after creating this project, you must also update the build.gradle file in the
+ * project.
+ */
+public class Robot extends LoggedRobot {
+ private Command autonomousCommand;
+ private RobotContainer robotContainer;
+
+ /**
+ * This function is run when the robot is first started up and should be used for any
+ * initialization code.
+ */
+ @Override
+ public void robotInit() {
+ // Record metadata
+ Logger.recordMetadata("ProjectName", BuildConstants.MAVEN_NAME);
+ Logger.recordMetadata("BuildDate", BuildConstants.BUILD_DATE);
+ Logger.recordMetadata("GitSHA", BuildConstants.GIT_SHA);
+ Logger.recordMetadata("GitDate", BuildConstants.GIT_DATE);
+ Logger.recordMetadata("GitBranch", BuildConstants.GIT_BRANCH);
+ switch (BuildConstants.DIRTY) {
+ case 0:
+ Logger.recordMetadata("GitStatus", "All changes committed");
+ break;
+ case 1:
+ Logger.recordMetadata("GitStatus", "Uncomitted changes");
+ break;
+ default:
+ Logger.recordMetadata("GitStatus", "Unknown");
+ break;
+ }
+
+ // Set up data receivers & replay source
+ if (Robot.isReal()) {
+ Logger.addDataReceiver(new WPILOGWriter("/U/logs"));
+ Logger.addDataReceiver(new NT4Publisher());
+ } else {
+ switch (Constants.simulationMode) {
+ case SIM:
+ // Running a physics simulator, log to NT
+ Logger.addDataReceiver(new NT4Publisher());
+ break;
+
+ case REPLAY:
+ // Replaying a log, set up replay source
+ setUseTiming(false); // Run as fast as possible
+ String logPath = LogFileUtil.findReplayLog();
+ Logger.setReplaySource(new WPILOGReader(logPath));
+ Logger.addDataReceiver(new WPILOGWriter(LogFileUtil.addPathSuffix(logPath, "_sim")));
+ break;
+ }
+ }
+
+ // See http://bit.ly/3YIzFZ6 for more information on timestamps in AdvantageKit.
+ // Logger.disableDeterministicTimestamps()
+
+ // Start AdvantageKit logger
+ Logger.start();
+
+ // Instantiate our RobotContainer. This will perform all our button bindings,
+ // and put our autonomous chooser on the dashboard.
+ robotContainer = new RobotContainer();
+ }
+
+ /**
+ * This function is called periodically during all modes.
+ */
+ @Override
+ public void robotPeriodic() {
+ // Runs the Scheduler. This is responsible for polling buttons, adding
+ // newly-scheduled commands, running already-scheduled commands, removing
+ // finished or interrupted commands, and running subsystem periodic() methods.
+ // This must be called from the robot's periodic block in order for anything in
+ // the Command-based framework to work.
+ CommandScheduler.getInstance().run();
+ }
+
+ /**
+ * This function is called once when the robot is disabled.
+ */
+ @Override
+ public void disabledInit() {
+ }
+
+ /**
+ * This function is called periodically when disabled.
+ */
+ @Override
+ public void disabledPeriodic() {
+ }
+
+ /**
+ * This autonomous runs the autonomous command selected by your {@link RobotContainer} class.
+ */
+ @Override
+ public void autonomousInit() {
+ autonomousCommand = robotContainer.getAutonomousCommand();
+
+ // schedule the autonomous command (example)
+ if (autonomousCommand != null) {
+ autonomousCommand.schedule();
+ }
+ }
+
+ /**
+ * This function is called periodically during autonomous.
+ */
+ @Override
+ public void autonomousPeriodic() {
+ }
+
+ /**
+ * This function is called once when teleop is enabled.
+ */
+ @Override
+ public void teleopInit() {
+ // This makes sure that the autonomous stops running when
+ // teleop starts running. If you want the autonomous to
+ // continue until interrupted by another command, remove
+ // this line or comment it out.
+ if (autonomousCommand != null) {
+ autonomousCommand.cancel();
+ }
+ }
+
+ /**
+ * This function is called periodically during operator control.
+ */
+ @Override
+ public void teleopPeriodic() {
+ }
+
+ /**
+ * This function is called once when test mode is enabled.
+ */
+ @Override
+ public void testInit() {
+ // 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() {
+ }
+
+ /**
+ * This function is called once when the robot is first started up.
+ */
+ @Override
+ public void simulationInit() {
+ }
+
+ /**
+ * This function is called periodically whilst in simulation.
+ */
+ @Override
+ public void simulationPeriodic() {
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/RobotContainer.java b/src/main/java/org/team1540/advantagekitdemo/RobotContainer.java
new file mode 100644
index 0000000..1bb619f
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/RobotContainer.java
@@ -0,0 +1,66 @@
+// Copyright 2021-2023 FRC 6328
+// http://github.com/Mechanical-Advantage
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 3 as published by the Free Software Foundation or
+// available in the root directory of this project.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+package org.team1540.advantagekitdemo;
+
+import edu.wpi.first.wpilibj.GenericHID;
+import edu.wpi.first.wpilibj.XboxController;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.InstantCommand;
+import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
+import org.team1540.advantagekitdemo.subsystems.drivetrain.Drivetrain;
+import org.team1540.advantagekitdemo.subsystems.drivetrain.DrivetrainIOReal;
+import org.team1540.advantagekitdemo.subsystems.drivetrain.DrivetrainIOSim;
+
+/**
+ * This class is where the bulk of the robot should be declared. Since Command-based is a
+ * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot}
+ * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including
+ * subsystems, commands, and button mappings) should be declared here.
+ */
+public class RobotContainer {
+ // Controller
+ private final CommandXboxController controller = new CommandXboxController(0);
+
+ final Drivetrain drivetrain;
+
+ /**
+ * The container for the robot. Contains subsystems, OI devices, and commands.
+ */
+ public RobotContainer() {
+ if (Robot.isReal()) {
+ drivetrain = new Drivetrain(new DrivetrainIOReal());
+ } else {
+ drivetrain = new Drivetrain(new DrivetrainIOSim());
+ }
+ configureButtonBindings();
+ }
+
+ /**
+ * 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}.
+ */
+ private void configureButtonBindings() {
+ }
+
+ /**
+ * Use this to pass the autonomous command to the main {@link Robot} class.
+ *
+ * @return the command to run in autonomous
+ */
+ public Command getAutonomousCommand() {
+ return new InstantCommand();
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/commands/auto/PathPlannerDriveCommand.java b/src/main/java/org/team1540/advantagekitdemo/commands/auto/PathPlannerDriveCommand.java
new file mode 100644
index 0000000..54afcc4
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/commands/auto/PathPlannerDriveCommand.java
@@ -0,0 +1,16 @@
+package org.team1540.advantagekitdemo.commands.auto;
+
+import com.pathplanner.lib.path.PathPlannerPath;
+import com.pathplanner.lib.util.PathPlannerLogging;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.SequentialCommandGroup;
+import org.team1540.advantagekitdemo.subsystems.drivetrain.Drivetrain;
+
+public class PathPlannerDriveCommand extends SequentialCommandGroup {
+ public PathPlannerDriveCommand(Drivetrain drivetrain, PathPlannerPath path, boolean resetToPath) {
+ PathPlannerLogging.logActivePath(path);
+ Command pathCommand = drivetrain.getPathCommand(path, resetToPath);
+ addRequirements(drivetrain);
+ addCommands(pathCommand);
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/Drivetrain.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/Drivetrain.java
new file mode 100644
index 0000000..e9973e1
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/Drivetrain.java
@@ -0,0 +1,126 @@
+package org.team1540.advantagekitdemo.subsystems.drivetrain;
+
+import com.pathplanner.lib.commands.FollowPathRamsete;
+import com.pathplanner.lib.path.PathPlannerPath;
+import com.pathplanner.lib.util.PathPlannerLogging;
+import com.pathplanner.lib.util.ReplanningConfig;
+import edu.wpi.first.math.controller.PIDController;
+import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator;
+import edu.wpi.first.math.geometry.Pose2d;
+import edu.wpi.first.math.geometry.Rotation2d;
+import edu.wpi.first.math.kinematics.ChassisSpeeds;
+import edu.wpi.first.math.kinematics.DifferentialDriveWheelPositions;
+import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.Commands;
+import edu.wpi.first.wpilibj2.command.InstantCommand;
+import edu.wpi.first.wpilibj2.command.SubsystemBase;
+import org.littletonrobotics.junction.AutoLogOutput;
+import org.littletonrobotics.junction.Logger;
+
+import static org.team1540.advantagekitdemo.Constants.DrivetrainConstants.*;
+
+public class Drivetrain extends SubsystemBase {
+ private final DrivetrainIO io;
+ private final DrivetrainIOInputsAutoLogged inputs = new DrivetrainIOInputsAutoLogged();
+ private final DifferentialDrivePoseEstimator poseEstimator =
+ new DifferentialDrivePoseEstimator(
+ driveKinematics,
+ getYaw(),
+ getWheelPositions().leftMeters,
+ getWheelPositions().rightMeters,
+ new Pose2d()
+ );
+ private final PIDController velocityPID = new PIDController(VELOCITY_KP, VELOCITY_KI, VELOCITY_KD);
+
+ private boolean isClosedLoop = false;
+ private DifferentialDriveWheelSpeeds closedLoopSetpoint;
+
+ public Drivetrain(DrivetrainIO io) {
+ this.io = io;
+ PathPlannerLogging.setLogActivePathCallback(
+ activePath -> {
+ Logger.recordOutput("odometry/activePath", activePath.toArray(new Pose2d[activePath.size()]));
+ }
+ );
+ }
+
+ @Override
+ public void periodic() {
+ poseEstimator.update(getYaw(), getWheelPositions());
+ if (isClosedLoop && closedLoopSetpoint != null) {
+ setVoltage(
+ velocityPID.calculate(getWheelSpeeds().leftMetersPerSecond, closedLoopSetpoint.leftMetersPerSecond),
+ velocityPID.calculate(getWheelSpeeds().rightMetersPerSecond, closedLoopSetpoint.rightMetersPerSecond)
+ );
+ }
+
+ io.updateInputs(inputs);
+ Logger.processInputs("Drivetrain", inputs);
+ }
+
+ public void drivePercent(double leftPercent, double rightPercent) {
+ isClosedLoop = false;
+ setVoltage(12 * leftPercent, 12 * rightPercent);
+ }
+
+ private void setVoltage(double leftVoltage, double rightVoltage) {
+ io.setVoltage(leftVoltage, rightVoltage);
+ }
+
+ public void setChassisSpeeds(ChassisSpeeds chassisSpeeds) {
+ setWheelSpeeds(driveKinematics.toWheelSpeeds(chassisSpeeds));
+ }
+
+ public void setWheelSpeeds(DifferentialDriveWheelSpeeds wheelSpeeds) {
+ isClosedLoop = true;
+ velocityPID.reset();
+ closedLoopSetpoint = wheelSpeeds;
+ }
+
+ public void stop() {
+ isClosedLoop = false;
+ io.setVoltage(0.0, 0.0);
+ }
+
+ public Command getPathCommand(PathPlannerPath path, boolean resetToPath) {
+ return Commands.sequence(
+ new InstantCommand(() -> {
+ if (resetToPath) resetOdometry(path.getStartingDifferentialPose());
+ }),
+ new FollowPathRamsete(
+ path,
+ this::getPose,
+ this::getChassisSpeeds,
+ this::setChassisSpeeds,
+ new ReplanningConfig(),
+ this
+ )
+ );
+ }
+
+ public Rotation2d getYaw() {
+ return inputs.gyroYaw;
+ }
+
+ @AutoLogOutput
+ public Pose2d getPose() {
+ return poseEstimator.getEstimatedPosition();
+ }
+
+ public void resetOdometry(Pose2d pose) {
+ poseEstimator.resetPosition(inputs.gyroYaw, getWheelPositions(), pose);
+ }
+
+ public ChassisSpeeds getChassisSpeeds() {
+ return driveKinematics.toChassisSpeeds(getWheelSpeeds());
+ }
+
+ public DifferentialDriveWheelPositions getWheelPositions() {
+ return new DifferentialDriveWheelPositions(inputs.leftPositionMeters, inputs.rightPositionMeters);
+ }
+
+ public DifferentialDriveWheelSpeeds getWheelSpeeds() {
+ return new DifferentialDriveWheelSpeeds(inputs.leftVelocityMPS, inputs.rightVelocityMPS);
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIO.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIO.java
new file mode 100644
index 0000000..ca59624
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIO.java
@@ -0,0 +1,25 @@
+package org.team1540.advantagekitdemo.subsystems.drivetrain;
+
+import edu.wpi.first.math.geometry.Rotation2d;
+import org.littletonrobotics.junction.AutoLog;
+
+public interface DrivetrainIO {
+ @AutoLog
+ class DrivetrainIOInputs {
+ public double leftPositionMeters = 0.0;
+ public double leftVelocityMPS = 0.0;
+ public double leftAppliedVolts = 0.0;
+ public double[] leftCurrentAmps = new double[] {};
+
+ public double rightPositionMeters = 0.0;
+ public double rightVelocityMPS = 0.0;
+ public double rightAppliedVolts = 0.0;
+ public double[] rightCurrentAmps = new double[] {};
+
+ public Rotation2d gyroYaw = new Rotation2d();
+ }
+
+ default void updateInputs(DrivetrainIOInputs inputs) {}
+
+ default void setVoltage(double leftVolts, double rightVolts) {}
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIOReal.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIOReal.java
new file mode 100644
index 0000000..914282c
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIOReal.java
@@ -0,0 +1,111 @@
+package org.team1540.advantagekitdemo.subsystems.drivetrain;
+
+import com.ctre.phoenix6.BaseStatusSignal;
+import com.ctre.phoenix6.StatusSignal;
+import com.ctre.phoenix6.configs.TalonFXConfiguration;
+import com.ctre.phoenix6.controls.Follower;
+import com.ctre.phoenix6.controls.VoltageOut;
+import com.ctre.phoenix6.hardware.Pigeon2;
+import com.ctre.phoenix6.hardware.TalonFX;
+import com.ctre.phoenix6.signals.NeutralModeValue;
+import edu.wpi.first.math.MathUtil;
+import edu.wpi.first.math.geometry.Rotation2d;
+import org.team1540.advantagekitdemo.util.Conversions;
+
+import static org.team1540.advantagekitdemo.Constants.DrivetrainConstants.*;
+
+public class DrivetrainIOReal implements DrivetrainIO {
+
+ private final TalonFX leftLeader = new TalonFX(FL_ID);
+ private final TalonFX leftFollower = new TalonFX(BL_ID);
+ private final TalonFX rightLeader = new TalonFX(FR_ID);
+ private final TalonFX rightFollower = new TalonFX(BR_ID);
+
+ private final StatusSignal leftPosition = leftLeader.getPosition();
+ private final StatusSignal leftVelocity = leftLeader.getVelocity();
+ private final StatusSignal leftAppliedVolts = leftLeader.getMotorVoltage();
+ private final StatusSignal leftLeaderCurrent = leftLeader.getStatorCurrent();
+ private final StatusSignal leftFollowerCurrent = leftFollower.getStatorCurrent();
+
+ private final StatusSignal rightPosition = rightLeader.getPosition();
+ private final StatusSignal rightVelocity = rightLeader.getVelocity();
+ private final StatusSignal rightAppliedVolts = rightLeader.getMotorVoltage();
+ private final StatusSignal rightLeaderCurrent = rightLeader.getStatorCurrent();
+ private final StatusSignal rightFollowerCurrent = rightFollower.getStatorCurrent();
+
+ private final Pigeon2 pigeon = new Pigeon2(20);
+ private final StatusSignal yaw = pigeon.getYaw();
+
+ public DrivetrainIOReal() {
+ var config = new TalonFXConfiguration();
+ config.CurrentLimits.StatorCurrentLimit = 30.0;
+ config.CurrentLimits.StatorCurrentLimitEnable = true;
+ config.MotorOutput.NeutralMode = NeutralModeValue.Brake;
+ leftLeader.getConfigurator().apply(config);
+ leftFollower.getConfigurator().apply(config);
+ rightLeader.getConfigurator().apply(config);
+ rightFollower.getConfigurator().apply(config);
+ leftFollower.setControl(new Follower(leftLeader.getDeviceID(), false));
+ rightFollower.setControl(new Follower(rightLeader.getDeviceID(), false));
+
+ BaseStatusSignal.setUpdateFrequencyForAll(
+ 100.0, leftPosition, rightPosition, yaw); // Required for odometry, use faster rate
+ BaseStatusSignal.setUpdateFrequencyForAll(
+ 50.0,
+ leftVelocity,
+ leftAppliedVolts,
+ leftLeaderCurrent,
+ leftFollowerCurrent,
+ rightVelocity,
+ rightAppliedVolts,
+ rightLeaderCurrent,
+ rightFollowerCurrent);
+ leftLeader.optimizeBusUtilization();
+ leftFollower.optimizeBusUtilization();
+ rightLeader.optimizeBusUtilization();
+ rightFollower.optimizeBusUtilization();
+ pigeon.optimizeBusUtilization();
+ }
+
+ @Override
+ public void updateInputs(DrivetrainIOInputs inputs) {
+ BaseStatusSignal.refreshAll(
+ leftPosition,
+ leftVelocity,
+ leftAppliedVolts,
+ leftLeaderCurrent,
+ leftFollowerCurrent,
+ rightPosition,
+ rightVelocity,
+ rightAppliedVolts,
+ rightLeaderCurrent,
+ rightFollowerCurrent,
+ yaw);
+
+ inputs.leftPositionMeters = Conversions.motorRotsToMeters(
+ leftPosition.getValue(), WHEEL_DIAMETER_METERS, GEAR_RATIO);
+ inputs.leftVelocityMPS = Conversions.motorRotsToMeters(
+ leftVelocity.getValue(), WHEEL_DIAMETER_METERS, GEAR_RATIO
+ );
+ inputs.leftAppliedVolts = leftAppliedVolts.getValueAsDouble();
+ inputs.leftCurrentAmps =
+ new double[]{leftLeaderCurrent.getValueAsDouble(), leftFollowerCurrent.getValueAsDouble()};
+
+ inputs.rightPositionMeters = Conversions.motorRotsToMeters(
+ rightPosition.getValue(), WHEEL_DIAMETER_METERS, GEAR_RATIO);
+ inputs.rightVelocityMPS = Conversions.motorRotsToMeters(
+ rightVelocity.getValue(), WHEEL_DIAMETER_METERS, GEAR_RATIO
+ );
+ inputs.rightAppliedVolts = rightAppliedVolts.getValueAsDouble();
+ inputs.rightCurrentAmps =
+ new double[]{rightLeaderCurrent.getValueAsDouble(), rightFollowerCurrent.getValueAsDouble()};
+
+ inputs.gyroYaw = Rotation2d.fromDegrees(yaw.getValueAsDouble());
+ }
+
+ @Override
+ public void setVoltage(double leftVolts, double rightVolts) {
+ leftLeader.setControl(new VoltageOut(MathUtil.clamp(leftVolts, -12, 12)));
+ rightLeader.setControl(new VoltageOut(MathUtil.clamp(rightVolts, -12, 12)));
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIOSim.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIOSim.java
new file mode 100644
index 0000000..2dd6d77
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/drivetrain/DrivetrainIOSim.java
@@ -0,0 +1,46 @@
+package org.team1540.advantagekitdemo.subsystems.drivetrain;
+
+import edu.wpi.first.math.MathUtil;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.wpilibj.simulation.DifferentialDrivetrainSim;
+
+import static org.team1540.advantagekitdemo.Constants.DrivetrainConstants.*;
+
+public class DrivetrainIOSim implements DrivetrainIO {
+ private final DifferentialDrivetrainSim sim =
+ new DifferentialDrivetrainSim(
+ DCMotor.getFalcon500(2),
+ GEAR_RATIO,
+ ROBOT_MOI,
+ ROBOT_WEIGHT_KG,
+ WHEEL_DIAMETER_METERS / 2,
+ TRACK_WIDTH_METERS,
+ null
+ );
+
+ private double leftAppliedVolts = 0.0;
+ private double rightAppliedVolts = 0.0;
+
+ @Override
+ public void updateInputs(DrivetrainIOInputs inputs) {
+ sim.update(0.02);
+ inputs.leftPositionMeters = sim.getLeftPositionMeters();
+ inputs.leftVelocityMPS = sim.getLeftVelocityMetersPerSecond();
+ inputs.leftAppliedVolts = leftAppliedVolts;
+ inputs.leftCurrentAmps = new double[]{sim.getLeftCurrentDrawAmps()};
+
+ inputs.rightPositionMeters = sim.getRightPositionMeters();
+ inputs.rightVelocityMPS = sim.getRightVelocityMetersPerSecond();
+ inputs.rightAppliedVolts = rightAppliedVolts;
+ inputs.rightCurrentAmps = new double[]{sim.getRightCurrentDrawAmps()};
+
+ inputs.gyroYaw = sim.getHeading();
+ }
+
+ @Override
+ public void setVoltage(double leftVolts, double rightVolts) {
+ leftAppliedVolts = MathUtil.clamp(leftVolts, -12.0, 12.0);
+ rightAppliedVolts = MathUtil.clamp(rightVolts, -12.0, 12.0);
+ sim.setInputs(leftAppliedVolts, rightAppliedVolts);
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/Elevator.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/Elevator.java
new file mode 100644
index 0000000..fd69f61
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/Elevator.java
@@ -0,0 +1,52 @@
+package org.team1540.advantagekitdemo.subsystems.elevator;
+
+import edu.wpi.first.math.controller.ElevatorFeedforward;
+import edu.wpi.first.math.controller.ProfiledPIDController;
+import edu.wpi.first.math.trajectory.TrapezoidProfile;
+import edu.wpi.first.wpilibj2.command.ProfiledPIDSubsystem;
+import org.littletonrobotics.junction.Logger;
+
+import static org.team1540.advantagekitdemo.Constants.ElevatorConstants.*;
+
+public class Elevator extends ProfiledPIDSubsystem {
+ private final ElevatorIO io;
+ private final ElevatorIOInputsAutoLogged inputs = new ElevatorIOInputsAutoLogged();
+
+ private final ElevatorFeedforward feedforward = new ElevatorFeedforward(KS, KG, KV);
+
+ public Elevator(ElevatorIO io) {
+ super(new ProfiledPIDController(KP, KI, KD, MOTION_CONSTRAINTS));
+ this.io = io;
+ }
+
+ @Override
+ public void periodic() {
+ super.periodic();
+ io.updateInputs(inputs);
+ Logger.processInputs("Elevator", inputs);
+ }
+
+ public void setPercent(double percentOutput) {
+ disable();
+ setVoltage(12 * percentOutput);
+ }
+
+ private void setVoltage(double volts) {
+ io.setVoltage(volts);
+ }
+
+ public void setPosition(double positionMeters) {
+ enable();
+ setGoal(positionMeters);
+ }
+
+ @Override
+ protected void useOutput(double output, TrapezoidProfile.State setpoint) {
+ setVoltage(output + feedforward.calculate(setpoint.velocity));
+ }
+
+ @Override
+ protected double getMeasurement() {
+ return inputs.positionMeters;
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/ElevatorIO.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/ElevatorIO.java
new file mode 100644
index 0000000..7b346df
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/ElevatorIO.java
@@ -0,0 +1,18 @@
+package org.team1540.advantagekitdemo.subsystems.elevator;
+
+import org.littletonrobotics.junction.AutoLog;
+
+public interface ElevatorIO {
+
+
+ @AutoLog
+ class ElevatorIOInputs {
+ public double positionMeters = 0;
+ public double appliedVolts = 0;
+ public double currentAmps = 0;
+ }
+
+ default void updateInputs(ElevatorIOInputs inputs) {}
+
+ default void setVoltage(double volts) {}
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/ElevatorIOSim.java b/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/ElevatorIOSim.java
new file mode 100644
index 0000000..5086917
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/subsystems/elevator/ElevatorIOSim.java
@@ -0,0 +1,38 @@
+package org.team1540.advantagekitdemo.subsystems.elevator;
+
+import edu.wpi.first.math.MathUtil;
+import edu.wpi.first.math.system.plant.DCMotor;
+import edu.wpi.first.wpilibj.simulation.ElevatorSim;
+
+import static org.team1540.advantagekitdemo.Constants.ElevatorConstants.*;
+
+public class ElevatorIOSim implements ElevatorIO {
+ private final ElevatorSim sim =
+ new ElevatorSim(
+ DCMotor.getFalcon500(2),
+ GEAR_RATIO,
+ CARRIAGE_MASS_KG,
+ DRUM_RADIUS_METERS,
+ 0,
+ MAX_HEIGHT_METERS/2, // divide by 2 due to cascade rigging
+ true,
+ 0,
+ null
+ );
+
+ private double appliedVolts = 0;
+
+ @Override
+ public void updateInputs(ElevatorIOInputs inputs) {
+ sim.update(0.02);
+ inputs.positionMeters = sim.getPositionMeters() * 2; // multiplied by 2 due to cascade rigging
+ inputs.appliedVolts = appliedVolts;
+ inputs.currentAmps = sim.getCurrentDrawAmps();
+ }
+
+ @Override
+ public void setVoltage(double volts) {
+ appliedVolts = MathUtil.clamp(volts, -12, 12);
+ sim.setInputVoltage(volts);
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/util/AutoCommand.java b/src/main/java/org/team1540/advantagekitdemo/util/AutoCommand.java
new file mode 100644
index 0000000..0f2f71b
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/util/AutoCommand.java
@@ -0,0 +1,34 @@
+package org.team1540.advantagekitdemo.util;
+
+import com.pathplanner.lib.commands.PathPlannerAuto;
+import com.pathplanner.lib.path.PathConstraints;
+import com.pathplanner.lib.path.PathPlannerPath;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.SequentialCommandGroup;
+import org.team1540.advantagekitdemo.commands.auto.PathPlannerDriveCommand;
+import org.team1540.advantagekitdemo.subsystems.drivetrain.Drivetrain;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public abstract class AutoCommand extends SequentialCommandGroup {
+
+ public Command getPathPlannerDriveCommand(Drivetrain drivetrain, String pathName, boolean resetToPath) {
+ PathPlannerPath path = PathPlannerPath.fromPathFile(pathName);
+ return new PathPlannerDriveCommand(drivetrain, path, resetToPath);
+ }
+
+ public List getPathPlannerDriveCommandGroup(
+ Drivetrain drivetrain,
+ String autoName,
+ boolean resetToPath) {
+ List paths = PathPlannerAuto.getPathGroupFromAutoFile(autoName);
+ LinkedList commands = new LinkedList<>();
+ commands.addLast(new PathPlannerDriveCommand(drivetrain, paths.get(0), resetToPath));
+ for (int i = 1; i < paths.size(); i++) {
+ commands.addLast(new PathPlannerDriveCommand(drivetrain, paths.get(i), false));
+ }
+ return commands;
+ }
+}
diff --git a/src/main/java/org/team1540/advantagekitdemo/util/Conversions.java b/src/main/java/org/team1540/advantagekitdemo/util/Conversions.java
new file mode 100644
index 0000000..09db2f6
--- /dev/null
+++ b/src/main/java/org/team1540/advantagekitdemo/util/Conversions.java
@@ -0,0 +1,71 @@
+package org.team1540.advantagekitdemo.util;
+
+import edu.wpi.first.math.geometry.Rotation2d;
+
+public class Conversions {
+ /**
+ * Converts a motor rotation count into mechanism rotations based on a gear ratio
+ * @param rotationCounts motor rotation counts
+ * @param gearRatio the gear ratio between motor and the mechanism
+ * @return mechanism rotation in {@link Rotation2d}
+ */
+ public static Rotation2d motorRotsToRotation2d(double rotationCounts, double gearRatio) {
+ return Rotation2d.fromRotations(rotationCounts / gearRatio);
+ }
+
+ /**
+ * Converts a mechanism rotation (in {@link Rotation2d}) to motor rotation counts
+ * @param rotations mechanism rotation
+ * @param gearRatio gear ratio between motor and mechanism
+ * @return motor rotation counts
+ */
+ public static double Rotation2dToMotorRots(Rotation2d rotations, double gearRatio) {
+ return rotations.getRotations() * gearRatio;
+ }
+
+ /**
+ * Converts a motor rotation count into meters
+ * @param rotationCounts motor rotation counts
+ * @param wheelDiameter wheel diameter in meters
+ * @param gearRatio gear ratio between motor and wheel
+ * @return meters
+ */
+ public static double motorRotsToMeters(double rotationCounts, double wheelDiameter, double gearRatio) {
+ double wheelCircumference = Math.PI * wheelDiameter;
+ return (rotationCounts / gearRatio) * wheelCircumference;
+ }
+
+ /**
+ * Converts meters to motor rotation counts
+ * @param meters meters
+ * @param wheelDiameter wheel diameter in meters
+ * @param gearRatio gear ratio between motor and wheel
+ * @return motor rotation counts
+ */
+ public static double metersToMotorRots(double meters, double wheelDiameter, double gearRatio) {
+ double wheelCircumference = Math.PI * wheelDiameter;
+ return (meters / wheelCircumference) * gearRatio;
+ }
+
+ /**
+ * Converts rotations per minute to meters per second
+ * @param rpm rotations per minute
+ * @param wheelDiameter wheel diameter in meters
+ * @param gearRatio gear ratio between motor and wheel
+ * @return meters per second
+ */
+ public static double RPMtoMPS(double rpm, double wheelDiameter, double gearRatio) {
+ return motorRotsToMeters(rpm/60, wheelDiameter, gearRatio);
+ }
+
+ /**
+ * Converts meters per second to rotations per minute
+ * @param mps meters per second
+ * @param wheelDiameter wheel diameter in meters
+ * @param gearRatio gear ratio between motor and wheel
+ * @return rotations per minute
+ */
+ public static double MPStoRPM(double mps, double wheelDiameter, double gearRatio) {
+ return metersToMotorRots(mps, wheelDiameter, gearRatio) * 60;
+ }
+}
diff --git a/vendordeps/AdvantageKit.json b/vendordeps/AdvantageKit.json
new file mode 100644
index 0000000..e5b7c21
--- /dev/null
+++ b/vendordeps/AdvantageKit.json
@@ -0,0 +1,42 @@
+{
+ "fileName": "AdvantageKit.json",
+ "name": "AdvantageKit",
+ "version": "3.0.0-beta-6",
+ "uuid": "d820cc26-74e3-11ec-90d6-0242ac120003",
+ "frcYear": "2024",
+ "mavenUrls": [],
+ "jsonUrl": "https://github.com/Mechanical-Advantage/AdvantageKit/releases/latest/download/AdvantageKit.json",
+ "javaDependencies": [
+ {
+ "groupId": "org.littletonrobotics.akit.junction",
+ "artifactId": "wpilib-shim",
+ "version": "3.0.0-beta-6"
+ },
+ {
+ "groupId": "org.littletonrobotics.akit.junction",
+ "artifactId": "junction-core",
+ "version": "3.0.0-beta-6"
+ },
+ {
+ "groupId": "org.littletonrobotics.akit.conduit",
+ "artifactId": "conduit-api",
+ "version": "3.0.0-beta-6"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "org.littletonrobotics.akit.conduit",
+ "artifactId": "conduit-wpilibio",
+ "version": "3.0.0-beta-6",
+ "skipInvalidPlatforms": false,
+ "isJar": false,
+ "validPlatforms": [
+ "linuxathena",
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ]
+ }
+ ],
+ "cppDependencies": []
+}
\ No newline at end of file
diff --git a/vendordeps/PathplannerLib.json b/vendordeps/PathplannerLib.json
new file mode 100644
index 0000000..ed56e28
--- /dev/null
+++ b/vendordeps/PathplannerLib.json
@@ -0,0 +1,38 @@
+{
+ "fileName": "PathplannerLib.json",
+ "name": "PathplannerLib",
+ "version": "2024.0.0-beta-5.1",
+ "uuid": "1b42324f-17c6-4875-8e77-1c312bc8c786",
+ "frcYear": "2024",
+ "mavenUrls": [
+ "https://3015rangerrobotics.github.io/pathplannerlib/repo"
+ ],
+ "jsonUrl": "https://3015rangerrobotics.github.io/pathplannerlib/PathplannerLib.json",
+ "javaDependencies": [
+ {
+ "groupId": "com.pathplanner.lib",
+ "artifactId": "PathplannerLib-java",
+ "version": "2024.0.0-beta-5.1"
+ }
+ ],
+ "jniDependencies": [],
+ "cppDependencies": [
+ {
+ "groupId": "com.pathplanner.lib",
+ "artifactId": "PathplannerLib-cpp",
+ "version": "2024.0.0-beta-5.1",
+ "libName": "PathplannerLib",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal",
+ "linuxathena",
+ "linuxarm32",
+ "linuxarm64"
+ ]
+ }
+ ]
+}
diff --git a/vendordeps/Phoenix6.json b/vendordeps/Phoenix6.json
new file mode 100644
index 0000000..3f79af2
--- /dev/null
+++ b/vendordeps/Phoenix6.json
@@ -0,0 +1,339 @@
+{
+ "fileName": "Phoenix6.json",
+ "name": "CTRE-Phoenix (v6)",
+ "version": "24.0.0-beta-4",
+ "frcYear": 2024,
+ "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-frc2024-beta-latest.json",
+ "conflictsWith": [
+ {
+ "uuid": "3fcf3402-e646-4fa6-971e-18afe8173b1a",
+ "errorMessage": "The combined Phoenix-6-And-5 vendordep is no longer supported. Please remove the vendordep and instead add both the latest Phoenix 6 vendordep and Phoenix 5 vendordep.",
+ "offlineFileName": "Phoenix6And5.json"
+ }
+ ],
+ "javaDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "wpiapi-java",
+ "version": "24.0.0-beta-4"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "tools",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxathena"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "tools-sim",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonSRX",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonFX",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simVictorSPX",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simCANCoder",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFX",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANcoder",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProPigeon2",
+ "version": "24.0.0-beta-4",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "wpiapi-cpp",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_Phoenix6_WPI",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxathena"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "tools",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_PhoenixTools",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxathena"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "wpiapi-cpp-sim",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_Phoenix6_WPISim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "tools-sim",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_PhoenixTools_Sim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonSRX",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimTalonSRX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonFX",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimTalonFX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simVictorSPX",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimVictorSPX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimPigeonIMU",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simCANCoder",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimCANCoder",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFX",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimProTalonFX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANcoder",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimProCANcoder",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProPigeon2",
+ "version": "24.0.0-beta-4",
+ "libName": "CTRE_SimProPigeon2",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ }
+ ]
+}
diff --git a/vendordeps/REVLib.json b/vendordeps/REVLib.json
new file mode 100644
index 0000000..cfafaba
--- /dev/null
+++ b/vendordeps/REVLib.json
@@ -0,0 +1,74 @@
+{
+ "fileName": "REVLib.json",
+ "name": "REVLib",
+ "version": "2024.0.0",
+ "frcYear": "2024",
+ "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb",
+ "mavenUrls": [
+ "https://maven.revrobotics.com/"
+ ],
+ "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2024.json",
+ "javaDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-java",
+ "version": "2024.0.0"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-driver",
+ "version": "2024.0.0",
+ "skipInvalidPlatforms": true,
+ "isJar": false,
+ "validPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxarm64",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxarm32",
+ "osxuniversal"
+ ]
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-cpp",
+ "version": "2024.0.0",
+ "libName": "REVLib",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxarm64",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxarm32",
+ "osxuniversal"
+ ]
+ },
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-driver",
+ "version": "2024.0.0",
+ "libName": "REVLibDriver",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxarm64",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxarm32",
+ "osxuniversal"
+ ]
+ }
+ ]
+}
diff --git a/vendordeps/WPILibNewCommands.json b/vendordeps/WPILibNewCommands.json
new file mode 100644
index 0000000..67bf389
--- /dev/null
+++ b/vendordeps/WPILibNewCommands.json
@@ -0,0 +1,38 @@
+{
+ "fileName": "WPILibNewCommands.json",
+ "name": "WPILib-New-Commands",
+ "version": "1.0.0",
+ "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
+ "frcYear": "2024",
+ "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"
+ ]
+ }
+ ]
+}