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