diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml
new file mode 100644
index 0000000..652d7eb
--- /dev/null
+++ b/.github/workflows/gradle.yml
@@ -0,0 +1,67 @@
+# This workflow uses actions that are not certified by GitHub.
+# They are provided by a third-party and are governed by
+# separate terms of service, privacy policy, and support
+# documentation.
+# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
+
+name: Java / Kotlin CI with Gradle
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ # Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
+ # See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
+ - name: Setup Gradle
+ uses: gradle/actions/setup-gradle@ec92e829475ac0c2315ea8f9eced72db85bb337a # v3.0.0
+
+ - name: Build with Gradle Wrapper
+ run: ./gradlew build
+
+ # NOTE: The Gradle Wrapper is the default and recommended way to run Gradle (https://docs.gradle.org/current/userguide/gradle_wrapper.html).
+ # If your project does not have the Gradle Wrapper configured, you can use the following configuration to run Gradle with a specified version.
+ #
+ # - name: Setup Gradle
+ # uses: gradle/actions/setup-gradle@ec92e829475ac0c2315ea8f9eced72db85bb337a # v3.0.0
+ # with:
+ # gradle-version: '8.5'
+ #
+ # - name: Build with Gradle 8.5
+ # run: gradle build
+
+ dependency-submission:
+
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+
+ # Generates and submits a dependency graph, enabling Dependabot Alerts for all project dependencies.
+ # See: https://github.com/gradle/actions/blob/main/dependency-submission/README.md
+ - name: Generate and submit dependency graph
+ uses: gradle/actions/dependency-submission@ec92e829475ac0c2315ea8f9eced72db85bb337a # v3.0.0
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e347dea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,182 @@
+# This gitignore has been specially created by the WPILib team.
+# If you remove items from this file, intellisense might break.
+
+### C++ ###
+# Prerequisites
+*.d
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+*.smod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+### Java ###
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### VisualStudioCode ###
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+### Windows ###
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+### Gradle ###
+.gradle
+/build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
+
+# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
+# gradle/wrapper/gradle-wrapper.properties
+
+# # VS Code Specific Java Settings
+# DO NOT REMOVE .classpath and .project
+.classpath
+.project
+.settings/
+bin/
+
+# IntelliJ
+*.iml
+*.ipr
+*.iws
+.idea/
+out/
+
+# Fleet
+.fleet
+
+# Simulation GUI and other tools window save file
+*-window.json
+
+ctre_sim/
+
+# Custom Owen stuff cause Logs suck
+logs/
+
+# Oh and I dont want someone elses sim
+simgui.json
+simgui-window.json
+simgui-ds.json
\ No newline at end of file
diff --git a/.pathplanner/settings.json b/.pathplanner/settings.json
new file mode 100644
index 0000000..47119bd
--- /dev/null
+++ b/.pathplanner/settings.json
@@ -0,0 +1,18 @@
+{
+ "robotWidth": 0.81,
+ "robotLength": 0.81,
+ "holonomicMode": true,
+ "pathFolders": [
+ "Amp Autos",
+ "Auto Move",
+ "General Defense",
+ "OP Autos",
+ "Other Team Autos"
+ ],
+ "autoFolders": [],
+ "defaultMaxVel": 5.0,
+ "defaultMaxAccel": 7.0,
+ "defaultMaxAngVel": 540.0,
+ "defaultMaxAngAccel": 720.0,
+ "maxModuleSpeed": 5.5
+}
\ No newline at end of file
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..c9c9713
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +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,
+ },
+ {
+ "type": "wpilib",
+ "name": "WPILib roboRIO Debug",
+ "request": "launch",
+ "desktop": false,
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..4ed293b
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,29 @@
+{
+ "java.configuration.updateBuildConfiguration": "automatic",
+ "java.server.launchMode": "Standard",
+ "files.exclude": {
+ "**/.git": true,
+ "**/.svn": true,
+ "**/.hg": true,
+ "**/CVS": true,
+ "**/.DS_Store": true,
+ "bin/": true,
+ "**/.classpath": true,
+ "**/.project": true,
+ "**/.settings": true,
+ "**/.factorypath": true,
+ "**/*~": true
+ },
+ "java.test.config": [
+ {
+ "name": "WPIlibUnitTests",
+ "workingDirectory": "${workspaceFolder}/build/jni/release",
+ "vmargs": [ "-Djava.library.path=${workspaceFolder}/build/jni/release" ],
+ "env": {
+ "LD_LIBRARY_PATH": "${workspaceFolder}/build/jni/release" ,
+ "DYLD_LIBRARY_PATH": "${workspaceFolder}/build/jni/release"
+ }
+ },
+ ],
+ "java.test.defaultConfig": "WPIlibUnitTests"
+}
diff --git a/.wpilib/wpilib_preferences.json b/.wpilib/wpilib_preferences.json
new file mode 100644
index 0000000..0b4f3e7
--- /dev/null
+++ b/.wpilib/wpilib_preferences.json
@@ -0,0 +1,6 @@
+{
+ "enableCppIntellisense": false,
+ "currentLanguage": "java",
+ "projectYear": "2024",
+ "teamNumber": 6854
+}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..42f7d8a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,7 @@
+
+
2024 Crescendo Official
+
+
+![Our 2024 Robot](/RobotPicture.png "Name TDB")
+
+The official robot code of FRC 6854's 2024 robot (Name TBD)
diff --git a/RobotPicture.png b/RobotPicture.png
new file mode 100644
index 0000000..5957293
Binary files /dev/null and b/RobotPicture.png differ
diff --git a/WPILib-License.md b/WPILib-License.md
new file mode 100644
index 0000000..645e542
--- /dev/null
+++ b/WPILib-License.md
@@ -0,0 +1,24 @@
+Copyright (c) 2009-2024 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..fff57fb
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,112 @@
+plugins {
+ id "java"
+ id "edu.wpi.first.GradleRIO" version "2024.3.2"
+ id 'org.jetbrains.kotlin.jvm' version '1.9.22'
+}
+
+
+java {
+}
+
+def ROBOT_MAIN_CLASS = "frc.robot.Main"
+
+// Define my targets (RoboRIO) and artifacts (deployable files)
+// This is added by GradleRIO's backing project DeployUtils.
+deploy {
+ targets {
+ roborio(getTargetTypeClass('RoboRIO')) {
+ checkImage = false
+ // 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
+
+// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
+// Also defines JUnit 5.
+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 "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
+ implementation 'io.github.microutils:kotlin-logging-jvm:2.0.11'
+ implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.4.14'
+}
+
+test {
+ useJUnitPlatform()
+ systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
+}
+
+// Simulation configuration (e.g. environment variables).
+wpi.sim.addGui().defaultEnabled = true
+wpi.sim.addDriverstation()
+
+// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat 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'
+}
+repositories {
+ mavenCentral()
+}
+kotlin {
+ jvmToolchain(17)
+}
diff --git a/elastic-layout.json b/elastic-layout.json
new file mode 100644
index 0000000..0e63a7e
--- /dev/null
+++ b/elastic-layout.json
@@ -0,0 +1 @@
+{"version":1.0,"grid_size":128,"tabs":[{"name":"Teleoperated","grid_layout":{"layouts":[{"title":"VisionSystemSim-photonvision","x":0.0,"y":512.0,"width":512.0,"height":256.0,"type":"List Layout","properties":{"label_position":"TOP"},"children":[{"title":"Sim Field","x":0.0,"y":0.0,"width":384.0,"height":256.0,"type":"Field","properties":{"topic":"/SmartDashboard/VisionSystemSim-photonvision/Sim Field","period":0.06,"field_game":"Crescendo","robot_width":0.85,"robot_length":0.85,"show_other_objects":true,"show_trajectories":false}}]}],"containers":[{"title":"Pose","x":768.0,"y":0.0,"width":768.0,"height":384.0,"type":"Field","properties":{"topic":"/Pose","period":0.06,"field_game":"Crescendo","robot_width":0.66,"robot_length":0.66,"show_other_objects":true,"show_trajectories":false}},{"title":"Autonomous Path Choices","x":1152.0,"y":384.0,"width":384.0,"height":128.0,"type":"ComboBox Chooser","properties":{"topic":"/SmartDashboard/Autonomous Path Choices","period":0.06,"sort_options":false}},{"title":"Scheduler","x":896.0,"y":384.0,"width":256.0,"height":384.0,"type":"Scheduler","properties":{"topic":"/SmartDashboard/Scheduler","period":0.06}},{"title":"Intake Command","x":1152.0,"y":512.0,"width":256.0,"height":128.0,"type":"Subsystem","properties":{"topic":"/SmartDashboard/Tools/Intake Command","period":0.06}},{"title":"Shooter Command","x":1152.0,"y":640.0,"width":256.0,"height":128.0,"type":"Subsystem","properties":{"topic":"/SmartDashboard/Tools/Shooter Command","period":0.06}},{"title":"IntakeFromGround","x":512.0,"y":0.0,"width":256.0,"height":128.0,"type":"Command","properties":{"topic":"/SmartDashboard/Tools/IntakeFromGround","period":0.06,"show_type":true}},{"title":"IntakeFromSource","x":512.0,"y":128.0,"width":256.0,"height":128.0,"type":"Command","properties":{"topic":"/SmartDashboard/Tools/IntakeFromSource","period":0.06,"show_type":true}},{"title":"Load","x":512.0,"y":256.0,"width":256.0,"height":128.0,"type":"Command","properties":{"topic":"/SmartDashboard/Tools/Load","period":0.06,"show_type":true}},{"title":"ShootToAmp","x":512.0,"y":384.0,"width":256.0,"height":128.0,"type":"Command","properties":{"topic":"/SmartDashboard/Tools/ShootToAmp","period":0.06,"show_type":true}}]}},{"name":"Autonomous","grid_layout":{"layouts":[],"containers":[]}}]}
\ No newline at end of file
diff --git a/glass.json b/glass.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/glass.json
@@ -0,0 +1 @@
+{}
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/networktables.json b/networktables.json
new file mode 100644
index 0000000..41b42e6
--- /dev/null
+++ b/networktables.json
@@ -0,0 +1,3 @@
+[
+
+]
diff --git a/networktables.json.bck b/networktables.json.bck
new file mode 100644
index 0000000..41b42e6
--- /dev/null
+++ b/networktables.json.bck
@@ -0,0 +1,3 @@
+[
+
+]
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..595ca4a
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,34 @@
+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
+ }
+ }
+}
+
+plugins {
+ id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
+}
+
+Properties props = System.getProperties();
+props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true");
diff --git a/src/main/deploy/pathplanner/autos/Amp + Defense Auto.auto b/src/main/deploy/pathplanner/autos/Amp + Defense Auto.auto
new file mode 100644
index 0000000..d5a4e4e
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Amp + Defense Auto.auto
@@ -0,0 +1,37 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.45267274290893716,
+ "y": 7.359196687936524
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Auto Score Preset"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Amplify"
+ }
+ },
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Defense"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Amp Auto Center.auto b/src/main/deploy/pathplanner/autos/Amp Auto Center.auto
new file mode 100644
index 0000000..6f1debd
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Amp Auto Center.auto
@@ -0,0 +1,49 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.45267274290893716,
+ "y": 7.359196687936524
+ },
+ "rotation": -90.0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Auto Score Preset"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Amplify"
+ }
+ },
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Auto Score Middle"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Amplify"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Amp Auto Neighbour.auto b/src/main/deploy/pathplanner/autos/Amp Auto Neighbour.auto
new file mode 100644
index 0000000..558e895
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Amp Auto Neighbour.auto
@@ -0,0 +1,49 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.45267274290893716,
+ "y": 7.359196687936524
+ },
+ "rotation": -90.15060842731938
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Auto Score Preset"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Amplify"
+ }
+ },
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Auto Score Neighbour"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Amplify"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Anti Anti Womp Womp Auto.auto b/src/main/deploy/pathplanner/autos/Anti Anti Womp Womp Auto.auto
new file mode 100644
index 0000000..9d87f53
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Anti Anti Womp Womp Auto.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.4986478208250535,
+ "y": 2.055327287125162
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Anti Anti Womp Womp Auto"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Defensive OP Park Top.auto b/src/main/deploy/pathplanner/autos/Defensive OP Park Top.auto
new file mode 100644
index 0000000..a5cb160
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Defensive OP Park Top.auto
@@ -0,0 +1,31 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.4860099872484003,
+ "y": 2.0585748379618596
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Park for OP Bot"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Break"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Dodge Leave.auto b/src/main/deploy/pathplanner/autos/Dodge Leave.auto
new file mode 100644
index 0000000..cdbd46e
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Dodge Leave.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 1.44445576200797,
+ "y": 1.5085103063607137
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Dodge Leave"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Go Straight Leave.auto b/src/main/deploy/pathplanner/autos/Go Straight Leave.auto
new file mode 100644
index 0000000..886683d
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Go Straight Leave.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 1.4694586952625677,
+ "y": 3.2170440787582084
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Basic Leave"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/One Note Amp.auto b/src/main/deploy/pathplanner/autos/One Note Amp.auto
new file mode 100644
index 0000000..5d90046
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/One Note Amp.auto
@@ -0,0 +1,49 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.45267274290893716,
+ "y": 7.359196687936524
+ },
+ "rotation": -90.93592681551108
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "wait",
+ "data": {
+ "waitTime": 9.0
+ }
+ },
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Auto Score Preset"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "Amplify"
+ }
+ },
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ },
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Amp Leave"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Pwow Pwow Auto.auto b/src/main/deploy/pathplanner/autos/Pwow Pwow Auto.auto
new file mode 100644
index 0000000..702e8cb
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Pwow Pwow Auto.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 1.4611243841777022,
+ "y": 7.350862376851658
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Pwow Pwow Auto"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Ready from Right.auto b/src/main/deploy/pathplanner/autos/Ready from Right.auto
new file mode 100644
index 0000000..f2aa94d
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Ready from Right.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.5110129205029978,
+ "y": 2.025237593622395
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Ready from Right"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Semi Defense from Right.auto b/src/main/deploy/pathplanner/autos/Semi Defense from Right.auto
new file mode 100644
index 0000000..e7082f7
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Semi Defense from Right.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.4743235368823679,
+ "y": 2.055327287125162
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Defense Auto Mini"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Three Note No Note Note Auto.auto b/src/main/deploy/pathplanner/autos/Three Note No Note Note Auto.auto
new file mode 100644
index 0000000..e982b9d
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Three Note No Note Note Auto.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.4864856788537107,
+ "y": 2.055327287125162
+ },
+ "rotation": 0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Three Note No Note Note Auto"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/autos/Womp Womp Auto.auto b/src/main/deploy/pathplanner/autos/Womp Womp Auto.auto
new file mode 100644
index 0000000..55e43ea
--- /dev/null
+++ b/src/main/deploy/pathplanner/autos/Womp Womp Auto.auto
@@ -0,0 +1,25 @@
+{
+ "version": 1.0,
+ "startingPose": {
+ "position": {
+ "x": 0.4864856788537107,
+ "y": 2.061408358110835
+ },
+ "rotation": 0.0
+ },
+ "command": {
+ "type": "sequential",
+ "data": {
+ "commands": [
+ {
+ "type": "path",
+ "data": {
+ "pathName": "Womp Womp Auto"
+ }
+ }
+ ]
+ }
+ },
+ "folder": null,
+ "choreoAuto": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/navgrid.json b/src/main/deploy/pathplanner/navgrid.json
new file mode 100644
index 0000000..8e821fc
--- /dev/null
+++ b/src/main/deploy/pathplanner/navgrid.json
@@ -0,0 +1 @@
+{"field_size":{"x":16.54,"y":8.21},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true],[true,true,true,true,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,false,false,false,true,true,true,true,true,true,true,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,true,true,true,true,true,true,true,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,true,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,true,false,false,false,true,true,true,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,true,true,true,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,true,false,false,false,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Amp Auto Score Middle.path b/src/main/deploy/pathplanner/paths/Amp Auto Score Middle.path
new file mode 100644
index 0000000..88f0ee9
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Amp Auto Score Middle.path
@@ -0,0 +1,178 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.8111654497420666,
+ "y": 7.692569131331156
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 7.928549786033582,
+ "y": 7.500879976379242
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.203582051834156,
+ "y": 7.417536865530584
+ },
+ "prevControl": {
+ "x": 5.328244727555445,
+ "y": 6.234064691479636
+ },
+ "nextControl": {
+ "x": 8.962674370619721,
+ "y": 7.729974863407541
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.153458855141061,
+ "y": 6.459091090771014
+ },
+ "prevControl": {
+ "x": 7.573649672824017,
+ "y": 6.295958185082336
+ },
+ "nextControl": {
+ "x": 6.4450424129274655,
+ "y": 6.734123356571587
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 5.494930949252761,
+ "y": 7.242516332748402
+ },
+ "prevControl": {
+ "x": 6.968261825121813,
+ "y": 6.987236230493863
+ },
+ "nextControl": {
+ "x": 3.8114001101098647,
+ "y": 7.534217220718706
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 1.8111654497420666,
+ "y": 7.692569131331156
+ },
+ "prevControl": {
+ "x": 2.3862329145978083,
+ "y": 7.542551531803571
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.1,
+ "rotationDegrees": -90.0,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 0.35,
+ "rotationDegrees": 180.0,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 1.0999999999999999,
+ "rotationDegrees": 180.0,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 3.15,
+ "rotationDegrees": -90.0,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 2.0999999999999996,
+ "rotationDegrees": -90.0,
+ "rotateFast": true
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [
+ {
+ "name": "Intake",
+ "waypointRelativePos": 0.45,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeFromGround"
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "Load",
+ "waypointRelativePos": 1.8,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "Keep",
+ "waypointRelativePos": 0.0,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 6.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 1000.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -88.8310161262258,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Amp Autos",
+ "previewStartingState": {
+ "rotation": -90.0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Amp Auto Score Neighbour.path b/src/main/deploy/pathplanner/paths/Amp Auto Score Neighbour.path
new file mode 100644
index 0000000..ec8f76f
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Amp Auto Score Neighbour.path
@@ -0,0 +1,152 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.8695056273361277,
+ "y": 7.767577931094949
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 1.43204914268401,
+ "y": 7.759476885082872
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 0.894391230406826,
+ "y": 6.800797845250513
+ },
+ "prevControl": {
+ "x": 0.2365563561237587,
+ "y": 7.140558714385723
+ },
+ "nextControl": {
+ "x": 1.6528135391296166,
+ "y": 6.40908522426182
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 3.986420642892047,
+ "y": 7.467542732039779
+ },
+ "prevControl": {
+ "x": 3.9943864024791202,
+ "y": 7.125015069795621
+ },
+ "nextControl": {
+ "x": 3.9780863318071815,
+ "y": 7.82591810868901
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 1.8695056273361277,
+ "y": 7.767577931094949
+ },
+ "prevControl": {
+ "x": 1.7111537167236786,
+ "y": 7.673816931390208
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.35,
+ "rotationDegrees": -90.0,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 1.35,
+ "rotationDegrees": 180.0,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 1.9500000000000002,
+ "rotationDegrees": -90.0,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [
+ {
+ "name": "Reset",
+ "waypointRelativePos": 0.0,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "Intake",
+ "waypointRelativePos": 0.65,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeFromGround"
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "name": "Load",
+ "waypointRelativePos": 1.5500000000000003,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "globalConstraints": {
+ "maxVelocity": 3.0,
+ "maxAcceleration": 5.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -90.82434282084512,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Amp Autos",
+ "previewStartingState": {
+ "rotation": -89.7344521391891,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Amp Auto Score Preset.path b/src/main/deploy/pathplanner/paths/Amp Auto Score Preset.path
new file mode 100644
index 0000000..6531085
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Amp Auto Score Preset.path
@@ -0,0 +1,52 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.45267274290893716,
+ "y": 7.359196687936524
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 1.0364555575333902,
+ "y": 7.18397428807996
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 1.7944968275723348,
+ "y": 7.700903442416022
+ },
+ "prevControl": {
+ "x": 1.520267746417846,
+ "y": 7.558696529157765
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 4.7,
+ "maxAcceleration": 4.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -90.0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Amp Autos",
+ "previewStartingState": {
+ "rotation": -90.0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Amp Defense.path b/src/main/deploy/pathplanner/paths/Amp Defense.path
new file mode 100644
index 0000000..d7df413
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Amp Defense.path
@@ -0,0 +1,251 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.8121591537300723,
+ "y": 7.71680437478522
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 6.0445845597573555,
+ "y": 7.692480090842535
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.641201870639037,
+ "y": 6.628292668350043
+ },
+ "prevControl": {
+ "x": 8.29356620782029,
+ "y": 6.197224446460777
+ },
+ "nextControl": {
+ "x": 8.793228645285383,
+ "y": 6.816805868908896
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.148635120799653,
+ "y": 7.430994038458665
+ },
+ "prevControl": {
+ "x": 7.948639244476473,
+ "y": 7.432278349060974
+ },
+ "nextControl": {
+ "x": 8.348630997122834,
+ "y": 7.4297097278563555
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.47701295402591,
+ "y": 6.628292668350043
+ },
+ "prevControl": {
+ "x": 8.683769367543297,
+ "y": 6.792481584966212
+ },
+ "nextControl": {
+ "x": 8.362523039267595,
+ "y": 6.537374206630526
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.002689417144419,
+ "y": 5.497213465011204
+ },
+ "prevControl": {
+ "x": 7.886503459776252,
+ "y": 5.879967724700685
+ },
+ "nextControl": {
+ "x": 8.118875374512587,
+ "y": 5.114459205321723
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.47701295402591,
+ "y": 5.229646341641664
+ },
+ "prevControl": {
+ "x": 8.277341384268052,
+ "y": 5.311202334922878
+ },
+ "nextControl": {
+ "x": 8.908768994009455,
+ "y": 5.053295283057193
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.148635120799653,
+ "y": 3.983026789586032
+ },
+ "prevControl": {
+ "x": 7.9501486296736,
+ "y": 4.207978146195556
+ },
+ "nextControl": {
+ "x": 8.331067250369797,
+ "y": 3.7762703760732044
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.641201870639037,
+ "y": 4.116810351267762
+ },
+ "prevControl": {
+ "x": 8.342885196685302,
+ "y": 4.1485461676458195
+ },
+ "nextControl": {
+ "x": 8.92701220696559,
+ "y": 4.086404996339404
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.148635120799653,
+ "y": 2.274245842612373
+ },
+ "prevControl": {
+ "x": 8.044138923975076,
+ "y": 2.5554584754175145
+ },
+ "nextControl": {
+ "x": 8.25313131762423,
+ "y": 1.9930332098072312
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.641201870639037,
+ "y": 2.438434759218498
+ },
+ "prevControl": {
+ "x": 8.489088970197463,
+ "y": 2.5682872352027912
+ },
+ "nextControl": {
+ "x": 8.890525781051563,
+ "y": 2.225597274723961
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.252013327556067,
+ "y": 0.9120859418149804
+ },
+ "prevControl": {
+ "x": 8.551626258367568,
+ "y": 0.9273204976189928
+ },
+ "nextControl": {
+ "x": 7.893230139402334,
+ "y": 0.8938427288579656
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 4.4817493164406885,
+ "y": 0.9120859418149804
+ },
+ "prevControl": {
+ "x": 4.442185136072626,
+ "y": 0.9194968759201448
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.5,
+ "rotationDegrees": -90.12087957511831,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 1.4,
+ "rotationDegrees": -50.90553805543688,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 3.4,
+ "rotationDegrees": -108.29489223558502,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 9.9,
+ "rotationDegrees": -136.64736084807365,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [
+ {
+ "name": "Load",
+ "waypointRelativePos": 0,
+ "command": {
+ "type": "parallel",
+ "data": {
+ "commands": [
+ {
+ "type": "named",
+ "data": {
+ "name": "IntakeLoadToShooter"
+ }
+ }
+ ]
+ }
+ }
+ }
+ ],
+ "globalConstraints": {
+ "maxVelocity": 5.5,
+ "maxAcceleration": 10.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 3.035758576645815e-10,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Amp Autos",
+ "previewStartingState": {
+ "rotation": -89.21517539700812,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Amp Leave.path b/src/main/deploy/pathplanner/paths/Amp Leave.path
new file mode 100644
index 0000000..5bcbd71
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Amp Leave.path
@@ -0,0 +1,52 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.8028311386572007,
+ "y": 7.717572064585753
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.802831138657201,
+ "y": 7.717572064585753
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 4.178109797843961,
+ "y": 7.717572064585753
+ },
+ "prevControl": {
+ "x": 3.1781097978439607,
+ "y": 7.717572064585753
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -88.72696997994328,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Amp Autos",
+ "previewStartingState": {
+ "rotation": -90.49630569155771,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Anti Anti Womp Womp Auto.path b/src/main/deploy/pathplanner/paths/Anti Anti Womp Womp Auto.path
new file mode 100644
index 0000000..27509bf
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Anti Anti Womp Womp Auto.path
@@ -0,0 +1,222 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.44433843182407134,
+ "y": 2.008568971452664
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 3.7363913103460717,
+ "y": 1.2668152848996053
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.478614317638893,
+ "y": 1.675196528058031
+ },
+ "prevControl": {
+ "x": 8.020932630102076,
+ "y": 1.3620851947631856
+ },
+ "nextControl": {
+ "x": 8.792212896346063,
+ "y": 1.8897370521214318
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.053564452306569,
+ "y": 2.616973680647869
+ },
+ "prevControl": {
+ "x": 7.928762800367872,
+ "y": 2.5453926177286186
+ },
+ "nextControl": {
+ "x": 8.258719502207933,
+ "y": 2.7346421273957127
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.178579118579556,
+ "y": 0.8417654195714485
+ },
+ "prevControl": {
+ "x": 8.759433484256135,
+ "y": 0.4247417724190323
+ },
+ "nextControl": {
+ "x": 7.203464721650255,
+ "y": 1.541847550700178
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.478614317638893,
+ "y": 3.350393056116061
+ },
+ "prevControl": {
+ "x": 8.870326938627585,
+ "y": 1.4168328844271907
+ },
+ "nextControl": {
+ "x": 8.378433951028827,
+ "y": 3.844900397680646
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.178579118579556,
+ "y": 4.142152609178315
+ },
+ "prevControl": {
+ "x": 8.101127060950382,
+ "y": 3.8237385944806097
+ },
+ "nextControl": {
+ "x": 8.25358791834335,
+ "y": 4.45052211931835
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.478614317638893,
+ "y": 5.126268134889211
+ },
+ "prevControl": {
+ "x": 8.736977961265568,
+ "y": 3.9504634542264014
+ },
+ "nextControl": {
+ "x": 8.39876332074187,
+ "y": 5.489667468437777
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.178579118579556,
+ "y": 5.783023801346283
+ },
+ "prevControl": {
+ "x": 8.045256914044762,
+ "y": 5.600591671780703
+ },
+ "nextControl": {
+ "x": 8.469791097405738,
+ "y": 6.181505221884166
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.603628983907715,
+ "y": 6.850803711759709
+ },
+ "prevControl": {
+ "x": 8.928667116213315,
+ "y": 6.109050025208735
+ },
+ "nextControl": {
+ "x": 8.425303113459558,
+ "y": 7.257752493042908
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.161793166225926,
+ "y": 7.32585944359706
+ },
+ "prevControl": {
+ "x": 8.01189289688223,
+ "y": 7.500879976379242
+ },
+ "nextControl": {
+ "x": 5.670714127623734,
+ "y": 7.018872582708374
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.520051212691258,
+ "y": 6.734123356571587
+ },
+ "prevControl": {
+ "x": 6.524218368233691,
+ "y": 6.488261179568046
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 2.25,
+ "rotationDegrees": 135.40041436608507,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 2.8000000000000003,
+ "rotationDegrees": 60.0,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 8.549999999999999,
+ "rotationDegrees": 131.73037673869962,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 4.0,
+ "rotationDegrees": 126.32682595212032,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 0.5,
+ "rotationDegrees": 122.68792798663786,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.5,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0.0,
+ "rotateFast": true
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Automatic Amp Approach.path b/src/main/deploy/pathplanner/paths/Automatic Amp Approach.path
new file mode 100644
index 0000000..db95686
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Automatic Amp Approach.path
@@ -0,0 +1,58 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 3.3613473115271097,
+ "y": 7.52588290963384
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.411235847852406,
+ "y": 7.600891709397633
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 1.8111654497420666,
+ "y": 7.709237753500888
+ },
+ "prevControl": {
+ "x": 1.8111654497420666,
+ "y": 7.142504599730012
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.0,
+ "rotationDegrees": -90.0,
+ "rotateFast": true
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -90.80692945510238,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Auto Move",
+ "previewStartingState": {
+ "rotation": -90.0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Automatic Source Approach.path b/src/main/deploy/pathplanner/paths/Automatic Source Approach.path
new file mode 100644
index 0000000..31c56c0
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Automatic Source Approach.path
@@ -0,0 +1,58 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 12.737447282001161,
+ "y": 1.6585279058882998
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 13.09582265865039,
+ "y": 1.5251789285304471
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 15.129394563357655,
+ "y": 0.9167742193352411
+ },
+ "prevControl": {
+ "x": 14.512655543077582,
+ "y": 2.550299191968943
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 1.0,
+ "rotationDegrees": 125.0,
+ "rotateFast": true
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 3.5,
+ "maxAcceleration": 8.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 121.5513849483135,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Auto Move",
+ "previewStartingState": {
+ "rotation": 124.38034472384476,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Automatic Speaker Left Approach.path b/src/main/deploy/pathplanner/paths/Automatic Speaker Left Approach.path
new file mode 100644
index 0000000..9bb956e
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Automatic Speaker Left Approach.path
@@ -0,0 +1,58 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 3.844737354449328,
+ "y": 6.509096957280209
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.4279044700221375,
+ "y": 6.742457667656452
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 1.1610891851225322,
+ "y": 6.225730380394771
+ },
+ "prevControl": {
+ "x": 2.5352399232710265,
+ "y": 6.225730380394771
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.7,
+ "rotationDegrees": 180.0,
+ "rotateFast": true
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -140.90614111377047,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Auto Move",
+ "previewStartingState": {
+ "rotation": -178.93908830973578,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Automatic Speaker Right Approach.path b/src/main/deploy/pathplanner/paths/Automatic Speaker Right Approach.path
new file mode 100644
index 0000000..c86b4d6
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Automatic Speaker Right Approach.path
@@ -0,0 +1,58 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 3.0363091792173424,
+ "y": 3.100363723570087
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 1.619476294790152,
+ "y": 3.3337244339463292
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 1.261100918140922,
+ "y": 5.167272872616811
+ },
+ "prevControl": {
+ "x": 2.635251656289414,
+ "y": 5.167272872616811
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.7,
+ "rotationDegrees": 180.0,
+ "rotateFast": true
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 178.025065989118,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Auto Move",
+ "previewStartingState": {
+ "rotation": 145.88552705465864,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Basic Leave.path b/src/main/deploy/pathplanner/paths/Basic Leave.path
new file mode 100644
index 0000000..86c158e
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Basic Leave.path
@@ -0,0 +1,52 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.4694586952625677,
+ "y": 3.2170440787582084
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.4694586952625652,
+ "y": 3.2170440787582084
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 3.553036466479024,
+ "y": 3.2170440787582084
+ },
+ "prevControl": {
+ "x": 2.553036466479024,
+ "y": 3.2170440787582084
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": null,
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Defense Auto Mini.path b/src/main/deploy/pathplanner/paths/Defense Auto Mini.path
new file mode 100644
index 0000000..ac3045a
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Defense Auto Mini.path
@@ -0,0 +1,132 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.4743235368823679,
+ "y": 2.055327287125162
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 4.2197813532682895,
+ "y": 1.1167976853720203
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.179040475728012,
+ "y": 1.623571247142495
+ },
+ "prevControl": {
+ "x": 7.697282154344558,
+ "y": 1.8970016457655368
+ },
+ "nextControl": {
+ "x": 8.629039728667694,
+ "y": 1.368166265744297
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.179040475728012,
+ "y": 0.7250850643833279
+ },
+ "prevControl": {
+ "x": 7.886878230609253,
+ "y": 0.8167624863168526
+ },
+ "nextControl": {
+ "x": 8.529933307329397,
+ "y": 0.6149786056822962
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.070233074476299,
+ "y": 2.5419648808840765
+ },
+ "prevControl": {
+ "x": 8.640015623001565,
+ "y": 2.83380078708467
+ },
+ "nextControl": {
+ "x": 7.147106946348856,
+ "y": 2.0691505575307354
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.914177710708363,
+ "y": 1.501949827429066
+ },
+ "prevControl": {
+ "x": 7.2224523256647775,
+ "y": 1.8600162269563465
+ },
+ "nextControl": {
+ "x": 6.711740367643171,
+ "y": 1.2668152848996053
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 5.4115878384041025,
+ "y": 1.623571247142495
+ },
+ "prevControl": {
+ "x": 5.600968652818167,
+ "y": 1.4789604303006754
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 1.9,
+ "rotationDegrees": 58.09914230935221,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 2.6500000000000004,
+ "rotationDegrees": 138.77299870068833,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 0.5,
+ "rotationDegrees": 60.56581968934775,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 650.0,
+ "maxAngularAcceleration": 1600.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0.0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": false
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Defense Wall Hug.path b/src/main/deploy/pathplanner/paths/Defense Wall Hug.path
new file mode 100644
index 0000000..7bf7070
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Defense Wall Hug.path
@@ -0,0 +1,52 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.4499992529396825,
+ "y": 7.400868243360852
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 0.9250549847770333,
+ "y": 7.942598463877129
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.31192809593741,
+ "y": 7.400868243360852
+ },
+ "prevControl": {
+ "x": 8.186913429664422,
+ "y": 7.717572064585753
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Defensive OP Trample.path b/src/main/deploy/pathplanner/paths/Defensive OP Trample.path
new file mode 100644
index 0000000..60aaaf9
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Defensive OP Trample.path
@@ -0,0 +1,84 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.4027842065836413,
+ "y": 2.041906215792126
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 4.688505729952637,
+ "y": 3.423568258901224
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.261922229428215,
+ "y": 2.5502991919751925
+ },
+ "prevControl": {
+ "x": 9.80860571748465,
+ "y": 6.0033600025197895
+ },
+ "nextControl": {
+ "x": 7.903546852778985,
+ "y": 1.7502053278280734
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.11178729971673,
+ "y": 0.9417771525960893
+ },
+ "prevControl": {
+ "x": 6.409509831882027,
+ "y": 1.6589966942145051
+ },
+ "nextControl": {
+ "x": 7.503499920705425,
+ "y": 0.5417302205225308
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.261922229428215,
+ "y": 0.8417654195776997
+ },
+ "prevControl": {
+ "x": 7.661851831317875,
+ "y": 0.8417654195776997
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "OP Autos",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Dodge Leave.path b/src/main/deploy/pathplanner/paths/Dodge Leave.path
new file mode 100644
index 0000000..23d6c9b
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Dodge Leave.path
@@ -0,0 +1,52 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.44445576200797,
+ "y": 1.5085103063607137
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.444455762007971,
+ "y": 1.5085103063607137
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 2.7779455355865017,
+ "y": 0.47505573183735095
+ },
+ "prevControl": {
+ "x": 2.76127691341677,
+ "y": 1.300152529239067
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": null,
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/I just want to be mean.path b/src/main/deploy/pathplanner/paths/I just want to be mean.path
new file mode 100644
index 0000000..7319ee2
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/I just want to be mean.path
@@ -0,0 +1,100 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.4716191785324748,
+ "y": 4.0742428543680616
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.471619178532474,
+ "y": 4.0742428543680616
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 3.9222907857580425,
+ "y": 2.8215422313197562
+ },
+ "prevControl": {
+ "x": 1.2471268902601693,
+ "y": 2.768038953409797
+ },
+ "nextControl": {
+ "x": 4.83445143360875,
+ "y": 2.839785444276771
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.227689043613383,
+ "y": 4.974241360247427
+ },
+ "prevControl": {
+ "x": 4.318592073740434,
+ "y": 4.8439381279183245
+ },
+ "nextControl": {
+ "x": 8.410121173183525,
+ "y": 4.980322431233098
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.227689043613383,
+ "y": 4.0742428543680616
+ },
+ "prevControl": {
+ "x": 8.312824037412783,
+ "y": 4.3843774746373025
+ },
+ "nextControl": {
+ "x": 8.142554049813983,
+ "y": 3.7641082340988206
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.227689043613383,
+ "y": 5.685726665570979
+ },
+ "prevControl": {
+ "x": 8.154716191785326,
+ "y": 5.4880918585366585
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0.0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Middle Aproach.path b/src/main/deploy/pathplanner/paths/Middle Aproach.path
new file mode 100644
index 0000000..6535e5a
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Middle Aproach.path
@@ -0,0 +1,84 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.4594570365611321,
+ "y": 1.501949827429066
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.4871580331395964,
+ "y": 1.7087062409418943
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.7256645101525505,
+ "y": 3.660730027342407
+ },
+ "prevControl": {
+ "x": 4.858775717551436,
+ "y": 4.585052817164458
+ },
+ "nextControl": {
+ "x": 7.439718750761607,
+ "y": 3.3071917714056753
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.30674296642711,
+ "y": 3.3445143360905365
+ },
+ "prevControl": {
+ "x": 7.771796551715273,
+ "y": 3.2803207663251173
+ },
+ "nextControl": {
+ "x": 8.458769741068895,
+ "y": 3.3627575490475503
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.30674296642711,
+ "y": 4.159377848167461
+ },
+ "prevControl": {
+ "x": 8.528702057404116,
+ "y": 4.049918570425378
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": "Other Team Autos",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Park for OP Bot.path b/src/main/deploy/pathplanner/paths/Park for OP Bot.path
new file mode 100644
index 0000000..e9a937a
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Park for OP Bot.path
@@ -0,0 +1,68 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.49434429833326626,
+ "y": 2.0502405268769923
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 4.569822418832655,
+ "y": 2.8420000799392464
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.986889963627642,
+ "y": 4.958915095495167
+ },
+ "prevControl": {
+ "x": 6.361699302078807,
+ "y": 4.817231807052447
+ },
+ "nextControl": {
+ "x": 8.244411234387643,
+ "y": 4.981365667817833
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.361933962446603,
+ "y": 5.784011892896883
+ },
+ "prevControl": {
+ "x": 8.434913507480042,
+ "y": 5.760135579691883
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": -89.44669604992542,
+ "rotateFast": true
+ },
+ "reversed": false,
+ "folder": "OP Autos",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Pwow Pwow Auto.path b/src/main/deploy/pathplanner/paths/Pwow Pwow Auto.path
new file mode 100644
index 0000000..4f2ba99
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Pwow Pwow Auto.path
@@ -0,0 +1,265 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.4694586952625677,
+ "y": 7.350862376851658
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.1794586952625674,
+ "y": 7.350862376851658
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 2.952966068368684,
+ "y": 7.717572064585753
+ },
+ "prevControl": {
+ "x": 1.9361801160150542,
+ "y": 7.68423482024629
+ },
+ "nextControl": {
+ "x": 4.072267801741834,
+ "y": 7.754270482073398
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.270256540513081,
+ "y": 6.609108690298599
+ },
+ "prevControl": {
+ "x": 7.235694207369861,
+ "y": 6.634138424164966
+ },
+ "nextControl": {
+ "x": 9.303711115036444,
+ "y": 6.584105757044002
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.270256540513081,
+ "y": 7.350862376851658
+ },
+ "prevControl": {
+ "x": 8.01400580719943,
+ "y": 7.363363843478957
+ },
+ "nextControl": {
+ "x": 8.526507273826732,
+ "y": 7.338360910224359
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.445277073295264,
+ "y": 6.050709847612589
+ },
+ "prevControl": {
+ "x": 8.781087013343967,
+ "y": 6.255115898077016
+ },
+ "nextControl": {
+ "x": 8.061898763391435,
+ "y": 5.817349137236346
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.061898763391435,
+ "y": 5.4256365162476525
+ },
+ "prevControl": {
+ "x": 7.695189075657338,
+ "y": 5.775677581812018
+ },
+ "nextControl": {
+ "x": 8.443423570522102,
+ "y": 5.061453745804742
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.603628983907715,
+ "y": 4.933912162240569
+ },
+ "prevControl": {
+ "x": 8.603628983907715,
+ "y": 5.258950294550337
+ },
+ "nextControl": {
+ "x": 8.603628983907715,
+ "y": 4.53351811779622
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.953552719288179,
+ "y": 3.9254605209718036
+ },
+ "prevControl": {
+ "x": 7.908991706553872,
+ "y": 4.129168007757208
+ },
+ "nextControl": {
+ "x": 8.01189289688224,
+ "y": 3.658762566256097
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.603628983907715,
+ "y": 3.3253901228614646
+ },
+ "prevControl": {
+ "x": 8.636966228247177,
+ "y": 3.6920998105955607
+ },
+ "nextControl": {
+ "x": 8.57646826009496,
+ "y": 3.0266221609211557
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.953552719288179,
+ "y": 2.291935548338102
+ },
+ "prevControl": {
+ "x": 7.903546852778984,
+ "y": 2.4752903922051503
+ },
+ "nextControl": {
+ "x": 8.028014589347134,
+ "y": 2.0189086914552714
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.445277073295264,
+ "y": 1.7502053278218235
+ },
+ "prevControl": {
+ "x": 8.4819854459243,
+ "y": 2.0479510169240047
+ },
+ "nextControl": {
+ "x": 8.37026827353147,
+ "y": 1.1418006186266199
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.061898763391435,
+ "y": 0.8751026639109117
+ },
+ "prevControl": {
+ "x": 8.411738520940533,
+ "y": 0.8530075213288637
+ },
+ "nextControl": {
+ "x": 7.270139210329182,
+ "y": 0.925108530420106
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.578391390285319,
+ "y": 1.3334897735785316
+ },
+ "prevControl": {
+ "x": 7.4363949604784425,
+ "y": 1.1230360676821038
+ },
+ "nextControl": {
+ "x": 5.694954415289541,
+ "y": 1.5501818617850442
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 4.803183129208898,
+ "y": 1.3334897735785316
+ },
+ "prevControl": {
+ "x": 5.344913349725176,
+ "y": 1.5835191061245062
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 1.35,
+ "rotationDegrees": 0,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 2.55,
+ "rotationDegrees": -43.451842301022175,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 3.8500000000000005,
+ "rotationDegrees": -124.30620777362209,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 10.75,
+ "rotationDegrees": -133.39606625532608,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 180.0,
+ "rotateFast": true
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 1.0230301886678488,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Ready from Right.path b/src/main/deploy/pathplanner/paths/Ready from Right.path
new file mode 100644
index 0000000..c4da725
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Ready from Right.path
@@ -0,0 +1,52 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.5110129205029978,
+ "y": 2.025237593622395
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 1.5110129205029974,
+ "y": 2.025237593622395
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.836755033916158,
+ "y": 1.4835073731061177
+ },
+ "prevControl": {
+ "x": 5.853306325901991,
+ "y": 1.3001525292390697
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": null,
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/This Feels Wrong.path b/src/main/deploy/pathplanner/paths/This Feels Wrong.path
new file mode 100644
index 0000000..32e6c18
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/This Feels Wrong.path
@@ -0,0 +1,58 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 1.502795939602031,
+ "y": 1.5085103063607137
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.5027959396020316,
+ "y": 1.5085103063607137
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 14.904368164066277,
+ "y": 0.6667448867955176
+ },
+ "prevControl": {
+ "x": 14.087605677749428,
+ "y": 1.5085103063732173
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 0.5,
+ "rotationDegrees": 180.0,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 120.14138555207604,
+ "rotateFast": false
+ },
+ "reversed": false,
+ "folder": null,
+ "previewStartingState": {
+ "rotation": -0.7638984609300048,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Three Note No Note Note Auto.path b/src/main/deploy/pathplanner/paths/Three Note No Note Note Auto.path
new file mode 100644
index 0000000..21d0652
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Three Note No Note Note Auto.path
@@ -0,0 +1,196 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.4864856788537107,
+ "y": 2.055327287125162
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 1.8758089961686033,
+ "y": 2.0829999940083486
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.293908470169882,
+ "y": 1.7695169507986073
+ },
+ "prevControl": {
+ "x": 3.6589761258218747,
+ "y": 0.6300867478373058
+ },
+ "nextControl": {
+ "x": 7.193906976049247,
+ "y": 2.1587054938815764
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.228467654904852,
+ "y": 3.2753842563522695
+ },
+ "prevControl": {
+ "x": 6.666923706625631,
+ "y": 2.942433419761933
+ },
+ "nextControl": {
+ "x": 7.915628676285715,
+ "y": 3.6828160123922538
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.603628983907715,
+ "y": 3.508703252700623
+ },
+ "prevControl": {
+ "x": 8.738499006409779,
+ "y": 3.0951904256749696
+ },
+ "nextControl": {
+ "x": 8.447176910349057,
+ "y": 3.988386862379535
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.278590851597945,
+ "y": 4.150486920263181
+ },
+ "prevControl": {
+ "x": 8.201138793968772,
+ "y": 3.8320729055654756
+ },
+ "nextControl": {
+ "x": 8.353599651361739,
+ "y": 4.458856430403216
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.478614317638893,
+ "y": 5.267284605633116
+ },
+ "prevControl": {
+ "x": 9.153693515508857,
+ "y": 4.0838124315842546
+ },
+ "nextControl": {
+ "x": 8.294261611057387,
+ "y": 5.590470831987306
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.378602584616337,
+ "y": 5.984035358933663
+ },
+ "prevControl": {
+ "x": 8.192205888120613,
+ "y": 5.96576117300271
+ },
+ "nextControl": {
+ "x": 8.803652449944494,
+ "y": 6.0257069143579916
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.603628983907715,
+ "y": 6.850803711759709
+ },
+ "prevControl": {
+ "x": 8.928667116213315,
+ "y": 6.109050025208735
+ },
+ "nextControl": {
+ "x": 8.425303113459558,
+ "y": 7.257752493042908
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.678520453487607,
+ "y": 7.267519266002999
+ },
+ "prevControl": {
+ "x": 8.458937853296941,
+ "y": 7.647322400576876
+ },
+ "nextControl": {
+ "x": 6.4283737907577345,
+ "y": 6.659114556807794
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.518908096639723,
+ "y": 5.570186316843223
+ },
+ "prevControl": {
+ "x": 6.523075252182156,
+ "y": 5.324324139839683
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 7.549999999999999,
+ "rotationDegrees": 127.15382193689126,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 0.55,
+ "rotationDegrees": 0,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 3.0,
+ "rotationDegrees": 126.32682595212032,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0,
+ "rotation": 0.0,
+ "rotateFast": true
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/deploy/pathplanner/paths/Womp Womp Auto.path b/src/main/deploy/pathplanner/paths/Womp Womp Auto.path
new file mode 100644
index 0000000..643c19f
--- /dev/null
+++ b/src/main/deploy/pathplanner/paths/Womp Womp Auto.path
@@ -0,0 +1,217 @@
+{
+ "version": 1.0,
+ "waypoints": [
+ {
+ "anchor": {
+ "x": 0.4864856788537107,
+ "y": 2.061408358110835
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 1.4699343868678794,
+ "y": 2.2614318241476155
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.278590851597945,
+ "y": 1.6335249726337016
+ },
+ "prevControl": {
+ "x": 5.418334941485961,
+ "y": 1.3883601803383812
+ },
+ "nextControl": {
+ "x": 8.57029173956825,
+ "y": 1.6585279058882998
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.278590851597945,
+ "y": 0.7834252419773882
+ },
+ "prevControl": {
+ "x": 7.936884097118446,
+ "y": 0.7584223087227898
+ },
+ "nextControl": {
+ "x": 8.453934571855962,
+ "y": 0.7962552702889507
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.278590851597945,
+ "y": 2.5419648808840765
+ },
+ "prevControl": {
+ "x": 8.653364012610378,
+ "y": 2.0066787192397926
+ },
+ "nextControl": {
+ "x": 8.084483672399713,
+ "y": 2.819206950780255
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.603628983907715,
+ "y": 3.408733233710122
+ },
+ "prevControl": {
+ "x": 8.61687758669635,
+ "y": 2.602623675835588
+ },
+ "nextControl": {
+ "x": 8.595337656630294,
+ "y": 3.91321799126715
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.278590851597945,
+ "y": 4.150486920263181
+ },
+ "prevControl": {
+ "x": 8.201138793968772,
+ "y": 3.8320729055654756
+ },
+ "nextControl": {
+ "x": 8.353599651361739,
+ "y": 4.458856430403216
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.478614317638893,
+ "y": 5.267284605633116
+ },
+ "prevControl": {
+ "x": 8.720255793452765,
+ "y": 4.414782829565659
+ },
+ "nextControl": {
+ "x": 8.377148782305843,
+ "y": 5.625251087958723
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.378602584616337,
+ "y": 5.984035358933663
+ },
+ "prevControl": {
+ "x": 8.191312365515342,
+ "y": 5.984254824323545
+ },
+ "nextControl": {
+ "x": 8.665526154581721,
+ "y": 5.9836991438688765
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 8.478614317638893,
+ "y": 6.8674723339273545
+ },
+ "prevControl": {
+ "x": 8.768904361338135,
+ "y": 6.445860538779902
+ },
+ "nextControl": {
+ "x": 8.334323534016512,
+ "y": 7.0770375519797275
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 7.545171476129753,
+ "y": 7.275853577087865
+ },
+ "prevControl": {
+ "x": 8.395271206786067,
+ "y": 7.450874109870047
+ },
+ "nextControl": {
+ "x": 6.0540924375275615,
+ "y": 6.968866716199179
+ },
+ "isLocked": false,
+ "linkedName": null
+ },
+ {
+ "anchor": {
+ "x": 6.570057079200454,
+ "y": 6.734123356571587
+ },
+ "prevControl": {
+ "x": 6.5742242347428865,
+ "y": 6.488261179568046
+ },
+ "nextControl": null,
+ "isLocked": false,
+ "linkedName": null
+ }
+ ],
+ "rotationTargets": [
+ {
+ "waypointRelativePos": 1.8,
+ "rotationDegrees": 55.22900579372395,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 2.75,
+ "rotationDegrees": 122.26035320751792,
+ "rotateFast": true
+ },
+ {
+ "waypointRelativePos": 8.549999999999999,
+ "rotationDegrees": 131.13601678654157,
+ "rotateFast": false
+ },
+ {
+ "waypointRelativePos": 0.45,
+ "rotationDegrees": 0,
+ "rotateFast": false
+ }
+ ],
+ "constraintZones": [],
+ "eventMarkers": [],
+ "globalConstraints": {
+ "maxVelocity": 5.0,
+ "maxAcceleration": 7.0,
+ "maxAngularVelocity": 540.0,
+ "maxAngularAcceleration": 720.0
+ },
+ "goalEndState": {
+ "velocity": 0.0,
+ "rotation": 0.0,
+ "rotateFast": true
+ },
+ "reversed": false,
+ "folder": "General Defense",
+ "previewStartingState": {
+ "rotation": 0,
+ "velocity": 0
+ },
+ "useDefaultConstraints": true
+}
\ No newline at end of file
diff --git a/src/main/java/frc/lib/light/Color.kt b/src/main/java/frc/lib/light/Color.kt
new file mode 100644
index 0000000..d93d190
--- /dev/null
+++ b/src/main/java/frc/lib/light/Color.kt
@@ -0,0 +1,7 @@
+package frc.lib.light
+
+data class Color(
+ val red: Int,
+ val green: Int,
+ val blue: Int
+)
diff --git a/src/main/java/frc/lib/light/LightActions.kt b/src/main/java/frc/lib/light/LightActions.kt
new file mode 100644
index 0000000..80c528e
--- /dev/null
+++ b/src/main/java/frc/lib/light/LightActions.kt
@@ -0,0 +1,15 @@
+package frc.lib.light
+
+enum class LightActions {
+ TOP_POINT,
+ BOTTOM_POINT,
+ LEFT_POINT,
+ RIGHT_POINT,
+ TOP_LEFT_POINT,
+ TOP_RIGHT_POINT,
+ BOTTOM_LEFT_POINT,
+ BOTTOM_RIGHT_POINT,
+ IDLE,
+ READY,
+ STOPPED
+}
\ No newline at end of file
diff --git a/src/main/java/frc/lib/light/NeopixelAnimations.kt b/src/main/java/frc/lib/light/NeopixelAnimations.kt
new file mode 100644
index 0000000..cb616c6
--- /dev/null
+++ b/src/main/java/frc/lib/light/NeopixelAnimations.kt
@@ -0,0 +1,5 @@
+package frc.lib.light
+
+enum class NeopixelAnimations {
+ BLANK, FLASHING, STROBE
+}
\ No newline at end of file
diff --git a/src/main/java/frc/lib/light/NeopixelSection.kt b/src/main/java/frc/lib/light/NeopixelSection.kt
new file mode 100644
index 0000000..ba7a43a
--- /dev/null
+++ b/src/main/java/frc/lib/light/NeopixelSection.kt
@@ -0,0 +1,16 @@
+package frc.lib.light
+
+import frc.lib.light.NeopixelAnimations
+import frc.robot.Constants.Indicators.Neopixels.NeopixelStates
+
+data class NeopixelSection(
+ val start: Int,
+ val end: Int,
+ val name: String,
+ val desiredState: HashMap,
+ var blacklistedAnimations: List? = null // This is not required to be set, the subsystem will handle it
+) {
+ fun size(): Int {
+ return end - start
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/CommandSwerveDrivetrain.java b/src/main/java/frc/robot/CommandSwerveDrivetrain.java
new file mode 100644
index 0000000..040c2c2
--- /dev/null
+++ b/src/main/java/frc/robot/CommandSwerveDrivetrain.java
@@ -0,0 +1,106 @@
+package frc.robot;
+
+import java.util.function.Supplier;
+
+import com.ctre.phoenix6.Utils;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveDrivetrain;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveDrivetrainConstants;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveModuleConstants;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveRequest;
+import com.pathplanner.lib.auto.AutoBuilder;
+import com.pathplanner.lib.util.HolonomicPathFollowerConfig;
+import com.pathplanner.lib.util.PIDConstants;
+import com.pathplanner.lib.util.ReplanningConfig;
+
+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.kinematics.ChassisSpeeds;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.Notifier;
+import edu.wpi.first.wpilibj.RobotController;
+import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.Subsystem;
+
+/**
+ * Class that extends the Phoenix SwerveDrivetrain class and implements subsystem
+ * so it can be used in command-based projects easily.
+ */
+public class CommandSwerveDrivetrain extends SwerveDrivetrain implements Subsystem {
+ private static final double kSimLoopPeriod = 0.005; // 5 ms
+ private Notifier m_simNotifier = null;
+ private double m_lastSimTime;
+
+ private SendableChooser chooser;
+
+ private final SwerveRequest.ApplyChassisSpeeds autoRequest = new SwerveRequest.ApplyChassisSpeeds();
+
+ public CommandSwerveDrivetrain(SwerveDrivetrainConstants driveTrainConstants, double OdometryUpdateFrequency, SwerveModuleConstants... modules) {
+ super(driveTrainConstants, OdometryUpdateFrequency, modules);
+ if (Utils.isSimulation()) {
+ startSimThread();
+ }
+ }
+ public CommandSwerveDrivetrain(SwerveDrivetrainConstants driveTrainConstants, SwerveModuleConstants... modules) {
+ super(driveTrainConstants, modules);
+ if (Utils.isSimulation()) {
+ startSimThread();
+ }
+ }
+
+ public void configurePathPlanner() {
+ double driveBaseRadius = 0;
+
+ for (var moduleLocation : m_moduleLocations) {
+ driveBaseRadius = Math.max(driveBaseRadius, moduleLocation.getNorm());
+ }
+
+ AutoBuilder.configureHolonomic(
+ ()->this.getState().Pose, // Supplier of current robot pose
+ this::seedFieldRelative, // Consumer for seeding pose against auto
+ this::getCurrentRobotChassisSpeeds,
+ (speeds)->this.setControl(autoRequest.withSpeeds(speeds)), // Consumer of ChassisSpeeds to drive the robot
+ new HolonomicPathFollowerConfig(new PIDConstants(8.0, 0.0, 0.0), // TODO: Move to Constants
+ new PIDConstants(10.0, 0.0, 0.08),
+ Constants.Robot.maxSpeed,
+ driveBaseRadius,
+ new ReplanningConfig(),
+ 0.004),
+ () -> {
+ return DriverStation.getAlliance().filter(value -> value == DriverStation.Alliance.Red).isPresent(); // Flip
+ }, this); // Subsystem for requirements, the language server sometimes gets mad at the supplier lmao
+
+ chooser = AutoBuilder.buildAutoChooser();
+ SmartDashboard.putData("Autonomous Path Choices", chooser);
+ }
+
+ public Command applyRequest(Supplier requestSupplier) {
+ return run(() -> this.setControl(requestSupplier.get()));
+ }
+
+ public Command getAutoPath() {
+ if (chooser == null) return null;
+ return chooser.getSelected();
+ }
+
+ public ChassisSpeeds getCurrentRobotChassisSpeeds() {
+ return m_kinematics.toChassisSpeeds(getState().ModuleStates);
+ }
+
+ private void startSimThread() {
+ m_lastSimTime = Utils.getCurrentTimeSeconds();
+
+ /* Run simulation at a faster rate so PID gains behave more reasonably */
+ m_simNotifier = new Notifier(() -> {
+ final double currentTime = Utils.getCurrentTimeSeconds();
+ double deltaTime = currentTime - m_lastSimTime;
+ m_lastSimTime = currentTime;
+
+ /* use the measured time delta, get battery voltage from WPILib */
+ updateSimState(deltaTime, RobotController.getBatteryVoltage());
+ });
+ m_simNotifier.startPeriodic(kSimLoopPeriod);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/Constants.kt b/src/main/java/frc/robot/Constants.kt
new file mode 100644
index 0000000..b70239f
--- /dev/null
+++ b/src/main/java/frc/robot/Constants.kt
@@ -0,0 +1,225 @@
+package frc.robot
+
+import com.pathplanner.lib.path.PathConstraints
+import frc.lib.light.Color
+import frc.lib.light.NeopixelSection
+import edu.wpi.first.math.geometry.Translation3d
+import edu.wpi.first.math.geometry.Rotation3d
+import edu.wpi.first.math.geometry.Transform3d
+import edu.wpi.first.math.geometry.Pose3d
+import edu.wpi.first.math.geometry.Rotation2d
+
+object Constants {
+ const val isDebug = true
+ const val beefySim = true
+ const val supportEnhancers = false
+
+ object Robot {
+ const val name = "Viper"
+
+ const val radius = 0.4064
+ const val width = 0.8128
+ const val length = 0.8128
+
+ const val maxSpeed = 6.21 // Meters per second
+ const val maxAngularSpeed = Math.PI * 1.75 // Radians per second
+ }
+
+ object Indicators {
+ const val enableCameraLED = false
+
+ object Neopixels {
+ const val neopixelPort = 0
+ const val numLEDs = 18
+ const val enabled = true
+
+ enum class NeopixelStates {
+ /* This is configurable to allow other states */
+ SHOOTING, INTAKING, IDLE, DEAD, AUTO, BREAKING
+ }
+
+
+ private val indicators = hashMapOf(
+ NeopixelStates.IDLE to Color(0, 240, 255), // Cyan
+ NeopixelStates.INTAKING to Color(0, 200, 0), // Green
+ NeopixelStates.SHOOTING to Color(255, 69, 0), // Orange
+ NeopixelStates.DEAD to Color(0, 12, 163), // Dark Cyan
+ NeopixelStates.AUTO to Color(255, 255, 0), // Yellow
+ NeopixelStates.BREAKING to Color(255, 0, 0) // Red
+ )
+
+ val sections = arrayOf(
+ NeopixelSection(0, 17, "Indicators", indicators),
+ )
+ }
+ }
+
+ object Enhancers {
+ val blueScorePosition = Pose3d(0.0, 5.5372, 2.032, Rotation3d(0.0, 0.0, 0.0))
+ val redScorePosition = Pose3d(16.54, 5.5372, 2.032, Rotation3d(0.0, 0.0, Math.PI))
+
+ object PathPlanner {
+ // TODO: Tune this (again and again and again)
+ object RotationGains {
+ const val kP = 6
+ const val kI = 0.0
+ const val kD = 0.0
+ }
+
+ object TranslationGains {
+ const val kP = 6
+ const val kI = 0.0
+ const val kD = 0.0
+ }
+ }
+
+ object Pathfinding {
+ val constraints = PathConstraints(6.1, 10.0, Rotation2d.fromDegrees(540.0).degrees, Rotation2d.fromDegrees(720.0).degrees)
+
+ const val approachSourcePath = "Automatic Source Approach"
+ const val approachAmpPath = "Automatic Amp Approach"
+ const val approachSpeakerPathLeft = "Automatic Speaker Left Approach"
+ const val approachSpeakerPathRight = "Automatic Speaker Right Approach"
+ }
+ }
+
+ object Simulation {
+ /* Simulation also takes data directly from Photon (Constants.Vision) */
+ object Camera {
+ const val width = 1280
+ const val height = 720
+ const val fov = 70
+ const val averageNoise = 0.25
+ const val deviatedNoise = .08
+ const val fps = 30
+ const val averageLatency = 35
+ const val standardDevLatency = 3
+ }
+ }
+
+ object Vision {
+ const val squareConstant = 0.291846 // The robot is square so this is the distance from the center of the robot to the corner
+ const val robotLift = 0.2001505 // Distance from ground to cameras
+
+ const val enable = false
+
+ object LeftCamera {
+ const val name = "leftCam"
+ val robotToCameraTrl = Translation3d(squareConstant, squareConstant, robotLift)
+ val robotToCameraRot = Rotation3d(0.0, Math.toRadians(-25.0), Math.toRadians(45.0))
+ val robotToCamera = Transform3d(robotToCameraTrl, robotToCameraRot)
+ }
+ object RightCamera {
+ const val name = "rightCam"
+ val robotToCameraTrl = Translation3d(squareConstant, -squareConstant, robotLift)
+ val robotToCameraRot = Rotation3d(0.0, Math.toRadians(-25.0), Math.toRadians(-45.0))
+ val robotToCamera = Transform3d(robotToCameraTrl, robotToCameraRot)
+ }
+ }
+
+ object IntakeFoldout {
+ const val canID = 22
+ const val gearRatio = (1.0/100.0)
+ const val inverted = true
+
+ const val throughBoreCountsPerRev = 8192
+ const val encoderPort = 0
+ const val forwardLimitSensorPort = 1
+
+ const val offset = 12.0 // Degrees
+
+ const val completedLoop = 5 // The tolerance for the loop to be considered done
+
+ const val simulationTime = 300 // The amount of ticks before a virtual beam break is triggered
+
+ object Control {
+ const val kP = 0.000135
+ const val kI = 0.0
+ const val kD = 0.0 // TODO: Up this
+ const val kIz = 0.0
+ const val kFF = 0.0
+
+ object Profile {
+ const val maxVelocity = 5400.0
+ const val maxAcceleration = 120000.0
+ }
+ }
+
+ object SimDummyControl {
+ const val kP = .06
+ const val kI = 0.0
+ const val kD = 0.0
+ const val kIz = 0.0
+ const val kFF = 0.0
+ }
+
+ enum class FoldoutState {
+ IDLE,
+ SHOOT_LOW,
+ SHOOT_MID,
+ SHOOT_HIGH,
+ INTAKE_DROP,
+ INTAKE_GROUND,
+ AMPLIFY,
+ }
+
+ /* Positions of the Intake Foldout States (in degrees) */
+ val positions = hashMapOf(
+ FoldoutState.IDLE to 40.0,
+ FoldoutState.SHOOT_LOW to 25.0, // Ok for disgruntled programmer looking at this code in five years, when pressing the shoot button it will position the intake a bit up or down for best angle
+ FoldoutState.SHOOT_MID to 45.0,
+ FoldoutState.SHOOT_HIGH to 68.0,
+ FoldoutState.INTAKE_DROP to 100.0,
+ FoldoutState.INTAKE_GROUND to 230.0,
+ FoldoutState.AMPLIFY to 109.0
+ )
+
+ /* The auto aims intake constants for optimal handoff, data in degrees of shooter per movement of Intake (TODO) */
+ val neededPositionChanges = hashMapOf(
+ FoldoutState.SHOOT_LOW to 0.0,
+ FoldoutState.SHOOT_MID to 30.0,
+ FoldoutState.SHOOT_HIGH to 50.0,
+ )
+ }
+
+ object IntakeRollers {
+ const val canID = 21
+
+ const val beamBreakID = 2
+
+ object Control {
+ const val kP = 0.1
+ const val kI = 0.0
+ const val kD = 0.0
+ const val kIz = 0.0
+ const val kFF = 0.0
+ const val kMinOutput = 0.0
+ const val kMaxOutput = 0.0
+ }
+
+ enum class Speed {
+ NEUTRAL, INTAKE, SHOOT, AMPLIFY
+ }
+
+ /* Speeds of the Intake Rollers (percent) */
+ val speeds = hashMapOf(
+ Speed.NEUTRAL to 0.0, // Apply a small amount of power to keep the note in place and centered
+ Speed.INTAKE to 80.0,
+ Speed.SHOOT to -100.0, // When Shooting this is the speed it pushes to the shooter
+ Speed.AMPLIFY to -55.0
+ )
+ }
+
+ object Climber {
+ const val leftMotorID = 31
+ const val rightMotorID = 32
+
+ const val isLeftInverted = true
+ const val isRightInverted = false
+
+ const val maximumPosition = 114.0
+ const val minimumPosition = 0.0
+
+ const val theoreticalMax = 120.0 // The maximum position the climber can go to in rotations
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/Enhancers.kt b/src/main/java/frc/robot/Enhancers.kt
new file mode 100644
index 0000000..fead717
--- /dev/null
+++ b/src/main/java/frc/robot/Enhancers.kt
@@ -0,0 +1,79 @@
+package frc.robot
+
+import com.pathplanner.lib.auto.AutoBuilder
+import com.pathplanner.lib.path.PathPlannerPath
+import edu.wpi.first.wpilibj2.command.Command
+import edu.wpi.first.wpilibj2.command.InstantCommand
+import edu.wpi.first.wpilibj2.command.SequentialCommandGroup
+import edu.wpi.first.wpilibj2.command.WaitCommand
+import frc.robot.commands.teleop.IntakeFromSource
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+/**
+ * On the Fly Path Generation (aka Enhancers) for the robot
+ */
+object Enhancers {
+ /**
+ * Generate a path to the source
+ * @return The path to the source
+ */
+ fun generateSourcePath() : Command {
+ if (!Constants.supportEnhancers) return InstantCommand()
+
+ val path = PathPlannerPath.fromPathFile(Constants.Enhancers.Pathfinding.approachSourcePath)
+ return AutoBuilder.pathfindThenFollowPath(path, Constants.Enhancers.Pathfinding.constraints, 0.0).withName("Enhancer to Source")
+ }
+
+ /**
+ * Generate a path to the amp
+ * @return The path to the amp
+ */
+
+ fun generateAmpPath() : Command {
+ if (!Constants.supportEnhancers) return InstantCommand()
+
+ val path = PathPlannerPath.fromPathFile(Constants.Enhancers.Pathfinding.approachAmpPath)
+ return AutoBuilder.pathfindThenFollowPath(path, Constants.Enhancers.Pathfinding.constraints, 0.0).withName("Enhancer to Amp")
+ }
+
+ /**
+ * Generate a path to the speaker (left)
+ * @return The path to the speaker (left)
+ */
+ fun generateSpeakerPathLeft() : Command {
+ if (!Constants.supportEnhancers) return InstantCommand()
+
+ val path = PathPlannerPath.fromPathFile(Constants.Enhancers.Pathfinding.approachSpeakerPathLeft)
+ return AutoBuilder.pathfindThenFollowPath(path, Constants.Enhancers.Pathfinding.constraints, 0.0).withName("Enhancer to Speaker (Left)")
+ }
+
+ /**
+ * Generate a path to the speaker (right)
+ * @return The path to the speaker (right)
+ */
+ fun generateSpeakerPathRight() : Command {
+ if (!Constants.supportEnhancers) return InstantCommand()
+
+ val path = PathPlannerPath.fromPathFile(Constants.Enhancers.Pathfinding.approachSpeakerPathRight)
+ return AutoBuilder.pathfindThenFollowPath(path, Constants.Enhancers.Pathfinding.constraints, 0.0).withName("Enhancer to Speaker (Right)")
+ }
+
+ /**
+ * Generate a cycle path, this is EXPERIMENTAL and should not be used in competition
+ * @return The cycle path
+ */
+ fun generateCyclePath(intakeFoldout: IntakeFoldout, intakeRollers: IntakeRollers) : SequentialCommandGroup {
+ if (!Constants.supportEnhancers) return SequentialCommandGroup()
+
+ if (Constants.isDebug) {
+ return SequentialCommandGroup(
+ generateSourcePath(),
+ IntakeFromSource(intakeFoldout, intakeRollers), // Wait until beam break sensor is triggered
+ WaitCommand(0.5),
+ generateSpeakerPathRight()
+ )
+ }
+ return SequentialCommandGroup(generateSpeakerPathRight())
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/Main.kt b/src/main/java/frc/robot/Main.kt
new file mode 100644
index 0000000..3febb87
--- /dev/null
+++ b/src/main/java/frc/robot/Main.kt
@@ -0,0 +1,13 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+package frc.robot
+
+import edu.wpi.first.wpilibj.RobotBase
+
+object Main {
+ @JvmStatic
+ fun main(args: Array) {
+ RobotBase.startRobot { Robot() }
+ }
+}
diff --git a/src/main/java/frc/robot/Robot.kt b/src/main/java/frc/robot/Robot.kt
new file mode 100644
index 0000000..5efeef1
--- /dev/null
+++ b/src/main/java/frc/robot/Robot.kt
@@ -0,0 +1,66 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+package frc.robot
+
+import edu.wpi.first.hal.FRCNetComm
+import edu.wpi.first.hal.HAL
+import edu.wpi.first.wpilibj.TimedRobot
+import edu.wpi.first.wpilibj2.command.Command
+import edu.wpi.first.wpilibj2.command.CommandScheduler
+
+class Robot : TimedRobot() {
+ private var m_autonomousCommand: Command? = null
+ private var m_robotContainer: RobotContainer? = null
+ override fun robotInit() {
+ m_robotContainer = RobotContainer()
+
+ m_robotContainer!!.drivetrain.daqThread.setThreadPriority(99)
+
+ HAL.report(FRCNetComm.tResourceType.kResourceType_Language, FRCNetComm.tInstances.kLanguage_Kotlin) // Flex on the FTAs
+ }
+
+ override fun robotPeriodic() {
+ CommandScheduler.getInstance().run()
+ // Ignore this, I might do fancy stuff here someday
+ }
+
+ override fun disabledInit() {
+ m_robotContainer!!.m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.DEAD)
+ m_robotContainer!!.m_Neopixels.chainBlinking = false
+ }
+ override fun disabledPeriodic() {}
+ override fun disabledExit() {}
+ override fun autonomousInit() {
+ m_robotContainer!!.m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.AUTO)
+ m_robotContainer!!.m_Neopixels.chainBlinking = true
+
+ m_autonomousCommand = m_robotContainer!!.autonomousCommand
+ if (m_autonomousCommand != null) {
+ m_autonomousCommand!!.schedule()
+ }
+ }
+
+ override fun autonomousPeriodic() {}
+ override fun autonomousExit() {
+ m_robotContainer!!.m_Neopixels.chainBlinking = false
+ }
+ override fun teleopInit() {
+ m_robotContainer!!.m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.IDLE)
+ m_robotContainer!!.m_Neopixels.chainBlinking = false
+
+ if (m_autonomousCommand != null) {
+ m_autonomousCommand!!.cancel()
+ }
+ }
+
+ override fun teleopPeriodic() {}
+ override fun teleopExit() {}
+ override fun testInit() {
+ CommandScheduler.getInstance().cancelAll()
+ }
+
+ override fun testPeriodic() {}
+ override fun testExit() {}
+ override fun simulationPeriodic() {}
+}
diff --git a/src/main/java/frc/robot/RobotContainer.kt b/src/main/java/frc/robot/RobotContainer.kt
new file mode 100644
index 0000000..06759bd
--- /dev/null
+++ b/src/main/java/frc/robot/RobotContainer.kt
@@ -0,0 +1,342 @@
+// Copyright (c) FIRST and other WPILib contributors.
+// Open Source Software; you can modify and/or share it under the terms of
+// the WPILib BSD license file in the root directory of this project.
+package frc.robot
+
+import com.ctre.phoenix6.mechanisms.swerve.SwerveDrivetrain.SwerveDriveState
+import com.ctre.phoenix6.mechanisms.swerve.SwerveModule.DriveRequestType
+import com.ctre.phoenix6.mechanisms.swerve.SwerveRequest.*
+import com.ctre.phoenix6.mechanisms.swerve.utility.PhoenixPIDController
+import com.pathplanner.lib.auto.NamedCommands
+import edu.wpi.first.math.geometry.Rotation2d
+import edu.wpi.first.wpilibj.DigitalInput
+import edu.wpi.first.wpilibj.DriverStation
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard
+import edu.wpi.first.wpilibj2.command.Command
+import edu.wpi.first.wpilibj2.command.CommandScheduler
+import edu.wpi.first.wpilibj2.command.InstantCommand
+import edu.wpi.first.wpilibj2.command.ParallelCommandGroup
+import edu.wpi.first.wpilibj2.command.ParallelDeadlineGroup
+import edu.wpi.first.wpilibj2.command.ParallelRaceGroup
+import edu.wpi.first.wpilibj2.command.SequentialCommandGroup
+import edu.wpi.first.wpilibj2.command.WaitCommand
+import edu.wpi.first.wpilibj2.command.button.CommandPS5Controller
+import edu.wpi.first.wpilibj2.command.button.Trigger
+import frc.robot.commands.auto.AutoIntakeFromGround
+import frc.robot.commands.auto.AutoIntakeLoadToShooter
+import frc.robot.commands.climb.DefaultClimber
+import frc.robot.commands.teleop.*
+import frc.robot.commands.vision.PhotonPoseEstimator
+import frc.robot.generated.TunerConstants
+import frc.robot.subsystems.climb.Climber
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.light.Neopixels
+import frc.robot.subsystems.rotation.IntakeRollers
+import frc.robot.subsystems.vision.PhotonVision
+
+import mu.KotlinLogging
+import kotlin.math.absoluteValue
+
+class RobotContainer {
+ /* Set logger */
+ private val textLogger = KotlinLogging.logger {}
+
+ val m_Neopixels = Neopixels()
+
+ private val MaxSpeed = Constants.Robot.maxSpeed
+ private val MaxAngularRate = Constants.Robot.maxAngularSpeed
+
+ private val joystick = CommandPS5Controller(0)
+ private val climbJoystick = CommandPS5Controller(1)
+
+ val drivetrain: CommandSwerveDrivetrain = TunerConstants.DriveTrain // My drivetrain
+
+ private val drive = FieldCentric()
+ .withDeadband(MaxSpeed * 0.1).withRotationalDeadband(MaxAngularRate * 0.1) // Add a 10% deadband
+ .withDriveRequestType(DriveRequestType.OpenLoopVoltage) // Open Loop Voltage control
+
+ private val autoRotate = FieldCentricFacingAngle()
+ .withDeadband(MaxSpeed * 0.1).withRotationalDeadband(MaxAngularRate * 0.1) // Add a 10% deadband
+ .withDriveRequestType(DriveRequestType.OpenLoopVoltage) // Open Loop Voltage control
+
+ private val breakSwerve = SwerveDriveBrake()
+
+ /* Feed Auto Command to Robot */
+ val autonomousCommand : Command // So the sendable chooser built into PathPlanner can be used
+ get() {
+ return drivetrain.autoPath
+ }
+
+ val zeroButton = DigitalInput(9) // TODO: Add to config
+
+ /* Subsystems */
+ private val logger = Telemetry(MaxSpeed)
+ private val m_Vision = PhotonVision(logger)
+
+ val m_IntakeFoldout = IntakeFoldout()
+ private val m_IntakeRollers = IntakeRollers()
+ private val m_Climber = Climber()
+
+ private val intakeLoadToShooterRunnable = Runnable {
+ IntakeLoadToShooter(m_IntakeFoldout, m_IntakeRollers).schedule()
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.IDLE)
+ m_Neopixels.chainBlinking = false
+ }
+
+ private fun configureSwerve() {
+ drivetrain.defaultCommand = drivetrain.applyRequest {
+ drive.withVelocityX(-joystick.leftY * MaxSpeed) // Drive forward with
+ // negative Y (forward)
+ .withVelocityY(-joystick.leftX * MaxSpeed) // Drive left with negative X (left)
+ .withRotationalRate(-joystick.rightX * MaxAngularRate)
+ }.withName("Free Driving") // Drive counterclockwise with negative X (left)
+
+ // reset the field-centric heading on left bumper press
+ joystick.L1().onTrue(drivetrain.runOnce { drivetrain.seedFieldRelative() })
+
+ joystick.R2().whileTrue(
+ drivetrain.applyRequest {
+ drive.withVelocityX(-joystick.leftY * (MaxSpeed * .7)) // Drive forward with
+ // negative Y (forward)
+ .withVelocityY(-joystick.leftX * (MaxSpeed * .7)) // Drive left with negative X (left)
+ .withRotationalRate(-joystick.rightX * MaxAngularRate)
+ }.withName("Fast Driving") // Drive counterclockwise with negative X (left)
+ )
+
+ joystick.L2().whileTrue(
+ drivetrain.applyRequest {
+ drive.withVelocityX(-joystick.leftY * (MaxSpeed * .4)) // Drive forward with
+ // negative Y (forward)
+ .withVelocityY(-joystick.leftX * (MaxSpeed * .4)) // Drive left with negative X (left)
+ .withRotationalRate(-joystick.rightX * MaxAngularRate)
+ }.withName("Slow Driving") // Drive counterclockwise with negative X (left)
+ )
+
+ drivetrain.registerTelemetry { state: SwerveDriveState? ->
+ logger.telemeterize(
+ state!!
+ )
+ }
+ }
+
+ private fun configureButtons() {
+ // Originally commands would not be timed and would end when its reached a setpoint, but we were messing with the controller and other stuff so didnt have time
+
+ joystick.circle().toggleOnTrue( /* Intake from Ground, then load to shooter */
+ IntakeFromGround(m_IntakeFoldout, m_IntakeRollers).alongWith(InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.INTAKING)
+ m_Neopixels.chainBlinking = true
+ })).withName("IntakeFromGround Group").finallyDo(
+ intakeLoadToShooterRunnable
+ )
+ )
+
+ joystick.triangle().toggleOnTrue( /* Intake from Source, then load to shooter */
+ SequentialCommandGroup(
+ IntakeFromSource(m_IntakeFoldout, m_IntakeRollers).alongWith(InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.INTAKING)
+ m_Neopixels.chainBlinking = true
+ }))
+ ).finallyDo(
+ intakeLoadToShooterRunnable
+ )
+ )
+
+ joystick.square().onTrue( /* Shoot into the amp */
+ SequentialCommandGroup(
+ ParallelRaceGroup(
+ ShootToAmp(m_IntakeFoldout, m_IntakeRollers),
+ WaitCommand(.9)
+ ).finallyDo(Runnable {
+ m_Neopixels.chainBlinking = true
+ }),
+ WaitCommand(.75)
+ ).alongWith(InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.SHOOTING)
+ })).finallyDo(
+ intakeLoadToShooterRunnable
+ ).withName("ShootToAmp Group")
+ )
+
+ joystick.cross().onTrue(
+ SequentialCommandGroup(
+ ParallelRaceGroup(
+ ShootToSpeaker(m_IntakeFoldout, m_IntakeRollers),
+ WaitCommand(0.4)
+ ).finallyDo(Runnable {
+ m_Neopixels.chainBlinking = true
+ }),
+ WaitCommand(0.4)
+ ).alongWith(InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.SHOOTING)
+ })).finallyDo(
+ intakeLoadToShooterRunnable
+ ).withName("ShootToSpeaker Group")
+ )
+
+ joystick.povDown().whileTrue(
+ drivetrain.applyRequest { breakSwerve }.alongWith(InstantCommand({
+ m_Neopixels.chainBlinking = true
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.BREAKING)
+ })).finallyDo(Runnable {
+ m_Neopixels.chainBlinking = false
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.IDLE)
+ })
+ )
+
+ Trigger { /* Zero button (if positions change from starting up to before a match) */
+ !zeroButton.get()
+ }.debounce(0.1).onTrue(
+ m_IntakeFoldout.zeroEncoder()
+ .finallyDo(Runnable {
+ textLogger.info { "Zeroing shooter via button" }
+ }
+ )
+ )
+ }
+
+ private fun configureClimber() {
+ m_Climber.defaultCommand = DefaultClimber(
+ m_Climber,
+ { if (climbJoystick.leftY.absoluteValue > 0.1) climbJoystick.leftY * -1 else 0.0 },
+ { if (climbJoystick.rightY.absoluteValue > 0.1) climbJoystick.rightY * -1 else 0.0 }
+ )
+ }
+
+ private fun configureEnhancers(){
+ /* Automatic Aim */
+ autoRotate.HeadingController = PhoenixPIDController(6.5, 0.0, 0.0)
+ autoRotate.HeadingController.enableContinuousInput(-Math.PI, Math.PI)
+
+// if (Constants.supportEnhancers) {
+// joystick.R1().toggleOnTrue(
+// ParallelCommandGroup(
+// drivetrain.applyRequest {
+// autoRotate.withVelocityX(-joystick.leftY * MaxSpeed) // Drive forward with
+// // negative Y (forward)
+// .withVelocityY(-joystick.leftX * MaxSpeed) // Drive left with negative X (left)
+// .withTargetDirection(
+// Rotation2d.fromDegrees(
+// Tools.calculateFacingAngle(
+// if (DriverStation.getAlliance()
+// .get() == DriverStation.Alliance.Red
+// ) Constants.Enhancers.redScorePosition
+// else Constants.Enhancers.blueScorePosition,
+// logger.position
+// )
+// )
+// )
+// }
+// ).withName("AutoAim")
+// )
+// } else {
+// textLogger.info { "Auto Aiming is OFF" }
+// }
+
+ // Default stuff
+
+// joystick.R1().whileTrue(
+// drivetrain.applyRequest {
+// autoRotate.withVelocityX(-joystick.leftY * MaxSpeed) // Drive forward with
+// // negative Y (forward)
+// .withVelocityY(-joystick.leftX * MaxSpeed) // Drive left with negative X (left)
+// .withTargetDirection(
+// Rotation2d.fromDegrees(
+// if (DriverStation.getAlliance().get() == DriverStation.Alliance.Red) 90.0
+// else 270.0
+// )
+// )
+// }.withName("Auto Heading to Amp")
+// )
+ }
+
+ private fun configureAuto() {
+ NamedCommands.registerCommand("IntakeFromGround", AutoIntakeFromGround(m_IntakeFoldout, m_IntakeRollers))
+ NamedCommands.registerCommand("IntakeLoadToShooter", AutoIntakeLoadToShooter(m_IntakeFoldout, m_IntakeRollers))
+
+ NamedCommands.registerCommand("Amplify",
+ SequentialCommandGroup(
+ ParallelRaceGroup(
+ ShootToAmp(m_IntakeFoldout, m_IntakeRollers),
+ WaitCommand(.8)
+ ).finallyDo(Runnable {
+ m_Neopixels.chainBlinking = true
+ }),
+ WaitCommand(1.0)
+ ).alongWith(InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.SHOOTING)
+ m_Neopixels.chainBlinking = false
+ })).finallyDo(Runnable {
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.AUTO)
+ }).withName("ShootToAmp Auto Group")
+ )
+
+ NamedCommands.registerCommand("Poop",
+ SequentialCommandGroup(
+ ParallelRaceGroup(
+ ShootToSpeaker(m_IntakeFoldout, m_IntakeRollers),
+ WaitCommand(0.2)
+ ).finallyDo(Runnable {
+ m_Neopixels.chainBlinking = true
+ }),
+ WaitCommand(0.4)
+ ).alongWith(InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.SHOOTING)
+ m_Neopixels.chainBlinking = false
+ })).finallyDo(
+ intakeLoadToShooterRunnable
+ ).withName("ShootToSpeaker Group")
+ )
+
+ NamedCommands.registerCommand("Break", ParallelDeadlineGroup( // Breaks for 5 seconds
+ WaitCommand(5.0),
+ drivetrain.applyRequest { breakSwerve },
+ InstantCommand({
+ m_Neopixels.updateState(Constants.Indicators.Neopixels.NeopixelStates.BREAKING)
+ m_Neopixels.chainBlinking = true
+ }) ).finallyDo(Runnable { m_Neopixels.chainBlinking = false }))
+
+ drivetrain.configurePathPlanner()
+ }
+
+ private fun configureVision() {
+ if (Constants.Vision.enable) {
+ PhotonPoseEstimator(drivetrain, logger, m_Vision).schedule()
+ }
+ }
+
+ private fun configureRobotTools() {
+ textLogger.info { "Robot tools are on!" }
+
+ SmartDashboard.putData(CommandScheduler.getInstance())
+
+ SmartDashboard.putData("Tools/IntakeFromGround", IntakeFromGround(m_IntakeFoldout, m_IntakeRollers))
+ SmartDashboard.putData("Tools/IntakeFromSource", IntakeFromSource(m_IntakeFoldout, m_IntakeRollers))
+ SmartDashboard.putData("Tools/Load", IntakeLoadToShooter(m_IntakeFoldout, m_IntakeRollers))
+ SmartDashboard.putData("Tools/ShootToAmp", ShootToAmp(m_IntakeFoldout, m_IntakeRollers))
+
+ SmartDashboard.putData("Tools/Intake Foldout Command", m_IntakeFoldout)
+ SmartDashboard.putData("Tools/Intake Rollers", m_IntakeRollers)
+ }
+
+ private fun configureInternalTools() {
+ SmartDashboard.putData("IntakeFoldout/Reset Encoder", m_IntakeFoldout.zeroEncoder())
+ SmartDashboard.putData("Internals/Climber Retract", m_Climber.setClimberToMaxPositions())
+ SmartDashboard.putData("Internals/Climber Uncap", m_Climber.setDisableSoftLimits())
+ }
+
+ init {
+ configureVision()
+ configureAuto()
+ configureSwerve()
+ configureEnhancers()
+ configureButtons()
+ configureClimber()
+
+ if (Constants.isDebug) {
+ configureRobotTools()
+ }
+
+ configureInternalTools()
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/Telemetry.kt b/src/main/java/frc/robot/Telemetry.kt
new file mode 100644
index 0000000..ff8d519
--- /dev/null
+++ b/src/main/java/frc/robot/Telemetry.kt
@@ -0,0 +1,133 @@
+package frc.robot
+
+import com.ctre.phoenix6.SignalLogger
+import com.ctre.phoenix6.Utils
+import com.ctre.phoenix6.mechanisms.swerve.SwerveDrivetrain.SwerveDriveState
+import edu.wpi.first.math.geometry.Pose2d
+import edu.wpi.first.networktables.NetworkTableInstance
+import edu.wpi.first.util.datalog.DoubleArrayLogEntry
+import edu.wpi.first.util.datalog.DoubleLogEntry
+import edu.wpi.first.wpilibj.DataLogManager
+import edu.wpi.first.wpilibj.Timer
+import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d
+import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard
+import edu.wpi.first.wpilibj.util.Color
+import edu.wpi.first.wpilibj.util.Color8Bit
+
+import mu.KotlinLogging;
+
+/**
+ * Class for telemetry data collection and publishing.
+ *
+ * @property MaxSpeed Maximum speed of the robot in meters per second.
+ */
+class Telemetry(private val MaxSpeed: Double) {
+ private val logger = KotlinLogging.logger {}
+ private val logEntry: DoubleArrayLogEntry
+ private val odomEntry: DoubleLogEntry
+
+ /* What to publish over networktables for telemetry */
+ private val inst = NetworkTableInstance.getDefault()
+
+ /* Robot pose for field positioning */
+ private val table = inst.getTable("Pose")
+ private val fieldPub = table.getDoubleArrayTopic("robotPose").publish()
+ private val fieldTypePub = table.getStringTopic(".type").publish()
+
+ /* Robot speeds for general checking */
+ private val driveStats = inst.getTable("Drive")
+ private val velocityX = driveStats.getDoubleTopic("Velocity X").publish()
+ private val velocityY = driveStats.getDoubleTopic("Velocity Y").publish()
+ private val speed = driveStats.getDoubleTopic("Speed").publish()
+ private val odomPeriod = driveStats.getDoubleTopic("Odometry Period").publish()
+
+ /* Keep a reference of the last pose to calculate the speeds */
+ private var m_lastPose = Pose2d()
+ private var lastTime = Utils.getCurrentTimeSeconds()
+
+ /* Mechanisms to represent the swerve module states */
+ private val m_moduleMechanisms = arrayOf(
+ Mechanism2d(1.0, 1.0),
+ Mechanism2d(1.0, 1.0),
+ Mechanism2d(1.0, 1.0),
+ Mechanism2d(1.0, 1.0)
+ )
+
+ /* A direction and length changing ligament for speed representation */
+ private val m_moduleSpeeds = arrayOf(
+ m_moduleMechanisms[0].getRoot("RootSpeed", 0.5, 0.5).append(MechanismLigament2d("Speed", 0.5, 0.0)),
+ m_moduleMechanisms[1].getRoot("RootSpeed", 0.5, 0.5).append(MechanismLigament2d("Speed", 0.5, 0.0)),
+ m_moduleMechanisms[2].getRoot("RootSpeed", 0.5, 0.5).append(MechanismLigament2d("Speed", 0.5, 0.0)),
+ m_moduleMechanisms[3].getRoot("RootSpeed", 0.5, 0.5).append(MechanismLigament2d("Speed", 0.5, 0.0))
+ )
+
+ /* A direction changing and length constant ligament for module direction */
+ private val m_moduleDirections = arrayOf(
+ m_moduleMechanisms[0].getRoot("RootDirection", 0.5, 0.5)
+ .append(MechanismLigament2d("Direction", 0.1, 0.0, 0.0, Color8Bit(Color.kWhite))),
+ m_moduleMechanisms[1].getRoot("RootDirection", 0.5, 0.5)
+ .append(MechanismLigament2d("Direction", 0.1, 0.0, 0.0, Color8Bit(Color.kWhite))),
+ m_moduleMechanisms[2].getRoot("RootDirection", 0.5, 0.5)
+ .append(MechanismLigament2d("Direction", 0.1, 0.0, 0.0, Color8Bit(Color.kWhite))),
+ m_moduleMechanisms[3].getRoot("RootDirection", 0.5, 0.5)
+ .append(MechanismLigament2d("Direction", 0.1, 0.0, 0.0, Color8Bit(Color.kWhite)))
+ )
+
+ /**
+ * Initializes the telemetry object and starts the SignalLogger.
+ */
+ init {
+ SignalLogger.start()
+ logEntry = DoubleArrayLogEntry(DataLogManager.getLog(), "odometry")
+ odomEntry = DoubleLogEntry(DataLogManager.getLog(), "odom period")
+ }
+
+ /**
+ * Publishes the current state of the swerve drive to the SmartDashboard.
+ *
+ * @param state The current state of the swerve drive.
+ */
+ fun telemeterize(state: SwerveDriveState) {
+ /* Telemeterize the pose */
+ val pose = state.Pose
+ fieldTypePub.set("Field2d")
+ fieldPub.set(
+ doubleArrayOf(
+ pose.x,
+ pose.y,
+ pose.rotation.degrees
+ )
+ )
+
+ /* Telemeterize the robot's general speeds */
+ val currentTime = Utils.getCurrentTimeSeconds()
+ val diffTime = currentTime - lastTime
+ lastTime = currentTime
+ val distanceDiff = pose.minus(m_lastPose).translation
+ m_lastPose = pose
+ val velocities = distanceDiff.div(diffTime)
+ speed.set(velocities.norm)
+ velocityX.set(velocities.x)
+ velocityY.set(velocities.y)
+ odomPeriod.set(1.0 / state.OdometryPeriod)
+
+ /* Telemeterize the module's states */for (i in 0..3) {
+ m_moduleSpeeds[i].setAngle(state.ModuleStates[i].angle)
+ m_moduleDirections[i].setAngle(state.ModuleStates[i].angle)
+ m_moduleSpeeds[i].setLength(state.ModuleStates[i].speedMetersPerSecond / (2 * MaxSpeed))
+ SmartDashboard.putData("Swerve/Module $i", m_moduleMechanisms[i])
+ }
+ val timestamp = (Timer.getFPGATimestamp() * 1000000).toLong()
+ logEntry.append(doubleArrayOf(pose.x, pose.y, pose.rotation.degrees), timestamp)
+ odomEntry.append(state.OdometryPeriod, timestamp)
+ }
+
+ /**
+ * Returns the last known pose of the robot.
+ */
+ val position: Pose2d
+ get() {
+ return m_lastPose
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/Tools.kt b/src/main/java/frc/robot/Tools.kt
new file mode 100644
index 0000000..6ce776f
--- /dev/null
+++ b/src/main/java/frc/robot/Tools.kt
@@ -0,0 +1,82 @@
+package frc.robot
+
+import com.revrobotics.CANSparkMax
+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.Transform3d
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard
+import kotlin.math.atan2
+import kotlin.math.sqrt
+
+/**
+ * A class that contains useful equations and tools for the robot
+ */
+object Tools {
+ /**
+ * Calculate the angle (in a cartesian plane) the robot should be facing to shoot at the target
+ * @param score_pos The position of the target
+ * @param robot_pose The position of the robot
+ * @return The angle the robot should be facing
+ */
+ fun calculateFacingAngle(score_pos: Pose3d, robot_pose: Pose2d): Double {
+ val dx = score_pos.translation.x - robot_pose.translation.x // delta X
+ val dy = score_pos.translation.y - robot_pose.translation.y // delta Y
+ return Math.toDegrees(atan2(dy, dx)) // Tangent Angle (in Rotations)
+ }
+
+ /**
+ * Calculate the distance between the robot and the target
+ * @param score_pos The position of the target
+ * @param robot_pose The position of the robot
+ * @return The distance between the robot and the target
+ */
+ fun calculateDistance(score_pos: Pose3d, robot_pose : Pose2d): Double {
+ val dx = score_pos.translation.x - robot_pose.translation.x // delta X
+ val dy = score_pos.translation.y - robot_pose.translation.y // delta Y
+ return sqrt(dx * dx + dy * dy) // Distance of B^2 = A^2 + C^2 (Find distance using Pythagorean Theorem)
+ }
+
+ /**
+ * Calculate the angle the robot shooter should shoot at to hit the target
+ * @param distance The distance between the robot and the target
+ * @param height The height of the target
+ * @return The angle the robot should shoot at
+ */
+ fun calculateShotAngle(distance: Double, height: Double): Double {
+ val angle = Math.toDegrees(atan2(height, distance)) // Tangent Angle (in Degrees)
+ return angle.coerceIn(4.0, 70.0) // Coerce the angle to be within the range of 4 to 65 degrees
+ }
+
+ /**
+ * Transform a 3D transform to a 2D pose
+ * @param transform The 3D transform
+ * @return The 2D pose
+ */
+ fun transform3DtoPose2D(transform : Transform3d) : Pose2d {
+ return Pose2d(transform.translation.x, transform.translation.y, Rotation2d.fromRadians(transform.rotation.z))
+ }
+
+ /**
+ * Calculate the distance between two poses
+ * @param pose1 The first pose
+ * @param pose2 The second pose
+ * @return The distance between the two poses
+ */
+ fun distanceBetweenPoses(pose1: Pose2d, pose2: Pose2d): Double {
+ val dx = pose1.translation.x - pose2.translation.x // delta X
+ val dy = pose1.translation.y - pose2.translation.y // delta Y
+ return sqrt(dx * dx + dy * dy) // Distance of B^2 = A^2 + C^2 (Find distance using Pythagorean Theorem)
+ }
+
+ fun invertWhen(value: Double, condition: Boolean): Double {
+ return if (condition) -value else value
+ }
+
+ fun provideMotorDetails(motor: CANSparkMax, name: String) {
+ SmartDashboard.putNumber("Motors/$name/Output", motor.appliedOutput)
+ SmartDashboard.putNumber("Motors/$name/Current", motor.outputCurrent)
+ SmartDashboard.putNumber("Motors/$name/Voltage", motor.busVoltage)
+ SmartDashboard.putNumber("Motors/$name/Temp", motor.motorTemperature)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/auto/AutoIntakeFromGround.kt b/src/main/java/frc/robot/commands/auto/AutoIntakeFromGround.kt
new file mode 100644
index 0000000..02d3701
--- /dev/null
+++ b/src/main/java/frc/robot/commands/auto/AutoIntakeFromGround.kt
@@ -0,0 +1,48 @@
+package frc.robot.commands.auto
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+/**
+ * Command for "automatically" intaking from the ground.
+ * This command sets the intake foldout to the ground intake state, the shooter foldout to the avoid state,
+ * and the intake rollers to the intake state.
+ *
+ * @property intakeFoldout The IntakeFoldout subsystem.
+ * @property shooterFoldout The ShooterFoldout subsystem.
+ * @property intakeRollers The IntakeRollers subsystem.
+ */
+class AutoIntakeFromGround(
+ private val intakeFoldout: IntakeFoldout,
+ private val intakeRollers: IntakeRollers
+) : Command() {
+
+ /**
+ * Initializes the command, adding the required subsystems and setting the command name.
+ */
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "AutoIntakeFromGround"
+ }
+
+ /**
+ * Called when the command is initially scheduled.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ */
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.INTAKE_GROUND)
+ intakeRollers.setState(Constants.IntakeRollers.Speed.INTAKE)
+ }
+
+ /**
+ * Returns whether the command has finished.
+ * The command is finished when the intake foldout is close to the ground intake state.
+ *
+ * @return True if the command is finished, false otherwise.
+ */
+ override fun isFinished(): Boolean {
+ return intakeFoldout.isCloseToState(Constants.IntakeFoldout.FoldoutState.INTAKE_GROUND)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/auto/AutoIntakeLoadToShooter.kt b/src/main/java/frc/robot/commands/auto/AutoIntakeLoadToShooter.kt
new file mode 100644
index 0000000..9b7add5
--- /dev/null
+++ b/src/main/java/frc/robot/commands/auto/AutoIntakeLoadToShooter.kt
@@ -0,0 +1,48 @@
+package frc.robot.commands.auto
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+/**
+ * Command for automatically loading the intake to the shooter.
+ * This command sets the intake foldout to the low shoot state, the shooter foldout to the avoid state,
+ * and the intake rollers to the neutral state.
+ *
+ * @property intakeFoldout The IntakeFoldout subsystem.
+ * @property shooterFoldout The ShooterFoldout subsystem.
+ * @property intakeRollers The IntakeRollers subsystem.
+ */
+class AutoIntakeLoadToShooter(
+ private val intakeFoldout: IntakeFoldout,
+ private val intakeRollers: IntakeRollers
+) : Command() {
+
+ /**
+ * Initializes the command, adding the required subsystems and setting the command name.
+ */
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "AutoIntakeLoadToShooter"
+ }
+
+ /**
+ * Called when the command is initially scheduled.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ */
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ }
+
+ /**
+ * Returns whether the command has finished.
+ * The command is finished when the intake foldout is close to the low shoot state.
+ *
+ * @return True if the command is finished, false otherwise.
+ */
+ override fun isFinished(): Boolean {
+ return intakeFoldout.isCloseToState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/climb/DefaultClimber.kt b/src/main/java/frc/robot/commands/climb/DefaultClimber.kt
new file mode 100644
index 0000000..21e0730
--- /dev/null
+++ b/src/main/java/frc/robot/commands/climb/DefaultClimber.kt
@@ -0,0 +1,27 @@
+package frc.robot.commands.climb
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.subsystems.climb.Climber
+import java.util.function.DoubleSupplier
+
+class DefaultClimber(
+ private val climber: Climber,
+ private val leftStick: DoubleSupplier,
+ private val rightStick: DoubleSupplier
+) : Command() {
+ init {
+ addRequirements(climber)
+ }
+
+ override fun execute() {
+ climber.setMotor(Climber.Motor.LEFT, leftStick.asDouble)
+ climber.setMotor(Climber.Motor.RIGHT, rightStick.asDouble)
+ }
+
+ override fun isFinished() = false
+
+ override fun end(interrupted: Boolean) {
+ climber.setMotor(Climber.Motor.LEFT, 0.0)
+ climber.setMotor(Climber.Motor.RIGHT, 0.0)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/IntakeFromGround.kt b/src/main/java/frc/robot/commands/teleop/IntakeFromGround.kt
new file mode 100644
index 0000000..8af3745
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/IntakeFromGround.kt
@@ -0,0 +1,68 @@
+package frc.robot.commands.teleop
+
+import com.ctre.phoenix6.Utils
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+/**
+ * Command for intaking from the ground during teleop.
+ * This command sets the intake foldout to the ground intake state, the shooter foldout to the avoid state,
+ * and the intake rollers to the intake state.
+ *
+ * @property intakeFoldout The IntakeFoldout subsystem.
+ * @property intakeRollers The IntakeRollers subsystem.
+ */
+class IntakeFromGround(
+ private val intakeFoldout: IntakeFoldout,
+ private val intakeRollers: IntakeRollers,
+) : Command() {
+ private var simulationTicks : Int? = null
+
+ /**
+ * Initializes the command, adding the required subsystems and setting the command name.
+ */
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "IntakeFromGround"
+ }
+
+ /**
+ * Called when the command is initially scheduled.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ */
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.INTAKE_GROUND)
+ intakeRollers.setState(Constants.IntakeRollers.Speed.INTAKE)
+
+ if (Utils.isSimulation()) {
+ simulationTicks = 0
+ }
+ }
+
+ /**
+ * Returns whether the command has finished.
+ * The command is finished when the intake rollers are broken or the simulation time has passed.
+ *
+ * @return True if the command is finished, false otherwise.
+ */
+ override fun isFinished(): Boolean {
+ if (simulationTicks != null) {
+ simulationTicks = simulationTicks?.plus(1)
+ return simulationTicks!! > Constants.IntakeFoldout.simulationTime
+ }
+ return intakeRollers.isBroken()
+ }
+
+ /**
+ * Called once after isFinished returns true or the command is interrupted.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ *
+ * @param interrupted Whether the command was interrupted.
+ */
+ override fun end(interrupted: Boolean) {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/IntakeFromSource.kt b/src/main/java/frc/robot/commands/teleop/IntakeFromSource.kt
new file mode 100644
index 0000000..6a6d966
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/IntakeFromSource.kt
@@ -0,0 +1,67 @@
+package frc.robot.commands.teleop
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+/**
+ * Command for intaking from a source during teleop.
+ * This command sets the intake foldout to the intake drop state, the shooter foldout to the avoid state,
+ * and the intake rollers to the intake state.
+ *
+ * @property intakeFoldout The IntakeFoldout subsystem.
+ * @property intakeRollers The IntakeRollers subsystem.
+ */
+class IntakeFromSource(
+ private val intakeFoldout: IntakeFoldout,
+ private val intakeRollers: IntakeRollers,
+) : Command() {
+ private var simulationTicks : Int? = null
+
+ /**
+ * Initializes the command, adding the required subsystems and setting the command name.
+ */
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "IntakeFromSource"
+ }
+
+ /**
+ * Called when the command is initially scheduled.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ */
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.INTAKE_DROP)
+ intakeRollers.setState(Constants.IntakeRollers.Speed.INTAKE)
+
+ if (simulationTicks != null) {
+ simulationTicks = 0
+ }
+ }
+
+ /**
+ * Returns whether the command has finished.
+ * The command is finished when the intake rollers are broken or the simulation time has passed.
+ *
+ * @return True if the command is finished, false otherwise.
+ */
+ override fun isFinished(): Boolean {
+ if (simulationTicks != null) {
+ simulationTicks = simulationTicks?.plus(1)
+ return simulationTicks!! > Constants.IntakeFoldout.simulationTime
+ }
+ return intakeRollers.isBroken()
+ }
+
+ /**
+ * Called once after isFinished returns true or the command is interrupted.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ *
+ * @param interrupted Whether the command was interrupted.
+ */
+ override fun end(interrupted: Boolean) {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/IntakeLoadToShooter.kt b/src/main/java/frc/robot/commands/teleop/IntakeLoadToShooter.kt
new file mode 100644
index 0000000..09d2b0d
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/IntakeLoadToShooter.kt
@@ -0,0 +1,46 @@
+package frc.robot.commands.teleop
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+/**
+ * Command for loading the intake to the shooter during teleop.
+ * This command sets the intake foldout to the low shoot state, the shooter foldout to the avoid state,
+ * and the intake rollers to the neutral state. It then resets the shooter foldout to the basic point state.
+ *
+ * @property intakeFoldout The IntakeFoldout subsystem.
+ * @property intakeRollers The IntakeRollers subsystem.
+ */
+class IntakeLoadToShooter(
+ private val intakeFoldout : IntakeFoldout,
+ private val intakeRollers : IntakeRollers
+) : Command() {
+ /**
+ * Initializes the command, adding the required subsystems and setting the command name.
+ */
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "IntakeLoadToShooter"
+ }
+
+ /**
+ * Called when the command is initially scheduled.
+ * Sets the state of the intake foldout, shooter foldout, and intake rollers.
+ */
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ }
+
+ /**
+ * Returns whether the command has finished.
+ * The command is finished when the intake foldout is close to the low shoot state.
+ *
+ * @return True if the command is finished, false otherwise.
+ */
+ override fun isFinished(): Boolean {
+ return intakeFoldout.isCloseToState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/ShootPoop.kt b/src/main/java/frc/robot/commands/teleop/ShootPoop.kt
new file mode 100644
index 0000000..96baef2
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/ShootPoop.kt
@@ -0,0 +1,27 @@
+package frc.robot.commands.teleop
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+class ShootPoop(
+ private val intakeFoldout : IntakeFoldout,
+ private val intakeRollers : IntakeRollers,
+) : Command() {
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ }
+
+ override fun initialize() {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ }
+
+ override fun isFinished(): Boolean {
+ return false
+ }
+
+ override fun end(interrupted: Boolean) {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.SHOOT)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/ShootReset.kt b/src/main/java/frc/robot/commands/teleop/ShootReset.kt
new file mode 100644
index 0000000..a879777
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/ShootReset.kt
@@ -0,0 +1,25 @@
+package frc.robot.commands.teleop
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+class ShootReset(
+ private val intakeFoldout : IntakeFoldout,
+ private val intakeRollers : IntakeRollers,
+) : Command() {
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "ShootReset"
+ }
+
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.IDLE)
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ }
+
+ override fun isFinished(): Boolean {
+ return true
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/ShootToAmp.kt b/src/main/java/frc/robot/commands/teleop/ShootToAmp.kt
new file mode 100644
index 0000000..364d063
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/ShootToAmp.kt
@@ -0,0 +1,28 @@
+package frc.robot.commands.teleop
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+class ShootToAmp(
+ private val intakeFoldout: IntakeFoldout,
+ private val intakeRollers: IntakeRollers,
+) : Command() {
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "ShootToAmp"
+ }
+
+ override fun initialize() {
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.AMPLIFY)
+ }
+
+ override fun isFinished(): Boolean {
+ return false
+ }
+
+ override fun end(interrupted: Boolean) {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.AMPLIFY)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/teleop/ShootToSpeaker.kt b/src/main/java/frc/robot/commands/teleop/ShootToSpeaker.kt
new file mode 100644
index 0000000..5ff5b56
--- /dev/null
+++ b/src/main/java/frc/robot/commands/teleop/ShootToSpeaker.kt
@@ -0,0 +1,29 @@
+package frc.robot.commands.teleop
+
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.Constants
+import frc.robot.subsystems.foldouts.IntakeFoldout
+import frc.robot.subsystems.rotation.IntakeRollers
+
+class ShootToSpeaker(
+ private val intakeFoldout : IntakeFoldout,
+ private val intakeRollers : IntakeRollers,
+) : Command() {
+ init {
+ addRequirements(intakeFoldout, intakeRollers)
+ name = "ShootToSpeaker"
+ }
+
+ override fun initialize() {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.NEUTRAL)
+ intakeFoldout.setState(Constants.IntakeFoldout.FoldoutState.SHOOT_HIGH)
+ }
+
+ override fun isFinished(): Boolean {
+ return false
+ }
+
+ override fun end(interrupted: Boolean) {
+ intakeRollers.setState(Constants.IntakeRollers.Speed.SHOOT)
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/commands/vision/PhotonPoseEstimator.kt b/src/main/java/frc/robot/commands/vision/PhotonPoseEstimator.kt
new file mode 100644
index 0000000..874e983
--- /dev/null
+++ b/src/main/java/frc/robot/commands/vision/PhotonPoseEstimator.kt
@@ -0,0 +1,55 @@
+package frc.robot.commands.vision
+
+import com.ctre.phoenix6.Utils
+import edu.wpi.first.math.geometry.Transform3d
+import edu.wpi.first.wpilibj.Timer
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard
+import edu.wpi.first.wpilibj2.command.Command
+import frc.robot.CommandSwerveDrivetrain
+import frc.robot.Telemetry
+import frc.robot.Tools
+import frc.robot.subsystems.vision.PhotonVision
+import kotlin.concurrent.thread
+import kotlin.math.abs
+
+class PhotonPoseEstimator(
+ private val drivetrain: CommandSwerveDrivetrain,
+ private val telemetry: Telemetry,
+ private val vision: PhotonVision
+) : Command() {
+ private val isSimulation = Utils.isSimulation()
+
+ override fun initialize() {
+ SmartDashboard.putNumberArray("Left Camera", arrayOf(0.0, 0.0, 0.0))
+ SmartDashboard.putNumberArray("Right Camera", arrayOf(0.0, 0.0, 0.0))
+
+ addRequirements(vision)
+ }
+
+ override fun execute() {
+ thread {
+ val (left, right) = vision.getCameraResults()
+
+ if (left.isPresent) addPosition(left.best, "Left Camera")
+ if (right.isPresent) addPosition(right.best, "Right Camera")
+ }
+ }
+
+ private fun addPosition(suggestedPosition: Transform3d, name : String) {
+ val dimensionalPose = Tools.transform3DtoPose2D(suggestedPosition)
+ val timestamp = Timer.getFPGATimestamp()
+
+ if (abs(Tools.distanceBetweenPoses(telemetry.position, dimensionalPose)) < 1) { // Suggested by CTRE Devs, may have issues if robot vision doesn't work the whole round and then starts back up?
+ if (!isSimulation) drivetrain.addVisionMeasurement(dimensionalPose, timestamp)
+ SmartDashboard.putNumberArray(name, arrayOf(dimensionalPose.translation.x, dimensionalPose.translation.y, dimensionalPose.rotation.degrees))
+ }
+ }
+
+ override fun runsWhenDisabled(): Boolean {
+ return true
+ }
+
+ override fun isFinished(): Boolean {
+ return false
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/generated/TunerConstants.java b/src/main/java/frc/robot/generated/TunerConstants.java
new file mode 100644
index 0000000..83c6121
--- /dev/null
+++ b/src/main/java/frc/robot/generated/TunerConstants.java
@@ -0,0 +1,138 @@
+package frc.robot.generated;
+
+import com.ctre.phoenix6.configs.Slot0Configs;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveDrivetrainConstants;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveModuleConstants;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveModuleConstantsFactory;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveModule.ClosedLoopOutputType;
+import com.ctre.phoenix6.mechanisms.swerve.SwerveModuleConstants.SteerFeedbackType;
+
+import edu.wpi.first.math.util.Units;
+import frc.robot.CommandSwerveDrivetrain;
+
+// Generated by the Tuner X Swerve Project Generator
+// https://v6.docs.ctr-electronics.com/en/stable/docs/tuner/tuner-swerve/index.html
+public class TunerConstants {
+ // Both sets of gains need to be tuned to your individual robot.
+
+ // The steer motor uses any SwerveModule.SteerRequestType control request with the
+ // output type specified by SwerveModuleConstants.SteerMotorClosedLoopOutput
+ private static final Slot0Configs steerGains = new Slot0Configs()
+ .withKP(100).withKI(0).withKD(0.2)
+ .withKS(0).withKV(1.5).withKA(0);
+ // When using closed-loop control, the drive motor uses the control
+ // output type specified by SwerveModuleConstants.DriveMotorClosedLoopOutput
+ private static final Slot0Configs driveGains = new Slot0Configs()
+ .withKP(3).withKI(0).withKD(0)
+ .withKS(0).withKV(0).withKA(0);
+
+ // The closed-loop output type to use for the steer motors;
+ // This affects the PID/FF gains for the steer motors
+ private static final ClosedLoopOutputType steerClosedLoopOutput = ClosedLoopOutputType.Voltage;
+ // The closed-loop output type to use for the drive motors;
+ // This affects the PID/FF gains for the drive motors
+ private static final ClosedLoopOutputType driveClosedLoopOutput = ClosedLoopOutputType.Voltage;
+
+ // The stator current at which the wheels start to slip;
+ // This needs to be tuned to your individual robot
+ private static final double kSlipCurrentA = 300.0;
+
+ // Theoretical free speed (m/s) at 12v applied output;
+ // This needs to be tuned to your individual robot
+ public static final double kSpeedAt12VoltsMps = 6.21;
+
+ // Every 1 rotation of the azimuth results in kCoupleRatio drive motor turns;
+ // This may need to be tuned to your individual robot
+ private static final double kCoupleRatio = 3;
+
+ private static final double kDriveGearRatio = 5.142857142857142;
+ private static final double kSteerGearRatio = 12.8;
+ private static final double kWheelRadiusInches = 2;
+
+ private static final boolean kSteerMotorReversed = false;
+ private static final boolean kInvertLeftSide = true;
+ private static final boolean kInvertRightSide = false;
+
+ private static final String kCANbusName = "";
+ private static final int kPigeonId = 2;
+
+
+ // These are only used for simulation
+ private static final double kSteerInertia = 0.00001;
+ private static final double kDriveInertia = 0.001;
+ // Simulated voltage necessary to overcome friction
+ private static final double kSteerFrictionVoltage = 0.25;
+ private static final double kDriveFrictionVoltage = 0.25;
+
+ private static final SwerveDrivetrainConstants DrivetrainConstants = new SwerveDrivetrainConstants()
+ .withPigeon2Id(kPigeonId)
+ .withCANbusName(kCANbusName);
+
+ private static final SwerveModuleConstantsFactory ConstantCreator = new SwerveModuleConstantsFactory()
+ .withDriveMotorGearRatio(kDriveGearRatio)
+ .withSteerMotorGearRatio(kSteerGearRatio)
+ .withWheelRadius(kWheelRadiusInches)
+ .withSlipCurrent(kSlipCurrentA)
+ .withSteerMotorGains(steerGains)
+ .withDriveMotorGains(driveGains)
+ .withSteerMotorClosedLoopOutput(steerClosedLoopOutput)
+ .withDriveMotorClosedLoopOutput(driveClosedLoopOutput)
+ .withSpeedAt12VoltsMps(kSpeedAt12VoltsMps)
+ .withSteerInertia(kSteerInertia)
+ .withDriveInertia(kDriveInertia)
+ .withSteerFrictionVoltage(kSteerFrictionVoltage)
+ .withDriveFrictionVoltage(kDriveFrictionVoltage)
+ .withFeedbackSource(SteerFeedbackType.FusedCANcoder)
+ .withCouplingGearRatio(kCoupleRatio)
+ .withSteerMotorInverted(kSteerMotorReversed);
+
+
+ // Front Left
+ private static final int kFrontLeftDriveMotorId = 10;
+ private static final int kFrontLeftSteerMotorId = 9;
+ private static final int kFrontLeftEncoderId = 11;
+ private static final double kFrontLeftEncoderOffset = -0.04931640625;
+
+ private static final double kFrontLeftXPosInches = 9.75;
+ private static final double kFrontLeftYPosInches = 9.75;
+
+ // Front Right
+ private static final int kFrontRightDriveMotorId = 13;
+ private static final int kFrontRightSteerMotorId = 12;
+ private static final int kFrontRightEncoderId = 14;
+ private static final double kFrontRightEncoderOffset = 0.06201171875;
+
+ private static final double kFrontRightXPosInches = 9.75;
+ private static final double kFrontRightYPosInches = -9.75;
+
+ // Back Left
+ private static final int kBackLeftDriveMotorId = 7;
+ private static final int kBackLeftSteerMotorId = 6;
+ private static final int kBackLeftEncoderId = 8;
+ private static final double kBackLeftEncoderOffset = -0.08984375;
+
+ private static final double kBackLeftXPosInches = -9.75;
+ private static final double kBackLeftYPosInches = 9.75;
+
+ // Back Right
+ private static final int kBackRightDriveMotorId = 4;
+ private static final int kBackRightSteerMotorId = 3;
+ private static final int kBackRightEncoderId = 5;
+ private static final double kBackRightEncoderOffset = -0.042724609375;
+
+ private static final double kBackRightXPosInches = -9.75;
+ private static final double kBackRightYPosInches = -9.75;
+
+
+ private static final SwerveModuleConstants FrontLeft = ConstantCreator.createModuleConstants(
+ kFrontLeftSteerMotorId, kFrontLeftDriveMotorId, kFrontLeftEncoderId, kFrontLeftEncoderOffset, Units.inchesToMeters(kFrontLeftXPosInches), Units.inchesToMeters(kFrontLeftYPosInches), kInvertLeftSide);
+ private static final SwerveModuleConstants FrontRight = ConstantCreator.createModuleConstants(
+ kFrontRightSteerMotorId, kFrontRightDriveMotorId, kFrontRightEncoderId, kFrontRightEncoderOffset, Units.inchesToMeters(kFrontRightXPosInches), Units.inchesToMeters(kFrontRightYPosInches), kInvertRightSide);
+ private static final SwerveModuleConstants BackLeft = ConstantCreator.createModuleConstants(
+ kBackLeftSteerMotorId, kBackLeftDriveMotorId, kBackLeftEncoderId, kBackLeftEncoderOffset, Units.inchesToMeters(kBackLeftXPosInches), Units.inchesToMeters(kBackLeftYPosInches), kInvertLeftSide);
+ private static final SwerveModuleConstants BackRight = ConstantCreator.createModuleConstants(
+ kBackRightSteerMotorId, kBackRightDriveMotorId, kBackRightEncoderId, kBackRightEncoderOffset, Units.inchesToMeters(kBackRightXPosInches), Units.inchesToMeters(kBackRightYPosInches), kInvertRightSide);
+
+ public static final CommandSwerveDrivetrain DriveTrain = new CommandSwerveDrivetrain(DrivetrainConstants, FrontLeft,
+ FrontRight, BackLeft, BackRight);
+}
diff --git a/src/main/java/frc/robot/subsystems/climb/Climber.kt b/src/main/java/frc/robot/subsystems/climb/Climber.kt
new file mode 100644
index 0000000..6519db5
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/climb/Climber.kt
@@ -0,0 +1,109 @@
+package frc.robot.subsystems.climb
+
+import com.ctre.phoenix6.configs.SoftwareLimitSwitchConfigs
+import com.ctre.phoenix6.controls.DutyCycleOut
+import com.ctre.phoenix6.controls.VoltageOut
+import com.ctre.phoenix6.hardware.TalonFX
+import com.ctre.phoenix6.signals.NeutralModeValue
+import edu.wpi.first.wpilibj2.command.Command
+import edu.wpi.first.wpilibj2.command.InstantCommand
+import edu.wpi.first.wpilibj2.command.SubsystemBase
+import frc.robot.Constants
+
+class Climber() : SubsystemBase() {
+ private val leftMotor = TalonFX(Constants.Climber.leftMotorID)
+ private val rightMotor = TalonFX(Constants.Climber.rightMotorID)
+ private val disabledLimits = false
+
+ private val request = DutyCycleOut(0.0)
+
+ enum class Motor {
+ LEFT, RIGHT
+ }
+
+ init {
+ leftMotor.inverted = Constants.Climber.isLeftInverted
+ rightMotor.inverted = Constants.Climber.isRightInverted
+
+ request.OverrideBrakeDurNeutral = true
+
+ leftMotor.setNeutralMode(NeutralModeValue.Brake)
+ rightMotor.setNeutralMode(NeutralModeValue.Brake)
+
+ // Soft limits
+ val climberLimit = SoftwareLimitSwitchConfigs()
+ .withForwardSoftLimitThreshold(Constants.Climber.maximumPosition)
+ .withReverseSoftLimitThreshold(Constants.Climber.minimumPosition)
+ .withForwardSoftLimitEnable(true)
+ .withReverseSoftLimitEnable(true)
+
+ leftMotor.configurator.apply(climberLimit)
+ rightMotor.configurator.apply(climberLimit)
+ }
+
+ fun setMotor(motor: Motor, percent: Double) {
+ val motorInstance = when (motor) {
+ Motor.LEFT -> leftMotor
+ Motor.RIGHT -> rightMotor
+ }
+
+ val currentPos = motorInstance.position
+ val output = if (currentPos.valueAsDouble >= Constants.Climber.maximumPosition && percent > 0 && !disabledLimits) {
+ 0.0 // Prevent positive output when above maximum position, wont work if limits are disabled
+ } else {
+ percent
+ }
+
+ motorInstance.setControl(request.withOutput(output))
+ }
+
+ private fun setEncoderPosition(motor: Motor, position: Double) {
+ if (position >= Constants.Climber.maximumPosition) {
+ val increasedLimit = SoftwareLimitSwitchConfigs()
+ .withForwardSoftLimitThreshold(position)
+ .withReverseSoftLimitThreshold(Constants.Climber.minimumPosition)
+ .withForwardSoftLimitEnable(true)
+ .withReverseSoftLimitEnable(true)
+
+ when (motor) {
+ Motor.LEFT -> leftMotor.configurator.apply(increasedLimit)
+ Motor.RIGHT -> rightMotor.configurator.apply(increasedLimit)
+ }
+ }
+
+ when (motor) {
+ Motor.LEFT -> leftMotor.setPosition(position)
+ Motor.RIGHT -> rightMotor.setPosition(position)
+ }
+ }
+
+ private fun disableSoftLimits() {
+ val disableLimits = SoftwareLimitSwitchConfigs()
+ .withForwardSoftLimitEnable(false)
+ .withReverseSoftLimitEnable(false)
+
+ leftMotor.configurator.apply(disableLimits)
+ rightMotor.configurator.apply(disableLimits)
+ }
+
+ fun setClimberToMaxPositions() : Command {
+ val command = InstantCommand({
+ setEncoderPosition(Motor.LEFT, Constants.Climber.theoreticalMax)
+ setEncoderPosition(Motor.RIGHT, Constants.Climber.theoreticalMax)
+ }, this)
+
+ command.name = "Set Climber to Max Positions"
+
+ return command
+ }
+
+ fun setDisableSoftLimits() : Command {
+ val command = InstantCommand({
+ disableSoftLimits()
+ }, this)
+
+ command.name = "Disable Soft Limits"
+
+ return command
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/subsystems/foldouts/IntakeFoldout.kt b/src/main/java/frc/robot/subsystems/foldouts/IntakeFoldout.kt
new file mode 100644
index 0000000..5b76f59
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/foldouts/IntakeFoldout.kt
@@ -0,0 +1,279 @@
+package frc.robot.subsystems.foldouts
+
+import com.ctre.phoenix6.Utils
+import com.revrobotics.*
+import com.revrobotics.CANSparkBase.ControlType
+import edu.wpi.first.math.controller.PIDController
+import edu.wpi.first.wpilibj.DigitalInput
+import edu.wpi.first.wpilibj.DutyCycleEncoder
+import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d
+import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard
+import edu.wpi.first.wpilibj.util.Color
+import edu.wpi.first.wpilibj.util.Color8Bit
+import edu.wpi.first.wpilibj2.command.Command
+import edu.wpi.first.wpilibj2.command.InstantCommand
+import edu.wpi.first.wpilibj2.command.SubsystemBase
+import frc.robot.Constants
+import frc.robot.Tools
+import frc.robot.subsystems.light.Neopixels
+import mu.KotlinLogging
+import kotlin.math.abs
+
+/**
+ * Subsystem for controlling the intake foldout (its motor and states).
+ * It uses a SparkMAX motor controller with a relative encoder and closed loop control.
+ */
+class IntakeFoldout : SubsystemBase() {
+ private val logger = KotlinLogging.logger("IntakeFoldout")
+ private val motor = CANSparkMax(Constants.IntakeFoldout.canID, CANSparkLowLevel.MotorType.kBrushless)
+ private val controller: SparkPIDController = motor.getPIDController()
+
+ private val encoder: RelativeEncoder = motor.encoder
+ private val throughBoreEncoder = DutyCycleEncoder(Constants.IntakeFoldout.encoderPort)
+
+ private val forwardLimitSensor = DigitalInput(Constants.IntakeFoldout.forwardLimitSensorPort)
+
+
+ private var targetRotations =
+ 0.0 // Updates with the selectedState, easier than checking the hashmap constantly and easy publishing too
+ private var selectedState: Constants.IntakeFoldout.FoldoutState = Constants.IntakeFoldout.FoldoutState.IDLE
+
+ private var simulationLoop: PIDController? = null
+ private var virtualEncoder: Double? = null
+
+ // TODO: Add Constants for the positions
+ private val mechanismCanvas = Mechanism2d(2.0, 2.0)
+ private val mechanism = mechanismCanvas.getRoot("IntakeFoldout", 0.63, 0.25)
+ private val pivot = mechanism.append(MechanismLigament2d("intake", 0.34, 0.0, 6.0, Color8Bit(Color.kBlue)))
+
+ /**
+ * Initializes the intake foldout, setting up the PID controller and starting the simulation loop if in simulation mode.
+ */
+ init {
+ motor.restoreFactoryDefaults()
+ //encoder.position = 0.0
+
+ motor.enableVoltageCompensation(12.0)
+ motor.setSmartCurrentLimit(30)
+ motor.setIdleMode(CANSparkBase.IdleMode.kCoast) // Just for right now TODO: Change if acting icky
+
+ controller.setP(Constants.IntakeFoldout.Control.kP)
+ controller.setI(Constants.IntakeFoldout.Control.kI)
+ controller.setD(Constants.IntakeFoldout.Control.kD)
+ controller.setIZone(Constants.IntakeFoldout.Control.kIz)
+ controller.setFF(Constants.IntakeFoldout.Control.kFF)
+
+ controller.setSmartMotionMaxAccel(Constants.IntakeFoldout.Control.Profile.maxAcceleration, 0)
+ controller.setSmartMotionMaxVelocity(Constants.IntakeFoldout.Control.Profile.maxVelocity, 0)
+ controller.setSmartMotionAllowedClosedLoopError(1.0, 0)
+
+ motor.inverted = Constants.IntakeFoldout.inverted
+
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus0, 50)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus1, 20)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus2, 20)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus3, 100)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus4, 1000)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus5, 1000)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus6, 1000)
+
+
+ if (Utils.isSimulation()) {
+ SmartDashboard.putNumber("IntakeFoldout/kP", Constants.IntakeFoldout.SimDummyControl.kP)
+ SmartDashboard.putNumber("IntakeFoldout/kI", Constants.IntakeFoldout.SimDummyControl.kI)
+ SmartDashboard.putNumber("IntakeFoldout/kD", Constants.IntakeFoldout.SimDummyControl.kD)
+ SmartDashboard.putNumber("IntakeFoldout/kIZ", Constants.IntakeFoldout.SimDummyControl.kIz)
+ SmartDashboard.putNumber("IntakeFoldout/kFF", Constants.IntakeFoldout.SimDummyControl.kFF)
+
+ simulationLoop = PIDController(
+ Constants.IntakeFoldout.SimDummyControl.kP,
+ Constants.IntakeFoldout.SimDummyControl.kI,
+ Constants.IntakeFoldout.SimDummyControl.kD
+ )
+ virtualEncoder = 0.0
+ } else {
+ SmartDashboard.putNumber("IntakeFoldout/kP", Constants.IntakeFoldout.Control.kP)
+ SmartDashboard.putNumber("IntakeFoldout/kI", Constants.IntakeFoldout.Control.kI)
+ SmartDashboard.putNumber("IntakeFoldout/kD", Constants.IntakeFoldout.Control.kD)
+ SmartDashboard.putNumber("IntakeFoldout/kIZ", Constants.IntakeFoldout.Control.kIz)
+ SmartDashboard.putNumber("IntakeFoldout/kFF", Constants.IntakeFoldout.Control.kFF)
+ }
+
+ if (Constants.isDebug) {
+ logger.warn { "In Debug Mode, Controller Unlocked" }
+ }
+
+ motor.burnFlash()
+ }
+
+ /**
+ * Updates the mechanism's rotation based on the given rotations.
+ *
+ * @param rotations The rotations to set the mechanism to.
+ */
+ private fun updateMechanism(rotations : Double) {
+ pivot.setAngle(abs(rotations * Constants.IntakeFoldout.gearRatio * 360) + Constants.IntakeFoldout.offset)
+ }
+
+ /**
+ * Updates the PID loops based on the values from the SmartDashboard.
+ */
+ private fun updateLoops() {
+ val p = SmartDashboard.getNumber("IntakeFoldout/kP", Constants.IntakeFoldout.Control.kP)
+ val i = SmartDashboard.getNumber("IntakeFoldout/kI", Constants.IntakeFoldout.Control.kI)
+ val d = SmartDashboard.getNumber("IntakeFoldout/kD", Constants.IntakeFoldout.Control.kD)
+ val iz = SmartDashboard.getNumber("IntakeFoldout/kIZ", Constants.IntakeFoldout.Control.kIz)
+ val ff = SmartDashboard.getNumber("IntakeFoldout/kFF", Constants.IntakeFoldout.Control.kFF)
+
+ if (p != Constants.IntakeFoldout.Control.kP) controller.setP(p)
+ if (i != Constants.IntakeFoldout.Control.kI) controller.setI(i)
+ if (d != Constants.IntakeFoldout.Control.kD) controller.setD(d)
+ if (iz != Constants.IntakeFoldout.Control.kIz) controller.setIZone(iz)
+ if (ff != Constants.IntakeFoldout.Control.kFF) controller.setFF(ff)
+ }
+
+ private fun updateSimLoops() {
+ val p = SmartDashboard.getNumber("IntakeFoldout/kP", Constants.IntakeFoldout.SimDummyControl.kP)
+ val i = SmartDashboard.getNumber("IntakeFoldout/kI", Constants.IntakeFoldout.SimDummyControl.kI)
+ val d = SmartDashboard.getNumber("IntakeFoldout/kD", Constants.IntakeFoldout.SimDummyControl.kD)
+
+ if (p != Constants.IntakeFoldout.SimDummyControl.kP) simulationLoop?.p = p
+ if (i != Constants.IntakeFoldout.SimDummyControl.kI) simulationLoop?.i = i
+ if (d != Constants.IntakeFoldout.SimDummyControl.kD) simulationLoop?.d = d
+ }
+
+ /**
+ * Periodically updates the intake foldout, setting the reference voltage based on the selected state.
+ */
+ override fun periodic() {
+ Tools.provideMotorDetails(motor, "IntakeFoldout")
+
+ if (Constants.isDebug && !Utils.isSimulation()) {
+ updateLoops() // PID Can be on the fly updated if on debug with SmartDashboard
+ }
+
+ // Update the reference angle from degrees to rotations
+ targetRotations = (
+ ((1 / Constants.IntakeFoldout.gearRatio) * ((Constants.IntakeFoldout.positions[selectedState] ?: 0.0) / 360)) - Constants.IntakeFoldout.offset / 360 / Constants.IntakeFoldout.gearRatio)
+
+ // Set the motor to the reference angle
+ // TODO: Set the motor to cancel when break is pressed
+ val controllerSuccess = controller.setReference(
+ targetRotations,
+ ControlType.kSmartMotion
+ ) // TODO: Make certain modes coast when loop is done
+
+ SmartDashboard.putNumber("IntakeFoldout/Rev Error ID", controllerSuccess.value.toDouble())
+ SmartDashboard.putString("IntakeFoldout/Rev Error Message", controllerSuccess.name)
+
+ SmartDashboard.putString("IntakeFoldout/State", selectedState.toString())
+ SmartDashboard.putNumber("IntakeFoldout/Setpoint", targetRotations)
+
+ SmartDashboard.putBoolean("IntakeFoldout/forwardLimitReached", !forwardLimitSensor.get())
+
+ if (virtualEncoder != null) {
+ SmartDashboard.putNumber("IntakeFoldout/Encoder", virtualEncoder!!)
+ updateMechanism(virtualEncoder!!)
+ }
+ else {
+ SmartDashboard.putNumber("IntakeFoldout/Encoder", encoder.position)
+ SmartDashboard.putNumber("IntakeFoldout/Through Bore Encoder", dutyCycleEncoder.toDouble())
+ SmartDashboard.putNumber("IntakeFoldout/Velocity", encoder.velocity)
+ updateMechanism(encoder.position)
+ }
+
+ SmartDashboard.putData("IntakeFoldout/Mechanism", mechanismCanvas)
+ }
+
+ /**
+ * Periodically updates the intake foldout in simulation mode, using a PID controller to calculate the virtual encoder value.
+ */
+ override fun simulationPeriodic() {
+ // REVLib sucks and doesn't have proper simulation support, this is all really basic tho
+
+ virtualEncoder?.let {
+ val changed = simulationLoop?.calculate(it, targetRotations)
+ virtualEncoder = virtualEncoder!! + changed!!
+ SmartDashboard.putNumber("IntakeFoldout/Sim Loop Velocity", changed*20*60)
+
+ if (Constants.isDebug) {
+ updateSimLoops()
+ }
+ }
+ }
+
+ /**
+ * Sets the state of the intake foldout.
+ *
+ * @param state The desired state of the intake foldout.
+ */
+ fun setState(state: Constants.IntakeFoldout.FoldoutState) {
+ selectedState = state
+ }
+
+ /**
+ * Checks if the intake foldout is close to the target angle.
+ *
+ * @param target The target angle to check against.
+ * @return True if the intake foldout is close to the target angle, false otherwise.
+ */
+ fun isClose(target : Double) : Boolean {
+ return if (!Utils.isSimulation()) abs(encoder.position - target) < Constants.IntakeFoldout.completedLoop
+ else {
+ abs(virtualEncoder!! - target) < Constants.IntakeFoldout.completedLoop
+ }
+ }
+
+ fun isClose(target: Double, tolerance: Double) : Boolean {
+ return if (!Utils.isSimulation()) abs(encoder.position - target) < tolerance
+ else {
+ abs(virtualEncoder!! - target) < tolerance
+ }
+ }
+
+ /**
+ * Checks if the intake foldout is close to the target state.
+ *
+ * @param state The target state to check against.
+ * @return True if the intake foldout is close to the target state, false otherwise.
+ */
+ fun isCloseToState(state: Constants.IntakeFoldout.FoldoutState) : Boolean {
+ return isClose((1 / Constants.IntakeFoldout.gearRatio) * ((Constants.IntakeFoldout.positions[state] ?: 0.0) / 360))
+ }
+
+ fun isCloseToState(state: Constants.IntakeFoldout.FoldoutState, tolerance: Double) : Boolean {
+ return isClose((1 / Constants.IntakeFoldout.gearRatio) * ((Constants.IntakeFoldout.positions[state] ?: 0.0) / 360), tolerance)
+ }
+
+ fun givenAngleSetState(angle : Double) {
+ if (angle > Constants.IntakeFoldout.neededPositionChanges[Constants.IntakeFoldout.FoldoutState.SHOOT_HIGH]!!) {
+ setState(Constants.IntakeFoldout.FoldoutState.SHOOT_HIGH)
+ } else if (angle > Constants.IntakeFoldout.neededPositionChanges[Constants.IntakeFoldout.FoldoutState.SHOOT_MID]!!) {
+ setState(Constants.IntakeFoldout.FoldoutState.SHOOT_MID)
+ } else {
+ setState(Constants.IntakeFoldout.FoldoutState.SHOOT_LOW)
+ }
+ }
+
+ fun zeroEncoder(): Command {
+ val command = InstantCommand({
+ encoder.position = 0.0
+
+ if (Utils.isSimulation()) {
+ virtualEncoder = 0.0
+ }
+ }, this).ignoringDisable(true)
+
+ command.name = "Zero IntakeFoldout Encoder"
+
+ return command
+ }
+
+ private val dutyCycleEncoder : Float
+ get() = throughBoreEncoder.absolutePosition.toFloat()
+
+ fun mirrorEncoder() : InstantCommand {
+ return InstantCommand({})
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/subsystems/light/CameraLEDs.kt b/src/main/java/frc/robot/subsystems/light/CameraLEDs.kt
new file mode 100644
index 0000000..219ce0b
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/light/CameraLEDs.kt
@@ -0,0 +1,44 @@
+package frc.robot.subsystems.light
+
+import edu.wpi.first.wpilibj2.command.SubsystemBase
+import edu.wpi.first.wpilibj.SerialPort
+import frc.lib.light.LightActions
+import frc.robot.Constants
+import mu.KotlinLogging
+
+class CameraLEDs() {
+ private val logger = KotlinLogging.logger("VisionLEDs")
+ private var connected = true;
+
+ val serialPort = try { SerialPort(9600, SerialPort.Port.kUSB) } catch (e: Exception) { connected = false; null }
+
+ init {
+ if (Constants.Indicators.enableCameraLED) {
+ if (connected) { // TODO: Add interactive error codes and blink codes
+ logger.info { "Camera LEDs connected" }
+ setAction(LightActions.IDLE)
+ }
+ else {
+ logger.warn { "Camera LEDs not connected" }
+ }
+ } else {
+ logger.info { "Camera LEDs disabled" }
+ }
+ }
+
+ fun setAction(action: LightActions) {
+ if (connected) {
+ serialPort!!.writeString(action.toString())
+ }
+ }
+
+ private fun sendString(string: String) {
+ if (connected) {
+ serialPort!!.writeString(string)
+
+ serialPort.flush()
+
+ serialPort.readString()
+ }
+ }
+}
diff --git a/src/main/java/frc/robot/subsystems/light/Neopixels.kt b/src/main/java/frc/robot/subsystems/light/Neopixels.kt
new file mode 100644
index 0000000..5948ce8
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/light/Neopixels.kt
@@ -0,0 +1,82 @@
+package frc.robot.subsystems.light
+
+import edu.wpi.first.wpilibj2.command.SubsystemBase
+import edu.wpi.first.wpilibj.AddressableLED
+import edu.wpi.first.wpilibj.AddressableLEDBuffer
+import frc.lib.light.NeopixelAnimations
+import frc.robot.Constants
+import frc.lib.light.NeopixelSection
+
+import mu.KotlinLogging
+
+class Neopixels : SubsystemBase() {
+ private val logger = KotlinLogging.logger("Neopixels")
+ private var sections : Array = Constants.Indicators.Neopixels.sections
+ private var buffer: AddressableLEDBuffer = AddressableLEDBuffer(Constants.Indicators.Neopixels.numLEDs)
+ private var led : AddressableLED = AddressableLED(Constants.Indicators.Neopixels.neopixelPort)
+
+ private var relativeTick : Int = 0 // Used for animations, goes up to 500 then resets to 0
+ private var started : Boolean = false
+
+ var chainBlinking = false
+
+ init {
+ logger.info { "Neopixels initialized" }
+
+ start()
+ }
+
+ private fun start() {
+ if (Constants.Indicators.Neopixels.enabled) {
+ logger.info { "Neopixels enabled" }
+ started = true
+ led.setLength(Constants.Indicators.Neopixels.numLEDs)
+ led.start()
+
+ updateState(Constants.Indicators.Neopixels.NeopixelStates.IDLE)
+ } else {
+ logger.info { "Neopixels disabled" }
+ }
+ }
+
+ override fun periodic() {
+ if (!started) return // If not started then don't do anything
+
+ if (chainBlinking) {
+ if (relativeTick % 10 > 5) {
+ val tempBuffer = AddressableLEDBuffer(Constants.Indicators.Neopixels.numLEDs)
+ for (i in 0 until Constants.Indicators.Neopixels.numLEDs) {
+ tempBuffer.setRGB(i, 200, 200, 200)
+ }
+ if (relativeTick % 2 == 0) led.setData(tempBuffer)
+ } else {
+ if (relativeTick % 2 == 0) publishBuffer()
+ }
+ } else {
+ if (relativeTick % 2 == 0) publishBuffer()
+ }
+
+ relativeTick = (relativeTick + 1) % 161
+ }
+
+ private fun publishBuffer() {
+ led.setData(buffer)
+ }
+
+ fun updateState(state : Constants.Indicators.Neopixels.NeopixelStates) {
+ for (section in sections) {
+ setSection(section, state)
+ }
+ }
+
+ private fun setSection(section: NeopixelSection, cState: Constants.Indicators.Neopixels.NeopixelStates) {
+ if (section.desiredState[cState] == null) return // If the desired state is null then don't do anything
+ for (i in section.start..section.end) {
+ buffer.setRGB(i,
+ (section.desiredState[cState]!!.red * .7).toInt(),
+ (section.desiredState[cState]!!.green * .7).toInt(),
+ (section.desiredState[cState]!!.blue * .7).toInt()
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/subsystems/rotation/IntakeRollers.kt b/src/main/java/frc/robot/subsystems/rotation/IntakeRollers.kt
new file mode 100644
index 0000000..c279942
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/rotation/IntakeRollers.kt
@@ -0,0 +1,113 @@
+package frc.robot.subsystems.rotation
+
+import com.ctre.phoenix6.Utils
+import com.revrobotics.CANSparkBase.ControlType
+import com.revrobotics.CANSparkLowLevel
+import com.revrobotics.CANSparkMax
+import edu.wpi.first.math.controller.PIDController
+import edu.wpi.first.wpilibj.DigitalInput
+import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard
+import edu.wpi.first.wpilibj2.command.SubsystemBase
+import frc.robot.Constants
+import frc.robot.Tools
+import mu.KotlinLogging
+
+/**
+ * Class for controlling the intake rollers of the robot.
+ */
+class IntakeRollers : SubsystemBase() {
+ private val logger = KotlinLogging.logger("IntakeRollers")
+ private val motor = CANSparkMax(Constants.IntakeRollers.canID, CANSparkLowLevel.MotorType.kBrushless)
+ private val controller = motor.pidController
+ private var selectedState = Constants.IntakeRollers.Speed.NEUTRAL
+
+ private val beamBreak = DigitalInput(Constants.IntakeRollers.beamBreakID)
+
+ private var simulationLoop: PIDController? = null
+ private var virtualEncoder: Double? = null
+
+ /**
+ * Initializes the intake rollers, setting up the PID controller and starting the simulation loop if in simulation mode.
+ */
+ init {
+ motor.restoreFactoryDefaults()
+
+ motor.setSmartCurrentLimit(20)
+ motor.enableVoltageCompensation(12.0)
+
+ controller.setP(Constants.IntakeRollers.Control.kP)
+ controller.setI(Constants.IntakeRollers.Control.kI)
+ controller.setD(Constants.IntakeRollers.Control.kD)
+ controller.setIZone(Constants.IntakeRollers.Control.kIz)
+ controller.setFF(Constants.IntakeRollers.Control.kFF)
+ controller.setOutputRange(
+ Constants.IntakeRollers.Control.kMinOutput,
+ Constants.IntakeRollers.Control.kMaxOutput
+ )
+
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus0, 50)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus1, 50)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus2, 20)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus3, 500)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus4, 1000)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus5, 1000)
+ motor.setPeriodicFramePeriod(CANSparkLowLevel.PeriodicFrame.kStatus6, 1000)
+
+ /* There's gonna be no on the fly tuning support cause it's not rlly needed */
+
+ if (Utils.isSimulation()) {
+ simulationLoop = PIDController(
+ Constants.IntakeRollers.Control.kP,
+ Constants.IntakeRollers.Control.kI,
+ Constants.IntakeRollers.Control.kD
+ )
+ virtualEncoder = 0.0
+ }
+ }
+
+ /**
+ * Sets the state of the intake rollers.
+ *
+ * @param state The desired state of the intake rollers.
+ */
+ fun setState(state: Constants.IntakeRollers.Speed) {
+ selectedState = state
+ }
+
+ /**
+ * Checks if the beam break sensor is broken.
+ *
+ * @return True if the beam break sensor is broken, false otherwise.
+ */
+ fun isBroken() = !beamBreak.get()
+
+ /**
+ * Periodically updates the intake rollers, setting the reference voltage based on the selected state.
+ */
+ override fun periodic() {
+ Tools.provideMotorDetails(motor, "IntakeRollers")
+
+ Constants.IntakeRollers.speeds[selectedState]?.let {
+ controller.setReference(
+ (it / 100) * 12,
+ ControlType.kVoltage
+ )
+ }
+
+ if (virtualEncoder != null) SmartDashboard.putNumber("IntakeRollers/Encoder", virtualEncoder!!) else SmartDashboard.putNumber("IntakeRollers/Encoder", motor.encoder.velocity)
+ SmartDashboard.putString("IntakeRollers/State", selectedState.name)
+ SmartDashboard.putBoolean("IntakeRollers/Sensor", isBroken())
+ }
+
+ /**
+ * Periodically updates the intake rollers in simulation mode, using a PID controller to calculate the virtual encoder value.
+ */
+ override fun simulationPeriodic() {
+ simulationLoop?.let {
+ Constants.IntakeRollers.speeds[selectedState]?.let { speed ->
+ virtualEncoder = virtualEncoder!! + it.calculate(virtualEncoder!!, (speed / 100) * 12)
+ SmartDashboard.putNumber("IntakeRollers/Sim Loop Velocity", (virtualEncoder!! / 12) * 5400)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/frc/robot/subsystems/vision/PhotonVision.kt b/src/main/java/frc/robot/subsystems/vision/PhotonVision.kt
new file mode 100644
index 0000000..e3f3984
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/vision/PhotonVision.kt
@@ -0,0 +1,96 @@
+package frc.robot.subsystems.vision
+
+import edu.wpi.first.wpilibj2.command.SubsystemBase
+import edu.wpi.first.apriltag.AprilTagFieldLayout
+import edu.wpi.first.apriltag.AprilTagFields
+import edu.wpi.first.math.geometry.Rotation2d
+import org.photonvision.simulation.VisionSystemSim
+import org.photonvision.simulation.SimCameraProperties
+import org.photonvision.simulation.PhotonCameraSim
+import org.photonvision.PhotonCamera
+import com.ctre.phoenix6.Utils
+import edu.wpi.first.wpilibj.DriverStation.Alliance
+import frc.robot.Constants
+import frc.robot.Telemetry
+import org.photonvision.targeting.PNPResult
+
+/**
+ * Main vision system of the robot.
+ * Packages simulator and real robot vision into one interface.
+ */
+class PhotonVision(private val telemetry : Telemetry) : SubsystemBase() {
+ /**
+ * The layout of the AprilTag field.
+ */
+ private val tagLayout: AprilTagFieldLayout = AprilTagFieldLayout.loadFromResource(AprilTagFields.k2024Crescendo.m_resourceFile)
+
+ /**
+ * The left camera used by the PhotonVision system.
+ * This is initialized with the name specified in the Constants.Vision.LeftCamera.name.
+ */
+ private val leftCamera = PhotonCamera(Constants.Vision.LeftCamera.name)
+
+ /**
+ * The right camera used by the PhotonVision system.
+ * This is initialized with the name specified in the Constants.Vision.RightCamera.name.
+ */
+ private val rightCamera = PhotonCamera(Constants.Vision.RightCamera.name)
+
+ /* Simulation properties */
+ private var visionSim: VisionSystemSim? = null
+ private var cameraSimProp: SimCameraProperties? = null
+ private var leftCameraSim: PhotonCameraSim? = null
+ private var rightCameraSim: PhotonCameraSim? = null
+
+ init {
+ if (Utils.isSimulation() && Constants.Vision.enable) {
+ setupSimulation()
+ }
+ }
+
+ /**
+ * Retrieves the latest pose estimation results from both the left and right cameras.
+ *
+ * @return A pair of PNPResult objects, where the first element is the result from the left camera and the second element is the result from the right camera.
+ */
+ fun getCameraResults() : Pair {
+ return Pair(
+ leftCamera.latestResult.multiTagResult.estimatedPose,
+ rightCamera.latestResult.multiTagResult.estimatedPose
+ )
+ }
+
+ /**
+ * Sets up the simulation.
+ */
+ private fun setupSimulation() {
+ visionSim = VisionSystemSim("photonvision")
+ visionSim?.addAprilTags(tagLayout)
+
+ cameraSimProp = SimCameraProperties().apply {
+ setCalibration(Constants.Simulation.Camera.width, Constants.Simulation.Camera.height, Rotation2d.fromDegrees(Constants.Simulation.Camera.fov.toDouble()))
+ setCalibError(Constants.Simulation.Camera.averageNoise, Constants.Simulation.Camera.deviatedNoise)
+ fps = Constants.Simulation.Camera.fps.toDouble()
+ avgLatencyMs = Constants.Simulation.Camera.averageLatency.toDouble()
+ latencyStdDevMs = Constants.Simulation.Camera.standardDevLatency.toDouble()
+ }
+
+ leftCameraSim = PhotonCameraSim(leftCamera, cameraSimProp)
+ rightCameraSim = PhotonCameraSim(rightCamera, cameraSimProp)
+
+ visionSim?.addCamera(leftCameraSim, Constants.Vision.LeftCamera.robotToCamera)
+ visionSim?.addCamera(rightCameraSim, Constants.Vision.RightCamera.robotToCamera)
+
+ visionSim?.debugField
+
+ leftCameraSim?.enableDrawWireframe(true)
+ rightCameraSim?.enableDrawWireframe(true)
+ }
+
+ /**
+ * Updates the simulation periodically.
+ */
+ override fun simulationPeriodic() {
+ visionSim?.update(telemetry.position) // When disabled and in the simulation, Kotlin's null safety will prevent this from running
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
new file mode 100644
index 0000000..a57cb9b
--- /dev/null
+++ b/src/main/resources/logback.xml
@@ -0,0 +1,11 @@
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} MDC=%X{user} - %msg%n
+
+
+
+
+
+
+
diff --git a/vendordeps/PathplannerLib.json b/vendordeps/PathplannerLib.json
new file mode 100644
index 0000000..6dc648d
--- /dev/null
+++ b/vendordeps/PathplannerLib.json
@@ -0,0 +1,38 @@
+{
+ "fileName": "PathplannerLib.json",
+ "name": "PathplannerLib",
+ "version": "2024.2.8",
+ "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.2.8"
+ }
+ ],
+ "jniDependencies": [],
+ "cppDependencies": [
+ {
+ "groupId": "com.pathplanner.lib",
+ "artifactId": "PathplannerLib-cpp",
+ "version": "2024.2.8",
+ "libName": "PathplannerLib",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal",
+ "linuxathena",
+ "linuxarm32",
+ "linuxarm64"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/vendordeps/Phoenix6.json b/vendordeps/Phoenix6.json
new file mode 100644
index 0000000..2b7d172
--- /dev/null
+++ b/vendordeps/Phoenix6.json
@@ -0,0 +1,339 @@
+{
+ "fileName": "Phoenix6.json",
+ "name": "CTRE-Phoenix (v6)",
+ "version": "24.2.0",
+ "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-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.2.0"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "tools",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "linuxathena"
+ ],
+ "simMode": "hwsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "tools-sim",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonSRX",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simTalonFX",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simVictorSPX",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simCANCoder",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProTalonFX",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProCANcoder",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ },
+ {
+ "groupId": "com.ctre.phoenix6.sim",
+ "artifactId": "simProPigeon2",
+ "version": "24.2.0",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.ctre.phoenix6",
+ "artifactId": "wpiapi-cpp",
+ "version": "24.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "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.2.0",
+ "libName": "CTRE_SimProPigeon2",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxuniversal"
+ ],
+ "simMode": "swsim"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/vendordeps/REVLib.json b/vendordeps/REVLib.json
new file mode 100644
index 0000000..f85acd4
--- /dev/null
+++ b/vendordeps/REVLib.json
@@ -0,0 +1,74 @@
+{
+ "fileName": "REVLib.json",
+ "name": "REVLib",
+ "version": "2024.2.4",
+ "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.2.4"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-driver",
+ "version": "2024.2.4",
+ "skipInvalidPlatforms": true,
+ "isJar": false,
+ "validPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxarm64",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxarm32",
+ "osxuniversal"
+ ]
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-cpp",
+ "version": "2024.2.4",
+ "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.2.4",
+ "libName": "REVLibDriver",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxarm64",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxarm32",
+ "osxuniversal"
+ ]
+ }
+ ]
+}
\ No newline at end of file
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"
+ ]
+ }
+ ]
+}
diff --git a/vendordeps/photonlib.json b/vendordeps/photonlib.json
new file mode 100644
index 0000000..0e80a16
--- /dev/null
+++ b/vendordeps/photonlib.json
@@ -0,0 +1,57 @@
+{
+ "fileName": "photonlib.json",
+ "name": "photonlib",
+ "version": "v2024.3.1",
+ "uuid": "515fe07e-bfc6-11fa-b3de-0242ac130004",
+ "frcYear": "2024",
+ "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": [],
+ "cppDependencies": [
+ {
+ "groupId": "org.photonvision",
+ "artifactId": "photonlib-cpp",
+ "version": "v2024.3.1",
+ "libName": "photonlib",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxathena",
+ "linuxx86-64",
+ "osxuniversal"
+ ]
+ },
+ {
+ "groupId": "org.photonvision",
+ "artifactId": "photontargeting-cpp",
+ "version": "v2024.3.1",
+ "libName": "photontargeting",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxathena",
+ "linuxx86-64",
+ "osxuniversal"
+ ]
+ }
+ ],
+ "javaDependencies": [
+ {
+ "groupId": "org.photonvision",
+ "artifactId": "photonlib-java",
+ "version": "v2024.3.1"
+ },
+ {
+ "groupId": "org.photonvision",
+ "artifactId": "photontargeting-java",
+ "version": "v2024.3.1"
+ }
+ ]
+}
\ No newline at end of file