--- /dev/null
+*.gradle text eol=lf
+*.java text eol=lf
+*.md text eol=lf
+*.xml text eol=lf
--- /dev/null
+<!--
+PLEASE CHECK THE PR GUIDLINES:
+ https://docs.google.com/document/d/14ZIhQRlUPK0wl5_AmM80N2D2KJUd6k_7I6isLS89YKU/edit
+These are the things we are going to be checking your PR has, if it doesn't your PR will be rejected!
+-->
+
+## Overview
+<!-- A general very short overview of the PR -->
+This PR will..
+
+
+## Design Doc
+<!-- Link your approved design doc. We will be checking that the code fits everything in the design doc. If the PR is only meant to address part of the deisgn doc, note here what is not yet implemented from the Design Doc -->
+
+
+## Tests Ran
+<!-- Explicity list the exact tests you ran. These should be the tests listed in the Testing and Evaluation section of your design doc, and of every merged design doc. List the actual result of the test and how it was within the measurement specified by the test. -->
+
+
+## Additional Notes
+<!-- Anything else that will help the reviewer understand your PR -->
--- /dev/null
+# This is a basic workflow to build robot code. credit: WPI
+
+name: CI
+
+# Controls when the action will run. Triggers the workflow on push or pull request
+# events but only for the main branch.
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+ # This workflow contains a single job called "build"
+ build:
+ # The type of runner that the job will run on
+ runs-on: ubuntu-latest
+
+ # This grabs the WPILib docker container
+ container: wpilib/roborio-cross-ubuntu:2022-18.04
+
+ # Steps represent a sequence of tasks that will be executed as part of the job
+ steps:
+ # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
+ - uses: actions/checkout@v2
+
+ # Grant execute permission for gradlew
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+
+ # Runs a single command using the runners shell
+ - name: Compile and run tests on robot code
+ run: ./gradlew build
--- /dev/null
+# 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/
+
+# Simulation GUI and other tools window save file
+*-window.json
+
+# File that has git and version data
+src/main/java/frc/robot/util/BuildData.java
\ No newline at end of file
--- /dev/null
+{
+ // 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,
+ }
+ ]
+}
--- /dev/null
+{
+ "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"
+}
--- /dev/null
+{
+ "enableCppIntellisense": false,
+ "currentLanguage": "java",
+ "projectYear": "2022",
+ "teamNumber": 972
+}
\ No newline at end of file
--- /dev/null
+# Code-Structure-2023
+
+[](https://github.com/iron-claw-972/Code-Structure-2023/actions/workflows/main.yml)
+
+
+Code Structure for our future 2023 repository.
--- /dev/null
+Copyright (c) 2009-2021 FIRST and other WPILib contributors
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of FIRST, WPILib, nor the names of other WPILib
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
+PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+import edu.wpi.first.gradlerio.deploy.roborio.RoboRIO
+
+plugins {
+ id "java"
+ id "edu.wpi.first.GradleRIO" version "2022.4.1"
+ id "com.peterabeles.gversion" version "1.10"
+}
+
+sourceCompatibility = JavaVersion.VERSION_11
+targetCompatibility = JavaVersion.VERSION_11
+
+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')) {
+ // 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 4.
+dependencies {
+ implementation wpi.java.deps.wpilib()
+ implementation wpi.java.vendor.java()
+
+ roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio)
+ roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio)
+
+ roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio)
+ roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio)
+
+ nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
+ nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
+ simulationDebug wpi.sim.enableDebug()
+
+ nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop)
+ nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
+ simulationRelease wpi.sim.enableRelease()
+}
+
+// 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) } }
+ 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)
+
+project.compileJava.dependsOn(createVersionFile)
+gversion {
+ srcDir = "src/main/java/"
+ classPackage = "frc.robot.util"
+ className = "BuildData"
+ dateFormat = "yyyy-MM-dd HH:mm:ss z"
+ timeZone = "PST"
+ indent = " "
+}
\ No newline at end of file
--- /dev/null
+distributionBase=GRADLE_USER_HOME
+distributionPath=permwrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=permwrapper/dists
--- /dev/null
+#!/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/master/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
+
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+APP_NAME="Gradle"
+APP_BASE_NAME=${0##*/}
+
+# 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"'
+
+# 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
+ which java >/dev/null 2>&1 || 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
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ 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
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# 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" "$@"
--- /dev/null
+@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=.
+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%" == "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%"=="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!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
--- /dev/null
+import org.gradle.internal.os.OperatingSystem
+
+pluginManagement {
+ repositories {
+ mavenLocal()
+ gradlePluginPortal()
+ String frcYear = '2022'
+ 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
+ }
+ }
+}
--- /dev/null
+Files placed in this directory will be deployed to the RoboRIO into the
+'deploy' directory in the home folder. Use the 'Filesystem.getDeployDirectory' wpilib function
+to get a proper path relative to the deploy directory.
\ No newline at end of file
--- /dev/null
+{
+ "waypoints": [
+ {
+ "anchorPoint": {
+ "x": 1.0,
+ "y": 3.0
+ },
+ "prevControl": null,
+ "nextControl": {
+ "x": 2.0,
+ "y": 3.0
+ },
+ "holonomicAngle": 0,
+ "isReversal": false,
+ "velOverride": null,
+ "isLocked": false,
+ "isStopPoint": false,
+ "stopEvent": {
+ "names": [],
+ "executionBehavior": "parallel",
+ "waitBehavior": "none",
+ "waitTime": 0
+ }
+ },
+ {
+ "anchorPoint": {
+ "x": 5.334010668021336,
+ "y": 5.955334987593052
+ },
+ "prevControl": {
+ "x": 5.334010668021336,
+ "y": 4.955334987593052
+ },
+ "nextControl": {
+ "x": 5.334010668021336,
+ "y": 4.955334987593052
+ },
+ "holonomicAngle": 0,
+ "isReversal": true,
+ "velOverride": null,
+ "isLocked": false,
+ "isStopPoint": false,
+ "stopEvent": {
+ "names": [],
+ "executionBehavior": "parallel",
+ "waitBehavior": "none",
+ "waitTime": 0
+ }
+ },
+ {
+ "anchorPoint": {
+ "x": 5.0,
+ "y": 3.0
+ },
+ "prevControl": {
+ "x": 4.0,
+ "y": 3.0
+ },
+ "nextControl": null,
+ "holonomicAngle": 0,
+ "isReversal": false,
+ "velOverride": null,
+ "isLocked": false,
+ "isStopPoint": false,
+ "stopEvent": {
+ "names": [],
+ "executionBehavior": "parallel",
+ "waitBehavior": "none",
+ "waitTime": 0
+ }
+ }
+ ],
+ "markers": []
+}
\ No newline at end of file
--- /dev/null
+// 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;
+
+/**
+ * Do NOT add any static variables to this class, or any initialization at all. Unless you know what
+ * you are doing, do not modify this file except to change the parameter class to the startRobot
+ * call.
+ */
+public final class Main {
+ private Main() {}
+
+ /**
+ * Main initialization function. Do not perform any initialization here.
+ *
+ * <p>If you change your main robot class, change the parameter type.
+ */
+ public static void main(String... args) {
+ RobotBase.startRobot(Robot::new);
+ }
+}
--- /dev/null
+// 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.DriverStation;
+import edu.wpi.first.wpilibj.TimedRobot;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.CommandScheduler;
+import frc.robot.controls.Driver;
+import frc.robot.controls.Operator;
+import frc.robot.subsystems.Drivetrain;
+import frc.robot.util.PathGroupLoader;
+import frc.robot.util.ShuffleboardManager;
+
+/**
+ * The VM is configured to automatically run this class, and to call the functions corresponding to
+ * each mode, as described in the TimedRobot documentation. If you change the name of this class or
+ * the package after creating this project, you must also update the build.gradle file in the
+ * project.
+ */
+public class Robot extends TimedRobot {
+ private Command m_autoCommand;
+ public static ShuffleboardManager shuffleboard;
+ public static Drivetrain drive;
+
+ private static boolean isTestMode = false;
+
+ /**
+ * This function is run when the robot is first started up and should be used for any
+ * initialization code.
+ */
+ @Override
+ public void robotInit() {
+
+ // This is really annoying so it's disabled
+ DriverStation.silenceJoystickConnectionWarning(true);
+
+ // load paths before auto starts
+ PathGroupLoader.loadPathGroups();
+
+ // make subsystems
+ shuffleboard = new ShuffleboardManager();
+ drive = new Drivetrain();
+
+ shuffleboard.setup();
+
+ Driver.configureControls();
+ Operator.configureControls();
+ }
+
+ /**
+ * This function is called every robot packet, no matter the mode. Use this for items like
+ * diagnostics that you want ran during disabled, autonomous, teleoperated and test.
+ *
+ * <p>This runs after the mode specific periodic functions, but before LiveWindow and
+ * SmartDashboard integrated updating.
+ */
+ @Override
+ public void robotPeriodic() {
+ // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled
+ // commands, running already-scheduled commands, removing finished or interrupted commands,
+ // and running subsystem periodic() methods. This must be called from the robot's periodic
+ // block in order for anything in the Command-based framework to work.
+ CommandScheduler.getInstance().run();
+ }
+
+ /** This function is called once each time the robot enters Disabled mode. */
+ @Override
+ public void disabledInit() {
+ CommandScheduler.getInstance().cancelAll();
+ isTestMode = false;
+ }
+
+ @Override
+ public void disabledPeriodic() {
+ m_autoCommand = getAutonomousCommand();
+ }
+
+ /** This autonomous runs the autonomous command selected by your {@link Robot} class. */
+ @Override
+ public void autonomousInit() {
+ isTestMode = false;
+ if (m_autoCommand != null) {
+ m_autoCommand.schedule();
+ }
+ }
+
+ /** This function is called periodically during autonomous. */
+ @Override
+ public void autonomousPeriodic() {}
+
+ @Override
+ public void teleopInit() {
+ // This makes sure that the autonomous stops running when
+ // teleop starts running. If you want the autonomous to
+ // continue until interrupted by another command, remove
+ // this line or comment it out.
+ if (m_autoCommand != null) {
+ m_autoCommand.cancel();
+ }
+ isTestMode = false;
+ }
+
+ /** This function is called periodically during operator control. */
+ @Override
+ public void teleopPeriodic() {}
+
+ @Override
+ public void testInit() {
+ // Cancels all running commands at the start of test mode.
+ CommandScheduler.getInstance().cancelAll();
+
+ // it may be needed to disable LiveWindow (we don't use it anyway)
+ //LiveWindow.setEnabled(false)
+
+ isTestMode = true;
+
+ }
+
+ /** This function is called periodically during test mode. */
+ @Override
+ public void testPeriodic() {}
+
+ /**
+ * Use this to pass the autonomous command to the main {@link Robot} class.
+ *
+ * @return the command to run in autonomous
+ */
+ public Command getAutonomousCommand() {
+ return shuffleboard.getAutonomousCommand();
+ }
+
+ public static boolean isTestMode() {
+ return isTestMode;
+ }
+}
--- /dev/null
+package frc.robot.commands;
+
+import edu.wpi.first.wpilibj2.command.InstantCommand;
+
+public class DoNothing extends InstantCommand {}
--- /dev/null
+package frc.robot.constants;
+
+public class AutoConstants {
+
+ // Pathplanner output folder should be src/main/deploy/pathplanner
+ public final String kTrajectoryDirectory = "pathplanner/";
+
+ public final double kMaxAutoSpeed = 1.0; // m/s
+ public final double kMaxAutoAccel = 1.0; // m/s^2
+}
--- /dev/null
+package frc.robot.constants;
+
+public final class Constants {
+ public static final double kGravitationalAccel = 9.8;
+ public static final double kMaxVoltage = 12.0;
+ public static final double kLoopTime = 0.02;
+
+ public static final double kCancoderResolution = 4096;
+
+ // CAN bus names
+ // public static final String kCanivoreCAN = ""; // replace this if using Canivore
+ public static final String kRioCAN = "rio";
+
+ public static final OIConstants oi = new OIConstants();
+ public static final DriveConstants drive = new DriveConstants();
+ public static final AutoConstants auto = new AutoConstants();
+ public static final FalconConstants falcon = new FalconConstants();
+}
--- /dev/null
+package frc.robot.constants;
+
+public class DriveConstants {
+
+ public final int kLeftMotor1 = -1;
+ public final int kLeftMotor2 = -1;
+ public final int kRightMotor1 = -1;
+ public final int kRightMotor2 = -1;
+}
--- /dev/null
+package frc.robot.constants;
+
+public class FalconConstants {
+
+ // Stored in hex though not really a hex. 21.0 = 0x2100, ex. 1.2 = 0x0102
+ public final int kFirmwareVersion = 0x2100;
+ public final boolean kBreakOnWrongFirmware = true;
+
+ public final double kResolution = 2048;
+ public final double kMaxRpm = 6380.0; // Rotations per minute
+
+ /*
+ * Talon Stator / Supply Limits explanation
+ * Supply current is current that’s being drawn at the input bus voltage. Stator
+ * current is current that’s being drawn by the motor.
+ * Supply limiting (supported by Talon FX and SRX) is useful for preventing
+ * breakers from tripping in the PDP.
+ * Stator limiting (supported by Talon FX) is useful for limiting
+ * acceleration/heat.
+ */
+
+ // These are the default values
+
+ // Stator
+ public final boolean kStatorLimitEnable = false; // enabled?
+ public final double kStatorCurrentLimit = 100; // Limit(amp)
+ public final double kStatorTriggerThreshold = 100; // Trigger Threshold(amp)
+ public final double kStatorTriggerDuration = 0; // Trigger Threshold Time(s)
+
+ // Supply
+ public final boolean kSupplyLimitEnable = false; // enabled?
+ public final double kSupplyCurrentLimit = 40; // Limit(amp), current to hold after trigger hit
+ public final double kSupplyTriggerThreshold = 55; // (amp), amps to activate trigger
+ public final double kSupplyTriggerDuration = 3; // (s), how long after trigger before reducing
+
+}
--- /dev/null
+package frc.robot.constants;
+
+// OI stands for Operator Input
+public class OIConstants {
+ public final int kDriverJoy = 0;
+ public final int kOperatorJoy = 1;
+
+ public final double kDeadband = 0.05;
+}
--- /dev/null
+package frc.robot.controls;
+
+import edu.wpi.first.wpilibj2.command.RunCommand;
+import edu.wpi.first.wpilibj2.command.SequentialCommandGroup;
+import frc.robot.Robot;
+import frc.robot.commands.DoNothing;
+import frc.robot.constants.Constants;
+import frc.robot.util.TestType;
+import lib.controllers.GameController;
+import lib.controllers.GameController.Button;
+
+public class Driver {
+ private static GameController driver = new GameController(Constants.oi.kDriverJoy);
+
+ public static void configureControls() {
+
+ // example button binding implementation
+ driver.get(Button.A).whenPressed(new DoNothing());
+
+ // example test type implementation
+ // tests drivetrain, when in TEST_DRIVE test mode and
+ driver.get(Button.A).and(Robot.shuffleboard.isTestTypeTrigger(TestType.TEST_DRIVE)).whenActive(
+ new SequentialCommandGroup(
+ new RunCommand(() -> Robot.drive.tankDrive(0.5, 0.5), Robot.drive).withTimeout(1),
+ new RunCommand(() -> Robot.drive.tankDrive(-0.5, -0.5), Robot.drive).withTimeout(1),
+ new RunCommand(() -> Robot.drive.tankDrive(0.5, -0.5), Robot.drive).withTimeout(1),
+ new RunCommand(() -> Robot.drive.tankDrive(-0.5, 0.5), Robot.drive).withTimeout(1)
+ )
+ );
+ }
+}
--- /dev/null
+package frc.robot.controls;
+
+import frc.robot.commands.DoNothing;
+import frc.robot.constants.Constants;
+import lib.controllers.GameController;
+import lib.controllers.GameController.Button;
+
+public class Operator {
+ private static GameController operator = new GameController(Constants.oi.kOperatorJoy);
+
+ public static void configureControls() {
+ operator.get(Button.A).whenPressed(new DoNothing());
+ }
+}
--- /dev/null
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package frc.robot.subsystems;
+
+import com.ctre.phoenix.motorcontrol.ControlMode;
+import com.ctre.phoenix.motorcontrol.SupplyCurrentLimitConfiguration;
+import com.ctre.phoenix.motorcontrol.can.WPI_TalonFX;
+import edu.wpi.first.wpilibj2.command.SubsystemBase;
+import frc.robot.constants.Constants;
+import frc.robot.util.MotorFactory;
+
+public class Drivetrain extends SubsystemBase {
+
+ private final WPI_TalonFX m_leftMotor1;
+ private final WPI_TalonFX m_leftMotor2;
+ private final WPI_TalonFX m_rightMotor1;
+ private final WPI_TalonFX m_rightMotor2;
+
+ public Drivetrain() {
+
+ m_leftMotor1 = MotorFactory.createTalonFX(Constants.drive.kLeftMotor1, Constants.kRioCAN);
+ m_leftMotor2 = MotorFactory.createTalonFX(Constants.drive.kLeftMotor2, Constants.kRioCAN);
+ m_rightMotor1 = MotorFactory.createTalonFX(Constants.drive.kRightMotor1, Constants.kRioCAN);
+ m_rightMotor2 = MotorFactory.createTalonFX(Constants.drive.kRightMotor2, Constants.kRioCAN);
+
+ SupplyCurrentLimitConfiguration supplyCurrentLimit = new SupplyCurrentLimitConfiguration(true, 40, 45, 1);
+
+ m_leftMotor1.configSupplyCurrentLimit(supplyCurrentLimit);
+ m_leftMotor2.configSupplyCurrentLimit(supplyCurrentLimit);
+ m_rightMotor1.configSupplyCurrentLimit(supplyCurrentLimit);
+ m_rightMotor2.configSupplyCurrentLimit(supplyCurrentLimit);
+
+ m_leftMotor2.follow(m_leftMotor1);
+ m_rightMotor2.follow(m_rightMotor1);
+ }
+
+ /**
+ * Drives the robot using tank drive controls Tank drive is slightly easier to code but less
+ * intuitive to control, so this is here as an example for now
+ *
+ * @param leftPower the commanded power to the left motors
+ * @param rightPower the commanded power to the right motors
+ */
+ public void tankDrive(double leftPower, double rightPower) {
+ m_leftMotor1.set(ControlMode.PercentOutput, leftPower);
+ m_rightMotor1.set(ControlMode.PercentOutput, rightPower);
+ }
+
+ /**
+ * Drives the robot using arcade controls.
+ *
+ * @param forward the commanded forward movement
+ * @param turn the commanded turn rotation
+ */
+ public void arcadeDrive(double throttle, double turn) {
+ m_leftMotor1.set(ControlMode.PercentOutput, throttle + turn);
+ m_rightMotor1.set(ControlMode.PercentOutput, throttle - turn);
+ }
+}
--- /dev/null
+package frc.robot.util;
+
+import frc.robot.constants.Constants;
+
+public class Functions {
+
+ /**
+ * Deadbands an input to [-1, -deadband], [deadband, 1], rescaling inputs to be linear from
+ * (deadband, 0) to (1,1)
+ *
+ * @param input The input value to rescale
+ * @param deadband The deadband
+ * @return the input rescaled and to fit [-1, -deadband], [deadband, 1]
+ */
+ public static double deadband(double input, double deadband) {
+ if (Math.abs(input) <= deadband) {
+ return 0;
+ } else if (Math.abs(input) == 1) {
+ return input;
+ } else {
+ return (1 / (1 - deadband) * (input + Math.signum(-input) * deadband));
+ }
+ }
+
+ /**
+ * Deadbands an input to [-1, -Constants.oi.kDeadband], [Constants.oi.kDeadband, 1], rescaling inputs to be linear from
+ * (Constants.oi.kDeadband, 0) to (1,1)
+ *
+ * @param input The input value to rescale
+ * @return the input rescaled and to fit [-1, -kDeadband], [kDeadband, 1]
+ */
+ public static double deadband(double input) {
+ return deadband(input, Constants.oi.kDeadband);
+ }
+
+ /**
+ * An exponential function that maintains positive or negative.
+ * @param exponent the power to raise the base to
+ * @param base the base which will be raised to the power
+ * @return base to the power of exponent, maintaining sign of base
+ */
+ public static double expoMS(double exponent, double base) {
+ // weird stuff will happen if you don't put a number > 0
+ double finVal = Math.pow(Math.abs(base), exponent);
+ if (base < 0) {
+ finVal *= -1;
+ }
+ return finVal;
+ }
+}
--- /dev/null
+package frc.robot.util;
+
+import java.io.IOException;
+
+import java.io.IOError;
+
+import com.ctre.phoenix.motorcontrol.FeedbackDevice;
+import com.ctre.phoenix.motorcontrol.NeutralMode;
+import com.ctre.phoenix.motorcontrol.StatorCurrentLimitConfiguration;
+import com.ctre.phoenix.motorcontrol.SupplyCurrentLimitConfiguration;
+import com.ctre.phoenix.motorcontrol.can.TalonFXConfiguration;
+import com.ctre.phoenix.motorcontrol.can.TalonSRXConfiguration;
+import com.ctre.phoenix.motorcontrol.can.WPI_TalonFX;
+import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX;
+import com.revrobotics.CANSparkMax;
+import com.revrobotics.CANSparkMax.IdleMode;
+import com.revrobotics.CANSparkMaxLowLevel.MotorType;
+
+import edu.wpi.first.wpilibj.DriverStation;
+import frc.robot.constants.Constants;
+
+public class MotorFactory {
+
+ private static int talonSRXDefaultContinuousLimit = 38;
+ private static int kTalonSRXDefaultPeakLimit = 45;
+ private static int kTalonSRXDefaultPeakDuration = 125;
+
+ private static int kSparkMaxDefaultCurrentLimit = 60;
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // TALON SRX
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Create a TalonSRX with current limiting enabled, using parameters. It will
+ * have current
+ * limiting and voltage compensation enabled and be set to Brake Mode.
+ *
+ * @param id the ID of the TalonSRX
+ * @param continuousCurrentLimit the continuous current limit to set in amps (A)
+ * @param peakCurrentLimit the peak current limit to set in amps (A)
+ * @param peakCurrentDuration the peak current limit duration to set in
+ * milliseconds (ms)
+ * @return a fully configured TalonSRX object
+ */
+ public static WPI_TalonSRX createTalonSRX(
+ int id, int continuousCurrentLimit, int peakCurrentLimit, int peakCurrentDuration) {
+
+ TalonSRXConfiguration config = new TalonSRXConfiguration();
+ config.continuousCurrentLimit = continuousCurrentLimit;
+ config.peakCurrentLimit = peakCurrentLimit;
+ config.peakCurrentDuration = peakCurrentDuration;
+ config.voltageCompSaturation = Constants.kMaxVoltage;
+
+ WPI_TalonSRX talon = new WPI_TalonSRX(id);
+ talon.configFactoryDefault();
+ talon.configAllSettings(config);
+ talon.enableCurrentLimit(true);
+ talon.enableVoltageCompensation(true);
+ talon.setNeutralMode(NeutralMode.Brake);
+
+ return talon;
+ }
+
+ /**
+ * Create a TalonSRX using default current limits.
+ *
+ * @param id the ID of the TalonSRX
+ * @return a fully configured TalonSRX object
+ */
+ public static WPI_TalonSRX createTalonSRXDefault(int id) {
+ return createTalonSRX(id, talonSRXDefaultContinuousLimit, kTalonSRXDefaultPeakLimit, kTalonSRXDefaultPeakDuration);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // SPARK MAX
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Create a CANSparkMax with current limiting enabled
+ *
+ * @param id the ID of the Spark MAX
+ * @param motortype the type of motor the Spark MAX is connected to
+ * @param stallLimit the current limit to set at stall
+ * @return a fully configured CANSparkMAX
+ */
+ public static CANSparkMax createSparkMAX(int id, MotorType motortype, int stallLimit) {
+ CANSparkMax sparkMAX = new CANSparkMax(id, motortype);
+ sparkMAX.restoreFactoryDefaults();
+ sparkMAX.enableVoltageCompensation(Constants.kMaxVoltage);
+ sparkMAX.setSmartCurrentLimit(stallLimit);
+ sparkMAX.setIdleMode(IdleMode.kBrake);
+
+ sparkMAX.burnFlash();
+ return sparkMAX;
+ }
+
+ /**
+ * Create a CANSparkMax with default current limiting enabled
+ *
+ * @param id the ID of the Spark MAX
+ * @param motortype the type of motor the Spark MAX is connected to
+ * @return a fully configured CANSparkMAX
+ */
+ public static CANSparkMax createSparkMAXDefault(int id, MotorType motortype) {
+ return createSparkMAX(id, motortype, kSparkMaxDefaultCurrentLimit);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+ // TALON FX (Falcon 500)
+ ///////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ *
+ * Creates a TalonFX with all current limit options. If you would like to use
+ * defaults it is recommended to use the other createTalonFX.. methods.
+ *
+ * @param id the id of the the motor
+ * @param CANBus the CAN Bus the motor is on
+ * @param StatorLimitEnable whether or not to enable stator limiting
+ * @param StatorCurrentLimit the current, in amps, to return to after the
+ * stator limit is triggered
+ * @param StatorTriggerThreshold the threshold current to trigger the stator
+ * limit
+ * @param StatorTriggerDuration the duration, in seconds, the current is above
+ * the threshold before triggering
+ * @param SupplyLimitEnable whether or not to enable supply limiting
+ * @param SupplyCurrentLimit the current, in amps, to return to after the
+ * supply limit is triggered
+ * @param SupplyTriggerThreshold the threshold current to trigger the supply
+ * limit
+ * @param SupplyTriggerDuration the duration, in seconds, the current is above
+ * the threshold before triggering
+ * @return A fully configured TalonFX
+ */
+ public static WPI_TalonFX createTalonFXFull(int id, String CANBus, boolean StatorLimitEnable,
+ double StatorCurrentLimit,
+ double StatorTriggerThreshold, double StatorTriggerDuration, boolean SupplyLimitEnable, double SupplyCurrentLimit,
+ double SupplyTriggerThreshold, double SupplyTriggerDuration) {
+
+ if (id == -1) {
+ return null;
+ }
+
+ WPI_TalonFX talon = new WPI_TalonFX(id, CANBus);
+
+ if (talon.getFirmwareVersion() != Constants.falcon.kFirmwareVersion) {
+ String errorMessage = "TalonFX " + id + " firmware incorrect. Has " + talon.getFirmwareVersion()
+ + ", currently FalconConstants.java requires: " + Constants.falcon.kFirmwareVersion;
+ if (Constants.falcon.kBreakOnWrongFirmware) {
+ DriverStation.reportError(errorMessage, true);
+ throw new IOError(new IOException(errorMessage));
+ } else {
+ DriverStation.reportWarning(errorMessage + ", ignoring due to user specification.", false);
+ }
+ }
+
+ TalonFXConfiguration config = new TalonFXConfiguration();
+
+ // See explanations for Supply and Stator limiting in FalconConstants.java
+ config.statorCurrLimit = new StatorCurrentLimitConfiguration(StatorLimitEnable, StatorCurrentLimit,
+ StatorTriggerThreshold, StatorTriggerDuration);
+ config.supplyCurrLimit = new SupplyCurrentLimitConfiguration(SupplyLimitEnable, SupplyCurrentLimit,
+ SupplyTriggerThreshold, SupplyTriggerDuration);
+
+ config.voltageCompSaturation = Constants.kMaxVoltage;
+
+ talon.configFactoryDefault();
+ talon.configAllSettings(config);
+ talon.enableVoltageCompensation(true);
+ talon.setNeutralMode(NeutralMode.Brake);
+ talon.configSelectedFeedbackSensor(FeedbackDevice.IntegratedSensor);
+
+ return talon;
+ }
+
+ /**
+ * @param id
+ * @param CANBus
+ */
+ public static WPI_TalonFX createTalonFX(int id, String CANBus) {
+ return createTalonFXFull(id, CANBus, Constants.falcon.kStatorLimitEnable, Constants.falcon.kStatorCurrentLimit,
+ Constants.falcon.kStatorTriggerThreshold, Constants.falcon.kStatorTriggerDuration,
+ Constants.falcon.kSupplyLimitEnable, Constants.falcon.kSupplyCurrentLimit,
+ Constants.falcon.kSupplyTriggerThreshold, Constants.falcon.kSupplyTriggerDuration);
+ }
+
+ public static WPI_TalonFX createTalonFXSupplyLimit(int id, String CANBus, double currentLimit,
+ double triggerThreshold, double triggerDuration) {
+ return createTalonFXFull(id, CANBus, Constants.falcon.kStatorLimitEnable, Constants.falcon.kStatorCurrentLimit,
+ Constants.falcon.kStatorTriggerThreshold, Constants.falcon.kStatorTriggerDuration, true, currentLimit,
+ triggerThreshold, triggerDuration);
+ }
+
+ public static WPI_TalonFX createTalonFXStatorLimit(int id, String CANBus, double currentLimit,
+ double triggerThreshold, double triggerDuration) {
+ return createTalonFXFull(id, CANBus, true, currentLimit, triggerThreshold, triggerDuration,
+ Constants.falcon.kSupplyLimitEnable, Constants.falcon.kSupplyCurrentLimit,
+ Constants.falcon.kSupplyTriggerThreshold, Constants.falcon.kSupplyTriggerDuration);
+ }
+}
--- /dev/null
+package frc.robot.util;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.pathplanner.lib.PathConstraints;
+import com.pathplanner.lib.PathPlanner;
+import com.pathplanner.lib.PathPlannerTrajectory;
+
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.Filesystem;
+import frc.robot.constants.Constants;
+
+public class PathGroupLoader{
+
+ private static HashMap<String, ArrayList<PathPlannerTrajectory>> pathGroups = new HashMap<String, ArrayList<PathPlannerTrajectory>>();
+
+ public static void loadPathGroups() {
+ double totalTime = 0;
+ File[] directoryListing = Filesystem.getDeployDirectory().toPath().resolve(Constants.auto.kTrajectoryDirectory).toFile().listFiles();
+ if (directoryListing != null) {
+ for (File file : directoryListing) {
+ if (file.isFile() && file.getName().indexOf(".") != -1) {
+ long startTime = System.nanoTime();
+ String name = file.getName().substring(0, file.getName().indexOf("."));
+ pathGroups.put(name, PathPlanner.loadPathGroup(name, new PathConstraints(Constants.auto.kMaxAutoSpeed, Constants.auto.kMaxAutoAccel)));
+ double time = (System.nanoTime() - startTime) / 1000000.0;
+ totalTime += time;
+ System.out.println("Processed file: " + file.getName() + ", took " + time + " milliseconds.");
+ }
+ }
+ } else {
+ System.out.println("Error processing file");
+ DriverStation.reportWarning(
+ "Issue with finding path files. Paths will not be loaded.",
+ true
+ );
+ }
+ System.out.println("File processing took a total of " + totalTime + " milliseconds");
+ }
+
+ public static ArrayList<PathPlannerTrajectory> getPathGroup(String pathGroupName) {
+ if (pathGroups.get(pathGroupName) == null) {
+ System.out.println("Error retrieving " + pathGroupName + " path!");
+ }
+ return pathGroups.get(pathGroupName);
+ }
+}
\ No newline at end of file
--- /dev/null
+package frc.robot.util;
+
+import edu.wpi.first.networktables.NetworkTableEntry;
+import edu.wpi.first.wpilibj.DriverStation;
+import edu.wpi.first.wpilibj.RobotBase;
+import edu.wpi.first.wpilibj.livewindow.LiveWindow;
+import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard;
+import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab;
+import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
+import edu.wpi.first.wpilibj2.command.Command;
+import edu.wpi.first.wpilibj2.command.CommandScheduler;
+import edu.wpi.first.wpilibj2.command.PrintCommand;
+import edu.wpi.first.wpilibj2.command.button.Trigger;
+import frc.robot.Robot;
+
+public class ShuffleboardManager {
+
+ SendableChooser<Command> m_autoCommand = new SendableChooser<>();
+ SendableChooser<TestType> m_testType = new SendableChooser<>();
+
+ ShuffleboardTab m_mainTab = Shuffleboard.getTab("Main");
+ ShuffleboardTab m_autoTab = Shuffleboard.getTab("Auto");
+ ShuffleboardTab m_testTab = Shuffleboard.getTab("Test");
+
+ NetworkTableEntry m_commandScheduler = m_mainTab.add("Command Scheduler", "NULL").getEntry();
+
+ public void setup() {
+ LiveWindow.disableAllTelemetry(); // LiveWindow is causing periodic loop overruns
+
+ autoChooserUpdate();
+
+ m_autoTab.add("Auto Chooser", m_autoCommand);
+ m_testTab.add("Run Test", m_testType);
+ }
+
+ public Command getAutonomousCommand() {
+ return m_autoCommand.getSelected();
+ }
+
+ public void autoChooserUpdate() {
+ m_autoCommand.addOption("Do Nothing", new PrintCommand("This will do nothing!"));
+ }
+
+
+ public TestType getTestType() {
+ if (Robot.isTestMode()) {
+ return m_testType.getSelected();
+ }
+ return TestType.NONE;
+ }
+
+ public Trigger isTestTypeTrigger(TestType testType) {
+ return new Trigger(() -> m_testType.getSelected() == testType);
+ }
+
+ public void testChooserUpdate() {
+ m_testType.addOption("No Test", TestType.NONE);
+ }
+
+ public void loadCommandSchedulerShuffleboard() {
+ CommandScheduler.getInstance()
+ .onCommandInitialize(
+ command -> m_commandScheduler.setString(command.getName() + " initialized."));
+ CommandScheduler.getInstance()
+ .onCommandInterrupt(
+ command -> m_commandScheduler.setString(command.getName() + " interrupted."));
+ CommandScheduler.getInstance()
+ .onCommandFinish(command -> m_commandScheduler.setString(command.getName() + " finished."));
+ }
+}
--- /dev/null
+package frc.robot.util;
+
+public enum TestType {
+ NONE, TUNE_EXAMPLE_PID, TEST_DRIVE
+}
--- /dev/null
+package lib.controllers;
+
+import edu.wpi.first.wpilibj.Joystick;
+
+public class Controller {
+ protected final Joystick m_controller;
+
+ public Controller(int port) {
+ this.m_controller = new Joystick(port);
+ }
+}
--- /dev/null
+package lib.controllers;
+
+import edu.wpi.first.wpilibj.Joystick;
+import edu.wpi.first.wpilibj2.command.button.*;
+
+public class Ex3DProController extends Controller {
+ public Ex3DProController(int port) {
+ super(port);
+ }
+
+ public enum Button {
+ B1(1),
+ B2(2),
+ B3(3),
+ B4(4),
+ B6(6),
+ B7(7),
+ B8(8),
+ B9(9),
+ B10(10),
+ B11(11),
+ B12(12);
+
+ public final int id;
+
+ Button(final int id) {
+ this.id = id;
+ }
+ }
+
+ public enum Axis {
+ X(0),
+ Y(1),
+ Z(2),
+ SLIDER(3);
+
+ public final int id;
+
+ Axis(final int id) {
+ this.id = id;
+ }
+ }
+
+ public JoystickButton get(Button button) {
+ return new JoystickButton(m_controller, button.id);
+ }
+
+ public double get(Axis axis) {
+ return m_controller.getRawAxis(axis.id);
+ }
+
+ public Joystick get() {
+ return m_controller;
+ }
+}
--- /dev/null
+package lib.controllers;
+
+import edu.wpi.first.wpilibj.GenericHID.RumbleType;
+import edu.wpi.first.wpilibj.Joystick;
+import edu.wpi.first.wpilibj2.command.button.*;
+import java.util.function.BooleanSupplier;
+
+public class GameController extends Controller {
+ // These are the different controller triggers
+ public final BooleanSupplier LEFT_TRIGGER_BUTTON = () -> get(Axis.LEFT_TRIGGER) > 0.5,
+ RIGHT_TRIGGER_BUTTON = () -> get(Axis.RIGHT_TRIGGER) > 0.5;
+ public final Trigger ALL_UP = get(DPad.UP).or(get(DPad.UP_LEFT)).or(get(DPad.UP_RIGHT)),
+ ALL_DOWN = get(DPad.DOWN).or(get(DPad.DOWN_LEFT)).or(get(DPad.DOWN_RIGHT)),
+ ALL_LEFT = get(DPad.LEFT).or(get(DPad.UP_LEFT)).or(get(DPad.DOWN_LEFT)),
+ ALL_RIGHT = get(DPad.RIGHT).or(get(DPad.UP_RIGHT)).or(get(DPad.DOWN_RIGHT));
+
+ public GameController(int port) {
+ super(port);
+ }
+
+ public enum Button {
+ A(1),
+ B(2),
+ X(3),
+ Y(4),
+ LB(5),
+ RB(6),
+ BACK(7),
+ START(8),
+ LEFT_JOY(9),
+ RIGHT_JOY(10);
+
+ public final int id;
+
+ Button(final int id) {
+ this.id = id;
+ }
+ }
+
+ public enum Axis {
+ LEFT_X(0),
+ LEFT_Y(1),
+ LEFT_TRIGGER(2),
+ RIGHT_TRIGGER(3),
+ RIGHT_X(4),
+ RIGHT_Y(5);
+
+ public final int id;
+
+ Axis(final int id) {
+ this.id = id;
+ }
+ }
+
+ public enum DPad {
+ UNPRESSED(-1),
+ UP(0),
+ UP_RIGHT(45),
+ RIGHT(90),
+ DOWN_RIGHT(135),
+ DOWN(180),
+ DOWN_LEFT(235),
+ LEFT(270),
+ UP_LEFT(315);
+
+ public final int angle;
+
+ DPad(final int angle) {
+ this.angle = angle;
+ }
+ }
+
+ public enum RumbleStatus {
+ RUMBLE_ON(0.7),
+ RUMBLE_OFF(0);
+
+ public final double rumbleValue;
+
+ RumbleStatus(final double rumbleValue) {
+ this.rumbleValue = rumbleValue;
+ }
+ }
+
+ public JoystickButton get(Button button) {
+ return new JoystickButton(m_controller, button.id);
+ }
+
+ public double get(Axis axis) {
+ return m_controller.getRawAxis(axis.id);
+ }
+
+ public POVButton get(DPad dPad) {
+ return new POVButton(m_controller, dPad.angle);
+ }
+
+ public Trigger get(BooleanSupplier condition) {
+ return new Trigger(condition);
+ }
+
+ public Trigger get(Trigger trigger) {
+ return trigger;
+ }
+
+ public Joystick get() {
+ return m_controller;
+ }
+
+ public void setRumble(RumbleStatus rumbleStatus) {
+ m_controller.setRumble(RumbleType.kLeftRumble, rumbleStatus.rumbleValue);
+ m_controller.setRumble(RumbleType.kRightRumble, rumbleStatus.rumbleValue);
+ }
+}
--- /dev/null
+package lib.controllers;
+
+import edu.wpi.first.wpilibj.Joystick;
+import edu.wpi.first.wpilibj2.command.button.*;
+
+public class MadCatzController extends Controller {
+ public final Trigger
+ ALL_UP = get(HatSwitch.UP).or(get(HatSwitch.UP_LEFT)).or(get(HatSwitch.UP_RIGHT)),
+ ALL_DOWN = get(HatSwitch.DOWN).or(get(HatSwitch.DOWN_LEFT)).or(get(HatSwitch.DOWN_RIGHT)),
+ ALL_LEFT = get(HatSwitch.LEFT).or(get(HatSwitch.UP_LEFT)).or(get(HatSwitch.DOWN_LEFT)),
+ ALL_RIGHT = get(HatSwitch.RIGHT).or(get(HatSwitch.UP_RIGHT)).or(get(HatSwitch.DOWN_RIGHT));
+
+ public MadCatzController(int port) {
+ super(port);
+ }
+
+ public enum Button {
+ B1(1),
+ B2(2),
+ B3(3),
+ B4(4),
+ B6(6),
+ B7(7);
+
+ public final int id;
+
+ Button(final int id) {
+ this.id = id;
+ }
+ }
+
+ public enum Axis {
+ X(0),
+ Y(1),
+ ZAXIS(2),
+ ZROTATE(3);
+
+ public final int id;
+
+ Axis(final int id) {
+ this.id = id;
+ }
+ }
+
+ public enum HatSwitch {
+ UNPRESSED(-1),
+ UP(0),
+ UP_RIGHT(45),
+ RIGHT(90),
+ DOWN_RIGHT(135),
+ DOWN(180),
+ DOWN_LEFT(235),
+ LEFT(270),
+ UP_LEFT(315);
+
+ public final int angle;
+
+ HatSwitch(final int angle) {
+ this.angle = angle;
+ }
+ }
+
+ public JoystickButton get(Button button) {
+ return new JoystickButton(m_controller, button.id);
+ }
+
+ public double get(Axis axis) {
+ return m_controller.getRawAxis(axis.id);
+ }
+
+ public POVButton get(HatSwitch hatSwitch) {
+ return new POVButton(m_controller, hatSwitch.angle);
+ }
+
+ public Trigger get(Trigger trigger) {
+ return trigger;
+ }
+
+ public Joystick get() {
+ return m_controller;
+ }
+}
--- /dev/null
+package lib.controllers;
+
+import edu.wpi.first.wpilibj.Joystick;
+import edu.wpi.first.wpilibj2.command.button.JoystickButton;
+import edu.wpi.first.wpilibj2.command.button.Trigger;
+
+public class PistolController extends Controller {
+ public final Trigger TOP_BACK_ONLY = get(Button.TOP_BACK).and(get(Button.TOP_FRONT).negate()),
+ TOP_FRONT_ONLY = get(Button.TOP_FRONT).and(get(Button.TOP_BACK).negate()),
+ BOTTOM_BACK_ONLY = get(Button.BOTTOM_BACK).and(get(Button.BOTTOM_FRONT).negate()),
+ BOTTOM_FRONT_ONLY = get(Button.BOTTOM_FRONT).and(get(Button.BOTTOM_BACK).negate());
+
+ public PistolController(int port) {
+ super(port);
+ }
+
+ public enum Button {
+ TOP_BACK(1),
+ TOP_FRONT(2),
+ BOTTOM_FRONT(3),
+ BOTTOM_BACK(4),
+ BOTTOM(5);
+
+ public final int id;
+
+ Button(final int id) {
+ this.id = id;
+ }
+ }
+
+ public enum Axis {
+ WHEEL(0),
+ TRIGGER(1);
+
+ public final int id;
+
+ Axis(final int id) {
+ this.id = id;
+ }
+ }
+
+ public JoystickButton get(Button button) {
+ return new JoystickButton(m_controller, button.id);
+ }
+
+ public double get(Axis axis) {
+ return m_controller.getRawAxis(axis.id);
+ }
+
+ public Trigger get(Trigger trigger) {
+ return trigger;
+ }
+
+ public Joystick get() {
+ return m_controller;
+ }
+}
--- /dev/null
+package lib.ctre_shims;
+
+import com.ctre.phoenix.motorcontrol.InvertType;
+import com.ctre.phoenix.motorcontrol.can.BaseMotorController;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+import edu.wpi.first.wpilibj.motorcontrol.MotorController;
+import java.util.Arrays;
+
+/**
+ * Allows multiple {@link MotorController} objects to be linked together.
+ *
+ * <p>Reimplementation with supports CTRE CAN follower functionality.
+ */
+public class PhoenixMotorControllerGroup implements MotorController, Sendable, AutoCloseable {
+ private final MotorController[] m_motorControllers;
+ private final MotorController m_leadMotorController;
+ private static int instances;
+
+ /**
+ * Create a new PhoenixMotorControllerGroup with the provided MotorControllers.
+ *
+ * @param leadMotorController The lead MotorController to add
+ * @param motorControllers The MotorControllers to add
+ */
+ public PhoenixMotorControllerGroup(
+ MotorController leadMotorController, MotorController... motorControllers) {
+ boolean validArgumentTypes = leadMotorController instanceof BaseMotorController;
+ for (MotorController motorController : motorControllers) {
+ validArgumentTypes = validArgumentTypes && (motorController instanceof BaseMotorController);
+ }
+
+ if (!validArgumentTypes) {
+ throw new IllegalArgumentException(
+ "One or more MotorControllers do not inherit from BaseMotorController, i.e. are not CTRE classes");
+ }
+ m_leadMotorController = leadMotorController;
+ m_motorControllers = Arrays.copyOf(motorControllers, motorControllers.length);
+ init();
+ }
+
+ private void init() {
+ SendableRegistry.addChild(this, m_leadMotorController);
+ for (MotorController controller : m_motorControllers) {
+ SendableRegistry.addChild(this, controller);
+ ((BaseMotorController) controller).follow((BaseMotorController) m_leadMotorController);
+ ((BaseMotorController) controller).setInverted(InvertType.FollowMaster);
+ }
+ instances++;
+ SendableRegistry.addLW(this, "PhoenixMotorControllerGroup", instances);
+ }
+
+ @Override
+ public void close() {
+ SendableRegistry.remove(this);
+ }
+
+ @Override
+ public void set(double speed) {
+ m_leadMotorController.set(speed);
+ }
+
+ @Override
+ public double get() {
+ return m_leadMotorController.get();
+ }
+
+ @Override
+ public void setInverted(boolean isInverted) {
+ m_leadMotorController.setInverted(isInverted);
+ }
+
+ @Override
+ public boolean getInverted() {
+ return m_leadMotorController.getInverted();
+ }
+
+ @Override
+ public void disable() {
+ m_leadMotorController.disable();
+ for (MotorController motorController : m_motorControllers) {
+ motorController.disable();
+ }
+ }
+
+ @Override
+ public void stopMotor() {
+ m_leadMotorController.stopMotor();
+ for (MotorController motorController : m_motorControllers) {
+ motorController.stopMotor();
+ }
+ }
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType("Phoenix Motor Controller");
+ builder.setActuator(true);
+ builder.setSafeState(this::stopMotor);
+ builder.addDoubleProperty("Value", this::get, this::set);
+ }
+
+ @Override
+ public void setVoltage(double outputVolts) {
+ m_leadMotorController.setVoltage(outputVolts);
+ for (MotorController motorController : m_motorControllers) {
+ motorController.setVoltage(outputVolts);
+ }
+ }
+}
--- /dev/null
+package lib.ctre_shims;
+
+import com.ctre.phoenix.ParamEnum;
+import com.ctre.phoenix.motorcontrol.FeedbackDevice;
+import com.ctre.phoenix.motorcontrol.can.BaseTalon;
+import edu.wpi.first.util.sendable.Sendable;
+import edu.wpi.first.util.sendable.SendableBuilder;
+import edu.wpi.first.util.sendable.SendableRegistry;
+
+/** A class to read encoder data from CTRE motors, frc::Encoder compatible. */
+public class TalonEncoder implements Sendable, AutoCloseable {
+ private final BaseTalon m_motor;
+ private double m_distancePerPulse = 1;
+
+ public TalonEncoder(BaseTalon motor) {
+ this(motor, false);
+ }
+
+ public TalonEncoder(BaseTalon motor, boolean reverseDirection) {
+ m_motor = motor;
+ setReverseDirection(reverseDirection);
+ SendableRegistry.addLW(this, "Talon Encoder", motor.getDeviceID());
+ }
+
+ @Override
+ public void close() {
+ SendableRegistry.remove(this);
+ }
+
+ /**
+ * Gets the current count. Returns the current count on the Encoder. This method compensates for
+ * the decoding type.
+ *
+ * @return Current count from the Encoder adjusted for the 1x, 2x, or 4x scale factor.
+ */
+ public int get() {
+ return (int) m_motor.getSelectedSensorPosition();
+ }
+
+ /** Reset the Encoder distance to zero. Resets the current count to zero on the encoder. */
+ public void reset() {
+ m_motor.setSelectedSensorPosition(0);
+ }
+
+ /**
+ * Returns the period of the most recent pulse. Returns the period of the most recent Encoder
+ * pulse in seconds. This method compensates for the decoding type.
+ *
+ * <p><b>Warning:</b> This returns unscaled periods. Use getRate() for rates that are scaled using
+ * the value from setDistancePerPulse().
+ *
+ * @return Period in seconds of the most recent pulse.
+ * @deprecated Use getRate() in favor of this method.
+ */
+ @Deprecated
+ public double getPeriod() {
+ // distance / (distance / second) = seconds
+ return m_distancePerPulse / getRate();
+ }
+
+ /**
+ * The last direction the encoder value changed.
+ *
+ * @return The last direction the encoder value changed.
+ */
+ public boolean getDirection() {
+ if (getRate() >= 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Get the distance the robot has driven since the last reset as scaled by the value from {@link
+ * #setDistancePerPulse(double)}.
+ *
+ * @return The distance driven since the last reset
+ */
+ public double getDistance() {
+ return get() * m_distancePerPulse;
+ }
+
+ /**
+ * Get the current rate of the encoder. Units are distance per second as scaled by the value from
+ * setDistancePerPulse().
+ *
+ * @return The current rate of the encoder.
+ */
+ public double getRate() {
+ return m_motor.getSelectedSensorVelocity() * 10 * m_distancePerPulse;
+ }
+
+ /**
+ * Set the distance per pulse for this encoder. This sets the multiplier used to determine the
+ * distance driven based on the count value from the encoder. Do not include the decoding type in
+ * this scale. The library already compensates for the decoding type. Set this value based on the
+ * encoder's rated Pulses per Revolution and factor in gearing reductions following the encoder
+ * shaft. This distance can be in any units you like, linear or angular.
+ *
+ * @param distancePerPulse The scale factor that will be used to convert pulses to useful units.
+ */
+ public void setDistancePerPulse(double distancePerPulse) {
+ m_distancePerPulse = distancePerPulse;
+ }
+
+ /**
+ * Get the distance per pulse for this encoder.
+ *
+ * @return The scale factor that will be used to convert pulses to useful units.
+ */
+ public double getDistancePerPulse() {
+ return m_distancePerPulse;
+ }
+
+ /**
+ * Set the direction sensing for this encoder. This sets the direction sensing on the encoder so
+ * that it could count in the correct software direction regardless of the mounting.
+ *
+ * @param reverseDirection true if the encoder direction should be reversed
+ */
+ public void setReverseDirection(boolean reverseDirection) {
+ m_motor.setSensorPhase(reverseDirection);
+ }
+
+ /**
+ * Set the Samples to Average which specifies the number of samples of the timer to average when
+ * calculating the period. Perform averaging to account for mechanical imperfections or as
+ * oversampling to increase resolution.
+ *
+ * <p>Defaults to 64. See also, CTRE's ConfigVelocityMeasurementPeriod().
+ * https://docs.ctre-phoenix.com/en/stable/ch14_MCSensor.html#changing-velocity-measurement-parameters
+ * See also, the note in Measurement-Delays.md in the root of this repository.
+ *
+ * @param samplesToAverage The number of samples to average (one of 1, 2, 4, 8, 16, 32, or 64).
+ */
+ public void setSamplesToAverage(int samplesToAverage) {
+ // (n & (n-1)) checks if it is a power of two. See:
+ // http://
+ // www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2
+ if (samplesToAverage < 1
+ || samplesToAverage > 64
+ || (samplesToAverage & (samplesToAverage - 1)) != 0) {
+ throw new IllegalArgumentException(
+ "Samples to average must be a power of 2 between 1 and 64, got " + samplesToAverage);
+ }
+ m_motor.configVelocityMeasurementWindow(samplesToAverage);
+ }
+
+ /**
+ * Get the Samples to Average which specifies the number of samples of the timer to average when
+ * calculating the period. Perform averaging to account for mechanical imperfections or as
+ * oversampling to increase resolution.
+ *
+ * <p>Defaults to 64. See also, CTRE's ConfigVelocityMeasurementPeriod().
+ * https://docs.ctre-phoenix.com/en/stable/ch14_MCSensor.html#changing-velocity-measurement-parameters
+ * See also, the note in Measurement-Delays.md in the root of this repository.
+ *
+ * @return samplesToAverage The number of samples to average (one of 1, 2, 4, 8, 16, 32, or 64).
+ */
+ public int getSamplesToAverage() {
+ return (int) m_motor.configGetParameter(ParamEnum.eSampleVelocityWindow, 0);
+ }
+
+ public BaseTalon getMotor() {
+ return m_motor;
+ }
+
+ public FeedbackDevice getSelectedFeedbackSensor() {
+ return FeedbackDevice.valueOf(m_motor.configGetParameter(ParamEnum.eFeedbackSensorType, 0));
+ }
+
+ @Override
+ public void initSendable(SendableBuilder builder) {
+ builder.setSmartDashboardType(
+ String.format("Encoder (%s)", getSelectedFeedbackSensor().name()));
+ builder.addDoubleProperty("Speed", this::getRate, null);
+ builder.addDoubleProperty("Distance", this::getDistance, null);
+ builder.addDoubleProperty("Distance per Tick", this::getDistancePerPulse, null);
+ }
+}
--- /dev/null
+package lib.ctre_shims;
+
+import com.ctre.phoenix.motorcontrol.FeedbackDevice;
+import com.ctre.phoenix.motorcontrol.TalonFXSimCollection;
+import com.ctre.phoenix.motorcontrol.TalonSRXSimCollection;
+import com.ctre.phoenix.motorcontrol.can.TalonFX;
+import com.ctre.phoenix.motorcontrol.can.TalonSRX;
+
+/** Class to control a simulated encoder. */
+public class TalonEncoderSim {
+ private TalonEncoder m_encoder;
+
+ private TalonSRXSimCollection m_simCollectionSRX = null;
+ private TalonFXSimCollection m_simCollectionFX = null;
+
+ /**
+ * Constructs from an Encoder object.
+ *
+ * @param encoder Encoder to simulate
+ */
+ public TalonEncoderSim(TalonEncoder encoder) {
+ m_encoder = encoder;
+
+ if (m_encoder.getMotor() instanceof TalonSRX) {
+ m_simCollectionSRX = new TalonSRXSimCollection(m_encoder.getMotor());
+ } else if (m_encoder.getMotor() instanceof TalonFX) {
+ m_simCollectionFX = new TalonFXSimCollection(m_encoder.getMotor());
+ } else {
+ throw new IllegalStateException(
+ "Motor type " + m_encoder.getMotor().getClass().getName() + " is unsupported.");
+ }
+ }
+
+ /**
+ * Read the count of the encoder.
+ *
+ * @return the count
+ */
+ public int getCount() {
+ return m_encoder.get();
+ }
+
+ /**
+ * Change the count of the encoder.
+ *
+ * @param count the new count
+ */
+ public void setCount(int count) {
+ if (m_simCollectionSRX != null) {
+ FeedbackDevice selected = m_encoder.getSelectedFeedbackSensor();
+
+ switch (selected) {
+ case QuadEncoder:
+ case CTRE_MagEncoder_Relative:
+ m_simCollectionSRX.setQuadratureRawPosition(count);
+ break;
+
+ case Analog:
+ m_simCollectionSRX.setAnalogPosition(count);
+ break;
+
+ default:
+ throw new IllegalStateException(
+ "Selected feedback sensor is not supported: " + selected.name());
+ }
+ } else if (m_simCollectionFX != null) {
+ m_simCollectionFX.setIntegratedSensorRawPosition(count);
+ } else {
+ // This should have errored already in the constructor.
+ assert false;
+ }
+ }
+
+ /**
+ * Read the period of the encoder.
+ *
+ * @return the encoder period
+ */
+ public double getPeriod() {
+ return m_encoder.getRate();
+ }
+
+ /**
+ * Change the encoder period.
+ *
+ * @param period the new period
+ */
+ public void setPeriod(double period) {
+ // seconds -> distance/second
+ // m_distancePerPulse (distance) / period (seconds) = distance / second
+ setRate(m_encoder.getDistancePerPulse() / period);
+ }
+
+ // These are no-op in WPILib
+ // boolean getReset();
+ // void setReset();
+
+ /**
+ * Get the direction of the encoder.
+ *
+ * @return the direction of the encoder
+ */
+ public boolean getDirection() {
+ return m_encoder.getDirection();
+ }
+
+ /**
+ * Get the samples-to-average value.
+ *
+ * <p>See {@link TalonEncoder#getSamplesToAverage()}.
+ *
+ * @return the samples-to-average value
+ */
+ public int getSamplesToAverage() {
+ return m_encoder.getSamplesToAverage();
+ }
+
+ /**
+ * Set the samples-to-average value.
+ *
+ * <p>See {@link TalonEncoder#setSamplesToAverage()}.
+ *
+ * @param samplesToAverage the new value
+ */
+ public void setSamplesToAverage(int samplesToAverage) {
+ m_encoder.setSamplesToAverage(samplesToAverage);
+ }
+
+ /**
+ * Change the encoder distance.
+ *
+ * @param distance the new distance
+ */
+ public void setDistance(double distance) {
+ setCount((int) (distance / m_encoder.getDistancePerPulse()));
+ }
+
+ /**
+ * Read the distance of the encoder.
+ *
+ * @return the encoder distance
+ */
+ public double getDistance() {
+ return m_encoder.getDistance();
+ }
+
+ /**
+ * Change the rate of the encoder.
+ *
+ * @param rate the new rate
+ */
+ public void setRate(double rate) {
+ int rateInNativeUnits = (int) (rate / (10 * m_encoder.getDistancePerPulse()));
+
+ if (m_simCollectionSRX != null) {
+ FeedbackDevice selected = m_encoder.getSelectedFeedbackSensor();
+
+ switch (selected) {
+ case QuadEncoder:
+ case CTRE_MagEncoder_Relative:
+ m_simCollectionSRX.setQuadratureVelocity(rateInNativeUnits);
+ break;
+
+ case Analog:
+ m_simCollectionSRX.setAnalogVelocity(rateInNativeUnits);
+ break;
+
+ default:
+ throw new IllegalStateException(
+ "Selected feedback sensor is not supported: " + selected.name());
+ }
+ } else if (m_simCollectionFX != null) {
+ m_simCollectionFX.setIntegratedSensorVelocity(rateInNativeUnits);
+ } else {
+ // This should have errored already in the constructor.
+ assert false;
+ }
+ }
+
+ /**
+ * Get the rate of the encoder.
+ *
+ * @return the rate of change
+ */
+ public double getRate() {
+ return m_encoder.getRate();
+ }
+
+ /** Resets all simulation data for this encoder. */
+ public void resetData() {
+ setDistance(0);
+ setRate(0);
+ }
+}
--- /dev/null
+{
+ "fileName": "PathplannerLib.json",
+ "name": "PathplannerLib",
+ "version": "2023.0.1",
+ "uuid": "1b42324f-17c6-4875-8e77-1c312bc8c786",
+ "mavenUrls": [
+ "https://3015rangerrobotics.github.io/pathplannerlib/repo"
+ ],
+ "jsonUrl": "https://3015rangerrobotics.github.io/pathplannerlib/PathplannerLib.json",
+ "javaDependencies": [
+ {
+ "groupId": "com.pathplanner.lib",
+ "artifactId": "PathplannerLib-java",
+ "version": "2023.0.1"
+ }
+ ],
+ "jniDependencies": [],
+ "cppDependencies": [
+ {
+ "groupId": "com.pathplanner.lib",
+ "artifactId": "PathplannerLib-cpp",
+ "version": "2023.0.1",
+ "libName": "PathplannerLib",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64",
+ "linuxathena"
+ ]
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "fileName": "Phoenix.json",
+ "name": "CTRE-Phoenix",
+ "version": "5.21.2",
+ "frcYear": 2022,
+ "uuid": "ab676553-b602-441f-a38d-f1296eff6537",
+ "mavenUrls": [
+ "https://maven.ctr-electronics.com/release/"
+ ],
+ "jsonUrl": "https://maven.ctr-electronics.com/release/com/ctre/phoenix/Phoenix-frc2022-latest.json",
+ "javaDependencies": [
+ {
+ "groupId": "com.ctre.phoenix",
+ "artifactId": "api-java",
+ "version": "5.21.2"
+ },
+ {
+ "groupId": "com.ctre.phoenix",
+ "artifactId": "wpiapi-java",
+ "version": "5.21.2"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.ctre.phoenix",
+ "artifactId": "cci",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "linuxathena"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "cci-sim",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simTalonSRX",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simTalonFX",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simVictorSPX",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simCANCoder",
+ "version": "5.21.2",
+ "isJar": false,
+ "skipInvalidPlatforms": true,
+ "validPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.ctre.phoenix",
+ "artifactId": "wpiapi-cpp",
+ "version": "5.21.2",
+ "libName": "CTRE_Phoenix_WPI",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "linuxathena"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix",
+ "artifactId": "api-cpp",
+ "version": "5.21.2",
+ "libName": "CTRE_Phoenix",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "linuxathena"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix",
+ "artifactId": "cci",
+ "version": "5.21.2",
+ "libName": "CTRE_PhoenixCCI",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "linuxathena"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "wpiapi-cpp-sim",
+ "version": "5.21.2",
+ "libName": "CTRE_Phoenix_WPISim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "api-cpp-sim",
+ "version": "5.21.2",
+ "libName": "CTRE_PhoenixSim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "cci-sim",
+ "version": "5.21.2",
+ "libName": "CTRE_PhoenixCCISim",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simTalonSRX",
+ "version": "5.21.2",
+ "libName": "CTRE_SimTalonSRX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simTalonFX",
+ "version": "5.21.2",
+ "libName": "CTRE_SimTalonFX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simVictorSPX",
+ "version": "5.21.2",
+ "libName": "CTRE_SimVictorSPX",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simPigeonIMU",
+ "version": "5.21.2",
+ "libName": "CTRE_SimPigeonIMU",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.ctre.phoenix.sim",
+ "artifactId": "simCANCoder",
+ "version": "5.21.2",
+ "libName": "CTRE_SimCANCoder",
+ "headerClassifier": "headers",
+ "sharedLibrary": true,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "fileName": "REVLib.json",
+ "name": "REVLib",
+ "version": "2022.1.1",
+ "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb",
+ "mavenUrls": [
+ "https://maven.revrobotics.com/"
+ ],
+ "jsonUrl": "https://software-metadata.revrobotics.com/REVLib.json",
+ "javaDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-java",
+ "version": "2022.1.1"
+ }
+ ],
+ "jniDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-driver",
+ "version": "2022.1.1",
+ "skipInvalidPlatforms": true,
+ "isJar": false,
+ "validPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxaarch64bionic",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxraspbian",
+ "osxx86-64"
+ ]
+ }
+ ],
+ "cppDependencies": [
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-cpp",
+ "version": "2022.1.1",
+ "libName": "REVLib",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxaarch64bionic",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxraspbian",
+ "osxx86-64"
+ ]
+ },
+ {
+ "groupId": "com.revrobotics.frc",
+ "artifactId": "REVLib-driver",
+ "version": "2022.1.1",
+ "libName": "REVLibDriver",
+ "headerClassifier": "headers",
+ "sharedLibrary": false,
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "windowsx86-64",
+ "windowsx86",
+ "linuxaarch64bionic",
+ "linuxx86-64",
+ "linuxathena",
+ "linuxraspbian",
+ "osxx86-64"
+ ]
+ }
+ ]
+}
\ No newline at end of file
--- /dev/null
+{
+ "fileName": "WPILibNewCommands.json",
+ "name": "WPILib-New-Commands",
+ "version": "2020.0.0",
+ "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
+ "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",
+ "linuxraspbian",
+ "linuxaarch64bionic",
+ "windowsx86-64",
+ "windowsx86",
+ "linuxx86-64",
+ "osxx86-64"
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "fileName": "navx_frc.json",
+ "name": "KauaiLabs_navX_FRC",
+ "version": "4.0.447",
+ "uuid": "cb311d09-36e9-4143-a032-55bb2b94443b",
+ "mavenUrls": [
+ "https://repo1.maven.org/maven2/"
+ ],
+ "jsonUrl": "https://www.kauailabs.com/dist/frc/2022/navx_frc.json",
+ "javaDependencies": [
+ {
+ "groupId": "com.kauailabs.navx.frc",
+ "artifactId": "navx-java",
+ "version": "4.0.447"
+ }
+ ],
+ "jniDependencies": [],
+ "cppDependencies": [
+ {
+ "groupId": "com.kauailabs.navx.frc",
+ "artifactId": "navx-cpp",
+ "version": "4.0.447",
+ "headerClassifier": "headers",
+ "sourcesClassifier": "sources",
+ "sharedLibrary": false,
+ "libName": "navx_frc",
+ "skipInvalidPlatforms": true,
+ "binaryPlatforms": [
+ "linuxathena",
+ "linuxraspbian",
+ "windowsx86-64"
+ ]
+ }
+ ]
+}
\ No newline at end of file