first commit
This commit is contained in:
+187
@@ -0,0 +1,187 @@
|
||||
# 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
|
||||
networktables.json
|
||||
simgui.json
|
||||
*-window.json
|
||||
|
||||
# Simulation data log directory
|
||||
logs/
|
||||
|
||||
# Folder that has CTRE Phoenix Sim device config storage
|
||||
ctre_sim/
|
||||
|
||||
# clangd
|
||||
/.cache
|
||||
compile_commands.json
|
||||
|
||||
# Eclipse generated file for annotation processors
|
||||
.factorypath
|
||||
Vendored
+21
@@ -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,
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"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",
|
||||
"java.import.gradle.annotationProcessing.enabled": false,
|
||||
"java.completion.favoriteStaticMembers": [
|
||||
"org.junit.Assert.*",
|
||||
"org.junit.Assume.*",
|
||||
"org.junit.jupiter.api.Assertions.*",
|
||||
"org.junit.jupiter.api.Assumptions.*",
|
||||
"org.junit.jupiter.api.DynamicContainer.*",
|
||||
"org.junit.jupiter.api.DynamicTest.*",
|
||||
"org.mockito.Mockito.*",
|
||||
"org.mockito.ArgumentMatchers.*",
|
||||
"org.mockito.Answers.*",
|
||||
"edu.wpi.first.units.Units.*"
|
||||
],
|
||||
"java.completion.filteredTypes": [
|
||||
"java.awt.*",
|
||||
"com.sun.*",
|
||||
"sun.*",
|
||||
"jdk.*",
|
||||
"org.graalvm.*",
|
||||
"io.micrometer.shaded.*",
|
||||
"java.beans.*",
|
||||
"java.util.Base64.*",
|
||||
"java.util.Timer",
|
||||
"java.sql.*",
|
||||
"javax.swing.*",
|
||||
"javax.management.*",
|
||||
"javax.smartcardio.*",
|
||||
"edu.wpi.first.math.proto.*",
|
||||
"edu.wpi.first.math.**.proto.*",
|
||||
"edu.wpi.first.math.**.struct.*",
|
||||
],
|
||||
"java.dependency.enableDependencyCheckup": false
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"enableCppIntellisense": false,
|
||||
"currentLanguage": "java",
|
||||
"projectYear": "2026",
|
||||
"teamNumber": 6494
|
||||
}␍
|
||||
@@ -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.
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
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'
|
||||
deleteOldFiles = false // Change to true to delete files on roboRIO that no
|
||||
// longer exist in deploy directory of this project
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def deployArtifact = deploy.targets.roborio.artifacts.frcJava
|
||||
|
||||
// Set to true to use debug for all targets including JNI, which will drastically impact
|
||||
// performance.
|
||||
wpi.java.debugJni = false
|
||||
|
||||
// Set this to true to enable desktop support.
|
||||
def includeDesktopSupport = true
|
||||
|
||||
// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
|
||||
// Also defines JUnit 5.
|
||||
dependencies {
|
||||
annotationProcessor wpi.java.deps.wpilibAnnotations()
|
||||
implementation wpi.java.deps.wpilib()
|
||||
implementation wpi.java.vendor.java()
|
||||
|
||||
roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio)
|
||||
roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio)
|
||||
|
||||
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:5.10.1'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
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'
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=permwrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=permwrapper/dists
|
||||
@@ -0,0 +1,252 @@
|
||||
#!/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.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# 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/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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 -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || 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" "$@"
|
||||
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
@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
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@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. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
: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
|
||||
@@ -0,0 +1,30 @@
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
String frcYear = '2026'
|
||||
File frcHome
|
||||
if (OperatingSystem.current().isWindows()) {
|
||||
String publicFolder = System.getenv('PUBLIC')
|
||||
if (publicFolder == null) {
|
||||
publicFolder = "C:\\Users\\Public"
|
||||
}
|
||||
def homeRoot = new File(publicFolder, "wpilib")
|
||||
frcHome = new File(homeRoot, frcYear)
|
||||
} else {
|
||||
def userFolder = System.getProperty("user.home")
|
||||
def homeRoot = new File(userFolder, "wpilib")
|
||||
frcHome = new File(homeRoot, frcYear)
|
||||
}
|
||||
def frcHomeMaven = new File(frcHome, 'maven')
|
||||
maven {
|
||||
name 'frcHome'
|
||||
url frcHomeMaven
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Properties props = System.getProperties();
|
||||
props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true");
|
||||
@@ -0,0 +1,3 @@
|
||||
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.
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Line"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": false,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Line"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "LineBack"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 1.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": false,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Rotate"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": false,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "RotateAndLine"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": false,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 4.15
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 14.299415121255347,
|
||||
"y": 4.61077032810271
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": "StartingPointRed1"
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 6.668017118402283
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 14.247660485021397,
|
||||
"y": 6.305734664764623
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 6.668017118402283
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 14.299415121255347,
|
||||
"y": 7.128787446504993
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": "Point1"
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 4.15
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 14.299415121255347,
|
||||
"y": 4.597831669044222
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": "StartingPointRed2"
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 4.15
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 14.064,
|
||||
"y": 4.15
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": "StartingPointRed1"
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 4.15
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 14.650181888846735,
|
||||
"y": 4.15
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 4.15
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 14.312353780313838,
|
||||
"y": 4.74015691868759
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": "StartingPointRed1"
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 14.314,
|
||||
"y": 6.357489300998574
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 14.312353780313838,
|
||||
"y": 6.098716119828817
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"robotWidth": 0.85,
|
||||
"robotLength": 0.85,
|
||||
"holonomicMode": true,
|
||||
"pathFolders": [],
|
||||
"autoFolders": [],
|
||||
"defaultMaxVel": 1.5,
|
||||
"defaultMaxAccel": 3.0,
|
||||
"defaultMaxAngVel": 360.0,
|
||||
"defaultMaxAngAccel": 720.0,
|
||||
"defaultNominalVoltage": 12.0,
|
||||
"robotMass": 30.0,
|
||||
"robotMOI": 3.6,
|
||||
"robotTrackwidth": 0.546,
|
||||
"driveWheelRadius": 0.045,
|
||||
"driveGearing": 5.902,
|
||||
"maxDriveSpeed": 4.89,
|
||||
"driveMotorType": "krakenX60",
|
||||
"driveCurrentLimit": 40.0,
|
||||
"wheelCOF": 1.2,
|
||||
"flModuleX": 0.289,
|
||||
"flModuleY": 0.289,
|
||||
"frModuleX": 0.289,
|
||||
"frModuleY": -0.289,
|
||||
"blModuleX": -0.289,
|
||||
"blModuleY": 0.289,
|
||||
"brModuleX": -0.289,
|
||||
"brModuleY": -0.289,
|
||||
"bumperOffsetX": 0.0,
|
||||
"bumperOffsetY": 0.0,
|
||||
"robotFeatures": [
|
||||
"{\"name\":\"Circle\",\"type\":\"circle\",\"data\":{\"center\":{\"x\":0.0,\"y\":0.0},\"radius\":0.1,\"strokeWidth\":0.02,\"filled\":false}}"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package frc.robot;
|
||||
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import edu.wpi.first.math.geometry.Pose2d;
|
||||
|
||||
public final class Constants {
|
||||
public static final boolean LEDUsing = false;
|
||||
public class Shooter {
|
||||
public static final double conveyorSpeedkP = 10;
|
||||
public static final Slot0Configs flyWheelSlot0Configs = new Slot0Configs()
|
||||
.withKP(0.0).withKI(0).withKD(0)
|
||||
.withKV(0.1).withKA(0.0).withKS(0.15);
|
||||
|
||||
public static final Slot0Configs conveyorSlot0Configs = new Slot0Configs()
|
||||
.withKP(0.0).withKI(0).withKD(0)
|
||||
.withKV(0.02).withKA(0.15).withKS(0);
|
||||
|
||||
public static final Slot0Configs backboardSlot0Configs = new Slot0Configs()
|
||||
.withKP(0.01).withKI(0).withKD(0)
|
||||
.withKV(0.008).withKA(0.0).withKS(0.010);
|
||||
|
||||
public class backboardPositionPID {
|
||||
public static final double kP = 0.1;
|
||||
public static final double kI = 0.0;
|
||||
public static final double kD = 0.0;
|
||||
|
||||
}
|
||||
public static final double backboardSpeedMax = 60; //也就是output
|
||||
// 背板的上下限位角度
|
||||
public static final double backboardUpLimit = 3000.0; // 背板上限角度(根据实际需求设置)
|
||||
public static final double backboardDownLimit = 0.0; // 背板下限角度(根据实际需求设置)
|
||||
}
|
||||
public class ShooterCalculation{
|
||||
public static final double positionNear = 0; // 近距离背板角度
|
||||
public static final double positionMid = 1600; // 中距离背板角度
|
||||
public static final double postionFar = 3200; // 远距离背板角度
|
||||
}
|
||||
public class AutoRotation {
|
||||
public static final boolean autoRotationToHubEnabled = true;
|
||||
public static final double autoRotationToHubkP = 0.12;
|
||||
public static final boolean autoRotationForBump = false;
|
||||
public static final double autoRotationForBumpkP = 0.2;
|
||||
public static final double autoRotationForBumpTargetDegrees = 45;
|
||||
|
||||
public static final boolean teleopOffsetEnabled = true;
|
||||
public static final double teleopOffsetkP = 15;
|
||||
}
|
||||
|
||||
public class StartingPoints{
|
||||
public class Red{
|
||||
public static final Pose2d Point1 = new Pose2d(12.93, 7.47, edu.wpi.first.math.geometry.Rotation2d.fromDegrees(0));
|
||||
public static final Pose2d Point2 = new Pose2d(14.314, 4.15, edu.wpi.first.math.geometry.Rotation2d.fromDegrees(-180));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public enum DriveMode {
|
||||
ROBOT_CENTRIC,
|
||||
FIELD_CENTRIC,
|
||||
SYSID,
|
||||
OTHER
|
||||
}
|
||||
public class Pigeon {
|
||||
public static final int CANID = 0;
|
||||
}
|
||||
|
||||
public class Limelight {
|
||||
public static final String LIMELIGHT_NAME = "limelight-zy";
|
||||
}
|
||||
|
||||
public class Field {
|
||||
public static final double RedHubPositionX = 11.914;
|
||||
public static final double RedHubPositionY = 4.034;
|
||||
|
||||
}
|
||||
|
||||
public class Intaker {
|
||||
|
||||
public static final double intakeRotaterUpLimit = 0.0; // rotator上限角度
|
||||
public static final double intakeRotaterDownLimit = 0.0; // rotator下限角度
|
||||
|
||||
public static final Slot0Configs intakeGetterSlot0Configs = new Slot0Configs()
|
||||
.withKP(0.00).withKI(0.00).withKD(0.00)
|
||||
.withKV(0.00).withKA(0.00).withKS(0.00);
|
||||
// getter 如果你只用固定速度开关,也可以先不启闭环;若用闭环速度,这里 kP/kV/KS 等需要实测调参(这句fromAI)
|
||||
|
||||
public static final Slot0Configs intakeRotaterSlot0Configs = new Slot0Configs()
|
||||
.withKP(0.00).withKI(0.00).withKD(0.00)
|
||||
.withKV(0.00).withKA(0.00).withKS(0.00);
|
||||
//如果 rotater 受重力影响明显,可能需要用 withKG/withGravityType/withGravityArmPositionOffset(看机构形式)(这句fromAI)
|
||||
|
||||
public static final double IntakeGetterSpeed = 0.0;
|
||||
// 单位RPS
|
||||
public static final double positionToleranceRotations = 0.00;
|
||||
//rotater容差
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
|
||||
public final class Main {
|
||||
private Main() {}
|
||||
|
||||
public static void main(String... args) {
|
||||
RobotBase.startRobot(Robot::new);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// 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.TimedRobot;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.CommandScheduler;
|
||||
|
||||
public class Robot extends TimedRobot {
|
||||
private Command m_autonomousCommand;
|
||||
|
||||
private final RobotContainer m_robotContainer;
|
||||
|
||||
public Robot() {
|
||||
m_robotContainer = new RobotContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void robotPeriodic() {
|
||||
CommandScheduler.getInstance().run();
|
||||
m_robotContainer.tunerPeriodic();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disabledInit() {}
|
||||
|
||||
@Override
|
||||
public void disabledPeriodic() {}
|
||||
|
||||
@Override
|
||||
public void disabledExit() {}
|
||||
|
||||
@Override
|
||||
public void autonomousInit() {
|
||||
m_autonomousCommand = m_robotContainer.getAutonomousCommand();
|
||||
|
||||
if (m_autonomousCommand != null) {
|
||||
CommandScheduler.getInstance().schedule(m_autonomousCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void autonomousPeriodic() {}
|
||||
|
||||
@Override
|
||||
public void autonomousExit() {}
|
||||
|
||||
@Override
|
||||
public void teleopInit() {
|
||||
if (m_autonomousCommand != null) {
|
||||
CommandScheduler.getInstance().cancel(m_autonomousCommand);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void teleopPeriodic() {}
|
||||
|
||||
@Override
|
||||
public void teleopExit() {}
|
||||
|
||||
@Override
|
||||
public void testInit() {
|
||||
CommandScheduler.getInstance().cancelAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testPeriodic() {}
|
||||
|
||||
@Override
|
||||
public void testExit() {}
|
||||
|
||||
@Override
|
||||
public void simulationPeriodic() {}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package frc.robot;
|
||||
|
||||
import com.ctre.phoenix6.SignalLogger;
|
||||
import com.pathplanner.lib.auto.AutoBuilder;
|
||||
|
||||
import edu.wpi.first.math.geometry.Pose2d;
|
||||
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.Commands;
|
||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||
import edu.wpi.first.wpilibj2.command.button.RobotModeTriggers;
|
||||
import frc.robot.controls.DriveControls;
|
||||
import frc.robot.controls.ShooterControls;
|
||||
import frc.robot.generated.TunerConstants;
|
||||
import frc.robot.subsystems.CommandSwerveDrivetrain;
|
||||
import frc.robot.subsystems.LEDSubsystem;
|
||||
import frc.robot.subsystems.ShooterSubsystem;
|
||||
import frc.robot.tuning.ConfigTalonFXMotorTuner;
|
||||
import frc.robot.tuning.ConfigTalonFXSMotorTuner;
|
||||
import frc.robot.tuning.DriveGainsTuner;
|
||||
import frc.robot.utils.LedBindings;
|
||||
|
||||
public class RobotContainer {
|
||||
|
||||
/* ====================== */
|
||||
/* 手柄 */
|
||||
/* ====================== */
|
||||
|
||||
// 只使用一个 Xbox 手柄(端口 0)
|
||||
private final CommandXboxController controller = new CommandXboxController(0);
|
||||
|
||||
/* ====================== */
|
||||
/* 子系统 */
|
||||
/* ====================== */
|
||||
|
||||
// Phoenix TunerX 生成的底盘
|
||||
public final CommandSwerveDrivetrain drivetrain = TunerConstants.createDrivetrain();
|
||||
public final ShooterSubsystem shooterSubsystem = new ShooterSubsystem();
|
||||
|
||||
// LED 子系统
|
||||
private final LEDSubsystem leds = new LEDSubsystem(0, 72 ,0); // 总长度=72+72
|
||||
|
||||
/* ====================== */
|
||||
/* 控制封装/日志 */
|
||||
/* ====================== */
|
||||
|
||||
private final DriveControls driveControls = new DriveControls(drivetrain, controller);
|
||||
private final ShooterControls shooterControls = new ShooterControls(shooterSubsystem, controller);
|
||||
|
||||
private final DriveGainsTuner driveGainsTuner = new DriveGainsTuner(drivetrain);
|
||||
private ConfigTalonFXMotorTuner configFlywheelTuner = new ConfigTalonFXMotorTuner(shooterSubsystem.flywheelMotorLeft, "flywheel", Constants.Shooter.flyWheelSlot0Configs);
|
||||
private ConfigTalonFXMotorTuner configConveyorTuner = new ConfigTalonFXMotorTuner(shooterSubsystem.conveyorMotor, "conveyor", Constants.Shooter.conveyorSlot0Configs);
|
||||
private ConfigTalonFXSMotorTuner configBackboardTuner = new ConfigTalonFXSMotorTuner(shooterSubsystem.backboardMotor, "backboard", Constants.Shooter.backboardSlot0Configs);
|
||||
|
||||
private final SendableChooser<Command> autoChooser;
|
||||
|
||||
public RobotContainer() {
|
||||
SignalLogger.enableAutoLogging(false);
|
||||
autoChooser = AutoBuilder.buildAutoChooser();
|
||||
SmartDashboard.putData("Auto Chooser", autoChooser);
|
||||
configueSwerve();
|
||||
configueShooter();
|
||||
bingdingLED();
|
||||
}
|
||||
|
||||
/* ====================== */
|
||||
/* 底盘配置 */
|
||||
/* ====================== */
|
||||
|
||||
private void configueSwerve() {
|
||||
Pose2d startingPose = Constants.StartingPoints.Red.Point2;
|
||||
drivetrain.resetPose(startingPose);
|
||||
|
||||
// 默认驾驶命令
|
||||
drivetrain.setDefaultCommand(driveControls.defaultDriveCommand());
|
||||
|
||||
// Disabled 时进入 idle(防止模块乱动)
|
||||
RobotModeTriggers.disabled().whileTrue(driveControls.idleCommand());
|
||||
|
||||
|
||||
//左保险:按住刹车
|
||||
controller.leftBumper()
|
||||
.onTrue(Commands.runOnce(driveControls::emergencyStop))
|
||||
.whileTrue(driveControls.brakeWhileHeld());
|
||||
|
||||
// Back:重置场地坐标系
|
||||
controller.back().onTrue(drivetrain.runOnce(drivetrain::seedFieldCentric));
|
||||
|
||||
// Start:切换场地/车体坐标系
|
||||
controller.start().onTrue(Commands.runOnce(driveControls::toggleDriveFrame));
|
||||
|
||||
// 右保险:按住加速(Boost)
|
||||
controller.rightBumper()
|
||||
.onTrue(Commands.runOnce(() -> driveControls.setBoostEnabled(true)))
|
||||
.onFalse(Commands.runOnce(() -> driveControls.setBoostEnabled(false)));
|
||||
|
||||
controller.a().whileTrue(drivetrain.runOnce(drivetrain::forceUsingLimelightMT2));
|
||||
|
||||
}
|
||||
|
||||
private void configueShooter(){
|
||||
shooterSubsystem.setDefaultCommand(shooterControls.defaultShooterCommand());
|
||||
|
||||
controller.povLeft().onTrue(Commands.runOnce(() -> shooterControls.adjustFlywheelSpeedOffset(-5)));
|
||||
controller.povRight().onTrue(Commands.runOnce(() -> shooterControls.adjustFlywheelSpeedOffset(5)));
|
||||
controller.povUp().onTrue(Commands.runOnce(() -> shooterControls.adjustBackboardRateOffset(1500)));
|
||||
controller.povDown().onTrue(Commands.runOnce(() -> shooterControls.adjustBackboardRateOffset(-1500)));
|
||||
|
||||
controller.b().onTrue(shooterControls.resetBackboardCommand());
|
||||
}
|
||||
|
||||
/* ====================== */
|
||||
/* LED 绑定 */
|
||||
/* ====================== */
|
||||
|
||||
private void bingdingLED() {
|
||||
LedBindings.bindModeIndicators(leds);
|
||||
}
|
||||
|
||||
public Command getAutonomousCommand() {
|
||||
|
||||
return autoChooser.getSelected();
|
||||
}
|
||||
|
||||
public void tunerPeriodic() {
|
||||
driveGainsTuner.periodic();
|
||||
configFlywheelTuner.periodic(() -> shooterSubsystem.applyLeftConfigurationToRight());
|
||||
configConveyorTuner.periodic(null);
|
||||
configBackboardTuner.periodic();
|
||||
shooterSubsystem.setRightFollowLeft();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package frc.robot.controls;
|
||||
import static edu.wpi.first.units.Units.MetersPerSecond;
|
||||
import static edu.wpi.first.units.Units.RotationsPerSecond;
|
||||
import com.ctre.phoenix6.swerve.SwerveModule.DriveRequestType;
|
||||
import com.ctre.phoenix6.swerve.SwerveRequest;
|
||||
|
||||
import edu.wpi.first.math.filter.SlewRateLimiter;
|
||||
import edu.wpi.first.math.geometry.Pose2d;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.Constants.DriveMode;
|
||||
import frc.robot.generated.TunerConstants;
|
||||
import frc.robot.subsystems.CommandSwerveDrivetrain;
|
||||
|
||||
public class DriveControls {
|
||||
private final CommandSwerveDrivetrain drivetrain;
|
||||
private final CommandXboxController driver;
|
||||
|
||||
private final double maxSpeed = TunerConstants.kSpeedAt12Volts.in(MetersPerSecond);
|
||||
private final double maxAngularRate = RotationsPerSecond.of(0.75).in(edu.wpi.first.units.Units.RadiansPerSecond);
|
||||
|
||||
// 默认速度比例(平时开车)
|
||||
private double normalDriveScale = 0.3;
|
||||
private double normalTurnScale = 0.7;
|
||||
|
||||
// 加速模式比例(按住 RB)
|
||||
private double boostDriveScale = 1.0;
|
||||
private double boostTurnScale = 1.0;
|
||||
|
||||
private boolean boostEnabled = false;
|
||||
|
||||
private final SlewRateLimiter vxLimiter = new SlewRateLimiter(5.0); // m/s^2 等效(调)
|
||||
private final SlewRateLimiter vyLimiter = new SlewRateLimiter(5.0);
|
||||
private final SlewRateLimiter omegaLimiter = new SlewRateLimiter(9.0); // rad/s^2 等效(调)
|
||||
|
||||
// ====== 类成员变量里新增:记录上一次输出 ======
|
||||
private double lastVx = 0.0;
|
||||
private double lastVy = 0.0;
|
||||
private double lastOmega = 0.0;
|
||||
|
||||
private NetworkTable autoControlNetworkTable;
|
||||
|
||||
public void setBoostEnabled(boolean enabled) {
|
||||
boostEnabled = enabled;
|
||||
}
|
||||
|
||||
// 新增:当前是否使用场地坐标系(默认 true)
|
||||
private boolean fieldCentricEnabled = true;
|
||||
|
||||
private final SwerveRequest.FieldCentric fieldCentric =
|
||||
new SwerveRequest.FieldCentric()
|
||||
.withDeadband(maxSpeed * 0.05)
|
||||
.withRotationalDeadband(maxAngularRate * 0.05)
|
||||
.withDriveRequestType(DriveRequestType.Velocity);
|
||||
|
||||
private final SwerveRequest.RobotCentric robotCentric =
|
||||
new SwerveRequest.RobotCentric()
|
||||
.withDeadband(maxSpeed * 0.05)
|
||||
.withRotationalDeadband(maxAngularRate * 0.05)
|
||||
.withDriveRequestType(DriveRequestType.Velocity);
|
||||
|
||||
public DriveControls(CommandSwerveDrivetrain drivetrain, CommandXboxController driver) {
|
||||
this.drivetrain = drivetrain;
|
||||
this.driver = driver;
|
||||
autoControlNetworkTable = NetworkTableInstance.getDefault().getTable("AutoControl");
|
||||
}
|
||||
|
||||
public void toggleDriveFrame() {
|
||||
fieldCentricEnabled = !fieldCentricEnabled;
|
||||
}
|
||||
|
||||
public boolean isFieldCentricEnabled() {
|
||||
return fieldCentricEnabled;
|
||||
}
|
||||
public DriveMode getCurrentDriveMode() {
|
||||
return fieldCentricEnabled ? DriveMode.FIELD_CENTRIC : DriveMode.ROBOT_CENTRIC;
|
||||
}
|
||||
/** 底盘的默认驾驶命令(teleop 期间持续执行) */
|
||||
public Command defaultDriveCommand() {
|
||||
return drivetrain.applyRequest(() -> {
|
||||
double driveScale = boostEnabled ? boostDriveScale : normalDriveScale;
|
||||
double turnScale = boostEnabled ? boostTurnScale : normalTurnScale;
|
||||
|
||||
double vx = -driver.getLeftY() * maxSpeed * driveScale;
|
||||
double vy = -driver.getLeftX() * maxSpeed * driveScale;
|
||||
double omega = -driver.getRightX() * maxAngularRate * turnScale;
|
||||
|
||||
// ====== execute 内替换 limiter:只限加速、不限减速 ======
|
||||
double limitedVx = limitAccelOnly(vx, lastVx, vxLimiter);
|
||||
double limitedVy = limitAccelOnly(vy, lastVy, vyLimiter);
|
||||
double limitedOmega = limitAccelOnly(omega, lastOmega, omegaLimiter);
|
||||
|
||||
lastVx = limitedVx;
|
||||
lastVy = limitedVy;
|
||||
lastOmega = limitedOmega;
|
||||
|
||||
vx = limitedVx;
|
||||
vy = limitedVy;
|
||||
omega = limitedOmega;
|
||||
|
||||
double[] distanceAndRotation = calculateDistanceAndRotationToHub();
|
||||
// 将距离值写入 NetworkTable
|
||||
autoControlNetworkTable.getEntry("distanceToHub").setDouble(distanceAndRotation[0]);
|
||||
autoControlNetworkTable.getEntry("angleDifferenceToHub").setDouble(distanceAndRotation[1]);
|
||||
|
||||
if(Constants.AutoRotation.autoRotationToHubEnabled) {
|
||||
double autoRotationPower = driver.getLeftTriggerAxis();
|
||||
if(autoRotationPower > 0.1) {
|
||||
autoControlNetworkTable.getEntry("autoRotationAvailable").setBoolean(true);
|
||||
|
||||
double angleDifference = distanceAndRotation[1];
|
||||
|
||||
// Calculate rotation speed using the angle difference
|
||||
omega = calculateRotationSpeedFromRotationAngle(angleDifference, autoRotationPower);
|
||||
|
||||
autoControlNetworkTable.getEntry("autoRotationRate").setDouble(omega);
|
||||
} else {
|
||||
autoControlNetworkTable.getEntry("autoRotationAvailable").setBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (fieldCentricEnabled) {
|
||||
return fieldCentric
|
||||
.withVelocityX(vx)
|
||||
.withVelocityY(vy)
|
||||
.withRotationalRate(omega);
|
||||
} else {
|
||||
return robotCentric
|
||||
.withVelocityX(vx)
|
||||
.withVelocityY(vy)
|
||||
.withRotationalRate(omega);
|
||||
}
|
||||
}, () -> fieldCentricEnabled ? DriveMode.FIELD_CENTRIC : DriveMode.ROBOT_CENTRIC);
|
||||
}
|
||||
|
||||
// Calculate distance and rotation (angle difference)
|
||||
public double[] calculateDistanceAndRotationToHub() {
|
||||
Pose2d currentPose = drivetrain.getState().Pose; // 获取机器人当前的位置和角度
|
||||
double targetX = Constants.Field.RedHubPositionX; // 目标 X 坐标
|
||||
double targetY = Constants.Field.RedHubPositionY; // 目标 Y 坐标
|
||||
|
||||
// 计算目标角度(相对于场地坐标系)
|
||||
double deltaX = targetX - currentPose.getX();
|
||||
double deltaY = targetY - currentPose.getY();
|
||||
double targetAngle = Math.toDegrees(Math.atan2(deltaY, deltaX)); // 转换为度
|
||||
|
||||
// 当前机器人角度
|
||||
double currentAngle = currentPose.getRotation().getDegrees();
|
||||
double angleDifference = targetAngle - currentAngle;
|
||||
// Normalize angle difference to the range [-180, 180]
|
||||
if (angleDifference > 180) {
|
||||
angleDifference -= 360;
|
||||
} else if (angleDifference < -180) {
|
||||
angleDifference += 360;
|
||||
}
|
||||
|
||||
// 计算距离
|
||||
double distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
|
||||
// 计算距离和旋转角度
|
||||
double[] distanceAndRotation = new double[]{distance, angleDifference};
|
||||
|
||||
// 返回距离和角度差
|
||||
return distanceAndRotation;
|
||||
}
|
||||
|
||||
// Calculate rotation speed from rotation angle difference
|
||||
public double calculateRotationSpeedFromRotationAngle(double angleDifference, double autoRotationPower) {
|
||||
double calDifference = angleDifference;
|
||||
|
||||
// Optional: Apply teleop offset if enabled
|
||||
if (Constants.AutoRotation.teleopOffsetEnabled) {
|
||||
double teleopOffset = -driver.getRightX();
|
||||
calDifference += teleopOffset * Constants.AutoRotation.teleopOffsetkP;
|
||||
}
|
||||
|
||||
// If angle difference is within threshold, don't rotate
|
||||
if (Math.abs(calDifference) > 1.0) {
|
||||
return calDifference * autoRotationPower * Constants.AutoRotation.autoRotationToHubkP;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 只限制“加速”(幅值变大),不限制“减速”(幅值变小)
|
||||
* 这样松杆/刹车会更及时,同时 boost 仍然能抑制电流冲击
|
||||
*/
|
||||
private double limitAccelOnly(double target, double last, SlewRateLimiter limiter) {
|
||||
// 如果正在减速(幅值变小),直接放行到目标值
|
||||
if (Math.abs(target) < Math.abs(last)) {
|
||||
limiter.reset(target); // 同步 limiter 内部状态,防止下一次突变
|
||||
return target;
|
||||
}
|
||||
// 否则是加速,使用 limiter
|
||||
return limiter.calculate(target);
|
||||
}
|
||||
|
||||
/** 紧急停止:清零限速器,让速度输出立刻归零 */
|
||||
public void emergencyStop() {
|
||||
vxLimiter.reset(0.0);
|
||||
vyLimiter.reset(0.0);
|
||||
omegaLimiter.reset(0.0);
|
||||
|
||||
lastVx = 0.0;
|
||||
lastVy = 0.0;
|
||||
lastOmega = 0.0;
|
||||
}
|
||||
|
||||
public Command idleCommand() {
|
||||
final var idle = new SwerveRequest.Idle();
|
||||
return drivetrain.applyRequest(() -> idle).ignoringDisable(true);
|
||||
}
|
||||
|
||||
public Command brakeWhileHeld() {
|
||||
final var brake = new SwerveRequest.SwerveDriveBrake();
|
||||
return drivetrain.applyRequest(() -> brake);
|
||||
}
|
||||
|
||||
|
||||
public SwerveRequest.SwerveDriveBrake brakeRequest() {
|
||||
return new SwerveRequest.SwerveDriveBrake();
|
||||
}
|
||||
|
||||
public SwerveRequest.Idle idleRequest() {
|
||||
return new SwerveRequest.Idle();
|
||||
}
|
||||
|
||||
public double getMaxSpeed() {
|
||||
return maxSpeed;
|
||||
}
|
||||
|
||||
public double getMaxAngularRate() {
|
||||
return maxAngularRate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package frc.robot.controls;
|
||||
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||
import frc.robot.subsystems.IntakerSubsystem;
|
||||
|
||||
public class IntakerControls {
|
||||
private final IntakerSubsystem intakerSubsystem;
|
||||
private final CommandXboxController controller;
|
||||
|
||||
private static final double ROTATER_STEP_PER_CYCLE = 0.00; // 需要你按实际速度调:越大越快(fromAI)
|
||||
|
||||
public IntakerControls(IntakerSubsystem intakerSubsystem, CommandXboxController controller) {
|
||||
this.intakerSubsystem = intakerSubsystem;
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public void configureBindings() {
|
||||
|
||||
//B.A:按住下降 + getter转;松开后 rotater保持当前位置,getter继续转
|
||||
controller.a()
|
||||
.whileTrue(
|
||||
Commands.run(() -> {
|
||||
// rotater下降:范围会被 subsystem 限制
|
||||
double cur = intakerSubsystem.getIntakerotaterPosition();
|
||||
intakerSubsystem.setIntakerRotaterPosition(cur - ROTATER_STEP_PER_CYCLE);
|
||||
|
||||
// getter 开
|
||||
intakerSubsystem.setIntakeGetterOn(true);
|
||||
}, intakerSubsystem)
|
||||
)
|
||||
.onFalse(
|
||||
Commands.runOnce(() -> {
|
||||
// 松:把当前位置作为target保持
|
||||
double cur = intakerSubsystem.getIntakerotaterPosition();
|
||||
intakerSubsystem.setIntakerRotaterPosition(cur);
|
||||
|
||||
// gtter继续转
|
||||
intakerSubsystem.setIntakeGetterOn(true);
|
||||
}, intakerSubsystem)
|
||||
);
|
||||
|
||||
// === B.B:按住上升+getter停;松开后rotater保持当前位置
|
||||
controller.b()
|
||||
.whileTrue(
|
||||
Commands.run(() -> {
|
||||
// rotater升
|
||||
double cur = intakerSubsystem.getIntakerotaterPosition();
|
||||
intakerSubsystem.setIntakerRotaterPosition(cur + ROTATER_STEP_PER_CYCLE);
|
||||
|
||||
// getter关
|
||||
intakerSubsystem.setIntakeGetterOn(false);
|
||||
}, intakerSubsystem)
|
||||
)
|
||||
.onFalse(
|
||||
Commands.runOnce(() -> {
|
||||
// 松:保持当前位置
|
||||
double cur = intakerSubsystem.getIntakerotaterPosition();
|
||||
intakerSubsystem.setIntakerRotaterPosition(cur);
|
||||
|
||||
// getter仍然停止
|
||||
intakerSubsystem.setIntakeGetterOn(false);
|
||||
}, intakerSubsystem)
|
||||
);
|
||||
}
|
||||
|
||||
public Command defaultIntakerCommand() {
|
||||
return Commands.none();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package frc.robot.controls;
|
||||
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
import edu.wpi.first.wpilibj2.command.RunCommand;
|
||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.subsystems.ShooterSubsystem;
|
||||
import frc.robot.subsystems.ShooterSubsystem.Mode;
|
||||
|
||||
public class ShooterControls {
|
||||
private final ShooterSubsystem shooterSubsystem;
|
||||
private final CommandXboxController controller;
|
||||
|
||||
private double flywheelSpeedOffset = 0.0;
|
||||
private double backboardPositionOffset = 0.0;
|
||||
|
||||
public ShooterControls(ShooterSubsystem shooterSubsystem, CommandXboxController controller) {
|
||||
this.shooterSubsystem = shooterSubsystem;
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public Command defaultShooterCommand() {
|
||||
return Commands.run(() -> {
|
||||
// System.out.println("running");
|
||||
if (controller.getRightTriggerAxis() < 0.1) {
|
||||
shooterSubsystem.setConveyorSpeedByRPS(0);
|
||||
shooterSubsystem.setFlywheelSpeedByRPS(0);
|
||||
return;
|
||||
}
|
||||
double flywheelSpeed;
|
||||
double backboardPosition;
|
||||
double conveyorSpeed;
|
||||
flywheelSpeed = calculateFlywheelSpeedOnlywithOffset(20);
|
||||
backboardPosition = calculateBackboardPositionOnlywithOffset(100);
|
||||
conveyorSpeed = controller.getRightTriggerAxis() * Constants.Shooter.conveyorSpeedkP;
|
||||
|
||||
// double flywheelSpeed = calculateFlywheelSpeed(0);
|
||||
// double BackboardPosition = calculateBackboardPosition(0);
|
||||
// shooterSubsystem.setFlywheelSpeedByRPS(flywheelSpeed);
|
||||
// shooterSubsystem.setConveyorSpeedByRPS(conveyorSpeed);
|
||||
shooterSubsystem.setBackboardPosition(backboardPosition);
|
||||
}, shooterSubsystem);
|
||||
}
|
||||
|
||||
// public Command resetBackboardCommand(){
|
||||
// return
|
||||
// Commands.runOnce(()->{
|
||||
// shooterSubsystem.backboardMotor.set(-0.1);
|
||||
// shooterSubsystem.currentBackboardInalyzeMode = Mode.Inalyzing;}, shooterSubsystem)
|
||||
// .andThen(
|
||||
// Commands.waitSeconds(0.5))
|
||||
// .andThen(Commands.runOnce(()->{
|
||||
// shooterSubsystem.backboardMotor.set(0);
|
||||
// shooterSubsystem.backboardEncoder.reset();
|
||||
// shooterSubsystem.backboardPID.reset(0);}, shooterSubsystem))
|
||||
// .andThen(
|
||||
// Commands.waitSeconds(1))
|
||||
// .andThen(Commands.runOnce(()->{
|
||||
// shooterSubsystem.currentBackboardInalyzeMode = Mode.Inalyzed;}, shooterSubsystem));
|
||||
// }
|
||||
|
||||
public Command resetBackboardCommand(){
|
||||
return
|
||||
Commands.runOnce(()->{
|
||||
shooterSubsystem.backboardEncoder.reset();
|
||||
shooterSubsystem.backboardPID.reset(0);}, shooterSubsystem);
|
||||
}
|
||||
|
||||
//打表参数
|
||||
private static final double[][] FLYWHEEL_TABLE = {
|
||||
{1.5, 0.42},
|
||||
{2.0, 0.46},
|
||||
{2.5, 0.51},
|
||||
{3.0, 0.57},
|
||||
{3.5, 0.64},
|
||||
{4.0, 0.72}
|
||||
};
|
||||
|
||||
//线性插值函数
|
||||
private static double lerp(double x0, double y0, double x1, double y1, double x) {
|
||||
if (Math.abs(x1 - x0) < 1e-9) {
|
||||
return y0;
|
||||
}
|
||||
double t = (x - x0) / (x1 - x0);
|
||||
return y0 + t * (y1 - y0);
|
||||
}
|
||||
private double calculateFlywheelSpeedOnlywithOffset(double defaultSpeed) {
|
||||
return defaultSpeed + flywheelSpeedOffset;
|
||||
}
|
||||
private double calculateBackboardPositionOnlywithOffset(double defaultPosition) {
|
||||
return defaultPosition + backboardPositionOffset;
|
||||
}
|
||||
|
||||
private double calculateFlywheelSpeed(double distance) {
|
||||
// 小于最小距离:用第一个点
|
||||
if (distance <= FLYWHEEL_TABLE[0][0]) {
|
||||
return FLYWHEEL_TABLE[0][1] + flywheelSpeedOffset;
|
||||
}
|
||||
// 大于最大距离:用最后一个点
|
||||
int last = FLYWHEEL_TABLE.length - 1;
|
||||
if (distance >= FLYWHEEL_TABLE[last][0]) {
|
||||
return FLYWHEEL_TABLE[last][1] + flywheelSpeedOffset;
|
||||
}
|
||||
// 查找区间并插值
|
||||
for (int i = 0; i < FLYWHEEL_TABLE.length - 1; i++) {
|
||||
double d0 = FLYWHEEL_TABLE[i][0];
|
||||
double s0 = FLYWHEEL_TABLE[i][1];
|
||||
double d1 = FLYWHEEL_TABLE[i + 1][0];
|
||||
double s1 = FLYWHEEL_TABLE[i + 1][1];
|
||||
if (distance >= d0 && distance <= d1) {
|
||||
return lerp(d0, s0, d1, s1, distance) + flywheelSpeedOffset;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private double calculateBackboardPosition(double distance) {
|
||||
double BackboardPosition;
|
||||
// 距离阈值(单位自己按distance进行修改)
|
||||
final double DISTANCE_NEAR = 2.0; // 近距离阈值
|
||||
final double DISTANCE_MID = 4.0; // 中距离阈值
|
||||
if (distance < DISTANCE_NEAR) {
|
||||
BackboardPosition = Constants.ShooterCalculation.positionNear;
|
||||
}
|
||||
else if (distance < DISTANCE_MID) {
|
||||
BackboardPosition = Constants.ShooterCalculation.positionMid;
|
||||
}
|
||||
else {
|
||||
BackboardPosition = Constants.ShooterCalculation.postionFar;
|
||||
}
|
||||
BackboardPosition += backboardPositionOffset;
|
||||
return BackboardPosition;
|
||||
}
|
||||
|
||||
public void adjustFlywheelSpeedOffset(double offset) {
|
||||
flywheelSpeedOffset += offset;
|
||||
}
|
||||
|
||||
public void adjustBackboardRateOffset(double offset) {
|
||||
backboardPositionOffset += offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
package frc.robot.generated;
|
||||
|
||||
import static edu.wpi.first.units.Units.*;
|
||||
|
||||
import com.ctre.phoenix6.CANBus;
|
||||
import com.ctre.phoenix6.configs.*;
|
||||
import com.ctre.phoenix6.hardware.*;
|
||||
import com.ctre.phoenix6.signals.*;
|
||||
import com.ctre.phoenix6.swerve.*;
|
||||
import com.ctre.phoenix6.swerve.SwerveModuleConstants.*;
|
||||
|
||||
import edu.wpi.first.math.Matrix;
|
||||
import edu.wpi.first.math.numbers.N1;
|
||||
import edu.wpi.first.math.numbers.N3;
|
||||
import edu.wpi.first.units.measure.*;
|
||||
|
||||
import frc.robot.subsystems.CommandSwerveDrivetrain;
|
||||
|
||||
// Generated by the 2026 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(70).withKI(0).withKD(0.5)
|
||||
.withKS(0.1).withKV(1.59).withKA(0)
|
||||
.withStaticFeedforwardSign(StaticFeedforwardSignValue.UseClosedLoopSign);
|
||||
// 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(0.01).withKI(0).withKD(0)
|
||||
.withKS(0.05).withKV(0.117);
|
||||
|
||||
// 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 kSteerClosedLoopOutput = 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 kDriveClosedLoopOutput = ClosedLoopOutputType.Voltage;
|
||||
|
||||
// The type of motor used for the drive motor
|
||||
private static final DriveMotorArrangement kDriveMotorType = DriveMotorArrangement.TalonFX_Integrated;
|
||||
// The type of motor used for the drive motor
|
||||
private static final SteerMotorArrangement kSteerMotorType = SteerMotorArrangement.TalonFX_Integrated;
|
||||
|
||||
// The remote sensor feedback type to use for the steer motors;
|
||||
// When not Pro-licensed, Fused*/Sync* automatically fall back to Remote*
|
||||
private static final SteerFeedbackType kSteerFeedbackType = SteerFeedbackType.FusedCANcoder;
|
||||
|
||||
// The stator current at which the wheels start to slip;
|
||||
// This needs to be tuned to your individual robot
|
||||
private static final Current kSlipCurrent = Amps.of(120);
|
||||
|
||||
// Initial configs for the drive and steer motors and the azimuth encoder; these cannot be null.
|
||||
// Some configs will be overwritten; check the `with*InitialConfigs()` API documentation.
|
||||
private static final TalonFXConfiguration driveInitialConfigs = new TalonFXConfiguration();
|
||||
private static final TalonFXConfiguration steerInitialConfigs = new TalonFXConfiguration()
|
||||
.withCurrentLimits(
|
||||
new CurrentLimitsConfigs()
|
||||
// Swerve azimuth does not require much torque output, so we can set a relatively low
|
||||
// stator current limit to help avoid brownouts without impacting performance.
|
||||
.withStatorCurrentLimit(Amps.of(60))
|
||||
.withStatorCurrentLimitEnable(true)
|
||||
);
|
||||
private static final CANcoderConfiguration encoderInitialConfigs = new CANcoderConfiguration();
|
||||
// Configs for the Pigeon 2; leave this null to skip applying Pigeon 2 configs
|
||||
private static final Pigeon2Configuration pigeonConfigs = null;
|
||||
|
||||
// CAN bus that the devices are located on;
|
||||
// All swerve devices must share the same CAN bus
|
||||
public static final CANBus kCANBus = new CANBus("", "./logs/example.hoot");
|
||||
|
||||
// Theoretical free speed (m/s) at 12 V applied output;
|
||||
// This needs to be tuned to your individual robot
|
||||
public static final LinearVelocity kSpeedAt12Volts = MetersPerSecond.of(4.73);
|
||||
|
||||
// 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.125;
|
||||
|
||||
private static final double kDriveGearRatio = 5.902777777777778;
|
||||
private static final double kSteerGearRatio = 12.8;
|
||||
private static final Distance kWheelRadius = Inches.of(1.81);
|
||||
|
||||
private static final boolean kInvertLeftSide = false;
|
||||
private static final boolean kInvertRightSide = true;
|
||||
|
||||
private static final int kPigeonId = 0;
|
||||
|
||||
// These are only used for simulation
|
||||
private static final MomentOfInertia kSteerInertia = KilogramSquareMeters.of(0.01);
|
||||
private static final MomentOfInertia kDriveInertia = KilogramSquareMeters.of(0.01);
|
||||
// Simulated voltage necessary to overcome friction
|
||||
private static final Voltage kSteerFrictionVoltage = Volts.of(0.2);
|
||||
private static final Voltage kDriveFrictionVoltage = Volts.of(0.2);
|
||||
|
||||
public static final SwerveDrivetrainConstants DrivetrainConstants = new SwerveDrivetrainConstants()
|
||||
.withCANBusName(kCANBus.getName())
|
||||
.withPigeon2Id(kPigeonId)
|
||||
.withPigeon2Configs(pigeonConfigs);
|
||||
|
||||
private static final SwerveModuleConstantsFactory<TalonFXConfiguration, TalonFXConfiguration, CANcoderConfiguration> ConstantCreator =
|
||||
new SwerveModuleConstantsFactory<TalonFXConfiguration, TalonFXConfiguration, CANcoderConfiguration>()
|
||||
.withDriveMotorGearRatio(kDriveGearRatio)
|
||||
.withSteerMotorGearRatio(kSteerGearRatio)
|
||||
.withCouplingGearRatio(kCoupleRatio)
|
||||
.withWheelRadius(kWheelRadius)
|
||||
.withSteerMotorGains(steerGains)
|
||||
.withDriveMotorGains(driveGains)
|
||||
.withSteerMotorClosedLoopOutput(kSteerClosedLoopOutput)
|
||||
.withDriveMotorClosedLoopOutput(kDriveClosedLoopOutput)
|
||||
.withSlipCurrent(kSlipCurrent)
|
||||
.withSpeedAt12Volts(kSpeedAt12Volts)
|
||||
.withDriveMotorType(kDriveMotorType)
|
||||
.withSteerMotorType(kSteerMotorType)
|
||||
.withFeedbackSource(kSteerFeedbackType)
|
||||
.withDriveMotorInitialConfigs(driveInitialConfigs)
|
||||
.withSteerMotorInitialConfigs(steerInitialConfigs)
|
||||
.withEncoderInitialConfigs(encoderInitialConfigs)
|
||||
.withSteerInertia(kSteerInertia)
|
||||
.withDriveInertia(kDriveInertia)
|
||||
.withSteerFrictionVoltage(kSteerFrictionVoltage)
|
||||
.withDriveFrictionVoltage(kDriveFrictionVoltage);
|
||||
|
||||
|
||||
// Front Left
|
||||
private static final int kFrontLeftDriveMotorId = 11;
|
||||
private static final int kFrontLeftSteerMotorId = 12;
|
||||
private static final int kFrontLeftEncoderId = 13;
|
||||
private static final Angle kFrontLeftEncoderOffset = Rotations.of(-0.412841796875);
|
||||
private static final boolean kFrontLeftSteerMotorInverted = false;
|
||||
private static final boolean kFrontLeftEncoderInverted = false;
|
||||
|
||||
private static final Distance kFrontLeftXPos = Inches.of(11.375);
|
||||
private static final Distance kFrontLeftYPos = Inches.of(11.375);
|
||||
|
||||
// Front Right
|
||||
private static final int kFrontRightDriveMotorId = 21;
|
||||
private static final int kFrontRightSteerMotorId = 22;
|
||||
private static final int kFrontRightEncoderId = 23;
|
||||
private static final Angle kFrontRightEncoderOffset = Rotations.of(-0.012939453125);
|
||||
private static final boolean kFrontRightSteerMotorInverted = false;
|
||||
private static final boolean kFrontRightEncoderInverted = false;
|
||||
|
||||
private static final Distance kFrontRightXPos = Inches.of(11.375);
|
||||
private static final Distance kFrontRightYPos = Inches.of(-11.375);
|
||||
|
||||
// Back Left
|
||||
private static final int kBackLeftDriveMotorId = 1;
|
||||
private static final int kBackLeftSteerMotorId = 2;
|
||||
private static final int kBackLeftEncoderId = 3;
|
||||
private static final Angle kBackLeftEncoderOffset = Rotations.of(0.07275390625);
|
||||
private static final boolean kBackLeftSteerMotorInverted = false;
|
||||
private static final boolean kBackLeftEncoderInverted = false;
|
||||
|
||||
private static final Distance kBackLeftXPos = Inches.of(-11.375);
|
||||
private static final Distance kBackLeftYPos = Inches.of(11.375);
|
||||
|
||||
// Back Right
|
||||
private static final int kBackRightDriveMotorId = 31;
|
||||
private static final int kBackRightSteerMotorId = 32;
|
||||
private static final int kBackRightEncoderId = 33;
|
||||
private static final Angle kBackRightEncoderOffset = Rotations.of(-0.4892578125);
|
||||
private static final boolean kBackRightSteerMotorInverted = false;
|
||||
private static final boolean kBackRightEncoderInverted = false;
|
||||
|
||||
private static final Distance kBackRightXPos = Inches.of(-11.375);
|
||||
private static final Distance kBackRightYPos = Inches.of(-11.375);
|
||||
|
||||
|
||||
public static final SwerveModuleConstants<TalonFXConfiguration, TalonFXConfiguration, CANcoderConfiguration> FrontLeft =
|
||||
ConstantCreator.createModuleConstants(
|
||||
kFrontLeftSteerMotorId, kFrontLeftDriveMotorId, kFrontLeftEncoderId, kFrontLeftEncoderOffset,
|
||||
kFrontLeftXPos, kFrontLeftYPos, kInvertLeftSide, kFrontLeftSteerMotorInverted, kFrontLeftEncoderInverted
|
||||
);
|
||||
public static final SwerveModuleConstants<TalonFXConfiguration, TalonFXConfiguration, CANcoderConfiguration> FrontRight =
|
||||
ConstantCreator.createModuleConstants(
|
||||
kFrontRightSteerMotorId, kFrontRightDriveMotorId, kFrontRightEncoderId, kFrontRightEncoderOffset,
|
||||
kFrontRightXPos, kFrontRightYPos, kInvertRightSide, kFrontRightSteerMotorInverted, kFrontRightEncoderInverted
|
||||
);
|
||||
public static final SwerveModuleConstants<TalonFXConfiguration, TalonFXConfiguration, CANcoderConfiguration> BackLeft =
|
||||
ConstantCreator.createModuleConstants(
|
||||
kBackLeftSteerMotorId, kBackLeftDriveMotorId, kBackLeftEncoderId, kBackLeftEncoderOffset,
|
||||
kBackLeftXPos, kBackLeftYPos, kInvertLeftSide, kBackLeftSteerMotorInverted, kBackLeftEncoderInverted
|
||||
);
|
||||
public static final SwerveModuleConstants<TalonFXConfiguration, TalonFXConfiguration, CANcoderConfiguration> BackRight =
|
||||
ConstantCreator.createModuleConstants(
|
||||
kBackRightSteerMotorId, kBackRightDriveMotorId, kBackRightEncoderId, kBackRightEncoderOffset,
|
||||
kBackRightXPos, kBackRightYPos, kInvertRightSide, kBackRightSteerMotorInverted, kBackRightEncoderInverted
|
||||
);
|
||||
|
||||
/**
|
||||
* Creates a CommandSwerveDrivetrain instance.
|
||||
* This should only be called once in your robot program,.
|
||||
*/
|
||||
public static CommandSwerveDrivetrain createDrivetrain() {
|
||||
return new CommandSwerveDrivetrain(
|
||||
DrivetrainConstants, FrontLeft, FrontRight, BackLeft, BackRight
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Swerve Drive class utilizing CTR Electronics' Phoenix 6 API with the selected device types.
|
||||
*/
|
||||
public static class TunerSwerveDrivetrain extends SwerveDrivetrain<TalonFX, TalonFX, CANcoder> {
|
||||
/**
|
||||
* Constructs a CTRE SwerveDrivetrain using the specified constants.
|
||||
* <p>
|
||||
* This constructs the underlying hardware devices, so users should not construct
|
||||
* the devices themselves. If they need the devices, they can access them through
|
||||
* getters in the classes.
|
||||
*
|
||||
* @param drivetrainConstants Drivetrain-wide constants for the swerve drive
|
||||
* @param modules Constants for each specific module
|
||||
*/
|
||||
public TunerSwerveDrivetrain(
|
||||
SwerveDrivetrainConstants drivetrainConstants,
|
||||
SwerveModuleConstants<?, ?, ?>... modules
|
||||
) {
|
||||
super(
|
||||
TalonFX::new, TalonFX::new, CANcoder::new,
|
||||
drivetrainConstants, modules
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CTRE SwerveDrivetrain using the specified constants.
|
||||
* <p>
|
||||
* This constructs the underlying hardware devices, so users should not construct
|
||||
* the devices themselves. If they need the devices, they can access them through
|
||||
* getters in the classes.
|
||||
*
|
||||
* @param drivetrainConstants Drivetrain-wide constants for the swerve drive
|
||||
* @param odometryUpdateFrequency The frequency to run the odometry loop. If
|
||||
* unspecified or set to 0 Hz, this is 250 Hz on
|
||||
* CAN FD, and 100 Hz on CAN 2.0.
|
||||
* @param modules Constants for each specific module
|
||||
*/
|
||||
public TunerSwerveDrivetrain(
|
||||
SwerveDrivetrainConstants drivetrainConstants,
|
||||
double odometryUpdateFrequency,
|
||||
SwerveModuleConstants<?, ?, ?>... modules
|
||||
) {
|
||||
super(
|
||||
TalonFX::new, TalonFX::new, CANcoder::new,
|
||||
drivetrainConstants, odometryUpdateFrequency, modules
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a CTRE SwerveDrivetrain using the specified constants.
|
||||
* <p>
|
||||
* This constructs the underlying hardware devices, so users should not construct
|
||||
* the devices themselves. If they need the devices, they can access them through
|
||||
* getters in the classes.
|
||||
*
|
||||
* @param drivetrainConstants Drivetrain-wide constants for the swerve drive
|
||||
* @param odometryUpdateFrequency The frequency to run the odometry loop. If
|
||||
* unspecified or set to 0 Hz, this is 250 Hz on
|
||||
* CAN FD, and 100 Hz on CAN 2.0.
|
||||
* @param odometryStandardDeviation The standard deviation for odometry calculation
|
||||
* in the form [x, y, theta]ᵀ, with units in meters
|
||||
* and radians
|
||||
* @param visionStandardDeviation The standard deviation for vision calculation
|
||||
* in the form [x, y, theta]ᵀ, with units in meters
|
||||
* and radians
|
||||
* @param modules Constants for each specific module
|
||||
*/
|
||||
public TunerSwerveDrivetrain(
|
||||
SwerveDrivetrainConstants drivetrainConstants,
|
||||
double odometryUpdateFrequency,
|
||||
Matrix<N3, N1> odometryStandardDeviation,
|
||||
Matrix<N3, N1> visionStandardDeviation,
|
||||
SwerveModuleConstants<?, ?, ?>... modules
|
||||
) {
|
||||
super(
|
||||
TalonFX::new, TalonFX::new, CANcoder::new,
|
||||
drivetrainConstants, odometryUpdateFrequency,
|
||||
odometryStandardDeviation, visionStandardDeviation, modules
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
package frc.robot.subsystems;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.ctre.phoenix6.Utils;
|
||||
import com.ctre.phoenix6.swerve.SwerveDrivetrainConstants;
|
||||
import com.ctre.phoenix6.swerve.SwerveModuleConstants;
|
||||
import com.ctre.phoenix6.swerve.SwerveRequest;
|
||||
import com.pathplanner.lib.auto.AutoBuilder;
|
||||
import com.pathplanner.lib.config.PIDConstants;
|
||||
import com.pathplanner.lib.config.RobotConfig;
|
||||
import com.pathplanner.lib.controllers.PPHolonomicDriveController;
|
||||
|
||||
import edu.wpi.first.math.Matrix;
|
||||
import edu.wpi.first.math.VecBuilder;
|
||||
import edu.wpi.first.math.geometry.Pose2d;
|
||||
import edu.wpi.first.math.geometry.Rotation2d;
|
||||
import edu.wpi.first.math.kinematics.ChassisSpeeds;
|
||||
import edu.wpi.first.math.numbers.N1;
|
||||
import edu.wpi.first.math.numbers.N3;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.Field2d;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Subsystem;
|
||||
import frc.robot.Constants.DriveMode;
|
||||
import frc.robot.generated.TunerConstants.TunerSwerveDrivetrain;
|
||||
import frc.robot.Constants;
|
||||
|
||||
import edu.wpi.first.networktables.*;
|
||||
|
||||
|
||||
/**
|
||||
* Class that extends the Phoenix 6 SwerveDrivetrain class and implements
|
||||
* Subsystem so it can easily be used in command-based projects.
|
||||
*
|
||||
* Generated by the 2026 Tuner X Swerve Project Generator
|
||||
* https://v6.docs.ctr-electronics.com/en/stable/docs/tuner/tuner-swerve/index.html
|
||||
*/
|
||||
public class CommandSwerveDrivetrain extends TunerSwerveDrivetrain implements Subsystem {
|
||||
|
||||
/* Blue alliance sees forward as 0 degrees (toward red alliance wall) */
|
||||
private static final Rotation2d kBlueAlliancePerspectiveRotation = Rotation2d.kZero;
|
||||
/* Red alliance sees forward as 180 degrees (toward blue alliance wall) */
|
||||
private static final Rotation2d kRedAlliancePerspectiveRotation = Rotation2d.kCW_90deg;
|
||||
/* Keep track if we've ever applied the operator perspective before or not */
|
||||
private boolean m_hasAppliedOperatorPerspective = false;
|
||||
|
||||
private DriveMode m_driveMode = DriveMode.OTHER;
|
||||
|
||||
private NetworkTable positioningNetworkTable;
|
||||
private NetworkTable driveNetworkTable;
|
||||
|
||||
private final StructPublisher<Pose2d> posePub =
|
||||
NetworkTableInstance.getDefault()
|
||||
.getStructTopic("/Odometry/RobotPose", Pose2d.struct)
|
||||
.publish();
|
||||
|
||||
private Field2d m_field;
|
||||
public CommandSwerveDrivetrain(
|
||||
SwerveDrivetrainConstants drivetrainConstants,
|
||||
SwerveModuleConstants<?, ?, ?>... modules
|
||||
) {
|
||||
super(drivetrainConstants, modules);
|
||||
m_field = new Field2d();
|
||||
SmartDashboard.putData("Field", m_field);
|
||||
LimelightHelpers.SetIMUMode(Constants.Limelight.LIMELIGHT_NAME, 0);
|
||||
positioningNetworkTable = NetworkTableInstance.getDefault().getTable("Positioning");
|
||||
driveNetworkTable = NetworkTableInstance.getDefault().getTable("Drive");
|
||||
|
||||
configueAutoBuilder();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void configueAutoBuilder(){
|
||||
|
||||
RobotConfig config;
|
||||
try {
|
||||
config = RobotConfig.fromGUISettings();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load PathPlanner RobotConfig", e);
|
||||
}
|
||||
|
||||
AutoBuilder.configure(
|
||||
this::getPose, // 当前机器人 Pose
|
||||
this::resetPose, // 重置里程计
|
||||
this::getRobotRelativeSpeeds, // ROBOT RELATIVE speeds
|
||||
(speeds, feedforwards) -> driveRobotRelative(speeds), // 用 speeds 驱动机器人
|
||||
new PPHolonomicDriveController(
|
||||
new PIDConstants(5.0, 0.0, 0.0), // X/Y PID
|
||||
new PIDConstants(5.0, 0.0, 0.0) // Theta PID
|
||||
),
|
||||
config,
|
||||
() -> false,
|
||||
this
|
||||
);
|
||||
|
||||
}
|
||||
public Pose2d getPose() {
|
||||
return getState().Pose;
|
||||
}
|
||||
|
||||
public ChassisSpeeds getRobotRelativeSpeeds() {
|
||||
return getState().Speeds;
|
||||
}
|
||||
|
||||
public void driveRobotRelative(ChassisSpeeds speeds) {
|
||||
ChassisSpeeds scaled = new ChassisSpeeds(
|
||||
speeds.vxMetersPerSecond, // X 不变
|
||||
speeds.vyMetersPerSecond, // Y 不变
|
||||
speeds.omegaRadiansPerSecond * 1.3 // 只放大旋转
|
||||
);
|
||||
|
||||
setControl(
|
||||
new SwerveRequest.ApplyRobotSpeeds().withSpeeds(scaled)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static final double kMaxVisionJumpMeters = 1.0;
|
||||
private static final double kMaxOmegaDegPerSec = 360.0;
|
||||
|
||||
/**
|
||||
* Returns a command that applies the specified control request to this swerve drivetrain.
|
||||
*
|
||||
* @param request Function returning the request to apply
|
||||
* @return Command to run
|
||||
*/
|
||||
public Command applyRequest(Supplier<SwerveRequest> request) {
|
||||
return run(() -> this.setControl(request.get()));
|
||||
}
|
||||
|
||||
public Command applyRequest(Supplier<SwerveRequest> requestSupplier, Supplier<DriveMode> driveModeSupplier) {
|
||||
return run(() -> {
|
||||
DriveMode mode = driveModeSupplier.get();
|
||||
m_driveMode = mode;
|
||||
this.setControl(requestSupplier.get());
|
||||
});
|
||||
}
|
||||
|
||||
public void forceUsingLimelightMT2() {
|
||||
LimelightHelpers.PoseEstimate mt2 =
|
||||
LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME);
|
||||
|
||||
if (mt2 == null || mt2.tagCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var stdDevs = VecBuilder.fill(0.7, 0.7, 9999999);
|
||||
addVisionMeasurement(mt2.pose, mt2.timestampSeconds, stdDevs);
|
||||
}
|
||||
|
||||
private void fuseLimelightMT2() {
|
||||
|
||||
LimelightHelpers.PoseEstimate mt2 =
|
||||
LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.Limelight.LIMELIGHT_NAME);
|
||||
|
||||
Pose2d current = getState().Pose;
|
||||
Pose2d mt2Pose = mt2.pose;
|
||||
|
||||
double distance = current.getTranslation().getDistance(mt2Pose.getTranslation());
|
||||
Rotation2d deltaRotation = current.getRotation().minus(mt2Pose.getRotation());
|
||||
|
||||
positioningNetworkTable.getEntry("CurrentPoseX").setDouble(current.getX());
|
||||
positioningNetworkTable.getEntry("CurrentPoseY").setDouble(current.getY());
|
||||
positioningNetworkTable.getEntry("MetaTag2PoseX").setDouble(mt2Pose.getX());
|
||||
positioningNetworkTable.getEntry("MetaTag2PoseY").setDouble(mt2Pose.getY());
|
||||
positioningNetworkTable.getEntry("PoseDistance").setDouble(distance);
|
||||
positioningNetworkTable.getEntry("RotationDifference").setDouble(Math.abs(deltaRotation.getDegrees()));
|
||||
|
||||
// 1) 没看到 tag:拒绝
|
||||
if (mt2 == null || mt2.tagCount == 0) {
|
||||
positioningNetworkTable.getEntry("MetaTag2Available").setBoolean(false);
|
||||
return;
|
||||
}
|
||||
// 2) 转太快:拒绝(角速度你可以从 Pigeon2 或 drivetrain state 拿)
|
||||
double omegaDegPerSec = getPigeon2().getAngularVelocityZWorld().getValueAsDouble(); // 若你有这个信号
|
||||
if (Math.abs(omegaDegPerSec) > kMaxOmegaDegPerSec) {
|
||||
positioningNetworkTable.getEntry("MetaTag2Available").setBoolean(false);
|
||||
System.out.println("NoUsingMetaTag2ForTooFastRotationSpeed");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3) 跳变太大:拒绝(Phoenix6 推荐的稳定策略)
|
||||
//Pose2d current = getState().Pose;
|
||||
if (current.getTranslation().getDistance(mt2.pose.getTranslation()) > kMaxVisionJumpMeters) {
|
||||
positioningNetworkTable.getEntry("MetaTag2Available").setBoolean(false);
|
||||
System.out.println("NoUsingMetaTag2ForTooChangingPose");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4) 设置测量噪声(示例:theta 基本不信任就给极大)
|
||||
// 你也可以根据 mt2.avgTagDist / mt2.tagSpan 动态调
|
||||
var stdDevs = VecBuilder.fill(0.7, 0.7, 9999999);
|
||||
|
||||
// 5) 融合:注意 timestampSeconds 的处理
|
||||
addVisionMeasurement(mt2.pose, mt2.timestampSeconds, stdDevs);
|
||||
positioningNetworkTable.getEntry("MetaTag2Available").setBoolean(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void periodic() {
|
||||
Pose2d pose = getState().Pose;
|
||||
m_field.setRobotPose(pose);
|
||||
posePub.set(pose);
|
||||
driveNetworkTable.getEntry("YawFromState").setDouble(getState().Pose.getRotation().getDegrees());
|
||||
driveNetworkTable.getEntry("DriveMode").setString(m_driveMode.name());
|
||||
driveNetworkTable.getEntry("IsFieldCentric").setBoolean(m_driveMode == DriveMode.FIELD_CENTRIC);
|
||||
|
||||
// 1) 每帧喂给 LL:机器人当前 yaw(度),其余先全 0
|
||||
LimelightHelpers.SetRobotOrientation(
|
||||
Constants.Limelight.LIMELIGHT_NAME,
|
||||
pose.getRotation().getDegrees(), // 关键:要符合 wpiBlue 约定
|
||||
0, 0, 0, 0, 0
|
||||
);
|
||||
|
||||
fuseLimelightMT2();
|
||||
|
||||
if (!m_hasAppliedOperatorPerspective || DriverStation.isDisabled()) {
|
||||
DriverStation.getAlliance().ifPresent(allianceColor -> {
|
||||
setOperatorPerspectiveForward(
|
||||
allianceColor == Alliance.Red
|
||||
? kRedAlliancePerspectiveRotation
|
||||
: kBlueAlliancePerspectiveRotation
|
||||
);
|
||||
m_hasAppliedOperatorPerspective = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a vision measurement to the Kalman Filter. This will correct the odometry pose estimate
|
||||
* while still accounting for measurement noise.
|
||||
*
|
||||
* @param visionRobotPoseMeters The pose of the robot as measured by the vision camera.
|
||||
* @param timestampSeconds The timestamp of the vision measurement in seconds.
|
||||
*/
|
||||
@Override
|
||||
public void addVisionMeasurement(Pose2d visionRobotPoseMeters, double timestampSeconds) {
|
||||
super.addVisionMeasurement(visionRobotPoseMeters, Utils.fpgaToCurrentTime(timestampSeconds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a vision measurement to the Kalman Filter. This will correct the odometry pose estimate
|
||||
* while still accounting for measurement noise.
|
||||
* <p>
|
||||
* Note that the vision measurement standard deviations passed into this method
|
||||
* will continue to apply to future measurements until a subsequent call to
|
||||
* {@link #setVisionMeasurementStdDevs(Matrix)} or this method.
|
||||
*
|
||||
* @param visionRobotPoseMeters The pose of the robot as measured by the vision camera.
|
||||
* @param timestampSeconds The timestamp of the vision measurement in seconds.
|
||||
* @param visionMeasurementStdDevs Standard deviations of the vision pose measurement
|
||||
* in the form [x, y, theta]ᵀ, with units in meters and radians.
|
||||
*/
|
||||
@Override
|
||||
public void addVisionMeasurement(
|
||||
Pose2d visionRobotPoseMeters,
|
||||
double timestampSeconds,
|
||||
Matrix<N3, N1> visionMeasurementStdDevs
|
||||
) {
|
||||
super.addVisionMeasurement(visionRobotPoseMeters, Utils.fpgaToCurrentTime(timestampSeconds), visionMeasurementStdDevs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the pose at a given timestamp, if the buffer is not empty.
|
||||
*
|
||||
* @param timestampSeconds The timestamp of the pose in seconds.
|
||||
* @return The pose at the given timestamp (or Optional.empty() if the buffer is empty).
|
||||
*/
|
||||
@Override
|
||||
public Optional<Pose2d> samplePoseAt(double timestampSeconds) {
|
||||
return super.samplePoseAt(Utils.fpgaToCurrentTime(timestampSeconds));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package frc.robot.subsystems;
|
||||
|
||||
import com.ctre.phoenix6.controls.PositionVoltage;
|
||||
import com.ctre.phoenix6.controls.VelocityVoltage;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
|
||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||
import frc.robot.Constants;
|
||||
|
||||
public class IntakerSubsystem extends SubsystemBase{
|
||||
//定义intakerotater&intakegetter
|
||||
private TalonFX intakerotater;
|
||||
private TalonFX intakegetter;
|
||||
|
||||
//PID
|
||||
private final VelocityVoltage velocityRequest = new VelocityVoltage(0);
|
||||
private final PositionVoltage positionRequest = new PositionVoltage(0);
|
||||
|
||||
private double intakeRotaterTargetPosition = 0.0;
|
||||
|
||||
public IntakerSubsystem() {
|
||||
//初始化rotater&getter
|
||||
intakegetter = new TalonFX(47);
|
||||
intakerotater = new TalonFX(48);
|
||||
intakegetter.getConfigurator().apply(Constants.Intaker.intakeGetterSlot0Configs);
|
||||
intakerotater.getConfigurator().apply(Constants.Intaker.intakeRotaterSlot0Configs);
|
||||
}
|
||||
|
||||
public void setIntakerRotaterPosition(double targetPosition) {
|
||||
//目标position
|
||||
if (targetPosition > Constants.Intaker.intakeRotaterUpLimit) {
|
||||
targetPosition = Constants.Intaker.intakeRotaterUpLimit; // 限制最大上限
|
||||
} else if (targetPosition < Constants.Intaker.intakeRotaterDownLimit) {
|
||||
targetPosition = Constants.Intaker.intakeRotaterDownLimit; // 限制最小下限
|
||||
}
|
||||
|
||||
intakeRotaterTargetPosition = targetPosition;
|
||||
|
||||
intakerotater.setControl(positionRequest.withPosition(targetPosition)); // 设置rotater位置(TalonFX 内部闭环 PID)
|
||||
}
|
||||
|
||||
// 获取intakerotater当前角度
|
||||
public double getIntakerotaterPosition() {
|
||||
return intakerotater.getPosition().getValueAsDouble();
|
||||
}
|
||||
|
||||
public boolean isIntakerotaterAtTarget() {
|
||||
// 到位判断容差
|
||||
double error = Math.abs(intakeRotaterTargetPosition - getIntakerotaterPosition());
|
||||
return error <= Constants.Intaker.positionToleranceRotations;
|
||||
}
|
||||
|
||||
public void stopintakerotater() {
|
||||
intakerotater.setControl(velocityRequest.withVelocity(0));
|
||||
// 如果你希望停止后保持当前位置,建议改用中性模式/或维持 positionRequest(这句fromAI)
|
||||
}
|
||||
|
||||
//intakegetter的on/off
|
||||
public void setIntakeGetterOn(boolean on) {
|
||||
if (on) {
|
||||
intakegetter.setControl(velocityRequest.withVelocity(Constants.Intaker.IntakeGetterSpeed));
|
||||
}
|
||||
else {
|
||||
intakegetter.setControl(velocityRequest.withVelocity(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package frc.robot.subsystems;
|
||||
|
||||
import edu.wpi.first.wpilibj.AddressableLED;
|
||||
import edu.wpi.first.wpilibj.AddressableLEDBuffer;
|
||||
import edu.wpi.first.wpilibj.Timer;
|
||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||
import frc.robot.Constants;
|
||||
|
||||
public class LEDSubsystem extends SubsystemBase {
|
||||
|
||||
public enum Mode {
|
||||
OFF,
|
||||
SOLID,
|
||||
BREATH,
|
||||
RAINBOW
|
||||
}
|
||||
|
||||
private final AddressableLED led;
|
||||
private final AddressableLEDBuffer buffer;
|
||||
private final Timer timer = new Timer();
|
||||
|
||||
// 左右灯带分段(左 0~71,右 72~143)
|
||||
private final int leftStart = 0;
|
||||
private final int leftLen;
|
||||
private final int rightStart;
|
||||
private final int rightLen;
|
||||
|
||||
private Mode leftMode = Mode.OFF;
|
||||
private Mode rightMode = Mode.OFF;
|
||||
|
||||
// 左右颜色
|
||||
private int lr = 0, lg = 0, lb = 0;
|
||||
private int rr = 0, rg = 0, rb = 0;
|
||||
|
||||
// 动画参数
|
||||
private double leftBreathPeriodSec = 2.0;
|
||||
private double rightBreathPeriodSec = 2.0;
|
||||
private int leftRainbowOffset = 0;
|
||||
private int rightRainbowOffset = 0;
|
||||
|
||||
/**
|
||||
* @param pwmPort PWM 端口(只能用一个!)
|
||||
* @param leftCount 左灯数量
|
||||
* @param rightCount 右灯数量
|
||||
*/
|
||||
public LEDSubsystem(int pwmPort, int leftCount, int rightCount) {
|
||||
this.leftLen = leftCount;
|
||||
this.rightLen = rightCount;
|
||||
this.rightStart = leftStart + leftLen;
|
||||
|
||||
led = new AddressableLED(pwmPort);
|
||||
buffer = new AddressableLEDBuffer(leftLen + rightLen);
|
||||
|
||||
led.setLength(buffer.getLength());
|
||||
led.start();
|
||||
|
||||
timer.start();
|
||||
}
|
||||
|
||||
/* ====================== */
|
||||
/* 对外API */
|
||||
/* ====================== */
|
||||
|
||||
public void offLeft() { leftMode = Mode.OFF; }
|
||||
public void offRight() { rightMode = Mode.OFF; }
|
||||
public void offAll() { leftMode = Mode.OFF; rightMode = Mode.OFF; }
|
||||
|
||||
public void solidLeft(int r, int g, int b) {
|
||||
lr = clamp8(r); lg = clamp8(g); lb = clamp8(b);
|
||||
leftMode = Mode.SOLID;
|
||||
}
|
||||
|
||||
public void solidRight(int r, int g, int b) {
|
||||
rr = clamp8(r); rg = clamp8(g); rb = clamp8(b);
|
||||
rightMode = Mode.SOLID;
|
||||
}
|
||||
|
||||
public void breathLeft(int r, int g, int b, double periodSeconds) {
|
||||
lr = clamp8(r); lg = clamp8(g); lb = clamp8(b);
|
||||
leftBreathPeriodSec = Math.max(0.2, periodSeconds);
|
||||
leftMode = Mode.BREATH;
|
||||
}
|
||||
|
||||
public void breathRight(int r, int g, int b, double periodSeconds) {
|
||||
rr = clamp8(r); rg = clamp8(g); rb = clamp8(b);
|
||||
rightBreathPeriodSec = Math.max(0.2, periodSeconds);
|
||||
rightMode = Mode.BREATH;
|
||||
}
|
||||
|
||||
public void rainbowLeft() { leftMode = Mode.RAINBOW; }
|
||||
public void rainbowRight() { rightMode = Mode.RAINBOW; }
|
||||
public void rainbowAll() { leftMode = Mode.RAINBOW; rightMode = Mode.RAINBOW; }
|
||||
|
||||
@Override
|
||||
public void periodic() {
|
||||
if(!Constants.LEDUsing) {led.close(); return;}
|
||||
// 左段
|
||||
switch (leftMode) {
|
||||
case OFF -> setRange(leftStart, leftLen, 0, 0, 0);
|
||||
case SOLID -> setRange(leftStart, leftLen, lr, lg, lb);
|
||||
case BREATH -> updateBreath(leftStart, leftLen, lr, lg, lb, leftBreathPeriodSec);
|
||||
case RAINBOW -> updateRainbow(leftStart, leftLen, true);
|
||||
}
|
||||
|
||||
// 右段
|
||||
switch (rightMode) {
|
||||
case OFF -> setRange(rightStart, rightLen, 0, 0, 0);
|
||||
case SOLID -> setRange(rightStart, rightLen, rr, rg, rb);
|
||||
case BREATH -> updateBreath(rightStart, rightLen, rr, rg, rb, rightBreathPeriodSec);
|
||||
case RAINBOW -> updateRainbow(rightStart, rightLen, false);
|
||||
}
|
||||
|
||||
led.setData(buffer);
|
||||
}
|
||||
|
||||
/* ====================== */
|
||||
/* 内部实现 */
|
||||
/* ====================== */
|
||||
|
||||
private void setRange(int start, int len, int r, int g, int b) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
buffer.setRGB(start + i, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBreath(int start, int len, int r, int g, int b, double periodSec) {
|
||||
double t = timer.get();
|
||||
double phase = (t % periodSec) / periodSec; // 0..1
|
||||
double brightness = 0.5 * (1.0 + Math.sin(2.0 * Math.PI * phase)); // 0..1
|
||||
int rr = (int) (r * brightness);
|
||||
int gg = (int) (g * brightness);
|
||||
int bb = (int) (b * brightness);
|
||||
setRange(start, len, rr, gg, bb);
|
||||
}
|
||||
|
||||
private void updateRainbow(int start, int len, boolean isLeft) {
|
||||
int offset = isLeft ? leftRainbowOffset : rightRainbowOffset;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
int hue = (offset + (i * 180 / len)) % 180;
|
||||
buffer.setHSV(start + i, hue, 255, 128);
|
||||
}
|
||||
|
||||
if (isLeft) leftRainbowOffset = (leftRainbowOffset + 2) % 180;
|
||||
else rightRainbowOffset = (rightRainbowOffset + 2) % 180;
|
||||
}
|
||||
|
||||
private static int clamp8(int v) {
|
||||
return Math.max(0, Math.min(255, v));
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,171 @@
|
||||
package frc.robot.subsystems;
|
||||
|
||||
import com.ctre.phoenix6.configs.MotorOutputConfigs;
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import com.ctre.phoenix6.controls.Follower;
|
||||
import com.ctre.phoenix6.controls.VelocityDutyCycle;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
import com.ctre.phoenix6.hardware.TalonFXS;
|
||||
import com.ctre.phoenix6.signals.InvertedValue;
|
||||
import com.ctre.phoenix6.signals.MotorAlignmentValue;
|
||||
|
||||
import edu.wpi.first.math.controller.ProfiledPIDController;
|
||||
import edu.wpi.first.math.trajectory.TrapezoidProfile.Constraints;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import edu.wpi.first.wpilibj.Encoder;
|
||||
import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
||||
import frc.robot.Constants;
|
||||
|
||||
public class ShooterSubsystem extends SubsystemBase {
|
||||
// 定义飞轮、传动和背板电机
|
||||
public TalonFX flywheelMotorLeft;
|
||||
private TalonFX flywheelMotorRight;
|
||||
public TalonFX conveyorMotor;
|
||||
public TalonFXS backboardMotor;
|
||||
public Encoder backboardEncoder;
|
||||
|
||||
// PID 控制器,控制背板角度
|
||||
public ProfiledPIDController backboardPID;
|
||||
private Follower flyWheelFollower;
|
||||
|
||||
private NetworkTable shooterNetworkTable;
|
||||
|
||||
private final VelocityDutyCycle velocityRequest = new VelocityDutyCycle(0);
|
||||
|
||||
public enum Mode{
|
||||
Inalyzed,
|
||||
UnInalyed,
|
||||
Inalyzing;
|
||||
}
|
||||
public Mode currentBackboardInalyzeMode;
|
||||
// 初始化各个部件
|
||||
public ShooterSubsystem() {
|
||||
// 初始化飞轮电机
|
||||
flywheelMotorLeft = new TalonFX(41); // 41是飞轮left的CAN ID
|
||||
flywheelMotorRight = new TalonFX(42); // 42是飞轮right的CAN ID
|
||||
flywheelMotorLeft.getConfigurator().apply(Constants.Shooter.flyWheelSlot0Configs);
|
||||
flywheelMotorRight.getConfigurator().apply(Constants.Shooter.flyWheelSlot0Configs);
|
||||
// 初始化传动电机
|
||||
conveyorMotor = new TalonFX(43);
|
||||
conveyorMotor.getConfigurator().apply(Constants.Shooter.conveyorSlot0Configs);
|
||||
|
||||
var configs1 = new MotorOutputConfigs();
|
||||
configs1.Inverted = InvertedValue.Clockwise_Positive;
|
||||
flywheelMotorLeft.getConfigurator().apply(configs1);
|
||||
flyWheelFollower = new Follower(flywheelMotorLeft.getDeviceID(), MotorAlignmentValue.Opposed).withUpdateFreqHz(50);
|
||||
|
||||
var configs2 = new MotorOutputConfigs();
|
||||
configs2.Inverted = InvertedValue.Clockwise_Positive;
|
||||
conveyorMotor.getConfigurator().apply(configs2);
|
||||
|
||||
// 初始化背板电机和编码器
|
||||
backboardMotor = new TalonFXS(44);
|
||||
backboardMotor.getConfigurator().apply(Constants.Shooter.backboardSlot0Configs);
|
||||
backboardEncoder = new Encoder(0, 1, false, Encoder.EncodingType.k4X);
|
||||
backboardEncoder.setSamplesToAverage(5);
|
||||
backboardEncoder.setMinRate(1.0);
|
||||
backboardEncoder.setDistancePerPulse(1);
|
||||
|
||||
// 初始化背板的PID控制器
|
||||
backboardPID = new ProfiledPIDController(Constants.Shooter.backboardPositionPID.kP, Constants.Shooter.backboardPositionPID.kI, Constants.Shooter.backboardPositionPID.kD,
|
||||
new Constraints(10000,100000));
|
||||
|
||||
backboardPID.setTolerance(10.0);
|
||||
|
||||
shooterNetworkTable = NetworkTableInstance.getDefault().getTable("Shooter");
|
||||
|
||||
currentBackboardInalyzeMode = Mode.UnInalyed;
|
||||
}
|
||||
|
||||
public void setRightFollowLeft(){
|
||||
flywheelMotorRight.setControl(flyWheelFollower);
|
||||
}
|
||||
|
||||
public void applyLeftConfigurationToRight(){
|
||||
Slot0Configs configs = new Slot0Configs();
|
||||
flywheelMotorLeft.getConfigurator().refresh(configs);
|
||||
flywheelMotorRight.getConfigurator().apply(configs);
|
||||
}
|
||||
|
||||
|
||||
// 设置飞轮的速度
|
||||
public void setFlywheelSpeedByRPS(double targetSpeed) {
|
||||
flywheelMotorLeft.setControl(velocityRequest.withVelocity(targetSpeed)); //RPS 转每秒
|
||||
setRightFollowLeft();
|
||||
// System.out.println("set flywheel "+targetSpeed);
|
||||
}
|
||||
|
||||
// 设置传动的速度
|
||||
public void setConveyorSpeedByRPS(double speed) {
|
||||
conveyorMotor.setControl(velocityRequest.withVelocity(speed)); // 设置传动电机速度
|
||||
}
|
||||
|
||||
//调试用
|
||||
public void setBackboardSpeedByRPS(double speed){
|
||||
backboardMotor.setControl(velocityRequest.withVelocity(speed));
|
||||
}
|
||||
|
||||
// 设置背板的目标位置,通过PID控制器来调整 范围0-3000
|
||||
public void setBackboardPosition(double targetPosition) {
|
||||
// 限制目标位置在上下限之间
|
||||
if (targetPosition > Constants.Shooter.backboardUpLimit) {
|
||||
targetPosition = Constants.Shooter.backboardUpLimit; // 限制最大上限
|
||||
} else if (targetPosition < Constants.Shooter.backboardDownLimit) {
|
||||
targetPosition = Constants.Shooter.backboardDownLimit; // 限制最小下限
|
||||
}
|
||||
backboardPID.setGoal(targetPosition);
|
||||
}
|
||||
public void outputBackboard(){
|
||||
|
||||
// 使用PID控制器来计算背板的运动速度
|
||||
double pidOutput = backboardPID.calculate(getBackboardPosition());
|
||||
pidOutput = Math.max(-Constants.Shooter.backboardSpeedMax, Math.min(Constants.Shooter.backboardSpeedMax, pidOutput)); // 限制输出范围在-1到1之间
|
||||
shooterNetworkTable.getEntry("backboardPIDOutput").setDouble(pidOutput);
|
||||
// // 设置背板电机的速度,根据PID输出进行调整
|
||||
setBackboardSpeedByRPS(pidOutput);
|
||||
}
|
||||
// 停止所有电机
|
||||
public void stopMotors() {
|
||||
flywheelMotorLeft.set(0);
|
||||
flywheelMotorRight.set(0);
|
||||
conveyorMotor.set(0);
|
||||
backboardMotor.set(0);
|
||||
}
|
||||
|
||||
// 获取背板当前角度
|
||||
public double getBackboardPosition() {
|
||||
return backboardEncoder.getDistance(); // 返回背板电机编码器的当前角度
|
||||
}
|
||||
|
||||
// 检查背板是否到达目标角度
|
||||
public boolean isBackboardAtTarget() {
|
||||
return backboardPID.atGoal(); // 判断背板是否到达目标角度
|
||||
}
|
||||
|
||||
@Override
|
||||
public void periodic() {
|
||||
if(currentBackboardInalyzeMode != Mode.Inalyzing){
|
||||
backboardPID.calculate(getBackboardPosition());
|
||||
if(isBackboardAtTarget()){
|
||||
backboardMotor.set(0);
|
||||
}else{
|
||||
outputBackboard();
|
||||
}
|
||||
}
|
||||
shooterNetworkTable.getEntry("flywheelSpeed").setDouble(flywheelMotorLeft.getVelocity().getValueAsDouble());
|
||||
shooterNetworkTable.getEntry("flywheelPIDReference").setDouble(flywheelMotorLeft.getClosedLoopReference().getValueAsDouble());
|
||||
shooterNetworkTable.getEntry("conveyorSpeed").setDouble(conveyorMotor.getVelocity().getValueAsDouble());
|
||||
shooterNetworkTable.getEntry("conveyorPIDReference").setDouble(conveyorMotor.getClosedLoopReference().getValueAsDouble());
|
||||
shooterNetworkTable.getEntry("backboardCurrentRate").setDouble(getBackboardPosition());
|
||||
shooterNetworkTable.getEntry("backboardTargetRate").setDouble(backboardPID.getSetpoint().position);
|
||||
shooterNetworkTable.getEntry("isBackboardAtTarget").setBoolean(isBackboardAtTarget());
|
||||
shooterNetworkTable.getEntry("distanceGetted").setDouble(getDistance());
|
||||
shooterNetworkTable.getEntry("InalyzeBackboardMode").setString(currentBackboardInalyzeMode.name());
|
||||
}
|
||||
|
||||
private double getDistance(){
|
||||
//获得车子距离Hub的距离
|
||||
return NetworkTableInstance.getDefault().getTable("AutoControl").getEntry("distanceToHub").getDouble(0.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package frc.robot.tuning;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import com.ctre.phoenix6.controls.VelocityDutyCycle;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
import edu.wpi.first.networktables.*;
|
||||
|
||||
public class ConfigTalonFXMotorTuner {
|
||||
private final TalonFX motor;
|
||||
private final String motorName;
|
||||
private final Slot0Configs motorSlot0Configs;
|
||||
private final NetworkTable table;
|
||||
|
||||
// ---- Subscribers:读取 Elastic 改过的新值 ----
|
||||
private final BooleanSubscriber enableSub;
|
||||
private final DoubleSubscriber KpSub;
|
||||
private final DoubleSubscriber KiSub;
|
||||
private final DoubleSubscriber KdSub;
|
||||
private final DoubleSubscriber KvSub;
|
||||
private final DoubleSubscriber KaSub;
|
||||
private final DoubleSubscriber KsSub;
|
||||
|
||||
private final BooleanSubscriber enableRuningSub;
|
||||
private final DoubleSubscriber runningSpeedRPS;
|
||||
private double lastKp = 0, lastKi = 0, lastKd = 0, lastKv = 0, lastKa = 0, lastKs = 0;
|
||||
|
||||
private final VelocityDutyCycle velocityRequest = new VelocityDutyCycle(0);
|
||||
public ConfigTalonFXMotorTuner(TalonFX motor_, String motorName_, Slot0Configs motorSlot0Configs_) {
|
||||
this.motor = motor_;
|
||||
this.motorName = motorName_;
|
||||
this.motorSlot0Configs = motorSlot0Configs_;
|
||||
|
||||
this.table = NetworkTableInstance.getDefault().getTable("Tuning/" + motorName);
|
||||
|
||||
table.getBooleanTopic(motorName+"Enable").publish().set(false);
|
||||
table.getDoubleTopic(motorName+"kP").publish().set(motorSlot0Configs.kP);;
|
||||
table.getDoubleTopic(motorName+"kI").publish().set(motorSlot0Configs.kI);
|
||||
table.getDoubleTopic(motorName+"kD").publish().set(motorSlot0Configs.kD);
|
||||
table.getDoubleTopic(motorName+"kV").publish().set(motorSlot0Configs.kV);
|
||||
table.getDoubleTopic(motorName+"kA").publish().set(motorSlot0Configs.kA);
|
||||
table.getDoubleTopic(motorName+"kS").publish().set(motorSlot0Configs.kS);
|
||||
|
||||
table.getBooleanTopic(motorName+"EnableRunning").publish().set(false);;
|
||||
table.getDoubleTopic(motorName+"RunningSpeedRPS").publish().set(0);;
|
||||
|
||||
this.enableSub = table.getBooleanTopic(motorName+"Enable").subscribe(false);
|
||||
this.KpSub = table.getDoubleTopic(motorName+"kP").subscribe(motorSlot0Configs.kP);
|
||||
this.KiSub = table.getDoubleTopic(motorName+"kI").subscribe(motorSlot0Configs.kI);
|
||||
this.KdSub = table.getDoubleTopic(motorName+"kD").subscribe(motorSlot0Configs.kD);
|
||||
this.KvSub = table.getDoubleTopic(motorName+"kV").subscribe(motorSlot0Configs.kV);
|
||||
this.KaSub = table.getDoubleTopic(motorName+"kA").subscribe(motorSlot0Configs.kA);
|
||||
this.KsSub = table.getDoubleTopic(motorName+"kS").subscribe(motorSlot0Configs.kS);
|
||||
this.enableRuningSub = table.getBooleanTopic(motorName+"EnableRunning").subscribe(false);
|
||||
this.runningSpeedRPS = table.getDoubleTopic(motorName+"RunningSpeedRPS").subscribe(0);
|
||||
}
|
||||
|
||||
public void periodic(Runnable func) {
|
||||
if (!enableSub.get()) return;
|
||||
double kp = KpSub.get();
|
||||
double ki = KiSub.get();
|
||||
double kd = KdSub.get();
|
||||
double kv = KvSub.get();
|
||||
double ka = KaSub.get();
|
||||
double ks = KsSub.get();
|
||||
|
||||
if (!(kp == lastKp && ki == lastKi && kd == lastKd && kv == lastKv && ka == lastKa && ks == lastKs)) {
|
||||
|
||||
Slot0Configs slot0 = new Slot0Configs()
|
||||
.withKP(kp).withKI(ki).withKD(kd).withKV(kv).withKA(ka).withKS(ks);
|
||||
|
||||
motor.getConfigurator().apply(slot0);
|
||||
System.out.println("applyed settings: "+motorName);
|
||||
|
||||
lastKp = kp; lastKi = ki; lastKd = kd; lastKv = kv; lastKa = ka; lastKs = ks;
|
||||
|
||||
if(func!=null){
|
||||
func.run();
|
||||
}
|
||||
}
|
||||
|
||||
if (enableRuningSub.get()) {;
|
||||
double speed = runningSpeedRPS.get();
|
||||
motor.setControl(velocityRequest.withVelocity(speed));
|
||||
// System.out.println("running motor with speed: "+speed+" on motor: "+motorName);
|
||||
}else{
|
||||
motor.setControl(velocityRequest.withVelocity(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package frc.robot.tuning;
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import com.ctre.phoenix6.controls.VelocityDutyCycle;
|
||||
import com.ctre.phoenix6.controls.VelocityVoltage;
|
||||
import com.ctre.phoenix6.hardware.TalonFXS;
|
||||
|
||||
import edu.wpi.first.networktables.*;
|
||||
|
||||
public class ConfigTalonFXSMotorTuner {
|
||||
private final TalonFXS motor;
|
||||
private final String motorName;
|
||||
private final Slot0Configs motorSlot0Configs;
|
||||
private final NetworkTable table;
|
||||
|
||||
// ---- Subscribers:读取 Elastic 改过的新值 ----
|
||||
private final BooleanSubscriber enableSub;
|
||||
private final DoubleSubscriber KpSub;
|
||||
private final DoubleSubscriber KiSub;
|
||||
private final DoubleSubscriber KdSub;
|
||||
private final DoubleSubscriber KvSub;
|
||||
private final DoubleSubscriber KaSub;
|
||||
private final DoubleSubscriber KsSub;
|
||||
|
||||
private final BooleanSubscriber enableRuningSub;
|
||||
private final DoubleSubscriber runningSpeedRPS;
|
||||
private double lastKp = 0, lastKi = 0, lastKd = 0, lastKv = 0, lastKa = 0, lastKs = 0;
|
||||
|
||||
private final VelocityDutyCycle velocityRequest = new VelocityDutyCycle(0);
|
||||
public ConfigTalonFXSMotorTuner(TalonFXS motor_, String motorName_, Slot0Configs motorSlot0Configs_) {
|
||||
this.motor = motor_;
|
||||
this.motorName = motorName_;
|
||||
this.motorSlot0Configs = motorSlot0Configs_;
|
||||
|
||||
this.table = NetworkTableInstance.getDefault().getTable("Tuning/" + motorName);
|
||||
table.getBooleanTopic(motorName+"Enable").publish().set(false);
|
||||
table.getDoubleTopic(motorName+"kP").publish().set(motorSlot0Configs.kP);
|
||||
table.getDoubleTopic(motorName+"kI").publish().set(motorSlot0Configs.kI);
|
||||
table.getDoubleTopic(motorName+"kD").publish().set(motorSlot0Configs.kD);
|
||||
table.getDoubleTopic(motorName+"kV").publish().set(motorSlot0Configs.kV);
|
||||
table.getDoubleTopic(motorName+"kA").publish().set(motorSlot0Configs.kA);
|
||||
table.getDoubleTopic(motorName+"kS").publish().set(motorSlot0Configs.kS);
|
||||
|
||||
table.getBooleanTopic(motorName+"EnableRunning").publish().set(false);
|
||||
table.getDoubleTopic(motorName+"RunningSpeedRPS").publish().set(0);
|
||||
|
||||
this.enableSub = table.getBooleanTopic(motorName+"Enable").subscribe(false);
|
||||
this.KpSub = table.getDoubleTopic(motorName+"kP").subscribe(motorSlot0Configs.kP);
|
||||
this.KiSub = table.getDoubleTopic(motorName+"kI").subscribe(motorSlot0Configs.kI);
|
||||
this.KdSub = table.getDoubleTopic(motorName+"kD").subscribe(motorSlot0Configs.kD);
|
||||
this.KvSub = table.getDoubleTopic(motorName+"kV").subscribe(motorSlot0Configs.kV);
|
||||
this.KaSub = table.getDoubleTopic(motorName+"kA").subscribe(motorSlot0Configs.kA);
|
||||
this.KsSub = table.getDoubleTopic(motorName+"kS").subscribe(motorSlot0Configs.kS);
|
||||
this.enableRuningSub = table.getBooleanTopic(motorName+"EnableRunning").subscribe(false);
|
||||
this.runningSpeedRPS = table.getDoubleTopic(motorName+"RunningSpeedRPS").subscribe(0);
|
||||
}
|
||||
|
||||
public void periodic() {
|
||||
if (!enableSub.get()) return;
|
||||
|
||||
double kp = KpSub.get();
|
||||
double ki = KiSub.get();
|
||||
double kd = KdSub.get();
|
||||
double kv = KvSub.get();
|
||||
double ka = KaSub.get();
|
||||
double ks = KsSub.get();
|
||||
|
||||
if (!(kp == lastKp && ki == lastKi && kd == lastKd && kv == lastKv && ka == lastKa && ks == lastKs)) {
|
||||
|
||||
Slot0Configs slot0 = new Slot0Configs()
|
||||
.withKP(kp).withKI(ki).withKD(kd).withKV(kv).withKA(ka).withKS(ks);
|
||||
|
||||
motor.getConfigurator().apply(slot0);
|
||||
System.out.println("applyed settings: "+motorName);
|
||||
|
||||
lastKp = kp; lastKi = ki; lastKd = kd; lastKv = kv; lastKa = ka; lastKs = ks;
|
||||
}
|
||||
|
||||
if (enableRuningSub.get()) {;
|
||||
double speed = runningSpeedRPS.get();
|
||||
motor.setControl(velocityRequest.withVelocity(speed));
|
||||
// System.out.println("running motor with speed: "+speed+" on motor: "+motorName);
|
||||
}else{
|
||||
motor.setControl(velocityRequest.withVelocity(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package frc.robot.tuning;
|
||||
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
import com.ctre.phoenix6.swerve.SwerveDrivetrain;
|
||||
import edu.wpi.first.networktables.*;
|
||||
|
||||
public class DriveGainsTuner {
|
||||
private final NetworkTable table =
|
||||
NetworkTableInstance.getDefault().getTable("Tuning/Drive");
|
||||
|
||||
// ---- Publishers:让 Elastic 能“看到”这些键,并给初值 ----
|
||||
private final BooleanPublisher enablePub =
|
||||
table.getBooleanTopic("Enable").publish();
|
||||
|
||||
private final DoublePublisher kpPub = table.getDoubleTopic("kP").publish();
|
||||
private final DoublePublisher kiPub = table.getDoubleTopic("kI").publish();
|
||||
private final DoublePublisher kdPub = table.getDoubleTopic("kD").publish();
|
||||
private final DoublePublisher kvPub = table.getDoubleTopic("kV").publish();
|
||||
|
||||
// ---- Subscribers:读取 Elastic 改过的新值 ----
|
||||
private final BooleanSubscriber enableSub =
|
||||
table.getBooleanTopic("Enable").subscribe(false);
|
||||
|
||||
private final DoubleSubscriber kpSub = table.getDoubleTopic("kP").subscribe(0.01);
|
||||
private final DoubleSubscriber kiSub = table.getDoubleTopic("kI").subscribe(0.0);
|
||||
private final DoubleSubscriber kdSub = table.getDoubleTopic("kD").subscribe(0.0);
|
||||
private final DoubleSubscriber kvSub = table.getDoubleTopic("kV").subscribe(0.124);
|
||||
|
||||
private double lastKP = Double.NaN, lastKI = Double.NaN, lastKD = Double.NaN, lastKV = Double.NaN;
|
||||
|
||||
private final TalonFX[] driveMotors;
|
||||
|
||||
public DriveGainsTuner(SwerveDrivetrain<?, ?, ?> drivetrain) {
|
||||
// 发布初始值(这一步做完 Elastic 就能看到这些键)
|
||||
enablePub.set(false);
|
||||
kpPub.set(0.01);
|
||||
kiPub.set(0.0);
|
||||
kdPub.set(0.0);
|
||||
kvPub.set(0.124);
|
||||
|
||||
var modules = drivetrain.getModules();
|
||||
driveMotors = new TalonFX[modules.length];
|
||||
for (int i = 0; i < modules.length; i++) {
|
||||
driveMotors[i] = (TalonFX) modules[i].getDriveMotor();
|
||||
}
|
||||
}
|
||||
|
||||
public void periodic() {
|
||||
if (!enableSub.get()) return;
|
||||
|
||||
double kp = kpSub.get();
|
||||
double ki = kiSub.get();
|
||||
double kd = kdSub.get();
|
||||
double kv = kvSub.get();
|
||||
|
||||
if (kp == lastKP && ki == lastKI && kd == lastKD && kv == lastKV) return;
|
||||
|
||||
Slot0Configs slot0 = new Slot0Configs()
|
||||
.withKP(kp).withKI(ki).withKD(kd).withKV(kv);
|
||||
|
||||
for (TalonFX m : driveMotors) {
|
||||
m.getConfigurator().apply(slot0);
|
||||
}
|
||||
|
||||
lastKP = kp; lastKI = ki; lastKD = kd; lastKV = kv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package frc.robot.utils;
|
||||
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
import edu.wpi.first.wpilibj2.command.button.RobotModeTriggers;
|
||||
import frc.robot.subsystems.LEDSubsystem;
|
||||
|
||||
public final class LedBindings {
|
||||
private LedBindings() {}
|
||||
|
||||
public static void bindModeIndicators(LEDSubsystem leds) {
|
||||
// Disabled:左右红色呼吸(允许在禁用状态运行)
|
||||
RobotModeTriggers.disabled().onTrue(
|
||||
Commands.runOnce(() -> {
|
||||
leds.breathLeft(255, 0, 0, 1.0);
|
||||
leds.breathRight(255, 0, 0, 1.0);
|
||||
}, leds).ignoringDisable(true)
|
||||
);
|
||||
|
||||
// Teleop:左右彩虹
|
||||
RobotModeTriggers.teleop().onTrue(
|
||||
Commands.runOnce(leds::rainbowAll, leds)
|
||||
);
|
||||
|
||||
// Auto:左右蓝色常亮
|
||||
RobotModeTriggers.autonomous().onTrue(
|
||||
Commands.runOnce(() -> {
|
||||
leds.solidLeft(0, 0, 255);
|
||||
leds.solidRight(0, 0, 255);
|
||||
}, leds)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
{
|
||||
"Version": "1.0.0.0",
|
||||
"LastState": 11,
|
||||
"Modules": [
|
||||
{
|
||||
"ModuleName": "Front Left",
|
||||
"ModuleId": 0,
|
||||
"Encoder": {
|
||||
"Id": 13,
|
||||
"Name": "Mod1 Cancoder",
|
||||
"Model": "CANCoder vers. H",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": null
|
||||
},
|
||||
"SteerMotor": {
|
||||
"Id": 12,
|
||||
"Name": "Mod1 Angle",
|
||||
"Model": "Talon FX",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"DriveMotor": {
|
||||
"Id": 11,
|
||||
"Name": "Mod1 Drive",
|
||||
"Model": "Talon FX vers. C",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"IsEncoderInverted": false,
|
||||
"IsSteerInverted": false,
|
||||
"SelectedEncoderType": "CANcoder",
|
||||
"EncoderOffset": -0.412841796875,
|
||||
"DriveMotorSelectionState": 1,
|
||||
"SteerMotorSelectionState": 1,
|
||||
"SteerEncoderSelectionState": 1,
|
||||
"IsModuleValidationComplete": true,
|
||||
"ValidatedSteerId": 12,
|
||||
"ValidatedDriveId": 11,
|
||||
"ValidatedEncoderId": 13
|
||||
},
|
||||
{
|
||||
"ModuleName": "Front Right",
|
||||
"ModuleId": 1,
|
||||
"Encoder": {
|
||||
"Id": 23,
|
||||
"Name": "Mod2 Cancoder",
|
||||
"Model": "CANCoder vers. H",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": null
|
||||
},
|
||||
"SteerMotor": {
|
||||
"Id": 22,
|
||||
"Name": "Mod2 Angle",
|
||||
"Model": "Talon FX",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"DriveMotor": {
|
||||
"Id": 21,
|
||||
"Name": "Mod2 Drive",
|
||||
"Model": "Talon FX vers. C",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"IsEncoderInverted": false,
|
||||
"IsSteerInverted": false,
|
||||
"SelectedEncoderType": "CANcoder",
|
||||
"EncoderOffset": -0.012939453125,
|
||||
"DriveMotorSelectionState": 1,
|
||||
"SteerMotorSelectionState": 1,
|
||||
"SteerEncoderSelectionState": 1,
|
||||
"IsModuleValidationComplete": true,
|
||||
"ValidatedSteerId": 22,
|
||||
"ValidatedDriveId": 21,
|
||||
"ValidatedEncoderId": 23
|
||||
},
|
||||
{
|
||||
"ModuleName": "Back Left",
|
||||
"ModuleId": 2,
|
||||
"Encoder": {
|
||||
"Id": 3,
|
||||
"Name": "Mod0 Cancoder",
|
||||
"Model": "CANCoder",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": null
|
||||
},
|
||||
"SteerMotor": {
|
||||
"Id": 2,
|
||||
"Name": "Mod0 Angle",
|
||||
"Model": "Talon FX",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"DriveMotor": {
|
||||
"Id": 1,
|
||||
"Name": "Mod0 Drive",
|
||||
"Model": "Talon FX vers. C",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"IsEncoderInverted": false,
|
||||
"IsSteerInverted": false,
|
||||
"SelectedEncoderType": "CANcoder",
|
||||
"EncoderOffset": 0.07275390625,
|
||||
"DriveMotorSelectionState": 1,
|
||||
"SteerMotorSelectionState": 1,
|
||||
"SteerEncoderSelectionState": 1,
|
||||
"IsModuleValidationComplete": true,
|
||||
"ValidatedSteerId": 2,
|
||||
"ValidatedDriveId": 1,
|
||||
"ValidatedEncoderId": 3
|
||||
},
|
||||
{
|
||||
"ModuleName": "Back Right",
|
||||
"ModuleId": 3,
|
||||
"Encoder": {
|
||||
"Id": 33,
|
||||
"Name": "Mod3 Cancoder",
|
||||
"Model": "CANCoder vers. H",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": null
|
||||
},
|
||||
"SteerMotor": {
|
||||
"Id": 32,
|
||||
"Name": "Mod3 Angle",
|
||||
"Model": "Talon FX",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"DriveMotor": {
|
||||
"Id": 31,
|
||||
"Name": "Mod3 Drive",
|
||||
"Model": "Talon FX vers. C",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": {
|
||||
"Name": "WCP Kraken x60",
|
||||
"FreeSpeedRps": 96.7,
|
||||
"SlipCurrentLimit": 120,
|
||||
"StatorCurrentLimit": 60
|
||||
}
|
||||
},
|
||||
"IsEncoderInverted": false,
|
||||
"IsSteerInverted": false,
|
||||
"SelectedEncoderType": "CANcoder",
|
||||
"EncoderOffset": -0.4892578125,
|
||||
"DriveMotorSelectionState": 1,
|
||||
"SteerMotorSelectionState": 1,
|
||||
"SteerEncoderSelectionState": 1,
|
||||
"IsModuleValidationComplete": true,
|
||||
"ValidatedSteerId": 32,
|
||||
"ValidatedDriveId": 31,
|
||||
"ValidatedEncoderId": 33
|
||||
}
|
||||
],
|
||||
"SwerveOptions": {
|
||||
"Gyro": {
|
||||
"Id": 0,
|
||||
"Name": "Pigeon 2 vers. S (Device ID 0)",
|
||||
"Model": "Pigeon 2 vers. S",
|
||||
"CANbus": "rio",
|
||||
"CANbusFriendly": "",
|
||||
"SelectedMotorType": null
|
||||
},
|
||||
"IsValidGyroCANbus": true,
|
||||
"VerticalTrackSizeInches": 22.75,
|
||||
"HorizontalTrackSizeInches": 22.75,
|
||||
"WheelRadiusInches": 1.81,
|
||||
"IsLeftSideInverted": false,
|
||||
"IsRightSideInverted": true,
|
||||
"SwerveModuleType": 6,
|
||||
"SwerveModuleConfiguration": {
|
||||
"ModuleBrand": 6,
|
||||
"DriveRatio": 5.902777777777778,
|
||||
"SteerRatio": 12.8,
|
||||
"CouplingRatio": 3.125,
|
||||
"CustomName": "L2+"
|
||||
},
|
||||
"HasVerifiedSteer": true,
|
||||
"SelectedModuleManufacturer": "Swerve Drive Specialties (SDS)",
|
||||
"HasVerifiedDrive": true,
|
||||
"IsValidConfiguration": true
|
||||
},
|
||||
"TeamNumber": 6494,
|
||||
"schema_version": "1"
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"fileName": "PathplannerLib-2026.1.2.json",
|
||||
"name": "PathplannerLib",
|
||||
"version": "2026.1.2",
|
||||
"uuid": "1b42324f-17c6-4875-8e77-1c312bc8c786",
|
||||
"frcYear": "2026",
|
||||
"mavenUrls": [
|
||||
"https://3015rangerrobotics.github.io/pathplannerlib/repo"
|
||||
],
|
||||
"jsonUrl": "https://3015rangerrobotics.github.io/pathplannerlib/PathplannerLib.json",
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "com.pathplanner.lib",
|
||||
"artifactId": "PathplannerLib-java",
|
||||
"version": "2026.1.2"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "com.pathplanner.lib",
|
||||
"artifactId": "PathplannerLib-cpp",
|
||||
"version": "2026.1.2",
|
||||
"libName": "PathplannerLib",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"osxuniversal",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"linuxarm64"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,449 @@
|
||||
{
|
||||
"fileName": "Phoenix6-26.1.1.json",
|
||||
"name": "CTRE-Phoenix (v6)",
|
||||
"version": "26.1.1",
|
||||
"frcYear": "2026",
|
||||
"uuid": "e995de00-2c64-4df5-8831-c1441420ff19",
|
||||
"mavenUrls": [
|
||||
"https://maven.ctr-electronics.com/release/"
|
||||
],
|
||||
"jsonUrl": "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/latest/Phoenix6-frc2026-latest.json",
|
||||
"conflictsWith": [
|
||||
{
|
||||
"uuid": "e7900d8d-826f-4dca-a1ff-182f658e98af",
|
||||
"errorMessage": "Users can not have both the replay and regular Phoenix 6 vendordeps in their robot program.",
|
||||
"offlineFileName": "Phoenix6-replay-frc2026-latest.json"
|
||||
}
|
||||
],
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "wpiapi-java",
|
||||
"version": "26.1.1"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "api-cpp",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "tools",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "api-cpp-sim",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "tools-sim",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simTalonSRX",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simVictorSPX",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simPigeonIMU",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProTalonFX",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProTalonFXS",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANcoder",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProPigeon2",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANrange",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANdi",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANdle",
|
||||
"version": "26.1.1",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
}
|
||||
],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "wpiapi-cpp",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_Phoenix6_WPI",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "tools",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_PhoenixTools",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "wpiapi-cpp-sim",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_Phoenix6_WPISim",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "tools-sim",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_PhoenixTools_Sim",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simTalonSRX",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimTalonSRX",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simVictorSPX",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimVictorSPX",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simPigeonIMU",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimPigeonIMU",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProTalonFX",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProTalonFX",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProTalonFXS",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProTalonFXS",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANcoder",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProCANcoder",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProPigeon2",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProPigeon2",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANrange",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProCANrange",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANdi",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProCANdi",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANdle",
|
||||
"version": "26.1.1",
|
||||
"libName": "CTRE_SimProCANdle",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"fileName": "WPILibNewCommands.json",
|
||||
"name": "WPILib-New-Commands",
|
||||
"version": "1.0.0",
|
||||
"uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266",
|
||||
"frcYear": "2026",
|
||||
"mavenUrls": [],
|
||||
"jsonUrl": "",
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "edu.wpi.first.wpilibNewCommands",
|
||||
"artifactId": "wpilibNewCommands-java",
|
||||
"version": "wpilib"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "edu.wpi.first.wpilibNewCommands",
|
||||
"artifactId": "wpilibNewCommands-cpp",
|
||||
"version": "wpilib",
|
||||
"libName": "wpilibNewCommands",
|
||||
"headerClassifier": "headers",
|
||||
"sourcesClassifier": "sources",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"linuxsystemcore",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"linuxarm64",
|
||||
"windowsx86-64",
|
||||
"windowsx86",
|
||||
"linuxx86-64",
|
||||
"osxuniversal"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user