From 37c9c6d8cd39f14a93a90b7778fd3e7a8aae108f Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sun, 11 Jan 2026 16:26:20 -0600 Subject: [PATCH 001/161] Seed development branch with 2024 and 2025 snapshots This commit seeds a new development branch with the files in the tip of the same branch from robot-code-2024 and robot-code-2025. --- .../documentation/2024 Robot User Manual.pdf | Bin 234370 -> 233675 bytes .../src/main/java/frc/robot/Constants.java | 35 +-- .../main/java/frc/robot/RobotContainer.java | 36 +-- .../frc/robot/subsystems/DriveSubsystem.java | 36 +-- .../subsystems/GooseRotationSubsystem.java | 17 +- .../Examples/PrototypeBoard/.gitignore | 187 +++++++++++++ .../PrototypeBoard/.vscode/launch.json | 21 ++ .../PrototypeBoard/.vscode/settings.json | 60 +++++ .../.wpilib/wpilib_preferences.json | 6 + .../Examples/PrototypeBoard/WPILib-License.md | 24 ++ .../Examples/PrototypeBoard/build.gradle | 104 ++++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../Examples/PrototypeBoard/gradlew | 252 ++++++++++++++++++ .../Examples/PrototypeBoard/gradlew.bat | 94 +++++++ .../Examples/PrototypeBoard/settings.gradle | 30 +++ .../src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Main.java | 25 ++ .../src/main/java/frc/robot/Robot.java | 113 ++++++++ .../PrototypeBoard/vendordeps/REVLib.json} | 12 +- .../vendordeps/WPILibNewCommands.json | 38 +++ 2025-Reefscape/Examples/Shooter/.gitignore | 187 +++++++++++++ .../Examples/Shooter/.vscode/launch.json | 21 ++ .../Examples/Shooter/.vscode/settings.json | 60 +++++ .../Shooter/.wpilib/wpilib_preferences.json | 6 + .../Examples/Shooter/WPILib-License.md | 24 ++ 2025-Reefscape/Examples/Shooter/build.gradle | 104 ++++++++ .../Shooter/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + 2025-Reefscape/Examples/Shooter/gradlew | 252 ++++++++++++++++++ 2025-Reefscape/Examples/Shooter/gradlew.bat | 94 +++++++ .../Examples/Shooter/settings.gradle | 30 +++ .../Shooter/src/main/deploy/example.txt | 3 + .../Shooter/src/main/java/frc/robot/Main.java | 25 ++ .../src/main/java/frc/robot/Robot.java | 58 ++++ .../Examples/Shooter/vendordeps/REVLib.json | 71 +++++ .../Shooter/vendordeps/WPILibNewCommands.json | 38 +++ 2025-Reefscape/build.gradle | 2 +- .../src/main/java/frc/robot/Constants.java | 34 ++- .../main/java/frc/robot/RobotContainer.java | 14 + .../robot/commands/ShooterSpeedCommand.java | 55 ++++ .../robot/subsystems/ShooterSubsystem.java | 57 ++++ ....3.1.json => Phoenix6-frc2025-latest.json} | 207 +++++--------- 2025-Reefscape/vendordeps/REVLib.json | 71 +++++ .../vendordeps/libgrapplefrc2025.json | 10 +- 45 files changed, 2294 insertions(+), 236 deletions(-) create mode 100644 2025-Reefscape/Examples/PrototypeBoard/.gitignore create mode 100644 2025-Reefscape/Examples/PrototypeBoard/.vscode/launch.json create mode 100644 2025-Reefscape/Examples/PrototypeBoard/.vscode/settings.json create mode 100644 2025-Reefscape/Examples/PrototypeBoard/.wpilib/wpilib_preferences.json create mode 100644 2025-Reefscape/Examples/PrototypeBoard/WPILib-License.md create mode 100644 2025-Reefscape/Examples/PrototypeBoard/build.gradle create mode 100644 2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.jar create mode 100644 2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.properties create mode 100644 2025-Reefscape/Examples/PrototypeBoard/gradlew create mode 100644 2025-Reefscape/Examples/PrototypeBoard/gradlew.bat create mode 100644 2025-Reefscape/Examples/PrototypeBoard/settings.gradle create mode 100644 2025-Reefscape/Examples/PrototypeBoard/src/main/deploy/example.txt create mode 100644 2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Main.java create mode 100644 2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Robot.java rename 2025-Reefscape/{vendordeps/REVLib-2025.0.0.json => Examples/PrototypeBoard/vendordeps/REVLib.json} (90%) create mode 100644 2025-Reefscape/Examples/PrototypeBoard/vendordeps/WPILibNewCommands.json create mode 100644 2025-Reefscape/Examples/Shooter/.gitignore create mode 100644 2025-Reefscape/Examples/Shooter/.vscode/launch.json create mode 100644 2025-Reefscape/Examples/Shooter/.vscode/settings.json create mode 100644 2025-Reefscape/Examples/Shooter/.wpilib/wpilib_preferences.json create mode 100644 2025-Reefscape/Examples/Shooter/WPILib-License.md create mode 100644 2025-Reefscape/Examples/Shooter/build.gradle create mode 100644 2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.jar create mode 100644 2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.properties create mode 100644 2025-Reefscape/Examples/Shooter/gradlew create mode 100644 2025-Reefscape/Examples/Shooter/gradlew.bat create mode 100644 2025-Reefscape/Examples/Shooter/settings.gradle create mode 100644 2025-Reefscape/Examples/Shooter/src/main/deploy/example.txt create mode 100644 2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Main.java create mode 100644 2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Robot.java create mode 100644 2025-Reefscape/Examples/Shooter/vendordeps/REVLib.json create mode 100644 2025-Reefscape/Examples/Shooter/vendordeps/WPILibNewCommands.json create mode 100644 2025-Reefscape/src/main/java/frc/robot/commands/ShooterSpeedCommand.java create mode 100644 2025-Reefscape/src/main/java/frc/robot/subsystems/ShooterSubsystem.java rename 2025-Reefscape/vendordeps/{Phoenix6-25.3.1.json => Phoenix6-frc2025-latest.json} (72%) create mode 100644 2025-Reefscape/vendordeps/REVLib.json diff --git a/2024-Crescendo/documentation/2024 Robot User Manual.pdf b/2024-Crescendo/documentation/2024 Robot User Manual.pdf index 9443c10497605adcebd62440cd7ab13a8e3592ba..fad6144e0e9e0a618d7229f1bb334c976cd6e0b1 100644 GIT binary patch delta 5680 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 delta 6373 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 m_autoChooser = new SendableChooser<>(); - private final SendableChooser m_driveTypeChooser = new SendableChooser<>(); // The robot's subsystems and commands are defined here... private final PneumaticHub m_pnuematicHub = new PneumaticHub(); @@ -49,20 +47,16 @@ public class RobotContainer { // Joysticks private final XboxController m_operatorController = new XboxController(OperatorConstants.kOperatorController); - private final Joystick m_driverJoystickLeft = new Joystick(DriverConstants.kLeftDriveJoystick); - private final Joystick m_driverJoystickRight = new Joystick(DriverConstants.kRightDriveJoystick); + private final Joystick m_driverJoystick = new Joystick(DriverConstants.kDriveJoystick); // Driver Buttons public final JoystickButton m_lowGearButton = - new JoystickButton(m_driverJoystickLeft, DriverConstants.kLowGear); + new JoystickButton(m_driverJoystick, DriverConstants.kLowGear); public final JoystickButton m_forwardModeButton = - new JoystickButton(m_driverJoystickLeft, DriverConstants.kForwardMode); + new JoystickButton(m_driverJoystick, DriverConstants.kForwardMode); public final JoystickButton m_reverseModeButton = - new JoystickButton(m_driverJoystickLeft, DriverConstants.kReverseMode); - - public final JoystickButton m_driveStraightButton = - new JoystickButton(m_driverJoystickRight, DriverConstants.kDriveStraight); + new JoystickButton(m_driverJoystick, DriverConstants.kReverseMode); // Pnuematics Climb Buttons private final JoystickButton m_climbUpButton = @@ -112,12 +106,6 @@ public void reportStatus() { SmartDashboard.putBoolean("Compressor Running", m_pnuematicHub.getCompressor()); } - if(m_tickCount % (RobotConstants.periodicTicksPerSecond/RobotConstants.imuReportingFreq) == 0) - { - // Report IMU state. - SmartDashboard.putNumber("Heading", m_driveSubsystem.getHeading()); - } - if(m_tickCount % (RobotConstants.periodicTicksPerSecond/RobotConstants.gooseReportingFreq) == 0) { // Report Goose ARM state. @@ -139,28 +127,18 @@ private void configureDriverStationControls() m_autoChooser.addOption("Drive forward 4 Seconds", new AutonomousDrive4Sec(m_driveSubsystem)); m_autoChooser.addOption("Drive forward 6 Seconds", new AutonomousDrive6Sec(m_driveSubsystem)); SmartDashboard.putData(m_autoChooser); - - // Drive control option selector - m_driveTypeChooser.setDefaultOption("Arcade Drive", true); - m_driveTypeChooser.addOption("Tank Drive", false); - SmartDashboard.putData(m_driveTypeChooser); } private void configureBindings() { // Drive Controllers. We set arcade drive as the default here but may change this // during teleopInit depending upon the value of a dashboard chooser. - m_driveSubsystem.initDefaultCommand(m_driverJoystickLeft, m_driverJoystickRight, true); - m_lowGearButton.onTrue(new SetGearCommand(m_driveSubsystem, true)); m_lowGearButton.onFalse(new SetGearCommand(m_driveSubsystem, false)); m_forwardModeButton.onTrue(new SetModeCommand(m_driveSubsystem, false)); m_reverseModeButton.onTrue(new SetModeCommand(m_driveSubsystem, true)); - m_driveStraightButton.onTrue(new SetDriveStraightCommand(m_driveSubsystem, true)); - m_driveStraightButton.onFalse(new SetDriveStraightCommand(m_driveSubsystem, false)); - // Climb Buttons m_climbUpButton.onTrue(new ClimbCommand(m_climbSubsystem, ClimbSubsystem.State.LIFTED)); m_climbDownButton.onTrue(new ClimbCommand(m_climbSubsystem, ClimbSubsystem.State.GROUNDED)); @@ -206,11 +184,9 @@ public Command getAutonomousCommand() { return m_autoChooser.getSelected(); } - // Set the driver's choice of control mode based on the selection provided - // in a dashboard control. + // Set drive command to arcade public void setDriveType() { - Boolean bArcade = m_driveTypeChooser.getSelected(); - m_driveSubsystem.initDefaultCommand(m_driverJoystickLeft, m_driverJoystickRight, bArcade); + m_driveSubsystem.initDefaultCommand(m_driverJoystick); } } diff --git a/2024-Crescendo/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2024-Crescendo/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 1756438..3a94f54 100644 --- a/2024-Crescendo/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2024-Crescendo/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -5,17 +5,15 @@ package frc.robot.subsystems; import frc.robot.Constants.*; -import frc.robot.commands.TankDriveCommand; import frc.robot.commands.ArcadeDriveCommand; import edu.wpi.first.wpilibj2.command.SubsystemBase; import edu.wpi.first.wpilibj.Joystick; import edu.wpi.first.wpilibj.drive.DifferentialDrive; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; -import edu.wpi.first.wpilibj.SPI; import com.ctre.phoenix6.controls.Follower; import com.ctre.phoenix6.hardware.TalonFX; -import com.kauailabs.navx.frc.AHRS; +import com.ctre.phoenix6.signals.NeutralModeValue; public class DriveSubsystem extends SubsystemBase { @@ -23,11 +21,10 @@ public class DriveSubsystem extends SubsystemBase private final TalonFX m_leftBackMotor = new TalonFX(DrivetrainConstants.kLeftBackMotorCANID); private final TalonFX m_rightFrontMotor = new TalonFX(DrivetrainConstants.kRightFrontMotorCANID); private final TalonFX m_rightBackMotor = new TalonFX(DrivetrainConstants.kRightBackMotorCANID); - private final AHRS m_NavX = new AHRS(SPI.Port.kMXP); private DifferentialDrive m_Drivetrain; private double m_leftSpeed = 0.0; private double m_rightSpeed = 0.0; - private double m_speedDivider = 1.0; + private double m_speedDivider = 2.5; // Default 1.0 private double m_modeMultiplier = 1.0; private boolean m_driveStraight = false; @@ -42,28 +39,24 @@ public DriveSubsystem() m_rightFrontMotor.setInverted(true); m_rightBackMotor.setInverted(true); + // Set all motors to brake mode for safety. In the default, coast mode, + // the robot takes very much longer to stop if the joystick is released or + // and emergency stop occurs. In this mode, it stops very quickly. + m_leftFrontMotor.setNeutralMode(NeutralModeValue.Brake); + m_leftBackMotor.setNeutralMode(NeutralModeValue.Brake); + m_rightFrontMotor.setNeutralMode(NeutralModeValue.Brake); + m_rightBackMotor.setNeutralMode(NeutralModeValue.Brake); + /* Set back motors to follow the front motors. */ m_leftBackMotor.setControl(new Follower(m_leftFrontMotor.getDeviceID(), false)); m_rightBackMotor.setControl(new Follower(m_rightFrontMotor.getDeviceID(), false)); m_Drivetrain = new DifferentialDrive(m_leftFrontMotor, m_rightFrontMotor); - - - // Set gyro 0 angle to point forward. - m_NavX.reset(); - m_NavX.zeroYaw(); } - public void initDefaultCommand(Joystick leftJoystick, Joystick rightJoystick, Boolean bArcadeDrive) + public void initDefaultCommand(Joystick leftJoystick) { - if (bArcadeDrive) - { - setDefaultCommand(new ArcadeDriveCommand(this, leftJoystick)); - } - else - { - setDefaultCommand(new TankDriveCommand(this, leftJoystick, rightJoystick)); - } + setDefaultCommand(new ArcadeDriveCommand(this, leftJoystick)); } // Sets left and right motors to set speeds to support tank drive models. @@ -118,11 +111,6 @@ public double getSpeed(boolean bLeft) } } - public double getHeading() - { - return (double)m_NavX.getYaw(); - } - @Override public void periodic() { // This method will be called once per scheduler run diff --git a/2024-Crescendo/src/main/java/frc/robot/subsystems/GooseRotationSubsystem.java b/2024-Crescendo/src/main/java/frc/robot/subsystems/GooseRotationSubsystem.java index cef95e2..79cf7b4 100644 --- a/2024-Crescendo/src/main/java/frc/robot/subsystems/GooseRotationSubsystem.java +++ b/2024-Crescendo/src/main/java/frc/robot/subsystems/GooseRotationSubsystem.java @@ -69,6 +69,14 @@ public GooseRotationSubsystem() m_pidController.setFF(m_kFF); m_pidController.setOutputRange(m_kMinOutput, m_kMaxOutput); + if (GooseRotationConstants.kUseSmartMotion) + { + m_pidController.setSmartMotionMaxVelocity(GooseRotationConstants.kMaxVelocity, GooseRotationConstants.kSmartMotionSlot); + m_pidController.setSmartMotionMinOutputVelocity(GooseRotationConstants.kMinVelocity, GooseRotationConstants.kSmartMotionSlot); + m_pidController.setSmartMotionMaxAccel(GooseRotationConstants.kMaxAcceleration, GooseRotationConstants.kSmartMotionSlot); + m_pidController.setSmartMotionAllowedClosedLoopError(GooseRotationConstants.kMaxError, GooseRotationConstants.kSmartMotionSlot); + } + // display PID coefficients on SmartDashboard SmartDashboard.putNumber("P Gain", m_kP); SmartDashboard.putNumber("I Gain", m_kI); @@ -104,7 +112,14 @@ public void setSetPointAngle(double angleDegrees) double setpoint = getMotorPositionFromAngle(angleDegrees); SmartDashboard.putNumber("Set Degress", m_angleSet); SmartDashboard.putNumber("Set Reference", setpoint); - m_pidController.setReference(setpoint, CANSparkBase.ControlType.kPosition); + if(GooseRotationConstants.kUseSmartMotion) + { + m_pidController.setReference(setpoint, CANSparkBase.ControlType.kSmartMotion); + } + else + { + m_pidController.setReference(setpoint, CANSparkBase.ControlType.kPosition); + } } public double getSetPointAngle() diff --git a/2025-Reefscape/Examples/PrototypeBoard/.gitignore b/2025-Reefscape/Examples/PrototypeBoard/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/.gitignore @@ -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 diff --git a/2025-Reefscape/Examples/PrototypeBoard/.vscode/launch.json b/2025-Reefscape/Examples/PrototypeBoard/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/2025-Reefscape/Examples/PrototypeBoard/.vscode/settings.json b/2025-Reefscape/Examples/PrototypeBoard/.vscode/settings.json new file mode 100644 index 0000000..612cdd0 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/.vscode/settings.json @@ -0,0 +1,60 @@ +{ + "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.*", + ] +} diff --git a/2025-Reefscape/Examples/PrototypeBoard/.wpilib/wpilib_preferences.json b/2025-Reefscape/Examples/PrototypeBoard/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..a792267 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2025", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/2025-Reefscape/Examples/PrototypeBoard/WPILib-License.md b/2025-Reefscape/Examples/PrototypeBoard/WPILib-License.md new file mode 100644 index 0000000..645e542 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2024 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/2025-Reefscape/Examples/PrototypeBoard/build.gradle b/2025-Reefscape/Examples/PrototypeBoard/build.gradle new file mode 100644 index 0000000..c6fea4f --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/build.gradle @@ -0,0 +1,104 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2025.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 JNI. +wpi.java.debugJni = false + +// Set this to true to enable desktop support. +def includeDesktopSupport = true + +// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. +// Also defines JUnit 5. +dependencies { + 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' +} diff --git a/2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.jar b/2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.properties b/2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/2025-Reefscape/Examples/PrototypeBoard/gradlew b/2025-Reefscape/Examples/PrototypeBoard/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/gradlew @@ -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" "$@" diff --git a/2025-Reefscape/Examples/PrototypeBoard/gradlew.bat b/2025-Reefscape/Examples/PrototypeBoard/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/gradlew.bat @@ -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 diff --git a/2025-Reefscape/Examples/PrototypeBoard/settings.gradle b/2025-Reefscape/Examples/PrototypeBoard/settings.gradle new file mode 100644 index 0000000..c493958 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/settings.gradle @@ -0,0 +1,30 @@ +import org.gradle.internal.os.OperatingSystem + +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + String frcYear = '2025' + File frcHome + if (OperatingSystem.current().isWindows()) { + String publicFolder = System.getenv('PUBLIC') + if (publicFolder == null) { + publicFolder = "C:\\Users\\Public" + } + def homeRoot = new File(publicFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } else { + def userFolder = System.getProperty("user.home") + def homeRoot = new File(userFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } + def frcHomeMaven = new File(frcHome, 'maven') + maven { + name = 'frcHome' + url = frcHomeMaven + } + } +} + +Properties props = System.getProperties(); +props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true"); diff --git a/2025-Reefscape/Examples/PrototypeBoard/src/main/deploy/example.txt b/2025-Reefscape/Examples/PrototypeBoard/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Main.java b/2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Robot.java b/2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..c1714ad --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/src/main/java/frc/robot/Robot.java @@ -0,0 +1,113 @@ +// 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.Compressor; +import edu.wpi.first.wpilibj.Solenoid; +import edu.wpi.first.wpilibj.Joystick; +import edu.wpi.first.wpilibj.PneumaticsModuleType; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.shuffleboard.Shuffleboard; +import edu.wpi.first.wpilibj.shuffleboard.ShuffleboardTab; +import com.revrobotics.spark.SparkMax; +import com.revrobotics.spark.SparkLowLevel.MotorType; + +/** + * This is a sample program showing the use of the solenoid classes during operator control. Three + * buttons from a joystick will be used to control two solenoids: One button to control the position + * of a single solenoid and the other two buttons to control a double solenoid. Single solenoids can + * either be on or off, such that the air diverted through them goes through either one channel or + * the other. Double solenoids have three states: Off, Forward, and Reverse. Forward and Reverse + * divert the air through the two channels and correspond to the on and off of a single solenoid, + * but a double solenoid can also be "off", where the solenoid will remain in its default power off + * state. Additionally, double solenoids take up two channels on your PCM whereas single solenoids + * only take a single channel. + */ +public class Robot extends TimedRobot { + private final Joystick m_stick = new Joystick(0); + + // DoubleSolenoid corresponds to a double solenoid. + // In this case, it's connected to channels 1 and 2 of a PH with the default CAN ID. + private final Solenoid m_Solenoid = + new Solenoid(PneumaticsModuleType.REVPH, 0); + + // Compressor connected to a PH with a default CAN ID (1) + private final Compressor m_compressor = new Compressor(PneumaticsModuleType.REVPH); + + static final int kSolenoidForwardButton = 2; + static final int kSolenoidReverseButton = 3; + static final int kCompressorButton = 4; + + static final int kMotor1CANID = 10; + static final int kMotor2CANID = 20; + + private final SparkMax m_Motor1 = new SparkMax(kMotor1CANID, MotorType.kBrushless); + private final SparkMax m_Motor2 = new SparkMax(kMotor2CANID, MotorType.kBrushless); + + /** Called once at the beginning of the robot program. */ + public Robot() { + // Publish elements to shuffleboard. + ShuffleboardTab tab = Shuffleboard.getTab("Pneumatics"); + tab.add("Solenoid", m_Solenoid); + tab.add("Compressor", m_compressor); + + // Also publish some raw data + // Get the pressure (in PSI) from the analog sensor connected to the PH. + // This function is supported only on the PH! + // On a PCM, this function will return 0. + tab.addDouble("PH Pressure [PSI]", m_compressor::getPressure); + // Get compressor current draw. + tab.addDouble("Compressor Current", m_compressor::getCurrent); + // Get whether the compressor is active. + tab.addBoolean("Compressor Active", m_compressor::isEnabled); + // Get the digital pressure switch connected to the PCM/PH. + // The switch is open when the pressure is over ~120 PSI. + tab.addBoolean("Pressure Switch", m_compressor::getPressureSwitchValue); + + m_Motor1.set(0.0); + m_Motor2.set(0.0); + } + + @SuppressWarnings("PMD.UnconditionalIfStatement") + @Override + public void teleopPeriodic() { + + /* + * The joystick Y axis control the speed of motor 1 and the X + * axis controls motor 2. + */ + double speed = m_stick.getY(); + m_Motor1.set(speed); + + speed = m_stick.getX(); + m_Motor2.set(speed); + + /* + * GetRawButtonPressed will only return true once per press. + * If a button is pressed, set the solenoid to the respective channel. + */ + if (m_stick.getRawButtonPressed(kSolenoidForwardButton)) { + m_Solenoid.set(true); + } else if (m_stick.getRawButtonPressed(kSolenoidReverseButton)) { + m_Solenoid.set(false); + } + + // On button press, toggle the compressor. + if (m_stick.getRawButtonPressed(kCompressorButton)) { + // Check whether the compressor is currently enabled. + boolean isCompressorEnabled = m_compressor.isEnabled(); + if (isCompressorEnabled) { + // Disable closed-loop mode on the compressor. + m_compressor.disable(); + } else { + // Enable closed-loop mode based on the analog pressure sensor connected to the PH. + // The compressor will run while the pressure reported by the sensor is in the + // specified range ([70 PSI, 120 PSI] in this example). + // Analog mode exists only on the PH! On the PCM, this enables digital control. + m_compressor.enableAnalog(70, 120); + } + } + } +} diff --git a/2025-Reefscape/vendordeps/REVLib-2025.0.0.json b/2025-Reefscape/Examples/PrototypeBoard/vendordeps/REVLib.json similarity index 90% rename from 2025-Reefscape/vendordeps/REVLib-2025.0.0.json rename to 2025-Reefscape/Examples/PrototypeBoard/vendordeps/REVLib.json index b4f198f..ac62be8 100644 --- a/2025-Reefscape/vendordeps/REVLib-2025.0.0.json +++ b/2025-Reefscape/Examples/PrototypeBoard/vendordeps/REVLib.json @@ -1,7 +1,7 @@ { - "fileName": "REVLib-2025.0.0.json", + "fileName": "REVLib.json", "name": "REVLib", - "version": "2025.0.2", + "version": "2025.0.3", "frcYear": "2025", "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", "mavenUrls": [ @@ -12,14 +12,14 @@ { "groupId": "com.revrobotics.frc", "artifactId": "REVLib-java", - "version": "2025.0.2" + "version": "2025.0.3" } ], "jniDependencies": [ { "groupId": "com.revrobotics.frc", "artifactId": "REVLib-driver", - "version": "2025.0.2", + "version": "2025.0.3", "skipInvalidPlatforms": true, "isJar": false, "validPlatforms": [ @@ -36,7 +36,7 @@ { "groupId": "com.revrobotics.frc", "artifactId": "REVLib-cpp", - "version": "2025.0.2", + "version": "2025.0.3", "libName": "REVLib", "headerClassifier": "headers", "sharedLibrary": false, @@ -53,7 +53,7 @@ { "groupId": "com.revrobotics.frc", "artifactId": "REVLib-driver", - "version": "2025.0.2", + "version": "2025.0.3", "libName": "REVLibDriver", "headerClassifier": "headers", "sharedLibrary": false, diff --git a/2025-Reefscape/Examples/PrototypeBoard/vendordeps/WPILibNewCommands.json b/2025-Reefscape/Examples/PrototypeBoard/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..3718e0a --- /dev/null +++ b/2025-Reefscape/Examples/PrototypeBoard/vendordeps/WPILibNewCommands.json @@ -0,0 +1,38 @@ +{ + "fileName": "WPILibNewCommands.json", + "name": "WPILib-New-Commands", + "version": "1.0.0", + "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", + "frcYear": "2025", + "mavenUrls": [], + "jsonUrl": "", + "javaDependencies": [ + { + "groupId": "edu.wpi.first.wpilibNewCommands", + "artifactId": "wpilibNewCommands-java", + "version": "wpilib" + } + ], + "jniDependencies": [], + "cppDependencies": [ + { + "groupId": "edu.wpi.first.wpilibNewCommands", + "artifactId": "wpilibNewCommands-cpp", + "version": "wpilib", + "libName": "wpilibNewCommands", + "headerClassifier": "headers", + "sourcesClassifier": "sources", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "linuxathena", + "linuxarm32", + "linuxarm64", + "windowsx86-64", + "windowsx86", + "linuxx86-64", + "osxuniversal" + ] + } + ] +} diff --git a/2025-Reefscape/Examples/Shooter/.gitignore b/2025-Reefscape/Examples/Shooter/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/.gitignore @@ -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 diff --git a/2025-Reefscape/Examples/Shooter/.vscode/launch.json b/2025-Reefscape/Examples/Shooter/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/2025-Reefscape/Examples/Shooter/.vscode/settings.json b/2025-Reefscape/Examples/Shooter/.vscode/settings.json new file mode 100644 index 0000000..612cdd0 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/.vscode/settings.json @@ -0,0 +1,60 @@ +{ + "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.*", + ] +} diff --git a/2025-Reefscape/Examples/Shooter/.wpilib/wpilib_preferences.json b/2025-Reefscape/Examples/Shooter/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..a792267 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2025", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/2025-Reefscape/Examples/Shooter/WPILib-License.md b/2025-Reefscape/Examples/Shooter/WPILib-License.md new file mode 100644 index 0000000..645e542 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2024 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/2025-Reefscape/Examples/Shooter/build.gradle b/2025-Reefscape/Examples/Shooter/build.gradle new file mode 100644 index 0000000..ff9e9af --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/build.gradle @@ -0,0 +1,104 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2025.3.2" +} + +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 JNI. +wpi.java.debugJni = false + +// Set this to true to enable desktop support. +def includeDesktopSupport = true + +// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. +// Also defines JUnit 5. +dependencies { + 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' +} diff --git a/2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.jar b/2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 zcma&N1CXTcmMvW9vTb(Rwr$&4wr$(C?dmSu>@vG-+vuvg^_??!{yS%8zW-#zn-LkA z5&1^$^{lnmUON?}LBF8_K|(?T0Ra(xUH{($5eN!MR#ZihR#HxkUPe+_R8Cn`RRs(P z_^*#_XlXmGv7!4;*Y%p4nw?{bNp@UZHv1?Um8r6)Fei3p@ClJn0ECfg1hkeuUU@Or zDaPa;U3fE=3L}DooL;8f;P0ipPt0Z~9P0)lbStMS)ag54=uL9ia-Lm3nh|@(Y?B`; zx_#arJIpXH!U{fbCbI^17}6Ri*H<>OLR%c|^mh8+)*h~K8Z!9)DPf zR2h?lbDZQ`p9P;&DQ4F0sur@TMa!Y}S8irn(%d-gi0*WxxCSk*A?3lGh=gcYN?FGl z7D=Js!i~0=u3rox^eO3i@$0=n{K1lPNU zwmfjRVmLOCRfe=seV&P*1Iq=^i`502keY8Uy-WNPwVNNtJFx?IwAyRPZo2Wo1+S(xF37LJZ~%i)kpFQ3Fw=mXfd@>%+)RpYQLnr}B~~zoof(JVm^^&f zxKV^+3D3$A1G;qh4gPVjhrC8e(VYUHv#dy^)(RoUFM?o%W-EHxufuWf(l*@-l+7vt z=l`qmR56K~F|v<^Pd*p~1_y^P0P^aPC##d8+HqX4IR1gu+7w#~TBFphJxF)T$2WEa zxa?H&6=Qe7d(#tha?_1uQys2KtHQ{)Qco)qwGjrdNL7thd^G5i8Os)CHqc>iOidS} z%nFEDdm=GXBw=yXe1W-ShHHFb?Cc70+$W~z_+}nAoHFYI1MV1wZegw*0y^tC*s%3h zhD3tN8b=Gv&rj}!SUM6|ajSPp*58KR7MPpI{oAJCtY~JECm)*m_x>AZEu>DFgUcby z1Qaw8lU4jZpQ_$;*7RME+gq1KySGG#Wql>aL~k9tLrSO()LWn*q&YxHEuzmwd1?aAtI zBJ>P=&$=l1efe1CDU;`Fd+_;&wI07?V0aAIgc(!{a z0Jg6Y=inXc3^n!U0Atk`iCFIQooHqcWhO(qrieUOW8X(x?(RD}iYDLMjSwffH2~tB z)oDgNBLB^AJBM1M^c5HdRx6fBfka`(LD-qrlh5jqH~);#nw|iyp)()xVYak3;Ybik z0j`(+69aK*B>)e_p%=wu8XC&9e{AO4c~O1U`5X9}?0mrd*m$_EUek{R?DNSh(=br# z#Q61gBzEpmy`$pA*6!87 zSDD+=@fTY7<4A?GLqpA?Pb2z$pbCc4B4zL{BeZ?F-8`s$?>*lXXtn*NC61>|*w7J* z$?!iB{6R-0=KFmyp1nnEmLsA-H0a6l+1uaH^g%c(p{iT&YFrbQ$&PRb8Up#X3@Zsk zD^^&LK~111%cqlP%!_gFNa^dTYT?rhkGl}5=fL{a`UViaXWI$k-UcHJwmaH1s=S$4 z%4)PdWJX;hh5UoK?6aWoyLxX&NhNRqKam7tcOkLh{%j3K^4Mgx1@i|Pi&}<^5>hs5 zm8?uOS>%)NzT(%PjVPGa?X%`N2TQCKbeH2l;cTnHiHppPSJ<7y-yEIiC!P*ikl&!B z%+?>VttCOQM@ShFguHVjxX^?mHX^hSaO_;pnyh^v9EumqSZTi+#f&_Vaija0Q-e*| z7ulQj6Fs*bbmsWp{`auM04gGwsYYdNNZcg|ph0OgD>7O}Asn7^Z=eI>`$2*v78;sj-}oMoEj&@)9+ycEOo92xSyY344^ z11Hb8^kdOvbf^GNAK++bYioknrpdN>+u8R?JxG=!2Kd9r=YWCOJYXYuM0cOq^FhEd zBg2puKy__7VT3-r*dG4c62Wgxi52EMCQ`bKgf*#*ou(D4-ZN$+mg&7$u!! z-^+Z%;-3IDwqZ|K=ah85OLwkO zKxNBh+4QHh)u9D?MFtpbl)us}9+V!D%w9jfAMYEb>%$A;u)rrI zuBudh;5PN}_6J_}l55P3l_)&RMlH{m!)ai-i$g)&*M`eN$XQMw{v^r@-125^RRCF0 z^2>|DxhQw(mtNEI2Kj(;KblC7x=JlK$@78`O~>V!`|1Lm-^JR$-5pUANAnb(5}B}JGjBsliK4& zk6y(;$e&h)lh2)L=bvZKbvh@>vLlreBdH8No2>$#%_Wp1U0N7Ank!6$dFSi#xzh|( zRi{Uw%-4W!{IXZ)fWx@XX6;&(m_F%c6~X8hx=BN1&q}*( zoaNjWabE{oUPb!Bt$eyd#$5j9rItB-h*5JiNi(v^e|XKAj*8(k<5-2$&ZBR5fF|JA z9&m4fbzNQnAU}r8ab>fFV%J0z5awe#UZ|bz?Ur)U9bCIKWEzi2%A+5CLqh?}K4JHi z4vtM;+uPsVz{Lfr;78W78gC;z*yTch~4YkLr&m-7%-xc ztw6Mh2d>_iO*$Rd8(-Cr1_V8EO1f*^@wRoSozS) zy1UoC@pruAaC8Z_7~_w4Q6n*&B0AjOmMWa;sIav&gu z|J5&|{=a@vR!~k-OjKEgPFCzcJ>#A1uL&7xTDn;{XBdeM}V=l3B8fE1--DHjSaxoSjNKEM9|U9#m2<3>n{Iuo`r3UZp;>GkT2YBNAh|b z^jTq-hJp(ebZh#Lk8hVBP%qXwv-@vbvoREX$TqRGTgEi$%_F9tZES@z8Bx}$#5eeG zk^UsLBH{bc2VBW)*EdS({yw=?qmevwi?BL6*=12k9zM5gJv1>y#ML4!)iiPzVaH9% zgSImetD@dam~e>{LvVh!phhzpW+iFvWpGT#CVE5TQ40n%F|p(sP5mXxna+Ev7PDwA zamaV4m*^~*xV+&p;W749xhb_X=$|LD;FHuB&JL5?*Y2-oIT(wYY2;73<^#46S~Gx| z^cez%V7x$81}UWqS13Gz80379Rj;6~WdiXWOSsdmzY39L;Hg3MH43o*y8ibNBBH`(av4|u;YPq%{R;IuYow<+GEsf@R?=@tT@!}?#>zIIn0CoyV!hq3mw zHj>OOjfJM3F{RG#6ujzo?y32m^tgSXf@v=J$ELdJ+=5j|=F-~hP$G&}tDZsZE?5rX ztGj`!S>)CFmdkccxM9eGIcGnS2AfK#gXwj%esuIBNJQP1WV~b~+D7PJTmWGTSDrR` zEAu4B8l>NPuhsk5a`rReSya2nfV1EK01+G!x8aBdTs3Io$u5!6n6KX%uv@DxAp3F@{4UYg4SWJtQ-W~0MDb|j-$lwVn znAm*Pl!?Ps&3wO=R115RWKb*JKoexo*)uhhHBncEDMSVa_PyA>k{Zm2(wMQ(5NM3# z)jkza|GoWEQo4^s*wE(gHz?Xsg4`}HUAcs42cM1-qq_=+=!Gk^y710j=66(cSWqUe zklbm8+zB_syQv5A2rj!Vbw8;|$@C!vfNmNV!yJIWDQ>{+2x zKjuFX`~~HKG~^6h5FntRpnnHt=D&rq0>IJ9#F0eM)Y-)GpRjiN7gkA8wvnG#K=q{q z9dBn8_~wm4J<3J_vl|9H{7q6u2A!cW{bp#r*-f{gOV^e=8S{nc1DxMHFwuM$;aVI^ zz6A*}m8N-&x8;aunp1w7_vtB*pa+OYBw=TMc6QK=mbA-|Cf* zvyh8D4LRJImooUaSb7t*fVfih<97Gf@VE0|z>NcBwBQze);Rh!k3K_sfunToZY;f2 z^HmC4KjHRVg+eKYj;PRN^|E0>Gj_zagfRbrki68I^#~6-HaHg3BUW%+clM1xQEdPYt_g<2K+z!$>*$9nQ>; zf9Bei{?zY^-e{q_*|W#2rJG`2fy@{%6u0i_VEWTq$*(ZN37|8lFFFt)nCG({r!q#9 z5VK_kkSJ3?zOH)OezMT{!YkCuSSn!K#-Rhl$uUM(bq*jY? zi1xbMVthJ`E>d>(f3)~fozjg^@eheMF6<)I`oeJYx4*+M&%c9VArn(OM-wp%M<-`x z7sLP1&3^%Nld9Dhm@$3f2}87!quhI@nwd@3~fZl_3LYW-B?Ia>ui`ELg z&Qfe!7m6ze=mZ`Ia9$z|ARSw|IdMpooY4YiPN8K z4B(ts3p%2i(Td=tgEHX z0UQ_>URBtG+-?0E;E7Ld^dyZ;jjw0}XZ(}-QzC6+NN=40oDb2^v!L1g9xRvE#@IBR zO!b-2N7wVfLV;mhEaXQ9XAU+>=XVA6f&T4Z-@AX!leJ8obP^P^wP0aICND?~w&NykJ#54x3_@r7IDMdRNy4Hh;h*!u(Ol(#0bJdwEo$5437-UBjQ+j=Ic>Q2z` zJNDf0yO6@mr6y1#n3)s(W|$iE_i8r@Gd@!DWDqZ7J&~gAm1#~maIGJ1sls^gxL9LLG_NhU!pTGty!TbhzQnu)I*S^54U6Yu%ZeCg`R>Q zhBv$n5j0v%O_j{QYWG!R9W?5_b&67KB$t}&e2LdMvd(PxN6Ir!H4>PNlerpBL>Zvyy!yw z-SOo8caEpDt(}|gKPBd$qND5#a5nju^O>V&;f890?yEOfkSG^HQVmEbM3Ugzu+UtH zC(INPDdraBN?P%kE;*Ae%Wto&sgw(crfZ#Qy(<4nk;S|hD3j{IQRI6Yq|f^basLY; z-HB&Je%Gg}Jt@={_C{L$!RM;$$|iD6vu#3w?v?*;&()uB|I-XqEKqZPS!reW9JkLewLb!70T7n`i!gNtb1%vN- zySZj{8-1>6E%H&=V}LM#xmt`J3XQoaD|@XygXjdZ1+P77-=;=eYpoEQ01B@L*a(uW zrZeZz?HJsw_4g0vhUgkg@VF8<-X$B8pOqCuWAl28uB|@r`19DTUQQsb^pfqB6QtiT z*`_UZ`fT}vtUY#%sq2{rchyfu*pCg;uec2$-$N_xgjZcoumE5vSI{+s@iLWoz^Mf; zuI8kDP{!XY6OP~q5}%1&L}CtfH^N<3o4L@J@zg1-mt{9L`s^z$Vgb|mr{@WiwAqKg zp#t-lhrU>F8o0s1q_9y`gQNf~Vb!F%70f}$>i7o4ho$`uciNf=xgJ>&!gSt0g;M>*x4-`U)ysFW&Vs^Vk6m%?iuWU+o&m(2Jm26Y(3%TL; zA7T)BP{WS!&xmxNw%J=$MPfn(9*^*TV;$JwRy8Zl*yUZi8jWYF>==j~&S|Xinsb%c z2?B+kpet*muEW7@AzjBA^wAJBY8i|#C{WtO_or&Nj2{=6JTTX05}|H>N2B|Wf!*3_ z7hW*j6p3TvpghEc6-wufFiY!%-GvOx*bZrhZu+7?iSrZL5q9}igiF^*R3%DE4aCHZ zqu>xS8LkW+Auv%z-<1Xs92u23R$nk@Pk}MU5!gT|c7vGlEA%G^2th&Q*zfg%-D^=f z&J_}jskj|Q;73NP4<4k*Y%pXPU2Thoqr+5uH1yEYM|VtBPW6lXaetokD0u z9qVek6Q&wk)tFbQ8(^HGf3Wp16gKmr>G;#G(HRBx?F`9AIRboK+;OfHaLJ(P>IP0w zyTbTkx_THEOs%Q&aPrxbZrJlio+hCC_HK<4%f3ZoSAyG7Dn`=X=&h@m*|UYO-4Hq0 z-Bq&+Ie!S##4A6OGoC~>ZW`Y5J)*ouaFl_e9GA*VSL!O_@xGiBw!AF}1{tB)z(w%c zS1Hmrb9OC8>0a_$BzeiN?rkPLc9%&;1CZW*4}CDDNr2gcl_3z+WC15&H1Zc2{o~i) z)LLW=WQ{?ricmC`G1GfJ0Yp4Dy~Ba;j6ZV4r{8xRs`13{dD!xXmr^Aga|C=iSmor% z8hi|pTXH)5Yf&v~exp3o+sY4B^^b*eYkkCYl*T{*=-0HniSA_1F53eCb{x~1k3*`W zr~};p1A`k{1DV9=UPnLDgz{aJH=-LQo<5%+Em!DNN252xwIf*wF_zS^!(XSm(9eoj z=*dXG&n0>)_)N5oc6v!>-bd(2ragD8O=M|wGW z!xJQS<)u70m&6OmrF0WSsr@I%T*c#Qo#Ha4d3COcX+9}hM5!7JIGF>7<~C(Ear^Sn zm^ZFkV6~Ula6+8S?oOROOA6$C&q&dp`>oR-2Ym3(HT@O7Sd5c~+kjrmM)YmgPH*tL zX+znN>`tv;5eOfX?h{AuX^LK~V#gPCu=)Tigtq9&?7Xh$qN|%A$?V*v=&-2F$zTUv z`C#WyIrChS5|Kgm_GeudCFf;)!WH7FI60j^0o#65o6`w*S7R@)88n$1nrgU(oU0M9 zx+EuMkC>(4j1;m6NoGqEkpJYJ?vc|B zOlwT3t&UgL!pX_P*6g36`ZXQ; z9~Cv}ANFnJGp(;ZhS(@FT;3e)0)Kp;h^x;$*xZn*k0U6-&FwI=uOGaODdrsp-!K$Ac32^c{+FhI-HkYd5v=`PGsg%6I`4d9Jy)uW0y%) zm&j^9WBAp*P8#kGJUhB!L?a%h$hJgQrx!6KCB_TRo%9{t0J7KW8!o1B!NC)VGLM5! zpZy5Jc{`r{1e(jd%jsG7k%I+m#CGS*BPA65ZVW~fLYw0dA-H_}O zrkGFL&P1PG9p2(%QiEWm6x;U-U&I#;Em$nx-_I^wtgw3xUPVVu zqSuKnx&dIT-XT+T10p;yjo1Y)z(x1fb8Dzfn8e yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.properties b/2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/2025-Reefscape/Examples/Shooter/gradlew b/2025-Reefscape/Examples/Shooter/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/gradlew @@ -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" "$@" diff --git a/2025-Reefscape/Examples/Shooter/gradlew.bat b/2025-Reefscape/Examples/Shooter/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/gradlew.bat @@ -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 diff --git a/2025-Reefscape/Examples/Shooter/settings.gradle b/2025-Reefscape/Examples/Shooter/settings.gradle new file mode 100644 index 0000000..969c7b0 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/settings.gradle @@ -0,0 +1,30 @@ +import org.gradle.internal.os.OperatingSystem + +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + String frcYear = '2025' + File frcHome + if (OperatingSystem.current().isWindows()) { + String publicFolder = System.getenv('PUBLIC') + if (publicFolder == null) { + publicFolder = "C:\\Users\\Public" + } + def homeRoot = new File(publicFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } else { + def userFolder = System.getProperty("user.home") + def homeRoot = new File(userFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } + def frcHomeMaven = new File(frcHome, 'maven') + maven { + name 'frcHome' + url frcHomeMaven + } + } +} + +Properties props = System.getProperties(); +props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true"); diff --git a/2025-Reefscape/Examples/Shooter/src/main/deploy/example.txt b/2025-Reefscape/Examples/Shooter/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Main.java b/2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Robot.java b/2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..c2559b5 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/src/main/java/frc/robot/Robot.java @@ -0,0 +1,58 @@ +// 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.Encoder; +import edu.wpi.first.wpilibj.XboxController; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import com.revrobotics.spark.SparkMax; +import com.revrobotics.spark.SparkLowLevel.MotorType; +/** + * This sample program shows how to control a motor using a joystick. In the operator control part + * of the program, the joystick is read and the value is written to the motor. + * + *

Joystick analog values range from -1 to 1 and motor controller inputs also range from -1 to 1 + * making it easy to work together. + * + *

In addition, the encoder value of an encoder connected to ports 0 and 1 is consistently sent + * to the Dashboard. + */ +public class Robot extends TimedRobot { + private static final int kMotorPort = 50; // CAN ID + private static final int kJoystickPort = 0; + //private static final int kEncoderPortA = 0; + //private static final int kEncoderPortB = 1; + + private final SparkMax m_motor; + private final XboxController m_joystick; + //private final Encoder m_encoder; + + /** Called once at the beginning of the robot program. */ + public Robot() { + m_motor = new SparkMax(kMotorPort, MotorType.kBrushless); + m_joystick = new XboxController(kJoystickPort); + // m_encoder = new Encoder(kEncoderPortA, kEncoderPortB); + // Use SetDistancePerPulse to set the multiplier for GetDistance + // This is set up assuming a 6 inch wheel with a 360 CPR encoder. + // m_encoder.setDistancePerPulse((Math.PI * 6) / 360.0); + } + + /* + * The RobotPeriodic function is called every control packet no matter the + * robot mode. + */ + @Override + public void robotPeriodic() { + // SmartDashboard.putNumber("Encoder", m_encoder.getDistance()); + } + + /** The teleop periodic function is called every control packet in teleop. */ + @Override + public void teleopPeriodic() { + double speed = m_joystick.getLeftY(); + m_motor.set(speed); + } +} diff --git a/2025-Reefscape/Examples/Shooter/vendordeps/REVLib.json b/2025-Reefscape/Examples/Shooter/vendordeps/REVLib.json new file mode 100644 index 0000000..ac62be8 --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/vendordeps/REVLib.json @@ -0,0 +1,71 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2025.0.3", + "frcYear": "2025", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2025.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2025.0.3" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2025.0.3", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2025.0.3", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2025.0.3", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/2025-Reefscape/Examples/Shooter/vendordeps/WPILibNewCommands.json b/2025-Reefscape/Examples/Shooter/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..3718e0a --- /dev/null +++ b/2025-Reefscape/Examples/Shooter/vendordeps/WPILibNewCommands.json @@ -0,0 +1,38 @@ +{ + "fileName": "WPILibNewCommands.json", + "name": "WPILib-New-Commands", + "version": "1.0.0", + "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", + "frcYear": "2025", + "mavenUrls": [], + "jsonUrl": "", + "javaDependencies": [ + { + "groupId": "edu.wpi.first.wpilibNewCommands", + "artifactId": "wpilibNewCommands-java", + "version": "wpilib" + } + ], + "jniDependencies": [], + "cppDependencies": [ + { + "groupId": "edu.wpi.first.wpilibNewCommands", + "artifactId": "wpilibNewCommands-cpp", + "version": "wpilib", + "libName": "wpilibNewCommands", + "headerClassifier": "headers", + "sourcesClassifier": "sources", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "linuxathena", + "linuxarm32", + "linuxarm64", + "windowsx86-64", + "windowsx86", + "linuxx86-64", + "osxuniversal" + ] + } + ] +} diff --git a/2025-Reefscape/build.gradle b/2025-Reefscape/build.gradle index 1945af5..44f1061 100644 --- a/2025-Reefscape/build.gradle +++ b/2025-Reefscape/build.gradle @@ -1,6 +1,6 @@ plugins { id "java" - id "edu.wpi.first.GradleRIO" version "2025.2.1" + id "edu.wpi.first.GradleRIO" version "2025.3.2" } java { diff --git a/2025-Reefscape/src/main/java/frc/robot/Constants.java b/2025-Reefscape/src/main/java/frc/robot/Constants.java index f9a741c..92e0860 100644 --- a/2025-Reefscape/src/main/java/frc/robot/Constants.java +++ b/2025-Reefscape/src/main/java/frc/robot/Constants.java @@ -69,10 +69,14 @@ public static class OperatorConstants { public static final int kIntakeElevatorPosition = 2; // Button B public static final int kIncreaseElevatorLevel = 4; // Button Y + // In the future when disabling buttons, please comment out the command bind + // under the configureBindings function in the RobotContrainer. - Owen public static final int kCoralIntake = 6; // Right Bumper public static final int kCoralOuttake = 5; // Left Bumper public static final int kCoralStop = 9; // Left Thumbstick Button + public static final int kShooterShoot = 5; // Left Bumper + public static final int kAlageIntake = 8; // START public static final int kAlageOutput = 7; // BACK @@ -147,6 +151,25 @@ public static class CoralConstants { public static final int kTicksPerUpdate = 10; } + public static class ShooterConstants { + public static final int kIntakeMotorCANID = 40; + public static final int kOutputMotorCANID = 41; + + public static final double kMotorIntakeSpeed = 1.0; + public static final double kMotorOutputSpeed = -1.0; + + // number of ticks between sensor change and motor stop + public static final int kEndIntakeMaxCount = 6; // ~0.125 second(s) + public static final int kEndOutputMaxCount = 50; // 1 second(s) + + // Line Break? sensor to detect coral in the middle + public static final int kSensorChannel = 0; + public static final boolean kSensorFalseIsEmpty = false; + + // SmartDashboard update frequency for coral subsystem state in 20ms counts. + public static final int kTicksPerUpdate = 10; + } + public static class AlgaeConstants { public static final int kMotorCANID = 50; public static final int kMotorCurrentLimit = 7; @@ -159,7 +182,7 @@ public static class AlgaeConstants { public static final boolean kSensorFalseIsEmpty = true; // number of ticks between sensor change and motor stop - public static final int kEndIntakeMaxCount = 0; // 0 second(s) + public static final int kEndIntakeMaxCount = 15; // 0 second(s) public static final int kEndOutputMaxCount = 100; // 2 second(s) public static final double kIntakeSpeed = 1; @@ -188,8 +211,8 @@ public static class ElevatorConstants { public static final double kElevatorIntakePosition = 0.0; public static final double kElevatorL2Position = 0.46; // 0.45-0.47?? - public static final double kElevatorL3Position = 0.82; - public static final double kElevatorL4Position = 1.51; + public static final double kElevatorL3Position = 0.93; + public static final double kElevatorL4Position = 1.53; // The distance travelled for a single rotation of the Kraken output shaft. // 64 to 1 gear box, pulley is 47.75mm diameter (0.15m circumference), @@ -199,9 +222,4 @@ public static class ElevatorConstants { // SmartDashboard update frequency for elevator subsystem state in 20ms counts. public static final int kTicksPerUpdate = 5; } - - public static class DrivetrainConstants { - public static final int kLeftMotorCANID = 10; - public static final int kRightMotorCANID = 20; - } } diff --git a/2025-Reefscape/src/main/java/frc/robot/RobotContainer.java b/2025-Reefscape/src/main/java/frc/robot/RobotContainer.java index ff43b79..3cea0bd 100644 --- a/2025-Reefscape/src/main/java/frc/robot/RobotContainer.java +++ b/2025-Reefscape/src/main/java/frc/robot/RobotContainer.java @@ -25,6 +25,7 @@ import frc.robot.subsystems.DriveSubsystem; import frc.robot.subsystems.ElevatorSubsystem; import frc.robot.subsystems.IntakeSubsystem; +import frc.robot.subsystems.ShooterSubsystem; import java.util.Optional; @@ -54,6 +55,7 @@ public class RobotContainer { private final DriveSubsystem m_driveSubsystem = new DriveSubsystem(); private final Optional m_intakeSubsystem; private final Optional m_coralSubsystem; + private final Optional m_shooterSubsystem; private final Optional m_elevatorSubsystem; private final Optional m_algaeSubsystem; @@ -88,6 +90,10 @@ public class RobotContainer { private final JoystickButton m_coralStopMotorsButton = new JoystickButton(m_operatorController, OperatorConstants.kCoralStop); + private final JoystickButton m_shooterButton = + new JoystickButton(m_operatorController, OperatorConstants.kShooterShoot); + + private ElevatorManualSpeed m_manualSpeedCommand; // Keep track of time for SmartDashboard updates. @@ -99,6 +105,7 @@ public RobotContainer() { m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); m_coralSubsystem = getSubsystem(CoralSubsystem.class); + m_shooterSubsystem = getSubsystem(ShooterSubsystem.class); m_elevatorSubsystem = getSubsystem(ElevatorSubsystem.class); m_algaeSubsystem = getSubsystem(AlgaeSubsystem.class); @@ -198,6 +205,7 @@ private void configureBindings() { SmartDashboard.putBoolean("Intake Subsystem", m_intakeSubsystem.isPresent()); SmartDashboard.putBoolean("Coral Subsystem", m_coralSubsystem.isPresent()); + SmartDashboard.putBoolean("Shooter Subsystem", m_shooterSubsystem.isPresent()); SmartDashboard.putBoolean("Elevator Subsystem", m_elevatorSubsystem.isPresent()); SmartDashboard.putBoolean("Algae Subsystem", m_algaeSubsystem.isPresent()); @@ -209,6 +217,12 @@ private void configureBindings() { // TODO: Bind intake commands and controls. } + if (m_shooterSubsystem.isPresent()) + { + ShooterSubsystem shooterSubsystem = m_shooterSubsystem.get(); + // Poopoo + } + if (m_coralSubsystem.isPresent()) { CoralSubsystem coralSubsystem = m_coralSubsystem.get(); diff --git a/2025-Reefscape/src/main/java/frc/robot/commands/ShooterSpeedCommand.java b/2025-Reefscape/src/main/java/frc/robot/commands/ShooterSpeedCommand.java new file mode 100644 index 0000000..7547399 --- /dev/null +++ b/2025-Reefscape/src/main/java/frc/robot/commands/ShooterSpeedCommand.java @@ -0,0 +1,55 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.ShooterSubsystem; + +// TODO: Class header comment! + +/** An example command that uses an example subsystem. */ +public class ShooterSpeedCommand extends Command { + private final ShooterSubsystem m_subsystem; + private double m_intakeSpeed = 0.0; + private double m_outputSpeed = 0.0; + + /** + * Creates a new ShooterSpeedCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ShooterSpeedCommand(ShooterSubsystem subsystem, double inputSpeed, double outputSpped) + { + m_subsystem = subsystem; + + m_intakeSpeed = inputSpeed; + m_outputSpeed = outputSpped; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.setIntakeSpeed(m_intakeSpeed); + m_subsystem.setOutputSpeed(m_outputSpeed); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + m_subsystem.setIntakeSpeed(0); + m_subsystem.setOutputSpeed(0); + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2025-Reefscape/src/main/java/frc/robot/subsystems/ShooterSubsystem.java b/2025-Reefscape/src/main/java/frc/robot/subsystems/ShooterSubsystem.java new file mode 100644 index 0000000..e28016f --- /dev/null +++ b/2025-Reefscape/src/main/java/frc/robot/subsystems/ShooterSubsystem.java @@ -0,0 +1,57 @@ +// 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.subsystems; + +import com.revrobotics.spark.SparkLowLevel.MotorType; +import com.revrobotics.spark.SparkMax; + +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import frc.robot.Constants.ShooterConstants; + +public class ShooterSubsystem extends SubsystemBase { + private double m_intakeSpeed = 0; + private double m_outputSpeed = 0; + + private final SparkMax m_intakeMotor = new SparkMax(ShooterConstants.kIntakeMotorCANID, + MotorType.kBrushless); + private final SparkMax m_outputMotor = new SparkMax(ShooterConstants.kOutputMotorCANID, + MotorType.kBrushless); + + /** Creates a new ShooterSubsystem. */ + public ShooterSubsystem() { + // We need to know if the motor controllers we need are + // actually present on the CAN bus and, unfortunately, their + // constructors don't seem to throw exceptions in this case. Let's + // query the firmware fault status and use this for now. + if (m_intakeMotor.getFaults().firmware || m_outputMotor.getFaults().firmware) + { + throw new RuntimeException("Shooter subsystem motors not present"); + } + } + + public void setIntakeSpeed(double speed) + { + m_intakeMotor.set(speed); + m_intakeSpeed = speed; + } + + // Returns the last COMMANDED speed + public double getIntakeSpeed() + { + return m_intakeSpeed; + } + + public void setOutputSpeed(double speed) + { + m_outputMotor.set(speed); + m_outputSpeed = speed; + } + + // Returns the last COMMANDED speed. + public double getOutputSpeed() + { + return m_outputSpeed; + } +} diff --git a/2025-Reefscape/vendordeps/Phoenix6-25.3.1.json b/2025-Reefscape/vendordeps/Phoenix6-frc2025-latest.json similarity index 72% rename from 2025-Reefscape/vendordeps/Phoenix6-25.3.1.json rename to 2025-Reefscape/vendordeps/Phoenix6-frc2025-latest.json index 2b0bfd1..6f40c84 100644 --- a/2025-Reefscape/vendordeps/Phoenix6-25.3.1.json +++ b/2025-Reefscape/vendordeps/Phoenix6-frc2025-latest.json @@ -1,13 +1,7 @@ { -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "fileName": "Phoenix6-25.3.1.json", + "fileName": "Phoenix6-frc2025-latest.json", "name": "CTRE-Phoenix (v6)", - "version": "25.3.1", -======== - "fileName": "Phoenix6-25.1.0.json", - "name": "CTRE-Phoenix (v6)", - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "frcYear": "2025", "uuid": "e995de00-2c64-4df5-8831-c1441420ff19", "mavenUrls": [ @@ -25,22 +19,14 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "wpiapi-java", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1" -======== - "version": "25.1.0" ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0" } ], "jniDependencies": [ { "groupId": "com.ctre.phoenix6", "artifactId": "api-cpp", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -54,11 +40,7 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "tools", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -72,11 +54,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "api-cpp-sim", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -90,11 +68,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "tools-sim", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -108,11 +82,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simTalonSRX", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -126,11 +96,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simVictorSPX", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -144,11 +110,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simPigeonIMU", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -162,11 +124,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simCANCoder", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -180,18 +138,13 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFX", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ "windowsx86-64", "linuxx86-64", "linuxarm64", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json "osxuniversal" ], "simMode": "swsim" @@ -199,15 +152,13 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFXS", - "version": "25.3.1", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ "windowsx86-64", "linuxx86-64", "linuxarm64", -======== ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json "osxuniversal" ], "simMode": "swsim" @@ -215,11 +166,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANcoder", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -233,11 +180,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProPigeon2", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -251,8 +194,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANrange", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -266,10 +208,21 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANdi", - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "25.4.0", "isJar": false, "skipInvalidPlatforms": true, "validPlatforms": [ @@ -285,11 +238,7 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "wpiapi-cpp", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_Phoenix6_WPI", "headerClassifier": "headers", "sharedLibrary": true, @@ -305,11 +254,7 @@ { "groupId": "com.ctre.phoenix6", "artifactId": "tools", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_PhoenixTools", "headerClassifier": "headers", "sharedLibrary": true, @@ -325,11 +270,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "wpiapi-cpp-sim", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_Phoenix6_WPISim", "headerClassifier": "headers", "sharedLibrary": true, @@ -345,11 +286,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "tools-sim", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_PhoenixTools_Sim", "headerClassifier": "headers", "sharedLibrary": true, @@ -365,11 +302,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simTalonSRX", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimTalonSRX", "headerClassifier": "headers", "sharedLibrary": true, @@ -385,11 +318,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simVictorSPX", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimVictorSPX", "headerClassifier": "headers", "sharedLibrary": true, @@ -405,11 +334,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simPigeonIMU", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimPigeonIMU", "headerClassifier": "headers", "sharedLibrary": true, @@ -425,11 +350,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simCANCoder", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimCANCoder", "headerClassifier": "headers", "sharedLibrary": true, @@ -445,11 +366,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFX", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimProTalonFX", "headerClassifier": "headers", "sharedLibrary": true, @@ -458,7 +375,6 @@ "windowsx86-64", "linuxx86-64", "linuxarm64", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json "osxuniversal" ], "simMode": "swsim" @@ -466,7 +382,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProTalonFXS", - "version": "25.3.1", + "version": "25.4.0", "libName": "CTRE_SimProTalonFXS", "headerClassifier": "headers", "sharedLibrary": true, @@ -475,8 +391,6 @@ "windowsx86-64", "linuxx86-64", "linuxarm64", -======== ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json "osxuniversal" ], "simMode": "swsim" @@ -484,11 +398,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANcoder", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimProCANcoder", "headerClassifier": "headers", "sharedLibrary": true, @@ -504,11 +414,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProPigeon2", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimProPigeon2", "headerClassifier": "headers", "sharedLibrary": true, @@ -524,11 +430,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANrange", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json - "version": "25.3.1", -======== - "version": "25.1.0", ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "version": "25.4.0", "libName": "CTRE_SimProCANrange", "headerClassifier": "headers", "sharedLibrary": true, @@ -537,7 +439,6 @@ "windowsx86-64", "linuxx86-64", "linuxarm64", -<<<<<<<< HEAD:vendordeps/Phoenix6-25.3.1.json "osxuniversal" ], "simMode": "swsim" @@ -545,7 +446,7 @@ { "groupId": "com.ctre.phoenix6.sim", "artifactId": "simProCANdi", - "version": "25.3.1", + "version": "25.4.0", "libName": "CTRE_SimProCANdi", "headerClassifier": "headers", "sharedLibrary": true, @@ -554,8 +455,22 @@ "windowsx86-64", "linuxx86-64", "linuxarm64", -======== ->>>>>>>> main:vendordeps/Phoenix6-25.1.0.json + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "25.4.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", "osxuniversal" ], "simMode": "swsim" diff --git a/2025-Reefscape/vendordeps/REVLib.json b/2025-Reefscape/vendordeps/REVLib.json new file mode 100644 index 0000000..ac62be8 --- /dev/null +++ b/2025-Reefscape/vendordeps/REVLib.json @@ -0,0 +1,71 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2025.0.3", + "frcYear": "2025", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2025.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2025.0.3" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2025.0.3", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2025.0.3", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2025.0.3", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/2025-Reefscape/vendordeps/libgrapplefrc2025.json b/2025-Reefscape/vendordeps/libgrapplefrc2025.json index f593245..a49af31 100644 --- a/2025-Reefscape/vendordeps/libgrapplefrc2025.json +++ b/2025-Reefscape/vendordeps/libgrapplefrc2025.json @@ -1,7 +1,7 @@ { "fileName": "libgrapplefrc2025.json", "name": "libgrapplefrc", - "version": "2025.1.0", + "version": "2025.1.3", "frcYear": "2025", "uuid": "8ef3423d-9532-4665-8339-206dae1d7168", "mavenUrls": [ @@ -12,14 +12,14 @@ { "groupId": "au.grapplerobotics", "artifactId": "libgrapplefrcjava", - "version": "2025.1.0" + "version": "2025.1.3" } ], "jniDependencies": [ { "groupId": "au.grapplerobotics", "artifactId": "libgrapplefrcdriver", - "version": "2025.1.0", + "version": "2025.1.3", "skipInvalidPlatforms": true, "isJar": false, "validPlatforms": [ @@ -37,7 +37,7 @@ { "groupId": "au.grapplerobotics", "artifactId": "libgrapplefrccpp", - "version": "2025.1.0", + "version": "2025.1.3", "libName": "grapplefrc", "headerClassifier": "headers", "sharedLibrary": true, @@ -55,7 +55,7 @@ { "groupId": "au.grapplerobotics", "artifactId": "libgrapplefrcdriver", - "version": "2025.1.0", + "version": "2025.1.3", "libName": "grapplefrcdriver", "headerClassifier": "headers", "sharedLibrary": true, From cc5500e6f6731aae927f1fbb41dd448982ca775f Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sun, 11 Jan 2026 16:40:03 -0600 Subject: [PATCH 002/161] Populate prototype_projects with a couple of unmodified examples I've added the WPILib Flywheel_BangBangController and CTRE Phoenix6 VelocityClosedLoop examples to our prototype_projects tree just to illustrate how new projects should be added there and since they will likely be useful this season. Both build cleanly with 2026 WPILib. --- .../Flywheel_BangBangController/.gitignore | 187 ++++++++ .../.vscode/launch.json | 21 + .../.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 6 + .../WPILib-License.md | 24 + .../Flywheel_BangBangController/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../Flywheel_BangBangController/gradlew | 252 ++++++++++ .../Flywheel_BangBangController/gradlew.bat | 94 ++++ .../settings.gradle | 30 ++ .../src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 101 ++++ .../vendordeps/Phoenix6-26.1.0.json | 449 ++++++++++++++++++ .../vendordeps/REVLib.json | 133 ++++++ .../vendordeps/WPILibNewCommands.json | 39 ++ .../VelocityClosedLoop/.gitignore | 187 ++++++++ .../VelocityClosedLoop/.vscode/launch.json | 21 + .../VelocityClosedLoop/.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 6 + .../VelocityClosedLoop/WPILib-License.md | 24 + .../VelocityClosedLoop/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + prototype_projects/VelocityClosedLoop/gradlew | 252 ++++++++++ .../VelocityClosedLoop/gradlew.bat | 94 ++++ .../VelocityClosedLoop/settings.gradle | 30 ++ .../src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Mechanisms.java | 58 +++ .../src/main/java/frc/robot/Robot.java | 139 ++++++ .../main/java/frc/robot/sim/PhysicsSim.java | 81 ++++ .../java/frc/robot/sim/TalonFXSimProfile.java | 57 +++ .../vendordeps/Phoenix6-frc2026-latest.json | 449 ++++++++++++++++++ .../vendordeps/WPILibNewCommands.json | 39 ++ 36 files changed, 3179 insertions(+) create mode 100644 prototype_projects/Flywheel_BangBangController/.gitignore create mode 100644 prototype_projects/Flywheel_BangBangController/.vscode/launch.json create mode 100644 prototype_projects/Flywheel_BangBangController/.vscode/settings.json create mode 100644 prototype_projects/Flywheel_BangBangController/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/Flywheel_BangBangController/WPILib-License.md create mode 100644 prototype_projects/Flywheel_BangBangController/build.gradle create mode 100644 prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.properties create mode 100755 prototype_projects/Flywheel_BangBangController/gradlew create mode 100644 prototype_projects/Flywheel_BangBangController/gradlew.bat create mode 100644 prototype_projects/Flywheel_BangBangController/settings.gradle create mode 100644 prototype_projects/Flywheel_BangBangController/src/main/deploy/example.txt create mode 100644 prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/Flywheel_BangBangController/vendordeps/Phoenix6-26.1.0.json create mode 100644 prototype_projects/Flywheel_BangBangController/vendordeps/REVLib.json create mode 100644 prototype_projects/Flywheel_BangBangController/vendordeps/WPILibNewCommands.json create mode 100644 prototype_projects/VelocityClosedLoop/.gitignore create mode 100644 prototype_projects/VelocityClosedLoop/.vscode/launch.json create mode 100644 prototype_projects/VelocityClosedLoop/.vscode/settings.json create mode 100644 prototype_projects/VelocityClosedLoop/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/VelocityClosedLoop/WPILib-License.md create mode 100644 prototype_projects/VelocityClosedLoop/build.gradle create mode 100644 prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.properties create mode 100755 prototype_projects/VelocityClosedLoop/gradlew create mode 100644 prototype_projects/VelocityClosedLoop/gradlew.bat create mode 100644 prototype_projects/VelocityClosedLoop/settings.gradle create mode 100644 prototype_projects/VelocityClosedLoop/src/main/deploy/example.txt create mode 100644 prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Mechanisms.java create mode 100644 prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/PhysicsSim.java create mode 100644 prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/TalonFXSimProfile.java create mode 100644 prototype_projects/VelocityClosedLoop/vendordeps/Phoenix6-frc2026-latest.json create mode 100644 prototype_projects/VelocityClosedLoop/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/Flywheel_BangBangController/.gitignore b/prototype_projects/Flywheel_BangBangController/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/.gitignore @@ -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 diff --git a/prototype_projects/Flywheel_BangBangController/.vscode/launch.json b/prototype_projects/Flywheel_BangBangController/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/Flywheel_BangBangController/.vscode/settings.json b/prototype_projects/Flywheel_BangBangController/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/Flywheel_BangBangController/.wpilib/wpilib_preferences.json b/prototype_projects/Flywheel_BangBangController/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..994eeed --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/prototype_projects/Flywheel_BangBangController/WPILib-License.md b/prototype_projects/Flywheel_BangBangController/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/Flywheel_BangBangController/build.gradle b/prototype_projects/Flywheel_BangBangController/build.gradle new file mode 100644 index 0000000..e9b0020 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/Flywheel_BangBangController/gradlew b/prototype_projects/Flywheel_BangBangController/gradlew new file mode 100755 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/gradlew @@ -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" "$@" diff --git a/prototype_projects/Flywheel_BangBangController/gradlew.bat b/prototype_projects/Flywheel_BangBangController/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/gradlew.bat @@ -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 diff --git a/prototype_projects/Flywheel_BangBangController/settings.gradle b/prototype_projects/Flywheel_BangBangController/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/settings.gradle @@ -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"); diff --git a/prototype_projects/Flywheel_BangBangController/src/main/deploy/example.txt b/prototype_projects/Flywheel_BangBangController/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Main.java b/prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Robot.java b/prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..67a7ab8 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/src/main/java/frc/robot/Robot.java @@ -0,0 +1,101 @@ +// 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.math.controller.BangBangController; +import edu.wpi.first.math.controller.SimpleMotorFeedforward; +import edu.wpi.first.math.numbers.N1; +import edu.wpi.first.math.system.LinearSystem; +import edu.wpi.first.math.system.plant.DCMotor; +import edu.wpi.first.math.system.plant.LinearSystemId; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.wpilibj.Encoder; +import edu.wpi.first.wpilibj.Joystick; +import edu.wpi.first.wpilibj.RobotController; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax; +import edu.wpi.first.wpilibj.simulation.EncoderSim; +import edu.wpi.first.wpilibj.simulation.FlywheelSim; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; + +/** + * This is a sample program to demonstrate the use of a BangBangController with a flywheel to + * control RPM. + */ +public class Robot extends TimedRobot { + private static final int kMotorPort = 0; + private static final int kEncoderAChannel = 0; + private static final int kEncoderBChannel = 1; + + // Max setpoint for joystick control in RPM + private static final double kMaxSetpointValue = 6000.0; + + // Joystick to control setpoint + private final Joystick m_joystick = new Joystick(0); + + private final PWMSparkMax m_flywheelMotor = new PWMSparkMax(kMotorPort); + private final Encoder m_encoder = new Encoder(kEncoderAChannel, kEncoderBChannel); + + private final BangBangController m_bangBangController = new BangBangController(); + + // Gains are for example purposes only - must be determined for your own robot! + public static final double kFlywheelKs = 0.0001; // V + public static final double kFlywheelKv = 0.000195; // V/RPM + public static final double kFlywheelKa = 0.0003; // V/(RPM/s) + private final SimpleMotorFeedforward m_feedforward = + new SimpleMotorFeedforward(kFlywheelKs, kFlywheelKv, kFlywheelKa); + + // Simulation classes help us simulate our robot + + // Reduction between motors and encoder, as output over input. If the flywheel + // spins slower than the motors, this number should be greater than one. + private static final double kFlywheelGearing = 1.0; + + // 1/2 MR² + private static final double kFlywheelMomentOfInertia = + 0.5 * Units.lbsToKilograms(1.5) * Math.pow(Units.inchesToMeters(4), 2); + + private final DCMotor m_gearbox = DCMotor.getNEO(1); + + private final LinearSystem m_plant = + LinearSystemId.createFlywheelSystem(m_gearbox, kFlywheelGearing, kFlywheelMomentOfInertia); + + private final FlywheelSim m_flywheelSim = new FlywheelSim(m_plant, m_gearbox); + private final EncoderSim m_encoderSim = new EncoderSim(m_encoder); + + public Robot() { + // Add bang-bang controller to SmartDashboard and networktables. + SmartDashboard.putData(m_bangBangController); + } + + /** Controls flywheel to a set speed (RPM) controlled by a joystick. */ + @Override + public void teleopPeriodic() { + // Scale setpoint value between 0 and maxSetpointValue + double setpoint = + Math.max( + 0.0, + m_joystick.getRawAxis(0) + * Units.rotationsPerMinuteToRadiansPerSecond(kMaxSetpointValue)); + + // Set setpoint and measurement of the bang-bang controller + double bangOutput = m_bangBangController.calculate(m_encoder.getRate(), setpoint) * 12.0; + + // Controls a motor with the output of the BangBang controller and a + // feedforward. The feedforward is reduced slightly to avoid overspeeding + // the shooter. + m_flywheelMotor.setVoltage(bangOutput + 0.9 * m_feedforward.calculate(setpoint)); + } + + /** Update our simulation. This should be run every robot loop in simulation. */ + @Override + public void simulationPeriodic() { + // To update our simulation, we set motor voltage inputs, update the + // simulation, and write the simulated velocities to our simulated encoder + m_flywheelSim.setInputVoltage(m_flywheelMotor.get() * RobotController.getInputVoltage()); + m_flywheelSim.update(0.02); + m_encoderSim.setRate(m_flywheelSim.getAngularVelocityRadPerSec()); + } +} diff --git a/prototype_projects/Flywheel_BangBangController/vendordeps/Phoenix6-26.1.0.json b/prototype_projects/Flywheel_BangBangController/vendordeps/Phoenix6-26.1.0.json new file mode 100644 index 0000000..dc5dc62 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/vendordeps/Phoenix6-26.1.0.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-26.1.0.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Flywheel_BangBangController/vendordeps/REVLib.json b/prototype_projects/Flywheel_BangBangController/vendordeps/REVLib.json new file mode 100644 index 0000000..4f96af8 --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/vendordeps/REVLib.json @@ -0,0 +1,133 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2026.0.0", + "frcYear": "2026", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2026.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2026.0.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2026.0.0", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.0", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.0", + "libName": "BackendDriver", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.0", + "libName": "REVLibWpi", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Flywheel_BangBangController/vendordeps/WPILibNewCommands.json b/prototype_projects/Flywheel_BangBangController/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/Flywheel_BangBangController/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} diff --git a/prototype_projects/VelocityClosedLoop/.gitignore b/prototype_projects/VelocityClosedLoop/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/.gitignore @@ -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 diff --git a/prototype_projects/VelocityClosedLoop/.vscode/launch.json b/prototype_projects/VelocityClosedLoop/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/VelocityClosedLoop/.vscode/settings.json b/prototype_projects/VelocityClosedLoop/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/VelocityClosedLoop/.wpilib/wpilib_preferences.json b/prototype_projects/VelocityClosedLoop/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..eadec71 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 7762 +} diff --git a/prototype_projects/VelocityClosedLoop/WPILib-License.md b/prototype_projects/VelocityClosedLoop/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/VelocityClosedLoop/build.gradle b/prototype_projects/VelocityClosedLoop/build.gradle new file mode 100644 index 0000000..e9b0020 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/VelocityClosedLoop/gradlew b/prototype_projects/VelocityClosedLoop/gradlew new file mode 100755 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/gradlew @@ -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" "$@" diff --git a/prototype_projects/VelocityClosedLoop/gradlew.bat b/prototype_projects/VelocityClosedLoop/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/gradlew.bat @@ -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 diff --git a/prototype_projects/VelocityClosedLoop/settings.gradle b/prototype_projects/VelocityClosedLoop/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/settings.gradle @@ -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"); diff --git a/prototype_projects/VelocityClosedLoop/src/main/deploy/example.txt b/prototype_projects/VelocityClosedLoop/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Main.java b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Mechanisms.java b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Mechanisms.java new file mode 100644 index 0000000..572e396 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Mechanisms.java @@ -0,0 +1,58 @@ +package frc.robot; + +import static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.StatusSignal; + +import edu.wpi.first.units.measure.Angle; +import edu.wpi.first.units.measure.AngularVelocity; +import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d; +import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj.util.Color; +import edu.wpi.first.wpilibj.util.Color8Bit; + +/** + * Class to keep all the mechanism-specific objects together and out of the main example + */ +public class Mechanisms { + double HEIGHT = 1; // Controls the height of the mech2d SmartDashboard + double WIDTH = 1; // Controls the height of the mech2d SmartDashboard + + Mechanism2d mech = new Mechanism2d(WIDTH, HEIGHT); + // Velocity + MechanismLigament2d VelocityMech = mech. + getRoot("velocityLineReferencePosition", 0.75, 0.5). + append(new MechanismLigament2d("velocityLine", 1,90, 6, new Color8Bit(Color.kAliceBlue))); + + MechanismLigament2d midline = mech. + getRoot("midline", 0.7, 0.5). + append(new MechanismLigament2d("midline", 0.1, 0, 3, new Color8Bit(Color.kCyan))); + + //Position + MechanismLigament2d arm = mech. + getRoot("pivotPoint", 0.25, 0.5). + append(new MechanismLigament2d("arm", .2, 0, 0, new Color8Bit(Color.kAliceBlue))); + + MechanismLigament2d side1 = arm.append(new MechanismLigament2d("side1", 0.15307, 112.5, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side2 = side1.append(new MechanismLigament2d("side2", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side3 = side2.append(new MechanismLigament2d("side3", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side4 = side3.append(new MechanismLigament2d("side4", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side5 = side4.append(new MechanismLigament2d("side5", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side6 = side5.append(new MechanismLigament2d("side6", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side7 = side6.append(new MechanismLigament2d("side7", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side8 = side7.append(new MechanismLigament2d("side8", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + + /** + * Runs the mech2d widget in GUI. + * + * This utilizes GUI to simulate and display a TalonFX and exists to allow users to test and understand + * features of our products in simulation using our examples out of the box. Users may modify to have a + * display interface that they find more intuitive or visually appealing. + */ + public void update(StatusSignal position, StatusSignal velocity) { + VelocityMech.setLength(velocity.getValue().in(RotationsPerSecond)/120); + arm.setAngle(position.getValue().in(Rotations) * 360); // Divide by 120 to scale motion to fit in the window + SmartDashboard.putData("mech2d", mech); // Creates mech2d in SmartDashboard + } +} diff --git a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..fbc7ae3 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java @@ -0,0 +1,139 @@ +// 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 static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.CANBus; +import com.ctre.phoenix6.StatusCode; +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.Follower; +import com.ctre.phoenix6.controls.NeutralOut; +import com.ctre.phoenix6.controls.VelocityTorqueCurrentFOC; +import com.ctre.phoenix6.controls.VelocityVoltage; +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.signals.MotorAlignmentValue; + +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.XboxController; +import frc.robot.sim.PhysicsSim; + +/** + * The VM is configured to automatically run this class, and to call the functions corresponding to + * each mode, as described in the TimedRobot documentation. If you change the name of this class or + * the package after creating this project, you must also update the build.gradle file in the + * project. + */ +public class Robot extends TimedRobot { + private final CANBus canbus = new CANBus("canivore"); + private final TalonFX m_fx = new TalonFX(0, canbus); + private final TalonFX m_fllr = new TalonFX(1, canbus); + + /* Be able to switch which control request to use based on a button press */ + /* Start at velocity 0, use slot 0 */ + private final VelocityVoltage m_velocityVoltage = new VelocityVoltage(0).withSlot(0); + /* Start at velocity 0, use slot 1 */ + private final VelocityTorqueCurrentFOC m_velocityTorque = new VelocityTorqueCurrentFOC(0).withSlot(1); + /* Keep a neutral out so we can disable the motor */ + private final NeutralOut m_brake = new NeutralOut(); + + private final XboxController m_joystick = new XboxController(0); + + private final Mechanisms m_mechanisms = new Mechanisms(); + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + public Robot() { + TalonFXConfiguration configs = new TalonFXConfiguration(); + + /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ + configs.Slot0.kS = 0.1; // To account for friction, add 0.1 V of static feedforward + configs.Slot0.kV = 0.12; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second + configs.Slot0.kP = 0.11; // An error of 1 rotation per second results in 0.11 V output + configs.Slot0.kI = 0; // No output for integrated error + configs.Slot0.kD = 0; // No output for error derivative + // Peak output of 8 volts + configs.Voltage.withPeakForwardVoltage(Volts.of(8)) + .withPeakReverseVoltage(Volts.of(-8)); + + /* Torque-based velocity does not require a velocity feed forward, as torque will accelerate the rotor up to the desired velocity by itself */ + configs.Slot1.kS = 2.5; // To account for friction, add 2.5 A of static feedforward + configs.Slot1.kP = 5; // An error of 1 rotation per second results in 5 A output + configs.Slot1.kI = 0; // No output for integrated error + configs.Slot1.kD = 0; // No output for error derivative + // Peak output of 40 A + configs.TorqueCurrent.withPeakForwardTorqueCurrent(Amps.of(40)) + .withPeakReverseTorqueCurrent(Amps.of(-40)); + + /* Retry config apply up to 5 times, report if failure */ + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = m_fx.getConfigurator().apply(configs); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs, error code: " + status.toString()); + } + + m_fllr.setControl(new Follower(m_fx.getDeviceID(), MotorAlignmentValue.Aligned)); + } + + @Override + public void robotPeriodic() { + m_mechanisms.update(m_fx.getPosition(), m_fx.getVelocity()); + } + + @Override + public void autonomousInit() {} + + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() {} + + @Override + public void teleopPeriodic() { + double joyValue = m_joystick.getLeftY(); + if (Math.abs(joyValue) < 0.1) joyValue = 0; + + double desiredRotationsPerSecond = joyValue * 50; // Go for plus/minus 50 rotations per second + + if (m_joystick.getLeftBumperButton()) { + /* Use velocity voltage */ + m_fx.setControl(m_velocityVoltage.withVelocity(desiredRotationsPerSecond)); + } else if (m_joystick.getRightBumperButton()) { + /* Use velocity torque */ + m_fx.setControl(m_velocityTorque.withVelocity(desiredRotationsPerSecond)); + } else { + /* Disable the motor instead */ + m_fx.setControl(m_brake); + } + } + + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + @Override + public void testInit() {} + + @Override + public void testPeriodic() {} + + @Override + public void simulationInit() { + PhysicsSim.getInstance().addTalonFX(m_fx, 0.001); + } + + @Override + public void simulationPeriodic() { + PhysicsSim.getInstance().run(); + } +} diff --git a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/PhysicsSim.java b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/PhysicsSim.java new file mode 100644 index 0000000..6000bca --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/PhysicsSim.java @@ -0,0 +1,81 @@ +package frc.robot.sim; + +import java.util.ArrayList; + +import com.ctre.phoenix6.Utils; +import com.ctre.phoenix6.hardware.TalonFX; + +/** + * Manages physics simulation for CTRE products. + */ +public class PhysicsSim { + private static final PhysicsSim sim = new PhysicsSim(); + + /** + * Gets the robot simulator instance. + */ + public static PhysicsSim getInstance() { + return sim; + } + + /** + * Adds a TalonFX controller to the simulator. + * + * @param talonFX + * The TalonFX device + * @param rotorInertia + * Rotational Inertia of the mechanism at the rotor + */ + public void addTalonFX(TalonFX talonFX, final double rotorInertia) { + if (talonFX != null) { + TalonFXSimProfile simTalonFX = new TalonFXSimProfile(talonFX, rotorInertia); + _simProfiles.add(simTalonFX); + } + } + + /** + * Runs the simulator: + * - enable the robot + * - simulate sensors + */ + public void run() { + // Simulate devices + for (SimProfile simProfile : _simProfiles) { + simProfile.run(); + } + } + + private final ArrayList _simProfiles = new ArrayList(); + + /** + * Holds information about a simulated device. + */ + static class SimProfile { + private double _lastTime; + private boolean _running = false; + + /** + * Runs the simulation profile. + * Implemented by device-specific profiles. + */ + public void run() { + } + + /** + * Returns the time since last call, in seconds. + */ + protected double getPeriod() { + // set the start time if not yet running + if (!_running) { + _lastTime = Utils.getCurrentTimeSeconds(); + _running = true; + } + + double now = Utils.getCurrentTimeSeconds(); + final double period = now - _lastTime; + _lastTime = now; + + return period; + } + } +} \ No newline at end of file diff --git a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/TalonFXSimProfile.java b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/TalonFXSimProfile.java new file mode 100644 index 0000000..0dc9756 --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/sim/TalonFXSimProfile.java @@ -0,0 +1,57 @@ +package frc.robot.sim; + +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.sim.TalonFXSimState; + +import edu.wpi.first.math.system.plant.DCMotor; +import edu.wpi.first.math.system.plant.LinearSystemId; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import frc.robot.sim.PhysicsSim.SimProfile; + +/** + * Holds information about a simulated TalonFX. + */ +class TalonFXSimProfile extends SimProfile { + private static final double kMotorResistance = 0.002; // Assume 2mOhm resistance for voltage drop calculation + private final TalonFXSimState _talonFXSim; + private final DCMotorSim _motorSim; + + /** + * Creates a new simulation profile for a TalonFX device. + * + * @param talonFX + * The TalonFX device + * @param rotorInertia + * Rotational Inertia of the mechanism at the rotor + */ + public TalonFXSimProfile(final TalonFX talonFX, final double rotorInertia) { + var gearbox = DCMotor.getKrakenX60Foc(1); + this._motorSim = new DCMotorSim(LinearSystemId.createDCMotorSystem(gearbox, rotorInertia, 1.0), gearbox); + this._talonFXSim = talonFX.getSimState(); + } + + /** + * Runs the simulation profile. + * + * This uses very rudimentary physics simulation and exists to allow users to + * test features of our products in simulation using our examples out of the + * box. Users may modify this to utilize more accurate physics simulation. + */ + public void run() { + /// DEVICE SPEED SIMULATION + + _motorSim.setInputVoltage(_talonFXSim.getMotorVoltage()); + + _motorSim.update(getPeriod()); + + /// SET SIM PHYSICS INPUTS + final double position_rot = _motorSim.getAngularPositionRotations(); + final double velocity_rps = Units.radiansToRotations(_motorSim.getAngularVelocityRadPerSec()); + + _talonFXSim.setRawRotorPosition(position_rot); + _talonFXSim.setRotorVelocity(velocity_rps); + + _talonFXSim.setSupplyVoltage(12 - _talonFXSim.getSupplyCurrent() * kMotorResistance); + } +} \ No newline at end of file diff --git a/prototype_projects/VelocityClosedLoop/vendordeps/Phoenix6-frc2026-latest.json b/prototype_projects/VelocityClosedLoop/vendordeps/Phoenix6-frc2026-latest.json new file mode 100644 index 0000000..8f6e30f --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/vendordeps/Phoenix6-frc2026-latest.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-frc2026-latest.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/VelocityClosedLoop/vendordeps/WPILibNewCommands.json b/prototype_projects/VelocityClosedLoop/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/VelocityClosedLoop/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} From 472a8ddea700d6c3ae82227120ed2c727f8c2e7b Mon Sep 17 00:00:00 2001 From: Dave Wilson <32313507+dawilson9@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:41:36 -0600 Subject: [PATCH 003/161] Merge pull request #2 from frc9577/1-complete-the-repos-readme Complete the Repos ReadMe, adding information on expected branch usage. --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ed65ecd..5e15129 100644 --- a/README.md +++ b/README.md @@ -16,4 +16,13 @@ This top-level directory contains prototype, example and experiment projects dev ## Branching Strategy and Commit Rules -To be completed... \ No newline at end of file +This repository uses a modified feature branch workflow. Where all big features are done on short-lived feature branches, and then merged into a development branch for final bug testing before being put through pull request (PR) into main. Although, if the change is quick enough to do in one setting and meets the commit requirements (talked about later) for the development branch the change can be committed directly to it. + +### Main: +The most stable copy of the current year's competition code. Code cannot be directly committed to this branch and instead it is required to use a PR. Before a PR is merged into main, a full test of the robot is required to make sure every feature works. + +### Development: +This branch houses all of the in-development features that aren't stable enough for main. Although, we should try our best to make sure that the current year's code in the development branch always works via quick testing on a mule or similar to make sure that any changes do not outright “brick” the robot. Pull requests are not required, but if you think a change should have a discussion feel free to make one. + +### Feature Branches: +Feature branches are short-lived branches to work on specific features, they should be named with this format: “YEAR-FEATURE_SHORTHAND”. An example is “2026-ground_pickup” which would be a feature branch for a ground pickup for the 2026 competition. These branches have no commit requirements and are not required to run or build. This is so we can upload our changes to the github at the end of sessions without losing it due to the chance of using a different computer. After a feature is completed, make sure to merge development into your branch and make sure that the robot still mostly works via a quick test. Once that is completed you can merge your branch into development and delete the feature branch. From 0ac28a58b05b68b4a7d6fac4f18a49b9f0d798ee Mon Sep 17 00:00:00 2001 From: 15 - Phosphorus <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:10:53 -0600 Subject: [PATCH 004/161] Ported the experimental drivetrain. --- .../Experimental_Drivetrain/.SysId/sysid.json | 1 + .../.github/workflows/ci.yml | 36 + .../Experimental_Drivetrain/.gitignore | 193 ++ .../.vscode/launch.json | 21 + .../.vscode/settings.json | 60 + .../.wpilib/wpilib_preferences.json | 6 + .../Experimental_Drivetrain/LICENSE | 21 + .../Experimental_Drivetrain/Makefile | 22 + .../Experimental_Drivetrain/README.md | 42 + .../Experimental_Drivetrain/WPILib-License.md | 24 + .../Experimental_Drivetrain/build.gradle | 104 ++ .../common-repo-sync.sh | 8 + .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../Experimental_Drivetrain/gradlew | 252 +++ .../Experimental_Drivetrain/gradlew.bat | 94 + .../Experimental_Drivetrain/settings.gradle | 30 + .../Experimental_Drivetrain/simgui-ds.json | 92 + .../src/main/deploy/example.txt | 3 + .../deploy/pathplanner/autos/SampleAuto.auto | 19 + .../src/main/deploy/pathplanner/navgrid.json | 1 + .../pathplanner/paths/Example Path.path | 54 + .../src/main/deploy/pathplanner/settings.json | 34 + .../src/main/java/frc/robot/Constants.java | 91 + .../main/java/frc/robot/LimelightHelpers.java | 1645 +++++++++++++++++ .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 103 ++ .../main/java/frc/robot/RobotContainer.java | 156 ++ .../robot/commands/ArcadeDriveCommand.java | 53 + .../main/java/frc/robot/commands/Autos.java | 20 + .../commands/DifferentialDriveCommand.java | 57 + .../frc/robot/commands/ExampleCommand.java | 43 + .../robot/factorys/DriveSubsystemFactory.java | 33 + .../frc/robot/factorys/TalonFXFactory.java | 20 + .../frc/robot/subsystems/DriveSubsystem.java | 285 +++ .../robot/subsystems/ExampleSubsystem.java | 47 + .../robot/subsystems/LimelightSubsystem.java | 48 + .../java/frc/robot/utils/AutoCommands.java | 59 + .../main/java/frc/robot/utils/PIDControl.java | 69 + .../sysid_logs/Screenshot (1).png | Bin 0 -> 578440 bytes .../hoots/rio_2025-11-11_19-44-12.hoot | Bin 0 -> 405544 bytes .../rio_2025-11-11_19-44-12.hoot.wpilog | Bin 0 -> 603578 bytes .../vendordeps/PathplannerLib-2025.2.7.json | 38 + .../vendordeps/Phoenix6-frc2025-latest.json | 479 +++++ .../vendordeps/REVLib.json | 71 + .../vendordeps/Studica-2025.0.1.json | 71 + .../vendordeps/WPILibNewCommands.json | 38 + 47 files changed, 4575 insertions(+) create mode 100644 prototype_projects/Experimental_Drivetrain/.SysId/sysid.json create mode 100644 prototype_projects/Experimental_Drivetrain/.github/workflows/ci.yml create mode 100644 prototype_projects/Experimental_Drivetrain/.gitignore create mode 100644 prototype_projects/Experimental_Drivetrain/.vscode/launch.json create mode 100644 prototype_projects/Experimental_Drivetrain/.vscode/settings.json create mode 100644 prototype_projects/Experimental_Drivetrain/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/Experimental_Drivetrain/LICENSE create mode 100644 prototype_projects/Experimental_Drivetrain/Makefile create mode 100644 prototype_projects/Experimental_Drivetrain/README.md create mode 100644 prototype_projects/Experimental_Drivetrain/WPILib-License.md create mode 100644 prototype_projects/Experimental_Drivetrain/build.gradle create mode 100644 prototype_projects/Experimental_Drivetrain/common-repo-sync.sh create mode 100644 prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/Experimental_Drivetrain/gradlew create mode 100644 prototype_projects/Experimental_Drivetrain/gradlew.bat create mode 100644 prototype_projects/Experimental_Drivetrain/settings.gradle create mode 100644 prototype_projects/Experimental_Drivetrain/simgui-ds.json create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/deploy/example.txt create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/autos/SampleAuto.auto create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/navgrid.json create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/paths/Example Path.path create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/settings.json create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Constants.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/LimelightHelpers.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/RobotContainer.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ArcadeDriveCommand.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/Autos.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/DifferentialDriveCommand.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ExampleCommand.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/TalonFXFactory.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/DriveSubsystem.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/ExampleSubsystem.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/LimelightSubsystem.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/AutoCommands.java create mode 100644 prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/PIDControl.java create mode 100644 prototype_projects/Experimental_Drivetrain/sysid_logs/Screenshot (1).png create mode 100644 prototype_projects/Experimental_Drivetrain/sysid_logs/hoots/rio_2025-11-11_19-44-12.hoot create mode 100644 prototype_projects/Experimental_Drivetrain/sysid_logs/wpilogs/rio_2025-11-11_19-44-12.hoot.wpilog create mode 100644 prototype_projects/Experimental_Drivetrain/vendordeps/PathplannerLib-2025.2.7.json create mode 100644 prototype_projects/Experimental_Drivetrain/vendordeps/Phoenix6-frc2025-latest.json create mode 100644 prototype_projects/Experimental_Drivetrain/vendordeps/REVLib.json create mode 100644 prototype_projects/Experimental_Drivetrain/vendordeps/Studica-2025.0.1.json create mode 100644 prototype_projects/Experimental_Drivetrain/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/Experimental_Drivetrain/.SysId/sysid.json b/prototype_projects/Experimental_Drivetrain/.SysId/sysid.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/.SysId/sysid.json @@ -0,0 +1 @@ +{} diff --git a/prototype_projects/Experimental_Drivetrain/.github/workflows/ci.yml b/prototype_projects/Experimental_Drivetrain/.github/workflows/ci.yml new file mode 100644 index 0000000..28e5370 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/.github/workflows/ci.yml @@ -0,0 +1,36 @@ +# This YML defines the basic build CI job. For syntax, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions +# This workflow file is based on this WPILib Reference with modifications: https://docs.wpilib.org/en/stable/docs/software/advanced-gradlerio/robot-code-ci.html +name: robot_ci + +# This action runs on all pull requests into main and when the result of the pull request is merged. +on: + pull_request: + branches: + - main + push: + branches: + - main + +# The concurrency setting prevents multiple runs of this workflow on the same ref/hash +concurrency: ${{ github.workflow }}-${{ github.ref }} + +# We define one job called 'ci' which runs the gradle build. A separate ruleset in the repository will make this a commit gate by requiring the job to pass +# In the job, we tell the orchestrator to run on a github provided ubuntu 22.04 instance and to use the WPILib provided docker container +# Using that docker container makes the build look like a developer machine install with WPILib available +# The job then runs gradlew build +# If the project structure significantly changes (e.g. gradlew moves) then the path below for both the chmod and the gradlew invocation need to match the change. +jobs: + ci: + runs-on: ubuntu-22.04 + container: + image: docker://wpilib/roborio-cross-ubuntu:2025-22.04 + steps: + - name: Git Checkout + uses: actions/checkout@v4 + - name: Git Clone Common Repo + run: | + sh common-repo-sync.sh + - name: Gradle Build + run: | + chmod +x gradlew + ./gradlew build \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/.gitignore b/prototype_projects/Experimental_Drivetrain/.gitignore new file mode 100644 index 0000000..8c93450 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/.gitignore @@ -0,0 +1,193 @@ +## Additional .gitingore file for the project defined by FRC 9577 +.gradle-home/ + +## This is the location of our common repo. +src/main/java/frc/recoil/ + +# 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 diff --git a/prototype_projects/Experimental_Drivetrain/.vscode/launch.json b/prototype_projects/Experimental_Drivetrain/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/Experimental_Drivetrain/.vscode/settings.json b/prototype_projects/Experimental_Drivetrain/.vscode/settings.json new file mode 100644 index 0000000..612cdd0 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/.vscode/settings.json @@ -0,0 +1,60 @@ +{ + "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.*", + ] +} diff --git a/prototype_projects/Experimental_Drivetrain/.wpilib/wpilib_preferences.json b/prototype_projects/Experimental_Drivetrain/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..a792267 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2025", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/LICENSE b/prototype_projects/Experimental_Drivetrain/LICENSE new file mode 100644 index 0000000..66c3dbc --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Recoil Robotics + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/prototype_projects/Experimental_Drivetrain/Makefile b/prototype_projects/Experimental_Drivetrain/Makefile new file mode 100644 index 0000000..4fbddeb --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/Makefile @@ -0,0 +1,22 @@ +WORKDIR ?= $(shell pwd) + +WPILIB_CONTAINER := wpilib/roborio-cross-ubuntu:2025-22.04 + +.PHONY: build +build: + bash common-repo-sync.sh + docker run -it -v ${WORKDIR}:/work -w /work -e GRADLE_USER_HOME=/work/.gradle-home ${WPILIB_CONTAINER} sh -c "./gradlew build" + +.PHONY: deploy +deploy: + docker run -it -v ${WORKDIR}:/work -w /work -e GRADLE_USER_HOME=/work/.gradle-home ${WPILIB_CONTAINER} sh -c "./gradlew deploy" + +.PHONY: clean +clean: + docker run -it -v ${WORKDIR}:/work -w /work -e GRADLE_USER_HOME=/work/.gradle-home ${WPILIB_CONTAINER} sh -c "rm -Rf build" + +.PHONY: deep-clean +deep-clean: clean + docker run -it -v ${WORKDIR}:/work -w /work -e GRADLE_USER_HOME=/work/.gradle-home ${WPILIB_CONTAINER} sh -c "rm -Rf .gradle && rm -Rf .gradle-home" + rm -Rf src/main/java/frc/recoil + git clean -fdx \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/README.md b/prototype_projects/Experimental_Drivetrain/README.md new file mode 100644 index 0000000..426720e --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/README.md @@ -0,0 +1,42 @@ +# robot-base +FRC 9577's Template Repository for Robot Code + +# How to use this template +This repositry is a github template repository. It represents the baseline code that FRC 9577 uses for our robots, including dependencies we use in our designs. To use our code, create a repository using this one as a template. + +## Repository Approach +The approach here is to minimize setup time for a developer. By leveraging the WPILib distributed docker container and through effective use of docker we limit the prerequisite install to just a few items. This approach is for development only and does not replace the driver station. We support both linux and Windows for development. (Currently ) + +## Installing Prerequsiites +This repository does not contain any tools. You need to install four tools to support your build: git, VSCode, make, and docker. + +### Installing on Linux +To install on linux, use your package manager to pick up git, make, and docker. Testing was done on git 2.43, make 4.3, and docker 27.3.1. + +Both make and git come directly from the package manager (e.g. for ubuntu `apt install make git`). + +VS Code is installation instructions are here: https://code.visualstudio.com/docs/setup/linux + +Docker installation instructions are here: https://docs.docker.com/engine/install/ubuntu/ + +### Installing on Windows +Herein, we provide references to each of the windows installers:https://gnuwin32.sourceforge.net/packages/make.htmz +* git: https://git-scm.com/downloads/win +* make: https://gnuwin32.sourceforge.net/packages/make.htm +* docker: https://docs.docker.com/desktop/install/windows-install/ +* VSCode: https://code.visualstudio.com/docs/setup/windows + +This is more manual than a linux install, but it's just 4 tools. + +When installing git, choose the option to install bash. Always use bash as your windows terminal when using this repo, as we only test on bash. + +### Windows "funnies" +- Need to install make for everyone and add the make path manually to system paths. +- Need to build via external git bash terminal started as administrator. + +# Updating this template +When a new version of tools or libraries becomes available, use the WPILIB VSCode plugin to update the files in the project. Then, open a pull request against main to merge your change in. + +Sometimes there are updates not serviced by the WPILib plugin. In these cases, make the changes using editors and push the results to github. + +This repository can also be forked. diff --git a/prototype_projects/Experimental_Drivetrain/WPILib-License.md b/prototype_projects/Experimental_Drivetrain/WPILib-License.md new file mode 100644 index 0000000..645e542 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2024 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/Experimental_Drivetrain/build.gradle b/prototype_projects/Experimental_Drivetrain/build.gradle new file mode 100644 index 0000000..bb54b03 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/build.gradle @@ -0,0 +1,104 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2025.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 = true // 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 JNI. +wpi.java.debugJni = false + +// Set this to true to enable desktop support. +def includeDesktopSupport = true + +// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. +// Also defines JUnit 5. +dependencies { + 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' +} diff --git a/prototype_projects/Experimental_Drivetrain/common-repo-sync.sh b/prototype_projects/Experimental_Drivetrain/common-repo-sync.sh new file mode 100644 index 0000000..fc3b951 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/common-repo-sync.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +git config --global --add safe.directory /home/jeff/work/robot-base/src/main/java/frc/recoil +if [ -d "src/main/java/frc/recoil" ]; then + (cd src/main/java/frc/recoil && git pull) +else + git clone --branch main --depth 1 https://github.com/frc9577/common src/main/java/frc/recoil +fi diff --git a/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/Experimental_Drivetrain/gradlew b/prototype_projects/Experimental_Drivetrain/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/gradlew @@ -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" "$@" diff --git a/prototype_projects/Experimental_Drivetrain/gradlew.bat b/prototype_projects/Experimental_Drivetrain/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/gradlew.bat @@ -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 diff --git a/prototype_projects/Experimental_Drivetrain/settings.gradle b/prototype_projects/Experimental_Drivetrain/settings.gradle new file mode 100644 index 0000000..969c7b0 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/settings.gradle @@ -0,0 +1,30 @@ +import org.gradle.internal.os.OperatingSystem + +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + String frcYear = '2025' + File frcHome + if (OperatingSystem.current().isWindows()) { + String publicFolder = System.getenv('PUBLIC') + if (publicFolder == null) { + publicFolder = "C:\\Users\\Public" + } + def homeRoot = new File(publicFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } else { + def userFolder = System.getProperty("user.home") + def homeRoot = new File(userFolder, "wpilib") + frcHome = new File(homeRoot, frcYear) + } + def frcHomeMaven = new File(frcHome, 'maven') + maven { + name 'frcHome' + url frcHomeMaven + } + } +} + +Properties props = System.getProperties(); +props.setProperty("org.gradle.internal.native.headers.unresolved.dependencies.ignore", "true"); diff --git a/prototype_projects/Experimental_Drivetrain/simgui-ds.json b/prototype_projects/Experimental_Drivetrain/simgui-ds.json new file mode 100644 index 0000000..73cc713 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/simgui-ds.json @@ -0,0 +1,92 @@ +{ + "keyboardJoysticks": [ + { + "axisConfig": [ + { + "decKey": 65, + "incKey": 68 + }, + { + "decKey": 87, + "incKey": 83 + }, + { + "decKey": 69, + "decayRate": 0.0, + "incKey": 82, + "keyRate": 0.009999999776482582 + } + ], + "axisCount": 3, + "buttonCount": 4, + "buttonKeys": [ + 90, + 88, + 67, + 86 + ], + "povConfig": [ + { + "key0": 328, + "key135": 323, + "key180": 322, + "key225": 321, + "key270": 324, + "key315": 327, + "key45": 329, + "key90": 326 + } + ], + "povCount": 1 + }, + { + "axisConfig": [ + { + "decKey": 74, + "incKey": 76 + }, + { + "decKey": 73, + "incKey": 75 + } + ], + "axisCount": 2, + "buttonCount": 4, + "buttonKeys": [ + 77, + 44, + 46, + 47 + ], + "povCount": 0 + }, + { + "axisConfig": [ + { + "decKey": 263, + "incKey": 262 + }, + { + "decKey": 265, + "incKey": 264 + } + ], + "axisCount": 2, + "buttonCount": 6, + "buttonKeys": [ + 260, + 268, + 266, + 261, + 269, + 267 + ], + "povCount": 0 + }, + { + "axisCount": 0, + "buttonCount": 0, + "povCount": 0 + } + ] +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/example.txt b/prototype_projects/Experimental_Drivetrain/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/autos/SampleAuto.auto b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/autos/SampleAuto.auto new file mode 100644 index 0000000..70b7ab2 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/autos/SampleAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Example Path" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/navgrid.json b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/navgrid.json new file mode 100644 index 0000000..23e0db9 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/navgrid.json @@ -0,0 +1 @@ +{"field_size":{"x":17.548,"y":8.052},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/paths/Example Path.path b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/paths/Example Path.path new file mode 100644 index 0000000..d474f95 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/paths/Example Path.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.1486729452054796, + "y": 6.48169948630137 + }, + "prevControl": null, + "nextControl": { + "x": 2.3986729452054796, + "y": 6.48169948630137 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 5.213912671232877, + "y": 6.48169948630137 + }, + "prevControl": { + "x": 4.963912671232877, + "y": 6.48169948630137 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 3.0, + "maxAcceleration": 3.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/settings.json b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/settings.json new file mode 100644 index 0000000..75d95ab --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/settings.json @@ -0,0 +1,34 @@ +{ + "robotWidth": 0.9, + "robotLength": 0.9, + "holonomicMode": false, + "pathFolders": [ + "New Folder" + ], + "autoFolders": [], + "defaultMaxVel": 3.0, + "defaultMaxAccel": 3.0, + "defaultMaxAngVel": 540.0, + "defaultMaxAngAccel": 720.0, + "defaultNominalVoltage": 12.0, + "robotMass": 74.088, + "robotMOI": 6.883, + "robotTrackwidth": 0.546, + "driveWheelRadius": 0.0508, + "driveGearing": 5.143, + "maxDriveSpeed": 5.45, + "driveMotorType": "krakenX60", + "driveCurrentLimit": 60.0, + "wheelCOF": 1.0, + "flModuleX": 0.273, + "flModuleY": 0.273, + "frModuleX": 0.273, + "frModuleY": -0.273, + "blModuleX": -0.273, + "blModuleY": 0.273, + "brModuleX": -0.273, + "brModuleY": -0.273, + "bumperOffsetX": 0.0, + "bumperOffsetY": 0.0, + "robotFeatures": [] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..5a4561c --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Constants.java @@ -0,0 +1,91 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import com.pathplanner.lib.config.ModuleConfig; +import com.pathplanner.lib.config.RobotConfig; + +import edu.wpi.first.math.system.plant.DCMotor; + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + public static class AutoConstants { + // Module Config Stuff + public static final double kMaxDriveVelocityMPS = 40.0; // This is what SysID is saying i dont think its going 90 mph + public static final double kWheelCOF = 1.0; + public static final int kNumMotors = 4; + public static final double kDriveCurrentLimit = 10.0; + + public static final DCMotor kDriveMotor = DCMotor.getKrakenX60(kNumMotors); + public static final ModuleConfig kMoudleConfig = new ModuleConfig( + DrivetrainConstants.kWheelRadiusMeters, + kMaxDriveVelocityMPS, + kWheelCOF, + kDriveMotor, + kDriveCurrentLimit, + kNumMotors + ); + + // Robot Config Stuff + // TODO: Run SYS ID and fill in! + public static final double kMassKG = 15.0; + public static final double kMOI = kMassKG * (DrivetrainConstants.trackWidthMeters/2) * (DrivetrainConstants.kA_angular / DrivetrainConstants.kA_linear); // Moment of Intertia + + public static final RobotConfig kRobotConfig = new RobotConfig(kMassKG, kMOI, kMoudleConfig, DrivetrainConstants.trackWidthMeters); + } + + public static class OperatorConstants { + public static final int kDriverControllerPort = 0; + } + + public static class DrivetrainConstants { + public static final int kLeftMotorCANID = 10; + public static final int kOptionalLeftMotorCANID = 11; + + public static final int kRightMotorCANID = 20; + public static final int kOptionalRightMotorCANID = 21; + + public static final double kTurnDivider = 2; + public static final double kSpeedDivider = 2.5; + + // These numbers came from sys id program + public static final double kV = 1.8747; // Add x V output to overcome static friction + public static final double kS = 0.15316; // A velocity target of 1 rps results in xV output + public static final double kP = 2.7562; // An error of 1 rotation results in x V output + public static final double kI = 0.0; + public static final double kD = 0.0; // A velocity of 1 rps results in x V output + public static final double kA_linear = 0.1141; // Voltage needed to induce a given accel. in the motor shaft + public static final double kA_angular = 0.1141; // TODO: We need to measure this! + public static final double PeakVoltage = 10.0; + + public static final int maxVelocity = 30; // rps/s + public static final int maxAcceleration = 50; // rps + + // Constants used by differential drive command. + public static final double maxVelocityMPS = 1.0; + + // For Auto Potentially + public static boolean kLeftPositiveMovesForward = true; + public static boolean kRightPositiveMovesForward = true; + + // Physical measurements related to the drivetrain. + public static final double kDrivetrainGearRatio = 0.2; + public static final double kWheelRadiusMeters = (4.0 / 2.0) * 0.0254; // Four Inch Wheels + public static final double kWheelCircumference = 2 * Math.PI * DrivetrainConstants.kWheelRadiusMeters; + + // SmartDashboard update frequency for drive subsystem state in 20ms counts. + public static final int kTicksPerUpdate = 5; + + // The track width in meters. + public static final double trackWidthMeters = 29.0 * 0.0254; + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/LimelightHelpers.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/LimelightHelpers.java new file mode 100644 index 0000000..1dbf387 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/LimelightHelpers.java @@ -0,0 +1,1645 @@ +//LimelightHelpers v1.11 (REQUIRES LLOS 2025.0 OR LATER) + +package frc.robot; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Pose3d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.geometry.Rotation3d; +import edu.wpi.first.math.geometry.Translation2d; +import edu.wpi.first.math.geometry.Translation3d; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.networktables.DoubleArrayEntry; +import edu.wpi.first.networktables.NetworkTable; +import edu.wpi.first.networktables.NetworkTableEntry; +import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.networktables.TimestampedDoubleArray; + +/** + * LimelightHelpers provides static methods and classes for interfacing with Limelight vision cameras in FRC. + * This library supports all Limelight features including AprilTag tracking, Neural Networks, and standard color/retroreflective tracking. + */ +public class LimelightHelpers { + + private static final Map doubleArrayEntries = new ConcurrentHashMap<>(); + + /** + * Represents a Color/Retroreflective Target Result extracted from JSON Output + */ + public static class LimelightTarget_Retro { + + @JsonProperty("t6c_ts") + private double[] cameraPose_TargetSpace; + + @JsonProperty("t6r_fs") + private double[] robotPose_FieldSpace; + + @JsonProperty("t6r_ts") + private double[] robotPose_TargetSpace; + + @JsonProperty("t6t_cs") + private double[] targetPose_CameraSpace; + + @JsonProperty("t6t_rs") + private double[] targetPose_RobotSpace; + + public Pose3d getCameraPose_TargetSpace() + { + return toPose3D(cameraPose_TargetSpace); + } + public Pose3d getRobotPose_FieldSpace() + { + return toPose3D(robotPose_FieldSpace); + } + public Pose3d getRobotPose_TargetSpace() + { + return toPose3D(robotPose_TargetSpace); + } + public Pose3d getTargetPose_CameraSpace() + { + return toPose3D(targetPose_CameraSpace); + } + public Pose3d getTargetPose_RobotSpace() + { + return toPose3D(targetPose_RobotSpace); + } + + public Pose2d getCameraPose_TargetSpace2D() + { + return toPose2D(cameraPose_TargetSpace); + } + public Pose2d getRobotPose_FieldSpace2D() + { + return toPose2D(robotPose_FieldSpace); + } + public Pose2d getRobotPose_TargetSpace2D() + { + return toPose2D(robotPose_TargetSpace); + } + public Pose2d getTargetPose_CameraSpace2D() + { + return toPose2D(targetPose_CameraSpace); + } + public Pose2d getTargetPose_RobotSpace2D() + { + return toPose2D(targetPose_RobotSpace); + } + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ts") + public double ts; + + public LimelightTarget_Retro() { + cameraPose_TargetSpace = new double[6]; + robotPose_FieldSpace = new double[6]; + robotPose_TargetSpace = new double[6]; + targetPose_CameraSpace = new double[6]; + targetPose_RobotSpace = new double[6]; + } + + } + + /** + * Represents an AprilTag/Fiducial Target Result extracted from JSON Output + */ + public static class LimelightTarget_Fiducial { + + @JsonProperty("fID") + public double fiducialID; + + @JsonProperty("fam") + public String fiducialFamily; + + @JsonProperty("t6c_ts") + private double[] cameraPose_TargetSpace; + + @JsonProperty("t6r_fs") + private double[] robotPose_FieldSpace; + + @JsonProperty("t6r_ts") + private double[] robotPose_TargetSpace; + + @JsonProperty("t6t_cs") + private double[] targetPose_CameraSpace; + + @JsonProperty("t6t_rs") + private double[] targetPose_RobotSpace; + + public Pose3d getCameraPose_TargetSpace() + { + return toPose3D(cameraPose_TargetSpace); + } + public Pose3d getRobotPose_FieldSpace() + { + return toPose3D(robotPose_FieldSpace); + } + public Pose3d getRobotPose_TargetSpace() + { + return toPose3D(robotPose_TargetSpace); + } + public Pose3d getTargetPose_CameraSpace() + { + return toPose3D(targetPose_CameraSpace); + } + public Pose3d getTargetPose_RobotSpace() + { + return toPose3D(targetPose_RobotSpace); + } + + public Pose2d getCameraPose_TargetSpace2D() + { + return toPose2D(cameraPose_TargetSpace); + } + public Pose2d getRobotPose_FieldSpace2D() + { + return toPose2D(robotPose_FieldSpace); + } + public Pose2d getRobotPose_TargetSpace2D() + { + return toPose2D(robotPose_TargetSpace); + } + public Pose2d getTargetPose_CameraSpace2D() + { + return toPose2D(targetPose_CameraSpace); + } + public Pose2d getTargetPose_RobotSpace2D() + { + return toPose2D(targetPose_RobotSpace); + } + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ts") + public double ts; + + public LimelightTarget_Fiducial() { + cameraPose_TargetSpace = new double[6]; + robotPose_FieldSpace = new double[6]; + robotPose_TargetSpace = new double[6]; + targetPose_CameraSpace = new double[6]; + targetPose_RobotSpace = new double[6]; + } + } + + /** + * Represents a Barcode Target Result extracted from JSON Output + */ + public static class LimelightTarget_Barcode { + + /** + * Barcode family type (e.g. "QR", "DataMatrix", etc.) + */ + @JsonProperty("fam") + public String family; + + /** + * Gets the decoded data content of the barcode + */ + @JsonProperty("data") + public String data; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ta") + public double ta; + + @JsonProperty("pts") + public double[][] corners; + + public LimelightTarget_Barcode() { + } + + public String getFamily() { + return family; + } + } + + /** + * Represents a Neural Classifier Pipeline Result extracted from JSON Output + */ + public static class LimelightTarget_Classifier { + + @JsonProperty("class") + public String className; + + @JsonProperty("classID") + public double classID; + + @JsonProperty("conf") + public double confidence; + + @JsonProperty("zone") + public double zone; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("typ") + public double ty_pixels; + + public LimelightTarget_Classifier() { + } + } + + /** + * Represents a Neural Detector Pipeline Result extracted from JSON Output + */ + public static class LimelightTarget_Detector { + + @JsonProperty("class") + public String className; + + @JsonProperty("classID") + public double classID; + + @JsonProperty("conf") + public double confidence; + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + public LimelightTarget_Detector() { + } + } + + /** + * Limelight Results object, parsed from a Limelight's JSON results output. + */ + public static class LimelightResults { + + public String error; + + @JsonProperty("pID") + public double pipelineID; + + @JsonProperty("tl") + public double latency_pipeline; + + @JsonProperty("cl") + public double latency_capture; + + public double latency_jsonParse; + + @JsonProperty("ts") + public double timestamp_LIMELIGHT_publish; + + @JsonProperty("ts_rio") + public double timestamp_RIOFPGA_capture; + + @JsonProperty("v") + @JsonFormat(shape = Shape.NUMBER) + public boolean valid; + + @JsonProperty("botpose") + public double[] botpose; + + @JsonProperty("botpose_wpired") + public double[] botpose_wpired; + + @JsonProperty("botpose_wpiblue") + public double[] botpose_wpiblue; + + @JsonProperty("botpose_tagcount") + public double botpose_tagcount; + + @JsonProperty("botpose_span") + public double botpose_span; + + @JsonProperty("botpose_avgdist") + public double botpose_avgdist; + + @JsonProperty("botpose_avgarea") + public double botpose_avgarea; + + @JsonProperty("t6c_rs") + public double[] camerapose_robotspace; + + public Pose3d getBotPose3d() { + return toPose3D(botpose); + } + + public Pose3d getBotPose3d_wpiRed() { + return toPose3D(botpose_wpired); + } + + public Pose3d getBotPose3d_wpiBlue() { + return toPose3D(botpose_wpiblue); + } + + public Pose2d getBotPose2d() { + return toPose2D(botpose); + } + + public Pose2d getBotPose2d_wpiRed() { + return toPose2D(botpose_wpired); + } + + public Pose2d getBotPose2d_wpiBlue() { + return toPose2D(botpose_wpiblue); + } + + @JsonProperty("Retro") + public LimelightTarget_Retro[] targets_Retro; + + @JsonProperty("Fiducial") + public LimelightTarget_Fiducial[] targets_Fiducials; + + @JsonProperty("Classifier") + public LimelightTarget_Classifier[] targets_Classifier; + + @JsonProperty("Detector") + public LimelightTarget_Detector[] targets_Detector; + + @JsonProperty("Barcode") + public LimelightTarget_Barcode[] targets_Barcode; + + public LimelightResults() { + botpose = new double[6]; + botpose_wpired = new double[6]; + botpose_wpiblue = new double[6]; + camerapose_robotspace = new double[6]; + targets_Retro = new LimelightTarget_Retro[0]; + targets_Fiducials = new LimelightTarget_Fiducial[0]; + targets_Classifier = new LimelightTarget_Classifier[0]; + targets_Detector = new LimelightTarget_Detector[0]; + targets_Barcode = new LimelightTarget_Barcode[0]; + + } + + + } + + /** + * Represents a Limelight Raw Fiducial result from Limelight's NetworkTables output. + */ + public static class RawFiducial { + public int id = 0; + public double txnc = 0; + public double tync = 0; + public double ta = 0; + public double distToCamera = 0; + public double distToRobot = 0; + public double ambiguity = 0; + + + public RawFiducial(int id, double txnc, double tync, double ta, double distToCamera, double distToRobot, double ambiguity) { + this.id = id; + this.txnc = txnc; + this.tync = tync; + this.ta = ta; + this.distToCamera = distToCamera; + this.distToRobot = distToRobot; + this.ambiguity = ambiguity; + } + } + + /** + * Represents a Limelight Raw Neural Detector result from Limelight's NetworkTables output. + */ + public static class RawDetection { + public int classId = 0; + public double txnc = 0; + public double tync = 0; + public double ta = 0; + public double corner0_X = 0; + public double corner0_Y = 0; + public double corner1_X = 0; + public double corner1_Y = 0; + public double corner2_X = 0; + public double corner2_Y = 0; + public double corner3_X = 0; + public double corner3_Y = 0; + + + public RawDetection(int classId, double txnc, double tync, double ta, + double corner0_X, double corner0_Y, + double corner1_X, double corner1_Y, + double corner2_X, double corner2_Y, + double corner3_X, double corner3_Y ) { + this.classId = classId; + this.txnc = txnc; + this.tync = tync; + this.ta = ta; + this.corner0_X = corner0_X; + this.corner0_Y = corner0_Y; + this.corner1_X = corner1_X; + this.corner1_Y = corner1_Y; + this.corner2_X = corner2_X; + this.corner2_Y = corner2_Y; + this.corner3_X = corner3_X; + this.corner3_Y = corner3_Y; + } + } + + /** + * Represents a 3D Pose Estimate. + */ + public static class PoseEstimate { + public Pose2d pose; + public double timestampSeconds; + public double latency; + public int tagCount; + public double tagSpan; + public double avgTagDist; + public double avgTagArea; + + public RawFiducial[] rawFiducials; + public boolean isMegaTag2; + + /** + * Instantiates a PoseEstimate object with default values + */ + public PoseEstimate() { + this.pose = new Pose2d(); + this.timestampSeconds = 0; + this.latency = 0; + this.tagCount = 0; + this.tagSpan = 0; + this.avgTagDist = 0; + this.avgTagArea = 0; + this.rawFiducials = new RawFiducial[]{}; + this.isMegaTag2 = false; + } + + public PoseEstimate(Pose2d pose, double timestampSeconds, double latency, + int tagCount, double tagSpan, double avgTagDist, + double avgTagArea, RawFiducial[] rawFiducials, boolean isMegaTag2) { + + this.pose = pose; + this.timestampSeconds = timestampSeconds; + this.latency = latency; + this.tagCount = tagCount; + this.tagSpan = tagSpan; + this.avgTagDist = avgTagDist; + this.avgTagArea = avgTagArea; + this.rawFiducials = rawFiducials; + this.isMegaTag2 = isMegaTag2; + } + + } + + /** + * Encapsulates the state of an internal Limelight IMU. + */ + public static class IMUData { + public double robotYaw = 0.0; + public double Roll = 0.0; + public double Pitch = 0.0; + public double Yaw = 0.0; + public double gyroX = 0.0; + public double gyroY = 0.0; + public double gyroZ = 0.0; + public double accelX = 0.0; + public double accelY = 0.0; + public double accelZ = 0.0; + + public IMUData() {} + + public IMUData(double[] imuData) { + if (imuData != null && imuData.length >= 10) { + this.robotYaw = imuData[0]; + this.Roll = imuData[1]; + this.Pitch = imuData[2]; + this.Yaw = imuData[3]; + this.gyroX = imuData[4]; + this.gyroY = imuData[5]; + this.gyroZ = imuData[6]; + this.accelX = imuData[7]; + this.accelY = imuData[8]; + this.accelZ = imuData[9]; + } + } + } + + + private static ObjectMapper mapper; + + /** + * Print JSON Parse time to the console in milliseconds + */ + static boolean profileJSON = false; + + static final String sanitizeName(String name) { + if (name == "" || name == null) { + return "limelight"; + } + return name; + } + + /** + * Takes a 6-length array of pose data and converts it to a Pose3d object. + * Array format: [x, y, z, roll, pitch, yaw] where angles are in degrees. + * @param inData Array containing pose data [x, y, z, roll, pitch, yaw] + * @return Pose3d object representing the pose, or empty Pose3d if invalid data + */ + public static Pose3d toPose3D(double[] inData){ + if(inData.length < 6) + { + //System.err.println("Bad LL 3D Pose Data!"); + return new Pose3d(); + } + return new Pose3d( + new Translation3d(inData[0], inData[1], inData[2]), + new Rotation3d(Units.degreesToRadians(inData[3]), Units.degreesToRadians(inData[4]), + Units.degreesToRadians(inData[5]))); + } + + /** + * Takes a 6-length array of pose data and converts it to a Pose2d object. + * Uses only x, y, and yaw components, ignoring z, roll, and pitch. + * Array format: [x, y, z, roll, pitch, yaw] where angles are in degrees. + * @param inData Array containing pose data [x, y, z, roll, pitch, yaw] + * @return Pose2d object representing the pose, or empty Pose2d if invalid data + */ + public static Pose2d toPose2D(double[] inData){ + if(inData.length < 6) + { + //System.err.println("Bad LL 2D Pose Data!"); + return new Pose2d(); + } + Translation2d tran2d = new Translation2d(inData[0], inData[1]); + Rotation2d r2d = new Rotation2d(Units.degreesToRadians(inData[5])); + return new Pose2d(tran2d, r2d); + } + + /** + * Converts a Pose3d object to an array of doubles in the format [x, y, z, roll, pitch, yaw]. + * Translation components are in meters, rotation components are in degrees. + * + * @param pose The Pose3d object to convert + * @return A 6-element array containing [x, y, z, roll, pitch, yaw] + */ + public static double[] pose3dToArray(Pose3d pose) { + double[] result = new double[6]; + result[0] = pose.getTranslation().getX(); + result[1] = pose.getTranslation().getY(); + result[2] = pose.getTranslation().getZ(); + result[3] = Units.radiansToDegrees(pose.getRotation().getX()); + result[4] = Units.radiansToDegrees(pose.getRotation().getY()); + result[5] = Units.radiansToDegrees(pose.getRotation().getZ()); + return result; + } + + /** + * Converts a Pose2d object to an array of doubles in the format [x, y, z, roll, pitch, yaw]. + * Translation components are in meters, rotation components are in degrees. + * Note: z, roll, and pitch will be 0 since Pose2d only contains x, y, and yaw. + * + * @param pose The Pose2d object to convert + * @return A 6-element array containing [x, y, 0, 0, 0, yaw] + */ + public static double[] pose2dToArray(Pose2d pose) { + double[] result = new double[6]; + result[0] = pose.getTranslation().getX(); + result[1] = pose.getTranslation().getY(); + result[2] = 0; + result[3] = Units.radiansToDegrees(0); + result[4] = Units.radiansToDegrees(0); + result[5] = Units.radiansToDegrees(pose.getRotation().getRadians()); + return result; + } + + private static double extractArrayEntry(double[] inData, int position){ + if(inData.length < position+1) + { + return 0; + } + return inData[position]; + } + + private static PoseEstimate getBotPoseEstimate(String limelightName, String entryName, boolean isMegaTag2) { + DoubleArrayEntry poseEntry = LimelightHelpers.getLimelightDoubleArrayEntry(limelightName, entryName); + + TimestampedDoubleArray tsValue = poseEntry.getAtomic(); + double[] poseArray = tsValue.value; + long timestamp = tsValue.timestamp; + + if (poseArray.length == 0) { + // Handle the case where no data is available + return null; // or some default PoseEstimate + } + + var pose = toPose2D(poseArray); + double latency = extractArrayEntry(poseArray, 6); + int tagCount = (int)extractArrayEntry(poseArray, 7); + double tagSpan = extractArrayEntry(poseArray, 8); + double tagDist = extractArrayEntry(poseArray, 9); + double tagArea = extractArrayEntry(poseArray, 10); + + // Convert server timestamp from microseconds to seconds and adjust for latency + double adjustedTimestamp = (timestamp / 1000000.0) - (latency / 1000.0); + + RawFiducial[] rawFiducials = new RawFiducial[tagCount]; + int valsPerFiducial = 7; + int expectedTotalVals = 11 + valsPerFiducial * tagCount; + + if (poseArray.length != expectedTotalVals) { + // Don't populate fiducials + } else { + for(int i = 0; i < tagCount; i++) { + int baseIndex = 11 + (i * valsPerFiducial); + int id = (int)poseArray[baseIndex]; + double txnc = poseArray[baseIndex + 1]; + double tync = poseArray[baseIndex + 2]; + double ta = poseArray[baseIndex + 3]; + double distToCamera = poseArray[baseIndex + 4]; + double distToRobot = poseArray[baseIndex + 5]; + double ambiguity = poseArray[baseIndex + 6]; + rawFiducials[i] = new RawFiducial(id, txnc, tync, ta, distToCamera, distToRobot, ambiguity); + } + } + + return new PoseEstimate(pose, adjustedTimestamp, latency, tagCount, tagSpan, tagDist, tagArea, rawFiducials, isMegaTag2); + } + + /** + * Gets the latest raw fiducial/AprilTag detection results from NetworkTables. + * + * @param limelightName Name/identifier of the Limelight + * @return Array of RawFiducial objects containing detection details + */ + public static RawFiducial[] getRawFiducials(String limelightName) { + var entry = LimelightHelpers.getLimelightNTTableEntry(limelightName, "rawfiducials"); + var rawFiducialArray = entry.getDoubleArray(new double[0]); + int valsPerEntry = 7; + if (rawFiducialArray.length % valsPerEntry != 0) { + return new RawFiducial[0]; + } + + int numFiducials = rawFiducialArray.length / valsPerEntry; + RawFiducial[] rawFiducials = new RawFiducial[numFiducials]; + + for (int i = 0; i < numFiducials; i++) { + int baseIndex = i * valsPerEntry; + int id = (int) extractArrayEntry(rawFiducialArray, baseIndex); + double txnc = extractArrayEntry(rawFiducialArray, baseIndex + 1); + double tync = extractArrayEntry(rawFiducialArray, baseIndex + 2); + double ta = extractArrayEntry(rawFiducialArray, baseIndex + 3); + double distToCamera = extractArrayEntry(rawFiducialArray, baseIndex + 4); + double distToRobot = extractArrayEntry(rawFiducialArray, baseIndex + 5); + double ambiguity = extractArrayEntry(rawFiducialArray, baseIndex + 6); + + rawFiducials[i] = new RawFiducial(id, txnc, tync, ta, distToCamera, distToRobot, ambiguity); + } + + return rawFiducials; + } + + /** + * Gets the latest raw neural detector results from NetworkTables + * + * @param limelightName Name/identifier of the Limelight + * @return Array of RawDetection objects containing detection details + */ + public static RawDetection[] getRawDetections(String limelightName) { + var entry = LimelightHelpers.getLimelightNTTableEntry(limelightName, "rawdetections"); + var rawDetectionArray = entry.getDoubleArray(new double[0]); + int valsPerEntry = 12; + if (rawDetectionArray.length % valsPerEntry != 0) { + return new RawDetection[0]; + } + + int numDetections = rawDetectionArray.length / valsPerEntry; + RawDetection[] rawDetections = new RawDetection[numDetections]; + + for (int i = 0; i < numDetections; i++) { + int baseIndex = i * valsPerEntry; // Starting index for this detection's data + int classId = (int) extractArrayEntry(rawDetectionArray, baseIndex); + double txnc = extractArrayEntry(rawDetectionArray, baseIndex + 1); + double tync = extractArrayEntry(rawDetectionArray, baseIndex + 2); + double ta = extractArrayEntry(rawDetectionArray, baseIndex + 3); + double corner0_X = extractArrayEntry(rawDetectionArray, baseIndex + 4); + double corner0_Y = extractArrayEntry(rawDetectionArray, baseIndex + 5); + double corner1_X = extractArrayEntry(rawDetectionArray, baseIndex + 6); + double corner1_Y = extractArrayEntry(rawDetectionArray, baseIndex + 7); + double corner2_X = extractArrayEntry(rawDetectionArray, baseIndex + 8); + double corner2_Y = extractArrayEntry(rawDetectionArray, baseIndex + 9); + double corner3_X = extractArrayEntry(rawDetectionArray, baseIndex + 10); + double corner3_Y = extractArrayEntry(rawDetectionArray, baseIndex + 11); + + rawDetections[i] = new RawDetection(classId, txnc, tync, ta, corner0_X, corner0_Y, corner1_X, corner1_Y, corner2_X, corner2_Y, corner3_X, corner3_Y); + } + + return rawDetections; + } + + /** + * Prints detailed information about a PoseEstimate to standard output. + * Includes timestamp, latency, tag count, tag span, average tag distance, + * average tag area, and detailed information about each detected fiducial. + * + * @param pose The PoseEstimate object to print. If null, prints "No PoseEstimate available." + */ + public static void printPoseEstimate(PoseEstimate pose) { + if (pose == null) { + System.out.println("No PoseEstimate available."); + return; + } + + System.out.printf("Pose Estimate Information:%n"); + System.out.printf("Timestamp (Seconds): %.3f%n", pose.timestampSeconds); + System.out.printf("Latency: %.3f ms%n", pose.latency); + System.out.printf("Tag Count: %d%n", pose.tagCount); + System.out.printf("Tag Span: %.2f meters%n", pose.tagSpan); + System.out.printf("Average Tag Distance: %.2f meters%n", pose.avgTagDist); + System.out.printf("Average Tag Area: %.2f%% of image%n", pose.avgTagArea); + System.out.printf("Is MegaTag2: %b%n", pose.isMegaTag2); + System.out.println(); + + if (pose.rawFiducials == null || pose.rawFiducials.length == 0) { + System.out.println("No RawFiducials data available."); + return; + } + + System.out.println("Raw Fiducials Details:"); + for (int i = 0; i < pose.rawFiducials.length; i++) { + RawFiducial fiducial = pose.rawFiducials[i]; + System.out.printf(" Fiducial #%d:%n", i + 1); + System.out.printf(" ID: %d%n", fiducial.id); + System.out.printf(" TXNC: %.2f%n", fiducial.txnc); + System.out.printf(" TYNC: %.2f%n", fiducial.tync); + System.out.printf(" TA: %.2f%n", fiducial.ta); + System.out.printf(" Distance to Camera: %.2f meters%n", fiducial.distToCamera); + System.out.printf(" Distance to Robot: %.2f meters%n", fiducial.distToRobot); + System.out.printf(" Ambiguity: %.2f%n", fiducial.ambiguity); + System.out.println(); + } + } + + public static Boolean validPoseEstimate(PoseEstimate pose) { + return pose != null && pose.rawFiducials != null && pose.rawFiducials.length != 0; + } + + public static NetworkTable getLimelightNTTable(String tableName) { + return NetworkTableInstance.getDefault().getTable(sanitizeName(tableName)); + } + + public static void Flush() { + NetworkTableInstance.getDefault().flush(); + } + + public static NetworkTableEntry getLimelightNTTableEntry(String tableName, String entryName) { + return getLimelightNTTable(tableName).getEntry(entryName); + } + + public static DoubleArrayEntry getLimelightDoubleArrayEntry(String tableName, String entryName) { + String key = tableName + "/" + entryName; + return doubleArrayEntries.computeIfAbsent(key, k -> { + NetworkTable table = getLimelightNTTable(tableName); + return table.getDoubleArrayTopic(entryName).getEntry(new double[0]); + }); + } + + public static double getLimelightNTDouble(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getDouble(0.0); + } + + public static void setLimelightNTDouble(String tableName, String entryName, double val) { + getLimelightNTTableEntry(tableName, entryName).setDouble(val); + } + + public static void setLimelightNTDoubleArray(String tableName, String entryName, double[] val) { + getLimelightNTTableEntry(tableName, entryName).setDoubleArray(val); + } + + public static double[] getLimelightNTDoubleArray(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getDoubleArray(new double[0]); + } + + + public static String getLimelightNTString(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getString(""); + } + + public static String[] getLimelightNTStringArray(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getStringArray(new String[0]); + } + + + public static URL getLimelightURLString(String tableName, String request) { + String urlString = "http://" + sanitizeName(tableName) + ".local:5807/" + request; + URL url; + try { + url = new URL(urlString); + return url; + } catch (MalformedURLException e) { + System.err.println("bad LL URL"); + } + return null; + } + ///// + ///// + + /** + * Does the Limelight have a valid target? + * @param limelightName Name of the Limelight camera ("" for default) + * @return True if a valid target is present, false otherwise + */ + public static boolean getTV(String limelightName) { + return 1.0 == getLimelightNTDouble(limelightName, "tv"); + } + + /** + * Gets the horizontal offset from the crosshair to the target in degrees. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Horizontal offset angle in degrees + */ + public static double getTX(String limelightName) { + return getLimelightNTDouble(limelightName, "tx"); + } + + /** + * Gets the vertical offset from the crosshair to the target in degrees. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Vertical offset angle in degrees + */ + public static double getTY(String limelightName) { + return getLimelightNTDouble(limelightName, "ty"); + } + + /** + * Gets the horizontal offset from the principal pixel/point to the target in degrees. This is the most accurate 2d metric if you are using a calibrated camera and you don't need adjustable crosshair functionality. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Horizontal offset angle in degrees + */ + public static double getTXNC(String limelightName) { + return getLimelightNTDouble(limelightName, "txnc"); + } + + /** + * Gets the vertical offset from the principal pixel/point to the target in degrees. This is the most accurate 2d metric if you are using a calibrated camera and you don't need adjustable crosshair functionality. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Vertical offset angle in degrees + */ + public static double getTYNC(String limelightName) { + return getLimelightNTDouble(limelightName, "tync"); + } + + /** + * Gets the target area as a percentage of the image (0-100%). + * @param limelightName Name of the Limelight camera ("" for default) + * @return Target area percentage (0-100) + */ + public static double getTA(String limelightName) { + return getLimelightNTDouble(limelightName, "ta"); + } + + /** + * T2D is an array that contains several targeting metrcis + * @param limelightName Name of the Limelight camera + * @return Array containing [targetValid, targetCount, targetLatency, captureLatency, tx, ty, txnc, tync, ta, tid, targetClassIndexDetector, + * targetClassIndexClassifier, targetLongSidePixels, targetShortSidePixels, targetHorizontalExtentPixels, targetVerticalExtentPixels, targetSkewDegrees] + */ + public static double[] getT2DArray(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "t2d"); + } + + /** + * Gets the number of targets currently detected. + * @param limelightName Name of the Limelight camera + * @return Number of detected targets + */ + public static int getTargetCount(String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[1]; + } + return 0; + } + + /** + * Gets the classifier class index from the currently running neural classifier pipeline + * @param limelightName Name of the Limelight camera + * @return Class index from classifier pipeline + */ + public static int getClassifierClassIndex (String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[10]; + } + return 0; + } + + /** + * Gets the detector class index from the primary result of the currently running neural detector pipeline. + * @param limelightName Name of the Limelight camera + * @return Class index from detector pipeline + */ + public static int getDetectorClassIndex (String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[11]; + } + return 0; + } + + /** + * Gets the current neural classifier result class name. + * @param limelightName Name of the Limelight camera + * @return Class name string from classifier pipeline + */ + public static String getClassifierClass (String limelightName) { + return getLimelightNTString(limelightName, "tcclass"); + } + + /** + * Gets the primary neural detector result class name. + * @param limelightName Name of the Limelight camera + * @return Class name string from detector pipeline + */ + public static String getDetectorClass (String limelightName) { + return getLimelightNTString(limelightName, "tdclass"); + } + + /** + * Gets the pipeline's processing latency contribution. + * @param limelightName Name of the Limelight camera + * @return Pipeline latency in milliseconds + */ + public static double getLatency_Pipeline(String limelightName) { + return getLimelightNTDouble(limelightName, "tl"); + } + + /** + * Gets the capture latency. + * @param limelightName Name of the Limelight camera + * @return Capture latency in milliseconds + */ + public static double getLatency_Capture(String limelightName) { + return getLimelightNTDouble(limelightName, "cl"); + } + + /** + * Gets the active pipeline index. + * @param limelightName Name of the Limelight camera + * @return Current pipeline index (0-9) + */ + public static double getCurrentPipelineIndex(String limelightName) { + return getLimelightNTDouble(limelightName, "getpipe"); + } + + /** + * Gets the current pipeline type. + * @param limelightName Name of the Limelight camera + * @return Pipeline type string (e.g. "retro", "apriltag", etc) + */ + public static String getCurrentPipelineType(String limelightName) { + return getLimelightNTString(limelightName, "getpipetype"); + } + + /** + * Gets the full JSON results dump. + * @param limelightName Name of the Limelight camera + * @return JSON string containing all current results + */ + public static String getJSONDump(String limelightName) { + return getLimelightNTString(limelightName, "json"); + } + + /** + * Switch to getBotPose + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose"); + } + + /** + * Switch to getBotPose_wpiRed + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose_wpiRed(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + } + + /** + * Switch to getBotPose_wpiBlue + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose_wpiBlue(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + } + + public static double[] getBotPose(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose"); + } + + public static double[] getBotPose_wpiRed(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + } + + public static double[] getBotPose_wpiBlue(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + } + + public static double[] getBotPose_TargetSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_targetspace"); + } + + public static double[] getCameraPose_TargetSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "camerapose_targetspace"); + } + + public static double[] getTargetPose_CameraSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "targetpose_cameraspace"); + } + + public static double[] getTargetPose_RobotSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "targetpose_robotspace"); + } + + public static double[] getTargetColor(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "tc"); + } + + public static double getFiducialID(String limelightName) { + return getLimelightNTDouble(limelightName, "tid"); + } + + public static String getNeuralClassID(String limelightName) { + return getLimelightNTString(limelightName, "tclass"); + } + + public static String[] getRawBarcodeData(String limelightName) { + return getLimelightNTStringArray(limelightName, "rawbarcodes"); + } + + ///// + ///// + + public static Pose3d getBotPose3d(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose"); + return toPose3D(poseArray); + } + + /** + * (Not Recommended) Gets the robot's 3D pose in the WPILib Red Alliance Coordinate System. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation in Red Alliance field space + */ + public static Pose3d getBotPose3d_wpiRed(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + return toPose3D(poseArray); + } + + /** + * (Recommended) Gets the robot's 3D pose in the WPILib Blue Alliance Coordinate System. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation in Blue Alliance field space + */ + public static Pose3d getBotPose3d_wpiBlue(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + return toPose3D(poseArray); + } + + /** + * Gets the robot's 3D pose with respect to the currently tracked target's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation relative to the target + */ + public static Pose3d getBotPose3d_TargetSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_targetspace"); + return toPose3D(poseArray); + } + + /** + * Gets the camera's 3D pose with respect to the currently tracked target's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the camera's position and orientation relative to the target + */ + public static Pose3d getCameraPose3d_TargetSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "camerapose_targetspace"); + return toPose3D(poseArray); + } + + /** + * Gets the target's 3D pose with respect to the camera's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the target's position and orientation relative to the camera + */ + public static Pose3d getTargetPose3d_CameraSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "targetpose_cameraspace"); + return toPose3D(poseArray); + } + + /** + * Gets the target's 3D pose with respect to the robot's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the target's position and orientation relative to the robot + */ + public static Pose3d getTargetPose3d_RobotSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "targetpose_robotspace"); + return toPose3D(poseArray); + } + + /** + * Gets the camera's 3D pose with respect to the robot's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the camera's position and orientation relative to the robot + */ + public static Pose3d getCameraPose3d_RobotSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "camerapose_robotspace"); + return toPose3D(poseArray); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d_wpiBlue(String limelightName) { + + double[] result = getBotPose_wpiBlue(limelightName); + return toPose2D(result); + } + + /** + * Gets the MegaTag1 Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) in the WPILib Blue alliance coordinate system. + * + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiBlue(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_wpiblue", false); + } + + /** + * Gets the MegaTag2 Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) in the WPILib Blue alliance coordinate system. + * Make sure you are calling setRobotOrientation() before calling this method. + * + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiBlue_MegaTag2(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_orb_wpiblue", true); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d_wpiRed(String limelightName) { + + double[] result = getBotPose_wpiRed(limelightName); + return toPose2D(result); + + } + + /** + * Gets the Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) when you are on the RED + * alliance + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiRed(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_wpired", false); + } + + /** + * Gets the Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) when you are on the RED + * alliance + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiRed_MegaTag2(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_orb_wpired", true); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d(String limelightName) { + + double[] result = getBotPose(limelightName); + return toPose2D(result); + + } + + /** + * Gets the current IMU data from NetworkTables. + * IMU data is formatted as [robotYaw, Roll, Pitch, Yaw, gyroX, gyroY, gyroZ, accelX, accelY, accelZ]. + * Returns all zeros if data is invalid or unavailable. + * + * @param limelightName Name/identifier of the Limelight + * @return IMUData object containing all current IMU data + */ + public static IMUData getIMUData(String limelightName) { + double[] imuData = getLimelightNTDoubleArray(limelightName, "imu"); + if (imuData == null || imuData.length < 10) { + return new IMUData(); // Returns object with all zeros + } + return new IMUData(imuData); + } + + ///// + ///// + + public static void setPipelineIndex(String limelightName, int pipelineIndex) { + setLimelightNTDouble(limelightName, "pipeline", pipelineIndex); + } + + + public static void setPriorityTagID(String limelightName, int ID) { + setLimelightNTDouble(limelightName, "priorityid", ID); + } + + /** + * Sets LED mode to be controlled by the current pipeline. + * @param limelightName Name of the Limelight camera + */ + public static void setLEDMode_PipelineControl(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 0); + } + + public static void setLEDMode_ForceOff(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 1); + } + + public static void setLEDMode_ForceBlink(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 2); + } + + public static void setLEDMode_ForceOn(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 3); + } + + /** + * Enables standard side-by-side stream mode. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_Standard(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 0); + } + + /** + * Enables Picture-in-Picture mode with secondary stream in the corner. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_PiPMain(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 1); + } + + /** + * Enables Picture-in-Picture mode with primary stream in the corner. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_PiPSecondary(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 2); + } + + + /** + * Sets the crop window for the camera. The crop window in the UI must be completely open. + * @param limelightName Name of the Limelight camera + * @param cropXMin Minimum X value (-1 to 1) + * @param cropXMax Maximum X value (-1 to 1) + * @param cropYMin Minimum Y value (-1 to 1) + * @param cropYMax Maximum Y value (-1 to 1) + */ + public static void setCropWindow(String limelightName, double cropXMin, double cropXMax, double cropYMin, double cropYMax) { + double[] entries = new double[4]; + entries[0] = cropXMin; + entries[1] = cropXMax; + entries[2] = cropYMin; + entries[3] = cropYMax; + setLimelightNTDoubleArray(limelightName, "crop", entries); + } + + /** + * Sets 3D offset point for easy 3D targeting. + */ + public static void setFiducial3DOffset(String limelightName, double offsetX, double offsetY, double offsetZ) { + double[] entries = new double[3]; + entries[0] = offsetX; + entries[1] = offsetY; + entries[2] = offsetZ; + setLimelightNTDoubleArray(limelightName, "fiducial_offset_set", entries); + } + + /** + * Sets robot orientation values used by MegaTag2 localization algorithm. + * + * @param limelightName Name/identifier of the Limelight + * @param yaw Robot yaw in degrees. 0 = robot facing red alliance wall in FRC + * @param yawRate (Unnecessary) Angular velocity of robot yaw in degrees per second + * @param pitch (Unnecessary) Robot pitch in degrees + * @param pitchRate (Unnecessary) Angular velocity of robot pitch in degrees per second + * @param roll (Unnecessary) Robot roll in degrees + * @param rollRate (Unnecessary) Angular velocity of robot roll in degrees per second + */ + public static void SetRobotOrientation(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate) { + SetRobotOrientation_INTERNAL(limelightName, yaw, yawRate, pitch, pitchRate, roll, rollRate, true); + } + + public static void SetRobotOrientation_NoFlush(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate) { + SetRobotOrientation_INTERNAL(limelightName, yaw, yawRate, pitch, pitchRate, roll, rollRate, false); + } + + private static void SetRobotOrientation_INTERNAL(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate, boolean flush) { + + double[] entries = new double[6]; + entries[0] = yaw; + entries[1] = yawRate; + entries[2] = pitch; + entries[3] = pitchRate; + entries[4] = roll; + entries[5] = rollRate; + setLimelightNTDoubleArray(limelightName, "robot_orientation_set", entries); + if(flush) + { + Flush(); + } + } + + /** + * Configures the IMU mode for MegaTag2 Localization + * + * @param limelightName Name/identifier of the Limelight + * @param mode IMU mode. + */ + public static void SetIMUMode(String limelightName, int mode) { + setLimelightNTDouble(limelightName, "imumode_set", mode); + } + + /** + * Sets the 3D point-of-interest offset for the current fiducial pipeline. + * https://docs.limelightvision.io/docs/docs-limelight/pipeline-apriltag/apriltag-3d#point-of-interest-tracking + * + * @param limelightName Name/identifier of the Limelight + * @param x X offset in meters + * @param y Y offset in meters + * @param z Z offset in meters + */ + public static void SetFidcuial3DOffset(String limelightName, double x, double y, + double z) { + + double[] entries = new double[3]; + entries[0] = x; + entries[1] = y; + entries[2] = z; + setLimelightNTDoubleArray(limelightName, "fiducial_offset_set", entries); + } + + /** + * Overrides the valid AprilTag IDs that will be used for localization. + * Tags not in this list will be ignored for robot pose estimation. + * + * @param limelightName Name/identifier of the Limelight + * @param validIDs Array of valid AprilTag IDs to track + */ + public static void SetFiducialIDFiltersOverride(String limelightName, int[] validIDs) { + double[] validIDsDouble = new double[validIDs.length]; + for (int i = 0; i < validIDs.length; i++) { + validIDsDouble[i] = validIDs[i]; + } + setLimelightNTDoubleArray(limelightName, "fiducial_id_filters_set", validIDsDouble); + } + + /** + * Sets the downscaling factor for AprilTag detection. + * Increasing downscale can improve performance at the cost of potentially reduced detection range. + * + * @param limelightName Name/identifier of the Limelight + * @param downscale Downscale factor. Valid values: 1.0 (no downscale), 1.5, 2.0, 3.0, 4.0. Set to 0 for pipeline control. + */ + public static void SetFiducialDownscalingOverride(String limelightName, float downscale) + { + int d = 0; // pipeline + if (downscale == 1.0) + { + d = 1; + } + if (downscale == 1.5) + { + d = 2; + } + if (downscale == 2) + { + d = 3; + } + if (downscale == 3) + { + d = 4; + } + if (downscale == 4) + { + d = 5; + } + setLimelightNTDouble(limelightName, "fiducial_downscale_set", d); + } + + /** + * Sets the camera pose relative to the robot. + * @param limelightName Name of the Limelight camera + * @param forward Forward offset in meters + * @param side Side offset in meters + * @param up Up offset in meters + * @param roll Roll angle in degrees + * @param pitch Pitch angle in degrees + * @param yaw Yaw angle in degrees + */ + public static void setCameraPose_RobotSpace(String limelightName, double forward, double side, double up, double roll, double pitch, double yaw) { + double[] entries = new double[6]; + entries[0] = forward; + entries[1] = side; + entries[2] = up; + entries[3] = roll; + entries[4] = pitch; + entries[5] = yaw; + setLimelightNTDoubleArray(limelightName, "camerapose_robotspace_set", entries); + } + + ///// + ///// + + public static void setPythonScriptData(String limelightName, double[] outgoingPythonData) { + setLimelightNTDoubleArray(limelightName, "llrobot", outgoingPythonData); + } + + public static double[] getPythonScriptData(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "llpython"); + } + + ///// + ///// + + /** + * Asynchronously take snapshot. + */ + public static CompletableFuture takeSnapshot(String tableName, String snapshotName) { + return CompletableFuture.supplyAsync(() -> { + return SYNCH_TAKESNAPSHOT(tableName, snapshotName); + }); + } + + private static boolean SYNCH_TAKESNAPSHOT(String tableName, String snapshotName) { + URL url = getLimelightURLString(tableName, "capturesnapshot"); + try { + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + if (snapshotName != null && snapshotName != "") { + connection.setRequestProperty("snapname", snapshotName); + } + + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + return true; + } else { + System.err.println("Bad LL Request"); + } + } catch (IOException e) { + System.err.println(e.getMessage()); + } + return false; + } + + /** + * Gets the latest JSON results output and returns a LimelightResults object. + * @param limelightName Name of the Limelight camera + * @return LimelightResults object containing all current target data + */ + public static LimelightResults getLatestResults(String limelightName) { + + long start = System.nanoTime(); + LimelightHelpers.LimelightResults results = new LimelightHelpers.LimelightResults(); + if (mapper == null) { + mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + try { + results = mapper.readValue(getJSONDump(limelightName), LimelightResults.class); + } catch (JsonProcessingException e) { + results.error = "lljson error: " + e.getMessage(); + } + + long end = System.nanoTime(); + double millis = (end - start) * .000001; + results.latency_jsonParse = millis; + if (profileJSON) { + System.out.printf("lljson: %.2f\r\n", millis); + } + + return results; + } +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Main.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..687a0a0 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Robot.java @@ -0,0 +1,103 @@ +// 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; + +/** + * The VM is configured to automatically run this class, and to call the functions corresponding to + * each mode, as described in the TimedRobot documentation. If you change the name of this class or + * the package after creating this project, you must also update the build.gradle file in the + * project. + */ +public class Robot extends TimedRobot { + private Command m_autonomousCommand; + + private RobotContainer m_robotContainer; + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + @Override + public void robotInit() { + // Instantiate our RobotContainer. This will perform all our button bindings, and put our + // autonomous chooser on the dashboard. + m_robotContainer = new RobotContainer(); + } + + /** + * This function is called every 20 ms, no matter the mode. Use this for items like diagnostics + * that you want ran during disabled, autonomous, teleoperated and test. + * + *

This runs after the mode specific periodic functions, but before LiveWindow and + * SmartDashboard integrated updating. + */ + @Override + public void robotPeriodic() { + // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled + // commands, running already-scheduled commands, removing finished or interrupted commands, + // and running subsystem periodic() methods. This must be called from the robot's periodic + // block in order for anything in the Command-based framework to work. + CommandScheduler.getInstance().run(); + } + + /** This function is called once each time the robot enters Disabled mode. */ + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ + @Override + public void autonomousInit() { + m_autonomousCommand = m_robotContainer.getAutonomousCommand(); + + // schedule the autonomous command (example) + if (m_autonomousCommand != null) { + m_autonomousCommand.schedule(); + } + } + + /** This function is called periodically during autonomous. */ + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() { + // This makes sure that the autonomous stops running when + // teleop starts running. If you want the autonomous to + // continue until interrupted by another command, remove + // this line or comment it out. + if (m_autonomousCommand != null) { + m_autonomousCommand.cancel(); + } + } + + /** This function is called periodically during operator control. */ + @Override + public void teleopPeriodic() {} + + @Override + public void testInit() { + // Cancels all running commands at the start of test mode. + CommandScheduler.getInstance().cancelAll(); + } + + /** This function is called periodically during test mode. */ + @Override + public void testPeriodic() {} + + /** This function is called once when the robot is first started up. */ + @Override + public void simulationInit() {} + + /** This function is called periodically whilst in simulation. */ + @Override + public void simulationPeriodic() {} +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/RobotContainer.java new file mode 100644 index 0000000..7f035cd --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/RobotContainer.java @@ -0,0 +1,156 @@ +// 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 java.util.ArrayList; +import java.util.Optional; + +import com.ctre.phoenix6.hardware.TalonFX; +import com.pathplanner.lib.auto.AutoBuilder; +import com.studica.frc.AHRS; +import com.studica.frc.AHRS.NavXComType; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +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.button.CommandXboxController; +import edu.wpi.first.wpilibj2.command.button.Trigger; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.factorys.DriveSubsystemFactory; +import frc.robot.factorys.TalonFXFactory; +import frc.robot.subsystems.DriveSubsystem; +import frc.robot.utils.AutoCommands; + +/** + * This class is where the bulk of the robot should be declared. Since Command-based is a + * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot} + * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including + * subsystems, commands, and trigger mappings) should be declared here. + */ +public class RobotContainer { + // The robot's subsystems and commands are defined here... + private final Optional m_driveSubsystem; + + // Replace with CommandPS4Controller or CommandJoystick if needed + //private final CommandXboxController m_driverController = + // new CommandXboxController(OperatorConstants.kDriverControllerPort); + + private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); + private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.trackWidthMeters); + + // Pose Estimators + private DifferentialDrivePoseEstimator m_DrivePoseEstimator = new DifferentialDrivePoseEstimator( + m_DriveKinematics, + m_gyro.getRotation2d(), + 0, + 0, + new Pose2d()); + + // Sendable Choosers + private SendableChooser autoChooser; + + // Factorys + private TalonFXFactory m_TalonFXFactory = new TalonFXFactory(); + private DriveSubsystemFactory m_DriveSubsystemFactory = new DriveSubsystemFactory(); + + /** The container for the robot. Contains subsystems, OI devices, and commands. */ + public RobotContainer() { + // Init DriveSubsystem + Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); + Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); + Optional rightFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalRightMotorCANID); + Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); + m_driveSubsystem = m_DriveSubsystemFactory.construct(m_DrivePoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); + + // Init the subsystems + //m_limelightSubsystem = getSubsystem(LimelightSubsystem.class, m_limeLightPoseEstimator); + //m_exampleSubsystem = getSubsystem(ExampleSubsystem.class); + + // Init Auto + configureAutos(); + + // Configure the default commands + configureDefaultCommands(); + + // Configure the trigger bindings + configureBindings(); + } + + // Tom wrote this cool template to make the optional subsystem creation code in + // the constructor above a lot clearer. This is what clever coding looks like. + // Owen: I added the ability to pass object args through this for dependency injection, + // I hope this does not break anything or commited a coding sin or somthing + // private static Optional getSubsystem(Class subsystemClass, Object... args) { + // Optional iss; + // try { + + // iss = Optional.ofNullable(subsystemClass.getDeclaredConstructor().newInstance(args)); + // } catch (Exception e) { + // iss = Optional.empty(); + // // This is not tested! - Owen + // DriverStation.reportWarning( + // String.format( + // "The %s was not found!", subsystemClass.getName()), + // false + // ); + // } + // return iss; + // } + + private void configureAutos() { + // Init Autos (/home/lvuser/deploy/pathplanner/autos) + ArrayList autoCommands = AutoCommands.getAutoCommands(m_driveSubsystem); + + // Init Chooser + autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string + SmartDashboard.putData("Auto Chooser", autoChooser); + } + + private void configureDefaultCommands() { + if (m_driveSubsystem.isPresent()) + { + //DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + //driveSubsystem.initDefaultCommand(m_driverController); + } + } + + /** + * Use this method to define your trigger->command mappings. Triggers can be created via the + * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary + * predicate, or via the named factories in {@link + * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link + * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller + * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight + * joysticks}. + */ + private void configureBindings() { + // SmartDashboard.putBoolean("Example Subsystem", m_exampleSubsystem.isPresent()); + + // if (m_exampleSubsystem.isPresent()) + // { + // ExampleSubsystem exampleSubsystem = m_exampleSubsystem.get(); + + // // Schedule `ExampleCommand` when `exampleCondition` changes to `true` + // new Trigger(exampleSubsystem::exampleCondition) + // .onTrue(new ExampleCommand(exampleSubsystem)); + + // // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed, + // // cancelling on release. + // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); + // } + } + + /** + * Use this to pass the autonomous command to the main {@link Robot} class. + * + * @return the command to run in autonomous + */ + public Command getAutonomousCommand() { + return autoChooser.getSelected(); + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ArcadeDriveCommand.java new file mode 100644 index 0000000..a641317 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -0,0 +1,53 @@ +// 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.commands; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; + +/** An example command that uses an example subsystem. */ +public class ArcadeDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + m_subsystem.setDifferentialSpeeds( + -m_driveController.getRightY(), + -m_driveController.getLeftX() + ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/Autos.java new file mode 100644 index 0000000..107aad7 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/Autos.java @@ -0,0 +1,20 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.Commands; + +public final class Autos { + /** Example static factory for an autonomous command. */ + public static Command exampleAuto(ExampleSubsystem subsystem) { + return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); + } + + private Autos() { + throw new UnsupportedOperationException("This is a utility class!"); + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/DifferentialDriveCommand.java new file mode 100644 index 0000000..27f220a --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -0,0 +1,57 @@ +// 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.commands; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.Constants; + +/** An example command that uses an example subsystem. */ +public class DifferentialDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public DifferentialDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + double leftSpeed = -m_driveController.getLeftY(); + double rightSpeed = -m_driveController.getRightY(); + + leftSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + rightSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + + m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ExampleCommand.java new file mode 100644 index 0000000..151624c --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ExampleCommand.java @@ -0,0 +1,43 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; + +/** An example command that uses an example subsystem. */ +public class ExampleCommand extends Command { + @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField", "unused"}) + private final ExampleSubsystem m_subsystem; + + /** + * Creates a new ExampleCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ExampleCommand(ExampleSubsystem subsystem) { + m_subsystem = subsystem; + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java new file mode 100644 index 0000000..afc5b84 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -0,0 +1,33 @@ +package frc.robot.factorys; + +import java.util.Optional; +import com.ctre.phoenix6.hardware.TalonFX; +import com.studica.frc.AHRS; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import frc.robot.subsystems.DriveSubsystem; + +public class DriveSubsystemFactory { + public DriveSubsystemFactory() { + } + + public Optional construct(DifferentialDrivePoseEstimator poseEstimator, + DifferentialDriveKinematics kinematics, + AHRS gyro, Optional rightLead, Optional leftLead, Optional rightFollower, + Optional leftFollower) { + + if (rightLead.isEmpty() || leftLead.isEmpty()) { + return Optional.empty(); + } + + DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, gyro, rightLead.get(), + leftLead.get()); + + if (rightFollower.isPresent() && leftFollower.isPresent()) { + driveSubsystem.setFollowers(rightFollower.get(), leftFollower.get()); + } + + return Optional.of(driveSubsystem); + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/TalonFXFactory.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/TalonFXFactory.java new file mode 100644 index 0000000..1a84899 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/TalonFXFactory.java @@ -0,0 +1,20 @@ +package frc.robot.factorys; + +import java.util.Optional; + +import com.ctre.phoenix6.hardware.TalonFX; + +public class TalonFXFactory { + public TalonFXFactory() {} + + public Optional construct(int CANID) { + Optional newMotor; + try { + newMotor = Optional.of(new TalonFX(CANID)); + } catch (Exception e) { + newMotor = Optional.empty(); + } + + return newMotor; + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/DriveSubsystem.java new file mode 100644 index 0000000..6782406 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -0,0 +1,285 @@ +// 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. + +// https://github.com/CrossTheRoadElec/Phoenix6-Examples/blob/main/java/VelocityClosedLoop/src/main/java/frc/robot/Robot.java +// This is a link to do speed control on the kraken motors. We need something like this. +package frc.robot.subsystems; +import static edu.wpi.first.units.Units.Volts; + +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.Follower; +import com.ctre.phoenix6.controls.VelocityVoltage; +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.signals.InvertedValue; +import com.ctre.phoenix6.signals.NeutralModeValue; +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.controllers.PPLTVController; +import com.studica.frc.AHRS; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.kinematics.ChassisSpeeds; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds; +import edu.wpi.first.util.sendable.SendableRegistry; +import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj.drive.DifferentialDrive; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.Constants.AutoConstants; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.commands.DifferentialDriveCommand; +//import frc.robot.utils.PIDControl; + +public class DriveSubsystem extends SubsystemBase { + private TalonFX m_rightMotor; + private TalonFX m_optionalRightMotor; + + private TalonFX m_leftMotor; + private TalonFX m_optionalLeftMotor; + + /* Start at velocity 0, use slot 0 */ + private final VelocityVoltage m_leftVelocityVoltage = new VelocityVoltage(0).withSlot(0); + private final VelocityVoltage m_rightVelocityVoltage = new VelocityVoltage(0).withSlot(0); + + private DifferentialDrive m_Drivetrain; + + private double m_leftSpeed = 0.0; + private double m_rightSpeed = 0.0; + + private final DifferentialDriveKinematics m_kinematics; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final AHRS m_gyro; + + // PIDControl m_leftPidControl = new PIDControl( + // m_leftMotor, + // DrivetrainConstants.kLeftPositiveMovesForward + // ); + + // PIDControl m_rightPidControl = new PIDControl( + // m_rightMotor, + // DrivetrainConstants.kRightPositiveMovesForward + // ); + + /** Creates a new DriveSubsystem. */ + public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, AHRS gyro, TalonFX rightMotor, TalonFX leftMotor) { + m_poseEstimator = poseEstimator; + m_kinematics = kinematics; + m_gyro = gyro; + m_rightMotor = rightMotor; + m_leftMotor = leftMotor; + + // Right Motor + TalonFXConfiguration rightMotorConfig = new TalonFXConfiguration(); + rightMotorConfig.Slot0.kV = DrivetrainConstants.kV; + rightMotorConfig.Slot0.kS = DrivetrainConstants.kS; + rightMotorConfig.Slot0.kP = DrivetrainConstants.kP; + rightMotorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error + rightMotorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output + rightMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + rightMotorConfig.MotorOutput.Inverted = InvertedValue.Clockwise_Positive; + + rightMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + m_rightMotor.getConfigurator().apply(rightMotorConfig); + SendableRegistry.setName(m_rightMotor, "DriveSubsystem", "rightMotor"); + + // Left Motor + TalonFXConfiguration leftMotorConfig = new TalonFXConfiguration(); + leftMotorConfig.Slot0.kV = DrivetrainConstants.kV; + leftMotorConfig.Slot0.kS = DrivetrainConstants.kS; + leftMotorConfig.Slot0.kP = DrivetrainConstants.kP; + leftMotorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error + leftMotorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output + leftMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + leftMotorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; + + leftMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + m_leftMotor.getConfigurator().apply(leftMotorConfig); + SendableRegistry.setName(m_leftMotor, "DriveSubsystem", "leftMotor"); + + // Zeroing the encoders + m_leftMotor.setPosition(0); + m_rightMotor.setPosition(0); + + // Setting up the drive train + m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); + SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + + // Init Autobuilder + AutoBuilder.configure( + this::getPose, + this::resetPose, + this::getRobotRelativeSpeeds, + (speeds, feedforwards) -> driveRobotRelative(speeds), + new PPLTVController(0.02), + AutoConstants.kRobotConfig, + () -> { + // Boolean supplier that controls when the path will be mirrored for the red alliance + // This will flip the path being followed to the red side of the field. + // THE ORIGIN WILL REMAIN ON THE BLUE SIDE + + var alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + return alliance.get() == DriverStation.Alliance.Red; + } + return false; + }, + this + ); + SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + + // Gyro setup + m_gyro.zeroYaw(); + } + + public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { + m_optionalRightMotor = optionalRight; + + // Setting up Config + TalonFXConfiguration optionalRightMotorConfig = new TalonFXConfiguration(); + //check + optionalRightMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + optionalRightMotorConfig.MotorOutput.Inverted = InvertedValue.Clockwise_Positive; + + optionalRightMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + // Saving + m_optionalRightMotor.getConfigurator().apply(optionalRightMotorConfig); + + // Setting as a follwer + m_optionalRightMotor.setControl( + new Follower(m_rightMotor.getDeviceID(), false) + ); + + m_optionalLeftMotor = optionalLeft; + + // Setting up Config + TalonFXConfiguration optionalLeftMotorConfig = new TalonFXConfiguration(); + optionalLeftMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + optionalLeftMotorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; + + optionalLeftMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + // Saving + m_optionalLeftMotor.getConfigurator().apply(optionalLeftMotorConfig); + + // Setting as follower + m_optionalLeftMotor.setControl( + new Follower(m_leftMotor.getDeviceID(), false) + ); + } + + public void initDefaultCommand(CommandXboxController Controller) + { + setDefaultCommand(new DifferentialDriveCommand(this, Controller)); + } + + public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) + { + // NOTE: We are making our own custom input modifications + //m_leftSpeed = Math.pow(m_leftSpeed, 3); + //m_rightSpeed = Math.pow(m_rightSpeed, 3); + // NOTE: Notes can be useful for conveying information + + SmartDashboard.putNumber("Left Set", leftSpeedMPS); + SmartDashboard.putNumber("Right Set", rightSpeedMPS); + + double leftMPS = getMotorSpeedMPS(true); + double rightMPS = getMotorSpeedMPS(false); + + SmartDashboard.putNumber("Left MPS", leftMPS); + SmartDashboard.putNumber("Right MPS", rightMPS); + + // set motor voltage based on CTRE example + + double desiredLeftRotationsPerSecond =(leftMPS/Constants.DrivetrainConstants.kWheelCircumference)/Constants.DrivetrainConstants.kDrivetrainGearRatio; + double desiredRightRotationsPerSecond =(rightMPS/Constants.DrivetrainConstants.kWheelCircumference)/Constants.DrivetrainConstants.kDrivetrainGearRatio; + + m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(desiredLeftRotationsPerSecond)); + m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(desiredRightRotationsPerSecond)); + + } + + public double getSpeed(boolean bLeft) + { + if (bLeft) + { + return m_leftSpeed; + } + else + { + return m_rightSpeed; + } + } + + // Wrapping robot position inside of getposition + public Pose2d getPose(){ + return m_poseEstimator.getEstimatedPosition(); + } + + // Resets the drivetrains pose estimator to zero. + public void resetPose(Pose2d newPose){ + m_leftMotor.setPosition(0); + m_rightMotor.setPosition(0); + m_poseEstimator.resetPose(newPose); + } + + public double getMotorSpeedMPS(boolean bLeft) + { + double MPS; + if (bLeft) + { + MPS = m_leftMotor.getVelocity().getValueAsDouble() * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + } + else + { + MPS = m_rightMotor.getVelocity().getValueAsDouble() * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + } + return MPS; + } + + + // Returns a robot relative ChassisSpeeds object based on the avrg linear velocity + // in meters per second and avrg anglear velocity in readians per second + // Currently we are asuming that their is no scale for the motors, we cannot find anywhere to set the scale. + public ChassisSpeeds getRobotRelativeSpeeds() + { + // Linear Velocity in meters per second + double leftMPS = getMotorSpeedMPS(true); + double rightMPS = getMotorSpeedMPS(false); + + // Make wheelSpeeds object from MPS & converts it to chasis speeds + DifferentialDriveWheelSpeeds wheelSpeeds = new DifferentialDriveWheelSpeeds(leftMPS, rightMPS); + return m_kinematics.toChassisSpeeds(wheelSpeeds); + } + + // Gives the drivetrain a new drive command based on a robot relative + // chassis speed object. + public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ + m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, + relativeChassisSpeed.omegaRadiansPerSecond); + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + + m_poseEstimator.update( + m_gyro.getRotation2d(), + m_leftMotor.getPosition().getValueAsDouble(), + m_rightMotor.getPosition().getValueAsDouble()); + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/ExampleSubsystem.java new file mode 100644 index 0000000..6b375da --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/ExampleSubsystem.java @@ -0,0 +1,47 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class ExampleSubsystem extends SubsystemBase { + /** Creates a new ExampleSubsystem. */ + public ExampleSubsystem() {} + + /** + * Example command factory method. + * + * @return a command + */ + public Command exampleMethodCommand() { + // Inline construction of command goes here. + // Subsystem::RunOnce implicitly requires `this` subsystem. + return runOnce( + () -> { + /* one-time action goes here */ + }); + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/LimelightSubsystem.java new file mode 100644 index 0000000..0008e82 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -0,0 +1,48 @@ +// 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.subsystems; +import edu.wpi.first.math.VecBuilder; +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import frc.robot.LimelightHelpers; + +public class LimelightSubsystem extends SubsystemBase { + private final DifferentialDrivePoseEstimator m_poseEstimator; + + /** Creates a new PositionSubsystem. */ + public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { + m_poseEstimator = poseEstimator; + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler + + // This is copy and pasted from limelight's documentation for testing. + LimelightHelpers.PoseEstimate limelightMeasurement = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); + if (limelightMeasurement.tagCount >= 2) { // Only trust measurement if we see multiple tags + m_poseEstimator.setVisionMeasurementStdDevs(VecBuilder.fill(0.7, 0.7, 9999999)); + m_poseEstimator.addVisionMeasurement( + limelightMeasurement.pose, + limelightMeasurement.timestampSeconds + ); + } + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/AutoCommands.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/AutoCommands.java new file mode 100644 index 0000000..5475bf5 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/AutoCommands.java @@ -0,0 +1,59 @@ +package frc.robot.utils; + +import java.io.File; +import edu.wpi.first.wpilibj.Filesystem; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +import java.util.ArrayList; +import java.util.Optional; + +import com.pathplanner.lib.commands.PathPlannerAuto; + +// This goes to "/home/lvuser/deploy/pathplanner/autos" and grabs the names of all .auto files +// We are asuming that the PathPlannerAuto(string) is the file name of the auto +// We are asuming that the files are always in the "/home/lvuser/deploy/pathplanner/autos" +// We found this information at https://github.com/mjansen4857/pathplanner/wiki/PathPlannerLib:-Java-Usage +public class AutoCommands { + public static ArrayList getAutoNames() { + // Creating an ArrayList so I can fill it with auto file names w/o the extention. + ArrayList autoNames = new ArrayList(); + + // Getting the folder and files. + String deployDirectoryPath = Filesystem.getDeployDirectory().getPath(); + File deployDirectory = new File(deployDirectoryPath+"/pathplanner/autos"); + File[] listOfFiles = deployDirectory.listFiles(); + + // Checking if the files exist + if (listOfFiles != null) { + for (File file : listOfFiles) { + String fullName = file.getName(); // Returns [file_name].[extention] + if (file.isFile()) { + String[] splitName = fullName.split("\\."); // Splitting the file name into seprate parts. + + // If its an auto file then add it to the list. + if (splitName.length > 1 && "auto".equals(splitName[1])) { + autoNames.add(splitName[0]); + System.out.println("FOUND AUTO: "+splitName[0]); + } + } + } + } + + // Returning the new array + return autoNames; + } + + public static ArrayList getAutoCommands(Optional driveSubsystem) { + ArrayList autoCommands = new ArrayList(); + + if (driveSubsystem.isPresent()) { + ArrayList autoNames = getAutoNames(); + for (String autoName : autoNames) { + autoCommands.add(new PathPlannerAuto(autoName)); + } + } + + return autoCommands; + } +} diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/PIDControl.java b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/PIDControl.java new file mode 100644 index 0000000..ead0d7b --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/PIDControl.java @@ -0,0 +1,69 @@ +package frc.robot.utils; + +import com.ctre.phoenix6.controls.PositionVoltage; +import com.ctre.phoenix6.hardware.TalonFX; + +import edu.wpi.first.math.trajectory.TrapezoidProfile; +import frc.robot.Constants.DrivetrainConstants; + +public class PIDControl { + private TalonFX m_motor; + private boolean m_positiveMovesForward; + + private double m_targetPosition; + + private final TrapezoidProfile m_profile = new TrapezoidProfile( + new TrapezoidProfile.Constraints( + DrivetrainConstants.maxVelocity, + DrivetrainConstants.maxAcceleration + ) + ); + + private PositionVoltage m_positionVoltage; + private TrapezoidProfile.State m_goal = new TrapezoidProfile.State(); + private TrapezoidProfile.State m_setPoint = new TrapezoidProfile.State(); + + public PIDControl(TalonFX motor, boolean positiveMovesForward) { + m_motor = motor; + m_positiveMovesForward = positiveMovesForward; + } + + public void setTargetPosition(double position) { + m_targetPosition = position; + + double positionRotations = position * DrivetrainConstants.kDrivetrainGearRatio; + if (!m_positiveMovesForward) { + positionRotations = -positionRotations; + } + + m_goal = new TrapezoidProfile.State(positionRotations, 0); + m_setPoint = new TrapezoidProfile.State(0, 0); + + m_positionVoltage = new PositionVoltage(0).withSlot(0); + + m_motor.setPosition(0); // zero's motor at the start of the movement + } + + public void calculatePosition() { + m_setPoint = m_profile.calculate(0.020, m_setPoint, m_goal); + + m_positionVoltage.Position = m_setPoint.position; + m_positionVoltage.Velocity = m_setPoint.velocity; + m_motor.setControl(m_positionVoltage); + } + + public double getTargetPosition() { + return m_targetPosition; + } + + public double getPosition() { + double motorPosition = m_motor.getPosition().getValueAsDouble() / DrivetrainConstants.kDrivetrainGearRatio; + + if (m_positiveMovesForward) { + return motorPosition; + } else { + return -motorPosition; + } + } + +} diff --git a/prototype_projects/Experimental_Drivetrain/sysid_logs/Screenshot (1).png b/prototype_projects/Experimental_Drivetrain/sysid_logs/Screenshot (1).png new file mode 100644 index 0000000000000000000000000000000000000000..1130979a663ae09e5c0ed9aa508c832428ddb7b8 GIT binary patch literal 578440 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%0AX<1_ceo`UF{FO=^JAB6HG)Rk`RT#T@7fxTTAN_i ze$OWI7!G-`g4H)Wc-qXYo8H}=XaL0g4^j5+G~;zT7;vkXSuCC`NUV=kfRTL_f3Gg3 zf91Dn33=2d2di9fiG(rG_nRYbFa0TTCj{KE*#721AbC`V1|w~W;D3(FnYD)xA2w-w zUUs$i>i^lEk_OPnUyHtI!5Y`zBu&0AcnqH)koC5QcIy#|$26dsXE7!%rs4WnY`TlZ zpvKN2>RS!wOet@IO^urFN(Vyl(M#LaU_gUNuiEYS%N2Crx%GHI=m!BHkozt%zvStG zB_yV+s6@+`|M2@&avk)kGxfx67h|?z$3L(0du~dNl_mh$9sx*=9oQ^-^R=xBxU6*U zWel2)lx;nQtFFOBWspXlN5eOg>9ga29F2-d7}diTnKn^gS;=fZ#00IOzU*N%O6fCy z9EvZyu&DNi5el>q-vr-sn$yviXHtO#KE1<-73c2y zy?iK8z(RWo5M*YSm!EF@muS-Z3G9=Jk{EUsfKW;IEddFr@a^&yz+&wZwcQeX$CnM3MvjsUBW3WXNSQ^?zXUn4q5YoKO+xv_BUE$?3W(1nWer^wE`=nTB(&piJAjy*aYtW z^kF9fli^a!WY1d=tRM-==_`FTH*&|EASWZdO-P#kGfVj1{^GPwPuP@agQ(%_o=JDp z;jG)>q}Kmc%>(^Gu?8QDR4AYJRt6E;#@&rYs<*Y?yY~P1I3xBBj_DXaa}40`q`S9t zOP)LM1`%@VbS}%D6mFOjox;7;-Stp!!WWC(WVWqvfiC8x-vE54`5|KT6;(n&p$8*a zsy1>GMZc!(QfIaA)~I~9`Z^<+C>0eegZk&I>GC^XU_u>PFG+hOupnN%^6M>fB0+s@ zSZFGLPhT=>REt6$=3Y|Fm$Wnrh*L~?U!Vu3S-sKX82@YtkJ8Gt5!T3OY_Wrw2sPmh$5FI2(Xv)tk}+ z6scE~6HXNG5|Tb`hO@&$g!5331E z4NXm38&Q`85m8M?`~X33O0}T+qcsV%3`6>>?@tB-$V7s-cNVe@rtaQmgx; zm*1ZnV2F025=FotI2<@9}0|q=E5AEV;kq{DqC{h5K8gKxHG#afx-tC%eYoGVHP5(|} zpP+##(9crc0}>hS3#tp+^m7Y)Vs%*A3l`h z`?LY-f?l)q6Q~kw0ey5aQR+3@gk!`Q$*70}n6kz0xE}Cml|zyi?6W36LYz(xHyZLb z#`eZM$1Yx^vBqC_2LVRu*|89Wi?&BzT2k=x#=i8yF&Z~3Q3G5U9Ff1^OVxBeumKz) zt#Xde4-&wVLk=s7Lf?}ppuZE2%z}MoXhnsqBqoCj+G1@&G7FRErzq&E***a((oi+U zmtCV(7;@_COE>=UsesWyuT~ho6xJs_Rc!HVZMYVo-k*%MwBos)!#F&1QlR^pg&a?3 zKG^tE5dc8t*`=kH?ujZMl(36m083A9Zh856wzXQJ-Jn_NE>*h!*$6K1c@}G%HqP zfZkbVrpaeySC#@TGpBSdK^Xmoy{bz^IX9c_EceB+F&o@1=9YVF!kM%W5N?z0al;WG zKA^d|pYK^}X)!@SHU^T1g8&qd)xSMSo;(Q*4aHnCFp|7&8l~8hjQx-coqN;hAYV+a zIl1`1=%Q8^I4&jubZ`16l?HMIz=Bwd;SMZ?y`xgTIIf(zfdVoOZu>7{Q!+mrxo3hq z=Ucy$N-RxC;adVFJ)BngBUoeQ>I$f^i3JVLM+Z;rayPB4V2OGIS^QjobIS8WOiWB| zV^LfjAu4>k_F%B(y|Vz7Qf_lEsj1l4JysSLj-x{a5Pm`vXW5BYd`nOFR_Mk+S6yAybSjUZaGG_xsa;`SYkP5#l zBxDJ0@AmYA{(}cFOig`#FQ@W@gJvw>(eoO#8nOn?8E0fk27RTQ6;u`*-V8jo-r<_8 zC5xhyTbJnSjOqVTQnJuOlF|EJQ3NF#U+7R4GST*@ID8)=?jxKM!7s$1mOC_U);A6E9t%^`RId5*eqI4R%9Z@QJJq=L3F^20|GJGPST~ zv2D!6MhqYYNjjsSWEx5UcD3AJu}x~0XD^r|I6V4aQX*z_tV8mxUp|wk-6VguBB2=B zjh@3!x)0(!F+0B$`d)2mVU6wiM)T!%1Hd<4=WVO3gtZDRbuTG#fOo{*No=WBEwXWP z0{b=cuf;Z25PzKQSz{Y{kK&0F*+m8QoWyRrk0c`*WPcNKSuK}kE9Vyi_x3Ik&oit? zg}1;_1ShUq(9D_^owHPyg0RVKilmscBCbREQ;l#&-o(Vjcz1$n zy9J0z16I{op`NzcC{2XRai1SdV7>yV`vPty5L(1iKBIY$^%JGqu43c|X=!o&`&rf6 z{r^t4n=ul7_hm$r^_noB2-=0$oF2@r0pQc-X0ZQ|#r5~wv)7Fljex`{F=Z6DytW71 z4D|yNN2h_)MhbaD>Nz3)_pWt~O+47m{zhz76$@`tdLg-ko6K;lu;b?C1&%X58uZ(5-okoBO~7!)txob)O{!NS4KaC zOR;u@g*$9EP7%PK0%bu28r8DktAgd(e|2t9MudrH=ZZ{4{=4*SUv=Zbk7r!u2g zNmy4`SF5FYKva}2{?q`Rs@E!Bc2Az)I5Hk{^xA;Hv_2csI4~WMJ)OpK-X-YXadcvf z7r3x;-)uBLt}N$9U+$Pqby!EV8I)6u*1>nfU_E|kuGnRl^6QVkHn7CQ=l3hYicl~3 zL!tJ+r^C&x0D$rgtgy9B{-!6luJ`U8_^yZ!(ALjPERgWbl_+#5&6)HRwz;->6Wj@D z^VI&2cOHn7<#bBErI~-6Js%zOn6Ojq{r>919;9nOjH&@sOPr#L0Hu+i*0Vmk{;LW}StPOZFygfK40NULe z!*(Nq_uca}xllS~Mwi3&Utj~QKxTU99Ck#Za#aACHyg>tKaUM!I?oR>0Z`t|Ep7Dx=)~5+ zfz zs{K0YEwjP&bEx@(J)eJIXMZ#1wBA@h{z>;0#@f~i8y8oGZHn&-Z5N$^!0Fv5({XqV zHjcp(%R~9fOl_5mu7?{L&o8dBTaP{f7&|c)Ri)EPJxIX!B5?ZH4oWVd_u;T0`{QY1 zqSPPH>2K`xZ7<(~N zXb58e@?Skq@bQ~+RCiH)ThEJ%M9<4}#O1lQfR)uPu5Q9GimYl3o5M|k#qRSUrCc?e z`Bp8*jT5+iNf>oTH-J486z+dzCn-KeXzSuHW1|Xk)O7Y9>!XoOo(@Ftp8q&cCBps@ zqj=oDnbJnPKO13Mm#T2umxroFc03!rj*C#x^;x0qR8+CqpD@ka_q2?a&6pIc9c&0a z2QH4u?^GHz@N(VV812iIc=Y565%eFR$cqi5kYKi|Ka7t$yUXXa-U`H+Ood$E|Btb^ zfXZs?+J-GqQUw8NkyJ{$K~O+iMd@y&TUw>1yFpsI8|jn=X{1BCyZ(85p7;6Q`p5T; zamE=8McDV=d#yF+yh@N~XHl`upF|k!lnRTAZp|!pD_gIROA*9m#ZO#OCRXz_N2+1m z`Pk$i%b{5Kq4cuy=>t@U!{Z1Dl!p=HGd8wG2&cpTj0;H*%f)9*KGoUAZ9S?^0v1@;OeRVo+}Z~oRB}p+ zJqXxE1BkT`#svU=9N5Y*PZIKb$RCEf*hwDQ0lIDc;NW1`fpwt8zD~0++t7O8+E;Dn znm1jMc2CHOioGbF6|XMFewsV#{Inf;mr8Y>-OoA(zv`0|K_;HXI0- z13~)R9E1B{<;!Wm`oII#9-%D_AmNcVRaVB_oX{>{Xy$P|+|=$mMv01wDzMq3Iwa<- z57F%;b0JQH?x@gi+9iTP{rV^U&{ih_Q##Z%ta!Ojmi%RiPJPUf_Ku!+^ol$sGjP{4?_`tq#!mGoq0_ncQvNY5s zq?Ib3kdy)8MvHAv1oj#y2nRS17t2Z)w?8}6snobb+45~@rQjKdKD5#~YG+;x)NT*~ z$)dl6u2gE$D?v)?#*c=Ec6zWP6k_hDXKob~}~+2zGuIK^4Kr2+xTE0acHi8Qf_ zc=jh0^-fjhRn;de)33vZrhSPDmTmHZUsed0|7OYD!*bj;gJu9L9;%m{w?n52xEx#2!9KNlH#|F4RqP#&GGu^kJ}d#fU(d`L zBbW|Qsno_f4P}4WBM^@rSl@5Ii9AgkE*=+01n!u?Rmyl0{3!IZPw;&zpQkY&bnjsc zERMX&Am_(Jf9@wOsACPK7B27*va?yp$dYc|c0I=8qN1XL$c+0Wml2;nah!gz?4Xo> zfa+0u{sFQ}i%`;z-q1W)=rKVQ*q=WO4s1&1t5m)v;;oP$kITVI>wFa(asat-hM}L= zIdRjxU~CZnR1Qp>M<%PBmB-`VD}9)b)C5v@D@2Hhj~M%tP)5k=QoDF@ozatXr>}Oh|uMML2l#*|^>f4W z>);ivQ&hoI$6xX?3_uH-FmWem=g{+nx(DPb6>M)zESGe^WJ)rc+aKaJ#GCkI5P2&B z0WU>fHb>44w}gKYUpmr&^A2;32-MVbZqlYxpiXG+=?MVEBapiH-kf1E2ZmwQZ*g)q zQ<|h1B~quqdum}`Kut%-+hSuo$c=EW%{*)>NOmrTkcg8|7E6C{_7AK_oq(;Di2}T+}Dxj?Oo4 zWpah!KjeUioNCJq>FoXuC@`i>pJ~ zh9thGyj8;S(YahqD*}y9U((3bUxFUQJ?G!xcHLd&2k(!y)Xq*V|7_2`D~A-#uM1|# zZ)qMt=yyDX&h~*RVEPqv_)4ARVqY-%;}hDy6EQ?7r{f5|p-!8daKzR(|8j>B)7$o@ zo7B|QhTnre|6+R6EaH(8;Pa9gTfRsR&{o21N?d%V-HM_u!t){hdXSOmJxB>WeM334Ue! zmWJb?;W5reuCSyf{YO6th1mvdxX)bHAL?~S1!Vi80mh&=?6=}Hk(?il^oo5E(1 zmSp5)2sGJh@7K)f)71N*)yHsWOb`}ohIHb|x5Xva{tvAE1P@xpA<_u(NhN@NaA)g2 zbYyY%dnb7?`a4`{t0!wxs5a#T3jcpNfg@^+c3UVQ{_to#0unpZDCB-nV&L#&=PLP9 ziFo1S_gmrB4ZTB~hi$Hy~x3R+`l82 zLar1WbVu&V`*unecOUUg#dA9=5yY6n{52ZD43Wn!QkMejAqBddxXu(f;Qc_7Amj)2vmaj|m* zYOYB1FcI;Er%2-uF>rrYj9`Dl^d4yU#(Lky9}SQ@l!a=BRz>1r4CE%_!zpbtsZz+z z3b%^&yFeu+N~c~aJ|5m&UHJXRw!_dZy8=e(8lr774Ws?t zPn28ZJLMC0*ZejHg3t$l6{G8lR|iuEVsOU?e0Cdo^@3TYCvFLfh)-@_W)_!1OBLqi zupAZty|V#LCyZVe89F^{?xs#A=>Tc#l}Vq`jl0s@~lYc3FqR8hV({}1fMbo1Da#!-2Jjw5%5&6Wu^=&@GcD!KKw#T!b zCvpG8(Ra!Geyie|cw-j^oJHeQxVVIn=Z<=R_pXmu)~_e0`ZAVKv`XwM@l zF>w?P^6(Jhx+9I=DI?>nt&j%oT8e1&0S9_|`a;ssYh~TK9W`94l^<777CRTUoBv?k zLiUts8la;WFe}ev`>s-W&CN3}+!m3mfH3@Wty$>l$LjP>l@Ld@|M=`8(y+vIgyfSP zz4F^aAtWlvI2w#@W@e)soIIVXlRoGEzOr zBHJGh=C>i_Uie%lU2kX>9>#ue4{k!IrImGK9%^kBA1}>p4iV-XE3&v#tZ$p7^!~0} zlu9LC6iYFh&DsO)ahZ*=D&2>OUsHb_f`y6_`Fs5oK@bXUf}(&r{7B%&=4Cw##ab3BMSHpR=cD*V5GVhE!W$zq@%$ zxzN5zLym4k%74`(guX5wH%%Ndc_}n$6E5KRzm zmGLz0h=_D#3-~od0_6urx0#&`uq~I%n7!>qGlnRmxvqhoG+DaLn)lnxX9idH;ykM( z5*0}xxsFPh9@0DbT6=!5Y%Z7oM`C))28K$^A18wZ{i6iR3HO$5Q}p~Bk)5|7Lc!0Y z?qDWgz^l;k;*rZqCEwxU@W8Xb&&fKq?Gg-x7f>z6L|&0zDf6o+JAYl1sfoIu-P-vQ z>63VRl6SumuIt3>(|dx?f}-0V!z8pdkhm!af6&6lBI!f;&#oAzc(ZDoa8D`;>@*S0 ztCZ^uPQk9qy~zQL2Zu>I?Q_FlLOOz$$k7(c_0KDCkB@IL zIZRSfNsWCC4i1@p5v%cmAhM#k)L%ItDn=H=pXz=j)hMKik6Hsvr5Om(u1QMyNAYH| z2@0Cwvs)6^F;2-8r|V)|<`N8{A>OPA`b`gie#r-r}H{3dkbG+DjX zv^GKpK;BnzoIS$kg#z{z@$fJ2a)J`4aX06WgwHb7%Q@My38~&i((yEx^F{8O^rlIk z*$~>=%Au1)?IJa$uBaCjF;mJU#EGf#1YmNZUz&EuM5KuvH0GSlKfJh|t9P1n^>GR3 zlge%dd7Ejm(FhI@qCo@5w0>*ywK}!$RtpYcI7sdY*;40uq9poNR&p(NhBr-4s*F?K5u#cEG#h3Z>Evm+GWX)`%Uw+G7hhR$q@F8i8w{oIsMN88vSO|`1@=JbZ+H# zkJi}Z>f5OAm~B00H{k2wP0~F8lwC1mJAxn7rc&3FtomNWnBH-I48zZ_xJVh zazi&IBxL1sxc%TSj<(LWj|7(CEz)k=>?`ct+W%AP_lZN(c+@&1K-ERReOurThJRn% z`|PELh9(X!`&E*BwcEw8z)1vlQr zjS|J($b4SGTu5N^#1lqcZs6u0I}cEy((WGDhFj2kK&TeScNC=65{IGn_;E4{n(t#) zR><8|FSHuLQBk$TZ>|ZnKCI{Aex5*6y|xhLhQ~N%zB7P5Rf96$pE3fGN>^#Y=e?}R-zj(?+-~ljgYJz z_usZTApo{T7(rUpUu%0ON(7JZ#}7VL9=l}a$R06v<%xaO1xeqxloEfArYp5Y4LPp; zWfD{-y?z)WA(^iy#fPw3j_0vWwaGU7{;u$b_+nf9f*&DEj7ME}Tl1*Gc=*eynmju7 zqC0jRP0R`SNy5eHJH5F#b88L70N52cJqizpeiaT`4L!Y&g6jA9Me<3&x>GN#bU|jJ`2vedy1?cF{;`rqzqvZ=TcEAVQ}|-pRWsiLr8HWH@ExaK8>bS@gD=W-o)EM z6T?{A^X}T;L{b)Kn-)g+9nYKZLXm%HI~?{jIeTq2U`U>t1`jaUwowdbf~y(65snJL4BK{AlHjux)@5H5x;#p1!CA~P^U#i~x{arO1St^!w zHZoJ7cw;MUO-41&|sAMI(Z25NUk5 z$GXhOd!xQx!9z}4AxkOyqF`VM+z9=3)Cv4?VUDBn7MatdBlGygV}|seNRp5=;%#yB zGM$?alvkIwXyZg-?->~E8X z2uS2@luS^C!)4Q7w`VGl2~ed!txep<@O8Zk5ECd7%6#{_@QWtCK`B-Af@Lykq41t% ziIH+N{4!>!3r;aqTIMKG@IDVvdMqa#+gV;Vl8Xe4*UzSu7nYXl{PIpe=Pa}-(oL8a zGcDKDe1lF{n84;rM9nVuB6b)@u`s9HMWpI)i;WBs*bVh$FCISQ)Fk9HB|^|Z9zRYh zLPV?c=d0oK%H89CSsyRYJ8F%;N5gfsP^PEpOTZ-gaZE=~Kgt(bJJ>QYQ-@K1?ER$?5BE2tsQ@ zx6-|P_v-DYZ6iI?#)@!gqnT|8`ujV2wNB$~H^-$A-!_&(+O1Ufn42m_nwaNR6BN{s z!T-4nu3WLk7#|WZ)Xzmia~7bYS`AGg=sp`k?zuzY9}&rT)5m|veEnDzlekv5;K#Ph z&3d#g4#1+N<7*QsmZmN$Y|_+f(VJUaZ(xVI^AyI%8SkrSh<;Rfz|ez&!y6{fWglmJ z2h-;j^G%L4?JDWppHMN<@B@ZZ1R4^l14GnLdjZ1uW( zwp*1ybGUe-*`0Y#CO6DGV_7X|eXkN(ldhz#t?8&`eru0?eSuC?6A?6X=feoYQw(gx zyiV{q>zL2kf6kt4fth|{y?cl4tHhV^LQHa*;3~jv+9O#1Fl4SYF*&$MkRsSSJGVz(`(0I4QQ)#c@D)eOq5nKGGO6Ws}QWeXc7y5GlST0eZmO&o<~h3=172^!5;%yQ*J>m* zXs-?Brd%m5^~Cu2hz;O#wfN%b4xS1iGG2KuPh!6=c1pZJ2trs~FFbtpWvsx1CH>+Y z8#v$TvR>}ZxiAX-QM=ZV5YJQLG)u&Dc@YZ$3j|s_eZj@S@c_&Y^0T)mK~*wZq{(NZ zT&}f}?4iQ#8nLG@&1BX?=hha%C?8;BBxiBCFNV1_-F7tJwleZ`W4sc3Pp?1CjiflUdAo;j?QjvuV(#bm`>C(j)e&jWxhw!Jy zDo3~RdJ>l4aPlMJy5akBUd5rcHdz?87%n1Dy|x)Xw888A1i>pF?sx{%Lv7|4slmZt z^HjNufz_3#!r2DYs6SJsXd)u&c0Te~pPo4nAi9w`(tA`GClrV4KSY8X?F|Mh9*FGV z1?A*+8N9B$B`24Djfl^Iki|;7$~p^RaFrVazkYeI4x!Fs)g`RA_yz)Px8yYa26Hqz z$orH^B^}VkeAhS<1`9OBc9%+psX{@3A&81+J2$#hJ<#{=clFi_7#G!`+?nr=ea4{X zAawA-WBbr0MTX++#A|Ln4$bkbLff;tnwUN&!)onxEyBdULz+L{`tt(=1xMVj zvrHgJw_Z{4*AkB3*)|6=l>6ZnWGc{C#>JZe&kSI#UCx&96qhshpN}x-^qzJucpBZQ z+cO8+v+dvKihu+B~on41pqT>f&>JQbbjz$*9qD}sV|>*U{OBgHRd$ov27e}_m-Om{D8sKGfmC$kK=Sr8dMMEIy0JO83K~)w06e3Mgoa;dL{`~W~A1RL~)Vuv=^^ZIQ ziG*ijpF8`BHhk$yWbp;!<)2@rJfZ25Ne)9U5Pc zX0YE*dfmQ5qwonpLCcvwvMTGX&#s>Y1f&vD)ngT?++c>#U-9Nex>TZcwX|x5)e(u6 zUiY(CVT+y1&@wkgoAuc5&O~%6{R9lWuTG>#y@qB3*ZqOb=ICes9}c@~UC|%ejT+F* z%m~;GH15elaRpmZL+(Vm;dCL3tZTe9FpVFwID}o=#19wBFhmZP+cAP=`*Sy{1Ulu~ zkW2xo^yk-`ib}Trgy56@{}Em(^sa8YURaSpD}Q;qTvM_ZT4}MzB@s!QDwZ-}e60P* zHD|Lo3&%NAJ-_0TZD)Ym+aB%k_4gp`wc&mJjn&H>b)HX{8`*zCKV4o=qEmJ8Uh4i? zu^&E2(79NMKV56BXz z;{%SU)BST1*#t;_2IF&tZtR(`R&=)Oum3U{eF)x!+=G=bZgbnNh#M$OcF_Xy*I2DC z07%UiYP&q^lZE6>p6JPMO9_xSuEDt_=&RTLXQ~(v%H)Af)``jsb)XNd)s3uJ$MM+( z6k@wPqTx?62DfI|$+^t`JQ~#R5ec1)`Q(GXJ{<^QRQ(s#2`_~yRc>vMJhGKh( zFY~TTdGS0-N@OTpJx5+nKI&Enak0J~5enJUO|$ z+m;oMfS_H=Oh&d`pV!p_rr_W6yB0}fEAI+jPk7CmJAjC%HMK)v#Z{jxCl`^d<9caE zyXSJoH|9RjuK5BI$r<<@jvA(?Nk2i9Hxmd;st*2$87Mqd<}lNmTj)@!a`J#PkCKWi zg3a|@5L9K+`%OnB9|kdVr8_gVMHQ<}iD7R+-zl!JGnp1yvnBp`zJOwCYOh%C0Jv1H z-e80PnTyDFtBp}5fGq-27f7EruFhM4f~!zYHtWo0becapwg|c?{(E(DtA#IaukdKx z)9-OPeVZ>d{677qVct{?m5JVTUVI$4bBy7j{&T0t#>=h_8N!jK)K!4xCgu|sS-yd$ZHSML;+P* zrY?8S|L;X*(@2~st_Q=%GM7T(fArsKd;Z{zqlx)H7H4Yw(*1fh_=$w}bE zpfxro-@$aD-DquA5YAJHfVSmcw)DlveSYu(0n5XkC8>vng{0;Azu>?#Htu3#mz&)p z6*0~ss8oqCw%m30^9vgtR|1wRXMca;z-F&BLnH);e-0M+sdJ?%{Lp<{fFpB=79h-a z`m%F-k?HiePddUoZ^TQBYG@qazWS}h3|Uq6P$JaVn?HVBdtQVC-DF~?n-}4}x_q7j z*^t$JGW(AB6iT^AuKb3wRTn^%xH_-)2mJ&Aq@r*aS?@d^xB2r*ay?Q2ul)|lmm#B0 zdYsNlP(+W*+viSe`>(H_8&9e5mfl!aGo&!t=7jA zk1@kmWJAg4uLQC8G!r>)k@2*H?+~N}f-+a{S{otfM;ZjlSTi(z-%rM+M%&m}GSIBL z*uIGy`i@2qmW-(Vi(8U@vg#6$UZ9A&Ht5U%PcRuQ!NM5SgHQeW?680gm(bumF__@{={=Djm;{xt4 zu7K3#o4WT|3ZDVmr5GoqQ>_)cnj~N|@dP~`Z6tj|SC@I~LFpPth}7i`@Ijj0`{`9* z@2=Pon8*($mZpAWY+v7N5Ew!U=TTT*oFbF2X1y_h0=7_ym_VTD?u#*g0#~@zI?Mo9 zwUc?7pH>s&TBfF&+vniAY=78=w#?geTDH)>P*f2U`6cN3|DY7(_XJu02c?**rj_*H zlwz#ow;le@08BX^VPS<@Tut$zF36nuHUA$*F?y>P0b7=~p`njdPen+fdNE`8Ino^z zpBb2%Kn6EZsQs5(d^tMc%j9Hj`xWft{tk6;5q+puhj}?ep{2B9%?*RMHkhc5DzK%3 zhZen-)-M>B>wbl-@LuvqkI)n41yAcby!gwTbLgZB3!ahDb#0eo5oRwPtZ6tozu;fp zN*`>9<(U2Gc>C)@J{%E2X*BP}fh)Zlcx=pYXA2wqKGD&1`|CqfF6nZ4vYPkp(Q%9% zYE)0hE1gHBN`(%C~AEa!aX_6bMQ4)$87E!S=D-IMzw^Fr=Nu!sJFUUNw3Gr=1O%qD|7T$>i{i@~GrL*Z|Mbb31$lZ;? z66hq6$CW>vR+{E0B|5@s@o;D#<`LpY@=7HD$=+YYSB_A=2m3kU)erHs$IQ$j6LzMu zRqw=}hB5YbD|5h8_st5Yl?8n`q}&@92-uvrTs2Q!#AXs|%UW#WWCVOJ7zR3NVF4zj0;&q68v$%8A;n8hn~-U9V_p9&iy5Ev=r zaluKjlsf_f`w0B*{)>9dpQVM^6QswOH(5>JiPvEej0TmPrEpoX&r&`3i^pvG`TIYS zE1_xmirdmW`VeoK_jJn_hh7|tQkVeYUpJe2=){lXE+d9b*gb1Rz+H!#BxFEwRa`z- z8}3KxRwePm!*~u9oWHiP>eHX74m$5kqbTX zghocR&at7P3V&Cvrb2}NG`9G%8m;=cxxx2Sb}cz4g0AQBWActf z#w5COco;xD-9C`2Sb6m5QT?}?QZOcvi$D<|{U-A`yJ*&dt}z1-7gywYJt6Q^*bM9< zYxUI~KwP3x5RvaIF=>2Ymp@h#;LIG|r6CDTP{pEutY(~?+0-p8T#}w9(ZCSDyVXaV zbDCiHi6yb@@uFd|LsYe`tdtn`*AsbA$F}gSs zkcsYE5W~)tD@7&5qPKZ`C$TByCf=XD3Wnai#U!Oy6t^v-vEMz5__>%R4i9Vw@xX!$ zPbm=5=Z|#k!0H1TI7c*cCExiQ-qfmajhC3}-rJj*B?mVZ$Xo)Y!3|)*obIpc-V2pu zbasNU^c36f7#M;Ej||~}cdVg84EVYQGbVzM-eL-P;9P=E?$wLImkg2Qp&g+V z?*obWJRw09rszQG*NmmbgRhvqcN{L`Akv&kr|T0~&BL zcwO-P`fgQK2;7nRBS^Mzw?mL4Ip~#U)`=qfa@F$_8oKeX{om=owF|}2tbKG~*Sz}d z2EoEVwh#5-D|CXsM1UJs+q{HGNJ@;SBncP*#M)^)o%g$P@pXx1F~ftk73_%s>V?Xd zE_Nwjcw*?c7tEp)@w$Wi(@LG|$Z)aDG=-4`YGVd2{%YG8eTw2~n^WF&r)b7V5--R5 z*C`TYIvvBdSVcwofU5cXk+Cx)hiB4UM}R6iu87yfH-b($?X9Iouc_K>-z6V>()(~!E{JHvSQCyZ)^DB*sdGu>v*)arhm}CpWRR@F>4jVCoDhQ1kf?Kv7oPuz-LFm7i znwi-1lzqKG->rh!yAdN73^2Ls&6a;+3hFv=J;tZ2gAHY3sZRbrVT_yHrKWpqTc4HM zUCX6jdJOEM0(eyhT0bqo=Xo~khi~oxb51LaB(;_;G56Q_C$bb(@VO>@vs?K`$WVL zca{N5tn&#z`1*3{3u7lG^2*q6<&sM@J<7v)9nN2l>wxpiifr1)H*&_4?%8fP^L}*h ztpDMwkr9aSL}`>KCvSahk@w_IbmFUP`b?OIhYuLlRK|@TLG~Fe1+2^a9pTWee?B)J zD@Z8Bu3d&mJ5V^@;~zM~suzlb&y~pXuk7!jH~;c2Vhy$yBMrXR6N7BM-a2!`Lc(^v zQ@24Fjpa+PaFN-;RcewDx9-aUBqrRniPkBbH?_5$z6NMiMsC~Ho85yi?9w#9Y!Cgr zYlyToQ6ZCc*jVdKYVwl(4Vv$0!_YcPiHL7t4{mKR9RPL+g_;{mh?QAswfvtclTbG5 zm+kjrIJu4y5ceHRahASlWXjY0`RU08d|MEud)EBZWu%uKuSHw6J{Ug5xQ{4Zj72Fv zdGux(%r>%`3`7CN_4OlHm&?l|b>zFm(mLUbp^^6zqzFp;&)gY5^Tb*u670uZOiL2N z-7O6ewz@l&K3c+Ot$HkA%|xK|?#a&$pMS^bLWgm}v4EE!5ANl$>`aTHVhJ!}LvdGo#TpdXO?%ucWZlK?Z8L zPmFxH&QJ2EZ~dtYKn-kcNf*gm>0M2HUbdJ=Xg})wD{Dp-7zyvyv%sqJF!kc(8qMn<>HhL_BAGNDaoAcan6$o ze^Bb5_>*@|@iuekV~mW%QT-{bV}18ZSR|)f442rqHnmwhShVwP7>%-b|C>Ve35!59 zyJn^O#u4iOSPuvyVpF53SS*6HPu5vbLdO8kQfePa&E0ce)OZbu)@&k?o!!S<Pv@x#eLhwiOY&8O6;1Y-w){YJwKC(*YEdMs$}2$;3f1;6+WnCcAL%Uf)o)e5 z?TJftd`&=gN8SJ5^f&yFYtk#pmGJbpb$vk16*^uBoZ>qEOy~Ola<^5&&Yq2J5Osrg z>?_VsD==(Gmx)DW+Jpbx@uT5GB(A}XN7r!h)aOlt?jprTrhd{#F*V`u^$iV7y?Z|- z7-)J$GYb1@V81o5r{^c0Ib(3lGP#O3`>VJ5zb;tn;eR=9{j*NmJ+-v75OIj010N4} zVa7L6D%V@w)$NL9iG`M5Lrd$iKUUF`(9!2kzlIHh3-zC4h=+Y|ZHnipI6Kn)YLoNa z$29y+OxFI6sjl+Ck26jkOOFPZTeA}1mD3-DX2r17CZi1Tebvy>qx(M#_#dIgKc`ty z)aQ#c7ROdUiiuv?^j9wgV&pRB0oO7<*^`mWRYUOE4aRDaQbYq@QiUQM8QM9vF{TCR zJc)?QcAuTH=G=JBulhzPze-cR;+pR1aQ$S%S0uO7q6wCW!o2b*HiK{0@?W;c>_?T? z>hglyP^%|#=?Eqp9*H16e-Yuo*!zDER=@-$cR9KKx`eSX^z;CBa9ETFqWt+kJM&^? zvKcZGaCssrnvgj_Bw!J;hsRI=;inP#Dq@vIx-=@BD^~Uy2K~w4Of?4HY|% zV;7Zs_c7&N3_7;nrzozN$Ioht`$?_SaC~D=%MrRBl+-kM3XSC3B5E?0_V0x>v#d2&7H>-NwA&M*0wV9 zZDmLamns~v2EV@5Mm3P@JO#-J!thK24TR=Fg3ZTdchp7dYMp7qy6nrLxCY6OFoVoQ zS`4UV3iY?9C?-C;-A+qNY|d3KheLY7!aBru<#(l(m(_9)zOm5o!RXrk&OFi8I*y2z z$1iSwsvZdB?{9tZKDMyp8`E;G)b;KDg;Yha!qc`p(V`;$!ip_XrB~0K4yLY?b zt(H_(d3uAYc+tmzuuOTk)$KY*d78=N2F)zD}B=Ph^*5k=VI zizj^iEF3fd~w!PF5d=a)J%jZX>SV zIx_^>1c*#^-j}E0*-SFWFF5QdYsW7pzGLhO!1SmhI4qIX|UK5zMd7(P1=A zPbVgOpvjh5KQWXq3+rq}?xm6fpj&>Nve{@Noh>hq;Tk6wH^K|?#$@!9P%4Da(RjIuTS`g_MBl(|D&8(X zc@pqB+W(=zt=Y~eZ!4ZH_asKLTb=a~OGI60Z(S zq@>{d;&EF>yc)3;kSQa$6Q=fih)Y@>%9Q{CAqKkynuOu8sFekRS^BiZXu=b~JhAHQ z217+iAUiqv<2yCq7La6=A^j^;HP*%1ac^t*st`WH=;%V2r{4GS*;xcoHuxb;6+ao; zUe+A-M9+h@!7>|KDnH^E6T`XtCLm>t0R6W+UHvdS9_Tib><82R@YzC$NP|ba@+2kw zP7HSgt=Gmqh=zv|V4fmNx^^T_IqUupu;Mx1@gjZ5ro}16$Cvh-X2H_o=sX}jA>m!_ zTj4rN=`RF?g#G1qX5d%#8Iw2y7Z+5yzNFMr&A@Ra&3O0Ju)hX>FheRuzIV&q+Pd%P z2ejeeU)S;i4aPrV+F7(PS@(IowRN)O%3GB>i%{p=ceRXlURJZ`hQ?`sXCvr|;}QK)W%F96 znCBwxXE=T5xxLj2*x9vw#R1HHr^GoZt12_JO^A8h{k%Ly_L#Q@_(E3O|}ga76ap0?9&%QLLafWk>f9!KSDixSMazf zBvz3+6dX*R>*`Q!oND~9`kjmg{SAi83p=1NScSwo!3`6vwA5t+O(t+ZK}URgxY+`t ze}FOb1apEeOs1;Bn2Q4k=cRGdYYbb1x6iLF1c}aQV!b-)qsjV6XvHHsxx<`jLGv^; zu)3Afi6GI4?x$o)A%WI(YhSUVRK$@P;|4;vFYNQM+#XW3p@n^l=e4%OAtgP*{)BvfJX8o;f~?(Kvek* z2ZXOl1*-i(WTZmt1HG~OG`m@Y89-`Zf{^~J{akSu(tdBI+}~LZlS|_fqLH3W0Ur|o zG^5C#fxe?vcsftX-)G^i!-#gG%xu|9OklO#!#DEJ8LU}+rVp&4uBXwENX`Pkp(~Eh z3-Y|*lu6<{tAHqa1z@#|o;X2b!fZ1cI++Ash$ZujueM_`-@XSTp$_jiDO|3zUs(5j zeI+h?(t^BhPam$gu;epxq$CMdT7s>ew1L4Sw~-G%KK@SQ8Ku#P$xLIK1niJ!_2->Qs(=}_Q^0oTp7Ky%<5R#OL zT!oIX%t7w}c1b^dIjwU z0Q4YFE#c4}hW-yW2BDSa`vG7P00@d6@P)<>N8~P$DgwdshwYG*^OdZOj33tT7I`rG z9L`m2Nwd=Dv^{j_x!`O^_} z4UXeV15oS4LoObqE|_V^*xc^&6m% zPu;2|qhgOB;=1{hu=+ugg((47}71 z*C%Aa2cfyQIZq*p7pAcC`JtD;Q<9Tmw8rMa%bTh?<_T3MGywp9Jsz8m4w_jR)CYez zA*Yr&=d-&rB#FmxBF;i!&*|vl#`tRQb?S@lAGH_p$--X?99k?PbQ07got*aTcLrUf zV-`x~zCCvt&R6YT+|wVsn6}M&pR3h(S3_5~q(UO21o@*$7jke+%u{Y(fBe z0v-~~;}iK?q4t5!-(sPjpCM78Q(c)|wp@BcM}NtQj>+XtV`S-kUA)s^G9?HRQ(*Ih z<1(7$cQuQ_%r)DsF&LDU?30nwJ%0QJ+US8I8$vge(=Nq<*VjA)9yZ9xW?<20?wbGE zzRzv5(F)c`581USe%GyafOXc#%kxUXxNVzpi`@sbY8AV3`hJ-B`b|W~7K`GhYWwM4 zTZA{>qt>9czWyf1vhu=%@sCx2@Rov-(%U+2?+w8r(Ks|ki$eGDs z{!*Rb7zH zdRb3k)y*HqSC@PkNtn7g4V_@e1CLq7I+w9xeKkY{0?6o}BM?uKJ$?VZ9*jQ^O!C#w zigZpadlCd>K0g>H+ypXlsLOEzyexgmHiSy0Mr|#f^6i=?NIPPgU|$OKTzy=6#jpCs zxaVc&_ra=eE*7^tty<#!qBsuhO)3ayIbS)GKOE-IOifKCyab=I3p2A%B zn@oPfIky!RFkZJCCt^J@2p%?rqf=aEv7Y(bp~<-2de<-YjKK=co2`B%Y3eDwxqla* z*_K+)M8RidDPF}gCra4vBtPGOU-Sw z{s^NtVtsx6vd;`Tz`jMn~gAN}d@nx78sXcry&>z4-5KFGcJq_(ZgD z$&iRYVC=DjBMI)ZN`?8G=_|Nyz=802shHA)K4)jsLai{HQ= zNw1flew<3?WA@>LxR9`OOfug}xPQFbkNCqYebCa|m5qSjdze&?Cb~ zu-7PEe#mohaA1;h!91T&L_`DzoqPL+LTLb@FciZ}F?9<$r0vPdX+^qTdKfrDUOJx@ zSRN3Z-X(HRaU*v_J{)O_ij6I{9D94?##CRCl(I|IKDjCnp&SP^f08E_kJ+-`YXcNx z{bv#>f0+>!uuhQC9vcsi&zi44KibjGmdliU`I3SuBvnKlFh0?X(*p##^3c|H!1M>) zEW|~C?cCSwY>A@fdT27W_eXd9NO%$~uw7=xSQvA1bM9cGcplF$BU@KD#9 z^^$5MYcI!eML3=)fmL}sjQC;x@-s;AX6TQ8M*4xGcW=a9HpjnuBw&V>p*G3kb-E-P z=&5;YU3@10M~2;w%iQ~Zh|zd0qIP(@WmK!{D2WPCrqZajuL*XPZdXQA6IV)3`4{tG@an|eGPG{f>B6^85-X1 zoCgP(1L<9wp*?wDL}9v9%nK%jU!{8D!lX+uwL?Yx5mtRio4-fOk-Xf^VU7ivvnU-D z=Fq{c^#34qy{h&vT^pX?*y#4f1K-IXp4B^N9pF%>mmsB3@eu`Pdrc#~f#jlrJ4ba_ z1FNwS$Y+kw-8xvn-V2*WE7)w1@H(|mo}fW{kmYjGQEoPEdGZs-^mnbBYds-Y2sQ34 zGgesaQB_(|cWp;>=zxD=lxw-k@?ks=)U|ihgaly-i+$nyCCCPNlO84$cIFFznBY87 zDA6$tsXnSR9Q!ho@2ps+g#;urPK#X%qe}%*NToJ6FW~TI3u+uK*Is6T6T%k^Wg%{Q z2@p_L3B8T6Fz~ACgDcKaDUI2$rfa+3Q*r#T=`JXHf^2 z0lB&KV5GJV?uLL~&cMwFYw1c`zLnD${Dxn@ZbeHTPQ9#^q)K_?cFH-p)jCD5 z(_PsO=T5g*?%^Tutk|n_Y%oAPSWX3d(nnsUY(U%$0IRY*)w%|7M#dmf2T(NYT~_k| z4lSqSCQ)yKJ>;o7O?lR(z3;5pYX-K$Tf_hzQBk-TYMa|wGypb(r?3B)Ceizg?%0`3 zzc*fcVOx`kzaTJv;!?No)1}xHIX^!?;_1U@{x(R-cN=+o*P#deqU?|V+^3WX19_vR zU;H*7!0R_&mq{7|al8vCbQXt`T#(RsVs~a6Kq?>z1xRZ3nZe&;e`_Y`h2KNI7!(1? zg)^Vfhy0cglrN72w6sFh8D88g`ug3xiO@sNRM8_?Nm_LJ_1BvB^YThP^F#zs9|~w1 zW_$%(61R_#1)=iSv4R}3qSAV^b+Ua@+s-1Mii?%eiL?^b6}JW+zQB&fB>xK+Kb!X;-XwpHF@^na5Q)Bfz}ZbbJN_? z8WNP_e&xNFxY|Sf96&WRp4~iget?Put_lqe4GE;wm*1vk${FIp1g4^@Ih@tc|9#5v z_kIIbaJsk{7k(4`<{=^erL)=Z%9Jba^9|(${=LU$PKGZ9+r|GY%_;s;#LsT>_ik%G z#=~?oM|f-^PjSjBu}p)4#7);h*ElJ`dXsf?x?1$}c}MRxX=&4m$ zI3_kz#j|J>Cqsrb_$I?!vV7_vOT_J@AaJHc`=sT(5Hf5fBJ*d!*C4LW{Ie8rx}6rq zVJH!*+VOmZm{T`Jwn<;v?}0V-O$5OE+{E7U{C^0qu;a@ zzZOv30OKIxb$I#OeA2in4E|h8Rv|<2xC$zMA$Wj=T1aYjhmZ{(1NO9FvFzzv%p#LO znRrK1Oh<=;KY#w`$W3sI)-*KCOjHCPR$>8H*DqM_e^fei%ub@!H#Cqy326FT{QGlk z0)nq#M0vXSmO-`ZCBK~=7+0n{Pn4CIjYL%0e9#W@7wV&r)#i6;LLAXQN?_tp;owIJ>A&jKV7#C(gtK@xit}a7vtAG)} zY?wi2nBQZVzqAv7+_A!2*#u5VOt z0|5~Qqy_12kOl$iQcyaiySo($=>};L0g-Nzl5P-Gy1TpU`qt(1ywCpLZ}xs?@0mSw z|KWH$#CaX(I@bEFUu;diaSZq%n(>r6=E0*>`%%GaEfHXo9dAu@pCtZ^7q;Dyy#1(J zV9RBD@o?g`Fa&rnESoj#9H@(qHnpsW)+bkd5(_+tNN{~5Qy?J*nLRQ_OHwj-MBRZw z3ZAC}GF^i**zf7%9uS7Ly{3+l$P~}{rDqtsmoz~a<~3NMUqLAU9n0hYqIT659dC~J zU)*Z&dT6u)+w9^_aA}Vq-Jg%819EKu(5f`27SbIT;2{HH^I67Wgh*FMBuVmliKiRrFIE8QF7I%kltLFVVtA|PkDSI-BgIOh2RrA|ES6R*l8Ve3C zG~hP8%%X!Y@PrAvQRH2feYMBXaKV=f0C|quni{U|Eec+wpV{Uz9TbQCIgO zpf&dEz#B4{0QY7?ps!%)bNK#6ra8FSGQ8`63RFjgw9?MaSyr_Z%iM8F`fkj%cM`(# zP>jOtoc$jbY>Fp5Y8)9a?%6N*5HFwWX7+Odldi>f?SSB&g#{^NnCwGoLC@V34UQ|l z)504qev%obQr{j}_qkZny(Ucfpwh`n{5|&QE8E}osXF*A5x&euwjXNG1HU_<-~%%Oqgod}t;`UZbMb1iOYh%=5D z@BB-K(+TQo)T#AMRC8jCV^IBM7SpCx<9&mLrP;p3-A=XsIqh9tohcSwEC}&fRiaY% zwD!L8hA3yd<*i9d;eIe+&YGnQ4hvfZGz`vw(Rer_dZW9&UGgmQxC=({D+>p7bl}eK z&-qu0gg!RB1zr2io3&&%I?V(dTf0Wn)4SfQVVRll8a3*-hu$3=hSj{FhPg|Q`d32S zuunR-b%32log20kAQqUUf--w)Q*|z+dIT@&g*iNSb{=HS%O=-@1H7G1oxAw6XM^l% z+tHT!KQZY`vIT!g%=lH=zb?$Lau`QGD@ptCgH@UT!f;{^*xW~=#Uf|bX?|7 zfUp3B-~EvVvLL|^irwLe7>WP2h9sB{)Fwj7-rYZ>fE()_6?!y86o5w<*^?)SAxuEQ zTozEEi+6okF9hQdpb36}-Q+0ds+ZjcVnA&ei*P!Uv`Kwl%(lE*W&#v{J#+J~HnN@* zkFNrHAwv3{13MIGh@v>mx_LR*|7ZPA?mLZw*=?UHJ%gB-CHZ7~c+`eITL(M)$C8<)G%fSMx35ht{C`vi|w5zzP}F=+;vhGi_2?iO<(p!j!d_zAN{bUzMU+Qea@aEKbdx7an1?Zoiz0}3W-hDx5|_^Cl=2@4d`Zy5)8uUJBlNtKIU#;7o1MuE^@yaUVcGESCrJ%sFZUJph)StAo|pF!B!W9GfqV`a#qaGUW5T(u$Ss2}lEefvHIc z*8jos(}{NKJ>D8ue0y;Vsi8*m_Z3i3aNHjB2M5a)2CB~{8y1)HvR<7g&^PZMSTI8KF1_Bgzh$$p1_472tYxA%bA2<_%fA^R{01cqn2PJsHUzCAw5P(oYp;n zzI@KWVN`p=#h}Uxu5M;{*ZTVUkiKPOV`v;49N-)tVH4cug`92GQ^3vBUMVy^F-oHu+?56T(8m#@buo*!uz9 z14|f5pX2JVFbro%dnCRvGtQ9&tMBcr8&Em)Qo8JV$HtOgGzSh=4ZGy_P4&+&K+r80 zxAkPSvk?(ILHN$Qi_VK9x%zfzJ0rm4@4 zJPr6|N;1a`)GWIIb;GL1KQ;9ctcgIZqi18%4inQg00?Gh zGbNGe7XS#m2csNFhf1&t$79xJADKSCOUma5B$?vUQs0wfss3$u7`gotR0j!uLV-w> z1AS&Y?CtiK&?#hyDf{R^c(u|J zPfw)igGb|gh58Jf@b|`FJ(x*GTlP#6KGB9@TR+7WDhMSELFN$*%(ur_<|vq4aFrbZ z=%@zS1V}qHZ-%G_{5BP8e9d+*=kcA#g-Jc3=r0b`zrWfu{X3H+32mVDsu~YOXMK4o zb8lm`7ubg%1RePPYS#zu{^R50GjvsQufHvf*KLEg#>En>H&5OfGo^y1YHE!$hjovs z^X5n!Xk^t`O~N@D<&k~mk-0^(S`_RwI3Dy(eQ;XBacCl#^kJj%3t+=&XnTE&i zfHm-VJ2N+j#$Ng#m;R}`k+CImO3qkV%MlzxS0oLdj-74!OMg3_|*7<^KcZu;IGzDToIT+wijLzf$SBnim6OAvn9neRzJ<|}C z4s#u3$N`K0YTWF;1Kjcu#L!esCdLCvIj}o;%*hz5Ubc+&sNu>*qg@CxDPSm3t1-XT z9zm?XAK-+HV$B;?B9Z<4KXNezG`}Net^=nj+iHCXbc#$A0hlJ|;fRrHiz-f>3Jozw z$GcHcoivK)u(t$jBs$$fVyF-%UkVx7VVba}(adFuooVdHr0yjFF!4a{S zs7lt$fl82FGio;pYa-f7^Hh;4&Z~*6y7a`?8chS%kcvd+W19UOYU*>RBVy6)~7K|M3+ zOQV1v1Ga^GM^=8`ZZYL>n2;29Bzd^Y-+_3fhR8yep-uiosP)j+iLbz0I;sUGNii^L z;e~U%+@CUck*JJ}XKM1F3)h9MY$yTuTM!U9BdSt?4sCnYL$}nMb|~G&ikz8FKB3{! zw~RTh?_l0}nmO<>sK^x=K+)6FQ~Z#d8g*37&~&1=Me@kzwWO^GVZB?(alCn8;xIzi9yp{kd0 z+Yo~Gi4`W%J>n>#zx>5gMx+^{@(C^Ja^FB|N{#J{v3%7sb5(_uQCh1$XE3C^ckc)w z4WO{X{S6#JX=Zz%+WvnqUX24@Pgh(BF>n6v;UUGw4Xoi+Xp4ej8UsWeA{S^*1+fql zkN%6LD{g6-4>D`m+kxu=D3F)_tgHG3<`f<1f)GWm+7h+y>}a{MIdEjLuh&9%I#j*t z*?plBcBBokahJ3T3JQv&hE;S$KejS`9C*e;@JiYoU(LUQa)4=d^LAUD!_{*;;g}mT zS^toxtAc|}ZKbOQ5ERRtWWJrYJTXCiCzSidL6OG3{qCv`Z zV37;vKadrd?#Rgg9Dgx-??%NTi^F4FHIS=9ae+jq_Z)-48(xfsKVF zC)X3Wy=)-hPMmOXb{_y3A|fIr8hsayl9H0MHJE@PE71ho5^QEKvwH^%IlEKGQH1X^zpx->DaQydBUBz~DKA=1qUv7#mnx9dAv|6MmcX+)Fsq*I8oYCc z4egTxUB&dPOH>)7&anKJiIxvQ$3pTS`wJ{(zsK8s6cy4P;#XIu6^OTzWd=iU3NzEn z=bs!2%#=%~T&&~c+CPnQ81Jm?X1=sJ0v`8DxyElZo_>ZGwLD09%5Poo#jZboGB1Oq z+sPBPBqkFJs!O(r8;?DMF8$K;Zjo_x{g+ZO=gU~J+gEh<6Jd`x$KA2Rvc2m{SVef; zpL<8c6>>rpz5Ui$nkZd%C1I>3CcYTxeDCr%JVgRw)7I9qcj3uTo?#;_^22dzxvPQ6`<0CEEB$v$NUt{ zmI)da4-cgn^F@v`BS)E>TEb8d=b`<@gBPeljzkO&_BAN zq%sHYgL=qTO6sc*0;Ej7Vxo7t-|W7CzkcxGt;D|F`6+&Gfn5qNygfH>p9)U|5y06Yo-g(M5_e3pbjFk-6-Wv`N2eN|owpAij zxr;vjF)V6Hse6}MPN%-j&)scqFi>OU4O_D>8Wm`4Y$Z2u-h@Pllnu&QqYymhEPEq` zR9*wyUk>or+dA6~O{ZveG{1v|($3K)@F=FD=P(AP+sGfqT4@F7Q4yPJe&*q4o<^+n zm-nW|h>Scq*CUIn50=?z*zOX)dzUlEA zlRxKcWx6*>6oJyses>Re|0kP5(TiU1s249*D5Xb{%U_kPHuk1idl|KW5}TI{ZIyT& z1V~25hIs57T)*QEn1Bo^_r+Zaq>ND=+Z;7d@jPfJ# z<4GN=r$GX?X$I{sGR{cCo;QG?(;M=KK_Ho*guiYxl*4b?~pPugo}guFfv*uF+nvc zx`EE^swL0|yz&}Q?2Izg#npF~e>wxjyR$806Osdvl8MFl5Ssm89QeO~(Ea_pm!Ajs zl^<;?+MDkpHfGy+U4pW=#JsKhQc4Uy3{*!QfXqPTlkc?Bmq>I$bc;kgvf!!p@Ht~# zjHeRRGiQZ^p6u;g7oaOUwR4J4YHv`$mQV zScT;HW264{V7*^TZuerVxptd)Q!IuVm{Z8)i=S(ba1kig+~+W!a5YnokJB0yzds0? zpS|UdEgUv?`A~(wkkDio9K~VPeea#ONJk$#gc2<$`9_`w{nZ^HNfdwo6CwkF54g6to$NfoBoUm` zqfdT(2NkNn!BK<0+H044{>wQ!Gn!*3{&vg>!5S5pqt991_$1SR(aEVh$Pi_RZ~B;8 zfY6~JB|tpZv5U03MS&@c?C)vI3i@xSt%>Fc^4fqu))*X@r!;v}g!SOyOy?fcYDa_x zw;hiFsZsN%l|4Sc=M<0D9~HP+-4=d@mB8~$CR7~tWt4_*EZVhDoH;JYUU_WDGS@-v z$qq9&tkLf|I5;3JuoEL8=muyX(NBCh<7C8J(H5aSivMfJ3qMVhYGeEI!>a8G$RhTQ zycd<>9jf&`K(|P92A4n<)Yac4T1)%bP-vJeKhGk6DZ`bc0-6-Gxcz<(1Mi7%7;pB( zgP(u>h;psZ`6yZv`3i{+A)|C5vgiK|Wx8eZ?NJ7xF-RgQ#uyqd?Ni7{C(q@};Gbwl+k9o^PllD~% zWJYe_+1K~=V&vQjev-$Cfkz3y5-t1Vlt8_=w>zg>3(!ic#jaZ`9vCiGRe*2-S@Rj^ z^AxYuEcSN$*%=_cGQdZKa|HN=S+k_Q|AV<6lJ;xy6Fh+n=v0*B{gJd@yK_*gtP-Jwds7Z3Y&SurfAmYLTw>I>)`Hiid}E z7lW7u>C$=$h$1I=;>a5JRfXFWW#v#C^ESpxKL{_&lfF^z7Dr{eUd{P)a=sd7)_%P^ zXq2y2Cow$)mi`hE#3J1)Ry#oBdlR-kr1bqI-8G2n=5<`4ZD7%mgDwA+9fx;f8+;{8 zD=V{+k3!UK)DyK%G1AK3bFJt$*TBJ{3yukdq~4#JVi~P8K!I4lh4HjHzOG;>)YJ?)W~i_m)jQlX0%Q)ZJY-r6(Gx5Eb02;Hr0)wmoDZ7`?;kge zn*!(;{E(?@yz0TmR1GjtO;(RJ>omBas}chjS`d*g0>6w=?c4jv$jE1i?~e_2|Kop- zq%)o!AfbST^3KlLX30o~g@w|RSujsIv;#)D-fM)nt1AvAC66Cq7^Rk{Xif9&)#agH zFii2<+X^Fpd0;uvK{$+TdP0xx4nGPe%_ZwAfK|bBsgv7kY2I>!b#Tp$@>NrLrg9wCbl&i_UTa{UNlE_Xltgqub5uWX z@%G~MvwV}u-rxL>$Xh|j&(Gcu*F82Aj$=@fI@Ee5H3d?svWg0$mf{Q`5g8a7_N-M{ z@VKt90(_Vwa(MB<>>ydj-Z=c+BpI$i46s8?2A*M$+U}ofzTiJhV zc7pfnKl2B5+ouC*Ge)IEf)^(449qONeaYuVhno*W9xhhl`WGub<5<_nSwA9Wb4>v> zjerd|$U$DDr?I4rty&3?y1b9V~ zOz|Wx>B9#Io+9h%#oi+4_$bSJOhWvB6POFhXLDOy+0&K|qf%n{oQC*+%>QHf@1XwaCX$c<9}7}B7!*UZj@@!Cj^Wk9@u@?#?JhZ!Mn%T-k47*%VRPy-jFrg} zQn+6)@&7NM?(~o?X!UU#Fyl4(g^|MB__QxK=X=sS2{1!-~r1!!`Om z@*aQcEI`lN=G)yF|8W;M5;uO9OIg4B8#CQOk7QyXIlyj*>|nxZJREK{Xe}z%48SlM zE$#cf;lh&Be#DD%(+6fB$ker($gBPK&i(xT9cE_8fHBk!ATlZ@Wyc=Tm2(`mlBVD9pKrFRC{nEH$aIwIU;iA#E%}C9?HwA6l(MyA+DN-hZBHZ%%u$A8U5UJ|kvF#7XHdjjPL{ouhQ#k?uF2M+~B!NCEyc( zDs%H;O%4C`nwpyVs@d-rHO?+BHEm=5Z-X9L;01FAzai(^KfgizE#W@Sxo4V*=R%4L zvr9lChs%~nzsFQ0*LszzdxdO{!iAuoKx;6Lc&?ICrn{4|Lb}ANQr1F-?@p`sxUhfl z*>Q=Ae@S7+t(>tXlO*fAai4lji%U7G*B**y<*_u3D{gxbhX@67ztzJx;fUcb+x90z zh<_M#8(?<(8?xew2j@zp;rhET>uU&gv~({G4FK53F7~@pFf{s zq3ld=@;?)A)xD%n_%)jN=FL;lm{^soZD)OHE5M$!WE1GLiXR6A1RQJ(q#l7J?AvpZ zy>H*{K%@mnX8r4uBTvGFj$nTn`8oW zYwY-7WFYg4QWkr5cDCWA^bqa8o2+`9v$M07-1!6#85u=IOffOBCY`{}n)>gEtqEv_ z$U;x{6_7;mRctO?od$e;ndo0^Mx?C}wzT8q z^7~0#s_3oa3ro+M914bur#C0RVGZ4krg?L$C&?{rZz=|>`bTqi;`0>0sw#6 zZyHX(tFOO#^R~>{+3~78sI1ki^eB2YD>4d``QcoL6cMG~&XSQHdyuXRjFIh6pUSJC zNs~tG=!uz)*7C}#=6^N|QTgrUVA6MSYghTiFxHH+>=5H1NM6aC;AuhpmFMCb*WQ9% z#>-BuXOum*g|Et}Z=o$L!#@65y@%uz3yYeu!$Wu;$Sz~a!>u8q$*fU8%dxwgg!2MWCVX}(&w?8E~$X)d)RQiuc-Uiuqy9}CtSHpL6PW~J44NRf zs|#LAlOb?;1d(Ih8xxl-h>Z!V>eI8czaK@|&W zIQ3Qg6JBVtm zwRy5#C7eg9$JljumPJR;)W|pYUHR9Mk(eO7y8QKNtwEZ$e8$Ta)Oneb)Ei<20XP#yo!WTRKz1u%86sUj^Kv&LJ*g(6TXCYn!fY0rR2>Y(x|`#~r4+ zWi{!@C=7JVsKY9#()X7--+}%t@E&PYVAfi71Sb3`!)ICuVoM?9^Q}@YrS4QMr}fBF z66QO?VV0x$xzFoUYI(&rEUh5)-1#e>3aamp8>D_Cg`5>mYqE@IXe$0t347*u&M9g$ML(3F`8d?ozjZ$TxsoUGS|LZ;iBR<^8O${=*gKc=ivKO&$aKP0L0MgKs}#G=p2 z!0YbA5}pLhP_MUZ(Ie@tRZnoem~8%OM)i3RY<9#LeI#ho_aGx&_#XZ1y@0M(@2zMg z1lM#7wi&oaa?quq0hy(zd(k-^l8@w zxgRT#BpIWwKqzD<61WI7hPq;1SV-z**W-ayjTa~fPSv>&W;xJ+brl6&=VmlN z_m*`b-PGPvC&lQHhmlM|+hp%Uno;lSp`rv!BKUtV3tz6*5JZfZn@jKNi&I&B|Ngz) zav%jMU>|Fs1W<{>#pQ0y%NePzpFbn%k> z4WEGEMV_%dd{!b6Ta&b^m5hATPlKwFRFqQjE{;b4RER+y`a-YSSEXt!q>LTtTAa2H zaV|c%eF_R26P0lqToxTQKfy}bW=a5`kXjeWaO&zBgN0VfFKytPwhRs3hHGu9KM@&T zu#kLWj=T+e%#@)d#Jd=&z5VC30=)k>$FnR@??CUIEtm2%RfDdJe*Beo?oR2_(KkOS93kG@wdBJ=rpW?<#31Cb<>G2WEJMWU-#9Xx_aaY-uU*q z(HFdvb?mYISY|sWPxj@uTTNemhD@>o5Q#|7P`iV#)VF}@S|cPN1KNlSx9xG^-m6{O7oL`Z_a!0Y&*S}%70a% zkD`#O&0=#k3yWERFMbXTG!73(fQsXUi}TMQ7pIe>qis)G>defH9G&FXyu1*l+@}RY z_p!0XKN6yHY!ZuIyxdtZ&YFXb9uD{aTq9Rhb!RUl44_INdIo1^njZI5S zOGnKwa0|JkNkpU*=>Gr<%a@#N^qlSd^K;tb%2LRKA{O=$CMUN?$M)1@I&6gjF55yvSPTGOcqxA#;DsVdwt4&d+;=krlaFa&>TH@ z^oR+wGqPN$JAVUPR#j6SC+eW{R)fsNr;X^zBwsEs|&~VfsmZ3sl6J{2mWZdAK&IN$g1Q+ zaeFyvVy-U=y7-^N!^;=`A%6AuvTPfD7kXBEq8Ay0BI{7P|Qu?o7KZSP`$;@(C>Rr}G z!&~rT-W&D;L7sZ4?R5-7?nTghjyd1(^6E?BYplJ6u3qPyx*%k>I#9rnB@<5>Aq(TM z?ypZ_*pAAcJ78> zMzz{;#Co&To0_)>Sr~NriO&&Yi8OnC7pN=M#MY1{<4J6$YG-q+j%lcnhOS=S^E8TgP*LCdjW(0kC=!MRz;OW~ z6>W5b@8kLH?R4Y41V6jp_GR&}ox1F-N4bB@VJ$@_-2YUHdNf-p_4ccxN1p`yN9h2UA?Wpli; zv5DMnv-sZTcvO2UmHOUp9XxGZW}Roic1UEic!EtMZ#=s9FqT0xzR4f0v$^35x(;5D z>pt~p=)Q2Hw@x(}8wJg2ny0TV7|FQirDqEFg!;C2R?< z4A!AcdK}KS6(mp8AfAp7WxD8EPghekXf}y|oE}o;5)`b9C>*ne%ias+uHoj{Apkdn zwf~%=KY*StivS)Y1pVN$sQs82Ei;|2WMZy%@HseNv#@n2fW$d@fG>2u!{@qFaap%4 zP?t7jkX*%v2%utiJKz}#5X`|i*?)1T|E}X`T5qVvCJ+b*`cgysCf#=~+%EEY;1kAW z`Jni#EsSbcorzJc-tfWU`k%ORliLms92*;!ZhHr2!9{_Q2`r;NJCR4e=y1g#?K{K6 z?|EN!79IHM0d{@RY`SA_5_~h{UC5UKPfbG#|$>(IsVwR_sOHMRY7+-Eg4T`Rze67A#2a_E>k0fhtK3RHN z==Y*p(U*P|%3C;FjyF}v>JamLM)p18H#LAe1hy`(+bavScKP}ny*%)L7O~teRceQU z2tZ3BRTiBY2#CqoEu;5V@l-;)wN-e?>-m~AfhEOYyD$}pNl6VWn!!W?wVM7Iim7elsjzC2OBM(!OQS({*PCPI5?N;gi$7aW=sYoiWtSzk%#4I0#;dlU z*ST{U%O!UOXUT%Z8igtt@0>dRnv^`)$E^I$xPfwycmXEnh3@18Pq+POnz$?xIH5aB zaV#c7m~9s4Qf>KKtx>NT3ZE^1KCc|VC^HdkrQXVNd(Bhi6kBU$8It>s^YobFYzn{w zx&u2__5HS@cPYO|ldJH-AJ?hL%u#c)Y7eY-0Y0Gq_eR%~27DZL1-vw-QuN?uCu3v` zy=`3x(AQin1qucc=a2DoI>ne+cloctH-~+X-N6W(v`3*{A@12D5o7lYdRCSF}1%R{(xF;r3=#ukjcRH>3$}qMKCf52eQJw;|;6g zvK~qV1e|1NIwogikQHb?$uSI?vm8Cb1g_cMeL!cfUw>=pVjJml$qJRJZN5DMENn83 zLY8>=jF;g$ffv(=cGf(mHwjG2o0^+*!J`5+^)xUC{TwbTDUlX1bG*8^)nsJx$>+Un z;l#?9mja$A&!-Ms-H3%nfOW&l#Wqm+3hWXLNZKnv&h+wqb(zWT?{k8JvGPpWh%|hB zd{(!)XYkTg*h!lyeYnca%xne+D!XErk2Z+wjvHeb$oMiNSyp!T!L|z1p;+*IvV#dr zUbFI(-9D~s8n0M9<6uQf6{0LAOtUib4||>=A_l}P5TzCgH%5u)pRb1NgZ%vbdWl?l zpL<6-AW~JRa6#W4>CW`1#`)JbH`z*SMBw$yv$+p~c9ZJL%F6UAw2BD|sUx*cMB3kv zUyp?*j)l13JcUwnvLEpP#Ie{_0b!@}{Vzb=7$b7y%&cl2#-{o9(6;>^0zz&Jk-R6H zBPA9trRZd(>YBhqqVgu%McL$Yrk;Z=x})u)%_=aSnMzS#SzGy8U}AHIK^zLgTL)tW z#duq9mWl=hYz^%kdlVw3yjBKkSRhNOc}i&U*H6CUX4CP0VYbimPw|7FYReoJDO8f*<9XSP_c0vqAd;dN9xc@%-7lxqj?SvATtCfo-i`$lPRa(;7 z7W^mAEk;yH1>86qV59&Buu`jP;8Gjrz5Dd%Ffu0u#BH;@9agpc zn#qHbh^;@Gs0&a3!g~cswJF(Z2xS;VZY0JTBA@a>Z^Ccs58mA86Pa?O(jZ znv$AI!1+bj0>texZ+Pq>nKl0s* zf4FdZ284Lv(ee*gJQ}hlYE~hTbaEgK&vgCCW7MdPy}h*sruNqXRf~XYa2zq(Shn21 z>wOdoTbSLa&a+6lBJ9*>*DBUw&mE#&<06YS2pePSJpWrT&_Y1lIr8s;*&V~L%G{N} zKr^bM0o>$g02Dy?cO6h$q%49_t^5Nw>UMt*b(`X>=I&J;_g>KpxfISs)gn>w11uHT zNM^NedIoP&+Q!fxdj2Z&o%CN*AA;rXnv2iu^WnVb${8#kle5h0XKm+yX?B4wzIHEL z<2nu6?-i~^TzGFggvnSJl*s`G?V#{%8ouFhA<~qBobFX3~+6&+g`DIuf|lZbQ(`Q z#}oEX?iJ<}wTJ13M;pg;{zWWd$rUrZ^X+oU?5H=?t2dzAonK!Lw77Jq#fjv|;SdkO zF@}#0sJ$}!9Aa82NUM7D(XHcy!$Z5`s^zQZz*;nnI2T!HZlE<-=oJoKSuu5Vazg5o zhHWMmR!R)MU=69iqM>WPAln@u0H-}tz%qFj-I5|B@5jnKw6p8%?#vDZwM)a*whvNs z424prOVo#Hc6JtN*uzt*WbP!+v@{5w_!!`kM+5%qKga9`kOm&`YZ5$ z`AI(esFKGfr}XODW6A}pDQOv78Y6vu-?B37Tj&eJSAuQfB>puu3}^1{BV#QIOZ7nL zQ%rL&^X{dmR!o8Zwt$s8Lh&BWLqb9sTif?X%fm&@KmYvtbCm+isQ2&hq*3OQ%&xCX zg0?SwG{z_GbK6kcZE%+^vhj3t#%h~@JBi9JQ9Lxgsp<#V&Vd~wyW!5`p?r-_m_;7% zX;T8)9vg_}yF=hVF{NmujJaf}-Th|e@q{nM2~9FxM5*}TkBjT#y%ei)KN}ohnRsy=ddS)>I3(6@D_VD zUNJa77PyG7RY&e0>xr_n{dt|7>uL$EF`T!Irl{bGQ+nAq7FnA^eENR}CCX((tu-3L zL8Dd*x1ZZE${|3DND0No@N{`uI#7udg^bwYx6nttZLy-qL32M`Q8?XOT>X<%w6Jir z&_JVaVbEQGxDqP}S8M~gIQHWVq-c1lH`rmng-`Azno4$O9C6hSVzcNtjmvle&)C}7 z!#^Q-YGu}fpj2w6arz>>i_hG%BZWl?5+ z$`0D}AAZs?WEqy*eVdvf9hl#FuzHL98q`856+&jdbfa1q3ySLCGW2sGT*{H$ z76Rd{_~7wWy^o6>42!UN|5N!VS39JkJt9-iUnY9w05C@*xcTAr8m!iIkxqxFBZ;|X z(zd~SQD#7M4KP_^-r@+DjrRNdw6A>|Drzroe78E7iNd0DB2y_M8tpl~rENKWh3T?A z8FSFu)@BDTGdgwdx8A^30!nc9frN&-1Lku6aKa3I!x|Zmc-UnMu1lUwyRH>_+kv8$EwZMl)zaGbO@5i^hF@CP@=6 zDNo3?kbuC*(GFB_752D|Iu7~r80*}YhTsY$UAedF9sj>UC%+BK%Rx8+nI&{xvCQ&~ z|J=Iv?Qq&hYiDoHcUat4nU?LUj^oMC<%`q(J!6rR?2F@^lJCxDckE4DbDCZxH@YbAS=5|X-RUOvSp7pY zuXwM1)Yky^Ld7koS)3-~bG=_}zo>u0(qOLmV|;X!-D(fV`LZT?6S48LjgW|_%yO6f z9tmI1*x}&v7wc3$!?MbutNfRAb_J>t(1`8B{SNMTKf3*%y_3n(Klzz4GGb`3pquG> z{18iPHEs|uEcnrL63Ukjiz6}8I3nk=2kwW zA}-I8D+?ga23A(VU`r;WFFh~#5{zEXjyJo%uo+ZvkcQwe_iQ&@HGMEHP_T2|zlP7>vENoOej9o!D|LJLC zv97oL@J9P@tRJAkHEb)Vgo)4UQ z0$JVd39Wta5If#`T3_p? z4mu&or|3Pnxzo??9UNm%x~v>ApadT5kB}R&@hY2Y@TJ15t%aPuE)xc)s{$z-U?bOO z|3R$F65O!4W?fq{<1NJ*r~PR}FAc+I5?`bKUQS1H%QlN_lLfm=A0pb4?2?^gwMh}s zl!ZR|)xoUd9&_oZudjh`N^8IHCY8$|KW^ffNyZ+n3v(~O!cU)0mdYC=g0&Bs10GzH z6F80!YyXVrgVuEXm;;RW^XcwP3%&S99W}9#L7@T8MTDAnFWT)z2`s! z&|56cf&dWRsn%Z2s^ZT0FtGE;RLTW#xxJvC0ao@C4Tz^$ng!+$p)=uKin_RYI!hs` z)?k-;RO!}@OAde`xCjA=_aga%ifj}~4pneVyULDfSgr7GmVhLjmXi_#O6eWgsyVDT zAWo)>Ghij#2u?9VA3mR{!NEex@~Z9mGK+F(wujicxlK+YMGn@c9@bH2X)Y3PY=YW# zxvhY-s2s2*&UmIyn+tc4 z=vI53-)p$C;jy8hsCJd+8#kKI?u}(s_pL0@H0xe9?lngS{Q)C6vL$Q~bo9<|sU$fHZl6^0 zR!8fIVA?<`AB$XUV1v3VL-Cf{1;{l>Sq|{!K!h#<+qg%3mc#;4<@kp= zqxf%>%~$9NRL6)k&uxPjFi@X(G`R*pqzhKc`Yds{){`O>Hkc*TDJCrQ&4!kxPq;0^ zbI+jrn8cr22PeLL=pTQ;$g`0oZcp?Un%KX8ppgp=OXPFIQl?RC`tjpUTNoibjJ6Y6 z+KU#e1)&|*u0dpp)i_&1H-%v_j5NiG2XD<@N}3`d#2v2vUR)~Btlg16 zU0Xi*3j3V_wgFddIUms(&1{vt)A^zoaAC1zgW@OHqbrt9Ek__np&rfRH?VXlu|A{^xJS@bIEg4V z*%op$P1?=?)~|7YVn{_CJZa|FZNKSiy)Tn^9hPN`8!G|i$c>?y)o6g^KV!L6fgovY znvZ!z=~DL2_T+(?6wJ)bkjN@=ew79fLOzL8VUMVx5V+7WzeWiFCW`Le107dL$vpK> zFin8<@xt$217czO5AXtg1nNMEncMjhQ?vJJTncY0@48#CLmCa>I(!WmS12MPB4gjc z!oI|5-1&+`IG%$>(e~&!Dz!X*`kqE1YT{t*kWqMOsNvk_P9!rsb-bzs_Uq2uBMOBn zycKMStB3C=UV-O{>Iicb8x!Rxk zq3~B(Wf|_yjq%8K=gScbhlecp+h26(9c_(uLUB?{Y}{*w;25|U??QUyd&Id1F_llf z=LN6(0m^WXJiUNG3aXD{_UpI*5DUBGM>L}Zg?hG^y&U4}yQ_bJQ(umPNn*RW_6k@! zi`sCKj1-GDjJHx|wZ^&qM^;X#MBI}|P(HThReeK|+$oBq3)x@_`a_$j%zLi}hq>vJ z1WxXNkBc>jZO45HFkIVTVwp*p_HOT=PKU?Y1^)W|iIO}j&W%k}yQ0&d0}4hI@~N*} zi=!NfTPJ-oof~?2aPsLeA0l~(MKU1C0(kIk5Z2Gtm?4wVDvf{mIDp}xZ)PS9gEfn8 zy89(@vxd<_C-nx}_N}MgOs*1<2si{-%F5ZIY zs(86FpF`VyY*+7ZP);iC4l1&yDr2STdd|{N7WBFn8k%wIEgGMYxtE+=A74D@S!~;i zo2Jrc&)lHbXN<-NSjKH{K@aG$d&~u);o_||suD&Yn-_1|N<{!Px)Xhvp4Xu^=}w zo#3EAIqwg!VRs>}!LU;o>&h7H%AwpYAio2cOac26wg$o{#MwwqyGeh#Pt*bnoM|{q zgRJK}uQm}LCO%EwH5oUps>N>7$E%yPRz7!@uHA8h;Q~lm-2G{SF)m)wC?16d<_Z3_ z@>mRCDF0Y*;cg-xny#4JV})si1!ZBMwc*CvaQTm2K2iSY&eD1LcXuPJ^eTVcHnf&4 z_hZiSu3MD*s3cAMCs*MHGMg)F;0XLIx1$Jt7^XYSu-ZG^&;3hr2Zl|*?-drx;2#Ho z4<%j2sm@TodPzkInSj7WjKas?h3YY&eR=U&N)K(JKO!!R3Y>lD(ypCNfRmf);1@Dv zMuAjR6WtVm<{Y(KA0FQ^D=RB$6^1S)BCU4xeU zm01=)06YNi%h>J-CIkhigmt<=8SGpR%#iEb@-KE9KalaAzDv&qLxahPssFCSO!Y92|% z&&+f--#kOX&Qiwn4t zw}^SZEqrOFUJ#ieM{+g_bU<)K#n^1r?6;o87c#t4c(`UZ4rJa%7wns}H2OwH(yeH4 z`nLL5nggT6d+?EJrFwF(k(Vx1<@#J}j(PY~{`^AG(Fp~7GVCg;rWwG=9VgX|HM z@+2@I!Y!i8WsKtuIxeFWKqgdGn5f^jnhTtkJEv-*Ou8pwPN|;hk4HYaO;-2{(f=att)r@3 z+qPe9Q4|G~5>Ov`VV`+N64 zdyF;K7>>1=PM!C>t}~9~cNo^jzmjTtLK<#{sk}(WC+rjq@B3?`+u_r902yv>(w8tA zNG3y^bq=%%vUL2$%BwB_E!T&<>5x=e)TjuIqY=?-Y>A!B)?xv!TKOAdFf@b1f)KA) zJeu455r`&g%B}D}d<@np-%UE^o^*Jm@>A>!hq?D>$A@coFFpv?)4MT_ty@11Nn(BE zks99{fPES8&}+WS{XWDeJJu=wqYp8E{5>Q+-Nw-|h3B zY#m~;Id-fmF{5~SFF`-kH?tJFijsS^!`y!#pO(F%bw@8V7(QtJVzysSCun9%MH}W2 zIwnHN-aGQbSLDfC2iP9nZPCg8`X!vXu{8J~B&Xr$H?o7MkmvQ!udD^{VV4|y;C#Q) zY$&ncXg08GcK3b!iI0w*}*+v=cNDazEEnC)qH zj9Y(o+}{Dn5#yr~%_Vk+UZ^_pvm%-%<{Ji;7+_xdt#E}8cCkEuFLL2D@6A;I0}IxH zVsi#iIm|pD-d!De1`~o$6&2*t+}2oNNpJZ%(`+fH_n6cZ zuQG%&&mJ!T?ZY~PHQ}_1%~ToX3)6SVvV60)8mn398n~4r!+NlW9bxd6CaXMQTmB9iK;TbE?K)ERnnm@sCX)!Lns8-r%ITO0M!i*3jbmcB+?0We#9!`gy*+-8*(KI+F|m^M@sqD!aydemdb8C0 zU=IybDa_do(nn6X`g+R@s`mvnIL)UIXC#)#@}hY_`gb_i1=!AR6S3EyySuuQgpcf( zM+$-&wC4s&O=)9!@?Xlx9EwOFt?9r1VbkC*$9nTrd{UOJt}|r!G@dT^KwhBzW>n-E zEiNJd1@t#DCw#LsK#OZ-mdoMTJBKC*{i{Q`4lD zaeSKoo%>I(edMIu9-TNEzx7(MNRar-wWpB5TcNg%(@L-Da=)iEEAj2hIfC>7FSb@% z*;puZU!dD^7X1f90i zbMVMN(;ek8G=5Ylqy4(RivQqX+qWUA{HngXZkDeqew_ z+k$1$Q%L5pI{I<1@rs&tZ%Ye7l90DhDhPDZ=xSwHNzDa!Tx!3NBQD4bZ0E^#e zEgf4KZB)3I0&NQpgDgL+*bEMc>iSXPN3>n181jB5%E6q{|YJ--B z+m$&WGy@!T)A2x_YW6=cXWjmBL1Yt_B2!Mx?sk55)&NN;1*O?W-+WF@Ep?d5?N1a+ zChYHqip;CCAACHR*}HwbHwIcwGr@N9kz&__T>Hy!0ky4GVss9n1Z;(6Og996lzaH{ z?d-5qom7OFrlw{|9lt39gY>;;RWQCmejgC_CA$vf!bl*?cD^&z3zq`5n_&{#B#B{* zOlDHwsN%G`oDI!8K;84ryP}BM4Q*DdF2O9J8uQT2a4L)`U9D6)H`Z5dDNnKm>+~Se z&LeI8|WCnzb>g2ceS@dlTH$l0zpU&5%2tUsJ<; zT@=7uszmXIKLauY`FSpv{Fr)DQ(N=RUoOG$)lItR3C|PW|M(m}KTjN=V0e+lSe`2h zf7_~K&5{4~?ntz2Q+sfv%P@Jy`lKL?mtw8zqxToLaH_{P9%g%CoJn*U{}#2$P`$&)`;Fq; z*{v&=8&u(Y3UP_Bl9z`mwHVX67*1T$zRY+4hH8H0^P&*PGE~Mk0!KS!nR$q(et-4; z7}?O`r%1CNhmZX=dNO!%9h&usC;I9>s19wu65!n1lx)w(Gu5l78Qg$&Rt7ff#en{{ zFDzUhDEJteHPhSR zspSHrn$7k?rtSG2F95-@S+1IaH>C!QY{VRnw?<0slE&T%#%yn2{AS-8B^mc5(AnY! zsOmZ_bZ)sRrc%GdT^*?g({99LV>T)(mA&ObL0Q?a9OsVv8U*On%DA*#c0u*&#%KaL z1s5QeTtB+7%yA+*GiMEb-mxnzLvr6GXm`(#lpWdofrd0?gr!pqYiMXF$6)3f0JVRE zk}`hn@B7 zqx>Qre0)4~c1k~NmFR30i6Ycx6G!jM8ab}G2hfH)d>3mtnq}_0rjWM3b%Uh4rtF4r zJC{UIhKX!_-R69!@@U1TL}y&#o6PEhvjC^P%UWt|`*!0GaU>Z#IDO8vSkR{rO?UU7 zdY@3lJRG0!3SSlfBDK2NKb!GMG-I}LCic@6flI$@n!G=c?jtk=|vGf{h$jIbN>PxcQ=ZRN?u%_6Ln}!?EjM z4S9?6FDOXRT8CMPJ2tSx8xPK?zDIr>LK|-Xz2gV9rrgO?zVUw4+1r$5WE;3Ex>! z^499$zk{rcm3FwkM9%3sWcL+fSG9|RT@GTpS4S(e%;DM}d~|hf#@4>-Xn?({Y7)N` z3zwY#g^UUzLvsz@zBQ1CK}8B*5^=YG`SWZfCOhAl>q~JgnJLogNVD-Prpgn8>?T*; zbzkD+KTqdB�@Bsxa;FS5qs}_mtWrdusl?Z`=;c;MH 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�y4&^L}tls$W&evsIuS@ur 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

GC%OwgX@xvdJV|jVA>1oxh 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 $3vHmmM8H*H@ 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

!_nUG4 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


rh_TK?R9f6a0&lh|#8s1A* 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 zʔJw0+HIZ0j->XZ?verjeG>Egc*TzHrUz2SE6sql5+x^~U8?HL_@8zAD&>l&P+ z?0T+BR!94$P2uGlbRKIDCHB@34bTNkw=({0?aEA`FJtt3H`jy@-AfrY;%xo~R)t>8 z80rI5Jqu?3eov=HkmlRDnOGS}pmII*m6OxUY_0e3p}W`biFB-6Ds&mxe=VGqOXZtI zk?teYi-mt8unFdddu_hXU=>-ofnY&wlxJDT0ggoW-+3 z(RD{IuiV+6qBx)zmp~YPLCfL(aM@cGXRR&piD9VL6AC0eI~c~VF(6%)XA=8zaqI#;(YI}!k8YE@4xqglTquI zaEb3Kfd^8!578aTYEP@3pdM~pZ|Jvo%%W5}^#vp1boDvfJGshzR`p@@K1~?094{Vz z4=)B$RIm&Ob!$HNo;MQ+1&2|{kO zOG6!(9j^*P2#d|#P9K~m=Cgc(Ypg(k2s?Rncsk@I2F_LZn*z@BA47f?jcLb3h^2WP zGg+%B65(e48mK*e5W7|NRc5 zO{^VVWMLQbT-{2I(LJRu(hugG30oFSLko5j9zQ4h4u0`hTe4g3sm|`cHH12B3NO(WRT${q$XWr8S6Z_F0(FRvuA>4`rb@0) ztV9>W^*FVqH8N(Nwz~bZmMg50lXHdbrGDrqN;?FKLGk!^JkfKB%64!bZ#&0G=Pj`; zPxAW&;|T6wc8eKJyRZO6aH=pc(hauWKA^Sj%Nbt+H&XqAYXaS(e5czNuOJHw2zW1P zPWXR2n_{Ya5Cq!py_BGA04SauiU5FcLc)-*IVrpnI!+Qp>ek%ZWP7u!hqzISAUAVo zy13@H&1VI!xLz#3XUAF+w_^%FlwJQ0L&u4VaO+(hjToiFO@%*XpI2n;KXv76iSdEU zt?tzV4p6}%-qg1%WQJLFS=Y+(ll&WNA0O+j@q<0j&gAmO-m~6n4U?^=1_h|67LF%Ib<1bxxt!1D5&nng7yl{LY2%@d7ClIk z;Ii}O_&73OdB`lJ#HI-I_A_RO-)^QvYl|jF%XRc@m=G}B_0YWP?`HS7gkpI^Q#mm% z_15S7Ry^#R4|@I57^HnfE{0eLP~nULoxhk^I{j`2OxfD@c)*b{?Hvo27eh>RS_xi_ z(!2-}R4tUO2ahVw{iW8({R_O8SQ5k7p8aM9FZVP_pG19ojVZWyBHbn>S{mtIS@U+T zSMxDL+JGhOEXd<}bi8wIWO!BSZse7QW34@VlmdJ8m)tgsG%EQQqwNh=$6g!ovlSVP z%~z1&w$SAC?F~ttIUX2lm1Up$61@1gWrWwj-g&$r>BYnoBq#e~Xgeg^_1%%2kvpNd zo5Ih{%j_C*zdT}9a5fks@ht&i5!T9Y;OPGjyh!ICoP~^Mcz*+YZ!dDd;7D*rqsJ_O z`xJJomv-xEj73RT9&r~R+m(?m?T=mvx*6~xeuS<_^~4YMt@rH%3R@UVy^XDApa)+P zIm%hu?{X^b2PD++2~(YWKaw(Zg1yrru{HTQu>ZlW)z6Yj&8Fx~&JFo@uCIkvCp0ZD z;gJN?`NjnKh)Yh@y5}Bu7e8~}%A4B;|&=j*z@09hh*7 z&ZozYfjou1M*@OU1_etyaxZGModTOwjQAtlx&eZsQRRoC8E<5X-C@MxaIKuB zaXpZFNM!9bW@(6~Fg>-ngkMDvYE<(wS*v0ISL6C??l|b%0-OA-;^HQCzVaMoa=Y6| zdy8pcJv}EZN|Ot>nM|mxu)Zes{+hj%)Ki6Z5B5#>G0ue>?7{3Qcwcb>+-gQ#fBKs) zG6!Wak2*PDow40CPbjl0GP3yeS-J)z$pA7QzwZAT_eoe6j(3p#Tx2?z_w*`_h2sS- zT&Dc-E9TZaIW>7Mq)*#-$E;^T$x#C&f=WR)rS;KqiGd-Q*-BcO0Rx1v5*GKpxNPbv zlE6XG@%U6wyt=|6R(|1UEV*)|sWF3sf*faVam^C}FLf+`9p=#%zTrd4nrPtQUJIhN zk64V*ODuPJQEPZxc6Ri1X5@i+xg1aH)$-tdk+%LVn8=-D!ni5Q7gm-28Yuk<`a*eW zHNSH&%BD9;xlC3mR5xROnnn4v{27*f{gg#!Keipp-#*jxN{L#e%>!V9$Ey7p*wVN- zsn~mm3MdPxkgv2!AY;giJ443{{8(rACg%oO@3`0_TD_Msw2u*K znr-3v}U?T|hFJ&N@N0xNLL77Y9zlW7>TfL$9B3Q5edl$ksbE9=HS8$6W z#VTf%4WsIRCV&s73FtX-CV_PdsDkZLR|*Kk{@D_}j%znLZPKy|m{VrZ+UI9>87ajT z)I^=3Yu$KWL1dX1P$h*A?BT#^DO56{(Jqy&+wc!XU?2C)6Ut{4T&3K z!{<9iC8T}0d6m=bpeU!{O&fXtKmU#3t$SkeAvW4#@w_#t{;BNW64R;6wxt&L`^!$x zT7A+jN9$LV`sA~P z{_5h{!VSA;_$#XI`=2cialKPgVf~OlYyS5q+`_UC@ZTh7%jb@r(D>E+i=xz$u$MA3 z@z<4~Ju53zl;!dF*BKwI+UOgRI!0Ie18974tiqWJgxAosn?F!H>phqTRSF9oZ+9}I=X+nCw%I9Wiq(O8t|;G+Nrz>IQERX z&D(JztWcOX7?^qdbWN&Dm`l~yysP8C8FS+4kZXfZu#xk_E%mz#A6qF#nUBx5{Z+o^ zqN2`!XKV7V_TZMOGfiI#S~u0zHkIF)VIAY#ZDp?ST7M{hev$p5_muNxo;Ya5fu98F zzn+{szo;njL%wulx0V0kDrbvX-<&IJ>4+ISF8=;`oR&=Zo^lpW)v!EcWdHc@HbsT< z)7k}ZZMjd$UthdF#;t-Eu!jH3XryM%jSu-(gMDCr2>pHB{CR6fkYt={>T=8PODZyo zp}PmLJhjS7ogqbjM73LvQRI8d+a2S)+)|}lQASJtLK+8;ml_SaeGj7@v#!z^n!E9E zNlb6nTK?b0UH-ON%WFsWpTE%B>VA0l*Rq|L4E|6{8dn$%wiX@iYnA6-1w3(vOUu6( zybbXIL;_Fg4E4;bcGHtpkL>?;$?Qi><-9LPhA;D8?^D@u?(xe4KqD+T>1)}FXP@q~ z@K>CEPkHr8fLleQ&lUFBIdJ;*0X`xx0NMay=Gk4QgN^DQ01hXksL@fN*vmx zmA(SVF7kPMk^eVt9Qn0{Q&n9RA4x9R+}hN>r_$T{8=J)ey-yek0?wsrrQf=^>hYYS z>BYUe=hAVxo90ec9gPICTaCXj+xa1^yXSJ~4HtsG?3qV(0{=t`hb6San5mNyk$S~5 z-629`k#m|BTM5HscKv&C8~EJ$MR%wQ*FP+*7DkP_k6a$Cy-8~kkzOpXvg@CJ61Ur& zi|dtFC&6&8d1-(__V71kJgP@ME}nE>wqhy>f@Z6EK(jdDMPEM{WDT+aL5QH+2N(HQ ze@g3XZ9TZ2xApmpW*cjDy9e#UQb2e5Wbtz2rE{Kz#_lh8ztCyUvnMYto`cZ%eC~Z- zY;@nY^_Rk(pCXS0OzzbTnv!S=5C=Lach|QRj79axg;g)=nL6H3GPj~a67a?j(D{D*bCWC z-(^peEUk_A=&?;AoiNF<|8_Dk5ka&|ylqCA3=*3pMgXpRP9uXhl}>SF`-GrBj~_Tv zmJg*=uPnZYKkGD#(ZWYKC)hE8TA#m={F0hdAlLo;g*2VSgxM4h6@l`D>5NHqWVg4l z)gp*?3STwRk?mLBC)c&!z8C|NR;wQ7_6ISnP#=c1-UnPv&<-SmI0+_1l&^E=nlyxr z?g7bi7O}FlSUFua^#RF@mH!4(U-O>fUv=UCrU$M#<6pAhqBAfb8P)Kz86cQ+5#-oF zC{UG&kv%phgCEptzTpmL^=N-I)tU_6CGlKi^Ix_$a{RU{KXF^C+VoG^&fRe6G*&;= zs?ByVus!?B7~1)~mphcd)gWp-^`Ej854FD?P`4CaHEA#WX|Z$T^<_RMoL?kvnK(!k z+|{7k_?q~A{7*AgN8|S&v0r?8kT+u9tV7<;PsW6z2=LwVhOKR>@sXJvQ(gOBZ)hUQ zAo_$nMYV2P{#Pw2`uz5)J@fjELa&#I{HtcFo)t}f08%LB6@OoR&fl~(Q>8nU8_v1s zgYb=iym9Hu1#h+-I%4m=M-3zIQKb*2<_Vtnm9k0>-o2;!i%okdp`y|lyPB)40 z?%n%L2Dchcnc*+3eo4pddvPFFOvcQV8LzsL@Hk+>&6TTxK-U`ehJNROv09?zWj`%; zoL@Bkz@Y3#uXiYlB51;kaX@ z+~{eIF?JZ;uh&0juUnW;+9$HzcdP zxX-Sp{kHAO4&~mHBx_EoXR7wkL~aRi{V#u1-kC*(vaowC^R9cf# zbsCf_oOUIm+-Y)tpf^;~2M2;*BQOARRz%q89c+X5>3?l9NGE+!G!)WdWRPJp*z^;g z@v-$PkbHOy`1}h-rnSzy@QObw|0cOij_P^>*?Uf7^Y=qnU)xI`}(( zR=6jKsj!46pD3>)b0@9p(i_Spe7wG$8JHpb=#Dm?>mvAzt*ZZ?1+qU#hS-S91nC)L zP_#PS2kdO|e2@PD6El}QG22-do(S?o;HunL`iK6(Q4S4!CrtUJHhzlw%U7-BU zn+}Pwr#K}cVAo^I{`0V_4>TTGAVy`Y_u7#K-Xw|4gKl{6_B5~A65YH&Vy_Q<%60sr z_$6;heay($%th!K#c37xaWFXQR1x%T)FC+cupVlID@&m*o!;H1*F98SiyL4H$@)E( zOneIyfVlTTeB1j7{B?#70dJenzU9G5LKp8mS`G0WAWWMjN?ETf0D5n}(Uxc5m*l5& zZU-v7z9UcZsuIE;)%-GMIWme=8>UC+?;{uYQ;b*g3(7ex8HDW86cWuL7ZYh21==&7 z{E5et4F^#~U-La;fRv>`@AD%;*F^wlmvQ9(qWGgeOP{hV_~txg zTqt!r;CFEzNJa7WaGf>xa&K3l8V=oDi?fGqSH$! zlxUiNr67GVDY7NAJyj1uXXx1VN$fkJfg2*t>1dqtw?sO!%q5KaoyUSb14WA`7!T=~ zyX)e9mg>V$f1<8EeX!WDJ$i^Fg2_x6U_YJ%Zesu`oN$-6lU2FHte6yeB`V(o<_bej z3*KKG$Bxyk<-xHUH5egemEiHtXE@O#HUkPh!vj7~41*#)TI#0)J?1ZWmW#v9|3Gy@ zp0y#CKTCl;vvhC_tCedO4p{He%bdgC>4!(Omh7`Q<@|qrgcQ}+f*t}+Cs=I3HN-z< zN57N>i{RcP1gy=v|#YO48ME%%6&;2BJeD&qrL|UEZcyh;CP;MNj zBhfcH&#)fxYg$W*;oz%g;B<+Q!w`XYvV-PfAL*&m^UUvS?G6@klWp@q!`tE4(BeAM zCUF!JKj0t~eR(VoRZX{zK=L!B;Kq1|>lo99e3a|QF~@b0aBx2={*7B28I4`>6G;}E zy?(?4W<6$lyH}KuvCA@JO~3 z_t@xqQ@!NxvKFgV`?Dg4`mw3Q6KFanj;NaB|46ptIdF;4dI%~C?fM_0f>W!?@r(Zt zZtIr^a<#_1LY|k2or*|zHx3UhyMcz<=~`zYW0j^6DU4IBrgD=&V8t?|Z&gCRA2U@9 zR~GuI7KfrJX~_=&1Q7*-j(&@_%Az04I4v~H3{bp9DE7JwQj{h?AXdC&7a$BOBf@IU z$bCFJ=!lNT@k6;{DM&Z#i`T>kXMgl>(1)ydPbUUOl zE722>oVo~A`6@G@?0-pVa=V+W_0tuy&l2pQA{pW%{{{W51+yk;(;R!U?C$jC`t2vv z$u|O50PO|_p~Yf*LYo_-*alW=BXXLPk7o7k17Xhl(QrWMtRzSr8tE8g}TM`#8ee=Q&MiH z-Gtt?aMI)(c|u#VZl%$HJ=yjtK_M_VG;ayIiY8WV`EhQR`Q2xxa!06p_9+eeQN<5r zqvPNR?Fk5i9%)N7fBrzW;yfMx72;02{{0@dlRdhA*Kf27n`W~L=T0a0X zA^X5q>vS&XCLk^Dvg@}a@4(h*4O-2UFT!xBW*l={1hXe^$BYZmn$C%VMnIL>3kabw zu-ujisFG6catoj&vZ(U>p!50FAm!~hZqu4RVPAZq(KbG*okjka`Lo``Qv!=f)aPC9 z;5#0Om~dUkKkX6vCd#{dWe=l~*Uc}kNds#Fb-Lbt-}N%wT5IFeI9|W5Q^Db8Yh5U0 zxDiBxs?aEu?S!R%whlzH;uPNiMlyxj>NMqi(&OH-bY zLTk+ zos+|Qkk=~hhYe}U+j6wn9A4Qul%M~hto4S$hfYnXom5n$S7@ad;jyUI{v&Kv)T07& zzu;IZLgD*Hmzki7(hl&cpw=z+r~tu0jtqookb#8v9?BlR!ZUowfuA^6#+wPy&t5;Y zTzqf#+9@YLm$XDLocbEiaNE@bu$jP&$T9l$jqaMzXP=uU_Ea4}k6)DUs}X~*XqoF@ z_5$x8M%=R=cT5eO{r&Beb93wRQcw{*eEb)Vcjwgf+Lfn>M(&>RR;L~1yS?=ePE4dq zVI113>RRZFybSb>_%7xWd?Qbc*c>|h@^d^8{Vcn<3E1a9v+Liu4~G{vy&BP8ylYP0 z*f!JWNb^}qzp%}HKz?R}H(Ewv#+g7YG&HoL7d_H`mH79HsmPTwd|qnN7|3-mOi`kV}nfU37}&#=4zeFf%atJ>F{BW zsD9@gVKJ(L45B^mlL_-~Lg!+Pu`^Ue?X4%^B~<(ftu1NT@`t?t4Cdt*h;fHMYXS6d zSmCydSNNljTncsxSBRgJSPWBK;a^=&yDBuL3Z%X(tXi}CEue>_hwmJt934fDm5zN^ z_-n~n^w10U$MUc4 zMIm|L%ZgbH4g;Q6{ojrS-J~PvJgAUFzw*VL`gSjIfcXVI8ha1jAo>~q9-*_QQv?

*TgcsOJZT8vNVWW%u=JbWURl$3|fuWc$W(#6M0=M~nP+ak3 zX2qn;Qblsc=qxxPNI!xbVd;d0pf;j3s);`vr#z2d{g#Atam@1*daNo=Hs*4^@dc?< z!%a{|2-r#F+!&$56pY~9eTIWSlGeJoJeL1CX|1jY0pp184qhrVO$on*O2t6; zJirOvYNazTd2oofN^mT4`yxa;wz6loM(fUAenvKW9154znJ@?wtDgXs?MMSGn-AC^ zqyHN1VMQW2HQHkz87sBfHL-kYLs8?ZALmU+%BCfr0gHl!AAz^eV9>(s3amirv$=jA zu(4Bd$5u$liaO1+YQP%jm+2r=s?~hn=z$^oKA~Sb7TrQjmrR^ z@iw*~nqR^Mn(a1dAoMQNw^yGZcmK6jzT`@5-4HsC@*aCxsUCH`%r1npYXuB*4ICN- z#Ju=J%^QF_@TY%{xR4ExIFz1jg3kmaQxQk z{^kNCKdR8C66pUXC^D=NDdJoVrr1B+M|Xp8ojt)%v>8hNzSP4y6BV+n6k`x(0?*)Y4OURn}&rBg(hl?A15k*Mw?dJ zd>_g*l7>9wcbgc)#Faq@Bp@F>Ph{-U1Z5c?p+NDx<<02~3F%PnayH7711qeVJgJy) z6^cXA%h+zzm&i=x^Axs`NqIGnUSI+XespGxg}6y*`Ko@4sGg;8o&Xi zWQ5)-K#}4v;pYDVY{>l{4kM7?-<2S8Qiy+sx#OYT+wibSHrjF`dQx_3CWTOX4>{o5 z>ui`c8u&C(rt9!SwZSDs&}2FwNFCH>SHlE`$lX060ovV1gSo!tqRl&_4>xbdk#0bU z)c<4O+Hf&~tY0-qhRHZ2S6O!BY=H7@?)5Mm3Kp6^OO(wlOHi8|8T;(PIE2tZYCPB) zjb^^Rd94lSQo)ZWkn_w$*I|CJ09vD8atqMe@-15ciRTX4l}=HpUce_#!E`chyF9?3 zb?7rxTn4uFX{FB~tvA%OkF!_AA1v2+b=5cLLi7*0CnaGKd_)=esQ%mlGw2mL(mtjp zHc5+T%GP>ca?!gwHtA6gqTH3YA6$v&@pzTGVTUM%Yoji~*rZ}UYlN;z_WQe>Fd5uO zPM?@s3HTI$!O%rwyL@K+D_Z8n+)6HX5pFCW;QvhKlEQR63{K9d;7d^c3oSH$Ok*)5 zhea^A%{YEi&O&bdUS1@8`~r_|z4(aHvsl6`9(4ewzdPF z8wsVYFe6fzdSgBXMvK&_d7EA+ohl-?aP%){M0pZYuG&}Pcz>ypUbL7wqJ0sk7 zC~wE0W724IC$nSql%E2Dd?(jZPsgL0h~-`7;@^g&m2Un>VR&(Kw~ebTUBTTN3fK1p8aR?%kVFNBXxVIybK=UtNk7Gzi(hr%#SjAJor zUR061CZ(DA4*enugDRq7Xp#mOI-yAfN*3`VoDHei`qtA_Po-Aq4@}z)_}2Z3tRaoJ zoW@wgbGn8Y^`gzPHzd>mVnQt|47x#50KjW!`nAYqv+_K~;lmQ<0Ah3mo|EJ`^sl85 ztc&Yr<<;!Qf^OBk=fo31#+UBEL4uM?lz)eRb%3@_+7Hn6!-c3;Rh9-m=UKgXKUR_B zsE13%mjK-_5}POrp<@;uOp4TyM&Sc9CblIAeGaaz2ktO~CM9dkX60=Uz^~crGx$cv zVi=Hp{}trf(F>s$^w9(~#_AL|JMJt@2@)Pg?82+!__K1z8Q;~i-;?Bdj@mNOLdG-2s&NaI9}f=`nhLi4<|1~p4pbL&r|jBUG&9NE)Xwd60ue?28KZc zHoqVV`k{cAR9phyPqa3unA!AH5zjx%k|i*7I=OAl=fZhQZtmB`FjHK(s^6WV$JG!t zQcL!OH*bRP5qtm66P$`*-v@)Bj@;~?9|vm~5_7L)rDX`BJ8ynbjO7`@4=Wyz0IdSS zw>qFTRJcQng8Xk-3tEPt-G_n1^LIRcp?10!1(b`KH(zM}ywXth79AjZ2AiP?29^9K zz(gLxr!eCp_+$hQ5Rq;ebc}8f2B9m2LF53TQuOJYWmF)kTY6eMD z1)*VJ4HT1d%4>zLiEcavOp^?M`i3V7tB0yCPx7hfyI^BChQ9Uw1&h50B~h>PQ*L29 zc8xnDNUuPzmN*602DiYjLf#n{4BcdJ5LC83rua{4g=lD+ z6BlD^ZKydJ6j3MT+QZfzDS=&LXM+PzX$F^p*Ll2K3QtN<>@%`NsQ5(kQwt@z7vYFAns z>Lr&=T@08*ab`O}qSe*<_o!*uy5onRyspHjGpXOY$(L zb^~E(PWbVv94%(=-EwUfCbCI`rlewNMe57vP}pChFIQ98Kf`gR_#Y}(N1i_5{|)*5 zU3QCAPov1$Qv*Fr-;0Wq^9}YOJc0F!UY6^nP znWacJTcH`CPNKQ<7$DKXG~7u*0R{4Ja?s69vN1DQ9ImAf&=y)ZO2KgiyP<89Ru|h1 zr=KS~FjiWX^NfkKHenZk#rxz;zHn`m>{llJCpK+T-mc0gmDZz*J9xbOp~Gy7GPHJs za|Uhy0rf_Qa+42i>KX;JBgwipJ_5DMFe9aUKpKV%V9f8_c=!ehA_s#<0V+MTlEWfC zsTHEDNH%Le8Se&D zyI4p>uD`qr(**KvoISJ!RlU~T0*`+pX$K*QrtH>^#6$_ zu&@+xLnYQP`cXjO#P?RzhuePKREpe)UsQ`x$TZ5JTdc&>PIV|h*7w2pu8sE^Rmex< zEr8BdaX1qMHF32`5Ki#gQpdsxrkA8oDHW*MY9rLXPVAhvtyX9=fZ?fDDRk>@Z8gp~aDi8;h`0=dM%YtlzTJOug z{~K46?q7aTb`luv%)qheiLlCqDy;6l!ohQkMOQc&0)-W(;$7 zH=3S`WJX)%qKU@G3%G4dlg3Kh}J8r$z-@y^Vm*xKwl2SM1OawIf^ zPH_G6HpPtz9DQp-YMxH^f$Nyc6c`Pw`IsryaZ6yyD3zkusv=TZPCIkQfw(bTbj@Kg zj7ukLXUd64b}ofC@8d8?lL7|k2XZ@h2}kEf|A48J_=)X;)>3zielIjGMRkY_6XyV> z@1Ub~>T$LtBCqY)ysEnXeEXrA;=Iv#khXuBpg-8!Ne2#Ii?@h_sAy-7sW{Cyj z>+q=n6AMH>N3uDkTe3!fa33X`^=*M6)SK|&^H$hFe_-(}Jmt(Ng#az&S?Gf}a?>cm z70R=eT70C>`wQby71dj2dtZ%Dn(l8{Fjae~XU{jFdB4z%WSHfw`rtU``Xpu57gIP& zZe=)I_GaOpsnDb*7>HuM4h*=gdQ(vOAXR7}8qh%g?mad|n+zGf89!vpRy=sq*3%kf z@-?6o_kBr*<43b)S9U%CMRnWh5wN8pMMtjxK1>=J#bq6Q+6{V~B=ZYrrm4}V1L%yQ zTA17;uKx+9bqIVudDTFL0vAx|M%EfL`Cyh&?5tYMB?hWTfMXF8T&=saS>{w|t@D10 zV~HDYnsTy#jt#e$6}b~Q1|x{9B(V#0Oa|l{L?K?du+`;CMiS?Nx#azrtR07kiyxtwY+ECfkP0n zvbXXgOZsWjS@JQPwKS*Ap}*u9ITsLQ=D;yPB@oSlCYUQuVx{HKud<`3P-qqIe(2CY z_eUa+`i4XG8{}nIpII<9a-ud4X{eI-8jzt?$pjLxs7F$r#;dR_>|^Eauh1^)2#SVc zQnO5daL{I2HIh`7gBUuYh^Qd&Hla8t)T z5)SSo7sEp65_Z1XycDKmq*;FKOp3|Nk)DsZ!2fX5=54)NXB(3mj-XuO5Z^#wrcY>2;8EP(CS(`Rka_*b&k<_ zz=%|D1LxYLFqU{JW0e{o6v!{bLIwJz+N$`Uo~`!(p8XOzK!q)6GQ zVPZ`7wY1u?Oimw!NWafBQ%qGojljGrNntUxq0__08OG~D(~Ivk9>Oeun4atslv1#v zDdqtrxIc+p9wpK8$VR7Dp9Fhx$Egt5^&j*{ysY+uw&?4Vc8R!EIy)DLgMOjY-j5kt z2-N<89jAG0;B{4toM$h*uSRwZN`mh|em&X5$5Z29G`5$B#ba#{9p3mVN3X^VV|hy!^ukb zAgM=B=D!^l8B%AJWtT~M$-TGN4dJQX$)EKHC$j=n&C8ixaKhRIK9c`pyrTvk{5C1c zDaNJ1S9?3^t$j@ym)U7j>!P?UJNiE5vmr=&Xm5tmcC^D`tG-dyFK0WZGvVfPS?I+p zZ)U8o>XV?&l2~1BT`u>s(S0j0u*?AZm$lbe_kWJZYR{+%K%Wkp(&v+4bjzK{vO(i_ z!w{sz@^3@G=wpZwZUKzRMdz=AM#LfnkyVDJU-h_odMhS@0Ha#{%2csDjg%^vgJI zg_b9D$kf{M`Y3ja>%{?Dw1NRKcMSr2d`3C`@WRqukL>o6ti!T!${0-LLp2N@39Y@K zt6yT~aYL5TG?05e|7q>6hkDG@*Z|)kE&-k)k;!|h8=j5wr)vq zgR~Z~v~sLBgKF3GZ>q?2kmgOx?-~q#jXFrm;l)@y8GTZ1Q9yoBC8SUH!7!kW6g|6C z1N2yedB6x^a?Ao3sE-aI0?V>ur+^Q|GpQIA4_1)~FA-1U&$>YA7bB0s zxa`5mr`hr23n%}j)7{_X0i9@>mQNM?tC07z4?elt7*(;LAnSLbtwM8?VTlv z?qf-C9&~}I^kwL1@Y_)x4-_VIp@;`GAsG`OfaOC=u~H;E{4Rcos!FGs66uR)mK)6H z=mK;OsvB{VbkyXna)XE&y0oyE5O%zE*Py-D%;=iq--29E(3GSbn}D4#!sDek?SCU~ z?Hhr0pT!XWeff+(>wTQc(t(SP3a{Y4WMJHte}dyBl0sGx;PEX{&_82TEOY0 zRQGISR+#9^D!nyo!|YvG0|iYJFk_+U=0)zlfy2Q~GwAk0i@b#`VElX+SU_40g|tg6 z-I~tPQZ=-o$>l9eo}v1fEV$>ppE2VoGqcVS(g!dF?~Up6ZL-ZnbDBcTkv>WNo1r#4 zVFO&2nGiw6%|E<)mv4yzs6l5X%mAg$A7kf>=j=X(pw|Bmy_(>D~Ag`NB18+wAA%np4g8|@A;f}D)CQ&{{>SasJ} z^_kK6mTTjU4h~`xDV3%Fif%0|WJ@mI^BwP2g4SE)ks1pau9CdC;_jQPmA5m=jeEJb z#&|){X5p_4lTDpn0UvUN2=!r1GJh+y z1kj$;QO9~1b1SK%1csCS+f})GV*G!|o3tnk+B47ZSyPT0rBN%n@fn0_UBoFLz>Wl? znI4SZg~nV>@|U)34==5SarV(xsQ(UD9@Ktk-GnJ*C0(DKdH3dH3YKN6Ys~s5o~Oj% z;MBYNgK~02hi6_eV~b-O2Ok+a+e%DCM=-Yv(zM@>Y1Z9hyD^#Dsz<{q9&q^nKO z?&UH(St49uKs*gki-D>nqFv=s8P7s2TTC)6JW0fiTf>rTp?!E+$oWe=2-p(*Y>z{w@C{Q4)He~F68 z;Y$$Sm8y*`d@W7C)&lB-2iC((UJgRxW0v_^_OJY5=5adU;ig8<5zUh9;<<7 zB#$ft8a%-Cm@&0~{==fN;8gvSs(&9Fp32FsC^?*Lz-LvVwsky*79Uv*) zb4|(8A6`9&8u(0?h-~u#DnNZf`~hIWTo$(QjV0(sLzm>6two4Q#5h0<(P_$R!?lAI zlez)gN7v$^(i6bP4oL?W05=4oA!GnEC3~W4AYtaanB9l46Mhh{oJm&|Doc?kkX$xR z*FI6+{***^g&*|sHChz8KHl#STb86Q+Vs?L5#aE#`_^%qVBQJEI8M`A;(3?Tw1PJ$ z8P)zlf}+>~KB6@sKfLwsJ3EuYhnt_QG8*(pbFNo;4mu>!uxsgE0hd*=8j4XXZ?-b1 z(OI+R&D}HupQ%2GTyjd1kw*DKSAR}{=zZnwuUV3X{-@(upejlVwKQ3mcviZ3*FdBh zqn|T;0V0yOi=Zimsj?hxxe2gh3V%{XvXd>$0sqcdKmL}oab6hGO`sY6KoCL^+T%)C>0{}#r|>ZMx4+YP;0R=*4nvCJKq_DJ&8InNB6hL zZG6d?_mw7bD4Wb*0(gEZT7ru98zb3G88x1$_-FMW&?JE@hvj51O#bVPC) zDTx&ag@embq2g730D0M93D-vLA4i-oEx++8%koUi_xXQ9a{)~UgoCffkyFNUWdIAR z)b`&<<1%KRy_~>>-BOo1p5(kT0$(l%Tqh|&_0j*K?6oTHW5td-peYxc;$ak(0t0}*v+!B|M3&Yb>TwGaw6T*$ zUNfX+m(iYeIF=Zo`uGdfXHWQ@)Ee0L*~G2>&W{vZ(2K#>Uk%eosi%ksh!Txl4OVlg zyN6Gh$l*@K#3tJkfMOKntcnH_bdhKD7_0zk-2=Oh_JPv@h4l^2~HB?_^@c9dByLG^LU4VQ2siUV&$S}__J4bEl@_@h3Y?j$xGY#?<# zAmUaW$MKCkz>wmdybzcG%M(F}Pz{8ZEAGRR@ZEt#>~<`gZd8|4V7*qr_VFHaa{EG8 zWCUj`;j3==B{Op&GCr3pEiW4Xf8_ z#+UrRF)Gy&v<-T^k14{%NAAM5fZ!D?r3B)}$xsiohU5g1?wPlCHCULqS44St-vt|w zQbwxSN8`w>%N zPE|vQ5A=g^o=>;WyStGXp8#}41|^8(L~QVlb=)PL(so}ixRAGN=c$ zsuO?+B&b@>if|o3$S&OkGs5$$*K6{Zv@J3Y{Q#^*o6Gp$Fj55NG!{t#rDy*}qlLGI zLnJ~GtKc@TqErF5r^$YZjfmw;1%y~o%EQ%z6Zxfb%l^+PREQ8Mx;yTaSoUY&;WUsi zAKKyplsL`wXsx)znz9BO9(2z&FSfnEfxma3X_fMOh`6B-rTz$WSEZvLOud z5k;JYy5Zmg$CFR0`c!kXTks9^g8F{G(LF#5SA;>NVC$?8XDk|HtP{?^x}H)5-6h=h zhG+T_C~<%c(y(Zb4C>rs%lYCW71cEGn231%$;7a(6Vyxtn0N-IZ;S` z{s44G7B)dF4`Ulg7t6rCfFAA^ER1Hm<#1T6^88seJ??IWdgMXX+XI;jc#L%ft%PI) zOf$M1I?dsK_3fd7zOVgJ(2UxY#TbjCAUy9`DO@Wv9SJlNbPV$Q_##2x?~RC=LZeI?SW?P zwIc_aQO1+48l!qjsQ?DY0Hm1qfZ+#_!GUY!o9xRCt=LrpO~@wGjatoF6a*2&Xt@Dm zBu0!=VK!$duO_J&rodda2|y6$s?7l+kv&+xKLJL8EtKqhn9*ccaT?Hsj-ryLNac7+ zzfG%wi82j!PQsY@S7fhc?^rG1G^!Dm2T;VMi4Q@)WPcYW;jp-@eUd4F7ABya5Zwhb zke?!~2FO6CcjG#!NLP{${2xq-R>0@qP>({)=3jmX$swrTzUiGCHEeXz4i8w>0{Jx* zluv6bw&=HG*SppgTa?>=aXvVA&$o$fxaVspghX+v!c`@K;LJwHW!olmXiYpOZ8%)U z4!YD4AE$Bw8iXcI`fJ_A%masPknQTSr}=Z#wOW=cNH<@ITi{%;f}`%z4p%qT$4k+# z<8@K3%>sxekLQax)xt;{%*1ZIX9JF{`?HO`7AaF;${`0FomH>5m971agiWaOm-4{8_t>v zMOja^NY=l}6}ze2Fp6EVR{~TZln_c6Q2-H(X*cyXmRNu~hAhw%a8IqxbShLl+%Cc3 ziR9&4s}IxqU5wV-qRbY9_I|aMIb3{8AX(TecXQ*Me8Pz^6sb_D2jm>Xv?heYbVzqa zi0Q5qMBMNd$zqrT_cQ_KzGP$url!8u5kX=~uoEs3M4UJX490G!vNG9Ghk1Az+di|T zgtA}oBkvWd6T2<@7e0p+49hu76IfeBZ_rSG|92wdjwEo>? zJ;W}p@xVRVkK@mxffg7FkA1;ep(QKiFy=dnxCh8|=o`vHL!K=RiUNkdo&N$KgX1Ns zIUS-!XjI3aRgBh-++k!YmyT-i9$?dmoUJH#h3oL3r+0*n0+cn^|0t)kmN$PrqynK% zrQTI`Pxf%tH_zbJExlCe1~;m@xP+-;ok3CSy{{e`9i`4ZdM}l@yed45Vc+vvnpzk0 zx%V%e`U2gf!MCjeVHPd?M9y8dKlZc$=1A%`6_dJ65J~jh(SR?h+jEAB?I=-F(r8lm z&XmNQHc^3b9sg#)!o8piux*pvmOv6uYRN;!6lxDi`P&*tkOL ze5|(SDJC~m6)P>qg(%PCB}0V%k^CvP@PL9-bO}f+%aVm2r$HZ24{jw@bZ7qUKtFEoM$$B zzl%x_AAaeTz_;OtFv-pk2jq`9#QdLxDpf3D$} z@I+(}WOxM?lTVZ&95!WDBy{}{6S=%r#%jNNWQFwa!f=ktw(C6v>0)Gf-+M4?T%S|x zl5~bDae1nI<}TuONwv7uA;~w0xDi$-jJ-UbKLU< z5CZOZxPEutJQ}d$xv$wvEk6Mv`)~VGhNWiT_Ylhl&ELQ6081a zn8jNwoDNOU{7P}y0z=b%OJ_GPX2OKNn7v3j{%hvX9(49nEk27Z)|>0Pl>dw#cnpu! zhxW8oybc(WIW>;MkmPa4Z=Y-;H9U8WSKxnX8#=VW#P`p{GeNHgYLW&Z9s>}|eoj=J zW7=l2b4a?z7v0o2W|nFyB~nUPmJG>)$Prm({FMyTZOJPZ&0<~*x*x~O6Pd#cVutZ1pJ6I6@?9mPnX)=Os5rIFfDj?tx- z-7slVQW%6vN{v%sI#W{Armol)zNO|W;L;^#>H5zB+RBL&o^1pC(D<({X;!bo?x3pa{ z;#h0nR%=0eIk_YbevG-%z(gx8qo5|?71o@kxha$;)gRnLk#2*O6sU>zT|oTvU`;kf z;WB-S;lDKP3#KzHKBCg7Ziv`U`~wuyE(|~YE#y0+nnMt6!W~Yj&Z_^SM0yjb4%RrN zTe86aiVsm34{+EtPi_Sq9y2XnQD@r!C6k875phJPM)FjHPSM92s`x+9j7<;$7G>8(j6#l!|~&E3bv=2{&;%$K|6|11>}Adr@T%6Z!BaIr`PE$ zAaenEGQ7qHUVy+%&zTW+R>OH!nAF*zBY;V0p0}i!kx6AJybVap;3(MxcNpm|aL6dD z>OWZKVs#8YSc&+zH>`noFwmMdoKXm^=&a~Xn8aN$rDB#WjTO;;h^JKd6E|@uT+`4!@j& z3&J}Mb+3>MwXyy*D(_%abj&>$!~dN5g&Id${o^?m+cPj-mf<1!KQ0R4D*9Tp8U&G& zBLA6NQSpM7)7;A{t(LxU1D9U?@XZ32!u=(*UI_?HN9{yf2)spW@GRWue>Ji4sl_9i z2S8-@d!^3Mbu#qAygz)WYat)mJQjS&Iqedwogv`JJh^tAn%LkS=!O(8OMzO zwoSQ!0TH}T=mXD#lazaA3N>jSRUR(mRP+*K+vE@+49U`j!vNvonzRt-hK|I~1)Ul{ z6h!vuEI%vzO7<{h9xzPCa$lej9n88qoe;4_Y>M<1Bk|EB>7x6M#OYz$fXUrOZ!iBUAMd6EHlKKq{x z=k7PD4~&7^M|eq`AmXLe$P&2Lgqh0XB)Mt-w}luz3?2!Mfuh2k7_s(n-eoQ(#x=N` zbMbLug+!kc<9I^~Q}7(oIx1vh?I8+aZCmB$%$~aqCuauy$?1iaqS8!eK>D5lv^72? zmMfPJ=&)S5<9>hy@{Xl-6U=~RhF~$vl|yLn!ABt9ot>Q7opppjAqHPh)$BkxD{+Sy znw!%O(OoN%v`|i1lmvS7M?=Ed)p^+Egc(5axAO4{bSVL}pE7{}Abrfh1CXI7{YH42 zvpZB(K_T3EEX~Nzl#M=(uig-dm)nchM$1jhpVG58UF9x7cW@~6jEV#D;GOo0YCq@( zMTlX6h`UCWkOGA(@fBo(=$#vaet-83?@=x4hI$wy?A0kTWrB_tup%Bv+=W@5D=nYH zx=}pAX;(%jJQhm&ugHaK80!)e{4TgiTOctLs6v}Iyl{es@VupfByE9UODHDwAk$r8 z%6mhLt>+1>h(6wqT@f59(#jR4aK`}VrKpC*!2OnT0{YX~m&|1plbZ=?thgJd8zR%) z!D{zypjyOU8;9QhUHTy?(^E$50Y-_zYryBO=YjqR%uq@Y6Xze5aSt3D&PaU3r81q0 zZDe*s1VM!7NUawj#VDq!3-w5oEZ8*&kFBE$Wj_sDK%$WG9*fcBo;9^~o4FrR52_#g z;vYYofW8$O^i|fNJ49MW<`N5daD`q^&7J%LWFp1KOxHfrN@s6>o8w#Al=e7U3KL*x z$A>`v7KxY)s~4I)LxkuQx|R=`%D2XyL&}?g^NI z{9LdLC?*zl7zTVp@BaEffUoS4ky?Og?7UqC9LXY#rBIWs9UClWx_L6phj_`O+jS=Q z?xKy3hGss7(BvbeS))6QjUq4bv>BsW?6sgzSimw#Upy1Ct8sPH=0G(&imyvsoVW*R z&VB;@k#G1hj7G}QzWH1#9|B*~TQr_W2YEe22lwX+SSrdML5R4zysOc0&>!>Z38KZY z2~X4+DkCbChUUTJXQ$Z(^4+=^d&ZE9meMju*!P4@bTB^Lzgf06U;lphX(I$-k( z4J!6KHK_Q%)u2M(2oVeRYF-AAp*bxcRDM^!;V3;fqc%uZ2U13!?NT( zKpY)zn_vkviK8W`K6EX!@KS0mFt}b@Ze5OAhxFrlfbw(HISmr6uJlBv% z_MB+ilsS-;h8QO`XLIVNr2ezhkcR{2dYJi7P>fT{F&YDql*yuAQ+UA{sns*;JbWcL z#bq@>M6LF@QJnUewLDcbI29wc3<)A?x$r=%eMxpL4;qsu66FRH!?$0G%A%kx8r9mS z7VMq4b+aSm*w*1CTi|nY=rlFxcJ+jJYsifgau8-f2_5aZ8dVk{GP;x2z!=PHu?MQ5 zSFi7KTpU1tmtkyOMS5h8&%gX`*0}_J%yPz$-M^YZ9Pn8`#AQejL}y8% z-QNt)yp$e|xLMVJE(s8DJdb{p!N<7Ud6i1|hK|-^0W`pjWL~Ul^l%U`0>Yb;v376C z@X$KCZtyAl8IN$&A+6yMALatLsB(6)ThzXT-8dlJgzk$3yvPl6IBzE-e&xg$CW9lk z!tW!9Y#j%|<%F)82Cct&eRS~4jZL5lK5x@{p_xNgv2yQD<%ZMfkl{XpDdYdgpkD1@ z^ZSqktiA&iynP60ZoeHGlU;<6CU%H^8EG<39rJ&^YXQ6QXEo5?gBplDG^{jV^Np15 zm+_f9mA}w6E+69;Cc~MZC}JK59D_*^=X&mepB%z%zVJi90@vVdCzK)E5`}W=Q4X}swW>iBTWYo9`|9D zBpSaj6z$Z~;-1l1{CKaPP<&4Y;rLM4o=rpRx0uLmzixp)tq2$uTy7Ja-%C z2XHUwi}vm$7fp0=^Q`^k^AYWJhtZKr&68_jbUD4Ywl)bCmj$QmBOi@siWm!o*42Y| z5oKatAuuet_FaueY4*g@cAzxvU3DC{9uZMZzy#>#NcDtj=qc}R-(L+^i9u@-=3L3- z#7N;Cfas?!5*x>i4IEAjodXINeqp0JNSwz0&l3(s;voYgb_=n`@Pm3m`q#LFC1GO{ zG`})q0uXIj??F@UC!kWUGhlvGH??Y06-cRyceP35!CAND-?tcW6#(Nmf*Hvq$q$JXWR3QEUyb~wY}I>vLwwkKc| zbQcX=3%|grRmM-C0j+@V0WWSw1kq0v#8&}X9+CBCd(+B@<%uLUdW`J%qFeU1DbN~E znVf<%OE8`QHgb2O=ScRXWJXRR_e>L-`t_&1{-1R2Ugrg4;e8xv9_F&d5`HLb0V2Ls zwh$2K(h87un%z~F-0zP)Dn1E(a1fQA*`FnHdPUBpCeGvuO8|7x%nC4EF!mpbp7`a!zoIl~Ma!M0{qf=g4=Dut2W-b?xOB z$Z23^wWW!>snf7Ok$?3DN#LkOupCa5V^v!XnA1~cXWaoc67BiNVHHTUTXJ|)8H)C{ z$;YjXCcMR4fl|?X7l!W}(+?&XmYiOq+#tqHu;>pB>gS%rqS2ed@_jp?JBl+GC;r1K zL*bs=(KG`dGGu|mtnJF%bZv;&rgG#`-1F@3aSFbosE;_kug2zUifxXrs(k9*Fq-V1spakq2}Oom}tqW@ne?tJq% zzyuJ(RhAE77}689Vxc2fbgS7HKjQ9@3MDCUbp-WWpEmeLhSTL_zDu%z1^V|2>>dllYk%+Sos~vFb?kbrZs>M@_6&6oA9lJ zQuCUP0dZWJmJ0>jmA{>ZoxbZZ?;iW*ATvSoZ59=XX#;F2*~{mih7x>fBlmKTPO{k{ zcGeoIT&8e&7x?YjB0Ov@l_Bc{fjdc^`t|x4=5M)s{|-a*CBwF=cr|@S<=t6i<-aM9I%BzRjciNX;Rw86VVI|gC>D7^EgAG<+e77-c%qYzu!_Cb$y4iZFKQ(+n| z8t5`%saK#BHEqc)Ya|2&m%ClOrtq&m`;0=G=b$3$cRiy%y`z1){g+P_(+B(xfIu|t zDVR4L-piW`*2-aVq6NqG<`?$PQ=Y$s@7PEhXF|X0)BWV4X7QBA^iytyiFQCXG-gs- znmOJ(Au@$}Ii_*N4cF(|8enKZt~V;xhPYq$;w<=_5@o zpc8(asE*1B{2B#q!5;P_Lhhm|Q7nI?LFWVbu_M%$t>yzjPKg(d9_4={^-gbjWXbj< zd{UJo@#3b#uTjyW)(fDJ9$}4H5(rIkQ8Sjq4?F?yfIJvD4#gx7eA-o(@N<-C+5`l{ z&moQ9OsTrj;wbKM7)80#gY)_u7(!39aN*I=isS(mlRO}Z<@70w;0KnbqwpSm2QZ=? zV{8u;(M8|5NJ}q@>5vBSQ&LP)TV5BOk{z8$PxEJ8fDth)KjHSYD5ehxe)D_$lJxSZ z`V_+@f02e4Y!1J!MR`-jy0MWMLkyMYa6fC+=Kc~WOiFB_iwXR86efK5=1)g*lHlA5 z*pT3y?F>YrpIEXt?AH98RTea+Y}v-zdYC<`$_`RXv25)fdGWEc>t9k#wriY(OVS#+ zsADj=hwPluPjn21e{kzw#kM`FUH&6C}l7b=Xk4IrFIt_&Yj?rqI3`=I~H0+nQ*fnNXl z?s#Dhbnp>wUz=4h1DrsPmJ77fT&lxIrzbzyP1i_`KiOiWxIqR)z#~_Q<}!-X5{AQ| zkdACgvFsil_5>2i1%YEFER~XHYQ$a;74i~cgntJADl(8RcyZ-s4L~MXV z;2K;`HZP8(vVH8p;E&l|3+k-|NQj$%2;*%gQqmma0RlLc+B+)k)tDZ(93v}$Vy!Gy> zmQ&!$j82{F>t=cpY<`Gz@?^-?72j@W7quQcYyGSk{FM;#ZuLT$5VvwOfd?-X^EgM zUH_E}R|C=&Bu1vUblbzGgj~wK$z|+Peu&)fDMg0zon;#_P&} zVI1U>xJUu?f)-+Dq#xyImtf zh_vvL0wA;IFXNWL1tZeHJp8fpGJ^8H+;%F zGHU}gPF#%R;Zw-*#(*yVT7t|6=Ar|S@9}M5G)mavt%O>r*|1uu#qbJ&dgIYAMD@u$ z4i<8>GVq5PYwiP+e>s^zd?IV?xQkgS**9l3i+ezb|fZ=GsMUi@*p;k= zsOAfzOZ^hSsN@TJr6Ou~ivAM%4LyXobWU&;)VI_-lRo6+W|SkPgtpf1-SCDV={rJe zz@LsyaHesALV{>N+Is`OXvW$1s!ad)1~7iE^IUNsDZfpf@z1 z#MzEH!#*NQd>K%p@5K>lxtSj)c1ZC!uMczll}wKl7CD;t=ZmJ=!;23X)OOea)k*yc zzoiFVFrQ1WW+`gRVFlPT-Uu-}pdAQAxxIAwpY#F{IJr;m1y; zdzSX>5iM7r_o0lePF`6zyeLVRd;A(Wgy|a@_q-4MwAt?~R%n@WWD*9#x8YyZqoat2 zeRzWM=pX|+!!M73-W2WxlOVBTGVy@k&`qSirO4>_e_X*syAwabi(KEKBSN~s_;>E* ztfiZj(>Yb@b0IV*Pej1u3EZ;+hg0DjX_TkzpD+bU9^!Zt9Gr+xO-sgBmMxJa*Mr`j z7osXvFdf?9%IcN-J>g%CBN^_T2_Hj=W5p65lO=zFb{XpLdw?Dtj4as7@;#HZS2}W@ z9U#skGG4 zLj38d-({mKNlieI*_lp1IddVVPLC6_;kO>>FnT%RJiHN#E}@I%+}=EE6u{kES=P?+ z36@dz5CFVhj3KJd%_cu!`T5z*6K{EaMGibliZUkaMHeSydQ+eWxB1A{<;_7HU*}$n zfSP0=N%D$-#odS}#F-MPfczQ0dm%t9=C@>%M&MmL3;5w_$cphaWDxF^UM(01v)(F9 z0-^2y$JLbwR9$8N_t+oc10K5qvOENp5Kt3IjZHQULCvKQ0kJHd0>V-!?a3mm2#8y$ zfnYJ^AX3v{X|f8am6E0YrkOyou=>rQQ9m-L`F+m0_dRm{JMZ1^_j}LX&OQ5K;mf}t z2QP`VgCV847AyiJF2Lt@^AdE7d}lkd=s24j6B{;Li1PN;^}~8nOAsHIzGS@3?9bd% zoD4SjQX@@6O8%N6=0AdsK2nSHRS|i|)iChU_Ka)3Dkmbt0+8U`x@;RU5ccNTdm_r< z4oQT@%RbEHp&AEOT1@KKt7tf_Ie$VX)RVku{n?SSidjl)jEuqPF5HM(?o3ewQ|e_P zDK`s(L=Unc(lm4T3vHj}665gwVm!zy-%GWVL{^}^uJ{TcX1^jl7EN7yR+;}Dx%^m+ zwVQ)>x|B>k9sVvB$w8N-?^#iYYWFNu(|;l}uA<-=Qd45CM#4@1&U4l7;+Tu{E#zpJ ze-kf=G)=q8<@W|VBnyix?wwK_gvCNqRE%oV+(#yH^lI4M9(;pyU|OkH zJ)D-or)c(<@X8~HU!Pr`C&V`OWr&po85SMLF+qw=O_VLrWWP>sCfUM{{?pg3VpiMB z0yr|OT{8Vk<>QooEH)wKl%6$Qm5xELB=VwJSGZZ6=oX*+&4!plUWn->&FY84ZG7h9 zV>fw05-m;`??{|Tw4i!=N7%#4`k`dqWTf!^rW^h z;R;qlJ4V~E&i!FVEMo(ZNnkTd>?M5X#*;LSO52^A4T(Vcwk_yNbC39q@Q8PK#*|Tc5tRnc^Iw5opKmAy@3;}B?Lsn$hIqz!*H-K z$1tKP-;Vzj7d%M!K>^-)a~08N`!H)^ak!@I@f^?0$%MykDLP{ZgdYC_px@We(p!iN z*HfYRJHfnK;j7G*I-K{EN|Pk&iNgtNgD`b;P)+H-lYamkt-x~zQL=`ZF@@ziTNJA! zQsJ&`^Bg$9j6l8#`sWQ&?SfTa%KmL#X+qK&-ZwFSJhvv)YA%JgW~^4rH;!}}64^Xl z+dac?#RQoA@qv|&KEAd5M-=LuPV8^DEkI)m7E4)K`nACaoVBGX%XXo@C96|b-x$!} zNk^ydkk|9*;=B4g>CjF6okS3OuYKll&S0|lAwfCQYvB9iSc2Un&oNnJ{L@ z`I`nmLndbSAAIzInZfUqRK81Z_PwYN&r@aJo-^S55#6tuJ*8jkCSQfC+!dw$4r#@w z#K^HTLLSI6zdT`Tp7yQZR3p_wL#`25T*x95!Ol9)5bKZ4PyUi2waY}Y#)EX#lypk-IWYZ+@3({J@jOkU_AM+Ta;1X&D=x`_Xze;* ze7K0+o$Htkb9QgbynrcN|2faIhXn|Bub| z3Y0n#_vEye5B>OttW@YU?RTz{%t#k2ry->TePfuxYH}%Vi}uyMbY1r!rYv3_jUs+C zHgaB)>flvo8q}>omi0mXWnLHo%Py(b$x?B6*5#N+_y9A+tGGR2nv8lRh~=g$J$P(7 z`B_)(w8l_4E8rCCeKISc{jLPTq@@saj;bgSBm@xtZ_j>G?^s$z`(h758fXq*ZuDR+ zMUwM>d;v0a;2kRZP0gISnErzs@mlaz+-%-Wu0SWUfDXF?IVR#k%0`n}Xb-%|bR{6N zPW4*)0e`Ngz|T=4<9v@T^l3zl3y4%a=JQ7|bHB1m$NX{qGS3~uBni)wfmmPZ>P-+c zt2ra}8o_00i)%F_liYEf@=fgM+fW<$?3%IM2!)}r3p2(d@d~+DO>vzjDA}Jg82X{h}v>ARs zjm8XV@7j|Rna@Mtkr~c+*H45`6a{$ndAuWp_TbW2mm@j8&|Rn+%^vi#Rnt8?X0}W} zkg+^TUwOPYdbYS@jVeo?7eb$s{(F}c0hZxYp}7-?CPm@E3aJ$o`*dgboD*9*+n4n$C=ilrvH7r9w9xq010+8HvwAhE@Mfs(}9E=iFj zmLP%d`NOU9O6xjk?=0jbg&AJXpes!gwv%_bIjWDff74yVxv_b^@#uR7uLR)81vxyvH_4lVu#}* z;!{|=(HkD0BB)F5&=H`_%Fmjm8t0LZYK5cn16yZd$2x9YhK_~O!o5VMH`LyV!;o2N z(O-pTTD5qFnAS#FWJ_o9?G|2vQY{;eA-}}JZ`3S|j`_Ot3nbKP7M=26j-DICF>k`1 zDczR7$86QIwWkGJ)px91zdTOshosK6{(7bKwPJ{MuF0EvrS&i0^|Ws7eLCCfXYd9Q zn$C87uI8NJn3lmb1o@trqbrG4$vf`^#*9|&-M$kWrdX=Nbuw!L3YKOmIwXHEJ{ zABZY4Ga_V|X&*qXL1URyx{KM!Rg8}d?q#|zP@m!g@H1OekdTtImQg#cr zeEu{v#dN01^Pa+ED}$^bm}>ml&#J4<3%i0P85iYg#e{CQ_A8=+FH1iRv8qOK40FKz zZTNC*08&p-W4KU2RGh)2v&q=JMlM9XaRN|ymcD&O>3jNj<;~Upm{~TXxesDQ`ts)F zwOsVHSO)8?iz48x$m&~sC5b6e)KN?*NlN!B{ZM;C@?o@zmYtR@EjbrWg_(}stG9

X#IFWL_Daa9FO`|`6o}I6dQk_tZ9{tWvTp2#eN5Y6-**Z-# zcwAIZi)d#z_q~H3NJ~k=PpcHQZlBSgmiftxP_-Cw^8J~okuMYkVY)-P3X$HzOqxQu zyaTVDAx$J`Pd6nN&F~~s#r^l~x_;^(IsOGJWBps(p4uYVI$6E@MOs`4_N27^ldzb$ zr@n^+9;nAQmyS)?iCw>0g-!MN2ej5Sb>Bk3`D+jj^#W^g;>APD$<`695IF4wQS8#v zTX;-T>+h=zApx)olXwd^S%$jMu}1pgxI}tq$E9n}pg33t4f+ZJ%jap|u)TI%cQB~t z;<7(=5(TNzACT;}orS=xFVbX*E7c3rnu+~YL9YPKCoOLbLP)urLRME|fk6#0gq(SU zH^tR?gpqS)ABkbZ+t6{-9XYFzYnSnR21h_VZvi@)I2MY{ho=KymA3Vlt{71LshR z2lAtQbIBv~!PVdyJNYlmymDNFHPkckkKCk=cVV}&>FMe(WG804&)!s3^{}LCMyAx( z!1m7ivFu#rCfQwkUeI*{<2P#5xh&N9$7A}3wCdX4L+l)rH!V{91*od`5WF!G(9mDFavJHnc}6z4~f?KzsVm zM^{lMuY`g2_jJ9kOqN-?kT72E@g;SWc=%@MN;EMr$8FC+|2x_MDGY_jQ4>^aQNt{x zyWwLE_Ox(MC<4r-br=Ij=ScaSMo&cQR+m!T6jtr>mzp&*C@}EkuvozJERVe>MH8f0 z%tZDVHG@rhl;Bn8!4<-J8H*49jZ>)~YnT{@HA^t6LfJbMOm`XlvZ4jwV;pZlJ`u@~ zDkCd&xjeUulKH#nof)?4+Pbn_b%q1#Go#T=;#G!J*?rbD^cVLBZ|Bl8Q&&$u|dTt0W(J! z8Tl<Z*jICf}=Hw5TTxQzisvW#Ry;4 zF_nh}H?Vv}DrtCt$Secu35=1xZtR>(G)g4QGp5>qX{SZLY z1{jZV%naSl{U{(%c)eATqNQ-P4C-DmKK~yf-|?$#fY;?_p=(Fisc^%LYw%s6!yZbR9y>` zuJcnSpNV7V#=a<(Z`US+*<@gSb2KLuj`%+uK~cQIm3w zl@qYOfJ>&uQj&KqM?DR7@`~J0h5O|r0t3ZY5>&(=P5R#x2E+a!OxgdjBf3bY)Ck-a zg`tY{zx5RfN2MQw4I+EnEDyr_(nx_;k!K4RWI< z@{bA>N;2w{=YF@EyyB-Vbq~O>&v?whJYDWLPpd>@M@0Fs#o%t>;ir-}+bhhB@sfyl zA;u95bnDmMZT0+#9Kny}K%Y8b=+|;p8$H{G_^IH9jLN;P`H=)FmN&td>9NedAo}@ zC7;<&pUY0@BwEtWH~JXW6PIQ&CT4Z96QA2a;zniR2C#&&Qhi&0!5e?$eWu-8uIb>} zUTx60&Or)sobWH`I5vQ4h$yn|sLM@q$JYO2?|;hSWS~eX zhKz3~Y|%-wIom?HwqCKDfkm9c#EK6TL`Z1@xH>#2rtI>Uy^=%_R0NI5=6P+DW%@S0 z{DmRxwTdKNy!+YPK)ZM;_UewT*q%7fDg4C?uR=_eUIo0BtB4F>g9*74bMVJo6(Y>S zseG!>?yC%iwy4tCi>NNL?p9XJ-VehHC6HArjfhg(nIbySHL=80r5A!|)+$7iwI<~) z>MqIY!=>}UCthRX1G<`?<^`c48Y+AV%x?RsJB++r{rwl4heI{HobO8&b|ksv0~sFRMHa5uJ$dL~STH@!<DmabKTev9g`Rl)Lu*-`j|3!bj-j!?J6{MjQl4X zJ(ik)Y)z~lnP`g3@T%|d&)5Hzv1M5}$pnrMEntgyi&Wj)fwSw$-WpFey(1%9o*Fy2 z%i%|r*JPVm{|Txz+s~3B2j+d_3RH_wCx5a?ligJ*-{h>uU7dN-sLDQG+9Lna=ijVQ zdd;oZ9sDm5D5E#+N`yjuuo3=mDZ8QeO?BXNj`$mO)ewqqkBPV9<9Th$sN$QH3}bH91ZJ>TQ8`c2)ZMb z-i^V^X!zoI193V~!*Cb!dt46+7B2Pd`;PVE{C2AyMPP^M_P80CCDb=jBxH%<3!z{w z?~V0^s$dDGLZ!MOJ-^Lb0&|)a*+MBlz91dRpDsdm>$JqvOZ(XpIv@YHqJR84l?6Pll zQqe}0z?RFjq$LiZv*_C#q1cbndTiZcw1p!LessnXr2L1 zlHgFG)Jn{Z$0ArTOpcy^@n14BSyW(9H+gnC>wPpk^$x=rgMp0QiX_}ZH$UfH+;MIw&Ng+#+M`FsKy&@1 z>c3^PAFzK0J)(m>!-Jo58kVWDeHwL37-Rc5AMIDM11i(Mh|Jy%*F-p-9*CsXy#*=E zq{V#+DnCds5;)KpG{k%G$~aJSW+xeVqC8mAcVmx31It z8IKIXG8rfP^?QbI9P&cHkkNpAL&@mv*tOLCG4mW4V(?d{Tse#uUB)7rie=4 zB~)W3vamP93MEh;3micct3^sK3Y3SbhFi*u@=7V|<;~05&YIQmjYlSxVl@o?wLm37 zBYwC%sZwLE3fG-kgi!Z*Ml*6*uSI!=fjRfhKw|n!yO)vho28GQWeqMXU;8!9j+oWc z@#W7r1agh58eKWZI_Z&XL@`ZZ+n0^OWnOcAuGnCZ*wH46yw8;R=z?N)IK}i*=hz#T zwEih;7YyPyRC~e!m^WgmtmZ`gGlhn|h(^d>FF%e}Bfe;8@fmH|&4>q&NA>vo4CwE> zTk?iGj*Jn>bcT}^%~IG?kIqWm=S{H0s5Kgk1TB|Rk?kpcIY`aMo8UCPNX!<@;*-(3 zkzx(%o~3A(obz=~mXXA4`tovTeAr&^I-SF@SLN=f&T_Ope4PQ#76#1(I(eI>LUCR! z?1=-F%`+y`Oi(4|<5Q&F>lqvaDbwF%v#q(T8QdWVN}#+Ni+B`7LY-*b^lG=3VyzA9 zu>A2ns87X&n zbVm_Mis{%&8f$*oo>ArU7i$|<@0&u7{$9QB4+#KGH+YiwxZ~UJJWm?hDfFym@VmFF z7LG6IptSUx76czf=mqO)mf*fv(CXd5NGT$Ki!9QQ6>C^-_<}bL32<^Df31!dr*{sy zxK>Lj$lH706rGxf<5^F8$uShxWk_ByWd`vh`z{hvtvA94#Pa?=ZraCtv==vYxP_O` zaVPu%77Ho?9pItfM(6^%Qis-F4Q%+f(}}{L=3#n#L_%vte<4PP)CVp-kYC&CXG>En zH*^tL@NbIT5=8H70?qu0nBx?nsI$8fms%T@g!MRM^&KE3w#Ab4SR-BoSk zm%rd51WvB`zpqg0?f?&eTTcmI%a$?`6E`VFOS(xyYSt+6i&c@}`;(DQ>O#7sZBB7Mmb#C}lAv60l`}pK}J?n==wKG}F6$beB5- zKX*vWP+Es(m^i9zKREb3?=6Kd^-$WlWrS>Zne-7z@NTVLofb`-|5$f)22HMVu2~e_ z1C+@g2Hu3tZ10eADp)9v-@zIY2NS4^?pjn45~}fgL=?LRMUjn!qAuCsQtDQMehSW9 zcrrdg1ZT=_dbCTB$`;3!2^zqx!VDjSa5aMlQ+5d)+i~_@Maw;wobz_!8qx9fA~Nmd z9Xr_z?(e3(z`j|Xw?P^!yH!pNU}6j}djpkVU8fzV@OtBR^7bop8B4&v@n5y=?p|55pa# z+MAVkv%}*s8!KE7qML3i)@Qq0`Ac7OyicW>_X&j5^Lu$k+u?xH9KlLIc2-46ytL2{ z2hB>9{7S9^U2Pgq*$)pip}hMX@LVKi_3CMxI02E*Jt?qH#5qhqDQAf4NeOv$6b#S(B`g8`?@;DXrWDu@d-pKg!T;Pds5>DMjHjYr*o(Uj~~bt84w^^V%{ zw3#fll!bPZAGDrOK;|yyC+q@0y?U~7N)w47x%20CPC$Mvj4pyOj&yM*>(AWR@Zv-? zIcuL+r=Fmhqs8*~J?L5#l9)oxL(QP(b_E+N7!KQFif6j?P ztB%bQU3B?wUFt?!c7iTxpMdt3!a*etHJA~?W3TmqMumN%vT5kO_Xqn$NL@Ddmb$1j za(kuX*0*bDwc#ocdH!nKy|ET8Vo9OHS^lm14Vacs7n>!SU8*#+I~ zWr|gtvg9K)IuWUo&gxT9E|OXPho)JK&Ehe?t|m&}>C$F^beAkl>{y8AC7mfd5GgA; zZ|pc1h0Zi>P}&CS`xHAgyQnd`V;_H&VI#@<7bx9r-Rr!ddzVCy(Ga$h4BqD+jEWZD zUvY|=w*o(_evsC<^|7Hc-$^&kR5qhCxg%x9>(E|y67u!ZcVu+c$kJ0$OJ^I}I&n8egED=_YC9 znNKh(6U!Beg5Hr@U4X#7+=Ra7ioN>ubJ?g)I^=2*rZSMbLjk0X!Y68!1Bss;!cEw5Z zH4Rgr6Z#8LtM3nS3Cgo1HZD|lHAu+k9=Rqux$`!%A-4b(ghS5s*>8Pz}59xPB9s=o2iaX+ib%N#2z=q7XPQN zom{u3I~FDn$x`lXRkW-lTaYSm629%STQ4tE{+9)8n@HWN=74Cn)O3Ox-?6%aWg|R+ zT~C0f_@zhq&yP$*Q;RvWLiP{P^iN@Tj5LMQl;^H;32IA99v68?tDIL$PK=0HZK_J5 zy{Jln<`c_TyaPQ8lEwaFqp>0Ofxa7xX9bafVnl^${JN4C|6KLSazhS8FgXV&=SC}v zg7&&JzolM4%QipzZw%+vY`?8tuUpZhFFR$|OcB%z-1G%XOZJ&TuqOUe<;k|9xs*+z zvOfg! zvamL9_TAMfOqg08(e2Ub`)^S!rGEbaeA?Ntk{0cZWs&;QDVbI~cA_7j2ro*q*vjL_rvaw8#g~ zS3gV(Cc$ZRWLLECqdrOxLWm}>S3g7)J`Ei_ZvomiJ!Ip(Lm4PaEEPtFwqUaD@%$c& zcb263DlUroJ>~(M4bN}eH(e#ahj`93du~?2{&g*=`3B{0NVr*{QaIk0cf>JMx9_il zJ*g$v;s^;rqsfuZaM-)~pXfcuMz#HM786D_rSl4W{cantpi>s&ODA4A%|65YJ+O|6 z>|UlZL;+j9y-(x2LX;6jwk3wkl@f`=F|uMTr(eU9A+v~VqD%}^z*a>?w6lq0QM-M` z!QW^TkgMF$y~>#oMk_1gi+yG9EcEHU9`yylh20f1B}3Yc{%VaOZ7gOVpX$Y{{()?K zLfA`{mUAmgK{Tf?#M2h!UZxI}LQIfRl*Pi57FgA8xRF)#gry2rcZvHxUeTLB^9q`}W?a{cw#yTR*nBGD>J>1jg*QFp&HHs(h zL6kZpy!URiTsvs*=hs57f$@*N+@}(H{fsbYX}uWHRZbW%`~0jQ49gbpW#fm}!|aXf z8y1a3uj!6jJP`Pp%*VGiiQq($rC$HvP(c{b3a2MZup{xDM^x9klY{-r$o`mXlxU~U zb^GApKWU~6nXlky<`jfHRx~rwF3{<#g=r$MagycS37d&W(w%1c&gaC!T=WnVdCGB? zak88zs7n~>UMiuEI=YJYX%dlek^eQ%bTq;XaF5RNPH7@H6o8u@b~WUWYC-oNkI2X3 zw}jQw_$S=8oNLncFnN$X+wBk0X2tdWwLAU(#frh|0JOnL<)_T*6k(_%lO`uh<~1j+ z>`vPI*^$|}I(wr8omMGk7Le$u44@vdidv{xik3bbBCC3qQhP338;tVuF2*njk)~UT z+UoJhCv3XTOU2j;!@sctndk}v%X3R&$g;YlW~5m@_-Ft1Y4+scZk%L>aY0}=Lp`c_ zl~I0~&8rNVD<8Ql01wtU70CwDX!GYTsK$-FAGg0N2iRAfd3u}|891$OGr&0WG~ z>fNteY6bI4)pw>ql{N;Sj_?zTkG0hheUj}q^Uek|nKaKSS*A^#!XYM|O zo2<9Dovpwwv7ZFvCZfRCS;5qskf+s##kx5!V^Qzu)cP-zX^m-_|Reh9J8Dpw2Nq!S7<9MY2f zWQ)$ewSv$Fe5J1aZP1P-&4fZbsz$~Ns-_-2m-*y+6eY6l+uB0(?+1{8A2GCbxeXY} z8Mh1+ppbZ2>xF@xz^IT(*UgytL}_a~bf1@M*^l=VrzQ9aXBKp_lJN+#?Bb?{ciu^5 z*!O8i?PCDo#E}1`&%K(yNdJ+e95YQQCHzn78qst-KnMWiDfC5QROKQYRdaQSiELCo z3GRqvZ(ZdyUOX1EQz!!V+D7SHWZf8n4)vAzElh(&6=(p8@jcpa3?j5vDeAthT+y(~ zoqn^b{R)85hh6ySm%>^~@+RM&Bpqf^hM^Oug;lPNPI~IA$PdF=Y@EVobebKGQ$Iuy zob3sDVgKLJjeAN5H>h{>j6C~e0bb%mzY^BdOYD5g+`WB+uWXWJ*E!p}&{y(^bDi`# z>=EZm>K#9mEFJVOEnkA>b3XgQ^RnH#BX5Tnc${G{y5`|G3@o&mv|HCKaL!AgaAIBy zbKTuALd91)y=9cTpRz`#=o3XeVv)}EPy^$?YTx1<&SjA^$@-gmj#6ePOqmgAyZ-T3 zB%igH9Uk0}DOAN2rT6V2Z+ijk)Y%@Nd%LOZ zd`cu^;u;FUp(lK<{Gs6>9NEP__0sA=XzvoXE{q@!r&ZJs;SYDF-f>5(?i!&ZtfYhu z7-~8ia~fR`SnUF>-B79iMN4XmJKB`{4|pG$(M~oodNkN!Zgg?l|7jJ$?hzjT1NBAE z^&=8O_`>2r|0$zcOwsejM3Jqky1&8r;xzKxwcp$o26vj(i`StfXY@<~8(r4D^xtXo zZ)EvWh(l74ogIk*yiF~tMc)!VDmi1w@O^YzBwO%2_r^21jc7nKhVJ2bRQ8Z}j6Kp| z(y5+=RcW~Tff!IL>vbREmnNY$!TN0+DVpK8(+<*L-_}#Vejz)pCAW&T90YAgjsHOh zgA*OgUw+KVi72u85g&Yd{vLbVwBy7M^NqL^D>Iu<^XL789P4nxo~|TT5X_^tja?{GEitU_wxIH zYoY%nF%jJq251)6t{R~)ZpX+#IXMdN6>m>%TD6HxH}~sqzlcB?mZx0~f|eB&fzxh; zF?hOSu|#Ekg-&pd782fqy{#NVafZSwc#V(_xl)3T6Kw+x0>g1@s>r$MFx98OtQyFW(()?4u#< za}UKx?@CvwV$TyMOr^qmfiK-RZ&WxeGOK4x-3)n6!}> ze+|i+78VA$Sh3e-?VK0sMOA_IF|6JJ92T6KeGw7QgHULY?VpfpE;JivS$8j zvccDogj~1JW|fKKEH~TJ*KNEgYB)DBg`Zw$Wzgbst2{eK9@^5(yShUR`um%bsjhCq zvz@N25}N;(%#Ie~YNgpy(Dj|LRyHI-!2*>062$GzFF z23PH?zbD~~FCO$9N{yaT%+5w*ON@1SZps>R9$(fzW*2C-GHiNuEd2_NC&vc?k7MY# z`|KCqLq?5bkRXx|2CkMQh%m=vk^~_)Q?yO|mCK*22cg1LXS7x$pSw^|m@+DLj%!SH zr|VEvnCj>`Gsb&YAi~*9TN`PCF?Z2_&o0pT^=%5D(ee$`|9`X%(%yI)xw! z?Ou6^V`J;6VaNtrp@AbvNY=;a7@x8zFSt#<)1ZU^3Dbk?F(IgU3{oy>MRE{fM)~+BOrb2tzx3Q5#gUlk9%du2qVU|4TMg7l$Z}!C$_H zh^o@F#3vbn=(N{&14m$4;l-+%rg)KO$fy~*Cn07-sM9=$M{{K0Ebr8h0%cT}4B89L zz(?MxSAZm}cukbesU{njS9%&eYSN2n6I( zEJMZa4L-`&pE({dLYwAI`(e(v;%dLvr0xTI?=-TqXEaX&0~Y@Bczu~s=9tw=LV|r` z2VOJopd^FmTgejIeBFCNVzwWj(AVd8*KC9OtVjc4G5h8N=SqOdvcGt`nMz5gptIMjLzZ#y3c*U7EESa$m0m$deImn7(uG2|2}KYXG7 z)-&f|=pBX*)GKmmVLZeBb2l3_w{|=4jY?-UnEN6A*r8HwErFhDcgYEqkZ5;masoL- z0Gp?4uBoQv9Tq_RjjgY7djZ(;_MO zZLJryX-<{Vy5~6*6G`?y30n^#q>yja2hF;i*?o#m5<9 z+heOQ&dbDr*h& z5!1AFkTQbazBC2>)>u$PgxjZ>4V&o1wvk;jZ6Tyrhsm@gA-!v+t2SdbIa5~l#LT%t z#YZ~T?VOglGkoVv%niY~wJigPD@7#`WYFF{e%vm!eBucW-Hy3dS4X8ruL!%K_K z7CVvUpe&{elCm(n$VldGii^r5nfDm8@024Rm$#V{8G3cO^tP^r>uL9plRT&fzt$uu zHcNrsPWY^(GUZhRJ|rOhqm>#YRHB?J(0(xNQ8y~|cKZujkvRTO1KegX!nS3ZG$j}) zb+Y?KzMw$#bB|T+LL@d=RJ94dFYuv1NqH8@3wCXw9niK+iG$|q29l4iO5}W*$?kag zp!S8VVh<(;=akNJcnQ3muu`tRd!Z1T`qDgMSV#PzK1V}DkakKIALCtl{%lVkZy z+a*jkW5Pa{78f_8bM3Ng|1;<3RuQd#!lh1&A89*#nBb*6!p z4qo9@8{4cv$usy7*A|fD7QtOyWQcAdd;dF3llcQiU>~pK({7-JiDMA|Nbz;SjVY3 zXQe3P@7wXtt$0fc9=m(aW57?XK9_m(=mA>oYkTo*aUeldeescsC41}JOo;5EVw?R> ztRO+Is#Wy)eAqIa@&xmo=A}@{kZDxe*@KXZ=s}^b#JY|W|kczTB z!NUF3rMq7;bI5L@qvN3FxO zEnI444XSV&Xo_bDcEa7M`!yivRZeJ0$O~igE;!1_Qf#$DMjay!uwIX7qov011sPgk zM1#r=oxO3=C1cH2OJ1KJINR;ljMRvgZj>0Qn}&+R(n!^&qV10!(eLL!fG<8?C661V zrDMI-Yj^^GDIGN4=l(UGB^>qH)tXa8Ss^P_#!*jg7FV!S%j;ygQ-A-DpSyP7>SpNL zwkGCGWF~FTV`?9ez9)p-^cMHgwC2bs5~YWh%E3;dQtg+cU##dixtO72VwRQ%CP5To z46-P)C>`#IHrWtiYfer2RJd0zvE9XRbcM4Scb$1YP>c_ZMC&b~==96^sYz+F_zjqm z#Vmh#Ditf>f@_Q5!*>!?7~8=vqoAA4`0fdN)TCcx$V0DIcklrsj3cU)$z*ODTd#Fw!iH=~gEyQ! z319eC9IxO_V`H5lOIO-2FsV!YH?_Fwr0j_1c=h}#3vimL1Ifc4?|~VMe%5kNd&7nm;Y17h5k8fI zd};=h@vYZa(k5X!Ys6Q*>0D*JC0W-hmw<}Ei4$a4eskH3rq+KO5yqy|V!L!onLeN5MB=cJP}c(bSWkz{@m3oN$vy#K-0BT7L-$kNwsfTF$Mwdwq=J&>Z_v^u;ti8a4Qqi>r#R89 zU3j5mQY-y$E{Bl3_n90fB>4H{<0}@~J~6sIGf2p>`o<7b_D#QiEaj~<0F7>)^k;sp zpZ-kjjW|$!2=htofCEkinhb!WW+56a-M_m+v$TX5AC*)v`xF(asQ6a*Nxh?F;@ZYL zI9*hfzo@(9j7U><-?@o?J@(`~e5pqB*{sF%>o&pnIc@UGe)05=-8Gzy_SzUp7Czm_ z363PwRz7!B6>ip~S@Sa!@IZ)Qo~wg2^ob$~&?QEzh*X+X85a#>g?3U~5eW0dFGO9i z7S5A;*SI9DnH*Mqeg{4oaBT|QL&;5@z?7!qb4E#s_yE< zN~uzmhK}TA^59j?{tnt&yqEuj@D`Ls1}bQx&QcCeZM0*r=f?(jgCM*;yEZjC_HH-lnn`Tpr!|xvuhDuVp2oD= zpRPN{saFdYW;?Q)N}k)KuzxCN$G_}Rk6`MGz%v4`@d;NAE1i|rqvCvn2T&+H;w9{Xa7Q~ zMZ!sIJiFwQTetQPB={6q?hNLHdo<^>v^?;Y+q@zc*G&!vp#LjcFxFQu0NuAlI!$fE zdPzV@;Ua58-dgz}ipAxyIx{RC>^bA-Y{K;(MQ8u3&q{+E|tb>==uJ+@fX_RE*4@bad04C)9l%wMfgeLAOb*IMHY-bz0*3t_rRf9@}zgHN)7q}@!7V>`xJ z;r7r5D(b^}j1Sw)GYt&gy`5O4)Z#~rX_UR+D8p6WEf(!Si@;+U;yBDJt{68Bw!?~!>Z*7^4@nLT zx}+e6k{oC;4ZUDFP&}r8GdE8Uq^AYbk++2|al|Od%I3370$+Voo_3tVz7_-nr$X8R z-F}evr6CXn_VvTEs_}~QkJ?Jp5Zr|t+G$Z&*L_aV)bJLda$ds*9)2MjNUWu{RqKwj zF_x~?fB6784;+4`Hg!k_jG2p%z7$6?-*@>q+L29VpuM%aXM@5VU;H$k`IK;@}oGH$K zX7`syou!uO8dyFgG8`M<~QbkIn6&ED8gmf6!V zJ~7k94NbT^`w?uu%;UozSzYf#Up6#--}aBY-yAF_M|6zwB#`&n8k!&O1$uFm($|?I z*V>Z}Yp_4iWbP=KiQZ1Y&PlNtn}e>fRGR-aag~>Z@hM;$TMGHHNZaL<3u+nlVl*2g zBNlp4}9Uv>0^sL3#Bh8Wc8Y=`Tbd5O<_fMpWg!K>vzTdm6?m zBYK$K?%Vn?xb`^jfPO<|J^08*iN2aFkf5=ST%(wyvTB-992A`OMv$iS_aD=+a7GGo zmxU0Am#8iq5Wm&KC_fE*_w+%#Kep9yphIO&q(W6UHRglEE??Ebki{-IvO`-*2t`JgE1-efHVU-fOKrt!b}? zIb*I$rAG*`DsFMC&oz8wtTtXg|P>S7f8E( zZIj~CD&5+p{R`L`P7yy1O82=*>|7YM9v$Lk+~8N=uqtLj(OF0qt3z^DcofIIN;;ps z4^Fb94YBa9ca|;}uCyLorjqj!P7k%i7Z{-E#LF7sM^C;npgg?pOvk3BknMa z(DgQTF8a@8e^61$Fr1u@+FQxCBvesZ(b>4Z$LKCAT2hju;UKniE4!#rd9ZSt(R+tZ zkz5vh0sTJlAYnz2>dyXA4s)>X)LGJ*N3gQ3%?;5ePv@-R7>+il;o{@CRpW8;^*-i~ zgB}6~_Phzt2t?>e!5r&nVw!{;#YG`UHCF;lAxGKMj1nxXx1e`CK~zOvlb;}FR?z61 zVmba;@sj0w1D(em>xk8@G+S<5FKmT91s|P-DuK)`hmXPaPxAg?9ZsAs`Zzr)h!H=Pg(Z`EjC=w7!m$`f zLoyR@ShG)q$rHR`=$Vu9^f|QG%b0r=tU?QM&5K&T=DDqS^%R3XpFRk!TdP1_-?zia zE}qvLg@}_AKOSFQxy_RnS&jM=qKp60=`g-rFL`Ap;%!-G9&*niDRMoMx5$qYJ<0K; zVSUU>)=OhwYR*|8SBZ%45$kD+WG7cXCUOqD+EwB$(-xxM6$A9}Bv01;JR>BeW6rm< ze>8PVC#No9pD|}Mr1%h_Vwx4QMaI$)Nlw^NIdpu0-iB?Dl=(R68knj1aYTnqM|a2w zkmNKk&CqK1`La!JLUg;J1CuT}8(sB5G2n%$;mT0fyd|_7AYF^>0!Lbac3n9FGjj;4 z%L=y0K;s_Upex?6^x95KlQ`w*C|yV%B0`O(K|v6NMDuf<2K4i9HVZhVn}7#q?eGdm zWFcWymF8W;E``4~mP4pS1jPX{zExC8y$xyOgsLOl-K+B+t|xk94w4$) zqz7|M6{p+N_Ycq;`iFU1%s=##nE9j%aJp^82<>n++Mo!pNa$HS=1U6pqv?05d~&q$ z_6#}9Xfh?^9}^y5X*N(t(S;L`c;*fpJL}_&x*+@0bjD2w8Ap9U>d2%soTUI0K&+f{ zjw{e%R<3HYJ|>Tj7*WZroM=hcQ$pN?N@#np@$-nHEop{P3H}#0y}*y9O4Q@51%xw~tl&U45@lMnzkK4u*gziPuq z#{iqZHJzNz;?>Bb=U$RSu6>*saYM*1#ueQXscSRmA2QtboHLuuW+#J8Uv6g)52NUf zl3X}7f`~_Jg-VK_y~Gm*+lc^^H+{9{CB4{xC6jI@B>a%!&_6k`*l@~5Df0uBz)`~) z*UzLFxbq{heG2@|@(5S@)_;A3l(3=&x%6_WYsc&lUM4qQQBS$W@{KWB!ErC1h~?A> zDr*l+Xa$ELaEm>J1bQzSZj1VZ^XFRk0&@0yaBBg{M#{dL@yQ`_cc4Gg%-&Q4&Sodx z1XoaZgtLbQo$@w!nYh<%sIrotiFMHLp`R!}gy|XX46ebVIlma2-bT~L!NSx)eZ(#V z&&bAyQ%gFL)=lXq$9YC`vEx20vVZY~toa^vz^kuSOzH+-^O@q+s>P0WnUfPmK3-?2 zk|atGyIITHal3q|99i$-@I5~I?(ejCsi?U0)`C-$j`J0{Zg~ZgFS~~e*UeY)XX-_> zo14OEN!2u{BlQv|*xY4V@qGMlj!*|JL#9DopU^T4&M)_cGd6|ATxl})xK8SIzUC*F z^m#XVFt3u(yi``5c4oXUt4=+YZvkSy^1Zmo%cL-9725KZA6>UwQk`1sm5>HL>Mkwp zco)@iomy`XqjQI{=sde_y(5WkInTwcItZE(sn_9B^ns(EA)OMj;gcc}!*|wK|MHtG zemv&bW?QP%k+kG#N!M7u0a!D2KmD~gxTvtL&-)yo^7luqj!O@4H20Rs7$lWMqR2v0 zqjoZM;jA9ByWfU6VZ|f=&(@7zpfc37G{e)Qql#kzZr^5iT*rUr{va|1f*ja9|jf*Xp<#e~&*+v7UlOjRJo54q1G%swV_&8LKYV9O<6 z=yEpQ_MxLD)Wxlj!+SwznOC)2Y~)stRnQ}gi|Y<(_iw(W6@LI{aky8msW5a|G(DW> zLU#}_iu0Z7M=B^fj7`90U-PtM_3Xh~s?Dc_oaZH>n=H<-^n z&f0|GpaNNoBZ|Vx=NclpwFb?o-5{wG#Q*H4JZ2es{$MUSOoT-)z3!Oy$~&C_(V9py znum6}A#Cza=wYDYi9Vb6wL%$t&Dda~C*LW#OFx1`x(E_ASa}M4ult(rqUPH+AIRDr z@6{oa2V{E8b?}9(mn^W6oH>tLzH=QLaUon&?)vFggI%Yb3!=!Z-MOMP8RT2mR``kp ziXD`XC;CTYz+U>}_opXKBO%)F{c72e zTAOYovbL>2iz_#`SMy5-Rh;X~diG21b$-I~%G&(O4a5iWx~MU>`#@S3@oo4>==VJ1 zgC$?oh(dcpiVQbxdDes}JT{Nk+yr_Y)<88)1ENZbn7Kqr&2lX$>Fa)sy;gc65a9dD zDxJEMv}Sc0Rfu*yEdVoM(X@YqdC#7XeEoJW!eYlogv)aH;B-*lp7ZeqB(>c)EASqD z6`x6-Tb;L~5w39eMv^(TSBl(7bF`gT(fj42vlP1YsEshAoQasy-T0WzIhN-NyqkVt zmy@^pY#|^&^&Cfa3@_H0k)x9Ry|F*jm0OoJMSAPCe`bhd&!>Bc-Qmg|e`ld`xNd6q zs9lu>^sbr{c(3@*bh>P~Z0z6?^bgjF52o0V^c+oLE3V&n?^ftK9tQMY^GeR8Ke#CK1 z9yCzD1$+>vD30L^7Pz`~%0UZWn@3{~p_X~o9Y+aW;llC~9_6uvLufkY#A#l1Qb`t( z-@%}O-osmQPzU#@TAf<;M790WVw%~KNH0(+Y}pt%FK8zp#9PGxhr^rBkRqiu+cM-S zRR$rbRM!E)+J|Yy?md>1Y1P<-Mq$+1{K9l)$#T57bSfKQ^z1(1r-q2>XZGgM6iH{I za|BQOn7Q){kHKR}u@<92BXhsHxH0_Fp)=#KjB}~Mi-1nLan_(HZk(1Fj45uM5zvYi zFL|z^B~WzHX<|LU5cqecx74#XHLTQjV_M9*lQg|4nw2Gn#imwuY%%aFJ*7n!>}w`^ zU%f2q8CCW2R-pW2>_AZ!N^E+dOj3$Tm)NaQ+J22>|1TBDtL`t z38N`%ob;|S9@mDg|7r!B29^inJ2_*^L9!nPZ?%?=DQ$usaOv}A%}>uHm_Wvg@Z9Pg zH}9rT+1E3D&qiz6@ZPmQOfvH&NEFs)AX0LVo<^;^l!J|3EG~e9 z;sYT%*;eVSSRHB{l|qgxr4NCIoUE4Kmbn|AHB6qw< zVo>}2#=8-ZOqaJWXtmJ$--zJ_{V@Mbdj~Wc)$XWqLc-q6Vg<#GCBz zhA4wS*R~<6LFBez%wF_MTu|KC$%A5xX4=LCeeahYs{f;}) z30&y1_IbgDjt+q&^SPkMchBLGna>FK3Rbnz@CecIJt&rM^-+MN;@{MP=ecN zdux2gEW%m0iSlG5ghXK338SETy0q5HA`|4bc0YJI{wJ;{#cf*9lVmb{9oG=?U+3Gn zXljt2`_##?e@UTr(-9p)nUc;>P8v_8skLL;Zo{bMdup-L*4c~&LRa>zF#h+5T@#7% zD+-OxD_!;SRV&L}Z}Tgnt=Y7!PYNHEJGNNJsr@9WJH=w<$VX`nyF=ZzszPKCmd5_F zGDMEno}Oo7Ei43@*MeXwV+WhUq+aR%p13X+VY?XVghEr<%Z)4fxZsxTSLEsOl&>9~ z)VaF@IcnHWIwl(Jvo+>pDJhZUl5_Nqqhof@G=o$c&2&qU=(wn3VJ&+ufb4k+ zhhE2ks^spQ-Q=>sKhu8yu!d4^YO;bG4ZEygGF`ak&UMp?=> zzy4H~Y!nKNEJ+lagtJpshyzB7jEJ~KG<~yxy-}u^eS)F>;1gxq1q^YT0%EAC_*66# ztVi3`y^e~DQzz@Yzt3VwekGu7JxW0eQrz5Q^=|G@w<)_r^H-#gN%}2fuf5aYP`Ysl zX`TnQXkBU9=h{`)t0B=TKOZE?3ihvXEWXa@xjJC%QsH`%Gzs$}luTR{o~OQJr&1oe0HKlDe{yVdk!Y^F6{%Z;Hs`x7| zSmyJq^Oz=#I`2?DD=*WRqv4$;ES~z+0eYc@_J~EbaO~kC?}dTh8GwupBmR#=B&U+j z)-`C#H)=WRCXDR|H7jQBzNv_DQ7VA~)QJU7#T8Pbjsn)P3V^ZeX zLsP7X$0?o(LVo*d=9FyLnH(&^;$5w|%de}x%o2IQl~Wh%nXwa9=?WXrghh#oXWZR< z6zR&goBYzPEK8LKYO*G%N*~nR^Y%H4rlu(is5M;s{RYl!)tPsb6*)DezQqbHtMC?=R7F4_2n#RW7BqtkpjqY2Neh3!h%g|B6jPrb=}7;GW;t{q!M@oLJxA#&8rH43ih+QYIamPUY+(ji~xM=S?AYs$(2iR`?=Jheg}z^D#C2u@my zyNG|C?VS>wYS?0gt%Lt2M^ zN3D+O3?DSHXb&z{0p7u~pmM_~`!x=_Uj@{WiX|*!Nx5N9*vpe**BZ{N;rrLqxdlMx0N_I3Q=m8-Fy3gE;s%SCa_8rwn}$=8Icikk91_78nlR_yS&45_FD%^!woYsK!A$Z<#InyiE_B`F`FOyCc`i7g5DyGo33Y2Y+ue9+fqrbd!?LCJXEIKeK4CHD{_ zpVPZ7i;9`Z9nOBFqLyECQLPAe6a1KtOGL>R6vHyr8gXP1#v#ilnD^DYDsiEGCA z#KD74SkrgP)J{lWgywwgcIqCX{)jQ@bS291u^X*L*DQ;ADW?E5R*uAvSOe)5*J;yn zSwC*7^22|yL!5moz@8A~4DF3y|<*A!N+p@o43kJQ%x)rZ2z($UP%JOD+(nPcrNdgW5c$TUAGA5ytBMCHC z67a07vhzkiENKoz)0Uw9+F3)BLe^dPS7RHVB%6_r<2OeR-xwUcQ3_j)o|!3rrEJj zZP7;->zg!wUSJHymwhkzYBc*a14kbjnHBmNQ0Rgbff+sl>%=Po7j1*&Vn?-2w^&1% z=F;pK@P8uM>xePlQOl|fBCICP4TGyr67vyWj(?TI*IZA(dW^5-Y648b{=0Tg=p<5a zZPoJC-~<}>)UOqsfX8)P$${s3t{s}lULBl2$DrMPcU3eOX3wI12sqLX?_PXxvD9qWGfK zt|gjq6{p-S$$SN0tT&=K7Xv+GPw51QxJ@2h!G_`JAth$cLkq*#I-3iCl&|GY*;>jQ^A7WkuG?C0M%>Ns(Wuu+LBdh}9<*|+y!82|ciPvdX9%b^(pa$$zhj19N!4T*c;Q3Dq41{ zW&uX~LX~6B@jC7-q%;Z-y-o=OSSS)qi)6hPEm@Qv!PX)ETtLo2T8zHNlrx&&lE){i zWanQ`UrMtrOk$j7oBb*If4Wfgnie4;x2HY_9~nW@)o+~T(5gmhM=P{J-D z6ZsmY2*~oY8V$b3||(o~*`@Hk8`TPMZ; zEaho!o(iZ;yhKL>5P00dibN{9f4@HVgD7I*v|%3u&GY29P*Su7Dcjwji`jRJv;Y-< z!JLc+%;4p<4EFwHgVv@sF6r^?<3DqX0hEx!7vGuXahL^h}OlvgWv>>jRWO zLruj1*AE^~8k>)r$C3(hB_LnZz?S^(q-dDsiO%;M0l9bv#|J`e5I_?`#JMcO zgzOO$_XeZLOR`g4qAQ&U+ck@&PHs&E*g_;%R$)L5ML)F(!gJkKF`=EYbf`tTV)O~k z}UAJTj`DgTlboMDMGT+PvQ9zM#UzdeyLSi^)(J|;B~|-?5AVT1iN}80OFpaN z#|S&b!752m-c%@3?{15ku>!oPW=W;=QiJ_)(SXW6QwfKs;tNJ|9k4!v)<*6be8pFGI2Tz*+#NR^U$I`nuh0NO5*;^*=?n1{CtUF; z2A)Ch-gx&@S{KNOfIp7jqNsO|0x+JwPS>Pkko~TQZA}-lUwQGWO36VeSQj0B$7y6b zbdO{3X`HgWFeA27;wbt8W?*y{Bz(Itk>W%t>L%LKiE^|ig)kvOBBd-6L(|n_kv0R9 zHkn-W^m-Ol8uqOF%Of@v1g*q)YZkHB|5=djEKEq}n8_Ue!CjtQFBJhb$Tw=mE_C$v z9WqM}!~rwG7$hH_hH5?smgUPNTjquinA_g`8<@d?){kbpnMGU#5&V#hV$X+xhy#KULs^A<-z0skt zm}=S%UWTkquBjTYU%`m*2`q~2(4ac_Sh_Utx9_8-6!~GbKQ-mcqvMM;I0(rRwS$U@ zJO5zePW|FL=0iWeLM}#!>mK{0eVhDGv3cW+N5DHR;>~NOgGOpLz4(Rv4CNu8lw-a` zk34MyZB)q@LB%$JEZBFhWU~Xeq+OM(_bQQyT-2=fFmlg7-(E>#Y5dxIKzbdq>RfER z%udtV!tw8zR|cJYCE`(6|5~VQ6;?f`pX5k^WV(9q&ZXuT-YXoz?GZ%jgx`P>I;%>?YhpJ4-t%%ZD~!h7x2>k8$M$W_@Y{*XPS}J z2Zw@t^|&B!<3sUMs0O1+Znc&_^g&0TkSu)lCVS#>F_Ya6-P1AHm(j$=mjyg@O#A&!7Qe#g zwn?i}+i@P>apN$fOQ@ZY#Ik130-zkT>5GB8S>DC*%rYLBK)?_?)g3nl6y=3i+qxLQ zu&P89MUQ<*3X%*G_Qcj60eQ=~El8s8?FK8EzSdd*WGh}e1rVv(N|{`%L8eeSp9jex z_D4@ANchAL?1vo8__TFQJ1F5Jij0rvqX?)w*oQ#}-@0&Gj%u}qyCr6f$_dwe8PH-_K4XH{e9eg6kvX6FHB>F3<$0aHL>Yu|LYF7gVJe!Z8z}Z&9&bS zqcQu$CFY*)hIpAL{z9lwonnv$;LS6`kp9Gpm*p9s>}`b zG9UV#V=Hw5P4)u0Zjzqh81Q0hb)Q>4`94_uSqf9OEM($tWpLQKr6ld+m;5-p=8ii}ry&{Dw1 za$QSDM7nb4QnEfd&<*$HgN%zHFDZJ))cio2dtR~aJbtm zU$W88(3tX>7rNb7x?>9;CE{u$+iqToGE%bb+P~j}Z^*W5t+uU@wM(@b&<}@lh^4}% ziDY~LD^z6Y>y!3z#nx|&@q~Iq8d^}GP(Md>ke2+ZV2{jc2$})WfHq}{cM~+sA;cR| z)BpU26r&}jPJoJE{6uU;Wwm2iPCsqc#b@=PdA>>tyRrxL9R;GVO)vsB#5q}{tt4#f zP^tL51%GefN6Agc;%|QLqxg`=hsI7(o(%v+yw-DxPef=3I>m?k^fAg&Rv*UrVwlwX zKC}U1dlknG1NuE3oo_z0Q5lhYpV1Uw;rzaKA<>MN_1qP$@9RwZg@g=;r9^T%$JCiq zK|VgmV)L?O^?IX~2}a^`OcZ(Fdju2gv{~A-wS*9)%YMHr0CU&T?-#C)%xlz$7>Vo5 z@bw-N41=AB1f=|`!{A^e%0-EzKdmeCMlY5(As7a_=|+ymn51=Rly8jxeiCn_N}Dk* z!L68p!Tzyfm&xSy-`Fl;kAoo{jK%9nXM`q~Su4d(ngkYW=@Vfd(50r0%U>ZCgJLeG z?^E94gDy^>fDv7!qR1lVw22i@-deGyeDxI2Y~FTuvpii!os#tLr9`{_(CPYreQcUW z{L=Oznn8aK`RTlq$V^I!AA^DZXnqe`X^oNI7&h$3?{mk@4$oS$@2{9Pb?G8$+L}5h zS4h5Tv1$j!|~grms893V*U6W5k3&d?OG@c^o8p zF-G{MR!Mr~(xNrgmUcp8hu&eVFq*T(5+grJ-=lU(fpS60*TLN6-n1@wTE5Run)I{a z?Max{#~B|s?5fOkd?B5w5p0FQQjf9l8-RYh{$xJfz!9VU^tCr!mLe=tgdCy&R^<)h zjJD3E7G2X4$elkP!;U%%k$8TzX6-0eVa?QzSz=KnOI3IDOi)g|Ra52wE@DQF6lzq? zBEL+%G;1Km8{H(1{tu-CS(D`;p*pBA!kDt`&9P(>+zAVg#ie;I0L5QVkn+cJEJ(iV zXjq{|%1A&~HCuTy4QOy;UFyduKu6v^=OPtUOOulP(gXsZo)4ZoW{KJ#M98OIm>;oc zDi1gUlFf9r4<04>c*|bA2~>}qBx)b755xr0%2*kT(i8cb4eEJSU5biU!^ceivWP%< zez5Lg@l=Cs!}6Pak+dzQ>JK2s#l>KmafI2fwg3e6;JYPgYbC|DVs%zWw(RGkDKX8K z&Mi^ob1Qrx2(B`8ZcWUOb(faVaPtHuBn?uGbgb3GS3IiO3sD==j%?(FcA4fj(#4`& zr;7%6n0?9iOvh-k@6+L#>Fj{+Sf(8q%8-E&MONG4aHllf?kAWq^u;X|!-c(|hb5;IwuCcx_<9%y>X8XlCx~%|i=j zOOIMUrdmEB{DQaPu%m-}qLUldvUV)j7;RbTi!Hv3&hl7jaQO`A@}l*32aKr~S!Ss0 zKrJz9SKpfYhLk#@(vAX;)GX2c);rDUn5r--(Bg3Ul>hB4(VD#>89(#en50+!-#> zJ&}PlRX;IPi#XlbtVc5@V|M8yT&^yFVb-4KevNa9R6oqUeI?^NRgpxxb z9-mz+YrhA$6<^`4G^J;U`U@W#jowgm=`yiU6`Kil%8)q_+m8;|ekmHh zipt`~K2#ECV4;dZ%fGWfoTi>gM=o%IeFZdokT_ie56%+O_|BTo-;*4~iZ)R1d}WHF zIGepkCqM5Bu;xu6{%5=SmhlkFc&Fy?(StO{*Gtvnrp;;J{Xz$x$$njkbG&^0RB6b| z`H(LWvv+zRbFo5xdxIfbkj{E)Gd^PomS&_&iV9Jpncu$_pTyAkTqhm4SCtrl9P4uS z+75x}Y(4kXL6@6Iw-mV$gF+Dp2Odoq0mvRuN3Af@8urJ{*CAMWdzieXOY$hKviw;X zOkBUJHwY>whA6U2McX(Uj98}9ZF&Sh%tX!Qiqpc7ACFNRACn<+F!MPy0?NxNXZzi zI4!^ba&WV2mWj?A_l8^_F1C-B?5!cH zC0V1U!K4PV=B=2^SO4MT!~+=2#{kb{izsf=2O!%?k&>$yVUK0a@g&Tq13U9}kx@&3 zEJoy)ANlFjIbS^*LxMx-c-^Te{D2Fn0qb~!l0YkA$+R&7Ap9z|g;WTdKk?6+S$q?` zgCTh-4F{po$R2hI$fo{yhNktzfq(tmg&;RX!g|0sjGs$5I9eL#>;9R@8U)WQG@2Ji z{I`3~%t8dFE5!^|xVO|j6$tC9j{}AhnfG=C;saqqAI?B4Ddqqd*&XU)CBaU|^!=sw zGAxnV`0AhJ4cC>H8!h5MyEnB$zt6jJvJOUOV-uHnD<`Wkx2YeHQ)#3whG(rvXnuP1 zlZfOTY~k#<+?W5$9Q!}MHz7#yBN6`h@g~w1T%Tr(YG#nUwgkvwyhTy?O}$Vl8v3XeP#q?otzKN@8#=$l3ghz)?Wqc)7cF4Z&-(^`Ak5e1lj|tsGu>g|k3+-rl*~s* zYXO+}#>@&LnC)u5G}`%!41noKbmds5X_0V{TI)y@Z`MEp7~(E^&<4T_wmM21{m{?% z$Ct}l<#cL1(dRZ{(KQjD%Dx#_I3z_1rg4Qx4b~POFCV&G6dSrvb4EIJ!z(nvlMh|~ zpGoTTa=e`MHtfoCXu6-Su#%(&h$ll+R;wQ*rYv-3dK5ek7^Hijwn03l6Ijbd_R)?l zMdTOOt#ty{q*b2zPdQ7|742S_j?eD#L#vhf`^f!)CeiODG?Whk5wB-Syrg-bX!>uJ zbQ712f1Qea{aMV)#|9)uu(Nj(VCKVD{1180$RtMv-w}SHLgVJ0!G}lKC)0i!TJr)c zDh>yRbldp_Q5Q53nw$_2;|~&w!uvq0XO(C%EvULYEG~}#0Pw~IzAKC_ASTkk*wmeT zn*- z2UgRJ5-IAARhbseSopX#QcC39jo9T^eJ*Lf7O~5@wvHLW#w!QtdoY4Ydu9N3W&~sV z7huIu*hIM!`_bmzWvD!Vip-DM>-VEu3ai7lmA|tBt>tV45TVBs%Fm_}J+Thlr=R5h zM?X4G?{=^4MJ2~eJo`vZEti3LJoQ*hpF_c>o;Hs#rW`w>DX$}K7}mq3Zgr@U-%ghx zYqoC>mjDjdUs|Ykfh6;hHvS~j6U@L?omgbx3T&2PQ zzwv}Gbvt9&bI9~`NAnERgCm@;vy@Qc_$%7Q=$&P!l3HM#T10p9#Vf9o2_w32XUC{z zWMDp0uycsAe#ieUmJ*D+57!0A5q$@v)8S*zy05Mp-E$HfA&SfriM9k_wzDld=EE_; z)i_x;lVrP~md}-eA?hoZ_FqS@9{M78JcGc*M6aZw}| zS2ce+4MDe`U#UKZpj*o#Z8pAI#6CPt<7E&O-@Aab-z`GQY$Y5>@}3#&a!Wk9pXydD zg$vW>=)VdS`1N|JYx+t^L98)QgD(UKBm(*<(Sn)SO*Wqc0J`_M#0$#N;6v%)+1%C& zM=_qSu5}iu-9tvx%B$n?IZIi?pw?u5n*jSjR^ivd>0y1nzRG$PR<^Dk4TeJ;73 z)+||G?vtkc;Pok;^Y>sM3ssS&{CGo~I z4_i*Mx+SX#WMG~o#|mUv#A@BJY5>Fr#3TcKP?I|_M9aU<996E&p<34X#90~&Jx;|y6I^NfNr}*z9w_tVXV>C|6>BMPb!4EH zgsiQ%GggWqL@T#6!+Vl8TxOOFy8J1gZplPr<4nU5>0Nk8b|CZ}LY#LZ(u-vkuXN7&%eo8@4J;fzS8= z7&a!*iTAvo?`|eDhur}Md~l8(prKyIQ>CKm9j$0clef;s9$$Y*5ynN4M4{jxvH}I= zhWz3Xk&?tyg%)&u_J#AnczpWfNnVLtAJGhO-m)G0(YbfcFUyS2B*iS`q>ZcZ5+Qks zCDO<&t$BSTQ#T@K9C~8vib`5{o!pWc>CbJ2Fzrxq;Gr9)07Y{*OM_(uX&s%dxAJV0fI62%#{Ux|WyY2SU|10%3s3}B$ z;;>QmwxPf66k~mzP14Q{iaja2e);P+u{StfW1(A-rOf*nzA+cmFV4kpcSCf2Bw5=3Zs3T_L^8E1i+h<6i3Azcy z*j;*1;V=Q*=|jFzO1{h$H_GdeewC)FL$S|NeymI>r#ovOR!L4#3mwrPJ4Ka-_hUdl zjFPP}-WpeS&oABGGhevpYwVhH4ZHrJhn!*Df*x{8rD*u~YdtbRFFrdvLqO=%FMdEU z=iJ>hK@f^0!lktTkbX*3l7341n_hFqWSA=yLaDzl zFdr34nW+%%$PZt%J2$9?*oZt3ftFM^5(DCT+C5jOv4$Q;7iDPx@TiyI7c47iO0c#>D$x9J8H)(j zJ{b+EDAYMZX0d!!c?9MFpLSqSnhD2A;pmn(Vh2{MIIowe9it` zo9_ID%=Xxf8TSGX672uVsz+5qJvDy6rNqHzAIu?5Bp+IF$Kq~4KS#$x$2GGpPXfX5 z1Fpf&476l^+v2s`@($sm5JGdG-y$)6g+X>SB%P%-UD^1GL~&ZdxthLHqltt0i@xjn>N26@2RL{@J4yMYYCIN68NGa=c=DAA3j4FKm7 z!yTl9FaOSpqqSKQvVOflcEg6>?xdJ_&hn&7zr4Fa=-bm@-gq1Ob|{`R^|#+1J;D^s za2MyI1AdTiWbz1@P2l_hDYYQN*O$m_<>~aolh?w8nKD2@I4r~#F>q0UFns0f7^k5l zl5}j+6abmuGL&UywI0)9NxDWaya90{q$7}-{Zd~Zn~$sT3N#d4K>nNfd8 zOL)$Q4HDC0v*Xn`FpvDcL==f@$^P5Q+hD42=zYx&wp@kTKaf17ucre9$pQH|Y-z6HnX808D#-DHc*b91Wq14O7Ymv; zgRRo(c*ipvC<@NC=2nY@*DjX~bSmz{00Kp@_grL`frLt;49lNp!-O+mi2OgVTBAu1 zo-&xS1NQ8hAjsw2#23Z79lg*NF9;*J!eA0X2mYw){co|?c*J3 zIr&|0g$%HY6ULv_8UZ3!C)Lzut&+H+{6Gib#LTuT(+k95Zd(+Y-EONi!)Gk$+n3SY z5K~%a1HwEjDyr5|_p46OWtV>@Qvx(BXeWVxoen8g-{{oc2AvZBksUM8b0B-+V;GVP zmk!1WQK8j)$8CuvuI)DiY}43=Rr(`Q?l<;&@OQy#5D%n(X-8yC)}{Wi8%ea7$Xp`P zuI{&Z1dSxgZrPeGkUUxGcIpu-Q<=j^*l+iWG@pkTu0w4-$Igj7c7|eX!c}_F(lb(? ztf?n%OD}c@J7#?Hkn`1YxDO4!BT-*_+!rJB<)i%hDmvK0L1#*A z{V?$9)8dhB+?D0h%yu?s%20?R6K9}@hUOJG-k*l%706A6=06L_U%pPuE#3-!3D>8v z1giDqr%dXzGQ^Fg3LrO*Zk8t1+LL^<r70wrth@O%Kaf$c!=Dh3D9=Ph$HYiDV#a4S^ z82OxEuJ<-gz*pN@x-0Unyd`NYR5b-?A{6kUwrIhG(P->ZWB^P|LS?T+*XBW=wEvwz zY3xc917SU2H}ovi9VE2CeLTDo-3soXD^F7FHfpK!(cRVbG;)V$2z`YIkQd9V(UkHt zU*A22zK0MmO6+MR{w7~4xe~leOgXy0{E!l5BxRf6BhJW7rOH3(ZKJ5<#LWCR`%Lji z|Do$hlqiv%R|mmaO`ckThQRaQOHc@<6mumEgC!QKVQFbSY9i{e8rO3zAin%3N%A|j z*QL-<4vU9n_nReItMyLpqP1Ohzzm)8iWfyDY1e`rbj5ejj?OOWv=jf+X_xW{e-~eM zeuvGjEJ0;k0*o+DUN)cRk-@N-1H|`55OXzt$FO5S_VQ242CA+GvS@Qep7?~T769Sk zEq;0Y;#O1(mheT9*)VR)5`K3{Iv^po zCD-&deD&o)au4claiHm-2nX8-YCxtEmQJWBmV4R_)X1096q6^S%d%Ip!jP>O*80!QWdGLRly)$!|MIA`7%4^bu{{hV&01!xlyyk z(Z_t~`O_@l`CAd>%zZDGVVGJA6qsJ3MC4LV!2l*%n5R>&P*O{N}WJQ#jhel#(F8x`UTPL@frm zyc`-?_dVX5g!@Zch$E4Z99&h^d57eaCd&X|i3v9`1^j|=Toi;mO2g9yar8hDfMV}} z{Vf>&8Ea_aT);kocs_NFrA$e$-ztIJ-)Pnyb^#(0)_Rhm&lA^U3iDMl9=*vASUF>m z@+5luj!&?bsp#$2EOKfcM8sPi@7LRc8m?Yeup9M~DZYT1bvn1xAqWU(6)p-7ng>nb z`N>ieQRGBTS)aoHljU-q&CiMdm7zJlBNzQ#A<3u6{!yo2#GGNVXCeX<;3 zKhD=XE%eh%zs-5Q{=SwrpM}NvCq@uPrGAJ2+rgq2AD(kd|3BuaAGK)SJoEDh7` z(9i-&sGbmuTp{C?^inbgIZevi#!0gQ8;3PpsY6teJ&#$^d1wfkSav6-o7kmS4}kp0 zPE8hD(BI|Ndq}_F)SEM3Z$nq0`Fl;m`!W%8CNzegN&=15Zf)*FLpC><47lFbX!EADGw*XKqh0gT_x}zed1u=RB zXAJQ9o#pgZzu#*ZK=|j!-ZR4pvN*_4Z{E?cI3H%eC<^vNf^M^+1B;ol*T!+~hRjz?0CkL3plji)}%XC5lJ1)X2E z5yz>@0;KzegZWyU0VLUIdY2BX&_E;nOFEy$EhYzq&Zn#=YeD}b7PHN^5NN!r>~Hq~ zVD@1ZMTXt*1C2af%KAtC3(_H2W(s9wnCvWjx5UiB3DViBO z>b6S{c?N6LsF2O3j9-cpbd(-GEwljyU*3S>vDZxp4doZCDHJegds`C-PRr`9W6UTj zn`4{hX}Hyx0Wvc;%C(n1rb8^YAJ7PMAUAj>RG`ruT7iswh=i(vpT14DkT-tgZ7ba3;6qOAO!8MxAH=e)l zgm=Y_U_?SwQ(5@Sw+;M^gn!|`Z=ZifRC64(u=q#6!V{vp?_ZrIqrL$-Jk{n|B2J6`S2E(*B6JEITF@F52@M`=W%e zpl^haO~d!-iEoxtF7m9bUP`zTFW$X-DtclMa4L;@6EnT$Tj9U3B_uU?=|4o5EV^** zYp<}mI@ePAy2N6_TuG>=#9jSGtAYUL3N7FzT7AHiJFObkFL|*1i+zp5>v^LCcV$^3u<@id%e*>Fu z=wHFC^$5#3*L;LevFhg2cmlz;l;9mBU~}0* zr>)J!TRI_j+s}H8r9^(kiYYx{bJ^ybW-}yl&q@~q{4Z?2i<=|?%Ai;`)x1({s&FfG z`xAL+YD{$T?vYs_O(43u?8Sz|(-zbh-N5cSuIOtPKVr3MwMrdL?A1X76Eh!VIh{r$ ztyi}53Uti8ohS<4E^914V-@7#t`-6ZP8F95T7`dJPC|RH^a`;LfvGj&8U zhBHLjuOIIWbSb*M#jf7#((HJ~x7JAO$Z3Cin6!?Ht~H^S+1?tjA@D752cBPcX-GT^ z4-8qeO$v{$SlC>nlX_R!dTsoH49gIudV4`IR!L|rP|G)FX|D-t#bd2VE7Zn(%MW#% zZJi~TXJoslarv~VPaIV9VEk?aDT_1z7PAc(9{c!2 z=wrOQWc0p1#af19agYvbe__@wzbXe~c!tef1qu5Qp zCmRigLZI0c-wTBR7kSPux{ngf&VT^Gz71UFw@om)YiBt5OE1>EI*8tU404I?9)|%; zhjV$v%qs@7Q&`RJR|YgMKcd}uKPm%5vratj3$&Z}nqY4xT4FZeU19Uc<9bcWYn*ofFRw4-)x(^ghtulm)9>SM($%<|GpU(xIv|RK{*MU;u{|(GU zeD#D6;j7e-NO{RciT$37ul6nnm1^v$$gYR=+t9(_G@sWVB?mcbJ^8qry+jpVF8dm??ok-Da&6PhrWH+E#cB8*dy@)aN~|etqG~9vLLKl?qWkY0=+#|KeZf9>Rg}m+Xun<`aFFIIFoPzQj&KW= zH~RYNM;Ho?OdLUnHA}Hk_03;5PdrC%OX7br6iR=CocyH z#F1TIiU&C!?ALo>=Y2%qmfVC{aj>KFK%}J3>g@42EFI#a$Qvyo5e>vmZ1%t1lFT4A zrTlSTDMvB()6tII;x|X%IxQJr9U7kM)s~!Y z_B^j+E6XD=uW*tUhd%0)S%jjQBLMXDB#tLUWxAT0-y1(7T}?q2JB2N)H$w-o3gbb) zF1k9$%CzMR(bZ*V4n=FbWW@VP#&X^he$ly$WOIV913D1OG^2?q3dSZ=1(-k$(}UMMok{c+tr))`Gt_=X$Gnqk4(LYg=;DaXMeK-jVA-sPWMq1f zhz@bmO{^$`zX`dzT(#W+6c=SoBDL$Tkt}>^_z&{WEwPyUMC5HGX(;7F>v8E(L}P~% zqX`vLi7mk8)t|&gp<+s)x#QLEoZ17@(&+w=n=rbhkfV$AeKo*8FcNx9x6X(rQAlP{Y6jZ*ya;r zdshhBzD&evjGUAVHn0v-(wId9KvsHhz@pIRM=rElSmU%5AhLQ}d9jWFXPdAn5)MH# zrlKEaYX(E8cUmo661q6%o{H?y3ESn>S52uotuusA0&3NE2M`g$-J)FctVw}Z~Q;&?CpXv(&b?`_F56Dyh)w2FctGSP>#Q` zE64`6vSKYL`mEULXA*`lD)@?+u0gxh#pG9W)%_7Z-%OHwZbP^bQ&pIU@e_PV5SX8lCpNN7bZfsf|$&?fC+%k!R50( z6@teLJXeC}!7RUgZm?bYzaXAQ?QSCQ+vZ($c;jm;#A|6D3l5 z?f1p^UlBlDC%kb6^Rr^~9#`@)9t_~bF+RqQhC0hWJs#92!LBu#hC#&>#Qb!V(^&iL zouG=yjFImD`z~gyB}ThD(4LSXA+FnWGKwtV4!6*EOqA8Wz*|UWy?XeHUlnx>>EM6f zM=3-XEFNgrxyX*Oe<|-3hUHAd=Py8ZAp4?nNe>LC86^(~+!v+;nf^VWAbFV*L-I*_ zHr@zb?w?8=+sZSUF~XrMq1|FNvgCY8u~w;8gm4gT?QD_nb;oo9kM4@Vy%W*b+tHk# zRjNLOTW_ADQ*!e+0J*a|@y=WFa_v19g9pEEZ#{2`pA;Mn7nkQafIA|2Nf=w#lnt z7qunra$AD|0JuwBR9>7ZD9ox@r`d!oKkzH6XhsLbKlB%D{+1Ya+WWtCd`A8VQc&z; z+aWHn0Zg*%Tavm^2OMYM5Y>uzRo15aqUh-m~U2SAyhmU>|p_-PX zNu=@JuGLRs1D6vE5s{B}d{OOJ5&m?0afx}OqrfxvBzZ;GEhaRH5Sf2V0YHl`Q6S&I zMSg@4?YP14FaQ_9#;RH(8cXJ_AZnA(18qmtvRS{9y=PEs==M~mYTDwp3Az~h{A%iD zu~$0aS#^^covnWm5lI+HxV1OWu&ZnM!~3fE*W;PXG0Bnv57z}&LVON)AzIPJB`TR8 z6)j1Um{4O4chINg!@+gly0XhbiL;J0{|@)j?6QjdUDWD1Xu$G|$3it6pk@DJdP9Fi zM@JaYsvWH)N8QF__PS5ZAZ_$kb8~?!T-!gQLpXYcl|C4DjtO}<*?2?R--S>g1&0-Q=(cY4biEQ z$Jtjhyy_fr+o5_z~|^)l^WwEBE=r*!XnUV|;w%>tXKx%091LQmyM`<3ZRa7w31^BFtY&H(2iXU2|I>!3^u{KimSv|!19Fev~J6QBp%^n{|w zm&mYhrL=akosDcTC~d-oBn*1lk-QwjW}+*86Q;H|Ft0p)v!e4e6YB$Qyn>3>;)^d= z(bnL0#ON8fIU9(L&=9vbLy9N)psNP-+)80c&(7bQF`6uy@1_@r-Emaa5$C7Pur+|| zJ?lzC+&4TM#i%qo3kV24+C2zpiDyy;fK`}pYm7kvz7HMnv3SO(^>9#18ZnOxRY3J2 z!Z);L&yrDX9Lhnb;Urygar9gnf)Xrt+x$Si%0D49pj-*1PFcUtLX@|Ul#2}6UQVG@ZA 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 z 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

9l%=Edkio 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%0DcmJ%pMqOV0VV@SWw>}D!q=m0$ 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 C(0on+ literal 0 HcmV?d00001 diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/PathplannerLib-2025.2.7.json b/prototype_projects/Experimental_Drivetrain/vendordeps/PathplannerLib-2025.2.7.json new file mode 100644 index 0000000..d3f84e5 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/vendordeps/PathplannerLib-2025.2.7.json @@ -0,0 +1,38 @@ +{ + "fileName": "PathplannerLib-2025.2.7.json", + "name": "PathplannerLib", + "version": "2025.2.7", + "uuid": "1b42324f-17c6-4875-8e77-1c312bc8c786", + "frcYear": "2025", + "mavenUrls": [ + "https://3015rangerrobotics.github.io/pathplannerlib/repo" + ], + "jsonUrl": "https://3015rangerrobotics.github.io/pathplannerlib/PathplannerLib.json", + "javaDependencies": [ + { + "groupId": "com.pathplanner.lib", + "artifactId": "PathplannerLib-java", + "version": "2025.2.7" + } + ], + "jniDependencies": [], + "cppDependencies": [ + { + "groupId": "com.pathplanner.lib", + "artifactId": "PathplannerLib-cpp", + "version": "2025.2.7", + "libName": "PathplannerLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "osxuniversal", + "linuxathena", + "linuxarm32", + "linuxarm64" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/Phoenix6-frc2025-latest.json b/prototype_projects/Experimental_Drivetrain/vendordeps/Phoenix6-frc2025-latest.json new file mode 100644 index 0000000..6f40c84 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/vendordeps/Phoenix6-frc2025-latest.json @@ -0,0 +1,479 @@ +{ + "fileName": "Phoenix6-frc2025-latest.json", + "name": "CTRE-Phoenix (v6)", + "version": "25.4.0", + "frcYear": "2025", + "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-frc2025-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-frc2025-latest.json" + } + ], + "javaDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-java", + "version": "25.4.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "api-cpp-sim", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simCANCoder", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "25.4.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "libName": "CTRE_SimPigeonIMU", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simCANCoder", + "version": "25.4.0", + "libName": "CTRE_SimCANCoder", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "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": "25.4.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/REVLib.json b/prototype_projects/Experimental_Drivetrain/vendordeps/REVLib.json new file mode 100644 index 0000000..ac62be8 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/vendordeps/REVLib.json @@ -0,0 +1,71 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2025.0.3", + "frcYear": "2025", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2025.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2025.0.3" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2025.0.3", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2025.0.3", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2025.0.3", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/Studica-2025.0.1.json b/prototype_projects/Experimental_Drivetrain/vendordeps/Studica-2025.0.1.json new file mode 100644 index 0000000..5010be0 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/vendordeps/Studica-2025.0.1.json @@ -0,0 +1,71 @@ +{ + "fileName": "Studica-2025.0.1.json", + "name": "Studica", + "version": "2025.0.1", + "uuid": "cb311d09-36e9-4143-a032-55bb2b94443b", + "frcYear": "2025", + "mavenUrls": [ + "https://dev.studica.com/maven/release/2025/" + ], + "jsonUrl": "https://dev.studica.com/releases/2025/Studica-2025.0.1.json", + "cppDependencies": [ + { + "artifactId": "Studica-cpp", + "binaryPlatforms": [ + "linuxathena", + "linuxarm32", + "linuxarm64", + "linuxx86-64", + "osxuniversal", + "windowsx86-64" + ], + "groupId": "com.studica.frc", + "headerClassifier": "headers", + "libName": "Studica", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "version": "2025.0.1" + }, + { + "artifactId": "Studica-driver", + "binaryPlatforms": [ + "linuxathena", + "linuxarm32", + "linuxarm64", + "linuxx86-64", + "osxuniversal", + "windowsx86-64" + ], + "groupId": "com.studica.frc", + "headerClassifier": "headers", + "libName": "StudicaDriver", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "version": "2025.0.1" + } + ], + "javaDependencies": [ + { + "artifactId": "Studica-java", + "groupId": "com.studica.frc", + "version": "2025.0.1" + } + ], + "jniDependencies": [ + { + "artifactId": "Studica-driver", + "groupId": "com.studica.frc", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "linuxathena", + "linuxarm32", + "linuxarm64", + "linuxx86-64", + "osxuniversal", + "windowsx86-64" + ], + "version": "2025.0.1" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/WPILibNewCommands.json b/prototype_projects/Experimental_Drivetrain/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..3718e0a --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain/vendordeps/WPILibNewCommands.json @@ -0,0 +1,38 @@ +{ + "fileName": "WPILibNewCommands.json", + "name": "WPILib-New-Commands", + "version": "1.0.0", + "uuid": "111e20f7-815e-48f8-9dd6-e675ce75b266", + "frcYear": "2025", + "mavenUrls": [], + "jsonUrl": "", + "javaDependencies": [ + { + "groupId": "edu.wpi.first.wpilibNewCommands", + "artifactId": "wpilibNewCommands-java", + "version": "wpilib" + } + ], + "jniDependencies": [], + "cppDependencies": [ + { + "groupId": "edu.wpi.first.wpilibNewCommands", + "artifactId": "wpilibNewCommands-cpp", + "version": "wpilib", + "libName": "wpilibNewCommands", + "headerClassifier": "headers", + "sourcesClassifier": "sources", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "linuxathena", + "linuxarm32", + "linuxarm64", + "windowsx86-64", + "windowsx86", + "linuxx86-64", + "osxuniversal" + ] + } + ] +} From 85d58fbe589fec1d0881b5414ee33ce515525ce2 Mon Sep 17 00:00:00 2001 From: 15 - Phosphorus <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:13:23 -0600 Subject: [PATCH 005/161] Ported Experimental_Drivetrain_2025 to WPILIB 2026 --- .../.SysId/sysid.json | 0 .../.github/workflows/ci.yml | 0 .../.gitignore | 0 .../.vscode/launch.json | 0 .../.vscode/settings.json | 0 .../.wpilib/wpilib_preferences.json | 0 .../LICENSE | 0 .../Makefile | 0 .../README.md | 0 .../WPILib-License.md | 0 .../build.gradle | 0 .../common-repo-sync.sh | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../gradlew | 0 .../gradlew.bat | 0 .../settings.gradle | 0 .../simgui-ds.json | 0 .../src/main/deploy/example.txt | 0 .../deploy/pathplanner/autos/SampleAuto.auto | 0 .../src/main/deploy/pathplanner/navgrid.json | 0 .../pathplanner/paths/Example Path.path | 0 .../src/main/deploy/pathplanner/settings.json | 0 .../src/main/java/frc/robot/Constants.java | 0 .../main/java/frc/robot/LimelightHelpers.java | 0 .../src/main/java/frc/robot/Main.java | 0 .../src/main/java/frc/robot/Robot.java | 0 .../main/java/frc/robot/RobotContainer.java | 0 .../robot/commands/ArcadeDriveCommand.java | 0 .../main/java/frc/robot/commands/Autos.java | 0 .../commands/DifferentialDriveCommand.java | 0 .../frc/robot/commands/ExampleCommand.java | 0 .../robot/factorys/DriveSubsystemFactory.java | 0 .../frc/robot/factorys/TalonFXFactory.java | 0 .../frc/robot/subsystems/DriveSubsystem.java | 0 .../robot/subsystems/ExampleSubsystem.java | 0 .../robot/subsystems/LimelightSubsystem.java | 0 .../java/frc/robot/utils/AutoCommands.java | 0 .../main/java/frc/robot/utils/PIDControl.java | 0 .../sysid_logs/Screenshot (1).png | Bin .../hoots/rio_2025-11-11_19-44-12.hoot | Bin .../rio_2025-11-11_19-44-12.hoot.wpilog | Bin .../vendordeps/PathplannerLib-2025.2.7.json | 0 .../vendordeps/Phoenix6-frc2025-latest.json | 0 .../vendordeps/REVLib.json | 0 .../vendordeps/Studica-2025.0.1.json | 0 .../vendordeps/WPILibNewCommands.json | 0 .../Experimental_Drivetrain_2026/.gitignore | 187 ++ .../.vscode/launch.json | 21 + .../.vscode/settings.json | 61 + .../.wpilib/wpilib_preferences.json | 6 + .../WPILib-License.md | 24 + .../Experimental_Drivetrain_2026/build.gradle | 107 ++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../Experimental_Drivetrain_2026/gradlew | 252 +++ .../Experimental_Drivetrain_2026/gradlew.bat | 94 + .../settings.gradle | 30 + .../src/main/deploy/example.txt | 3 + .../deploy/pathplanner/autos/SampleAuto.auto | 19 + .../src/main/deploy/pathplanner/navgrid.json | 1 + .../pathplanner/paths/Example Path.path | 54 + .../src/main/deploy/pathplanner/settings.json | 34 + .../src/main/java/frc/robot/Constants.java | 91 + .../main/java/frc/robot/LimelightHelpers.java | 1645 +++++++++++++++++ .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 103 ++ .../main/java/frc/robot/RobotContainer.java | 156 ++ .../robot/commands/ArcadeDriveCommand.java | 53 + .../main/java/frc/robot/commands/Autos.java | 20 + .../commands/DifferentialDriveCommand.java | 57 + .../frc/robot/commands/ExampleCommand.java | 43 + .../robot/factorys/DriveSubsystemFactory.java | 33 + .../frc/robot/factorys/TalonFXFactory.java | 20 + .../frc/robot/subsystems/DriveSubsystem.java | 285 +++ .../robot/subsystems/ExampleSubsystem.java | 47 + .../robot/subsystems/LimelightSubsystem.java | 48 + .../java/frc/robot/utils/AutoCommands.java | 59 + .../main/java/frc/robot/utils/PIDControl.java | 69 + .../vendordeps/WPILibNewCommands.json | 39 + 80 files changed, 3693 insertions(+) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/.SysId/sysid.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/.github/workflows/ci.yml (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/.gitignore (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/.vscode/launch.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/.vscode/settings.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/.wpilib/wpilib_preferences.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/LICENSE (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/Makefile (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/README.md (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/WPILib-License.md (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/build.gradle (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/common-repo-sync.sh (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/gradle/wrapper/gradle-wrapper.jar (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/gradle/wrapper/gradle-wrapper.properties (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/gradlew (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/gradlew.bat (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/settings.gradle (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/simgui-ds.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/deploy/example.txt (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/deploy/pathplanner/autos/SampleAuto.auto (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/deploy/pathplanner/navgrid.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/deploy/pathplanner/paths/Example Path.path (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/deploy/pathplanner/settings.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/Constants.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/LimelightHelpers.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/Main.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/Robot.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/RobotContainer.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/commands/ArcadeDriveCommand.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/commands/Autos.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/commands/DifferentialDriveCommand.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/commands/ExampleCommand.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/factorys/TalonFXFactory.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/subsystems/DriveSubsystem.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/subsystems/ExampleSubsystem.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/subsystems/LimelightSubsystem.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/utils/AutoCommands.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/src/main/java/frc/robot/utils/PIDControl.java (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/sysid_logs/Screenshot (1).png (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/sysid_logs/hoots/rio_2025-11-11_19-44-12.hoot (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/sysid_logs/wpilogs/rio_2025-11-11_19-44-12.hoot.wpilog (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/vendordeps/PathplannerLib-2025.2.7.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/vendordeps/Phoenix6-frc2025-latest.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/vendordeps/REVLib.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/vendordeps/Studica-2025.0.1.json (100%) rename prototype_projects/{Experimental_Drivetrain => Experimental_Drivetrain_2025}/vendordeps/WPILibNewCommands.json (100%) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/.gitignore create mode 100644 prototype_projects/Experimental_Drivetrain_2026/.vscode/launch.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/.vscode/settings.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/WPILib-License.md create mode 100644 prototype_projects/Experimental_Drivetrain_2026/build.gradle create mode 100644 prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/Experimental_Drivetrain_2026/gradlew create mode 100644 prototype_projects/Experimental_Drivetrain_2026/gradlew.bat create mode 100644 prototype_projects/Experimental_Drivetrain_2026/settings.gradle create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/example.txt create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/LimelightHelpers.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/Autos.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ExampleCommand.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/ExampleSubsystem.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/AutoCommands.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java create mode 100644 prototype_projects/Experimental_Drivetrain_2026/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/Experimental_Drivetrain/.SysId/sysid.json b/prototype_projects/Experimental_Drivetrain_2025/.SysId/sysid.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/.SysId/sysid.json rename to prototype_projects/Experimental_Drivetrain_2025/.SysId/sysid.json diff --git a/prototype_projects/Experimental_Drivetrain/.github/workflows/ci.yml b/prototype_projects/Experimental_Drivetrain_2025/.github/workflows/ci.yml similarity index 100% rename from prototype_projects/Experimental_Drivetrain/.github/workflows/ci.yml rename to prototype_projects/Experimental_Drivetrain_2025/.github/workflows/ci.yml diff --git a/prototype_projects/Experimental_Drivetrain/.gitignore b/prototype_projects/Experimental_Drivetrain_2025/.gitignore similarity index 100% rename from prototype_projects/Experimental_Drivetrain/.gitignore rename to prototype_projects/Experimental_Drivetrain_2025/.gitignore diff --git a/prototype_projects/Experimental_Drivetrain/.vscode/launch.json b/prototype_projects/Experimental_Drivetrain_2025/.vscode/launch.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/.vscode/launch.json rename to prototype_projects/Experimental_Drivetrain_2025/.vscode/launch.json diff --git a/prototype_projects/Experimental_Drivetrain/.vscode/settings.json b/prototype_projects/Experimental_Drivetrain_2025/.vscode/settings.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/.vscode/settings.json rename to prototype_projects/Experimental_Drivetrain_2025/.vscode/settings.json diff --git a/prototype_projects/Experimental_Drivetrain/.wpilib/wpilib_preferences.json b/prototype_projects/Experimental_Drivetrain_2025/.wpilib/wpilib_preferences.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/.wpilib/wpilib_preferences.json rename to prototype_projects/Experimental_Drivetrain_2025/.wpilib/wpilib_preferences.json diff --git a/prototype_projects/Experimental_Drivetrain/LICENSE b/prototype_projects/Experimental_Drivetrain_2025/LICENSE similarity index 100% rename from prototype_projects/Experimental_Drivetrain/LICENSE rename to prototype_projects/Experimental_Drivetrain_2025/LICENSE diff --git a/prototype_projects/Experimental_Drivetrain/Makefile b/prototype_projects/Experimental_Drivetrain_2025/Makefile similarity index 100% rename from prototype_projects/Experimental_Drivetrain/Makefile rename to prototype_projects/Experimental_Drivetrain_2025/Makefile diff --git a/prototype_projects/Experimental_Drivetrain/README.md b/prototype_projects/Experimental_Drivetrain_2025/README.md similarity index 100% rename from prototype_projects/Experimental_Drivetrain/README.md rename to prototype_projects/Experimental_Drivetrain_2025/README.md diff --git a/prototype_projects/Experimental_Drivetrain/WPILib-License.md b/prototype_projects/Experimental_Drivetrain_2025/WPILib-License.md similarity index 100% rename from prototype_projects/Experimental_Drivetrain/WPILib-License.md rename to prototype_projects/Experimental_Drivetrain_2025/WPILib-License.md diff --git a/prototype_projects/Experimental_Drivetrain/build.gradle b/prototype_projects/Experimental_Drivetrain_2025/build.gradle similarity index 100% rename from prototype_projects/Experimental_Drivetrain/build.gradle rename to prototype_projects/Experimental_Drivetrain_2025/build.gradle diff --git a/prototype_projects/Experimental_Drivetrain/common-repo-sync.sh b/prototype_projects/Experimental_Drivetrain_2025/common-repo-sync.sh similarity index 100% rename from prototype_projects/Experimental_Drivetrain/common-repo-sync.sh rename to prototype_projects/Experimental_Drivetrain_2025/common-repo-sync.sh diff --git a/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/Experimental_Drivetrain_2025/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.jar rename to prototype_projects/Experimental_Drivetrain_2025/gradle/wrapper/gradle-wrapper.jar diff --git a/prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/Experimental_Drivetrain_2025/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from prototype_projects/Experimental_Drivetrain/gradle/wrapper/gradle-wrapper.properties rename to prototype_projects/Experimental_Drivetrain_2025/gradle/wrapper/gradle-wrapper.properties diff --git a/prototype_projects/Experimental_Drivetrain/gradlew b/prototype_projects/Experimental_Drivetrain_2025/gradlew similarity index 100% rename from prototype_projects/Experimental_Drivetrain/gradlew rename to prototype_projects/Experimental_Drivetrain_2025/gradlew diff --git a/prototype_projects/Experimental_Drivetrain/gradlew.bat b/prototype_projects/Experimental_Drivetrain_2025/gradlew.bat similarity index 100% rename from prototype_projects/Experimental_Drivetrain/gradlew.bat rename to prototype_projects/Experimental_Drivetrain_2025/gradlew.bat diff --git a/prototype_projects/Experimental_Drivetrain/settings.gradle b/prototype_projects/Experimental_Drivetrain_2025/settings.gradle similarity index 100% rename from prototype_projects/Experimental_Drivetrain/settings.gradle rename to prototype_projects/Experimental_Drivetrain_2025/settings.gradle diff --git a/prototype_projects/Experimental_Drivetrain/simgui-ds.json b/prototype_projects/Experimental_Drivetrain_2025/simgui-ds.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/simgui-ds.json rename to prototype_projects/Experimental_Drivetrain_2025/simgui-ds.json diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/example.txt b/prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/example.txt similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/deploy/example.txt rename to prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/example.txt diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/autos/SampleAuto.auto b/prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/autos/SampleAuto.auto similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/autos/SampleAuto.auto rename to prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/autos/SampleAuto.auto diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/navgrid.json b/prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/navgrid.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/navgrid.json rename to prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/navgrid.json diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/paths/Example Path.path b/prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/paths/Example Path.path similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/paths/Example Path.path rename to prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/paths/Example Path.path diff --git a/prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/settings.json b/prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/settings.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/deploy/pathplanner/settings.json rename to prototype_projects/Experimental_Drivetrain_2025/src/main/deploy/pathplanner/settings.json diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/Constants.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Constants.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/Constants.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/LimelightHelpers.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/LimelightHelpers.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/LimelightHelpers.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/LimelightHelpers.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Main.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/Main.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Main.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/Main.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/Robot.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/Robot.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/Robot.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/RobotContainer.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/RobotContainer.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/RobotContainer.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/ArcadeDriveCommand.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ArcadeDriveCommand.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/ArcadeDriveCommand.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/Autos.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/Autos.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/Autos.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/DifferentialDriveCommand.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/DifferentialDriveCommand.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/DifferentialDriveCommand.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/ExampleCommand.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/commands/ExampleCommand.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/commands/ExampleCommand.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/TalonFXFactory.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/factorys/TalonFXFactory.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/factorys/TalonFXFactory.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/factorys/TalonFXFactory.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/subsystems/DriveSubsystem.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/DriveSubsystem.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/subsystems/DriveSubsystem.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/subsystems/ExampleSubsystem.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/ExampleSubsystem.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/subsystems/ExampleSubsystem.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/subsystems/LimelightSubsystem.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/subsystems/LimelightSubsystem.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/subsystems/LimelightSubsystem.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/AutoCommands.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/utils/AutoCommands.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/AutoCommands.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/utils/AutoCommands.java diff --git a/prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/PIDControl.java b/prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/utils/PIDControl.java similarity index 100% rename from prototype_projects/Experimental_Drivetrain/src/main/java/frc/robot/utils/PIDControl.java rename to prototype_projects/Experimental_Drivetrain_2025/src/main/java/frc/robot/utils/PIDControl.java diff --git a/prototype_projects/Experimental_Drivetrain/sysid_logs/Screenshot (1).png b/prototype_projects/Experimental_Drivetrain_2025/sysid_logs/Screenshot (1).png similarity index 100% rename from prototype_projects/Experimental_Drivetrain/sysid_logs/Screenshot (1).png rename to prototype_projects/Experimental_Drivetrain_2025/sysid_logs/Screenshot (1).png diff --git a/prototype_projects/Experimental_Drivetrain/sysid_logs/hoots/rio_2025-11-11_19-44-12.hoot b/prototype_projects/Experimental_Drivetrain_2025/sysid_logs/hoots/rio_2025-11-11_19-44-12.hoot similarity index 100% rename from prototype_projects/Experimental_Drivetrain/sysid_logs/hoots/rio_2025-11-11_19-44-12.hoot rename to prototype_projects/Experimental_Drivetrain_2025/sysid_logs/hoots/rio_2025-11-11_19-44-12.hoot diff --git a/prototype_projects/Experimental_Drivetrain/sysid_logs/wpilogs/rio_2025-11-11_19-44-12.hoot.wpilog b/prototype_projects/Experimental_Drivetrain_2025/sysid_logs/wpilogs/rio_2025-11-11_19-44-12.hoot.wpilog similarity index 100% rename from prototype_projects/Experimental_Drivetrain/sysid_logs/wpilogs/rio_2025-11-11_19-44-12.hoot.wpilog rename to prototype_projects/Experimental_Drivetrain_2025/sysid_logs/wpilogs/rio_2025-11-11_19-44-12.hoot.wpilog diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/PathplannerLib-2025.2.7.json b/prototype_projects/Experimental_Drivetrain_2025/vendordeps/PathplannerLib-2025.2.7.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/vendordeps/PathplannerLib-2025.2.7.json rename to prototype_projects/Experimental_Drivetrain_2025/vendordeps/PathplannerLib-2025.2.7.json diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/Phoenix6-frc2025-latest.json b/prototype_projects/Experimental_Drivetrain_2025/vendordeps/Phoenix6-frc2025-latest.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/vendordeps/Phoenix6-frc2025-latest.json rename to prototype_projects/Experimental_Drivetrain_2025/vendordeps/Phoenix6-frc2025-latest.json diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/REVLib.json b/prototype_projects/Experimental_Drivetrain_2025/vendordeps/REVLib.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/vendordeps/REVLib.json rename to prototype_projects/Experimental_Drivetrain_2025/vendordeps/REVLib.json diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/Studica-2025.0.1.json b/prototype_projects/Experimental_Drivetrain_2025/vendordeps/Studica-2025.0.1.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/vendordeps/Studica-2025.0.1.json rename to prototype_projects/Experimental_Drivetrain_2025/vendordeps/Studica-2025.0.1.json diff --git a/prototype_projects/Experimental_Drivetrain/vendordeps/WPILibNewCommands.json b/prototype_projects/Experimental_Drivetrain_2025/vendordeps/WPILibNewCommands.json similarity index 100% rename from prototype_projects/Experimental_Drivetrain/vendordeps/WPILibNewCommands.json rename to prototype_projects/Experimental_Drivetrain_2025/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/Experimental_Drivetrain_2026/.gitignore b/prototype_projects/Experimental_Drivetrain_2026/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/.gitignore @@ -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 diff --git a/prototype_projects/Experimental_Drivetrain_2026/.vscode/launch.json b/prototype_projects/Experimental_Drivetrain_2026/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/.vscode/settings.json b/prototype_projects/Experimental_Drivetrain_2026/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/.wpilib/wpilib_preferences.json b/prototype_projects/Experimental_Drivetrain_2026/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..994eeed --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/WPILib-License.md b/prototype_projects/Experimental_Drivetrain_2026/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/Experimental_Drivetrain_2026/build.gradle b/prototype_projects/Experimental_Drivetrain_2026/build.gradle new file mode 100644 index 0000000..f2ceadb --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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 = false + +// 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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/Experimental_Drivetrain_2026/gradlew b/prototype_projects/Experimental_Drivetrain_2026/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/gradlew @@ -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" "$@" diff --git a/prototype_projects/Experimental_Drivetrain_2026/gradlew.bat b/prototype_projects/Experimental_Drivetrain_2026/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/gradlew.bat @@ -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 diff --git a/prototype_projects/Experimental_Drivetrain_2026/settings.gradle b/prototype_projects/Experimental_Drivetrain_2026/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/settings.gradle @@ -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"); diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/example.txt b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto new file mode 100644 index 0000000..70b7ab2 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Example Path" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json new file mode 100644 index 0000000..23e0db9 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json @@ -0,0 +1 @@ +{"field_size":{"x":17.548,"y":8.052},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path new file mode 100644 index 0000000..d474f95 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.1486729452054796, + "y": 6.48169948630137 + }, + "prevControl": null, + "nextControl": { + "x": 2.3986729452054796, + "y": 6.48169948630137 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 5.213912671232877, + "y": 6.48169948630137 + }, + "prevControl": { + "x": 4.963912671232877, + "y": 6.48169948630137 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 3.0, + "maxAcceleration": 3.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json new file mode 100644 index 0000000..75d95ab --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json @@ -0,0 +1,34 @@ +{ + "robotWidth": 0.9, + "robotLength": 0.9, + "holonomicMode": false, + "pathFolders": [ + "New Folder" + ], + "autoFolders": [], + "defaultMaxVel": 3.0, + "defaultMaxAccel": 3.0, + "defaultMaxAngVel": 540.0, + "defaultMaxAngAccel": 720.0, + "defaultNominalVoltage": 12.0, + "robotMass": 74.088, + "robotMOI": 6.883, + "robotTrackwidth": 0.546, + "driveWheelRadius": 0.0508, + "driveGearing": 5.143, + "maxDriveSpeed": 5.45, + "driveMotorType": "krakenX60", + "driveCurrentLimit": 60.0, + "wheelCOF": 1.0, + "flModuleX": 0.273, + "flModuleY": 0.273, + "frModuleX": 0.273, + "frModuleY": -0.273, + "blModuleX": -0.273, + "blModuleY": 0.273, + "brModuleX": -0.273, + "brModuleY": -0.273, + "bumperOffsetX": 0.0, + "bumperOffsetY": 0.0, + "robotFeatures": [] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..5a4561c --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -0,0 +1,91 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import com.pathplanner.lib.config.ModuleConfig; +import com.pathplanner.lib.config.RobotConfig; + +import edu.wpi.first.math.system.plant.DCMotor; + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + public static class AutoConstants { + // Module Config Stuff + public static final double kMaxDriveVelocityMPS = 40.0; // This is what SysID is saying i dont think its going 90 mph + public static final double kWheelCOF = 1.0; + public static final int kNumMotors = 4; + public static final double kDriveCurrentLimit = 10.0; + + public static final DCMotor kDriveMotor = DCMotor.getKrakenX60(kNumMotors); + public static final ModuleConfig kMoudleConfig = new ModuleConfig( + DrivetrainConstants.kWheelRadiusMeters, + kMaxDriveVelocityMPS, + kWheelCOF, + kDriveMotor, + kDriveCurrentLimit, + kNumMotors + ); + + // Robot Config Stuff + // TODO: Run SYS ID and fill in! + public static final double kMassKG = 15.0; + public static final double kMOI = kMassKG * (DrivetrainConstants.trackWidthMeters/2) * (DrivetrainConstants.kA_angular / DrivetrainConstants.kA_linear); // Moment of Intertia + + public static final RobotConfig kRobotConfig = new RobotConfig(kMassKG, kMOI, kMoudleConfig, DrivetrainConstants.trackWidthMeters); + } + + public static class OperatorConstants { + public static final int kDriverControllerPort = 0; + } + + public static class DrivetrainConstants { + public static final int kLeftMotorCANID = 10; + public static final int kOptionalLeftMotorCANID = 11; + + public static final int kRightMotorCANID = 20; + public static final int kOptionalRightMotorCANID = 21; + + public static final double kTurnDivider = 2; + public static final double kSpeedDivider = 2.5; + + // These numbers came from sys id program + public static final double kV = 1.8747; // Add x V output to overcome static friction + public static final double kS = 0.15316; // A velocity target of 1 rps results in xV output + public static final double kP = 2.7562; // An error of 1 rotation results in x V output + public static final double kI = 0.0; + public static final double kD = 0.0; // A velocity of 1 rps results in x V output + public static final double kA_linear = 0.1141; // Voltage needed to induce a given accel. in the motor shaft + public static final double kA_angular = 0.1141; // TODO: We need to measure this! + public static final double PeakVoltage = 10.0; + + public static final int maxVelocity = 30; // rps/s + public static final int maxAcceleration = 50; // rps + + // Constants used by differential drive command. + public static final double maxVelocityMPS = 1.0; + + // For Auto Potentially + public static boolean kLeftPositiveMovesForward = true; + public static boolean kRightPositiveMovesForward = true; + + // Physical measurements related to the drivetrain. + public static final double kDrivetrainGearRatio = 0.2; + public static final double kWheelRadiusMeters = (4.0 / 2.0) * 0.0254; // Four Inch Wheels + public static final double kWheelCircumference = 2 * Math.PI * DrivetrainConstants.kWheelRadiusMeters; + + // SmartDashboard update frequency for drive subsystem state in 20ms counts. + public static final int kTicksPerUpdate = 5; + + // The track width in meters. + public static final double trackWidthMeters = 29.0 * 0.0254; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/LimelightHelpers.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/LimelightHelpers.java new file mode 100644 index 0000000..1dbf387 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/LimelightHelpers.java @@ -0,0 +1,1645 @@ +//LimelightHelpers v1.11 (REQUIRES LLOS 2025.0 OR LATER) + +package frc.robot; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Pose3d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.geometry.Rotation3d; +import edu.wpi.first.math.geometry.Translation2d; +import edu.wpi.first.math.geometry.Translation3d; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.networktables.DoubleArrayEntry; +import edu.wpi.first.networktables.NetworkTable; +import edu.wpi.first.networktables.NetworkTableEntry; +import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.networktables.TimestampedDoubleArray; + +/** + * LimelightHelpers provides static methods and classes for interfacing with Limelight vision cameras in FRC. + * This library supports all Limelight features including AprilTag tracking, Neural Networks, and standard color/retroreflective tracking. + */ +public class LimelightHelpers { + + private static final Map doubleArrayEntries = new ConcurrentHashMap<>(); + + /** + * Represents a Color/Retroreflective Target Result extracted from JSON Output + */ + public static class LimelightTarget_Retro { + + @JsonProperty("t6c_ts") + private double[] cameraPose_TargetSpace; + + @JsonProperty("t6r_fs") + private double[] robotPose_FieldSpace; + + @JsonProperty("t6r_ts") + private double[] robotPose_TargetSpace; + + @JsonProperty("t6t_cs") + private double[] targetPose_CameraSpace; + + @JsonProperty("t6t_rs") + private double[] targetPose_RobotSpace; + + public Pose3d getCameraPose_TargetSpace() + { + return toPose3D(cameraPose_TargetSpace); + } + public Pose3d getRobotPose_FieldSpace() + { + return toPose3D(robotPose_FieldSpace); + } + public Pose3d getRobotPose_TargetSpace() + { + return toPose3D(robotPose_TargetSpace); + } + public Pose3d getTargetPose_CameraSpace() + { + return toPose3D(targetPose_CameraSpace); + } + public Pose3d getTargetPose_RobotSpace() + { + return toPose3D(targetPose_RobotSpace); + } + + public Pose2d getCameraPose_TargetSpace2D() + { + return toPose2D(cameraPose_TargetSpace); + } + public Pose2d getRobotPose_FieldSpace2D() + { + return toPose2D(robotPose_FieldSpace); + } + public Pose2d getRobotPose_TargetSpace2D() + { + return toPose2D(robotPose_TargetSpace); + } + public Pose2d getTargetPose_CameraSpace2D() + { + return toPose2D(targetPose_CameraSpace); + } + public Pose2d getTargetPose_RobotSpace2D() + { + return toPose2D(targetPose_RobotSpace); + } + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ts") + public double ts; + + public LimelightTarget_Retro() { + cameraPose_TargetSpace = new double[6]; + robotPose_FieldSpace = new double[6]; + robotPose_TargetSpace = new double[6]; + targetPose_CameraSpace = new double[6]; + targetPose_RobotSpace = new double[6]; + } + + } + + /** + * Represents an AprilTag/Fiducial Target Result extracted from JSON Output + */ + public static class LimelightTarget_Fiducial { + + @JsonProperty("fID") + public double fiducialID; + + @JsonProperty("fam") + public String fiducialFamily; + + @JsonProperty("t6c_ts") + private double[] cameraPose_TargetSpace; + + @JsonProperty("t6r_fs") + private double[] robotPose_FieldSpace; + + @JsonProperty("t6r_ts") + private double[] robotPose_TargetSpace; + + @JsonProperty("t6t_cs") + private double[] targetPose_CameraSpace; + + @JsonProperty("t6t_rs") + private double[] targetPose_RobotSpace; + + public Pose3d getCameraPose_TargetSpace() + { + return toPose3D(cameraPose_TargetSpace); + } + public Pose3d getRobotPose_FieldSpace() + { + return toPose3D(robotPose_FieldSpace); + } + public Pose3d getRobotPose_TargetSpace() + { + return toPose3D(robotPose_TargetSpace); + } + public Pose3d getTargetPose_CameraSpace() + { + return toPose3D(targetPose_CameraSpace); + } + public Pose3d getTargetPose_RobotSpace() + { + return toPose3D(targetPose_RobotSpace); + } + + public Pose2d getCameraPose_TargetSpace2D() + { + return toPose2D(cameraPose_TargetSpace); + } + public Pose2d getRobotPose_FieldSpace2D() + { + return toPose2D(robotPose_FieldSpace); + } + public Pose2d getRobotPose_TargetSpace2D() + { + return toPose2D(robotPose_TargetSpace); + } + public Pose2d getTargetPose_CameraSpace2D() + { + return toPose2D(targetPose_CameraSpace); + } + public Pose2d getTargetPose_RobotSpace2D() + { + return toPose2D(targetPose_RobotSpace); + } + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ts") + public double ts; + + public LimelightTarget_Fiducial() { + cameraPose_TargetSpace = new double[6]; + robotPose_FieldSpace = new double[6]; + robotPose_TargetSpace = new double[6]; + targetPose_CameraSpace = new double[6]; + targetPose_RobotSpace = new double[6]; + } + } + + /** + * Represents a Barcode Target Result extracted from JSON Output + */ + public static class LimelightTarget_Barcode { + + /** + * Barcode family type (e.g. "QR", "DataMatrix", etc.) + */ + @JsonProperty("fam") + public String family; + + /** + * Gets the decoded data content of the barcode + */ + @JsonProperty("data") + public String data; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ta") + public double ta; + + @JsonProperty("pts") + public double[][] corners; + + public LimelightTarget_Barcode() { + } + + public String getFamily() { + return family; + } + } + + /** + * Represents a Neural Classifier Pipeline Result extracted from JSON Output + */ + public static class LimelightTarget_Classifier { + + @JsonProperty("class") + public String className; + + @JsonProperty("classID") + public double classID; + + @JsonProperty("conf") + public double confidence; + + @JsonProperty("zone") + public double zone; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("typ") + public double ty_pixels; + + public LimelightTarget_Classifier() { + } + } + + /** + * Represents a Neural Detector Pipeline Result extracted from JSON Output + */ + public static class LimelightTarget_Detector { + + @JsonProperty("class") + public String className; + + @JsonProperty("classID") + public double classID; + + @JsonProperty("conf") + public double confidence; + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + public LimelightTarget_Detector() { + } + } + + /** + * Limelight Results object, parsed from a Limelight's JSON results output. + */ + public static class LimelightResults { + + public String error; + + @JsonProperty("pID") + public double pipelineID; + + @JsonProperty("tl") + public double latency_pipeline; + + @JsonProperty("cl") + public double latency_capture; + + public double latency_jsonParse; + + @JsonProperty("ts") + public double timestamp_LIMELIGHT_publish; + + @JsonProperty("ts_rio") + public double timestamp_RIOFPGA_capture; + + @JsonProperty("v") + @JsonFormat(shape = Shape.NUMBER) + public boolean valid; + + @JsonProperty("botpose") + public double[] botpose; + + @JsonProperty("botpose_wpired") + public double[] botpose_wpired; + + @JsonProperty("botpose_wpiblue") + public double[] botpose_wpiblue; + + @JsonProperty("botpose_tagcount") + public double botpose_tagcount; + + @JsonProperty("botpose_span") + public double botpose_span; + + @JsonProperty("botpose_avgdist") + public double botpose_avgdist; + + @JsonProperty("botpose_avgarea") + public double botpose_avgarea; + + @JsonProperty("t6c_rs") + public double[] camerapose_robotspace; + + public Pose3d getBotPose3d() { + return toPose3D(botpose); + } + + public Pose3d getBotPose3d_wpiRed() { + return toPose3D(botpose_wpired); + } + + public Pose3d getBotPose3d_wpiBlue() { + return toPose3D(botpose_wpiblue); + } + + public Pose2d getBotPose2d() { + return toPose2D(botpose); + } + + public Pose2d getBotPose2d_wpiRed() { + return toPose2D(botpose_wpired); + } + + public Pose2d getBotPose2d_wpiBlue() { + return toPose2D(botpose_wpiblue); + } + + @JsonProperty("Retro") + public LimelightTarget_Retro[] targets_Retro; + + @JsonProperty("Fiducial") + public LimelightTarget_Fiducial[] targets_Fiducials; + + @JsonProperty("Classifier") + public LimelightTarget_Classifier[] targets_Classifier; + + @JsonProperty("Detector") + public LimelightTarget_Detector[] targets_Detector; + + @JsonProperty("Barcode") + public LimelightTarget_Barcode[] targets_Barcode; + + public LimelightResults() { + botpose = new double[6]; + botpose_wpired = new double[6]; + botpose_wpiblue = new double[6]; + camerapose_robotspace = new double[6]; + targets_Retro = new LimelightTarget_Retro[0]; + targets_Fiducials = new LimelightTarget_Fiducial[0]; + targets_Classifier = new LimelightTarget_Classifier[0]; + targets_Detector = new LimelightTarget_Detector[0]; + targets_Barcode = new LimelightTarget_Barcode[0]; + + } + + + } + + /** + * Represents a Limelight Raw Fiducial result from Limelight's NetworkTables output. + */ + public static class RawFiducial { + public int id = 0; + public double txnc = 0; + public double tync = 0; + public double ta = 0; + public double distToCamera = 0; + public double distToRobot = 0; + public double ambiguity = 0; + + + public RawFiducial(int id, double txnc, double tync, double ta, double distToCamera, double distToRobot, double ambiguity) { + this.id = id; + this.txnc = txnc; + this.tync = tync; + this.ta = ta; + this.distToCamera = distToCamera; + this.distToRobot = distToRobot; + this.ambiguity = ambiguity; + } + } + + /** + * Represents a Limelight Raw Neural Detector result from Limelight's NetworkTables output. + */ + public static class RawDetection { + public int classId = 0; + public double txnc = 0; + public double tync = 0; + public double ta = 0; + public double corner0_X = 0; + public double corner0_Y = 0; + public double corner1_X = 0; + public double corner1_Y = 0; + public double corner2_X = 0; + public double corner2_Y = 0; + public double corner3_X = 0; + public double corner3_Y = 0; + + + public RawDetection(int classId, double txnc, double tync, double ta, + double corner0_X, double corner0_Y, + double corner1_X, double corner1_Y, + double corner2_X, double corner2_Y, + double corner3_X, double corner3_Y ) { + this.classId = classId; + this.txnc = txnc; + this.tync = tync; + this.ta = ta; + this.corner0_X = corner0_X; + this.corner0_Y = corner0_Y; + this.corner1_X = corner1_X; + this.corner1_Y = corner1_Y; + this.corner2_X = corner2_X; + this.corner2_Y = corner2_Y; + this.corner3_X = corner3_X; + this.corner3_Y = corner3_Y; + } + } + + /** + * Represents a 3D Pose Estimate. + */ + public static class PoseEstimate { + public Pose2d pose; + public double timestampSeconds; + public double latency; + public int tagCount; + public double tagSpan; + public double avgTagDist; + public double avgTagArea; + + public RawFiducial[] rawFiducials; + public boolean isMegaTag2; + + /** + * Instantiates a PoseEstimate object with default values + */ + public PoseEstimate() { + this.pose = new Pose2d(); + this.timestampSeconds = 0; + this.latency = 0; + this.tagCount = 0; + this.tagSpan = 0; + this.avgTagDist = 0; + this.avgTagArea = 0; + this.rawFiducials = new RawFiducial[]{}; + this.isMegaTag2 = false; + } + + public PoseEstimate(Pose2d pose, double timestampSeconds, double latency, + int tagCount, double tagSpan, double avgTagDist, + double avgTagArea, RawFiducial[] rawFiducials, boolean isMegaTag2) { + + this.pose = pose; + this.timestampSeconds = timestampSeconds; + this.latency = latency; + this.tagCount = tagCount; + this.tagSpan = tagSpan; + this.avgTagDist = avgTagDist; + this.avgTagArea = avgTagArea; + this.rawFiducials = rawFiducials; + this.isMegaTag2 = isMegaTag2; + } + + } + + /** + * Encapsulates the state of an internal Limelight IMU. + */ + public static class IMUData { + public double robotYaw = 0.0; + public double Roll = 0.0; + public double Pitch = 0.0; + public double Yaw = 0.0; + public double gyroX = 0.0; + public double gyroY = 0.0; + public double gyroZ = 0.0; + public double accelX = 0.0; + public double accelY = 0.0; + public double accelZ = 0.0; + + public IMUData() {} + + public IMUData(double[] imuData) { + if (imuData != null && imuData.length >= 10) { + this.robotYaw = imuData[0]; + this.Roll = imuData[1]; + this.Pitch = imuData[2]; + this.Yaw = imuData[3]; + this.gyroX = imuData[4]; + this.gyroY = imuData[5]; + this.gyroZ = imuData[6]; + this.accelX = imuData[7]; + this.accelY = imuData[8]; + this.accelZ = imuData[9]; + } + } + } + + + private static ObjectMapper mapper; + + /** + * Print JSON Parse time to the console in milliseconds + */ + static boolean profileJSON = false; + + static final String sanitizeName(String name) { + if (name == "" || name == null) { + return "limelight"; + } + return name; + } + + /** + * Takes a 6-length array of pose data and converts it to a Pose3d object. + * Array format: [x, y, z, roll, pitch, yaw] where angles are in degrees. + * @param inData Array containing pose data [x, y, z, roll, pitch, yaw] + * @return Pose3d object representing the pose, or empty Pose3d if invalid data + */ + public static Pose3d toPose3D(double[] inData){ + if(inData.length < 6) + { + //System.err.println("Bad LL 3D Pose Data!"); + return new Pose3d(); + } + return new Pose3d( + new Translation3d(inData[0], inData[1], inData[2]), + new Rotation3d(Units.degreesToRadians(inData[3]), Units.degreesToRadians(inData[4]), + Units.degreesToRadians(inData[5]))); + } + + /** + * Takes a 6-length array of pose data and converts it to a Pose2d object. + * Uses only x, y, and yaw components, ignoring z, roll, and pitch. + * Array format: [x, y, z, roll, pitch, yaw] where angles are in degrees. + * @param inData Array containing pose data [x, y, z, roll, pitch, yaw] + * @return Pose2d object representing the pose, or empty Pose2d if invalid data + */ + public static Pose2d toPose2D(double[] inData){ + if(inData.length < 6) + { + //System.err.println("Bad LL 2D Pose Data!"); + return new Pose2d(); + } + Translation2d tran2d = new Translation2d(inData[0], inData[1]); + Rotation2d r2d = new Rotation2d(Units.degreesToRadians(inData[5])); + return new Pose2d(tran2d, r2d); + } + + /** + * Converts a Pose3d object to an array of doubles in the format [x, y, z, roll, pitch, yaw]. + * Translation components are in meters, rotation components are in degrees. + * + * @param pose The Pose3d object to convert + * @return A 6-element array containing [x, y, z, roll, pitch, yaw] + */ + public static double[] pose3dToArray(Pose3d pose) { + double[] result = new double[6]; + result[0] = pose.getTranslation().getX(); + result[1] = pose.getTranslation().getY(); + result[2] = pose.getTranslation().getZ(); + result[3] = Units.radiansToDegrees(pose.getRotation().getX()); + result[4] = Units.radiansToDegrees(pose.getRotation().getY()); + result[5] = Units.radiansToDegrees(pose.getRotation().getZ()); + return result; + } + + /** + * Converts a Pose2d object to an array of doubles in the format [x, y, z, roll, pitch, yaw]. + * Translation components are in meters, rotation components are in degrees. + * Note: z, roll, and pitch will be 0 since Pose2d only contains x, y, and yaw. + * + * @param pose The Pose2d object to convert + * @return A 6-element array containing [x, y, 0, 0, 0, yaw] + */ + public static double[] pose2dToArray(Pose2d pose) { + double[] result = new double[6]; + result[0] = pose.getTranslation().getX(); + result[1] = pose.getTranslation().getY(); + result[2] = 0; + result[3] = Units.radiansToDegrees(0); + result[4] = Units.radiansToDegrees(0); + result[5] = Units.radiansToDegrees(pose.getRotation().getRadians()); + return result; + } + + private static double extractArrayEntry(double[] inData, int position){ + if(inData.length < position+1) + { + return 0; + } + return inData[position]; + } + + private static PoseEstimate getBotPoseEstimate(String limelightName, String entryName, boolean isMegaTag2) { + DoubleArrayEntry poseEntry = LimelightHelpers.getLimelightDoubleArrayEntry(limelightName, entryName); + + TimestampedDoubleArray tsValue = poseEntry.getAtomic(); + double[] poseArray = tsValue.value; + long timestamp = tsValue.timestamp; + + if (poseArray.length == 0) { + // Handle the case where no data is available + return null; // or some default PoseEstimate + } + + var pose = toPose2D(poseArray); + double latency = extractArrayEntry(poseArray, 6); + int tagCount = (int)extractArrayEntry(poseArray, 7); + double tagSpan = extractArrayEntry(poseArray, 8); + double tagDist = extractArrayEntry(poseArray, 9); + double tagArea = extractArrayEntry(poseArray, 10); + + // Convert server timestamp from microseconds to seconds and adjust for latency + double adjustedTimestamp = (timestamp / 1000000.0) - (latency / 1000.0); + + RawFiducial[] rawFiducials = new RawFiducial[tagCount]; + int valsPerFiducial = 7; + int expectedTotalVals = 11 + valsPerFiducial * tagCount; + + if (poseArray.length != expectedTotalVals) { + // Don't populate fiducials + } else { + for(int i = 0; i < tagCount; i++) { + int baseIndex = 11 + (i * valsPerFiducial); + int id = (int)poseArray[baseIndex]; + double txnc = poseArray[baseIndex + 1]; + double tync = poseArray[baseIndex + 2]; + double ta = poseArray[baseIndex + 3]; + double distToCamera = poseArray[baseIndex + 4]; + double distToRobot = poseArray[baseIndex + 5]; + double ambiguity = poseArray[baseIndex + 6]; + rawFiducials[i] = new RawFiducial(id, txnc, tync, ta, distToCamera, distToRobot, ambiguity); + } + } + + return new PoseEstimate(pose, adjustedTimestamp, latency, tagCount, tagSpan, tagDist, tagArea, rawFiducials, isMegaTag2); + } + + /** + * Gets the latest raw fiducial/AprilTag detection results from NetworkTables. + * + * @param limelightName Name/identifier of the Limelight + * @return Array of RawFiducial objects containing detection details + */ + public static RawFiducial[] getRawFiducials(String limelightName) { + var entry = LimelightHelpers.getLimelightNTTableEntry(limelightName, "rawfiducials"); + var rawFiducialArray = entry.getDoubleArray(new double[0]); + int valsPerEntry = 7; + if (rawFiducialArray.length % valsPerEntry != 0) { + return new RawFiducial[0]; + } + + int numFiducials = rawFiducialArray.length / valsPerEntry; + RawFiducial[] rawFiducials = new RawFiducial[numFiducials]; + + for (int i = 0; i < numFiducials; i++) { + int baseIndex = i * valsPerEntry; + int id = (int) extractArrayEntry(rawFiducialArray, baseIndex); + double txnc = extractArrayEntry(rawFiducialArray, baseIndex + 1); + double tync = extractArrayEntry(rawFiducialArray, baseIndex + 2); + double ta = extractArrayEntry(rawFiducialArray, baseIndex + 3); + double distToCamera = extractArrayEntry(rawFiducialArray, baseIndex + 4); + double distToRobot = extractArrayEntry(rawFiducialArray, baseIndex + 5); + double ambiguity = extractArrayEntry(rawFiducialArray, baseIndex + 6); + + rawFiducials[i] = new RawFiducial(id, txnc, tync, ta, distToCamera, distToRobot, ambiguity); + } + + return rawFiducials; + } + + /** + * Gets the latest raw neural detector results from NetworkTables + * + * @param limelightName Name/identifier of the Limelight + * @return Array of RawDetection objects containing detection details + */ + public static RawDetection[] getRawDetections(String limelightName) { + var entry = LimelightHelpers.getLimelightNTTableEntry(limelightName, "rawdetections"); + var rawDetectionArray = entry.getDoubleArray(new double[0]); + int valsPerEntry = 12; + if (rawDetectionArray.length % valsPerEntry != 0) { + return new RawDetection[0]; + } + + int numDetections = rawDetectionArray.length / valsPerEntry; + RawDetection[] rawDetections = new RawDetection[numDetections]; + + for (int i = 0; i < numDetections; i++) { + int baseIndex = i * valsPerEntry; // Starting index for this detection's data + int classId = (int) extractArrayEntry(rawDetectionArray, baseIndex); + double txnc = extractArrayEntry(rawDetectionArray, baseIndex + 1); + double tync = extractArrayEntry(rawDetectionArray, baseIndex + 2); + double ta = extractArrayEntry(rawDetectionArray, baseIndex + 3); + double corner0_X = extractArrayEntry(rawDetectionArray, baseIndex + 4); + double corner0_Y = extractArrayEntry(rawDetectionArray, baseIndex + 5); + double corner1_X = extractArrayEntry(rawDetectionArray, baseIndex + 6); + double corner1_Y = extractArrayEntry(rawDetectionArray, baseIndex + 7); + double corner2_X = extractArrayEntry(rawDetectionArray, baseIndex + 8); + double corner2_Y = extractArrayEntry(rawDetectionArray, baseIndex + 9); + double corner3_X = extractArrayEntry(rawDetectionArray, baseIndex + 10); + double corner3_Y = extractArrayEntry(rawDetectionArray, baseIndex + 11); + + rawDetections[i] = new RawDetection(classId, txnc, tync, ta, corner0_X, corner0_Y, corner1_X, corner1_Y, corner2_X, corner2_Y, corner3_X, corner3_Y); + } + + return rawDetections; + } + + /** + * Prints detailed information about a PoseEstimate to standard output. + * Includes timestamp, latency, tag count, tag span, average tag distance, + * average tag area, and detailed information about each detected fiducial. + * + * @param pose The PoseEstimate object to print. If null, prints "No PoseEstimate available." + */ + public static void printPoseEstimate(PoseEstimate pose) { + if (pose == null) { + System.out.println("No PoseEstimate available."); + return; + } + + System.out.printf("Pose Estimate Information:%n"); + System.out.printf("Timestamp (Seconds): %.3f%n", pose.timestampSeconds); + System.out.printf("Latency: %.3f ms%n", pose.latency); + System.out.printf("Tag Count: %d%n", pose.tagCount); + System.out.printf("Tag Span: %.2f meters%n", pose.tagSpan); + System.out.printf("Average Tag Distance: %.2f meters%n", pose.avgTagDist); + System.out.printf("Average Tag Area: %.2f%% of image%n", pose.avgTagArea); + System.out.printf("Is MegaTag2: %b%n", pose.isMegaTag2); + System.out.println(); + + if (pose.rawFiducials == null || pose.rawFiducials.length == 0) { + System.out.println("No RawFiducials data available."); + return; + } + + System.out.println("Raw Fiducials Details:"); + for (int i = 0; i < pose.rawFiducials.length; i++) { + RawFiducial fiducial = pose.rawFiducials[i]; + System.out.printf(" Fiducial #%d:%n", i + 1); + System.out.printf(" ID: %d%n", fiducial.id); + System.out.printf(" TXNC: %.2f%n", fiducial.txnc); + System.out.printf(" TYNC: %.2f%n", fiducial.tync); + System.out.printf(" TA: %.2f%n", fiducial.ta); + System.out.printf(" Distance to Camera: %.2f meters%n", fiducial.distToCamera); + System.out.printf(" Distance to Robot: %.2f meters%n", fiducial.distToRobot); + System.out.printf(" Ambiguity: %.2f%n", fiducial.ambiguity); + System.out.println(); + } + } + + public static Boolean validPoseEstimate(PoseEstimate pose) { + return pose != null && pose.rawFiducials != null && pose.rawFiducials.length != 0; + } + + public static NetworkTable getLimelightNTTable(String tableName) { + return NetworkTableInstance.getDefault().getTable(sanitizeName(tableName)); + } + + public static void Flush() { + NetworkTableInstance.getDefault().flush(); + } + + public static NetworkTableEntry getLimelightNTTableEntry(String tableName, String entryName) { + return getLimelightNTTable(tableName).getEntry(entryName); + } + + public static DoubleArrayEntry getLimelightDoubleArrayEntry(String tableName, String entryName) { + String key = tableName + "/" + entryName; + return doubleArrayEntries.computeIfAbsent(key, k -> { + NetworkTable table = getLimelightNTTable(tableName); + return table.getDoubleArrayTopic(entryName).getEntry(new double[0]); + }); + } + + public static double getLimelightNTDouble(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getDouble(0.0); + } + + public static void setLimelightNTDouble(String tableName, String entryName, double val) { + getLimelightNTTableEntry(tableName, entryName).setDouble(val); + } + + public static void setLimelightNTDoubleArray(String tableName, String entryName, double[] val) { + getLimelightNTTableEntry(tableName, entryName).setDoubleArray(val); + } + + public static double[] getLimelightNTDoubleArray(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getDoubleArray(new double[0]); + } + + + public static String getLimelightNTString(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getString(""); + } + + public static String[] getLimelightNTStringArray(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getStringArray(new String[0]); + } + + + public static URL getLimelightURLString(String tableName, String request) { + String urlString = "http://" + sanitizeName(tableName) + ".local:5807/" + request; + URL url; + try { + url = new URL(urlString); + return url; + } catch (MalformedURLException e) { + System.err.println("bad LL URL"); + } + return null; + } + ///// + ///// + + /** + * Does the Limelight have a valid target? + * @param limelightName Name of the Limelight camera ("" for default) + * @return True if a valid target is present, false otherwise + */ + public static boolean getTV(String limelightName) { + return 1.0 == getLimelightNTDouble(limelightName, "tv"); + } + + /** + * Gets the horizontal offset from the crosshair to the target in degrees. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Horizontal offset angle in degrees + */ + public static double getTX(String limelightName) { + return getLimelightNTDouble(limelightName, "tx"); + } + + /** + * Gets the vertical offset from the crosshair to the target in degrees. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Vertical offset angle in degrees + */ + public static double getTY(String limelightName) { + return getLimelightNTDouble(limelightName, "ty"); + } + + /** + * Gets the horizontal offset from the principal pixel/point to the target in degrees. This is the most accurate 2d metric if you are using a calibrated camera and you don't need adjustable crosshair functionality. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Horizontal offset angle in degrees + */ + public static double getTXNC(String limelightName) { + return getLimelightNTDouble(limelightName, "txnc"); + } + + /** + * Gets the vertical offset from the principal pixel/point to the target in degrees. This is the most accurate 2d metric if you are using a calibrated camera and you don't need adjustable crosshair functionality. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Vertical offset angle in degrees + */ + public static double getTYNC(String limelightName) { + return getLimelightNTDouble(limelightName, "tync"); + } + + /** + * Gets the target area as a percentage of the image (0-100%). + * @param limelightName Name of the Limelight camera ("" for default) + * @return Target area percentage (0-100) + */ + public static double getTA(String limelightName) { + return getLimelightNTDouble(limelightName, "ta"); + } + + /** + * T2D is an array that contains several targeting metrcis + * @param limelightName Name of the Limelight camera + * @return Array containing [targetValid, targetCount, targetLatency, captureLatency, tx, ty, txnc, tync, ta, tid, targetClassIndexDetector, + * targetClassIndexClassifier, targetLongSidePixels, targetShortSidePixels, targetHorizontalExtentPixels, targetVerticalExtentPixels, targetSkewDegrees] + */ + public static double[] getT2DArray(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "t2d"); + } + + /** + * Gets the number of targets currently detected. + * @param limelightName Name of the Limelight camera + * @return Number of detected targets + */ + public static int getTargetCount(String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[1]; + } + return 0; + } + + /** + * Gets the classifier class index from the currently running neural classifier pipeline + * @param limelightName Name of the Limelight camera + * @return Class index from classifier pipeline + */ + public static int getClassifierClassIndex (String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[10]; + } + return 0; + } + + /** + * Gets the detector class index from the primary result of the currently running neural detector pipeline. + * @param limelightName Name of the Limelight camera + * @return Class index from detector pipeline + */ + public static int getDetectorClassIndex (String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[11]; + } + return 0; + } + + /** + * Gets the current neural classifier result class name. + * @param limelightName Name of the Limelight camera + * @return Class name string from classifier pipeline + */ + public static String getClassifierClass (String limelightName) { + return getLimelightNTString(limelightName, "tcclass"); + } + + /** + * Gets the primary neural detector result class name. + * @param limelightName Name of the Limelight camera + * @return Class name string from detector pipeline + */ + public static String getDetectorClass (String limelightName) { + return getLimelightNTString(limelightName, "tdclass"); + } + + /** + * Gets the pipeline's processing latency contribution. + * @param limelightName Name of the Limelight camera + * @return Pipeline latency in milliseconds + */ + public static double getLatency_Pipeline(String limelightName) { + return getLimelightNTDouble(limelightName, "tl"); + } + + /** + * Gets the capture latency. + * @param limelightName Name of the Limelight camera + * @return Capture latency in milliseconds + */ + public static double getLatency_Capture(String limelightName) { + return getLimelightNTDouble(limelightName, "cl"); + } + + /** + * Gets the active pipeline index. + * @param limelightName Name of the Limelight camera + * @return Current pipeline index (0-9) + */ + public static double getCurrentPipelineIndex(String limelightName) { + return getLimelightNTDouble(limelightName, "getpipe"); + } + + /** + * Gets the current pipeline type. + * @param limelightName Name of the Limelight camera + * @return Pipeline type string (e.g. "retro", "apriltag", etc) + */ + public static String getCurrentPipelineType(String limelightName) { + return getLimelightNTString(limelightName, "getpipetype"); + } + + /** + * Gets the full JSON results dump. + * @param limelightName Name of the Limelight camera + * @return JSON string containing all current results + */ + public static String getJSONDump(String limelightName) { + return getLimelightNTString(limelightName, "json"); + } + + /** + * Switch to getBotPose + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose"); + } + + /** + * Switch to getBotPose_wpiRed + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose_wpiRed(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + } + + /** + * Switch to getBotPose_wpiBlue + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose_wpiBlue(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + } + + public static double[] getBotPose(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose"); + } + + public static double[] getBotPose_wpiRed(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + } + + public static double[] getBotPose_wpiBlue(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + } + + public static double[] getBotPose_TargetSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_targetspace"); + } + + public static double[] getCameraPose_TargetSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "camerapose_targetspace"); + } + + public static double[] getTargetPose_CameraSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "targetpose_cameraspace"); + } + + public static double[] getTargetPose_RobotSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "targetpose_robotspace"); + } + + public static double[] getTargetColor(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "tc"); + } + + public static double getFiducialID(String limelightName) { + return getLimelightNTDouble(limelightName, "tid"); + } + + public static String getNeuralClassID(String limelightName) { + return getLimelightNTString(limelightName, "tclass"); + } + + public static String[] getRawBarcodeData(String limelightName) { + return getLimelightNTStringArray(limelightName, "rawbarcodes"); + } + + ///// + ///// + + public static Pose3d getBotPose3d(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose"); + return toPose3D(poseArray); + } + + /** + * (Not Recommended) Gets the robot's 3D pose in the WPILib Red Alliance Coordinate System. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation in Red Alliance field space + */ + public static Pose3d getBotPose3d_wpiRed(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + return toPose3D(poseArray); + } + + /** + * (Recommended) Gets the robot's 3D pose in the WPILib Blue Alliance Coordinate System. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation in Blue Alliance field space + */ + public static Pose3d getBotPose3d_wpiBlue(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + return toPose3D(poseArray); + } + + /** + * Gets the robot's 3D pose with respect to the currently tracked target's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation relative to the target + */ + public static Pose3d getBotPose3d_TargetSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_targetspace"); + return toPose3D(poseArray); + } + + /** + * Gets the camera's 3D pose with respect to the currently tracked target's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the camera's position and orientation relative to the target + */ + public static Pose3d getCameraPose3d_TargetSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "camerapose_targetspace"); + return toPose3D(poseArray); + } + + /** + * Gets the target's 3D pose with respect to the camera's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the target's position and orientation relative to the camera + */ + public static Pose3d getTargetPose3d_CameraSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "targetpose_cameraspace"); + return toPose3D(poseArray); + } + + /** + * Gets the target's 3D pose with respect to the robot's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the target's position and orientation relative to the robot + */ + public static Pose3d getTargetPose3d_RobotSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "targetpose_robotspace"); + return toPose3D(poseArray); + } + + /** + * Gets the camera's 3D pose with respect to the robot's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the camera's position and orientation relative to the robot + */ + public static Pose3d getCameraPose3d_RobotSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "camerapose_robotspace"); + return toPose3D(poseArray); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d_wpiBlue(String limelightName) { + + double[] result = getBotPose_wpiBlue(limelightName); + return toPose2D(result); + } + + /** + * Gets the MegaTag1 Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) in the WPILib Blue alliance coordinate system. + * + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiBlue(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_wpiblue", false); + } + + /** + * Gets the MegaTag2 Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) in the WPILib Blue alliance coordinate system. + * Make sure you are calling setRobotOrientation() before calling this method. + * + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiBlue_MegaTag2(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_orb_wpiblue", true); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d_wpiRed(String limelightName) { + + double[] result = getBotPose_wpiRed(limelightName); + return toPose2D(result); + + } + + /** + * Gets the Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) when you are on the RED + * alliance + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiRed(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_wpired", false); + } + + /** + * Gets the Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) when you are on the RED + * alliance + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiRed_MegaTag2(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_orb_wpired", true); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d(String limelightName) { + + double[] result = getBotPose(limelightName); + return toPose2D(result); + + } + + /** + * Gets the current IMU data from NetworkTables. + * IMU data is formatted as [robotYaw, Roll, Pitch, Yaw, gyroX, gyroY, gyroZ, accelX, accelY, accelZ]. + * Returns all zeros if data is invalid or unavailable. + * + * @param limelightName Name/identifier of the Limelight + * @return IMUData object containing all current IMU data + */ + public static IMUData getIMUData(String limelightName) { + double[] imuData = getLimelightNTDoubleArray(limelightName, "imu"); + if (imuData == null || imuData.length < 10) { + return new IMUData(); // Returns object with all zeros + } + return new IMUData(imuData); + } + + ///// + ///// + + public static void setPipelineIndex(String limelightName, int pipelineIndex) { + setLimelightNTDouble(limelightName, "pipeline", pipelineIndex); + } + + + public static void setPriorityTagID(String limelightName, int ID) { + setLimelightNTDouble(limelightName, "priorityid", ID); + } + + /** + * Sets LED mode to be controlled by the current pipeline. + * @param limelightName Name of the Limelight camera + */ + public static void setLEDMode_PipelineControl(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 0); + } + + public static void setLEDMode_ForceOff(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 1); + } + + public static void setLEDMode_ForceBlink(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 2); + } + + public static void setLEDMode_ForceOn(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 3); + } + + /** + * Enables standard side-by-side stream mode. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_Standard(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 0); + } + + /** + * Enables Picture-in-Picture mode with secondary stream in the corner. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_PiPMain(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 1); + } + + /** + * Enables Picture-in-Picture mode with primary stream in the corner. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_PiPSecondary(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 2); + } + + + /** + * Sets the crop window for the camera. The crop window in the UI must be completely open. + * @param limelightName Name of the Limelight camera + * @param cropXMin Minimum X value (-1 to 1) + * @param cropXMax Maximum X value (-1 to 1) + * @param cropYMin Minimum Y value (-1 to 1) + * @param cropYMax Maximum Y value (-1 to 1) + */ + public static void setCropWindow(String limelightName, double cropXMin, double cropXMax, double cropYMin, double cropYMax) { + double[] entries = new double[4]; + entries[0] = cropXMin; + entries[1] = cropXMax; + entries[2] = cropYMin; + entries[3] = cropYMax; + setLimelightNTDoubleArray(limelightName, "crop", entries); + } + + /** + * Sets 3D offset point for easy 3D targeting. + */ + public static void setFiducial3DOffset(String limelightName, double offsetX, double offsetY, double offsetZ) { + double[] entries = new double[3]; + entries[0] = offsetX; + entries[1] = offsetY; + entries[2] = offsetZ; + setLimelightNTDoubleArray(limelightName, "fiducial_offset_set", entries); + } + + /** + * Sets robot orientation values used by MegaTag2 localization algorithm. + * + * @param limelightName Name/identifier of the Limelight + * @param yaw Robot yaw in degrees. 0 = robot facing red alliance wall in FRC + * @param yawRate (Unnecessary) Angular velocity of robot yaw in degrees per second + * @param pitch (Unnecessary) Robot pitch in degrees + * @param pitchRate (Unnecessary) Angular velocity of robot pitch in degrees per second + * @param roll (Unnecessary) Robot roll in degrees + * @param rollRate (Unnecessary) Angular velocity of robot roll in degrees per second + */ + public static void SetRobotOrientation(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate) { + SetRobotOrientation_INTERNAL(limelightName, yaw, yawRate, pitch, pitchRate, roll, rollRate, true); + } + + public static void SetRobotOrientation_NoFlush(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate) { + SetRobotOrientation_INTERNAL(limelightName, yaw, yawRate, pitch, pitchRate, roll, rollRate, false); + } + + private static void SetRobotOrientation_INTERNAL(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate, boolean flush) { + + double[] entries = new double[6]; + entries[0] = yaw; + entries[1] = yawRate; + entries[2] = pitch; + entries[3] = pitchRate; + entries[4] = roll; + entries[5] = rollRate; + setLimelightNTDoubleArray(limelightName, "robot_orientation_set", entries); + if(flush) + { + Flush(); + } + } + + /** + * Configures the IMU mode for MegaTag2 Localization + * + * @param limelightName Name/identifier of the Limelight + * @param mode IMU mode. + */ + public static void SetIMUMode(String limelightName, int mode) { + setLimelightNTDouble(limelightName, "imumode_set", mode); + } + + /** + * Sets the 3D point-of-interest offset for the current fiducial pipeline. + * https://docs.limelightvision.io/docs/docs-limelight/pipeline-apriltag/apriltag-3d#point-of-interest-tracking + * + * @param limelightName Name/identifier of the Limelight + * @param x X offset in meters + * @param y Y offset in meters + * @param z Z offset in meters + */ + public static void SetFidcuial3DOffset(String limelightName, double x, double y, + double z) { + + double[] entries = new double[3]; + entries[0] = x; + entries[1] = y; + entries[2] = z; + setLimelightNTDoubleArray(limelightName, "fiducial_offset_set", entries); + } + + /** + * Overrides the valid AprilTag IDs that will be used for localization. + * Tags not in this list will be ignored for robot pose estimation. + * + * @param limelightName Name/identifier of the Limelight + * @param validIDs Array of valid AprilTag IDs to track + */ + public static void SetFiducialIDFiltersOverride(String limelightName, int[] validIDs) { + double[] validIDsDouble = new double[validIDs.length]; + for (int i = 0; i < validIDs.length; i++) { + validIDsDouble[i] = validIDs[i]; + } + setLimelightNTDoubleArray(limelightName, "fiducial_id_filters_set", validIDsDouble); + } + + /** + * Sets the downscaling factor for AprilTag detection. + * Increasing downscale can improve performance at the cost of potentially reduced detection range. + * + * @param limelightName Name/identifier of the Limelight + * @param downscale Downscale factor. Valid values: 1.0 (no downscale), 1.5, 2.0, 3.0, 4.0. Set to 0 for pipeline control. + */ + public static void SetFiducialDownscalingOverride(String limelightName, float downscale) + { + int d = 0; // pipeline + if (downscale == 1.0) + { + d = 1; + } + if (downscale == 1.5) + { + d = 2; + } + if (downscale == 2) + { + d = 3; + } + if (downscale == 3) + { + d = 4; + } + if (downscale == 4) + { + d = 5; + } + setLimelightNTDouble(limelightName, "fiducial_downscale_set", d); + } + + /** + * Sets the camera pose relative to the robot. + * @param limelightName Name of the Limelight camera + * @param forward Forward offset in meters + * @param side Side offset in meters + * @param up Up offset in meters + * @param roll Roll angle in degrees + * @param pitch Pitch angle in degrees + * @param yaw Yaw angle in degrees + */ + public static void setCameraPose_RobotSpace(String limelightName, double forward, double side, double up, double roll, double pitch, double yaw) { + double[] entries = new double[6]; + entries[0] = forward; + entries[1] = side; + entries[2] = up; + entries[3] = roll; + entries[4] = pitch; + entries[5] = yaw; + setLimelightNTDoubleArray(limelightName, "camerapose_robotspace_set", entries); + } + + ///// + ///// + + public static void setPythonScriptData(String limelightName, double[] outgoingPythonData) { + setLimelightNTDoubleArray(limelightName, "llrobot", outgoingPythonData); + } + + public static double[] getPythonScriptData(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "llpython"); + } + + ///// + ///// + + /** + * Asynchronously take snapshot. + */ + public static CompletableFuture takeSnapshot(String tableName, String snapshotName) { + return CompletableFuture.supplyAsync(() -> { + return SYNCH_TAKESNAPSHOT(tableName, snapshotName); + }); + } + + private static boolean SYNCH_TAKESNAPSHOT(String tableName, String snapshotName) { + URL url = getLimelightURLString(tableName, "capturesnapshot"); + try { + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + if (snapshotName != null && snapshotName != "") { + connection.setRequestProperty("snapname", snapshotName); + } + + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + return true; + } else { + System.err.println("Bad LL Request"); + } + } catch (IOException e) { + System.err.println(e.getMessage()); + } + return false; + } + + /** + * Gets the latest JSON results output and returns a LimelightResults object. + * @param limelightName Name of the Limelight camera + * @return LimelightResults object containing all current target data + */ + public static LimelightResults getLatestResults(String limelightName) { + + long start = System.nanoTime(); + LimelightHelpers.LimelightResults results = new LimelightHelpers.LimelightResults(); + if (mapper == null) { + mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + try { + results = mapper.readValue(getJSONDump(limelightName), LimelightResults.class); + } catch (JsonProcessingException e) { + results.error = "lljson error: " + e.getMessage(); + } + + long end = System.nanoTime(); + double millis = (end - start) * .000001; + results.latency_jsonParse = millis; + if (profileJSON) { + System.out.printf("lljson: %.2f\r\n", millis); + } + + return results; + } +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Main.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..687a0a0 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -0,0 +1,103 @@ +// 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; + +/** + * The VM is configured to automatically run this class, and to call the functions corresponding to + * each mode, as described in the TimedRobot documentation. If you change the name of this class or + * the package after creating this project, you must also update the build.gradle file in the + * project. + */ +public class Robot extends TimedRobot { + private Command m_autonomousCommand; + + private RobotContainer m_robotContainer; + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + @Override + public void robotInit() { + // Instantiate our RobotContainer. This will perform all our button bindings, and put our + // autonomous chooser on the dashboard. + m_robotContainer = new RobotContainer(); + } + + /** + * This function is called every 20 ms, no matter the mode. Use this for items like diagnostics + * that you want ran during disabled, autonomous, teleoperated and test. + * + *

This runs after the mode specific periodic functions, but before LiveWindow and + * SmartDashboard integrated updating. + */ + @Override + public void robotPeriodic() { + // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled + // commands, running already-scheduled commands, removing finished or interrupted commands, + // and running subsystem periodic() methods. This must be called from the robot's periodic + // block in order for anything in the Command-based framework to work. + CommandScheduler.getInstance().run(); + } + + /** This function is called once each time the robot enters Disabled mode. */ + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ + @Override + public void autonomousInit() { + m_autonomousCommand = m_robotContainer.getAutonomousCommand(); + + // schedule the autonomous command (example) + if (m_autonomousCommand != null) { + m_autonomousCommand.schedule(); + } + } + + /** This function is called periodically during autonomous. */ + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() { + // This makes sure that the autonomous stops running when + // teleop starts running. If you want the autonomous to + // continue until interrupted by another command, remove + // this line or comment it out. + if (m_autonomousCommand != null) { + m_autonomousCommand.cancel(); + } + } + + /** This function is called periodically during operator control. */ + @Override + public void teleopPeriodic() {} + + @Override + public void testInit() { + // Cancels all running commands at the start of test mode. + CommandScheduler.getInstance().cancelAll(); + } + + /** This function is called periodically during test mode. */ + @Override + public void testPeriodic() {} + + /** This function is called once when the robot is first started up. */ + @Override + public void simulationInit() {} + + /** This function is called periodically whilst in simulation. */ + @Override + public void simulationPeriodic() {} +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java new file mode 100644 index 0000000..7f035cd --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -0,0 +1,156 @@ +// 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 java.util.ArrayList; +import java.util.Optional; + +import com.ctre.phoenix6.hardware.TalonFX; +import com.pathplanner.lib.auto.AutoBuilder; +import com.studica.frc.AHRS; +import com.studica.frc.AHRS.NavXComType; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +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.button.CommandXboxController; +import edu.wpi.first.wpilibj2.command.button.Trigger; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.factorys.DriveSubsystemFactory; +import frc.robot.factorys.TalonFXFactory; +import frc.robot.subsystems.DriveSubsystem; +import frc.robot.utils.AutoCommands; + +/** + * This class is where the bulk of the robot should be declared. Since Command-based is a + * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot} + * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including + * subsystems, commands, and trigger mappings) should be declared here. + */ +public class RobotContainer { + // The robot's subsystems and commands are defined here... + private final Optional m_driveSubsystem; + + // Replace with CommandPS4Controller or CommandJoystick if needed + //private final CommandXboxController m_driverController = + // new CommandXboxController(OperatorConstants.kDriverControllerPort); + + private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); + private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.trackWidthMeters); + + // Pose Estimators + private DifferentialDrivePoseEstimator m_DrivePoseEstimator = new DifferentialDrivePoseEstimator( + m_DriveKinematics, + m_gyro.getRotation2d(), + 0, + 0, + new Pose2d()); + + // Sendable Choosers + private SendableChooser autoChooser; + + // Factorys + private TalonFXFactory m_TalonFXFactory = new TalonFXFactory(); + private DriveSubsystemFactory m_DriveSubsystemFactory = new DriveSubsystemFactory(); + + /** The container for the robot. Contains subsystems, OI devices, and commands. */ + public RobotContainer() { + // Init DriveSubsystem + Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); + Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); + Optional rightFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalRightMotorCANID); + Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); + m_driveSubsystem = m_DriveSubsystemFactory.construct(m_DrivePoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); + + // Init the subsystems + //m_limelightSubsystem = getSubsystem(LimelightSubsystem.class, m_limeLightPoseEstimator); + //m_exampleSubsystem = getSubsystem(ExampleSubsystem.class); + + // Init Auto + configureAutos(); + + // Configure the default commands + configureDefaultCommands(); + + // Configure the trigger bindings + configureBindings(); + } + + // Tom wrote this cool template to make the optional subsystem creation code in + // the constructor above a lot clearer. This is what clever coding looks like. + // Owen: I added the ability to pass object args through this for dependency injection, + // I hope this does not break anything or commited a coding sin or somthing + // private static Optional getSubsystem(Class subsystemClass, Object... args) { + // Optional iss; + // try { + + // iss = Optional.ofNullable(subsystemClass.getDeclaredConstructor().newInstance(args)); + // } catch (Exception e) { + // iss = Optional.empty(); + // // This is not tested! - Owen + // DriverStation.reportWarning( + // String.format( + // "The %s was not found!", subsystemClass.getName()), + // false + // ); + // } + // return iss; + // } + + private void configureAutos() { + // Init Autos (/home/lvuser/deploy/pathplanner/autos) + ArrayList autoCommands = AutoCommands.getAutoCommands(m_driveSubsystem); + + // Init Chooser + autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string + SmartDashboard.putData("Auto Chooser", autoChooser); + } + + private void configureDefaultCommands() { + if (m_driveSubsystem.isPresent()) + { + //DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + //driveSubsystem.initDefaultCommand(m_driverController); + } + } + + /** + * Use this method to define your trigger->command mappings. Triggers can be created via the + * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary + * predicate, or via the named factories in {@link + * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link + * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller + * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight + * joysticks}. + */ + private void configureBindings() { + // SmartDashboard.putBoolean("Example Subsystem", m_exampleSubsystem.isPresent()); + + // if (m_exampleSubsystem.isPresent()) + // { + // ExampleSubsystem exampleSubsystem = m_exampleSubsystem.get(); + + // // Schedule `ExampleCommand` when `exampleCondition` changes to `true` + // new Trigger(exampleSubsystem::exampleCondition) + // .onTrue(new ExampleCommand(exampleSubsystem)); + + // // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed, + // // cancelling on release. + // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); + // } + } + + /** + * Use this to pass the autonomous command to the main {@link Robot} class. + * + * @return the command to run in autonomous + */ + public Command getAutonomousCommand() { + return autoChooser.getSelected(); + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java new file mode 100644 index 0000000..a641317 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -0,0 +1,53 @@ +// 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.commands; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; + +/** An example command that uses an example subsystem. */ +public class ArcadeDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + m_subsystem.setDifferentialSpeeds( + -m_driveController.getRightY(), + -m_driveController.getLeftX() + ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/Autos.java new file mode 100644 index 0000000..107aad7 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/Autos.java @@ -0,0 +1,20 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.Commands; + +public final class Autos { + /** Example static factory for an autonomous command. */ + public static Command exampleAuto(ExampleSubsystem subsystem) { + return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); + } + + private Autos() { + throw new UnsupportedOperationException("This is a utility class!"); + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java new file mode 100644 index 0000000..27f220a --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -0,0 +1,57 @@ +// 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.commands; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.Constants; + +/** An example command that uses an example subsystem. */ +public class DifferentialDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public DifferentialDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + double leftSpeed = -m_driveController.getLeftY(); + double rightSpeed = -m_driveController.getRightY(); + + leftSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + rightSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + + m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ExampleCommand.java new file mode 100644 index 0000000..151624c --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ExampleCommand.java @@ -0,0 +1,43 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; + +/** An example command that uses an example subsystem. */ +public class ExampleCommand extends Command { + @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField", "unused"}) + private final ExampleSubsystem m_subsystem; + + /** + * Creates a new ExampleCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ExampleCommand(ExampleSubsystem subsystem) { + m_subsystem = subsystem; + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java new file mode 100644 index 0000000..afc5b84 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -0,0 +1,33 @@ +package frc.robot.factorys; + +import java.util.Optional; +import com.ctre.phoenix6.hardware.TalonFX; +import com.studica.frc.AHRS; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import frc.robot.subsystems.DriveSubsystem; + +public class DriveSubsystemFactory { + public DriveSubsystemFactory() { + } + + public Optional construct(DifferentialDrivePoseEstimator poseEstimator, + DifferentialDriveKinematics kinematics, + AHRS gyro, Optional rightLead, Optional leftLead, Optional rightFollower, + Optional leftFollower) { + + if (rightLead.isEmpty() || leftLead.isEmpty()) { + return Optional.empty(); + } + + DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, gyro, rightLead.get(), + leftLead.get()); + + if (rightFollower.isPresent() && leftFollower.isPresent()) { + driveSubsystem.setFollowers(rightFollower.get(), leftFollower.get()); + } + + return Optional.of(driveSubsystem); + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java new file mode 100644 index 0000000..1a84899 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java @@ -0,0 +1,20 @@ +package frc.robot.factorys; + +import java.util.Optional; + +import com.ctre.phoenix6.hardware.TalonFX; + +public class TalonFXFactory { + public TalonFXFactory() {} + + public Optional construct(int CANID) { + Optional newMotor; + try { + newMotor = Optional.of(new TalonFX(CANID)); + } catch (Exception e) { + newMotor = Optional.empty(); + } + + return newMotor; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java new file mode 100644 index 0000000..6782406 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -0,0 +1,285 @@ +// 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. + +// https://github.com/CrossTheRoadElec/Phoenix6-Examples/blob/main/java/VelocityClosedLoop/src/main/java/frc/robot/Robot.java +// This is a link to do speed control on the kraken motors. We need something like this. +package frc.robot.subsystems; +import static edu.wpi.first.units.Units.Volts; + +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.Follower; +import com.ctre.phoenix6.controls.VelocityVoltage; +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.signals.InvertedValue; +import com.ctre.phoenix6.signals.NeutralModeValue; +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.controllers.PPLTVController; +import com.studica.frc.AHRS; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.kinematics.ChassisSpeeds; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds; +import edu.wpi.first.util.sendable.SendableRegistry; +import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj.drive.DifferentialDrive; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.Constants.AutoConstants; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.commands.DifferentialDriveCommand; +//import frc.robot.utils.PIDControl; + +public class DriveSubsystem extends SubsystemBase { + private TalonFX m_rightMotor; + private TalonFX m_optionalRightMotor; + + private TalonFX m_leftMotor; + private TalonFX m_optionalLeftMotor; + + /* Start at velocity 0, use slot 0 */ + private final VelocityVoltage m_leftVelocityVoltage = new VelocityVoltage(0).withSlot(0); + private final VelocityVoltage m_rightVelocityVoltage = new VelocityVoltage(0).withSlot(0); + + private DifferentialDrive m_Drivetrain; + + private double m_leftSpeed = 0.0; + private double m_rightSpeed = 0.0; + + private final DifferentialDriveKinematics m_kinematics; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final AHRS m_gyro; + + // PIDControl m_leftPidControl = new PIDControl( + // m_leftMotor, + // DrivetrainConstants.kLeftPositiveMovesForward + // ); + + // PIDControl m_rightPidControl = new PIDControl( + // m_rightMotor, + // DrivetrainConstants.kRightPositiveMovesForward + // ); + + /** Creates a new DriveSubsystem. */ + public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, AHRS gyro, TalonFX rightMotor, TalonFX leftMotor) { + m_poseEstimator = poseEstimator; + m_kinematics = kinematics; + m_gyro = gyro; + m_rightMotor = rightMotor; + m_leftMotor = leftMotor; + + // Right Motor + TalonFXConfiguration rightMotorConfig = new TalonFXConfiguration(); + rightMotorConfig.Slot0.kV = DrivetrainConstants.kV; + rightMotorConfig.Slot0.kS = DrivetrainConstants.kS; + rightMotorConfig.Slot0.kP = DrivetrainConstants.kP; + rightMotorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error + rightMotorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output + rightMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + rightMotorConfig.MotorOutput.Inverted = InvertedValue.Clockwise_Positive; + + rightMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + m_rightMotor.getConfigurator().apply(rightMotorConfig); + SendableRegistry.setName(m_rightMotor, "DriveSubsystem", "rightMotor"); + + // Left Motor + TalonFXConfiguration leftMotorConfig = new TalonFXConfiguration(); + leftMotorConfig.Slot0.kV = DrivetrainConstants.kV; + leftMotorConfig.Slot0.kS = DrivetrainConstants.kS; + leftMotorConfig.Slot0.kP = DrivetrainConstants.kP; + leftMotorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error + leftMotorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output + leftMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + leftMotorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; + + leftMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + m_leftMotor.getConfigurator().apply(leftMotorConfig); + SendableRegistry.setName(m_leftMotor, "DriveSubsystem", "leftMotor"); + + // Zeroing the encoders + m_leftMotor.setPosition(0); + m_rightMotor.setPosition(0); + + // Setting up the drive train + m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); + SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + + // Init Autobuilder + AutoBuilder.configure( + this::getPose, + this::resetPose, + this::getRobotRelativeSpeeds, + (speeds, feedforwards) -> driveRobotRelative(speeds), + new PPLTVController(0.02), + AutoConstants.kRobotConfig, + () -> { + // Boolean supplier that controls when the path will be mirrored for the red alliance + // This will flip the path being followed to the red side of the field. + // THE ORIGIN WILL REMAIN ON THE BLUE SIDE + + var alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + return alliance.get() == DriverStation.Alliance.Red; + } + return false; + }, + this + ); + SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + + // Gyro setup + m_gyro.zeroYaw(); + } + + public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { + m_optionalRightMotor = optionalRight; + + // Setting up Config + TalonFXConfiguration optionalRightMotorConfig = new TalonFXConfiguration(); + //check + optionalRightMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + optionalRightMotorConfig.MotorOutput.Inverted = InvertedValue.Clockwise_Positive; + + optionalRightMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + // Saving + m_optionalRightMotor.getConfigurator().apply(optionalRightMotorConfig); + + // Setting as a follwer + m_optionalRightMotor.setControl( + new Follower(m_rightMotor.getDeviceID(), false) + ); + + m_optionalLeftMotor = optionalLeft; + + // Setting up Config + TalonFXConfiguration optionalLeftMotorConfig = new TalonFXConfiguration(); + optionalLeftMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + optionalLeftMotorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; + + optionalLeftMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + + // Saving + m_optionalLeftMotor.getConfigurator().apply(optionalLeftMotorConfig); + + // Setting as follower + m_optionalLeftMotor.setControl( + new Follower(m_leftMotor.getDeviceID(), false) + ); + } + + public void initDefaultCommand(CommandXboxController Controller) + { + setDefaultCommand(new DifferentialDriveCommand(this, Controller)); + } + + public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) + { + // NOTE: We are making our own custom input modifications + //m_leftSpeed = Math.pow(m_leftSpeed, 3); + //m_rightSpeed = Math.pow(m_rightSpeed, 3); + // NOTE: Notes can be useful for conveying information + + SmartDashboard.putNumber("Left Set", leftSpeedMPS); + SmartDashboard.putNumber("Right Set", rightSpeedMPS); + + double leftMPS = getMotorSpeedMPS(true); + double rightMPS = getMotorSpeedMPS(false); + + SmartDashboard.putNumber("Left MPS", leftMPS); + SmartDashboard.putNumber("Right MPS", rightMPS); + + // set motor voltage based on CTRE example + + double desiredLeftRotationsPerSecond =(leftMPS/Constants.DrivetrainConstants.kWheelCircumference)/Constants.DrivetrainConstants.kDrivetrainGearRatio; + double desiredRightRotationsPerSecond =(rightMPS/Constants.DrivetrainConstants.kWheelCircumference)/Constants.DrivetrainConstants.kDrivetrainGearRatio; + + m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(desiredLeftRotationsPerSecond)); + m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(desiredRightRotationsPerSecond)); + + } + + public double getSpeed(boolean bLeft) + { + if (bLeft) + { + return m_leftSpeed; + } + else + { + return m_rightSpeed; + } + } + + // Wrapping robot position inside of getposition + public Pose2d getPose(){ + return m_poseEstimator.getEstimatedPosition(); + } + + // Resets the drivetrains pose estimator to zero. + public void resetPose(Pose2d newPose){ + m_leftMotor.setPosition(0); + m_rightMotor.setPosition(0); + m_poseEstimator.resetPose(newPose); + } + + public double getMotorSpeedMPS(boolean bLeft) + { + double MPS; + if (bLeft) + { + MPS = m_leftMotor.getVelocity().getValueAsDouble() * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + } + else + { + MPS = m_rightMotor.getVelocity().getValueAsDouble() * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + } + return MPS; + } + + + // Returns a robot relative ChassisSpeeds object based on the avrg linear velocity + // in meters per second and avrg anglear velocity in readians per second + // Currently we are asuming that their is no scale for the motors, we cannot find anywhere to set the scale. + public ChassisSpeeds getRobotRelativeSpeeds() + { + // Linear Velocity in meters per second + double leftMPS = getMotorSpeedMPS(true); + double rightMPS = getMotorSpeedMPS(false); + + // Make wheelSpeeds object from MPS & converts it to chasis speeds + DifferentialDriveWheelSpeeds wheelSpeeds = new DifferentialDriveWheelSpeeds(leftMPS, rightMPS); + return m_kinematics.toChassisSpeeds(wheelSpeeds); + } + + // Gives the drivetrain a new drive command based on a robot relative + // chassis speed object. + public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ + m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, + relativeChassisSpeed.omegaRadiansPerSecond); + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + + m_poseEstimator.update( + m_gyro.getRotation2d(), + m_leftMotor.getPosition().getValueAsDouble(), + m_rightMotor.getPosition().getValueAsDouble()); + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/ExampleSubsystem.java new file mode 100644 index 0000000..6b375da --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/ExampleSubsystem.java @@ -0,0 +1,47 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class ExampleSubsystem extends SubsystemBase { + /** Creates a new ExampleSubsystem. */ + public ExampleSubsystem() {} + + /** + * Example command factory method. + * + * @return a command + */ + public Command exampleMethodCommand() { + // Inline construction of command goes here. + // Subsystem::RunOnce implicitly requires `this` subsystem. + return runOnce( + () -> { + /* one-time action goes here */ + }); + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java new file mode 100644 index 0000000..0008e82 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -0,0 +1,48 @@ +// 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.subsystems; +import edu.wpi.first.math.VecBuilder; +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import frc.robot.LimelightHelpers; + +public class LimelightSubsystem extends SubsystemBase { + private final DifferentialDrivePoseEstimator m_poseEstimator; + + /** Creates a new PositionSubsystem. */ + public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { + m_poseEstimator = poseEstimator; + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler + + // This is copy and pasted from limelight's documentation for testing. + LimelightHelpers.PoseEstimate limelightMeasurement = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); + if (limelightMeasurement.tagCount >= 2) { // Only trust measurement if we see multiple tags + m_poseEstimator.setVisionMeasurementStdDevs(VecBuilder.fill(0.7, 0.7, 9999999)); + m_poseEstimator.addVisionMeasurement( + limelightMeasurement.pose, + limelightMeasurement.timestampSeconds + ); + } + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/AutoCommands.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/AutoCommands.java new file mode 100644 index 0000000..5475bf5 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/AutoCommands.java @@ -0,0 +1,59 @@ +package frc.robot.utils; + +import java.io.File; +import edu.wpi.first.wpilibj.Filesystem; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +import java.util.ArrayList; +import java.util.Optional; + +import com.pathplanner.lib.commands.PathPlannerAuto; + +// This goes to "/home/lvuser/deploy/pathplanner/autos" and grabs the names of all .auto files +// We are asuming that the PathPlannerAuto(string) is the file name of the auto +// We are asuming that the files are always in the "/home/lvuser/deploy/pathplanner/autos" +// We found this information at https://github.com/mjansen4857/pathplanner/wiki/PathPlannerLib:-Java-Usage +public class AutoCommands { + public static ArrayList getAutoNames() { + // Creating an ArrayList so I can fill it with auto file names w/o the extention. + ArrayList autoNames = new ArrayList(); + + // Getting the folder and files. + String deployDirectoryPath = Filesystem.getDeployDirectory().getPath(); + File deployDirectory = new File(deployDirectoryPath+"/pathplanner/autos"); + File[] listOfFiles = deployDirectory.listFiles(); + + // Checking if the files exist + if (listOfFiles != null) { + for (File file : listOfFiles) { + String fullName = file.getName(); // Returns [file_name].[extention] + if (file.isFile()) { + String[] splitName = fullName.split("\\."); // Splitting the file name into seprate parts. + + // If its an auto file then add it to the list. + if (splitName.length > 1 && "auto".equals(splitName[1])) { + autoNames.add(splitName[0]); + System.out.println("FOUND AUTO: "+splitName[0]); + } + } + } + } + + // Returning the new array + return autoNames; + } + + public static ArrayList getAutoCommands(Optional driveSubsystem) { + ArrayList autoCommands = new ArrayList(); + + if (driveSubsystem.isPresent()) { + ArrayList autoNames = getAutoNames(); + for (String autoName : autoNames) { + autoCommands.add(new PathPlannerAuto(autoName)); + } + } + + return autoCommands; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java new file mode 100644 index 0000000..ead0d7b --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java @@ -0,0 +1,69 @@ +package frc.robot.utils; + +import com.ctre.phoenix6.controls.PositionVoltage; +import com.ctre.phoenix6.hardware.TalonFX; + +import edu.wpi.first.math.trajectory.TrapezoidProfile; +import frc.robot.Constants.DrivetrainConstants; + +public class PIDControl { + private TalonFX m_motor; + private boolean m_positiveMovesForward; + + private double m_targetPosition; + + private final TrapezoidProfile m_profile = new TrapezoidProfile( + new TrapezoidProfile.Constraints( + DrivetrainConstants.maxVelocity, + DrivetrainConstants.maxAcceleration + ) + ); + + private PositionVoltage m_positionVoltage; + private TrapezoidProfile.State m_goal = new TrapezoidProfile.State(); + private TrapezoidProfile.State m_setPoint = new TrapezoidProfile.State(); + + public PIDControl(TalonFX motor, boolean positiveMovesForward) { + m_motor = motor; + m_positiveMovesForward = positiveMovesForward; + } + + public void setTargetPosition(double position) { + m_targetPosition = position; + + double positionRotations = position * DrivetrainConstants.kDrivetrainGearRatio; + if (!m_positiveMovesForward) { + positionRotations = -positionRotations; + } + + m_goal = new TrapezoidProfile.State(positionRotations, 0); + m_setPoint = new TrapezoidProfile.State(0, 0); + + m_positionVoltage = new PositionVoltage(0).withSlot(0); + + m_motor.setPosition(0); // zero's motor at the start of the movement + } + + public void calculatePosition() { + m_setPoint = m_profile.calculate(0.020, m_setPoint, m_goal); + + m_positionVoltage.Position = m_setPoint.position; + m_positionVoltage.Velocity = m_setPoint.velocity; + m_motor.setControl(m_positionVoltage); + } + + public double getTargetPosition() { + return m_targetPosition; + } + + public double getPosition() { + double motorPosition = m_motor.getPosition().getValueAsDouble() / DrivetrainConstants.kDrivetrainGearRatio; + + if (m_positiveMovesForward) { + return motorPosition; + } else { + return -motorPosition; + } + } + +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/vendordeps/WPILibNewCommands.json b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} From 3487f457bd863c35c1c4ab49db6884eec0cacf6e Mon Sep 17 00:00:00 2001 From: 15 - Phosphorus <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 12 Jan 2026 19:29:12 -0600 Subject: [PATCH 006/161] Updated VendorDeps & Fixed Changed thing for Experimental2026 --- .../frc/robot/subsystems/DriveSubsystem.java | 9 +- .../vendordeps/PathplannerLib-2026.1.2.json | 38 ++ .../vendordeps/Phoenix6-26.1.0.json | 449 ++++++++++++++++++ .../vendordeps/REVLib.json | 133 ++++++ .../vendordeps/Studica.json | 71 +++ 5 files changed, 696 insertions(+), 4 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/vendordeps/PathplannerLib-2026.1.2.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/vendordeps/Phoenix6-26.1.0.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/vendordeps/REVLib.json create mode 100644 prototype_projects/Experimental_Drivetrain_2026/vendordeps/Studica.json diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 6782406..592ba87 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -12,6 +12,7 @@ import com.ctre.phoenix6.controls.VelocityVoltage; import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.InvertedValue; +import com.ctre.phoenix6.signals.MotorAlignmentValue; import com.ctre.phoenix6.signals.NeutralModeValue; import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.controllers.PPLTVController; @@ -155,7 +156,7 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { // Setting as a follwer m_optionalRightMotor.setControl( - new Follower(m_rightMotor.getDeviceID(), false) + new Follower(m_rightMotor.getDeviceID(), MotorAlignmentValue.Aligned) ); m_optionalLeftMotor = optionalLeft; @@ -173,7 +174,7 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { // Setting as follower m_optionalLeftMotor.setControl( - new Follower(m_leftMotor.getDeviceID(), false) + new Follower(m_leftMotor.getDeviceID(), MotorAlignmentValue.Aligned) ); } @@ -200,8 +201,8 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) // set motor voltage based on CTRE example - double desiredLeftRotationsPerSecond =(leftMPS/Constants.DrivetrainConstants.kWheelCircumference)/Constants.DrivetrainConstants.kDrivetrainGearRatio; - double desiredRightRotationsPerSecond =(rightMPS/Constants.DrivetrainConstants.kWheelCircumference)/Constants.DrivetrainConstants.kDrivetrainGearRatio; + double desiredLeftRotationsPerSecond =(leftMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; + double desiredRightRotationsPerSecond =(rightMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(desiredLeftRotationsPerSecond)); m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(desiredRightRotationsPerSecond)); diff --git a/prototype_projects/Experimental_Drivetrain_2026/vendordeps/PathplannerLib-2026.1.2.json b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/PathplannerLib-2026.1.2.json new file mode 100644 index 0000000..f72fa41 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/PathplannerLib-2026.1.2.json @@ -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" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/vendordeps/Phoenix6-26.1.0.json b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/Phoenix6-26.1.0.json new file mode 100644 index 0000000..dc5dc62 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/Phoenix6-26.1.0.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-26.1.0.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/vendordeps/REVLib.json b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/REVLib.json new file mode 100644 index 0000000..4f96af8 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/REVLib.json @@ -0,0 +1,133 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2026.0.0", + "frcYear": "2026", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2026.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2026.0.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2026.0.0", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.0", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.0", + "libName": "BackendDriver", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.0", + "libName": "REVLibWpi", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/vendordeps/Studica.json b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/Studica.json new file mode 100644 index 0000000..b51bf58 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/vendordeps/Studica.json @@ -0,0 +1,71 @@ +{ + "fileName": "Studica.json", + "name": "Studica", + "version": "2026.0.0", + "frcYear": "2026", + "uuid": "cb311d09-36e9-4143-a032-55bb2b94443b", + "mavenUrls": [ + "https://dev.studica.com/maven/release/2026/" + ], + "jsonUrl": "https://dev.studica.com/maven/release/2026/json/Studica-2026.0.0.json", + "javaDependencies": [ + { + "groupId": "com.studica.frc", + "artifactId": "Studica-java", + "version": "2026.0.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.studica.frc", + "artifactId": "Studica-driver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.studica.frc", + "artifactId": "Studica-cpp", + "version": "2026.0.0", + "libName": "Studica", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.studica.frc", + "artifactId": "Studica-driver", + "version": "2026.0.0", + "libName": "StudicaDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file From d4c7c8400b9b877ee53247007b8a0d9dc0f39e50 Mon Sep 17 00:00:00 2001 From: 15 - Phosphorus <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:58:57 -0600 Subject: [PATCH 007/161] (2025-Reefscape) Gradle Updates --- .../.gradle/8.11/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/8.11/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.11/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes 2025-Reefscape/.gradle/8.11/gc.properties | 0 .../buildOutputCleanup/buildOutputCleanup.lock | Bin 0 -> 17 bytes .../.gradle/buildOutputCleanup/cache.properties | 2 ++ 2025-Reefscape/.gradle/vcs-1/gc.properties | 0 7 files changed, 2 insertions(+) create mode 100644 2025-Reefscape/.gradle/8.11/checksums/checksums.lock create mode 100644 2025-Reefscape/.gradle/8.11/fileChanges/last-build.bin create mode 100644 2025-Reefscape/.gradle/8.11/fileHashes/fileHashes.lock create mode 100644 2025-Reefscape/.gradle/8.11/gc.properties create mode 100644 2025-Reefscape/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 2025-Reefscape/.gradle/buildOutputCleanup/cache.properties create mode 100644 2025-Reefscape/.gradle/vcs-1/gc.properties diff --git a/2025-Reefscape/.gradle/8.11/checksums/checksums.lock b/2025-Reefscape/.gradle/8.11/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..543b153a265faf0faaee708104d3276bcce84492 GIT binary patch literal 17 TcmZSHJoVmo0jVV~8K3|FIu!(% literal 0 HcmV?d00001 diff --git a/2025-Reefscape/.gradle/8.11/fileChanges/last-build.bin b/2025-Reefscape/.gradle/8.11/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/2025-Reefscape/.gradle/8.11/fileHashes/fileHashes.lock b/2025-Reefscape/.gradle/8.11/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..6e1a0f55f9c70a4469a6f3fc57d4bd2592e6ee27 GIT binary patch literal 17 ScmZSPww;vVoanWh0SW*inF7}U literal 0 HcmV?d00001 diff --git a/2025-Reefscape/.gradle/8.11/gc.properties b/2025-Reefscape/.gradle/8.11/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/2025-Reefscape/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/2025-Reefscape/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..786922fd526d670ad4e0ccf18021be1874c4d840 GIT binary patch literal 17 UcmZQp-@5ppjlj<;1_)pT05qfoK>z>% literal 0 HcmV?d00001 diff --git a/2025-Reefscape/.gradle/buildOutputCleanup/cache.properties b/2025-Reefscape/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..815d0fe --- /dev/null +++ b/2025-Reefscape/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Tue Jan 13 18:35:10 CST 2026 +gradle.version=8.11 diff --git a/2025-Reefscape/.gradle/vcs-1/gc.properties b/2025-Reefscape/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 From df28d0c2ad9ecbc6cb8bbdd1516cef06078dd1af Mon Sep 17 00:00:00 2001 From: 15 - Phosphorus <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:59:24 -0600 Subject: [PATCH 008/161] (Experimental_Drivetrain_2026) Added dashboard control for smooth drive debug --- .../src/main/java/frc/robot/Constants.java | 3 +- .../src/main/java/frc/robot/Robot.java | 2 + .../main/java/frc/robot/RobotContainer.java | 13 +++-- .../DifferentailDriveFromDashboard.java | 51 +++++++++++++++++++ .../commands/DifferentialDriveCommand.java | 12 +++++ .../frc/robot/subsystems/DriveSubsystem.java | 27 ++++++++-- 6 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index 5a4561c..3011abc 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -45,6 +45,7 @@ public static class AutoConstants { public static class OperatorConstants { public static final int kDriverControllerPort = 0; + public static final double kDriverControllerDeadband = 0.02; // Exclusive } public static class DrivetrainConstants { @@ -60,7 +61,7 @@ public static class DrivetrainConstants { // These numbers came from sys id program public static final double kV = 1.8747; // Add x V output to overcome static friction public static final double kS = 0.15316; // A velocity target of 1 rps results in xV output - public static final double kP = 2.7562; // An error of 1 rotation results in x V output + public static final double kP = 0.5; //2.7562; // An error of 1 rotation results in x V output public static final double kI = 0.0; public static final double kD = 0.0; // A velocity of 1 rps results in x V output public static final double kA_linear = 0.1141; // Voltage needed to induce a given accel. in the motor shaft diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java index 687a0a0..f5ae815 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -77,6 +77,8 @@ public void teleopInit() { if (m_autonomousCommand != null) { m_autonomousCommand.cancel(); } + + m_robotContainer.teleopInit(); } /** This function is called periodically during operator control. */ diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 7f035cd..a6be922 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -21,6 +21,7 @@ import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Constants.DrivetrainConstants; +import frc.robot.Constants.OperatorConstants; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -37,8 +38,8 @@ public class RobotContainer { private final Optional m_driveSubsystem; // Replace with CommandPS4Controller or CommandJoystick if needed - //private final CommandXboxController m_driverController = - // new CommandXboxController(OperatorConstants.kDriverControllerPort); + private final CommandXboxController m_driverController = + new CommandXboxController(OperatorConstants.kDriverControllerPort); private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.trackWidthMeters); @@ -114,8 +115,8 @@ private void configureAutos() { private void configureDefaultCommands() { if (m_driveSubsystem.isPresent()) { - //DriveSubsystem driveSubsystem = m_driveSubsystem.get(); - //driveSubsystem.initDefaultCommand(m_driverController); + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + driveSubsystem.initDefaultCommand(m_driverController); } } @@ -145,6 +146,10 @@ private void configureBindings() { // } } + public void teleopInit() { + configureDefaultCommands(); + } + /** * Use this to pass the autonomous command to the main {@link Robot} class. * diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java new file mode 100644 index 0000000..e17124a --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java @@ -0,0 +1,51 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.Constants; +import frc.robot.subsystems.DriveSubsystem; + +public class DifferentailDriveFromDashboard extends Command { + private final DriveSubsystem m_subsystem; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public DifferentailDriveFromDashboard(DriveSubsystem subsystem) { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // This will stop the differential drive saftey warning + m_subsystem.callDrivetrainFeed(); + + double leftSpeed = SmartDashboard.getNumber("DB Left Set", 0); + double rightSpeed = SmartDashboard.getNumber("DB Right Set", 0); + + leftSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + rightSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + + m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java index 27f220a..323b65b 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -7,6 +7,7 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.Constants; +import frc.robot.Constants.OperatorConstants; /** An example command that uses an example subsystem. */ public class DifferentialDriveCommand extends Command { @@ -33,12 +34,23 @@ public void initialize() {} // Called every time the scheduler runs while the command is scheduled. @Override public void execute() { + // This will stop the differential drive saftey warning + m_subsystem.callDrivetrainFeed(); + // Note: We negate both axis values so that pushing the joystick forwards // (which makes the readin more negative) increases the speed and twisting clockwise // turns the robot clockwise. double leftSpeed = -m_driveController.getLeftY(); double rightSpeed = -m_driveController.getRightY(); + // Set the deadband + if (Math.abs(leftSpeed) < OperatorConstants.kDriverControllerDeadband) { + leftSpeed = 0; + } + if (Math.abs(rightSpeed) < OperatorConstants.kDriverControllerDeadband) { + rightSpeed = 0; + } + leftSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; rightSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 592ba87..fe2cc7b 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -31,6 +31,7 @@ import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.Constants.AutoConstants; import frc.robot.Constants.DrivetrainConstants; +import frc.robot.commands.DifferentailDriveFromDashboard; import frc.robot.commands.DifferentialDriveCommand; //import frc.robot.utils.PIDControl; @@ -137,6 +138,15 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential // Gyro setup m_gyro.zeroYaw(); + + // Init Smartdashboard + SmartDashboard.putNumber("Left Set", 0); + SmartDashboard.putNumber("Right Set", 0); + SmartDashboard.putNumber("Left MPS", getMotorSpeedMPS(true)); + SmartDashboard.putNumber("Right MPS", getMotorSpeedMPS(false)); + SmartDashboard.putNumber("DB Left Set", 0); + SmartDashboard.putNumber("DB Right Set", 0); + SmartDashboard.putBoolean("Dashboard Control", false); } public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { @@ -180,7 +190,12 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { public void initDefaultCommand(CommandXboxController Controller) { - setDefaultCommand(new DifferentialDriveCommand(this, Controller)); + boolean useDashboard = SmartDashboard.getBoolean("Dashboard Control", false); + if (useDashboard == true) { + setDefaultCommand(new DifferentailDriveFromDashboard(this)); + } else { + setDefaultCommand(new DifferentialDriveCommand(this, Controller)); + } } public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) @@ -201,8 +216,8 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) // set motor voltage based on CTRE example - double desiredLeftRotationsPerSecond =(leftMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; - double desiredRightRotationsPerSecond =(rightMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; + double desiredLeftRotationsPerSecond =(leftSpeedMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; + double desiredRightRotationsPerSecond =(rightSpeedMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(desiredLeftRotationsPerSecond)); m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(desiredRightRotationsPerSecond)); @@ -269,6 +284,12 @@ public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ relativeChassisSpeed.omegaRadiansPerSecond); } + // For Auto, needs to be in an auto command execute, so we can use the PID without + // differential drive timeing out. + public void callDrivetrainFeed() { + m_Drivetrain.feed(); + } + @Override public void periodic() { // This method will be called once per scheduler run From 4dc568291c1aee7dd0a593979b7efd53931141cf Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 16 Jan 2026 11:24:01 -0600 Subject: [PATCH 009/161] (Experimental_Drivetrain_2026) Made drivetrain units consistant and clear. --- .../src/main/java/frc/robot/Constants.java | 8 +-- .../src/main/java/frc/robot/Robot.java | 3 + .../main/java/frc/robot/RobotContainer.java | 38 +++++------- .../DifferentailDriveFromDashboard.java | 8 +-- .../commands/DifferentialDriveCommand.java | 6 +- .../frc/robot/subsystems/DriveSubsystem.java | 62 +++++++------------ 6 files changed, 51 insertions(+), 74 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index 3011abc..3cc4a34 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -68,11 +68,9 @@ public static class DrivetrainConstants { public static final double kA_angular = 0.1141; // TODO: We need to measure this! public static final double PeakVoltage = 10.0; - public static final int maxVelocity = 30; // rps/s - public static final int maxAcceleration = 50; // rps - - // Constants used by differential drive command. - public static final double maxVelocityMPS = 1.0; + public static final double maxVelocity = 30; // rps/s + public static final double maxAcceleration = 50; // rps + public static final double maxVelocityMPS = DrivetrainConstants.maxVelocity * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; // For Auto Potentially public static boolean kLeftPositiveMovesForward = true; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java index f5ae815..976f67d 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -44,6 +44,9 @@ public void robotPeriodic() { // and running subsystem periodic() methods. This must be called from the robot's periodic // block in order for anything in the Command-based framework to work. CommandScheduler.getInstance().run(); + + // Send subsystem and robot state back to the driver station. + m_robotContainer.UpdateSmartDashboard(); } /** This function is called once each time the robot enters Disabled mode. */ diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index a6be922..fb36060 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -59,6 +59,9 @@ public class RobotContainer { private TalonFXFactory m_TalonFXFactory = new TalonFXFactory(); private DriveSubsystemFactory m_DriveSubsystemFactory = new DriveSubsystemFactory(); + // Keep track of time for SmartDashboard updates. + static int m_iTickCount = 0; + /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { // Init DriveSubsystem @@ -82,27 +85,6 @@ public RobotContainer() { configureBindings(); } - // Tom wrote this cool template to make the optional subsystem creation code in - // the constructor above a lot clearer. This is what clever coding looks like. - // Owen: I added the ability to pass object args through this for dependency injection, - // I hope this does not break anything or commited a coding sin or somthing - // private static Optional getSubsystem(Class subsystemClass, Object... args) { - // Optional iss; - // try { - - // iss = Optional.ofNullable(subsystemClass.getDeclaredConstructor().newInstance(args)); - // } catch (Exception e) { - // iss = Optional.empty(); - // // This is not tested! - Owen - // DriverStation.reportWarning( - // String.format( - // "The %s was not found!", subsystemClass.getName()), - // false - // ); - // } - // return iss; - // } - private void configureAutos() { // Init Autos (/home/lvuser/deploy/pathplanner/autos) ArrayList autoCommands = AutoCommands.getAutoCommands(m_driveSubsystem); @@ -146,6 +128,20 @@ private void configureBindings() { // } } + // This function is called every 20mS. + public void UpdateSmartDashboard() { + // Drive subsystem + if(m_driveSubsystem.isPresent() && (m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) + { + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + + SmartDashboard.putNumber("Left Speed (MPS)", driveSubsystem.getMotorSpeedMPS(true)); + SmartDashboard.putNumber("Right Speed (MPS)", driveSubsystem.getMotorSpeedMPS(false)); + } + + m_iTickCount++; + } + public void teleopInit() { configureDefaultCommands(); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java index e17124a..132649c 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java @@ -2,7 +2,6 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; -import frc.robot.Constants; import frc.robot.subsystems.DriveSubsystem; public class DifferentailDriveFromDashboard extends Command { @@ -30,11 +29,8 @@ public void execute() { // This will stop the differential drive saftey warning m_subsystem.callDrivetrainFeed(); - double leftSpeed = SmartDashboard.getNumber("DB Left Set", 0); - double rightSpeed = SmartDashboard.getNumber("DB Right Set", 0); - - leftSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; - rightSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + double leftSpeed = SmartDashboard.getNumber("DB Left Set (MPS)", 0); + double rightSpeed = SmartDashboard.getNumber("DB Right Set (MPS)", 0); m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java index 323b65b..a45db1e 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -6,7 +6,7 @@ import frc.robot.subsystems.DriveSubsystem; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; -import frc.robot.Constants; +import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; /** An example command that uses an example subsystem. */ @@ -51,8 +51,8 @@ public void execute() { rightSpeed = 0; } - leftSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; - rightSpeed *= Constants.DrivetrainConstants.maxVelocityMPS; + leftSpeed *= DrivetrainConstants.maxVelocityMPS; + rightSpeed *= DrivetrainConstants.maxVelocityMPS; m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index fe2cc7b..4ebd7f6 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -48,9 +48,6 @@ public class DriveSubsystem extends SubsystemBase { private DifferentialDrive m_Drivetrain; - private double m_leftSpeed = 0.0; - private double m_rightSpeed = 0.0; - private final DifferentialDriveKinematics m_kinematics; private final DifferentialDrivePoseEstimator m_poseEstimator; private final AHRS m_gyro; @@ -198,42 +195,30 @@ public void initDefaultCommand(CommandXboxController Controller) } } - public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) - { - // NOTE: We are making our own custom input modifications - //m_leftSpeed = Math.pow(m_leftSpeed, 3); - //m_rightSpeed = Math.pow(m_rightSpeed, 3); - // NOTE: Notes can be useful for conveying information - - SmartDashboard.putNumber("Left Set", leftSpeedMPS); - SmartDashboard.putNumber("Right Set", rightSpeedMPS); - - double leftMPS = getMotorSpeedMPS(true); - double rightMPS = getMotorSpeedMPS(false); - - SmartDashboard.putNumber("Left MPS", leftMPS); - SmartDashboard.putNumber("Right MPS", rightMPS); - - // set motor voltage based on CTRE example - - double desiredLeftRotationsPerSecond =(leftSpeedMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; - double desiredRightRotationsPerSecond =(rightSpeedMPS/DrivetrainConstants.kWheelCircumference)/DrivetrainConstants.kDrivetrainGearRatio; + // TODO: Work on a naming scheme for conversion functions - m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(desiredLeftRotationsPerSecond)); - m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(desiredRightRotationsPerSecond)); + // This converts rotations per second to meters per second. + public double ConvertRPStoMPS(double RPS) { + return RPS * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + } + // This converts meters per second to rotations per second. + // This is the inverse function of the one above, calculated it myself. - Owen + public double ConvertMPStoRPS(double MPS) { + return (MPS / DrivetrainConstants.kDrivetrainGearRatio) / DrivetrainConstants.kWheelCircumference; } - public double getSpeed(boolean bLeft) + // This sets the differential speeds based on a desired MPS speed. + public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) { - if (bLeft) - { - return m_leftSpeed; - } - else - { - return m_rightSpeed; - } + SmartDashboard.putNumber("Left Target (MPS)", leftSpeedMPS); + SmartDashboard.putNumber("Right Target (MPS)", rightSpeedMPS); + + double leftSpeedRPS = ConvertMPStoRPS(leftSpeedMPS); + double rightSpeedRPS = ConvertMPStoRPS(rightSpeedMPS); + + m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(leftSpeedRPS)); + m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(rightSpeedRPS)); } // Wrapping robot position inside of getposition @@ -253,16 +238,15 @@ public double getMotorSpeedMPS(boolean bLeft) double MPS; if (bLeft) { - MPS = m_leftMotor.getVelocity().getValueAsDouble() * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + MPS = ConvertRPStoMPS(m_leftMotor.getVelocity().getValueAsDouble()); } else { - MPS = m_rightMotor.getVelocity().getValueAsDouble() * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + MPS = ConvertRPStoMPS(m_rightMotor.getVelocity().getValueAsDouble()); } return MPS; } - // Returns a robot relative ChassisSpeeds object based on the avrg linear velocity // in meters per second and avrg anglear velocity in readians per second // Currently we are asuming that their is no scale for the motors, we cannot find anywhere to set the scale. @@ -284,8 +268,8 @@ public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ relativeChassisSpeed.omegaRadiansPerSecond); } - // For Auto, needs to be in an auto command execute, so we can use the PID without - // differential drive timeing out. + // Needs to be called in any PID actions execute loop. + // This is because the drivetrain times out during PID control. public void callDrivetrainFeed() { m_Drivetrain.feed(); } From a7f32a74d14f4f3fc648b19c2ec5dafa77148432 Mon Sep 17 00:00:00 2001 From: 15 - Phosphorus <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 16 Jan 2026 18:37:04 -0600 Subject: [PATCH 010/161] Made Velocity and acceleration be MPS by default & removed unused PID controllers --- .../src/main/java/frc/robot/Constants.java | 5 +- .../frc/robot/subsystems/DriveSubsystem.java | 11 --- .../main/java/frc/robot/utils/PIDControl.java | 69 ------------------- 3 files changed, 2 insertions(+), 83 deletions(-) delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index 3cc4a34..481bfde 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -68,9 +68,8 @@ public static class DrivetrainConstants { public static final double kA_angular = 0.1141; // TODO: We need to measure this! public static final double PeakVoltage = 10.0; - public static final double maxVelocity = 30; // rps/s - public static final double maxAcceleration = 50; // rps - public static final double maxVelocityMPS = DrivetrainConstants.maxVelocity * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + public static final double maxVelocityMPS = 3.0; // 6 mps is the max of the motors during zero load. + public static final double maxAccelerationMPS2 = 5.0; // M/S^2 // For Auto Potentially public static boolean kLeftPositiveMovesForward = true; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 4ebd7f6..b87e35f 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -33,7 +33,6 @@ import frc.robot.Constants.DrivetrainConstants; import frc.robot.commands.DifferentailDriveFromDashboard; import frc.robot.commands.DifferentialDriveCommand; -//import frc.robot.utils.PIDControl; public class DriveSubsystem extends SubsystemBase { private TalonFX m_rightMotor; @@ -52,16 +51,6 @@ public class DriveSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; private final AHRS m_gyro; - // PIDControl m_leftPidControl = new PIDControl( - // m_leftMotor, - // DrivetrainConstants.kLeftPositiveMovesForward - // ); - - // PIDControl m_rightPidControl = new PIDControl( - // m_rightMotor, - // DrivetrainConstants.kRightPositiveMovesForward - // ); - /** Creates a new DriveSubsystem. */ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, AHRS gyro, TalonFX rightMotor, TalonFX leftMotor) { m_poseEstimator = poseEstimator; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java deleted file mode 100644 index ead0d7b..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/PIDControl.java +++ /dev/null @@ -1,69 +0,0 @@ -package frc.robot.utils; - -import com.ctre.phoenix6.controls.PositionVoltage; -import com.ctre.phoenix6.hardware.TalonFX; - -import edu.wpi.first.math.trajectory.TrapezoidProfile; -import frc.robot.Constants.DrivetrainConstants; - -public class PIDControl { - private TalonFX m_motor; - private boolean m_positiveMovesForward; - - private double m_targetPosition; - - private final TrapezoidProfile m_profile = new TrapezoidProfile( - new TrapezoidProfile.Constraints( - DrivetrainConstants.maxVelocity, - DrivetrainConstants.maxAcceleration - ) - ); - - private PositionVoltage m_positionVoltage; - private TrapezoidProfile.State m_goal = new TrapezoidProfile.State(); - private TrapezoidProfile.State m_setPoint = new TrapezoidProfile.State(); - - public PIDControl(TalonFX motor, boolean positiveMovesForward) { - m_motor = motor; - m_positiveMovesForward = positiveMovesForward; - } - - public void setTargetPosition(double position) { - m_targetPosition = position; - - double positionRotations = position * DrivetrainConstants.kDrivetrainGearRatio; - if (!m_positiveMovesForward) { - positionRotations = -positionRotations; - } - - m_goal = new TrapezoidProfile.State(positionRotations, 0); - m_setPoint = new TrapezoidProfile.State(0, 0); - - m_positionVoltage = new PositionVoltage(0).withSlot(0); - - m_motor.setPosition(0); // zero's motor at the start of the movement - } - - public void calculatePosition() { - m_setPoint = m_profile.calculate(0.020, m_setPoint, m_goal); - - m_positionVoltage.Position = m_setPoint.position; - m_positionVoltage.Velocity = m_setPoint.velocity; - m_motor.setControl(m_positionVoltage); - } - - public double getTargetPosition() { - return m_targetPosition; - } - - public double getPosition() { - double motorPosition = m_motor.getPosition().getValueAsDouble() / DrivetrainConstants.kDrivetrainGearRatio; - - if (m_positiveMovesForward) { - return motorPosition; - } else { - return -motorPosition; - } - } - -} From 64a633799f9c7e7bc2c728422828f6f8125e622a Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 16 Jan 2026 20:34:11 -0600 Subject: [PATCH 011/161] Updated VelocityClosedLoop to work with our mule drivetrain --- .../src/main/java/frc/robot/Robot.java | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java index fbc7ae3..f08ab6a 100644 --- a/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/VelocityClosedLoop/src/main/java/frc/robot/Robot.java @@ -6,7 +6,6 @@ import static edu.wpi.first.units.Units.*; -import com.ctre.phoenix6.CANBus; import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; @@ -18,6 +17,7 @@ import edu.wpi.first.wpilibj.TimedRobot; import edu.wpi.first.wpilibj.XboxController; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.sim.PhysicsSim; /** @@ -27,9 +27,8 @@ * project. */ public class Robot extends TimedRobot { - private final CANBus canbus = new CANBus("canivore"); - private final TalonFX m_fx = new TalonFX(0, canbus); - private final TalonFX m_fllr = new TalonFX(1, canbus); + private final TalonFX m_fx = new TalonFX(10); + private final TalonFX m_fllr = new TalonFX(20); /* Be able to switch which control request to use based on a button press */ /* Start at velocity 0, use slot 0 */ @@ -51,11 +50,11 @@ public Robot() { TalonFXConfiguration configs = new TalonFXConfiguration(); /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ - configs.Slot0.kS = 0.1; // To account for friction, add 0.1 V of static feedforward - configs.Slot0.kV = 0.12; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second - configs.Slot0.kP = 0.11; // An error of 1 rotation per second results in 0.11 V output - configs.Slot0.kI = 0; // No output for integrated error - configs.Slot0.kD = 0; // No output for error derivative + configs.Slot0.kS = 0.1; // To account for friction, add 0.1 V of static feedforward + configs.Slot0.kV = 0.12; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second + configs.Slot0.kP = 0.11; // An error of 1 rotation per second results in 0.11 V output + configs.Slot0.kI = 0; // No output for integrated error + configs.Slot0.kD = 0; // No output for error derivative // Peak output of 8 volts configs.Voltage.withPeakForwardVoltage(Volts.of(8)) .withPeakReverseVoltage(Volts.of(-8)); @@ -80,6 +79,9 @@ public Robot() { } m_fllr.setControl(new Follower(m_fx.getDeviceID(), MotorAlignmentValue.Aligned)); + + SmartDashboard.putNumber("desired RPS", 0); + SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); } @Override @@ -113,6 +115,9 @@ public void teleopPeriodic() { /* Disable the motor instead */ m_fx.setControl(m_brake); } + + SmartDashboard.putNumber("desired RPS", desiredRotationsPerSecond); + SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); } @Override From 89773ece6be0d5968c25191cf5e8357d67450a31 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 16 Jan 2026 20:48:20 -0600 Subject: [PATCH 012/161] Changed the smoothdrive PID values to the example & it started working. --- .../shuffleboard.json | 249 ++++++++++++++++++ .../src/main/java/frc/robot/Constants.java | 10 +- .../main/java/frc/robot/RobotContainer.java | 4 +- .../robot/factorys/DriveSubsystemFactory.java | 1 + .../frc/robot/subsystems/DriveSubsystem.java | 132 +++++----- 5 files changed, 323 insertions(+), 73 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json new file mode 100644 index 0000000..15cb0fb --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -0,0 +1,249 @@ +{ + "tabPane": [ + { + "title": "Dashboard Testing", + "autoPopulate": false, + "autoPopulatePrefix": "", + "widgetPane": { + "gridSize": 128.0, + "showGrid": true, + "hgap": 16.0, + "vgap": 16.0, + "titleType": 0, + "tiles": { + "3,1": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/DB Left Set (MPS)", + "_title": "/SmartDashboard/DB Left Set (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "4,1": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/DB Right Set (MPS)", + "_title": "SmartDashboard/DB Right Set (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "3,0": { + "size": [ + 2, + 1 + ], + "content": { + "_type": "Toggle Switch", + "_source0": "network_table:///SmartDashboard/Dashboard Control", + "_title": "SmartDashboard/Dashboard Control", + "_glyph": 148, + "_showGlyph": false + } + }, + "3,3": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Left Speed (MPS)", + "_title": "SmartDashboard/Left Speed (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "4,3": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Right Speed (MPS)", + "_title": "SmartDashboard/Right Speed (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "4,2": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Right Target (MPS)", + "_title": "SmartDashboard/Right Target (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "3,2": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Left Target (MPS)", + "_title": "SmartDashboard/Left Target (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "5,0": { + "size": [ + 8, + 4 + ], + "content": { + "_type": "Graph", + "_source0": "network_table:///SmartDashboard/Left Target (MPS)", + "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", + "_title": "Graph", + "_glyph": 148, + "_showGlyph": false, + "Graph/Visible time": 30.0, + "Graph/X-axis auto scrolling": true, + "Y-axis/Automatic bounds": false, + "Y-axis/Upper bound": 3.0, + "Y-axis/Lower bound": -3.0, + "Y-axis/Unit": "mps", + "Visible data/SmartDashboard/Left Speed (MPS)": true, + "Visible data/SmartDashboard/Left Target (MPS)": true + } + }, + "4,4": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Right Speed (RPS)", + "_title": "SmartDashboard/Right Speed (RPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "3,4": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Left Speed (RPS)", + "_title": "SmartDashboard/Left Speed (RPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "6,4": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Right Target (RPS)", + "_title": "/SmartDashboard/Right Target (RPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "5,4": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Left Target (RPS)", + "_title": "/SmartDashboard/Left Target (RPS)", + "_glyph": 148, + "_showGlyph": false + } + } + } + } + }, + { + "title": "Tab 2", + "autoPopulate": false, + "autoPopulatePrefix": "", + "widgetPane": { + "gridSize": 128.0, + "showGrid": true, + "hgap": 16.0, + "vgap": 16.0, + "titleType": 0, + "tiles": { + "3,1": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/current RPS", + "_title": "/SmartDashboard/current RPS", + "_glyph": 148, + "_showGlyph": false + } + }, + "3,0": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/desired RPS", + "_title": "/SmartDashboard/desired RPS", + "_glyph": 148, + "_showGlyph": false + } + }, + "4,0": { + "size": [ + 9, + 4 + ], + "content": { + "_type": "Graph", + "_source0": "network_table:///SmartDashboard/desired RPS", + "_source1": "network_table:///SmartDashboard/current RPS", + "_title": "Graph", + "_glyph": 148, + "_showGlyph": false, + "Graph/Visible time": 30.0, + "Graph/X-axis auto scrolling": true, + "Y-axis/Automatic bounds": false, + "Y-axis/Upper bound": 50.0, + "Y-axis/Lower bound": -50.0, + "Y-axis/Unit": "rps" + } + } + } + } + } + ], + "windowGeometry": { + "x": -5.0, + "y": 1.0, + "width": 1939.0, + "height": 844.0 + } +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index 481bfde..e90f2dd 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -58,15 +58,15 @@ public static class DrivetrainConstants { public static final double kTurnDivider = 2; public static final double kSpeedDivider = 2.5; - // These numbers came from sys id program - public static final double kV = 1.8747; // Add x V output to overcome static friction - public static final double kS = 0.15316; // A velocity target of 1 rps results in xV output - public static final double kP = 0.5; //2.7562; // An error of 1 rotation results in x V output + // These numbers came from the ctre example then tweaked + public static final double kS = 0.1; // A velocity target of 1 rps results in xV output + public static final double kV = 0.12; // Add x V output to overcome static friction + public static final double kP = 0.11; // An error of 1 rotation results in x V output public static final double kI = 0.0; public static final double kD = 0.0; // A velocity of 1 rps results in x V output public static final double kA_linear = 0.1141; // Voltage needed to induce a given accel. in the motor shaft public static final double kA_angular = 0.1141; // TODO: We need to measure this! - public static final double PeakVoltage = 10.0; + public static final double PeakVoltage = 8.0; public static final double maxVelocityMPS = 3.0; // 6 mps is the max of the motors during zero load. public static final double maxAccelerationMPS2 = 5.0; // M/S^2 diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index fb36060..77c8949 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -128,7 +128,7 @@ private void configureBindings() { // } } - // This function is called every 20mS. + // This function is called every 20mS. public void UpdateSmartDashboard() { // Drive subsystem if(m_driveSubsystem.isPresent() && (m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) @@ -137,6 +137,8 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Left Speed (MPS)", driveSubsystem.getMotorSpeedMPS(true)); SmartDashboard.putNumber("Right Speed (MPS)", driveSubsystem.getMotorSpeedMPS(false)); + SmartDashboard.putNumber("Left Speed (RPS)", driveSubsystem.getMotorSpeedRPS(true)); + SmartDashboard.putNumber("Right Speed (RPS)", driveSubsystem.getMotorSpeedRPS(false)); } m_iTickCount++; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java index afc5b84..5aa1d9a 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -24,6 +24,7 @@ public Optional construct(DifferentialDrivePoseEstimator poseEst DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, gyro, rightLead.get(), leftLead.get()); + // TODO: This code is being ran even when the followers dont exist. if (rightFollower.isPresent() && leftFollower.isPresent()) { driveSubsystem.setFollowers(rightFollower.get(), leftFollower.get()); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index b87e35f..4a5623a 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -7,6 +7,9 @@ package frc.robot.subsystems; import static edu.wpi.first.units.Units.Volts; +import java.io.Console; + +import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; import com.ctre.phoenix6.controls.VelocityVoltage; @@ -34,6 +37,7 @@ import frc.robot.commands.DifferentailDriveFromDashboard; import frc.robot.commands.DifferentialDriveCommand; +//TODO: Uncomment differential drive once velocity issues are fixed. public class DriveSubsystem extends SubsystemBase { private TalonFX m_rightMotor; private TalonFX m_optionalRightMotor; @@ -45,7 +49,7 @@ public class DriveSubsystem extends SubsystemBase { private final VelocityVoltage m_leftVelocityVoltage = new VelocityVoltage(0).withSlot(0); private final VelocityVoltage m_rightVelocityVoltage = new VelocityVoltage(0).withSlot(0); - private DifferentialDrive m_Drivetrain; + //private DifferentialDrive m_Drivetrain; private final DifferentialDriveKinematics m_kinematics; private final DifferentialDrivePoseEstimator m_poseEstimator; @@ -60,35 +64,11 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_leftMotor = leftMotor; // Right Motor - TalonFXConfiguration rightMotorConfig = new TalonFXConfiguration(); - rightMotorConfig.Slot0.kV = DrivetrainConstants.kV; - rightMotorConfig.Slot0.kS = DrivetrainConstants.kS; - rightMotorConfig.Slot0.kP = DrivetrainConstants.kP; - rightMotorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error - rightMotorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output - rightMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; - rightMotorConfig.MotorOutput.Inverted = InvertedValue.Clockwise_Positive; - - rightMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) - .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); - - m_rightMotor.getConfigurator().apply(rightMotorConfig); + setConfig(m_rightMotor, InvertedValue.Clockwise_Positive); SendableRegistry.setName(m_rightMotor, "DriveSubsystem", "rightMotor"); // Left Motor - TalonFXConfiguration leftMotorConfig = new TalonFXConfiguration(); - leftMotorConfig.Slot0.kV = DrivetrainConstants.kV; - leftMotorConfig.Slot0.kS = DrivetrainConstants.kS; - leftMotorConfig.Slot0.kP = DrivetrainConstants.kP; - leftMotorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error - leftMotorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output - leftMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; - leftMotorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; - - leftMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) - .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); - - m_leftMotor.getConfigurator().apply(leftMotorConfig); + setConfig(m_leftMotor, InvertedValue.CounterClockwise_Positive); SendableRegistry.setName(m_leftMotor, "DriveSubsystem", "leftMotor"); // Zeroing the encoders @@ -96,8 +76,8 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_rightMotor.setPosition(0); // Setting up the drive train - m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); - SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + //m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); + //SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); // Init Autobuilder AutoBuilder.configure( @@ -120,55 +100,63 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential }, this ); - SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + //SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); // Gyro setup m_gyro.zeroYaw(); // Init Smartdashboard - SmartDashboard.putNumber("Left Set", 0); - SmartDashboard.putNumber("Right Set", 0); - SmartDashboard.putNumber("Left MPS", getMotorSpeedMPS(true)); - SmartDashboard.putNumber("Right MPS", getMotorSpeedMPS(false)); - SmartDashboard.putNumber("DB Left Set", 0); - SmartDashboard.putNumber("DB Right Set", 0); + SmartDashboard.putNumber("DB Left Set (MPS)", 0); + SmartDashboard.putNumber("DB Right Set (MPS)", 0); + SmartDashboard.putNumber("Left Target (MPS)", 0); + SmartDashboard.putNumber("Right Target (MPS)", 0); + SmartDashboard.putNumber("Left Speed (MPS)", getMotorSpeedMPS(true)); + SmartDashboard.putNumber("Right Speed (MPS)", getMotorSpeedMPS(false)); + SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); + SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); SmartDashboard.putBoolean("Dashboard Control", false); } - public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { - m_optionalRightMotor = optionalRight; - - // Setting up Config - TalonFXConfiguration optionalRightMotorConfig = new TalonFXConfiguration(); - //check - optionalRightMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; - optionalRightMotorConfig.MotorOutput.Inverted = InvertedValue.Clockwise_Positive; + private void setConfig(TalonFX motor, InvertedValue Inverted) { + TalonFXConfiguration motorConfig = new TalonFXConfiguration(); + motorConfig.Slot0.kS = DrivetrainConstants.kS; + motorConfig.Slot0.kV = DrivetrainConstants.kV; + motorConfig.Slot0.kP = DrivetrainConstants.kP; + motorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error + motorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output + + motorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + motorConfig.MotorOutput.Inverted = Inverted; - optionalRightMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) + motorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); - // Saving - m_optionalRightMotor.getConfigurator().apply(optionalRightMotorConfig); + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = motor.getConfigurator().apply(motorConfig); + System.out.println("config attempt #" + (i+1) + ": " + status.toString()); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs, error code: " + status.toString()); + } + } - // Setting as a follwer + public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { + // Right Motor + m_optionalRightMotor = optionalRight; + + System.out.println("orm"); + setConfig(m_optionalRightMotor, InvertedValue.Clockwise_Positive); m_optionalRightMotor.setControl( new Follower(m_rightMotor.getDeviceID(), MotorAlignmentValue.Aligned) ); + // Left Motor m_optionalLeftMotor = optionalLeft; - // Setting up Config - TalonFXConfiguration optionalLeftMotorConfig = new TalonFXConfiguration(); - optionalLeftMotorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; - optionalLeftMotorConfig.MotorOutput.Inverted = InvertedValue.CounterClockwise_Positive; - - optionalLeftMotorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) - .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); - - // Saving - m_optionalLeftMotor.getConfigurator().apply(optionalLeftMotorConfig); - - // Setting as follower + System.out.println("olm"); + setConfig(m_optionalLeftMotor, InvertedValue.CounterClockwise_Positive); m_optionalLeftMotor.setControl( new Follower(m_leftMotor.getDeviceID(), MotorAlignmentValue.Aligned) ); @@ -206,6 +194,9 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) double leftSpeedRPS = ConvertMPStoRPS(leftSpeedMPS); double rightSpeedRPS = ConvertMPStoRPS(rightSpeedMPS); + SmartDashboard.putNumber("Left Target (RPS)", leftSpeedRPS); + SmartDashboard.putNumber("Right Target (RPS)", rightSpeedRPS); + m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(leftSpeedRPS)); m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(rightSpeedRPS)); } @@ -222,17 +213,24 @@ public void resetPose(Pose2d newPose){ m_poseEstimator.resetPose(newPose); } - public double getMotorSpeedMPS(boolean bLeft) + public double getMotorSpeedRPS(boolean bLeft) { - double MPS; + double RPS; if (bLeft) { - MPS = ConvertRPStoMPS(m_leftMotor.getVelocity().getValueAsDouble()); + RPS = m_leftMotor.getVelocity().getValueAsDouble(); } else { - MPS = ConvertRPStoMPS(m_rightMotor.getVelocity().getValueAsDouble()); + RPS = m_rightMotor.getVelocity().getValueAsDouble(); } + return RPS; + } + + public double getMotorSpeedMPS(boolean bLeft) + { + double RPS = getMotorSpeedRPS(bLeft); + double MPS = ConvertRPStoMPS(RPS); return MPS; } @@ -253,14 +251,14 @@ public ChassisSpeeds getRobotRelativeSpeeds() // Gives the drivetrain a new drive command based on a robot relative // chassis speed object. public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ - m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, - relativeChassisSpeed.omegaRadiansPerSecond); + //m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, + // relativeChassisSpeed.omegaRadiansPerSecond); } // Needs to be called in any PID actions execute loop. // This is because the drivetrain times out during PID control. public void callDrivetrainFeed() { - m_Drivetrain.feed(); + //m_Drivetrain.feed(); } @Override From a8dd799a97e1380396e0f9c3353b5ba098263dcb Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 17 Jan 2026 10:19:52 -0600 Subject: [PATCH 013/161] Updated talonfx factory to use the new api updates. --- .../robot/factorys/DriveSubsystemFactory.java | 1 - .../frc/robot/factorys/TalonFXFactory.java | 13 ++++++------- .../frc/robot/subsystems/DriveSubsystem.java | 19 +++++++------------ 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java index 5aa1d9a..afc5b84 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -24,7 +24,6 @@ public Optional construct(DifferentialDrivePoseEstimator poseEst DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, gyro, rightLead.get(), leftLead.get()); - // TODO: This code is being ran even when the followers dont exist. if (rightFollower.isPresent() && leftFollower.isPresent()) { driveSubsystem.setFollowers(rightFollower.get(), leftFollower.get()); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java index 1a84899..e50c14e 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/factorys/TalonFXFactory.java @@ -8,13 +8,12 @@ public class TalonFXFactory { public TalonFXFactory() {} public Optional construct(int CANID) { - Optional newMotor; - try { - newMotor = Optional.of(new TalonFX(CANID)); - } catch (Exception e) { - newMotor = Optional.empty(); - } + TalonFX talon = new TalonFX(CANID); - return newMotor; + if (talon.isConnected()) { + return Optional.of(talon); + } else { + return Optional.empty(); + } } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 4a5623a..66407ae 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -7,8 +7,6 @@ package frc.robot.subsystems; import static edu.wpi.first.units.Units.Volts; -import java.io.Console; - import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; @@ -37,7 +35,6 @@ import frc.robot.commands.DifferentailDriveFromDashboard; import frc.robot.commands.DifferentialDriveCommand; -//TODO: Uncomment differential drive once velocity issues are fixed. public class DriveSubsystem extends SubsystemBase { private TalonFX m_rightMotor; private TalonFX m_optionalRightMotor; @@ -49,7 +46,7 @@ public class DriveSubsystem extends SubsystemBase { private final VelocityVoltage m_leftVelocityVoltage = new VelocityVoltage(0).withSlot(0); private final VelocityVoltage m_rightVelocityVoltage = new VelocityVoltage(0).withSlot(0); - //private DifferentialDrive m_Drivetrain; + private DifferentialDrive m_Drivetrain; private final DifferentialDriveKinematics m_kinematics; private final DifferentialDrivePoseEstimator m_poseEstimator; @@ -76,8 +73,8 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_rightMotor.setPosition(0); // Setting up the drive train - //m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); - //SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); + SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); // Init Autobuilder AutoBuilder.configure( @@ -100,7 +97,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential }, this ); - //SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); // Gyro setup m_gyro.zeroYaw(); @@ -146,7 +143,6 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { // Right Motor m_optionalRightMotor = optionalRight; - System.out.println("orm"); setConfig(m_optionalRightMotor, InvertedValue.Clockwise_Positive); m_optionalRightMotor.setControl( new Follower(m_rightMotor.getDeviceID(), MotorAlignmentValue.Aligned) @@ -155,7 +151,6 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { // Left Motor m_optionalLeftMotor = optionalLeft; - System.out.println("olm"); setConfig(m_optionalLeftMotor, InvertedValue.CounterClockwise_Positive); m_optionalLeftMotor.setControl( new Follower(m_leftMotor.getDeviceID(), MotorAlignmentValue.Aligned) @@ -251,14 +246,14 @@ public ChassisSpeeds getRobotRelativeSpeeds() // Gives the drivetrain a new drive command based on a robot relative // chassis speed object. public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ - //m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, - // relativeChassisSpeed.omegaRadiansPerSecond); + m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, + relativeChassisSpeed.omegaRadiansPerSecond); } // Needs to be called in any PID actions execute loop. // This is because the drivetrain times out during PID control. public void callDrivetrainFeed() { - //m_Drivetrain.feed(); + m_Drivetrain.feed(); } @Override From 623b09ff662bd8fed1ca104a4e0981be6a6fbafb Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 17 Jan 2026 11:05:28 -0600 Subject: [PATCH 014/161] Added motormagic for accleration control and tuned it. --- .../shuffleboard.json | 2 +- .../src/main/java/frc/robot/Constants.java | 13 ++++++----- .../commands/DifferentialDriveCommand.java | 4 ++-- .../frc/robot/subsystems/DriveSubsystem.java | 22 ++++++++++++------- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 15cb0fb..5fcc9a1 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -114,7 +114,7 @@ "_title": "Graph", "_glyph": 148, "_showGlyph": false, - "Graph/Visible time": 30.0, + "Graph/Visible time": 10.0, "Graph/X-axis auto scrolling": true, "Y-axis/Automatic bounds": false, "Y-axis/Upper bound": 3.0, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index e90f2dd..1cfd5df 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -64,12 +64,15 @@ public static class DrivetrainConstants { public static final double kP = 0.11; // An error of 1 rotation results in x V output public static final double kI = 0.0; public static final double kD = 0.0; // A velocity of 1 rps results in x V output - public static final double kA_linear = 0.1141; // Voltage needed to induce a given accel. in the motor shaft - public static final double kA_angular = 0.1141; // TODO: We need to measure this! - public static final double PeakVoltage = 8.0; + public static final double kA_linear = 0.01; // Voltage needed to induce a given accel. in the motor shaft + public static final double kA_angular = 0.01; // TODO: We need to measure this! + public static final double kPeakVoltage = 8.0; - public static final double maxVelocityMPS = 3.0; // 6 mps is the max of the motors during zero load. - public static final double maxAccelerationMPS2 = 5.0; // M/S^2 + public static final double kMaxVelocityMPS = 3.0; // 6 mps is the max of the motors during zero load. + public static final double kMaxAccelerationMPS2 = 5.0; // M/S^2 + + public static final double kMotionMagicAcceleration = 100.0; // Higher number --> Faster (50.0 = ~1s to max) + public static final double kMotionMagicJerk = 4000.0; // For Auto Potentially public static boolean kLeftPositiveMovesForward = true; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java index a45db1e..df9185f 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -51,8 +51,8 @@ public void execute() { rightSpeed = 0; } - leftSpeed *= DrivetrainConstants.maxVelocityMPS; - rightSpeed *= DrivetrainConstants.maxVelocityMPS; + leftSpeed *= DrivetrainConstants.kMaxVelocityMPS; + rightSpeed *= DrivetrainConstants.kMaxVelocityMPS; m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 66407ae..69dc354 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -10,6 +10,7 @@ import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; +import com.ctre.phoenix6.controls.MotionMagicVelocityVoltage; import com.ctre.phoenix6.controls.VelocityVoltage; import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.InvertedValue; @@ -43,8 +44,8 @@ public class DriveSubsystem extends SubsystemBase { private TalonFX m_optionalLeftMotor; /* Start at velocity 0, use slot 0 */ - private final VelocityVoltage m_leftVelocityVoltage = new VelocityVoltage(0).withSlot(0); - private final VelocityVoltage m_rightVelocityVoltage = new VelocityVoltage(0).withSlot(0); + private final MotionMagicVelocityVoltage m_leftVelocityVoltage = new MotionMagicVelocityVoltage(0);//.withSlot(0); + private final MotionMagicVelocityVoltage m_rightVelocityVoltage = new MotionMagicVelocityVoltage(0);//.withSlot(0); private DifferentialDrive m_Drivetrain; @@ -61,11 +62,11 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_leftMotor = leftMotor; // Right Motor - setConfig(m_rightMotor, InvertedValue.Clockwise_Positive); + setConfig(m_rightMotor, InvertedValue.CounterClockwise_Positive); SendableRegistry.setName(m_rightMotor, "DriveSubsystem", "rightMotor"); // Left Motor - setConfig(m_leftMotor, InvertedValue.CounterClockwise_Positive); + setConfig(m_leftMotor, InvertedValue.Clockwise_Positive); SendableRegistry.setName(m_leftMotor, "DriveSubsystem", "leftMotor"); // Zeroing the encoders @@ -118,6 +119,7 @@ private void setConfig(TalonFX motor, InvertedValue Inverted) { TalonFXConfiguration motorConfig = new TalonFXConfiguration(); motorConfig.Slot0.kS = DrivetrainConstants.kS; motorConfig.Slot0.kV = DrivetrainConstants.kV; + motorConfig.Slot0.kA = DrivetrainConstants.kA_linear; motorConfig.Slot0.kP = DrivetrainConstants.kP; motorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error motorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output @@ -125,8 +127,12 @@ private void setConfig(TalonFX motor, InvertedValue Inverted) { motorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; motorConfig.MotorOutput.Inverted = Inverted; - motorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.PeakVoltage)) - .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.PeakVoltage)); + motorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.kPeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.kPeakVoltage)); + + var motionMagicConfigs = motorConfig.MotionMagic; + motionMagicConfigs.MotionMagicAcceleration = DrivetrainConstants.kMotionMagicAcceleration; + motionMagicConfigs.MotionMagicJerk = DrivetrainConstants.kMotionMagicJerk; StatusCode status = StatusCode.StatusCodeNotInitialized; for (int i = 0; i < 5; ++i) { @@ -143,7 +149,7 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { // Right Motor m_optionalRightMotor = optionalRight; - setConfig(m_optionalRightMotor, InvertedValue.Clockwise_Positive); + setConfig(m_optionalRightMotor, InvertedValue.CounterClockwise_Positive); m_optionalRightMotor.setControl( new Follower(m_rightMotor.getDeviceID(), MotorAlignmentValue.Aligned) ); @@ -151,7 +157,7 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { // Left Motor m_optionalLeftMotor = optionalLeft; - setConfig(m_optionalLeftMotor, InvertedValue.CounterClockwise_Positive); + setConfig(m_optionalLeftMotor, InvertedValue.Clockwise_Positive); m_optionalLeftMotor.setControl( new Follower(m_leftMotor.getDeviceID(), MotorAlignmentValue.Aligned) ); From b12d810935374288ca33b5f82ff16e91f5d45912 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:35:56 -0600 Subject: [PATCH 015/161] Working path following --- .../Experimental_Drivetrain_2026/build.gradle | 2 +- .../shuffleboard.json | 115 ++++++++++++------ .../src/main/java/frc/robot/Constants.java | 32 ++--- .../main/java/frc/robot/RobotContainer.java | 8 +- .../robot/commands/ArcadeDriveCommand.java | 1 + .../DifferentailDriveFromDashboard.java | 3 - .../commands/DifferentialDriveCommand.java | 3 - .../frc/robot/subsystems/DriveSubsystem.java | 63 +++++----- 8 files changed, 137 insertions(+), 90 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/build.gradle b/prototype_projects/Experimental_Drivetrain_2026/build.gradle index f2ceadb..478b497 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/build.gradle +++ b/prototype_projects/Experimental_Drivetrain_2026/build.gradle @@ -33,7 +33,7 @@ deploy { 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 + deleteOldFiles = true // Change to true to delete files on roboRIO that no // longer exist in deploy directory of this project } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 5fcc9a1..13e3421 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -1,7 +1,7 @@ { "tabPane": [ { - "title": "Dashboard Testing", + "title": "Teleop Dashboard Testing", "autoPopulate": false, "autoPopulatePrefix": "", "widgetPane": { @@ -149,91 +149,134 @@ "_glyph": 148, "_showGlyph": false } - }, - "6,4": { + } + } + } + }, + { + "title": "Auto Testing", + "autoPopulate": false, + "autoPopulatePrefix": "", + "widgetPane": { + "gridSize": 128.0, + "showGrid": true, + "hgap": 16.0, + "vgap": 16.0, + "titleType": 0, + "tiles": { + "3,1": { "size": [ 1, 1 ], "content": { "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Target (RPS)", - "_title": "/SmartDashboard/Right Target (RPS)", + "_source0": "network_table:///SmartDashboard/Left Target (MPS)", + "_title": "SmartDashboard/Left Target (MPS)", "_glyph": 148, "_showGlyph": false } }, - "5,4": { + "3,2": { "size": [ 1, 1 ], "content": { "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Target (RPS)", - "_title": "/SmartDashboard/Left Target (RPS)", + "_source0": "network_table:///SmartDashboard/Left Speed (MPS)", + "_title": "SmartDashboard/Left Speed (MPS)", "_glyph": 148, "_showGlyph": false } - } - } - } - }, - { - "title": "Tab 2", - "autoPopulate": false, - "autoPopulatePrefix": "", - "widgetPane": { - "gridSize": 128.0, - "showGrid": true, - "hgap": 16.0, - "vgap": 16.0, - "titleType": 0, - "tiles": { - "3,1": { + }, + "4,2": { "size": [ 1, 1 ], "content": { "_type": "Text View", - "_source0": "network_table:///SmartDashboard/current RPS", - "_title": "/SmartDashboard/current RPS", + "_source0": "network_table:///SmartDashboard/Right Speed (MPS)", + "_title": "SmartDashboard/Right Speed (MPS)", "_glyph": 148, "_showGlyph": false } }, - "3,0": { + "4,1": { "size": [ 1, 1 ], "content": { "_type": "Text View", - "_source0": "network_table:///SmartDashboard/desired RPS", - "_title": "/SmartDashboard/desired RPS", + "_source0": "network_table:///SmartDashboard/Right Target (MPS)", + "_title": "SmartDashboard/Right Target (MPS)", "_glyph": 148, "_showGlyph": false } }, - "4,0": { + "3,0": { "size": [ - 9, + 2, + 1 + ], + "content": { + "_type": "ComboBox Chooser", + "_source0": "network_table:///SmartDashboard/Auto Chooser", + "_title": "SmartDashboard/Auto Chooser", + "_glyph": 148, + "_showGlyph": false + } + }, + "5,0": { + "size": [ + 8, 4 ], "content": { "_type": "Graph", - "_source0": "network_table:///SmartDashboard/desired RPS", - "_source1": "network_table:///SmartDashboard/current RPS", + "_source0": "network_table:///SmartDashboard/Left Target (MPS)", + "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", + "_source2": "network_table:///SmartDashboard/Left Distance (m)", "_title": "Graph", "_glyph": 148, "_showGlyph": false, "Graph/Visible time": 30.0, "Graph/X-axis auto scrolling": true, "Y-axis/Automatic bounds": false, - "Y-axis/Upper bound": 50.0, - "Y-axis/Lower bound": -50.0, - "Y-axis/Unit": "rps" + "Y-axis/Upper bound": 3.0, + "Y-axis/Lower bound": -3.0, + "Y-axis/Unit": "m", + "Visible data/SmartDashboard/Left Distance (m)": true, + "Visible data/SmartDashboard/Left Speed (MPS)": true, + "Visible data/SmartDashboard/Left Target (MPS)": true + } + }, + "3,3": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Left Distance (m)", + "_title": "SmartDashboard/Left Distance (m)", + "_glyph": 148, + "_showGlyph": false + } + }, + "4,3": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Right Distance (m)", + "_title": "SmartDashboard/Right Distance (m)", + "_glyph": 148, + "_showGlyph": false } } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index 1cfd5df..4a5c247 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -19,14 +19,20 @@ */ public final class Constants { public static class AutoConstants { - // Module Config Stuff - public static final double kMaxDriveVelocityMPS = 40.0; // This is what SysID is saying i dont think its going 90 mph - public static final double kWheelCOF = 1.0; - public static final int kNumMotors = 4; - public static final double kDriveCurrentLimit = 10.0; + public static final double kMaxDriveVelocityMPS = 40.0; // true max speed of the robot mps + public static final double kWheelCOF = 1.0; // no data for this, bsed it + + public static final double kMassKG = 15.0; + //public static final double kMOI = (1/12) * kMassKG * ((DrivetrainConstants.kLengthMeters*DrivetrainConstants.kLengthMeters) + (DrivetrainConstants.kWidthMeters*DrivetrainConstants.kWidthMeters)); // Moment of Intertia + public static final double kMOI = kMassKG * (DrivetrainConstants.kTrackWidthMeters/2) * (DrivetrainConstants.kA_angular / DrivetrainConstants.kA_linear); // Moment of Intertia + + public static final double kDriveCurrentLimit = 10.0; // amps + + // These values may change per bot, we might want to populate these on init w/ accurate data + public static final int kNumMotors = 4; // # of motors in a gearbox public static final DCMotor kDriveMotor = DCMotor.getKrakenX60(kNumMotors); - public static final ModuleConfig kMoudleConfig = new ModuleConfig( + public static final ModuleConfig kModuleConfig = new ModuleConfig( DrivetrainConstants.kWheelRadiusMeters, kMaxDriveVelocityMPS, kWheelCOF, @@ -35,12 +41,8 @@ public static class AutoConstants { kNumMotors ); - // Robot Config Stuff - // TODO: Run SYS ID and fill in! - public static final double kMassKG = 15.0; - public static final double kMOI = kMassKG * (DrivetrainConstants.trackWidthMeters/2) * (DrivetrainConstants.kA_angular / DrivetrainConstants.kA_linear); // Moment of Intertia - - public static final RobotConfig kRobotConfig = new RobotConfig(kMassKG, kMOI, kMoudleConfig, DrivetrainConstants.trackWidthMeters); + public static final RobotConfig kRobotConfig = new RobotConfig(kMassKG, kMOI, kModuleConfig, DrivetrainConstants.kTrackWidthMeters); + // populate on init possibility end here } public static class OperatorConstants { @@ -82,11 +84,11 @@ public static class DrivetrainConstants { public static final double kDrivetrainGearRatio = 0.2; public static final double kWheelRadiusMeters = (4.0 / 2.0) * 0.0254; // Four Inch Wheels public static final double kWheelCircumference = 2 * Math.PI * DrivetrainConstants.kWheelRadiusMeters; + public static final double kWidthMeters = 0.760; + public static final double kLengthMeters = 0.760; + public static final double kTrackWidthMeters = 29.0 * 0.0254;//0.74; // SmartDashboard update frequency for drive subsystem state in 20ms counts. public static final int kTicksPerUpdate = 5; - - // The track width in meters. - public static final double trackWidthMeters = 29.0 * 0.0254; } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 77c8949..be6bb5c 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -4,7 +4,6 @@ package frc.robot; -import java.util.ArrayList; import java.util.Optional; import com.ctre.phoenix6.hardware.TalonFX; @@ -42,7 +41,7 @@ public class RobotContainer { new CommandXboxController(OperatorConstants.kDriverControllerPort); private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); - private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.trackWidthMeters); + private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.kTrackWidthMeters); // Pose Estimators private DifferentialDrivePoseEstimator m_DrivePoseEstimator = new DifferentialDrivePoseEstimator( @@ -87,7 +86,7 @@ public RobotContainer() { private void configureAutos() { // Init Autos (/home/lvuser/deploy/pathplanner/autos) - ArrayList autoCommands = AutoCommands.getAutoCommands(m_driveSubsystem); + AutoCommands.getAutoCommands(m_driveSubsystem); // Init Chooser autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string @@ -139,6 +138,9 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Right Speed (MPS)", driveSubsystem.getMotorSpeedMPS(false)); SmartDashboard.putNumber("Left Speed (RPS)", driveSubsystem.getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", driveSubsystem.getMotorSpeedRPS(false)); + + SmartDashboard.putNumber("Left Distance (m)", driveSubsystem.getMotorPositionMeters(true)); + SmartDashboard.putNumber("Right Distance (m)", driveSubsystem.getMotorPositionMeters(false)); } m_iTickCount++; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java index a641317..503602f 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -35,6 +35,7 @@ public void execute() { // Note: We negate both axis values so that pushing the joystick forwards // (which makes the readin more negative) increases the speed and twisting clockwise // turns the robot clockwise. + // TODO: This code is not correct for arcade drive, comeback and rewrite it - Owen m_subsystem.setDifferentialSpeeds( -m_driveController.getRightY(), -m_driveController.getLeftX() diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java index 132649c..4268bc3 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java @@ -26,9 +26,6 @@ public void initialize() {} // Called every time the scheduler runs while the command is scheduled. @Override public void execute() { - // This will stop the differential drive saftey warning - m_subsystem.callDrivetrainFeed(); - double leftSpeed = SmartDashboard.getNumber("DB Left Set (MPS)", 0); double rightSpeed = SmartDashboard.getNumber("DB Right Set (MPS)", 0); diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java index df9185f..16b0322 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -34,9 +34,6 @@ public void initialize() {} // Called every time the scheduler runs while the command is scheduled. @Override public void execute() { - // This will stop the differential drive saftey warning - m_subsystem.callDrivetrainFeed(); - // Note: We negate both axis values so that pushing the joystick forwards // (which makes the readin more negative) increases the speed and twisting clockwise // turns the robot clockwise. diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 69dc354..ba250b8 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -11,7 +11,6 @@ import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; import com.ctre.phoenix6.controls.MotionMagicVelocityVoltage; -import com.ctre.phoenix6.controls.VelocityVoltage; import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.InvertedValue; import com.ctre.phoenix6.signals.MotorAlignmentValue; @@ -27,7 +26,6 @@ import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds; import edu.wpi.first.util.sendable.SendableRegistry; import edu.wpi.first.wpilibj.DriverStation; -import edu.wpi.first.wpilibj.drive.DifferentialDrive; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; @@ -47,8 +45,6 @@ public class DriveSubsystem extends SubsystemBase { private final MotionMagicVelocityVoltage m_leftVelocityVoltage = new MotionMagicVelocityVoltage(0);//.withSlot(0); private final MotionMagicVelocityVoltage m_rightVelocityVoltage = new MotionMagicVelocityVoltage(0);//.withSlot(0); - private DifferentialDrive m_Drivetrain; - private final DifferentialDriveKinematics m_kinematics; private final DifferentialDrivePoseEstimator m_poseEstimator; private final AHRS m_gyro; @@ -71,11 +67,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential // Zeroing the encoders m_leftMotor.setPosition(0); - m_rightMotor.setPosition(0); - - // Setting up the drive train - m_Drivetrain = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); - SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); + m_rightMotor.setPosition(0); // Init Autobuilder AutoBuilder.configure( @@ -98,7 +90,6 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential }, this ); - SendableRegistry.setName(m_Drivetrain, "DriveSubsystem", "Drivetrain"); // Gyro setup m_gyro.zeroYaw(); @@ -175,15 +166,15 @@ public void initDefaultCommand(CommandXboxController Controller) // TODO: Work on a naming scheme for conversion functions - // This converts rotations per second to meters per second. - public double ConvertRPStoMPS(double RPS) { - return RPS * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + // This converts rotations of the motor shaft to meters travled. + public double ConvertRotationsToMeters(double rotations) { + return rotations * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; } - // This converts meters per second to rotations per second. + // This converts meters travled to rotations of the motor shaft. // This is the inverse function of the one above, calculated it myself. - Owen - public double ConvertMPStoRPS(double MPS) { - return (MPS / DrivetrainConstants.kDrivetrainGearRatio) / DrivetrainConstants.kWheelCircumference; + public double ConvertMetersToRotations(double meters) { + return (meters / DrivetrainConstants.kDrivetrainGearRatio) / DrivetrainConstants.kWheelCircumference; } // This sets the differential speeds based on a desired MPS speed. @@ -192,12 +183,14 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) SmartDashboard.putNumber("Left Target (MPS)", leftSpeedMPS); SmartDashboard.putNumber("Right Target (MPS)", rightSpeedMPS); - double leftSpeedRPS = ConvertMPStoRPS(leftSpeedMPS); - double rightSpeedRPS = ConvertMPStoRPS(rightSpeedMPS); + double leftSpeedRPS = ConvertMetersToRotations(leftSpeedMPS); + double rightSpeedRPS = ConvertMetersToRotations(rightSpeedMPS); SmartDashboard.putNumber("Left Target (RPS)", leftSpeedRPS); SmartDashboard.putNumber("Right Target (RPS)", rightSpeedRPS); + System.out.println(leftSpeedMPS + " // "+leftSpeedRPS); + m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(leftSpeedRPS)); m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(rightSpeedRPS)); } @@ -231,10 +224,23 @@ public double getMotorSpeedRPS(boolean bLeft) public double getMotorSpeedMPS(boolean bLeft) { double RPS = getMotorSpeedRPS(bLeft); - double MPS = ConvertRPStoMPS(RPS); + double MPS = ConvertRotationsToMeters(RPS); return MPS; } + // Gets the distance travled by the motor in meters + public double getMotorPositionMeters(boolean bLeft) { + double posRotations; + if (bLeft == true) { + posRotations = m_leftMotor.getPosition().getValueAsDouble(); + } else { + posRotations = m_rightMotor.getPosition().getValueAsDouble(); + } + + double posMeters = ConvertRotationsToMeters(posRotations); + return posMeters; + } + // Returns a robot relative ChassisSpeeds object based on the avrg linear velocity // in meters per second and avrg anglear velocity in readians per second // Currently we are asuming that their is no scale for the motors, we cannot find anywhere to set the scale. @@ -252,24 +258,23 @@ public ChassisSpeeds getRobotRelativeSpeeds() // Gives the drivetrain a new drive command based on a robot relative // chassis speed object. public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ - m_Drivetrain.arcadeDrive(relativeChassisSpeed.vxMetersPerSecond, - relativeChassisSpeed.omegaRadiansPerSecond); - } + DifferentialDriveWheelSpeeds wheelSpeeds = m_kinematics.toWheelSpeeds(relativeChassisSpeed); - // Needs to be called in any PID actions execute loop. - // This is because the drivetrain times out during PID control. - public void callDrivetrainFeed() { - m_Drivetrain.feed(); + setDifferentialSpeeds(wheelSpeeds.leftMetersPerSecond, wheelSpeeds.rightMetersPerSecond); } @Override public void periodic() { // This method will be called once per scheduler run + double lPositionMeters = getMotorPositionMeters(true); + double rPositionMeters = getMotorPositionMeters(false); + m_poseEstimator.update( - m_gyro.getRotation2d(), - m_leftMotor.getPosition().getValueAsDouble(), - m_rightMotor.getPosition().getValueAsDouble()); + m_gyro.getRotation2d(), + lPositionMeters, + rPositionMeters + ); } @Override From c1dffdf67b72af785361ccab9b0ea9a6fe1d2f07 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 17 Jan 2026 14:43:48 -0600 Subject: [PATCH 016/161] Added 2nd autoprogram, updated shuffleboard, and removed debug statements --- .../shuffleboard.json | 8 +-- .../deploy/pathplanner/autos/2MeterAuto.auto | 19 +++++++ .../deploy/pathplanner/paths/2 Meter New.path | 54 +++++++++++++++++++ .../frc/robot/subsystems/DriveSubsystem.java | 2 - 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 13e3421..a50b41d 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -114,7 +114,7 @@ "_title": "Graph", "_glyph": 148, "_showGlyph": false, - "Graph/Visible time": 10.0, + "Graph/Visible time": 30.0, "Graph/X-axis auto scrolling": true, "Y-axis/Automatic bounds": false, "Y-axis/Upper bound": 3.0, @@ -236,9 +236,9 @@ ], "content": { "_type": "Graph", - "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", - "_source2": "network_table:///SmartDashboard/Left Distance (m)", + "_source0": "network_table:///SmartDashboard/Left Distance (m)", + "_source1": "network_table:///SmartDashboard/Left Target (MPS)", + "_source2": "network_table:///SmartDashboard/Left Speed (MPS)", "_title": "Graph", "_glyph": 148, "_showGlyph": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto new file mode 100644 index 0000000..b9dbc81 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "2 Meter New" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path new file mode 100644 index 0000000..dfc9214 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 1.0, + "y": 1.0 + }, + "prevControl": null, + "nextControl": { + "x": 1.9999999999999996, + "y": 1.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 3.0, + "y": 1.0 + }, + "prevControl": { + "x": 2.0, + "y": 1.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 3.0, + "maxAcceleration": 3.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index ba250b8..c057add 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -189,8 +189,6 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) SmartDashboard.putNumber("Left Target (RPS)", leftSpeedRPS); SmartDashboard.putNumber("Right Target (RPS)", rightSpeedRPS); - System.out.println(leftSpeedMPS + " // "+leftSpeedRPS); - m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(leftSpeedRPS)); m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(rightSpeedRPS)); } From 3500f46b3310e7d195c7d860d29bd3b88d1642f8 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:35:57 -0600 Subject: [PATCH 017/161] Added a arcade drive command that uses the PID. --- .../shuffleboard.json | 26 ++++++------ .../robot/commands/ArcadeDriveCommand.java | 42 ++++++++++++++++--- .../frc/robot/subsystems/DriveSubsystem.java | 10 ++--- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index a50b41d..669a400 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -37,19 +37,6 @@ "_showGlyph": false } }, - "3,0": { - "size": [ - 2, - 1 - ], - "content": { - "_type": "Toggle Switch", - "_source0": "network_table:///SmartDashboard/Dashboard Control", - "_title": "SmartDashboard/Dashboard Control", - "_glyph": 148, - "_showGlyph": false - } - }, "3,3": { "size": [ 1, @@ -149,6 +136,19 @@ "_glyph": 148, "_showGlyph": false } + }, + "3,0": { + "size": [ + 2, + 1 + ], + "content": { + "_type": "Toggle Switch", + "_source0": "network_table:///SmartDashboard/Use Arcade", + "_title": "SmartDashboard/Use Arcade", + "_glyph": 148, + "_showGlyph": false + } } } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java index 503602f..bcdd679 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -3,6 +3,8 @@ // the WPILib BSD license file in the root directory of this project. package frc.robot.commands; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.Constants.OperatorConstants; import frc.robot.subsystems.DriveSubsystem; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; @@ -32,14 +34,44 @@ public void initialize() {} // Called every time the scheduler runs while the command is scheduled. @Override public void execute() { + // TODO: This code is not correct for arcade drive, comeback and rewrite it - Owen + // Note: We negate both axis values so that pushing the joystick forwards // (which makes the readin more negative) increases the speed and twisting clockwise // turns the robot clockwise. - // TODO: This code is not correct for arcade drive, comeback and rewrite it - Owen - m_subsystem.setDifferentialSpeeds( - -m_driveController.getRightY(), - -m_driveController.getLeftX() - ); + double speedInput = -m_driveController.getRightY(); + double turnInput = m_driveController.getLeftX(); + + // Set the deadband + if (Math.abs(speedInput) < OperatorConstants.kDriverControllerDeadband) { + speedInput = 0; + } + if (Math.abs(turnInput) < OperatorConstants.kDriverControllerDeadband) { + turnInput = 0; + } + + double leftSpeed = speedInput + turnInput; + double rightSpeed = speedInput - turnInput; + + // Find the maximum possible value of (throttle + turn) along the vector + // that the joystick is pointing, then desaturate the wheel speeds + double greaterInput = Math.max(Math.abs(speedInput), Math.abs(turnInput)); + double lesserInput = Math.min(Math.abs(speedInput), Math.abs(turnInput)); + if (greaterInput == 0.0) { + m_subsystem.setDifferentialSpeeds( + 0, + 0 + ); + } else { + double saturatedInput = (greaterInput + lesserInput) / greaterInput; + leftSpeed /= saturatedInput; + rightSpeed /= saturatedInput; + + m_subsystem.setDifferentialSpeeds( + leftSpeed * DrivetrainConstants.kMaxVelocityMPS, + rightSpeed * DrivetrainConstants.kMaxVelocityMPS + ); + } } // Called once the command ends or is interrupted. diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index c057add..eba6c1e 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -31,7 +31,7 @@ import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.Constants.AutoConstants; import frc.robot.Constants.DrivetrainConstants; -import frc.robot.commands.DifferentailDriveFromDashboard; +import frc.robot.commands.ArcadeDriveCommand; import frc.robot.commands.DifferentialDriveCommand; public class DriveSubsystem extends SubsystemBase { @@ -103,7 +103,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential SmartDashboard.putNumber("Right Speed (MPS)", getMotorSpeedMPS(false)); SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); - SmartDashboard.putBoolean("Dashboard Control", false); + SmartDashboard.putBoolean("Use Arcade", true); } private void setConfig(TalonFX motor, InvertedValue Inverted) { @@ -156,9 +156,9 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { public void initDefaultCommand(CommandXboxController Controller) { - boolean useDashboard = SmartDashboard.getBoolean("Dashboard Control", false); - if (useDashboard == true) { - setDefaultCommand(new DifferentailDriveFromDashboard(this)); + boolean useArcade = SmartDashboard.getBoolean("Use Arcade", true); + if (useArcade == true) { + setDefaultCommand(new ArcadeDriveCommand(this, Controller)); } else { setDefaultCommand(new DifferentialDriveCommand(this, Controller)); } From c865c30e4eb4655603f97b97da93b7008d059c1d Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 17 Jan 2026 15:47:35 -0600 Subject: [PATCH 018/161] Added a no pid arcade option, make a chooser list to select drivemode. --- .../robot/commands/ArcadeDriveCommand.java | 2 - .../commands/ArcadeDriveCommandNoPID.java | 77 +++++++++++++++++++ .../frc/robot/subsystems/DriveSubsystem.java | 17 +++- 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java index bcdd679..65eb3bd 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -34,8 +34,6 @@ public void initialize() {} // Called every time the scheduler runs while the command is scheduled. @Override public void execute() { - // TODO: This code is not correct for arcade drive, comeback and rewrite it - Owen - // Note: We negate both axis values so that pushing the joystick forwards // (which makes the readin more negative) increases the speed and twisting clockwise // turns the robot clockwise. diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java new file mode 100644 index 0000000..88ee73a --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java @@ -0,0 +1,77 @@ +// 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.commands; +import frc.robot.Constants.OperatorConstants; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; + +/** An example command that uses an example subsystem. */ +public class ArcadeDriveCommandNoPID extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeDriveCommandNoPID(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + double speedInput = -m_driveController.getRightY(); + double turnInput = m_driveController.getLeftX(); + + // Set the deadband + if (Math.abs(speedInput) < OperatorConstants.kDriverControllerDeadband) { + speedInput = 0; + } + if (Math.abs(turnInput) < OperatorConstants.kDriverControllerDeadband) { + turnInput = 0; + } + + double leftSpeed = speedInput + turnInput; + double rightSpeed = speedInput - turnInput; + + // Find the maximum possible value of (throttle + turn) along the vector + // that the joystick is pointing, then desaturate the wheel speeds + double greaterInput = Math.max(Math.abs(speedInput), Math.abs(turnInput)); + double lesserInput = Math.min(Math.abs(speedInput), Math.abs(turnInput)); + if (greaterInput == 0.0) { + m_subsystem.setDifferentialSpeedNoPid(0, 0); + } else { + double saturatedInput = (greaterInput + lesserInput) / greaterInput; + leftSpeed /= saturatedInput; + rightSpeed /= saturatedInput; + + m_subsystem.setDifferentialSpeedNoPid(leftSpeed, rightSpeed); + } + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index eba6c1e..b8bf840 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -32,6 +32,7 @@ import frc.robot.Constants.AutoConstants; import frc.robot.Constants.DrivetrainConstants; import frc.robot.commands.ArcadeDriveCommand; +import frc.robot.commands.ArcadeDriveCommandNoPID; import frc.robot.commands.DifferentialDriveCommand; public class DriveSubsystem extends SubsystemBase { @@ -103,7 +104,8 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential SmartDashboard.putNumber("Right Speed (MPS)", getMotorSpeedMPS(false)); SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); - SmartDashboard.putBoolean("Use Arcade", true); + SmartDashboard.putBoolean("PID Arcade", true); + SmartDashboard.putBoolean("No PID Arcade", false); } private void setConfig(TalonFX motor, InvertedValue Inverted) { @@ -154,11 +156,16 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { ); } + // TODO: Make a list chooser. public void initDefaultCommand(CommandXboxController Controller) { - boolean useArcade = SmartDashboard.getBoolean("Use Arcade", true); + boolean useArcade = SmartDashboard.getBoolean("PID Arcade", true); + boolean useNoPID = SmartDashboard.getBoolean("No PID Arcade", false); + if (useArcade == true) { setDefaultCommand(new ArcadeDriveCommand(this, Controller)); + } else if (useNoPID == true) { + setDefaultCommand(new ArcadeDriveCommandNoPID(this, Controller)); } else { setDefaultCommand(new DifferentialDriveCommand(this, Controller)); } @@ -193,6 +200,12 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(rightSpeedRPS)); } + // pass in -1 to 1 for the motor speed with no closed loop control. + public void setDifferentialSpeedNoPid(double left, double right) { + m_leftMotor.set(left); + m_rightMotor.set(right); + } + // Wrapping robot position inside of getposition public Pose2d getPose(){ return m_poseEstimator.getEstimatedPosition(); From 739429508f769b078aac73ba43d1fb0bc51428cc Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:54:29 -0600 Subject: [PATCH 019/161] Added new paths & attempted to debug not zeroing on auto --- .../shuffleboard.json | 14 ++--- .../deploy/pathplanner/autos/STurnAuto.auto | 19 +++++++ .../pathplanner/autos/SmoothTurnAuto.auto | 19 +++++++ .../deploy/pathplanner/paths/2 Meter New.path | 20 +++---- .../pathplanner/paths/Example Path.path | 4 +- .../main/deploy/pathplanner/paths/S Turn.path | 54 +++++++++++++++++++ .../deploy/pathplanner/paths/Smooth Turn.path | 54 +++++++++++++++++++ .../src/main/deploy/pathplanner/settings.json | 8 +-- .../src/main/java/frc/robot/Constants.java | 2 + .../frc/robot/subsystems/DriveSubsystem.java | 5 -- 10 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 669a400..82f14e4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -101,7 +101,7 @@ "_title": "Graph", "_glyph": 148, "_showGlyph": false, - "Graph/Visible time": 30.0, + "Graph/Visible time": 10.0, "Graph/X-axis auto scrolling": true, "Y-axis/Automatic bounds": false, "Y-axis/Upper bound": 3.0, @@ -172,7 +172,7 @@ "content": { "_type": "Text View", "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_title": "SmartDashboard/Left Target (MPS)", + "_title": "/SmartDashboard/Left Target (MPS)", "_glyph": 148, "_showGlyph": false } @@ -185,7 +185,7 @@ "content": { "_type": "Text View", "_source0": "network_table:///SmartDashboard/Left Speed (MPS)", - "_title": "SmartDashboard/Left Speed (MPS)", + "_title": "/SmartDashboard/Left Speed (MPS)", "_glyph": 148, "_showGlyph": false } @@ -198,7 +198,7 @@ "content": { "_type": "Text View", "_source0": "network_table:///SmartDashboard/Right Speed (MPS)", - "_title": "SmartDashboard/Right Speed (MPS)", + "_title": "/SmartDashboard/Right Speed (MPS)", "_glyph": 148, "_showGlyph": false } @@ -211,7 +211,7 @@ "content": { "_type": "Text View", "_source0": "network_table:///SmartDashboard/Right Target (MPS)", - "_title": "SmartDashboard/Right Target (MPS)", + "_title": "/SmartDashboard/Right Target (MPS)", "_glyph": 148, "_showGlyph": false } @@ -224,7 +224,7 @@ "content": { "_type": "ComboBox Chooser", "_source0": "network_table:///SmartDashboard/Auto Chooser", - "_title": "SmartDashboard/Auto Chooser", + "_title": "/SmartDashboard/Auto Chooser", "_glyph": 148, "_showGlyph": false } @@ -274,7 +274,7 @@ "content": { "_type": "Text View", "_source0": "network_table:///SmartDashboard/Right Distance (m)", - "_title": "SmartDashboard/Right Distance (m)", + "_title": "/SmartDashboard/Right Distance (m)", "_glyph": 148, "_showGlyph": false } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto new file mode 100644 index 0000000..45002a3 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "S Turn" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto new file mode 100644 index 0000000..870c422 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Smooth Turn" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path index dfc9214..0ba9ad5 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path @@ -3,25 +3,25 @@ "waypoints": [ { "anchor": { - "x": 1.0, - "y": 1.0 + "x": 0.0, + "y": 0.0 }, "prevControl": null, "nextControl": { - "x": 1.9999999999999996, - "y": 1.0 + "x": 0.9999999999999996, + "y": 0.0 }, "isLocked": false, "linkedName": null }, { "anchor": { - "x": 3.0, - "y": 1.0 + "x": 2.0, + "y": 0.0 }, "prevControl": { - "x": 2.0, - "y": 1.0 + "x": 1.0, + "y": 2.220446049250313e-16 }, "nextControl": null, "isLocked": false, @@ -33,8 +33,8 @@ "pointTowardsZones": [], "eventMarkers": [], "globalConstraints": { - "maxVelocity": 3.0, - "maxAcceleration": 3.0, + "maxVelocity": 1.0, + "maxAcceleration": 1.0, "maxAngularVelocity": 540.0, "maxAngularAcceleration": 720.0, "nominalVoltage": 12.0, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path index d474f95..0d78846 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path @@ -33,8 +33,8 @@ "pointTowardsZones": [], "eventMarkers": [], "globalConstraints": { - "maxVelocity": 3.0, - "maxAcceleration": 3.0, + "maxVelocity": 1.0, + "maxAcceleration": 1.0, "maxAngularVelocity": 540.0, "maxAngularAcceleration": 720.0, "nominalVoltage": 12.0, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path new file mode 100644 index 0000000..c0c3795 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.0, + "y": 0.0 + }, + "prevControl": null, + "nextControl": { + "x": 2.0, + "y": 0.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 2.0 + }, + "prevControl": { + "x": 0.0, + "y": 2.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path new file mode 100644 index 0000000..e4f9623 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.0, + "y": 0.0 + }, + "prevControl": null, + "nextControl": { + "x": 2.0, + "y": 0.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 2.0 + }, + "prevControl": { + "x": 2.0, + "y": 0.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json index 75d95ab..9479112 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/settings.json @@ -6,8 +6,8 @@ "New Folder" ], "autoFolders": [], - "defaultMaxVel": 3.0, - "defaultMaxAccel": 3.0, + "defaultMaxVel": 1.0, + "defaultMaxAccel": 1.0, "defaultMaxAngVel": 540.0, "defaultMaxAngAccel": 720.0, "defaultNominalVoltage": 12.0, @@ -30,5 +30,7 @@ "brModuleY": -0.273, "bumperOffsetX": 0.0, "bumperOffsetY": 0.0, - "robotFeatures": [] + "robotFeatures": [ + "{\"name\":\"Rectangle\",\"type\":\"rounded_rect\",\"data\":{\"center\":{\"x\":0.0,\"y\":0.0},\"size\":{\"width\":0.2,\"length\":0.2},\"borderRadius\":0.05,\"strokeWidth\":0.02,\"filled\":false}}" + ] } \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java index 4a5c247..2808f3b 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Constants.java @@ -23,6 +23,8 @@ public static class AutoConstants { public static final double kWheelCOF = 1.0; // no data for this, bsed it public static final double kMassKG = 15.0; + + // Uncommenting this causes the weird x y rotion error. //public static final double kMOI = (1/12) * kMassKG * ((DrivetrainConstants.kLengthMeters*DrivetrainConstants.kLengthMeters) + (DrivetrainConstants.kWidthMeters*DrivetrainConstants.kWidthMeters)); // Moment of Intertia public static final double kMOI = kMassKG * (DrivetrainConstants.kTrackWidthMeters/2) * (DrivetrainConstants.kA_angular / DrivetrainConstants.kA_linear); // Moment of Intertia diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index b8bf840..dfb2aec 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -32,7 +32,6 @@ import frc.robot.Constants.AutoConstants; import frc.robot.Constants.DrivetrainConstants; import frc.robot.commands.ArcadeDriveCommand; -import frc.robot.commands.ArcadeDriveCommandNoPID; import frc.robot.commands.DifferentialDriveCommand; public class DriveSubsystem extends SubsystemBase { @@ -105,7 +104,6 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); SmartDashboard.putBoolean("PID Arcade", true); - SmartDashboard.putBoolean("No PID Arcade", false); } private void setConfig(TalonFX motor, InvertedValue Inverted) { @@ -160,12 +158,9 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { public void initDefaultCommand(CommandXboxController Controller) { boolean useArcade = SmartDashboard.getBoolean("PID Arcade", true); - boolean useNoPID = SmartDashboard.getBoolean("No PID Arcade", false); if (useArcade == true) { setDefaultCommand(new ArcadeDriveCommand(this, Controller)); - } else if (useNoPID == true) { - setDefaultCommand(new ArcadeDriveCommandNoPID(this, Controller)); } else { setDefaultCommand(new DifferentialDriveCommand(this, Controller)); } From e17630194c7bec784612994adc3bf7195661df0b Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 20 Jan 2026 20:55:24 -0600 Subject: [PATCH 020/161] Add prototype fuel transport example Adding a project based on CTRE's velocity control example to drive the fuel transport mechanism in the 2026 FRC robot. --- prototype_projects/FuelTransport/.gitignore | 187 ++++++++ .../FuelTransport/.vscode/launch.json | 21 + .../FuelTransport/.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 6 + .../FuelTransport/WPILib-License.md | 24 + prototype_projects/FuelTransport/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + prototype_projects/FuelTransport/gradlew | 252 ++++++++++ prototype_projects/FuelTransport/gradlew.bat | 94 ++++ .../FuelTransport/settings.gradle | 30 ++ .../FuelTransport/src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Mechanisms.java | 58 +++ .../src/main/java/frc/robot/Robot.java | 100 ++++ .../main/java/frc/robot/sim/PhysicsSim.java | 81 ++++ .../java/frc/robot/sim/TalonFXSimProfile.java | 57 +++ .../vendordeps/Phoenix6-frc2026-latest.json | 449 ++++++++++++++++++ .../vendordeps/WPILibNewCommands.json | 39 ++ 19 files changed, 1601 insertions(+) create mode 100644 prototype_projects/FuelTransport/.gitignore create mode 100644 prototype_projects/FuelTransport/.vscode/launch.json create mode 100644 prototype_projects/FuelTransport/.vscode/settings.json create mode 100644 prototype_projects/FuelTransport/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/FuelTransport/WPILib-License.md create mode 100644 prototype_projects/FuelTransport/build.gradle create mode 100644 prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/FuelTransport/gradlew create mode 100644 prototype_projects/FuelTransport/gradlew.bat create mode 100644 prototype_projects/FuelTransport/settings.gradle create mode 100644 prototype_projects/FuelTransport/src/main/deploy/example.txt create mode 100644 prototype_projects/FuelTransport/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/FuelTransport/src/main/java/frc/robot/Mechanisms.java create mode 100644 prototype_projects/FuelTransport/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/FuelTransport/src/main/java/frc/robot/sim/PhysicsSim.java create mode 100644 prototype_projects/FuelTransport/src/main/java/frc/robot/sim/TalonFXSimProfile.java create mode 100644 prototype_projects/FuelTransport/vendordeps/Phoenix6-frc2026-latest.json create mode 100644 prototype_projects/FuelTransport/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/FuelTransport/.gitignore b/prototype_projects/FuelTransport/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/FuelTransport/.gitignore @@ -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 diff --git a/prototype_projects/FuelTransport/.vscode/launch.json b/prototype_projects/FuelTransport/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/FuelTransport/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/FuelTransport/.vscode/settings.json b/prototype_projects/FuelTransport/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/FuelTransport/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/FuelTransport/.wpilib/wpilib_preferences.json b/prototype_projects/FuelTransport/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..eadec71 --- /dev/null +++ b/prototype_projects/FuelTransport/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 7762 +} diff --git a/prototype_projects/FuelTransport/WPILib-License.md b/prototype_projects/FuelTransport/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/FuelTransport/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/FuelTransport/build.gradle b/prototype_projects/FuelTransport/build.gradle new file mode 100644 index 0000000..e9b0020 --- /dev/null +++ b/prototype_projects/FuelTransport/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ zQccdaaVK$5bz;*rnyK{_SQYM>;aES6Qs^lj9lEs6_J+%nIiuQC*fN;z8md>r_~Mfl zU%p5Dt_YT>gQqfr@`cR!$NWr~+`CZb%dn;WtzrAOI>P_JtsB76PYe*<%H(y>qx-`Kq!X_; z<{RpAqYhE=L1r*M)gNF3B8r(<%8mo*SR2hu zccLRZwGARt)Hlo1euqTyM>^!HK*!Q2P;4UYrysje@;(<|$&%vQekbn|0Ruu_Io(w4#%p6ld2Yp7tlA`Y$cciThP zKzNGIMPXX%&Ud0uQh!uQZz|FB`4KGD?3!ND?wQt6!n*f4EmCoJUh&b?;B{|lxs#F- z31~HQ`SF4x$&v00@(P+j1pAaj5!s`)b2RDBp*PB=2IB>oBF!*6vwr7Dp%zpAx*dPr zb@Zjq^XjN?O4QcZ*O+8>)|HlrR>oD*?WQl5ri3R#2?*W6iJ>>kH%KnnME&TT@ZzrHS$Q%LC?n|e>V+D+8D zYc4)QddFz7I8#}y#Wj6>4P%34dZH~OUDb?uP%-E zwjXM(?Sg~1!|wI(RVuxbu)-rH+O=igSho_pDCw(c6b=P zKk4ATlB?bj9+HHlh<_!&z0rx13K3ZrAR8W)!@Y}o`?a*JJsD+twZIv`W)@Y?Amu_u zz``@-e2X}27$i(2=9rvIu5uTUOVhzwu%mNazS|lZb&PT;XE2|B&W1>=B58#*!~D&) zfVmJGg8UdP*fx(>Cj^?yS^zH#o-$Q-*$SnK(ZVFkw+er=>N^7!)FtP3y~Xxnu^nzY zikgB>Nj0%;WOltWIob|}%lo?_C7<``a5hEkx&1ku$|)i>Rh6@3h*`slY=9U}(Ql_< zaNG*J8vb&@zpdhAvv`?{=zDedJ23TD&Zg__snRAH4eh~^oawdYi6A3w8<Ozh@Kw)#bdktM^GVb zrG08?0bG?|NG+w^&JvD*7LAbjED{_Zkc`3H!My>0u5Q}m!+6VokMLXxl`Mkd=g&Xx z-a>m*#G3SLlhbKB!)tnzfWOBV;u;ftU}S!NdD5+YtOjLg?X}dl>7m^gOpihrf1;PY zvll&>dIuUGs{Qnd- zwIR3oIrct8Va^Tm0t#(bJD7c$Z7DO9*7NnRZorrSm`b`cxz>OIC;jSE3DO8`hX955ui`s%||YQtt2 z5DNA&pG-V+4oI2s*x^>-$6J?p=I>C|9wZF8z;VjR??Icg?1w2v5Me+FgAeGGa8(3S z4vg*$>zC-WIVZtJ7}o9{D-7d>zCe|z#<9>CFve-OPAYsneTb^JH!Enaza#j}^mXy1 z+ULn^10+rWLF6j2>Ya@@Kq?26>AqK{A_| zQKb*~F1>sE*=d?A?W7N2j?L09_7n+HGi{VY;MoTGr_)G9)ot$p!-UY5zZ2Xtbm=t z@dpPSGwgH=QtIcEulQNI>S-#ifbnO5EWkI;$A|pxJd885oM+ zGZ0_0gDvG8q2xebj+fbCHYfAXuZStH2j~|d^sBAzo46(K8n59+T6rzBwK)^rfPT+B zyIFw)9YC-V^rhtK`!3jrhmW-sTmM+tPH+;nwjL#-SjQPUZ53L@A>y*rt(#M(qsiB2 zx6B)dI}6Wlsw%bJ8h|(lhkJVogQZA&n{?Vgs6gNSXzuZpEyu*xySy8ro07QZ7Vk1!3tJphN_5V7qOiyK8p z#@jcDD8nmtYi1^l8ml;AF<#IPK?!pqf9D4moYk>d99Im}Jtwj6c#+A;f)CQ*f-hZ< z=p_T86jog%!p)D&5g9taSwYi&eP z#JuEK%+NULWus;0w32-SYFku#i}d~+{Pkho&^{;RxzP&0!RCm3-9K6`>KZpnzS6?L z^H^V*s!8<>x8bomvD%rh>Zp3>Db%kyin;qtl+jAv8Oo~1g~mqGAC&Qi_wy|xEt2iz zWAJEfTV%cl2Cs<1L&DLRVVH05EDq`pH7Oh7sR`NNkL%wi}8n>IXcO40hp+J+sC!W?!krJf!GJNE8uj zg-y~Ns-<~D?yqbzVRB}G>0A^f0!^N7l=$m0OdZuqAOQqLc zX?AEGr1Ht+inZ-Qiwnl@Z0qukd__a!C*CKuGdy5#nD7VUBM^6OCpxCa2A(X;e0&V4 zM&WR8+wErQ7UIc6LY~Q9x%Sn*Tn>>P`^t&idaOEnOd(Ufw#>NoR^1QdhJ8s`h^|R_ zXX`c5*O~Xdvh%q;7L!_!ohf$NfEBmCde|#uVZvEo>OfEq%+Ns7&_f$OR9xsihRpBb z+cjk8LyDm@U{YN>+r46?nn{7Gh(;WhFw6GAxtcKD+YWV?uge>;+q#Xx4!GpRkVZYu zzsF}1)7$?%s9g9CH=Zs+B%M_)+~*j3L0&Q9u7!|+T`^O{xE6qvAP?XWv9_MrZKdo& z%IyU)$Q95AB4!#hT!_dA>4e@zjOBD*Y=XjtMm)V|+IXzjuM;(l+8aA5#Kaz_$rR6! zj>#&^DidYD$nUY(D$mH`9eb|dtV0b{S>H6FBfq>t5`;OxA4Nn{J(+XihF(stSche7$es&~N$epi&PDM_N`As;*9D^L==2Q7Z2zD+CiU(|+-kL*VG+&9!Yb3LgPy?A zm7Z&^qRG_JIxK7-FBzZI3Q<;{`DIxtc48k> zc|0dmX;Z=W$+)qE)~`yn6MdoJ4co;%!`ddy+FV538Y)j(vg}5*k(WK)KWZ3WaOG!8 z!syGn=s{H$odtpqFrT#JGM*utN7B((abXnpDM6w56nhw}OY}0TiTG1#f*VFZr+^-g zbP10`$LPq_;PvrA1XXlyx2uM^mrjTzX}w{yuLo-cOClE8MMk47T25G8M!9Z5ypOSV zAJUBGEg5L2fY)ZGJb^E34R2zJ?}Vf>{~gB!8=5Z) z9y$>5c)=;o0HeHHSuE4U)#vG&KF|I%-cF6f$~pdYJWk_dD}iOA>iA$O$+4%@>JU08 zS`ep)$XLPJ+n0_i@PkF#ri6T8?ZeAot$6JIYHm&P6EB=BiaNY|aA$W0I+nz*zkz_z zkEru!tj!QUffq%)8y0y`T&`fuus-1p>=^hnBiBqD^hXrPs`PY9tU3m0np~rISY09> z`P3s=-kt_cYcxWd{de@}TwSqg*xVhp;E9zCsnXo6z z?f&Sv^U7n4`xr=mXle94HzOdN!2kB~4=%)u&N!+2;z6UYKUDqi-s6AZ!haB;@&B`? z_TRX0%@suz^TRdCb?!vNJYPY8L_}&07uySH9%W^Tc&1pia6y1q#?*Drf}GjGbPjBS zbOPcUY#*$3sL2x4v_i*Y=N7E$mR}J%|GUI(>WEr+28+V z%v5{#e!UF*6~G&%;l*q*$V?&r$Pp^sE^i-0$+RH3ERUUdQ0>rAq2(2QAbG}$y{de( z>{qD~GGuOk559Y@%$?N^1ApVL_a704>8OD%8Y%8B;FCt%AoPu8*D1 zLB5X>b}Syz81pn;xnB}%0FnwazlWfUV)Z-~rZg6~b z6!9J$EcE&sEbzcy?CI~=boWA&eeIa%z(7SE^qgVLz??1Vbc1*aRvc%Mri)AJaAG!p z$X!_9Ds;Zz)f+;%s&dRcJt2==P{^j3bf0M=nJd&xwUGlUFn?H=2W(*2I2Gdu zv!gYCwM10aeus)`RIZSrCK=&oKaO_Ry~D1B5!y0R=%!i2*KfXGYX&gNv_u+n9wiR5 z*e$Zjju&ODRW3phN925%S(jL+bCHv6rZtc?!*`1TyYXT6%Ju=|X;6D@lq$8T zW{Y|e39ioPez(pBH%k)HzFITXHvnD6hw^lIoUMA;qAJ^CU?top1fo@s7xT13Fvn1H z6JWa-6+FJF#x>~+A;D~;VDs26>^oH0EI`IYT2iagy23?nyJ==i{g4%HrAf1-*v zK1)~@&(KkwR7TL}L(A@C_S0G;-GMDy=MJn2$FP5s<%wC)4jC5PXoxrQBFZ_k0P{{s@sz+gX`-!=T8rcB(=7vW}^K6oLWMmp(rwDh}b zwaGGd>yEy6fHv%jM$yJXo5oMAQ>c9j`**}F?MCry;T@47@r?&sKHgVe$MCqk#Z_3S z1GZI~nOEN*P~+UaFGnj{{Jo@16`(qVNtbU>O0Hf57-P>x8Jikp=`s8xWs^dAJ9lCQ z)GFm+=OV%AMVqVATtN@|vp61VVAHRn87}%PC^RAzJ%JngmZTasWBAWsoAqBU+8L8u z4A&Pe?fmTm0?mK-BL9t+{y7o(7jm+RpOhL9KnY#E&qu^}B6=K_dB}*VlSEiC9fn)+V=J;OnN)Ta5v66ic1rG+dGAJ1 z1%Zb_+!$=tQ~lxQrzv3x#CPb?CekEkA}0MYSgx$Jdd}q8+R=ma$|&1a#)TQ=l$1tQ z=tL9&_^vJ)Pk}EDO-va`UCT1m#Uty1{v^A3P~83_#v^ozH}6*9mIjIr;t3Uv%@VeW zGL6(CwCUp)Jq%G0bIG%?{_*Y#5IHf*5M@wPo6A{$Um++Co$wLC=J1aoG93&T7Ho}P z=mGEPP7GbvoG!uD$k(H3A$Z))+i{Hy?QHdk>3xSBXR0j!11O^mEe9RHmw!pvzv?Ua~2_l2Yh~_!s1qS`|0~0)YsbHSz8!mG)WiJE| z2f($6TQtt6L_f~ApQYQKSb=`053LgrQq7G@98#igV>y#i==-nEjQ!XNu9 z~;mE+gtj4IDDNQJ~JVk5Ux6&LCSFL!y=>79kE9=V}J7tD==Ga+IW zX)r7>VZ9dY=V&}DR))xUoV!u(Z|%3ciQi_2jl}3=$Agc(`RPb z8kEBpvY>1FGQ9W$n>Cq=DIpski};nE)`p3IUw1Oz0|wxll^)4dq3;CCY@RyJgFgc# zKouFh!`?Xuo{IMz^xi-h=StCis_M7yq$u) z?XHvw*HP0VgR+KR6wI)jEMX|ssqYvSf*_3W8zVTQzD?3>H!#>InzpSO)@SC8q*ii- z%%h}_#0{4JG;Jm`4zg};BPTGkYamx$Xo#O~lBirRY)q=5M45n{GCfV7h9qwyu1NxOMoP4)jjZMxmT|IQQh0U7C$EbnMN<3)Kk?fFHYq$d|ICu>KbY_hO zTZM+uKHe(cIZfEqyzyYSUBZa8;Fcut-GN!HSA9ius`ltNebF46ZX_BbZNU}}ZOm{M2&nANL9@0qvih15(|`S~z}m&h!u4x~(%MAO$jHRWNfuxWF#B)E&g3ghSQ9|> z(MFaLQj)NE0lowyjvg8z0#m6FIuKE9lDO~Glg}nSb7`~^&#(Lw{}GVOS>U)m8bF}x zVjbXljBm34Cs-yM6TVusr+3kYFjr28STT3g056y3cH5Tmge~ASxBj z%|yb>$eF;WgrcOZf569sDZOVwoo%8>XO>XQOX1OyN9I-SQgrm;U;+#3OI(zrWyow3 zk==|{lt2xrQ%FIXOTejR>;wv(Pb8u8}BUpx?yd(Abh6? zsoO3VYWkeLnF43&@*#MQ9-i-d0t*xN-UEyNKeyNMHw|A(k(_6QKO=nKMCxD(W(Yop zsRQ)QeL4X3Lxp^L%wzi2-WVSsf61dqliPUM7srDB?Wm6Lzn0&{*}|IsKQW;02(Y&| zaTKv|`U(pSzuvR6Rduu$wzK_W-Y-7>7s?G$)U}&uK;<>vU}^^ns@Z!p+9?St1s)dG zK%y6xkPyyS1$~&6v{kl?Md6gwM|>mt6Upm>oa8RLD^8T{0?HC!Z>;(Bob7el(DV6x zi`I)$&E&ngwFS@bi4^xFLAn`=fzTC;aimE^!cMI2n@Vo%Ae-ne`RF((&5y6xsjjAZ zVguVoQ?Z9uk$2ON;ersE%PU*xGO@T*;j1BO5#TuZKEf(mB7|g7pcEA=nYJ{s3vlbg zd4-DUlD{*6o%Gc^N!Nptgay>j6E5;3psI+C3Q!1ZIbeCubW%w4pq9)MSDyB{HLm|k zxv-{$$A*pS@csolri$Ge<4VZ}e~78JOL-EVyrbxKra^d{?|NnPp86!q>t<&IP07?Z z^>~IK^k#OEKgRH+LjllZXk7iA>2cfH6+(e&9ku5poo~6y{GC5>(bRK7hwjiurqAiZ zg*DmtgY}v83IjE&AbiWgMyFbaRUPZ{lYiz$U^&Zt2YjG<%m((&_JUbZcfJ22(>bi5 z!J?<7AySj0JZ&<-qXX;mcV!f~>G=sB0KnjWca4}vrtunD^1TrpfeS^4dvFr!65knK zZh`d;*VOkPs4*-9kL>$GP0`(M!j~B;#x?Ba~&s6CopvO86oM?-? zOw#dIRc;6A6T?B`Qp%^<U5 z19x(ywSH$_N+Io!6;e?`tWaM$`=Db!gzx|lQ${DG!zb1Zl&|{kX0y6xvO1o z220r<-oaS^^R2pEyY;=Qllqpmue|5yI~D|iI!IGt@iod{Opz@*ml^w2bNs)p`M(Io z|E;;m*Xpjd9l)4G#KaWfV(t8YUn@A;nK^#xgv=LtnArX|vWQVuw3}B${h+frU2>9^ z!l6)!Uo4`5k`<<;E(ido7M6lKTgWezNLq>U*=uz&s=cc$1%>VrAeOoUtA|T6gO4>UNqsdK=NF*8|~*sl&wI=x9-EGiq*aqV!(VVXA57 zw9*o6Ir8Lj1npUXvlevtn(_+^X5rzdR>#(}4YcB9O50q97%rW2me5_L=%ffYPUSRc z!vv?Kv>dH994Qi>U(a<0KF6NH5b16enCp+mw^Hb3Xs1^tThFpz!3QuN#}KBbww`(h z7GO)1olDqy6?T$()R7y%NYx*B0k_2IBiZ14&8|JPFxeMF{vW>HF-Vi3+ZOI=+qP}n zw(+!WcTd~4ZJX1!ZM&y!+uyt=&i!+~d(V%GjH;-NsEEv6nS1TERt|RHh!0>W4+4pp z1-*EzAM~i`+1f(VEHI8So`S`akPfPTfq*`l{Fz`hS%k#JS0cjT2mS0#QLGf=J?1`he3W*;m4)ce8*WFq1sdP=~$5RlH1EdWm|~dCvKOi4*I_96{^95p#B<(n!d?B z=o`0{t+&OMwKcxiBECznJcfH!fL(z3OvmxP#oWd48|mMjpE||zdiTBdWelj8&Qosv zZFp@&UgXuvJw5y=q6*28AtxZzo-UUpkRW%ne+Ylf!V-0+uQXBW=5S1o#6LXNtY5!I z%Rkz#(S8Pjz*P7bqB6L|M#Er{|QLae-Y{KA>`^} z@lPjeX>90X|34S-7}ZVXe{wEei1<{*e8T-Nbj8JmD4iwcE+Hg_zhkPVm#=@b$;)h6 z<<6y`nPa`f3I6`!28d@kdM{uJOgM%`EvlQ5B2bL)Sl=|y@YB3KeOzz=9cUW3clPAU z^sYc}xf9{4Oj?L5MOlYxR{+>w=vJjvbyO5}ptT(o6dR|ygO$)nVCvNGnq(6;bHlBd zl?w-|plD8spjDF03g5ip;W3Z z><0{BCq!Dw;h5~#1BuQilq*TwEu)qy50@+BE4bX28+7erX{BD4H)N+7U`AVEuREE8 z;X?~fyhF-x_sRfHIj~6f(+^@H)D=ngP;mwJjxhQUbUdzk8f94Ab%59-eRIq?ZKrwD z(BFI=)xrUlgu(b|hAysqK<}8bslmNNeD=#JW*}^~Nrswn^xw*nL@Tx!49bfJecV&KC2G4q5a!NSv)06A_5N3Y?veAz;Gv+@U3R% z)~UA8-0LvVE{}8LVDOHzp~2twReqf}ODIyXMM6=W>kL|OHcx9P%+aJGYi_Om)b!xe zF40Vntn0+VP>o<$AtP&JANjXBn7$}C@{+@3I@cqlwR2MdwGhVPxlTIcRVu@Ho-wO` z_~Or~IMG)A_`6-p)KPS@cT9mu9RGA>dVh5wY$NM9-^c@N=hcNaw4ITjm;iWSP^ZX| z)_XpaI61<+La+U&&%2a z0za$)-wZP@mwSELo#3!PGTt$uy0C(nTT@9NX*r3Ctw6J~7A(m#8fE)0RBd`TdKfAT zCf@$MAxjP`O(u9s@c0Fd@|}UQ6qp)O5Q5DPCeE6mSIh|Rj{$cAVIWsA=xPKVKxdhg zLzPZ`3CS+KIO;T}0Ip!fAUaNU>++ZJZRk@I(h<)RsJUhZ&Ru9*!4Ptn;gX^~4E8W^TSR&~3BAZc#HquXn)OW|TJ`CTahk+{qe`5+ixON^zA9IFd8)kc%*!AiLu z>`SFoZ5bW-%7}xZ>gpJcx_hpF$2l+533{gW{a7ce^B9sIdmLrI0)4yivZ^(Vh@-1q zFT!NQK$Iz^xu%|EOK=n>ug;(7J4OnS$;yWmq>A;hsD_0oAbLYhW^1Vdt9>;(JIYjf zdb+&f&D4@4AS?!*XpH>8egQvSVX`36jMd>$+RgI|pEg))^djhGSo&#lhS~9%NuWfX zDDH;3T*GzRT@5=7ibO>N-6_XPBYxno@mD_3I#rDD?iADxX`! zh*v8^i*JEMzyN#bGEBz7;UYXki*Xr(9xXax(_1qVW=Ml)kSuvK$coq2A(5ZGhs_pF z$*w}FbN6+QDseuB9=fdp_MTs)nQf!2SlROQ!gBJBCXD&@-VurqHj0wm@LWX-TDmS= z71M__vAok|@!qgi#H&H%Vg-((ZfxPAL8AI{x|VV!9)ZE}_l>iWk8UPTGHs*?u7RfP z5MC&=c6X;XlUzrz5q?(!eO@~* zoh2I*%J7dF!!_!vXoSIn5o|wj1#_>K*&CIn{qSaRc&iFVxt*^20ngCL;QonIS>I5^ zMw8HXm>W0PGd*}Ko)f|~dDd%;Wu_RWI_d;&2g6R3S63Uzjd7dn%Svu-OKpx*o|N>F zZg=-~qLb~VRLpv`k zWSdfHh@?dp=s_X`{yxOlxE$4iuyS;Z-x!*E6eqmEm*j2bE@=ZI0YZ5%Yj29!5+J$4h{s($nakA`xgbO8w zi=*r}PWz#lTL_DSAu1?f%-2OjD}NHXp4pXOsCW;DS@BC3h-q4_l`<))8WgzkdXg3! zs1WMt32kS2E#L0p_|x+x**TFV=gn`m9BWlzF{b%6j-odf4{7a4y4Uaef@YaeuPhU8 zHBvRqN^;$Jizy+ z=zW{E5<>2gp$pH{M@S*!sJVQU)b*J5*bX4h>5VJve#Q6ga}cQ&iL#=(u+KroWrxa%8&~p{WEUF0il=db;-$=A;&9M{Rq`ouZ5m%BHT6%st%saGsD6)fQgLN}x@d3q>FC;=f%O3Cyg=Ke@Gh`XW za@RajqOE9UB6eE=zhG%|dYS)IW)&y&Id2n7r)6p_)vlRP7NJL(x4UbhlcFXWT8?K=%s7;z?Vjts?y2+r|uk8Wt(DM*73^W%pAkZa1Jd zNoE)8FvQA>Z`eR5Z@Ig6kS5?0h;`Y&OL2D&xnnAUzQz{YSdh0k zB3exx%A2TyI)M*EM6htrxSlep!Kk(P(VP`$p0G~f$smld6W1r_Z+o?=IB@^weq>5VYsYZZR@` z&XJFxd5{|KPZmVOSxc@^%71C@;z}}WhbF9p!%yLj3j%YOlPL5s>7I3vj25 z@xmf=*z%Wb4;Va6SDk9cv|r*lhZ`(y_*M@>q;wrn)oQx%B(2A$9(74>;$zmQ!4fN; z>XurIk-7@wZys<+7XL@0Fhe-f%*=(weaQEdR9Eh6>Kl-EcI({qoZqyzziGwpg-GM#251sK_ z=3|kitS!j%;fpc@oWn65SEL73^N&t>Ix37xgs= zYG%eQDJc|rqHFia0!_sm7`@lvcv)gfy(+KXA@E{3t1DaZ$DijWAcA)E0@X?2ziJ{v z&KOYZ|DdkM{}t+@{@*6ge}m%xfjIxi%qh`=^2Rwz@w0cCvZ&Tc#UmCDbVwABrON^x zEBK43FO@weA8s7zggCOWhMvGGE`baZ62cC)VHyy!5Zbt%ieH+XN|OLbAFPZWyC6)p z4P3%8sq9HdS3=ih^0OOlqTPbKuzQ?lBEI{w^ReUO{V?@`ARsL|S*%yOS=Z%sF)>-y z(LAQdhgAcuF6LQjRYfdbD1g4o%tV4EiK&ElLB&^VZHbrV1K>tHTO{#XTo>)2UMm`2 z^t4s;vnMQgf-njU-RVBRw0P0-m#d-u`(kq7NL&2T)TjI_@iKuPAK-@oH(J8?%(e!0Ir$yG32@CGUPn5w4)+9@8c&pGx z+K3GKESI4*`tYlmMHt@br;jBWTei&(a=iYslc^c#RU3Q&sYp zSG){)V<(g7+8W!Wxeb5zJb4XE{I|&Y4UrFWr%LHkdQ;~XU zgy^dH-Z3lmY+0G~?DrC_S4@=>0oM8Isw%g(id10gWkoz2Q%7W$bFk@mIzTCcIB(K8 zc<5h&ZzCdT=9n-D>&a8vl+=ZF*`uTvQviG_bLde*k>{^)&0o*b05x$MO3gVLUx`xZ z43j+>!u?XV)Yp@MmG%Y`+COH2?nQcMrQ%k~6#O%PeD_WvFO~Kct za4XoCM_X!c5vhRkIdV=xUB3xI2NNStK*8_Zl!cFjOvp-AY=D;5{uXj}GV{LK1~IE2 z|KffUiBaStRr;10R~K2VVtf{TzM7FaPm;Y(zQjILn+tIPSrJh&EMf6evaBKIvi42-WYU9Vhj~3< zZSM-B;E`g_o8_XTM9IzEL=9Lb^SPhe(f(-`Yh=X6O7+6ALXnTcUFpI>ekl6v)ZQeNCg2 z^H|{SKXHU*%nBQ@I3It0m^h+6tvI@FS=MYS$ZpBaG7j#V@P2ZuYySbp@hA# ze(kc;P4i_-_UDP?%<6>%tTRih6VBgScKU^BV6Aoeg6Uh(W^#J^V$Xo^4#Ekp ztqQVK^g9gKMTHvV7nb64UU7p~!B?>Y0oFH5T7#BSW#YfSB@5PtE~#SCCg3p^o=NkMk$<8- z6PT*yIKGrvne7+y3}_!AC8NNeI?iTY(&nakN>>U-zT0wzZf-RuyZk^X9H-DT_*wk= z;&0}6LsGtfVa1q)CEUPlx#(ED@-?H<1_FrHU#z5^P3lEB|qsxEyn%FOpjx z3S?~gvoXy~L(Q{Jh6*i~=f%9kM1>RGjBzQh_SaIDfSU_9!<>*Pm>l)cJD@wlyxpBV z4Fmhc2q=R_wHCEK69<*wG%}mgD1=FHi4h!98B-*vMu4ZGW~%IrYSLGU{^TuseqVgV zLP<%wirIL`VLyJv9XG_p8w@Q4HzNt-o;U@Au{7%Ji;53!7V8Rv0^Lu^Vf*sL>R(;c zQG_ZuFl)Mh-xEIkGu}?_(HwkB2jS;HdPLSxVU&Jxy9*XRG~^HY(f0g8Q}iqnVmgjI zfd=``2&8GsycjR?M%(zMjn;tn9agcq;&rR!Hp z$B*gzHsQ~aXw8c|a(L^LW(|`yGc!qOnV(ZjU_Q-4z1&0;jG&vAKuNG=F|H?@m5^N@ zq{E!1n;)kNTJ>|Hb2ODt-7U~-MOIFo%9I)_@7fnX+eMMNh>)V$IXesJpBn|uo8f~#aOFytCT zf9&%MCLf8mp4kwHTcojWmM3LU=#|{3L>E}SKwOd?%{HogCZ_Z1BSA}P#O(%H$;z7XyJ^sjGX;j5 zrzp>|Ud;*&VAU3x#f{CKwY7Vc{%TKKqmB@oTHA9;>?!nvMA;8+Jh=cambHz#J18x~ zs!dF>$*AnsQ{{82r5Aw&^7eRCdvcgyxH?*DV5(I$qXh^zS>us*I66_MbL8y4d3ULj z{S(ipo+T3Ag!+5`NU2sc+@*m{_X|&p#O-SAqF&g_n7ObB82~$p%fXA5GLHMC+#qqL zdt`sJC&6C2)=juQ_!NeD>U8lDVpAOkW*khf7MCcs$A(wiIl#B9HM%~GtQ^}yBPjT@ z+E=|A!Z?A(rwzZ;T}o6pOVqHzTr*i;Wrc%&36kc@jXq~+w8kVrs;%=IFdACoLAcCAmhFNpbP8;s`zG|HC2Gv?I~w4ITy=g$`0qMQdkijLSOtX6xW%Z9Nw<;M- zMN`c7=$QxN00DiSjbVt9Mi6-pjv*j(_8PyV-il8Q-&TwBwH1gz1uoxs6~uU}PrgWB zIAE_I-a1EqlIaGQNbcp@iI8W1sm9fBBNOk(k&iLBe%MCo#?xI$%ZmGA?=)M9D=0t7 zc)Q0LnI)kCy{`jCGy9lYX%mUsDWwsY`;jE(;Us@gmWPqjmXL+Hu#^;k%eT>{nMtzj zsV`Iy6leTA8-PndszF;N^X@CJrTw5IIm!GPeu)H2#FQitR{1p;MasQVAG3*+=9FYK zw*k!HT(YQorfQj+1*mCV458(T5=fH`um$gS38hw(OqVMyunQ;rW5aPbF##A3fGH6h z@W)i9Uff?qz`YbK4c}JzQpuxuE3pcQO)%xBRZp{zJ^-*|oryTxJ-rR+MXJ)!f=+pp z10H|DdGd2exhi+hftcYbM0_}C0ZI-2vh+$fU1acsB-YXid7O|=9L!3e@$H*6?G*Zp z%qFB(sgl=FcC=E4CYGp4CN>=M8#5r!RU!u+FJVlH6=gI5xHVD&k;Ta*M28BsxfMV~ zLz+@6TxnfLhF@5=yQo^1&S}cmTN@m!7*c6z;}~*!hNBjuE>NLVl2EwN!F+)0$R1S! zR|lF%n!9fkZ@gPW|x|B={V6x3`=jS*$Pu0+5OWf?wnIy>Y1MbbGSncpKO0qE(qO=ts z!~@&!N`10S593pVQu4FzpOh!tvg}p%zCU(aV5=~K#bKi zHdJ1>tQSrhW%KOky;iW+O_n;`l9~omqM%sdxdLtI`TrJzN6BQz+7xOl*rM>xVI2~# z)7FJ^Dc{DC<%~VS?@WXzuOG$YPLC;>#vUJ^MmtbSL`_yXtNKa$Hk+l-c!aC7gn(Cg ze?YPYZ(2Jw{SF6MiO5(%_pTo7j@&DHNW`|lD`~{iH+_eSTS&OC*2WTT*a`?|9w1dh zh1nh@$a}T#WE5$7Od~NvSEU)T(W$p$s5fe^GpG+7fdJ9=enRT9$wEk+ZaB>G3$KQO zgq?-rZZnIv!p#>Ty~}c*Lb_jxJg$eGM*XwHUwuQ|o^}b3^T6Bxx{!?va8aC@-xK*H ztJBFvFfsSWu89%@b^l3-B~O!CXs)I6Y}y#0C0U0R0WG zybjroj$io0j}3%P7zADXOwHwafT#uu*zfM!oD$6aJx7+WL%t-@6^rD_a_M?S^>c;z zMK580bZXo1f*L$CuMeM4Mp!;P@}b~$cd(s5*q~FP+NHSq;nw3fbWyH)i2)-;gQl{S zZO!T}A}fC}vUdskGSq&{`oxt~0i?0xhr6I47_tBc`fqaSrMOzR4>0H^;A zF)hX1nfHs)%Zb-(YGX;=#2R6C{BG;k=?FfP?9{_uFLri~-~AJ;jw({4MU7e*d)?P@ zXX*GkNY9ItFjhwgAIWq7Y!ksbMzfqpG)IrqKx9q{zu%Mdl+{Dis#p9q`02pr1LG8R z@As?eG!>IoROgS!@J*to<27coFc1zpkh?w=)h9CbYe%^Q!Ui46Y*HO0mr% zEff-*$ndMNw}H2a5@BsGj5oFfd!T(F&0$<{GO!Qdd?McKkorh=5{EIjDTHU`So>8V zBA-fqVLb2;u7UhDV1xMI?y>fe3~4urv3%PX)lDw+HYa;HFkaLqi4c~VtCm&Ca+9C~ zge+67hp#R9`+Euq59WhHX&7~RlXn=--m8$iZ~~1C8cv^2(qO#X0?vl91gzUKBeR1J z^p4!!&7)3#@@X&2aF2-)1Ffcc^F8r|RtdL2X%HgN&XU-KH2SLCbpw?J5xJ*!F-ypZ zMG%AJ!Pr&}`LW?E!K~=(NJxuSVTRCGJ$2a*Ao=uUDSys!OFYu!Vs2IT;xQ6EubLIl z+?+nMGeQQhh~??0!s4iQ#gm3!BpMpnY?04kK375e((Uc7B3RMj;wE?BCoQGu=UlZt!EZ1Q*auI)dj3Jj{Ujgt zW5hd~-HWBLI_3HuO) zNrb^XzPsTIb=*a69wAAA3J6AAZZ1VsYbIG}a`=d6?PjM)3EPaDpW2YP$|GrBX{q*! z$KBHNif)OKMBCFP5>!1d=DK>8u+Upm-{hj5o|Wn$vh1&K!lVfDB&47lw$tJ?d5|=B z^(_9=(1T3Fte)z^>|3**n}mIX;mMN5v2F#l(q*CvU{Ga`@VMp#%rQkDBy7kYbmb-q z<5!4iuB#Q_lLZ8}h|hPODI^U6`gzLJre9u3k3c#%86IKI*^H-@I48Bi*@avYm4v!n0+v zWu{M{&F8#p9cx+gF0yTB_<2QUrjMPo9*7^-uP#~gGW~y3nfPAoV%amgr>PSyVAd@l)}8#X zR5zV6t*uKJZL}?NYvPVK6J0v4iVpwiN|>+t3aYiZSp;m0!(1`bHO}TEtWR1tY%BPB z(W!0DmXbZAsT$iC13p4f>u*ZAy@JoLAkJhzFf1#4;#1deO8#8d&89}en&z!W&A3++^1(;>0SB1*54d@y&9Pn;^IAf3GiXbfT`_>{R+Xv; zQvgL>+0#8-laO!j#-WB~(I>l0NCMt_;@Gp_f0#^c)t?&#Xh1-7RR0@zPyBz!U#0Av zT?}n({(p?p7!4S2ZBw)#KdCG)uPnZe+U|0{BW!m)9 zi_9$F?m<`2!`JNFv+w8MK_K)qJ^aO@7-Ig>cM4-r0bi=>?B_2mFNJ}aE3<+QCzRr*NA!QjHw# z`1OsvcoD0?%jq{*7b!l|L1+Tw0TTAM4XMq7*ntc-Ived>Sj_ZtS|uVdpfg1_I9knY z2{GM_j5sDC7(W&}#s{jqbybqJWyn?{PW*&cQIU|*v8YGOKKlGl@?c#TCnmnAkAzV- zmK={|1G90zz=YUvC}+fMqts0d4vgA%t6Jhjv?d;(Z}(Ep8fTZfHA9``fdUHkA+z3+ zhh{ohP%Bj?T~{i0sYCQ}uC#5BwN`skI7`|c%kqkyWIQ;!ysvA8H`b-t()n6>GJj6xlYDu~8qX{AFo$Cm3d|XFL=4uvc?Keb zzb0ZmMoXca6Mob>JqkNuoP>B2Z>D`Q(TvrG6m`j}-1rGP!g|qoL=$FVQYxJQjFn33lODt3Wb1j8VR zlR++vIT6^DtYxAv_hxupbLLN3e0%A%a+hWTKDV3!Fjr^cWJ{scsAdfhpI)`Bms^M6 zQG$waKgFr=c|p9Piug=fcJvZ1ThMnNhQvBAg-8~b1?6wL*WyqXhtj^g(Ke}mEfZVM zJuLNTUVh#WsE*a6uqiz`b#9ZYg3+2%=C(6AvZGc=u&<6??!slB1a9K)=VL zY9EL^mfyKnD zSJyYBc_>G;5RRnrNgzJz#Rkn3S1`mZgO`(r5;Hw6MveN(URf_XS-r58Cn80K)ArH4 z#Rrd~LG1W&@ttw85cjp8xV&>$b%nSXH_*W}7Ch2pg$$c0BdEo-HWRTZcxngIBJad> z;C>b{jIXjb_9Jis?NZJsdm^EG}e*pR&DAy0EaSGi3XWTa(>C%tz1n$u?5Fb z1qtl?;_yjYo)(gB^iQq?=jusF%kywm?CJP~zEHi0NbZ);$(H$w(Hy@{i>$wcVRD_X|w-~(0Z9BJyh zhNh;+eQ9BEIs;tPz%jSVnfCP!3L&9YtEP;svoj_bNzeGSQIAjd zBss@A;)R^WAu-37RQrM%{DfBNRx>v!G31Z}8-El9IOJlb_MSoMu2}GDYycNaf>uny z+8xykD-7ONCM!APry_Lw6-yT>5!tR}W;W`C)1>pxSs5o1z#j7%m=&=7O4hz+Lsqm` z*>{+xsabZPr&X=}G@obTb{nPTkccJX8w3CG7X+1+t{JcMabv~UNv+G?txRqXib~c^Mo}`q{$`;EBNJ;#F*{gvS12kV?AZ%O0SFB$^ zn+}!HbmEj}w{Vq(G)OGAzH}R~kS^;(-s&=ectz8vN!_)Yl$$U@HNTI-pV`LSj7Opu zTZ5zZ)-S_{GcEQPIQXLQ#oMS`HPu{`SQiAZ)m1at*Hy%3xma|>o`h%E%8BEbi9p0r zVjcsh<{NBKQ4eKlXU|}@XJ#@uQw*$4BxKn6#W~I4T<^f99~(=}a`&3(ur8R9t+|AQ zWkQx7l}wa48-jO@ft2h+7qn%SJtL%~890FG0s5g*kNbL3I&@brh&f6)TlM`K^(bhr zJWM6N6x3flOw$@|C@kPi7yP&SP?bzP-E|HSXQXG>7gk|R9BTj`e=4de9C6+H7H7n# z#GJeVs1mtHhLDmVO?LkYRQc`DVOJ_vdl8VUihO-j#t=0T3%Fc1f9F73ufJz*adn*p zc%&vi(4NqHu^R>sAT_0EDjVR8bc%wTz#$;%NU-kbDyL_dg0%TFafZwZ?5KZpcuaO54Z9hX zD$u>q!-9`U6-D`E#`W~fIfiIF5_m6{fvM)b1NG3xf4Auw;Go~Fu7cth#DlUn{@~yu z=B;RT*dp?bO}o%4x7k9v{r=Y@^YQ^UUm(Qmliw8brO^=NP+UOohLYiaEB3^DB56&V zK?4jV61B|1Uj_5fBKW;8LdwOFZKWp)g{B%7g1~DgO&N& z#lisxf?R~Z@?3E$Mms$$JK8oe@X`5m98V*aV6Ua}8Xs2#A!{x?IP|N(%nxsH?^c{& z@vY&R1QmQs83BW28qAmJfS7MYi=h(YK??@EhjL-t*5W!p z^gYX!Q6-vBqcv~ruw@oMaU&qp0Fb(dbVzm5xJN%0o_^@fWq$oa3X?9s%+b)x4w-q5Koe(@j6Ez7V@~NRFvd zfBH~)U5!ix3isg`6be__wBJp=1@yfsCMw1C@y+9WYD9_C%{Q~7^0AF2KFryfLlUP# zwrtJEcH)jm48!6tUcxiurAMaiD04C&tPe6DI0#aoqz#Bt0_7_*X*TsF7u*zv(iEfA z;$@?XVu~oX#1YXtceQL{dSneL&*nDug^OW$DSLF0M1Im|sSX8R26&)<0Fbh^*l6!5wfSu8MpMoh=2l z^^0Sr$UpZp*9oqa23fcCfm7`ya2<4wzJ`Axt7e4jJrRFVf?nY~2&tRL* zd;6_njcz01c>$IvN=?K}9ie%Z(BO@JG2J}fT#BJQ+f5LFSgup7i!xWRKw6)iITjZU z%l6hPZia>R!`aZjwCp}I zg)%20;}f+&@t;(%5;RHL>K_&7MH^S+7<|(SZH!u zznW|jz$uA`P9@ZWtJgv$EFp>)K&Gt+4C6#*khZQXS*S~6N%JDT$r`aJDs9|uXWdbg zBwho$phWx}x!qy8&}6y5Vr$G{yGSE*r$^r{}pw zVTZKvikRZ`J_IJrjc=X1uw?estdwm&bEahku&D04HD+0Bm~q#YGS6gp!KLf$A{%Qd z&&yX@Hp>~(wU{|(#U&Bf92+1i&Q*-S+=y=3pSZy$#8Uc$#7oiJUuO{cE6=tsPhwPe| zxQpK>`Dbka`V)$}e6_OXKLB%i76~4N*zA?X+PrhH<&)}prET;kel24kW%+9))G^JI zsq7L{P}^#QsZViX%KgxBvEugr>ZmFqe^oAg?{EI=&_O#e)F3V#rc z8$4}0Zr19qd3tE4#$3_f=Bbx9oV6VO!d3(R===i-7p=Vj`520w0D3W6lQfY48}!D* z&)lZMG;~er2qBoI2gsX+Ts-hnpS~NYRDtPd^FPzn!^&yxRy#CSz(b&E*tL|jIkq|l zf%>)7Dtu>jCf`-7R#*GhGn4FkYf;B$+9IxmqH|lf6$4irg{0ept__%)V*R_OK=T06 zyT_m-o@Kp6U{l5h>W1hGq*X#8*y@<;vsOFqEjTQXFEotR+{3}ODDnj;o0@!bB5x=N z394FojuGOtVKBlVRLtHp%EJv_G5q=AgF)SKyRN5=cGBjDWv4LDn$IL`*=~J7u&Dy5 zrMc83y+w^F&{?X(KOOAl-sWZDb{9X9#jrQtmrEXD?;h-}SYT7yM(X_6qksM=K_a;Z z3u0qT0TtaNvDER_8x*rxXw&C^|h{P1qxK|@pS7vdlZ#P z7PdB7MmC2}%sdzAxt>;WM1s0??`1983O4nFK|hVAbHcZ3x{PzytQLkCVk7hA!Lo` zEJH?4qw|}WH{dc4z%aB=0XqsFW?^p=X}4xnCJXK%c#ItOSjdSO`UXJyuc8bh^Cf}8 z@Ht|vXd^6{Fgai8*tmyRGmD_s_nv~r^Fy7j`Bu`6=G)5H$i7Q7lvQnmea&TGvJp9a|qOrUymZ$6G|Ly z#zOCg++$3iB$!6!>215A4!iryregKuUT344X)jQb3|9qY>c0LO{6Vby05n~VFzd?q zgGZv&FGlkiH*`fTurp>B8v&nSxNz)=5IF$=@rgND4d`!AaaX;_lK~)-U8la_Wa8i?NJC@BURO*sUW)E9oyv3RG^YGfN%BmxzjlT)bp*$<| zX3tt?EAy<&K+bhIuMs-g#=d1}N_?isY)6Ay$mDOKRh z4v1asEGWoAp=srraLW^h&_Uw|6O+r;wns=uwYm=JN4Q!quD8SQRSeEcGh|Eb5Jg8m zOT}u;N|x@aq)=&;wufCc^#)5U^VcZw;d_wwaoh9$p@Xrc{DD6GZUqZ ziC6OT^zSq@-lhbgR8B+e;7_Giv;DK5gn^$bs<6~SUadiosfewWDJu`XsBfOd1|p=q zE>m=zF}!lObA%ePey~gqU8S6h-^J2Y?>7)L2+%8kV}Gp=h`Xm_}rlm)SyUS=`=S7msKu zC|T!gPiI1rWGb1z$Md?0YJQ;%>uPLOXf1Z>N~`~JHJ!^@D5kSXQ4ugnFZ>^`zH8CAiZmp z6Ms|#2gcGsQ{{u7+Nb9sA?U>(0e$5V1|WVwY`Kn)rsnnZ4=1u=7u!4WexZD^IQ1Jk zfF#NLe>W$3m&C^ULjdw+5|)-BSHwpegdyt9NYC{3@QtMfd8GrIWDu`gd0nv-3LpGCh@wgBaG z176tikL!_NXM+Bv#7q^cyn9$XSeZR6#!B4JE@GVH zoobHZN_*RF#@_SVYKkQ_igme-Y5U}cV(hkR#k1c{bQNMji zU7aE`?dHyx=1`kOYZo_8U7?3-7vHOp`Qe%Z*i+FX!s?6huNp0iCEW-Z7E&jRWmUW_ z67j>)Ew!yq)hhG4o?^z}HWH-e=es#xJUhDRc4B51M4~E-l5VZ!&zQq`gWe`?}#b~7w1LH4Xa-UCT5LXkXQWheBa2YJYbyQ zl1pXR%b(KCXMO0OsXgl0P0Og<{(@&z1aokU-Pq`eQq*JYgt8xdFQ6S z6Z3IFSua8W&M#`~*L#r>Jfd6*BzJ?JFdBR#bDv$_0N!_5vnmo@!>vULcDm`MFU823 zpG9pqjqz^FE5zMDoGqhs5OMmC{Y3iVcl>F}5Rs24Y5B^mYQ;1T&ks@pIApHOdrzXF z-SdX}Hf{X;TaSxG_T$0~#RhqKISGKNK47}0*x&nRIPtmdwxc&QT3$8&!3fWu1eZ_P zJveQj^hJL#Sn!*4k`3}(d(aasl&7G0j0-*_2xtAnoX1@9+h zO#c>YQg60Z;o{Bi=3i7S`Ic+ZE>K{(u|#)9y}q*j8uKQ1^>+(BI}m%1v3$=4ojGBc zm+o1*!T&b}-lVvZqIUBc8V}QyFEgm#oyIuC{8WqUNV{Toz`oxhYpP!_p2oHHh5P@iB*NVo~2=GQm+8Yrkm2Xjc_VyHg1c0>+o~@>*Qzo zHVBJS>$$}$_4EniTI;b1WShX<5-p#TPB&!;lP!lBVBbLOOxh6FuYloD%m;n{r|;MU3!q4AVkua~fieeWu2 zQAQ$ue(IklX6+V;F1vCu-&V?I3d42FgWgsb_e^29ol}HYft?{SLf>DrmOp9o!t>I^ zY7fBCk+E8n_|apgM|-;^=#B?6RnFKlN`oR)`e$+;D=yO-(U^jV;rft^G_zl`n7qnM zL z*-Y4Phq+ZI1$j$F-f;`CD#|`-T~OM5Q>x}a>B~Gb3-+9i>Lfr|Ca6S^8g*{*?_5!x zH_N!SoRP=gX1?)q%>QTY!r77e2j9W(I!uAz{T`NdNmPBBUzi2{`XMB^zJGGwFWeA9 z{fk33#*9SO0)DjROug+(M)I-pKA!CX;IY(#gE!UxXVsa)X!UftIN98{pt#4MJHOhY zM$_l}-TJlxY?LS6Nuz1T<44m<4i^8k@D$zuCPrkmz@sdv+{ciyFJG2Zwy&%c7;atIeTdh!a(R^QXnu1Oq1b42*OQFWnyQ zWeQrdvP|w_idy53Wa<{QH^lFmEd+VlJkyiC>6B#s)F;w-{c;aKIm;Kp50HnA-o3lY z9B~F$gJ@yYE#g#X&3ADx&tO+P_@mnQTz9gv30_sTsaGXkfNYXY{$(>*PEN3QL>I!k zp)KibPhrfX3%Z$H6SY`rXGYS~143wZrG2;=FLj50+VM6soI~up_>fU(2Wl@{BRsMi zO%sL3x?2l1cXTF)k&moNsHfQrQ+wu(gBt{sk#CU=UhrvJIncy@tJX5klLjgMn>~h= zg|FR&;@eh|C7`>s_9c~0-{IAPV){l|Ts`i=)AW;d9&KPc3fMeoTS%8@V~D8*h;&(^>yjT84MM}=%#LS7shLAuuj(0VAYoozhWjq z4LEr?wUe2^WGwdTIgWBkDUJa>YP@5d9^Rs$kCXmMRxuF*YMVrn?0NFyPl}>`&dqZb z<5eqR=ZG3>n2{6v6BvJ`YBZeeTtB88TAY(x0a58EWyuf>+^|x8Qa6wA|1Nb_p|nA zWWa}|z8a)--Wj`LqyFk_a3gN2>5{Rl_wbW?#by7&i*^hRknK%jwIH6=dQ8*-_{*x0j^DUfMX0`|K@6C<|1cgZ~D(e5vBFFm;HTZF(!vT8=T$K+|F)x3kqzBV4-=p1V(lzi(s7jdu0>LD#N=$Lk#3HkG!a zIF<7>%B7sRNzJ66KrFV76J<2bdYhxll0y2^_rdG=I%AgW4~)1Nvz=$1UkE^J%BxLo z+lUci`UcU062os*=`-j4IfSQA{w@y|3}Vk?i;&SSdh8n+$iHA#%ERL{;EpXl6u&8@ zzg}?hkEOUOJt?ZL=pWZFJ19mI1@P=$U5*Im1e_8Z${JsM>Ov?nh8Z zP5QvI!{Jy@&BP48%P2{Jr_VgzW;P@7)M9n|lDT|Ep#}7C$&ud&6>C^5ZiwKIg2McPU(4jhM!BD@@L(Gd*Nu$ji(ljZ<{FIeW_1Mmf;76{LU z-ywN~=uNN)Xi6$<12A9y)K%X|(W0p|&>>4OXB?IiYr||WKDOJPxiSe01NSV-h24^L z_>m$;|C+q!Mj**-qQ$L-*++en(g|hw;M!^%_h-iDjFHLo-n3JpB;p?+o2;`*jpvJU zLY^lt)Un4joij^^)O(CKs@7E%*!w>!HA4Q?0}oBJ7Nr8NQ7QmY^4~jvf0-`%waOLn zdNjAPaC0_7c|RVhw)+71NWjRi!y>C+Bl;Z`NiL^zn2*0kmj5gyhCLCxts*cWCdRI| zjsd=sT5BVJc^$GxP~YF$-U{-?kW6r@^vHXB%{CqYzU@1>dzf#3SYedJG-Rm6^RB7s zGM5PR(yKPKR)>?~vpUIeTP7A1sc8-knnJk*9)3t^e%izbdm>Y=W{$wm(cy1RB-19i za#828DMBY+ps#7Y8^6t)=Ea@%Nkt)O6JCx|ybC;Ap}Z@Zw~*}3P>MZLPb4Enxz9Wf zssobT^(R@KuShj8>@!1M7tm|2%-pYYDxz-5`rCbaTCG5{;Uxm z*g=+H1X8{NUvFGzz~wXa%Eo};I;~`37*WrRU&K0dPSB$yk(Z*@K&+mFal^?c zurbqB-+|Kb5|sznT;?Pj!+kgFY1#Dr;_%A(GIQC{3ct|{*Bji%FNa6c-thbpBkA;U zURV!Dr&X{0J}iht#-Qp2=xzuh(fM>zRoiGrYl5ttw2#r34gC41CCOC31m~^UPTK@s z6;A@)7O7_%C)>bnAXerYuAHdE93>j2N}H${zEc6&SbZ|-fiG*-qtGuy-qDelH(|u$ zorf8_T6Zqe#Ub!+e3oSyrskt_HyW_^5lrWt#30l)tHk|j$@YyEkXUOV;6B51L;M@=NIWZXU;GrAa(LGxO%|im%7F<-6N;en0Cr zLH>l*y?pMwt`1*cH~LdBPFY_l;~`N!Clyfr;7w<^X;&(ZiVdF1S5e(+Q%60zgh)s4 zn2yj$+mE=miVERP(g8}G4<85^-5f@qxh2ec?n+$A_`?qN=iyT1?U@t?V6DM~BIlBB z>u~eXm-aE>R0sQy!-I4xtCNi!!qh?R1!kKf6BoH2GG{L4%PAz0{Sh6xpuyI%*~u)s z%rLuFl)uQUCBQAtMyN;%)zFMx4loh7uTfKeB2Xif`lN?2gq6NhWhfz0u5WP9J>=V2 zo{mLtSy&BA!mSzs&CrKWq^y40JF5a&GSXIi2= z{EYb59J4}VwikL4P=>+mc6{($FNE@e=VUwG+KV21;<@lrN`mnz5jYGASyvz7BOG_6(p^eTxD-4O#lROgon;R35=|nj#eHIfJBYPWG>H>`dHKCDZ3`R{-?HO0mE~(5_WYcFmp8sU?wr*UkAQiNDGc6T zA%}GOLXlOWqL?WwfHO8MB#8M8*~Y*gz;1rWWoVSXP&IbKxbQ8+s%4Jnt?kDsq7btI zCDr0PZ)b;B%!lu&CT#RJzm{l{2fq|BcY85`w~3LSK<><@(2EdzFLt9Y_`;WXL6x`0 zDoQ?=?I@Hbr;*VVll1Gmd8*%tiXggMK81a+T(5Gx6;eNb8=uYn z5BG-0g>pP21NPn>$ntBh>`*})Fl|38oC^9Qz>~MAazH%3Q~Qb!ALMf$srexgPZ2@&c~+hxRi1;}+)-06)!#Mq<6GhP z-Q?qmgo${aFBApb5p}$1OJKTClfi8%PpnczyVKkoHw7Ml9e7ikrF0d~UB}i3vizos zXW4DN$SiEV9{faLt5bHy2a>33K%7Td-n5C*N;f&ZqAg#2hIqEb(y<&f4u5BWJ>2^4 z414GosL=Aom#m&=x_v<0-fp1r%oVJ{T-(xnomNJ(Dryv zh?vj+%=II_nV+@NR+(!fZZVM&(W6{6%9cm+o+Z6}KqzLw{(>E86uA1`_K$HqINlb1 zKelh3-jr2I9V?ych`{hta9wQ2c9=MM`2cC{m6^MhlL2{DLv7C^j z$xXBCnDl_;l|bPGMX@*tV)B!c|4oZyftUlP*?$YU9C_eAsuVHJ58?)zpbr30P*C`T z7y#ao`uE-SOG(Pi+`$=e^mle~)pRrdwL5)N;o{gpW21of(QE#U6w%*C~`v-z0QqBML!!5EeYA5IQB0 z^l01c;L6E(iytN!LhL}wfwP7W9PNAkb+)Cst?qg#$n;z41O4&v+8-zPs+XNb-q zIeeBCh#ivnFLUCwfS;p{LC0O7tm+Sf9Jn)~b%uwP{%69;QC)Ok0t%*a5M+=;y8j=v z#!*pp$9@!x;UMIs4~hP#pnfVc!%-D<+wsG@R2+J&%73lK|2G!EQC)O05TCV=&3g)C!lT=czLpZ@Sa%TYuoE?v8T8`V;e$#Zf2_Nj6nvBgh1)2 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/FuelTransport/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/FuelTransport/gradlew b/prototype_projects/FuelTransport/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/FuelTransport/gradlew @@ -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" "$@" diff --git a/prototype_projects/FuelTransport/gradlew.bat b/prototype_projects/FuelTransport/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/FuelTransport/gradlew.bat @@ -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 diff --git a/prototype_projects/FuelTransport/settings.gradle b/prototype_projects/FuelTransport/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/FuelTransport/settings.gradle @@ -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"); diff --git a/prototype_projects/FuelTransport/src/main/deploy/example.txt b/prototype_projects/FuelTransport/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/FuelTransport/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/FuelTransport/src/main/java/frc/robot/Main.java b/prototype_projects/FuelTransport/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/FuelTransport/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/FuelTransport/src/main/java/frc/robot/Mechanisms.java b/prototype_projects/FuelTransport/src/main/java/frc/robot/Mechanisms.java new file mode 100644 index 0000000..572e396 --- /dev/null +++ b/prototype_projects/FuelTransport/src/main/java/frc/robot/Mechanisms.java @@ -0,0 +1,58 @@ +package frc.robot; + +import static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.StatusSignal; + +import edu.wpi.first.units.measure.Angle; +import edu.wpi.first.units.measure.AngularVelocity; +import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d; +import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj.util.Color; +import edu.wpi.first.wpilibj.util.Color8Bit; + +/** + * Class to keep all the mechanism-specific objects together and out of the main example + */ +public class Mechanisms { + double HEIGHT = 1; // Controls the height of the mech2d SmartDashboard + double WIDTH = 1; // Controls the height of the mech2d SmartDashboard + + Mechanism2d mech = new Mechanism2d(WIDTH, HEIGHT); + // Velocity + MechanismLigament2d VelocityMech = mech. + getRoot("velocityLineReferencePosition", 0.75, 0.5). + append(new MechanismLigament2d("velocityLine", 1,90, 6, new Color8Bit(Color.kAliceBlue))); + + MechanismLigament2d midline = mech. + getRoot("midline", 0.7, 0.5). + append(new MechanismLigament2d("midline", 0.1, 0, 3, new Color8Bit(Color.kCyan))); + + //Position + MechanismLigament2d arm = mech. + getRoot("pivotPoint", 0.25, 0.5). + append(new MechanismLigament2d("arm", .2, 0, 0, new Color8Bit(Color.kAliceBlue))); + + MechanismLigament2d side1 = arm.append(new MechanismLigament2d("side1", 0.15307, 112.5, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side2 = side1.append(new MechanismLigament2d("side2", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side3 = side2.append(new MechanismLigament2d("side3", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side4 = side3.append(new MechanismLigament2d("side4", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side5 = side4.append(new MechanismLigament2d("side5", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side6 = side5.append(new MechanismLigament2d("side6", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side7 = side6.append(new MechanismLigament2d("side7", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side8 = side7.append(new MechanismLigament2d("side8", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + + /** + * Runs the mech2d widget in GUI. + * + * This utilizes GUI to simulate and display a TalonFX and exists to allow users to test and understand + * features of our products in simulation using our examples out of the box. Users may modify to have a + * display interface that they find more intuitive or visually appealing. + */ + public void update(StatusSignal position, StatusSignal velocity) { + VelocityMech.setLength(velocity.getValue().in(RotationsPerSecond)/120); + arm.setAngle(position.getValue().in(Rotations) * 360); // Divide by 120 to scale motion to fit in the window + SmartDashboard.putData("mech2d", mech); // Creates mech2d in SmartDashboard + } +} diff --git a/prototype_projects/FuelTransport/src/main/java/frc/robot/Robot.java b/prototype_projects/FuelTransport/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..f36d3ca --- /dev/null +++ b/prototype_projects/FuelTransport/src/main/java/frc/robot/Robot.java @@ -0,0 +1,100 @@ +// 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 static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.StatusCode; +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.VelocityVoltage; +import com.ctre.phoenix6.hardware.TalonFX; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.XboxController; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; + +/** + * The VM is configured to automatically run this class, and to call the functions corresponding to + * each mode, as described in the TimedRobot documentation. If you change the name of this class or + * the package after creating this project, you must also update the build.gradle file in the + * project. + */ +public class Robot extends TimedRobot { + private final TalonFX m_fx = new TalonFX(30); + + /* Be able to switch which control request to use based on a button press */ + /* Start at velocity 0, use slot 0 */ + private final VelocityVoltage m_velocityVoltage = new VelocityVoltage(0).withSlot(0); + private final XboxController m_joystick = new XboxController(0); + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + public Robot() { + TalonFXConfiguration configs = new TalonFXConfiguration(); + + /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ + configs.Slot0.kS = 0.1; // To account for friction, add 0.1 V of static feedforward + configs.Slot0.kV = 0.12; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second + configs.Slot0.kP = 0.11; // An error of 1 rotation per second results in 0.11 V output + configs.Slot0.kI = 0; // No output for integrated error + configs.Slot0.kD = 0; // No output for error derivative + // Peak output of 8 volts + configs.Voltage.withPeakForwardVoltage(Volts.of(8)) + .withPeakReverseVoltage(Volts.of(-8)); + + /* Retry config apply up to 5 times, report if failure */ + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = m_fx.getConfigurator().apply(configs); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs, error code: " + status.toString()); + } + + SmartDashboard.putNumber("desired RPS", 0); + SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); + } + + @Override + public void robotPeriodic() { + } + + @Override + public void autonomousInit() {} + + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() {} + + @Override + public void teleopPeriodic() { + double joyValue = m_joystick.getLeftY(); + if (Math.abs(joyValue) < 0.1) joyValue = 0; + + double desiredRotationsPerSecond = joyValue * 125; // Go for plus/minus 50 rotations per second + + /* Use velocity voltage */ + m_fx.setControl(m_velocityVoltage.withVelocity(desiredRotationsPerSecond)); + + SmartDashboard.putNumber("desired RPS", desiredRotationsPerSecond); + SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); + } + + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + @Override + public void testInit() {} + + @Override + public void testPeriodic() {} +} diff --git a/prototype_projects/FuelTransport/src/main/java/frc/robot/sim/PhysicsSim.java b/prototype_projects/FuelTransport/src/main/java/frc/robot/sim/PhysicsSim.java new file mode 100644 index 0000000..6000bca --- /dev/null +++ b/prototype_projects/FuelTransport/src/main/java/frc/robot/sim/PhysicsSim.java @@ -0,0 +1,81 @@ +package frc.robot.sim; + +import java.util.ArrayList; + +import com.ctre.phoenix6.Utils; +import com.ctre.phoenix6.hardware.TalonFX; + +/** + * Manages physics simulation for CTRE products. + */ +public class PhysicsSim { + private static final PhysicsSim sim = new PhysicsSim(); + + /** + * Gets the robot simulator instance. + */ + public static PhysicsSim getInstance() { + return sim; + } + + /** + * Adds a TalonFX controller to the simulator. + * + * @param talonFX + * The TalonFX device + * @param rotorInertia + * Rotational Inertia of the mechanism at the rotor + */ + public void addTalonFX(TalonFX talonFX, final double rotorInertia) { + if (talonFX != null) { + TalonFXSimProfile simTalonFX = new TalonFXSimProfile(talonFX, rotorInertia); + _simProfiles.add(simTalonFX); + } + } + + /** + * Runs the simulator: + * - enable the robot + * - simulate sensors + */ + public void run() { + // Simulate devices + for (SimProfile simProfile : _simProfiles) { + simProfile.run(); + } + } + + private final ArrayList _simProfiles = new ArrayList(); + + /** + * Holds information about a simulated device. + */ + static class SimProfile { + private double _lastTime; + private boolean _running = false; + + /** + * Runs the simulation profile. + * Implemented by device-specific profiles. + */ + public void run() { + } + + /** + * Returns the time since last call, in seconds. + */ + protected double getPeriod() { + // set the start time if not yet running + if (!_running) { + _lastTime = Utils.getCurrentTimeSeconds(); + _running = true; + } + + double now = Utils.getCurrentTimeSeconds(); + final double period = now - _lastTime; + _lastTime = now; + + return period; + } + } +} \ No newline at end of file diff --git a/prototype_projects/FuelTransport/src/main/java/frc/robot/sim/TalonFXSimProfile.java b/prototype_projects/FuelTransport/src/main/java/frc/robot/sim/TalonFXSimProfile.java new file mode 100644 index 0000000..0dc9756 --- /dev/null +++ b/prototype_projects/FuelTransport/src/main/java/frc/robot/sim/TalonFXSimProfile.java @@ -0,0 +1,57 @@ +package frc.robot.sim; + +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.sim.TalonFXSimState; + +import edu.wpi.first.math.system.plant.DCMotor; +import edu.wpi.first.math.system.plant.LinearSystemId; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import frc.robot.sim.PhysicsSim.SimProfile; + +/** + * Holds information about a simulated TalonFX. + */ +class TalonFXSimProfile extends SimProfile { + private static final double kMotorResistance = 0.002; // Assume 2mOhm resistance for voltage drop calculation + private final TalonFXSimState _talonFXSim; + private final DCMotorSim _motorSim; + + /** + * Creates a new simulation profile for a TalonFX device. + * + * @param talonFX + * The TalonFX device + * @param rotorInertia + * Rotational Inertia of the mechanism at the rotor + */ + public TalonFXSimProfile(final TalonFX talonFX, final double rotorInertia) { + var gearbox = DCMotor.getKrakenX60Foc(1); + this._motorSim = new DCMotorSim(LinearSystemId.createDCMotorSystem(gearbox, rotorInertia, 1.0), gearbox); + this._talonFXSim = talonFX.getSimState(); + } + + /** + * Runs the simulation profile. + * + * This uses very rudimentary physics simulation and exists to allow users to + * test features of our products in simulation using our examples out of the + * box. Users may modify this to utilize more accurate physics simulation. + */ + public void run() { + /// DEVICE SPEED SIMULATION + + _motorSim.setInputVoltage(_talonFXSim.getMotorVoltage()); + + _motorSim.update(getPeriod()); + + /// SET SIM PHYSICS INPUTS + final double position_rot = _motorSim.getAngularPositionRotations(); + final double velocity_rps = Units.radiansToRotations(_motorSim.getAngularVelocityRadPerSec()); + + _talonFXSim.setRawRotorPosition(position_rot); + _talonFXSim.setRotorVelocity(velocity_rps); + + _talonFXSim.setSupplyVoltage(12 - _talonFXSim.getSupplyCurrent() * kMotorResistance); + } +} \ No newline at end of file diff --git a/prototype_projects/FuelTransport/vendordeps/Phoenix6-frc2026-latest.json b/prototype_projects/FuelTransport/vendordeps/Phoenix6-frc2026-latest.json new file mode 100644 index 0000000..8f6e30f --- /dev/null +++ b/prototype_projects/FuelTransport/vendordeps/Phoenix6-frc2026-latest.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-frc2026-latest.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/FuelTransport/vendordeps/WPILibNewCommands.json b/prototype_projects/FuelTransport/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/FuelTransport/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} From 0e82e97b9826c0a498a078f956d569c3ecd46e1a Mon Sep 17 00:00:00 2001 From: Jeffrey E Erickson <16201464+jee7s@users.noreply.github.com> Date: Wed, 21 Jan 2026 22:32:45 -0600 Subject: [PATCH 021/161] implement github ci (#8) * implement github ci * Add setup java step * update branches ci.yml applies to * update docs --- .github/workflows/ci.yml | 43 ++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++-- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..239c54f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,43 @@ +# This YML defines the basic build CI job. For syntax, see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions +# This workflow file is based on this WPILib Reference with modifications: https://docs.wpilib.org/en/stable/docs/software/advanced-gradlerio/robot-code-ci.html +name: robot_ci + +# This action runs on all pull requests into the branches indicated below and when the result of the pull request is merged. +on: + pull_request: + branches: + - main + - development + push: + branches: + - main + - development + +# The concurrency setting prevents multiple runs of this workflow on the same ref/hash +concurrency: ${{ github.workflow }}-${{ github.ref }} + +defaults: + run: + working-directory: ./2026-Rebuilt + +# We define one job called 'ci' which runs the gradle build. A separate ruleset in the repository will make this a commit gate for main by requiring the job to pass +# In the job, we tell the orchestrator to run on a github provided ubuntu 22.04 instance and to use the WPILib provided docker container +# Using that docker container makes the build look like a developer machine install with WPILib available +# The job then runs gradlew build +# If the project structure significantly changes (e.g. gradlew moves) then the path below for both the chmod and the gradlew invocation need to match the change. +jobs: + ci: + runs-on: ubuntu-22.04 + container: + image: docker://wpilib/roborio-cross-ubuntu:2026-22.04-py314 + steps: + - name: Git Checkout + uses: actions/checkout@v6 + - uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 17 + - name: Gradle Build + run: | + chmod +x gradlew + ./gradlew build \ No newline at end of file diff --git a/README.md b/README.md index 5e15129..6327070 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,10 @@ This top-level directory contains prototype, example and experiment projects dev This repository uses a modified feature branch workflow. Where all big features are done on short-lived feature branches, and then merged into a development branch for final bug testing before being put through pull request (PR) into main. Although, if the change is quick enough to do in one setting and meets the commit requirements (talked about later) for the development branch the change can be committed directly to it. ### Main: -The most stable copy of the current year's competition code. Code cannot be directly committed to this branch and instead it is required to use a PR. Before a PR is merged into main, a full test of the robot is required to make sure every feature works. +The most stable copy of the current year's competition code. Code cannot be directly committed to this branch and instead it is required to use a PR. Before a PR is merged into main, a full test of the robot is required to make sure every feature works. Automation runs the build on PRs to main and build failures block the ability to merge. After a merge, the build also runs on main. ### Development: -This branch houses all of the in-development features that aren't stable enough for main. Although, we should try our best to make sure that the current year's code in the development branch always works via quick testing on a mule or similar to make sure that any changes do not outright “brick” the robot. Pull requests are not required, but if you think a change should have a discussion feel free to make one. +This branch houses all of the in-development features that aren't stable enough for main. Although, we should try our best to make sure that the current year's code in the development branch always works via quick testing on a mule or similar to make sure that any changes do not outright “brick” the robot. Pull requests are not required, but if you think a change should have a discussion feel free to make one. During a PR to development, a build is run by automation but a build failure is not blocking. Pushes to development also trigger builds. ### Feature Branches: Feature branches are short-lived branches to work on specific features, they should be named with this format: “YEAR-FEATURE_SHORTHAND”. An example is “2026-ground_pickup” which would be a feature branch for a ground pickup for the 2026 competition. These branches have no commit requirements and are not required to run or build. This is so we can upload our changes to the github at the end of sessions without losing it due to the chance of using a different computer. After a feature is completed, make sure to merge development into your branch and make sure that the robot still mostly works via a quick test. Once that is completed you can merge your branch into development and delete the feature branch. From f68449162c9b18d7f69b86faa0b2953e64361f65 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 11:51:27 -0600 Subject: [PATCH 022/161] Added a chooser list for drive commands (untested) --- .../frc/robot/subsystems/DriveSubsystem.java | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index dfb2aec..ef59aac 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -26,12 +26,15 @@ import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds; import edu.wpi.first.util.sendable.SendableRegistry; import edu.wpi.first.wpilibj.DriverStation; +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.SubsystemBase; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.Constants.AutoConstants; import frc.robot.Constants.DrivetrainConstants; import frc.robot.commands.ArcadeDriveCommand; +import frc.robot.commands.ArcadeDriveCommandNoPID; import frc.robot.commands.DifferentialDriveCommand; public class DriveSubsystem extends SubsystemBase { @@ -49,6 +52,8 @@ public class DriveSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; private final AHRS m_gyro; + private final SendableChooser> m_driveChooser = new SendableChooser<>(); + /** Creates a new DriveSubsystem. */ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, AHRS gyro, TalonFX rightMotor, TalonFX leftMotor) { m_poseEstimator = poseEstimator; @@ -94,6 +99,12 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential // Gyro setup m_gyro.zeroYaw(); + // Drive Chooser Init + m_driveChooser.setDefaultOption("PID Arcade", ArcadeDriveCommand.class); + m_driveChooser.addOption("PID Differential", DifferentialDriveCommand.class); + m_driveChooser.addOption("NO-PID Arcade", ArcadeDriveCommandNoPID.class); + SmartDashboard.putData("Drive Commands", m_driveChooser); + // Init Smartdashboard SmartDashboard.putNumber("DB Left Set (MPS)", 0); SmartDashboard.putNumber("DB Right Set (MPS)", 0); @@ -103,7 +114,6 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential SmartDashboard.putNumber("Right Speed (MPS)", getMotorSpeedMPS(false)); SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); - SmartDashboard.putBoolean("PID Arcade", true); } private void setConfig(TalonFX motor, InvertedValue Inverted) { @@ -154,16 +164,26 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { ); } - // TODO: Make a list chooser. + // This takes the current class selected in the drive chooser and attempts to + // initilize a command object from it & run it. TODO: Test this! public void initDefaultCommand(CommandXboxController Controller) { - boolean useArcade = SmartDashboard.getBoolean("PID Arcade", true); - - if (useArcade == true) { - setDefaultCommand(new ArcadeDriveCommand(this, Controller)); - } else { - setDefaultCommand(new DifferentialDriveCommand(this, Controller)); + Class driveClass = m_driveChooser.getSelected(); + + try { + Object driveCommand = driveClass.getDeclaredConstructor().newInstance(this, Controller); + setDefaultCommand((Command) driveCommand); + + System.out.println(String.format("Loaded drive command \"%s\"!", driveClass.getName())); + } catch (Exception e) { + DriverStation.reportWarning( + String.format( + "Failed to load drive command \"%s\"!", driveClass.getName()), + false + ); } + + // setDefaultCommand(new ArcadeDriveCommand(this, Controller)); } // TODO: Work on a naming scheme for conversion functions From 7e22f0a5caa9f0e4dafea13213da659a89c48461 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:41:28 -0600 Subject: [PATCH 023/161] Tested and Debuged the new drivetrain chooser. --- .../shuffleboard.json | 62 +++++++++---------- .../frc/robot/subsystems/DriveSubsystem.java | 6 +- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 82f14e4..98ba112 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -164,19 +164,6 @@ "vgap": 16.0, "titleType": 0, "tiles": { - "3,1": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_title": "/SmartDashboard/Left Target (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, "3,2": { "size": [ 1, @@ -203,19 +190,6 @@ "_showGlyph": false } }, - "4,1": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Target (MPS)", - "_title": "/SmartDashboard/Right Target (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, "3,0": { "size": [ 2, @@ -236,9 +210,9 @@ ], "content": { "_type": "Graph", - "_source0": "network_table:///SmartDashboard/Left Distance (m)", - "_source1": "network_table:///SmartDashboard/Left Target (MPS)", - "_source2": "network_table:///SmartDashboard/Left Speed (MPS)", + "_source0": "network_table:///SmartDashboard/Left Target (MPS)", + "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", + "_source2": "network_table:///SmartDashboard/Left Distance (m)", "_title": "Graph", "_glyph": 148, "_showGlyph": false, @@ -278,15 +252,41 @@ "_glyph": 148, "_showGlyph": false } + }, + "3,1": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Left Target (MPS)", + "_title": "/SmartDashboard/Left Target (MPS)", + "_glyph": 148, + "_showGlyph": false + } + }, + "4,1": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Right Target (MPS)", + "_title": "/SmartDashboard/Right Target (MPS)", + "_glyph": 148, + "_showGlyph": false + } } } } } ], "windowGeometry": { - "x": -5.0, + "x": -7.0, "y": 1.0, - "width": 1939.0, + "width": 1934.0, "height": 844.0 } } \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index ef59aac..e257170 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -165,13 +165,13 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { } // This takes the current class selected in the drive chooser and attempts to - // initilize a command object from it & run it. TODO: Test this! + // initilize a command object from it & run it. public void initDefaultCommand(CommandXboxController Controller) { Class driveClass = m_driveChooser.getSelected(); try { - Object driveCommand = driveClass.getDeclaredConstructor().newInstance(this, Controller); + Object driveCommand = driveClass.getDeclaredConstructor(DriveSubsystem.class, CommandXboxController.class).newInstance(this, Controller); setDefaultCommand((Command) driveCommand); System.out.println(String.format("Loaded drive command \"%s\"!", driveClass.getName())); @@ -181,6 +181,8 @@ public void initDefaultCommand(CommandXboxController Controller) "Failed to load drive command \"%s\"!", driveClass.getName()), false ); + + e.printStackTrace(); } // setDefaultCommand(new ArcadeDriveCommand(this, Controller)); From c792505e4840ebeb00e67fa6055f0166c673fb7a Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 18:51:12 -0600 Subject: [PATCH 024/161] Fixed the improper reset of position in resetPose --- .../src/main/java/frc/robot/subsystems/DriveSubsystem.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index e257170..eaebfda 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -232,7 +232,12 @@ public Pose2d getPose(){ public void resetPose(Pose2d newPose){ m_leftMotor.setPosition(0); m_rightMotor.setPosition(0); - m_poseEstimator.resetPose(newPose); + + m_poseEstimator.resetPosition( + m_gyro.getRotation2d(), + 0, 0, + newPose + ); } public double getMotorSpeedRPS(boolean bLeft) From cf804c6288bf9d91ff620a6b4a35649ad1900d1f Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 19:25:00 -0600 Subject: [PATCH 025/161] Initial Fuel Intake --- .../fuelintake/Fuel Intake/.gitignore | 187 ++++++++ .../Fuel Intake/.vscode/launch.json | 21 + .../Fuel Intake/.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 6 + .../fuelintake/Fuel Intake/WPILib-License.md | 24 + .../fuelintake/Fuel Intake/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../fuelintake/Fuel Intake/gradlew | 252 ++++++++++ .../fuelintake/Fuel Intake/gradlew.bat | 94 ++++ .../fuelintake/Fuel Intake/settings.gradle | 30 ++ .../Fuel Intake/src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Constants.java | 19 + .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 108 +++++ .../main/java/frc/robot/RobotContainer.java | 63 +++ .../main/java/frc/robot/commands/Autos.java | 20 + .../frc/robot/commands/ExampleCommand.java | 43 ++ .../robot/subsystems/ExampleSubsystem.java | 47 ++ .../vendordeps/Phoenix6-26.1.0.json | 449 ++++++++++++++++++ .../Fuel Intake/vendordeps/REVLib.json | 133 ++++++ .../vendordeps/WPILibNewCommands.json | 39 ++ prototype_projects/fuleintake/.gitignore | 187 ++++++++ .../fuleintake/.vscode/launch.json | 21 + .../fuleintake/.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 6 + .../fuleintake/WPILib-License.md | 24 + prototype_projects/fuleintake/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + prototype_projects/fuleintake/gradlew | 252 ++++++++++ prototype_projects/fuleintake/gradlew.bat | 94 ++++ prototype_projects/fuleintake/settings.gradle | 30 ++ .../fuleintake/src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 57 +++ .../vendordeps/WPILibNewCommands.json | 39 ++ 37 files changed, 2651 insertions(+) create mode 100644 prototype_projects/fuelintake/Fuel Intake/.gitignore create mode 100644 prototype_projects/fuelintake/Fuel Intake/.vscode/launch.json create mode 100644 prototype_projects/fuelintake/Fuel Intake/.vscode/settings.json create mode 100644 prototype_projects/fuelintake/Fuel Intake/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/fuelintake/Fuel Intake/WPILib-License.md create mode 100644 prototype_projects/fuelintake/Fuel Intake/build.gradle create mode 100644 prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/fuelintake/Fuel Intake/gradlew create mode 100644 prototype_projects/fuelintake/Fuel Intake/gradlew.bat create mode 100644 prototype_projects/fuelintake/Fuel Intake/settings.gradle create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/deploy/example.txt create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Constants.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/RobotContainer.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/Autos.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/ExampleCommand.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/subsystems/ExampleSubsystem.java create mode 100644 prototype_projects/fuelintake/Fuel Intake/vendordeps/Phoenix6-26.1.0.json create mode 100644 prototype_projects/fuelintake/Fuel Intake/vendordeps/REVLib.json create mode 100644 prototype_projects/fuelintake/Fuel Intake/vendordeps/WPILibNewCommands.json create mode 100644 prototype_projects/fuleintake/.gitignore create mode 100644 prototype_projects/fuleintake/.vscode/launch.json create mode 100644 prototype_projects/fuleintake/.vscode/settings.json create mode 100644 prototype_projects/fuleintake/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/fuleintake/WPILib-License.md create mode 100644 prototype_projects/fuleintake/build.gradle create mode 100644 prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/fuleintake/gradlew create mode 100644 prototype_projects/fuleintake/gradlew.bat create mode 100644 prototype_projects/fuleintake/settings.gradle create mode 100644 prototype_projects/fuleintake/src/main/deploy/example.txt create mode 100644 prototype_projects/fuleintake/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/fuleintake/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/fuleintake/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/fuelintake/Fuel Intake/.gitignore b/prototype_projects/fuelintake/Fuel Intake/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/.gitignore @@ -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 diff --git a/prototype_projects/fuelintake/Fuel Intake/.vscode/launch.json b/prototype_projects/fuelintake/Fuel Intake/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/fuelintake/Fuel Intake/.vscode/settings.json b/prototype_projects/fuelintake/Fuel Intake/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/fuelintake/Fuel Intake/.wpilib/wpilib_preferences.json b/prototype_projects/fuelintake/Fuel Intake/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..994eeed --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/prototype_projects/fuelintake/Fuel Intake/WPILib-License.md b/prototype_projects/fuelintake/Fuel Intake/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/fuelintake/Fuel Intake/build.gradle b/prototype_projects/fuelintake/Fuel Intake/build.gradle new file mode 100644 index 0000000..f2ceadb --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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 = false + +// 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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/fuelintake/Fuel Intake/gradlew b/prototype_projects/fuelintake/Fuel Intake/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/gradlew @@ -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" "$@" diff --git a/prototype_projects/fuelintake/Fuel Intake/gradlew.bat b/prototype_projects/fuelintake/Fuel Intake/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/gradlew.bat @@ -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 diff --git a/prototype_projects/fuelintake/Fuel Intake/settings.gradle b/prototype_projects/fuelintake/Fuel Intake/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/settings.gradle @@ -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"); diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/deploy/example.txt b/prototype_projects/fuelintake/Fuel Intake/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Constants.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..c50ba05 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Constants.java @@ -0,0 +1,19 @@ +// 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; + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + public static class OperatorConstants { + public static final int kDriverControllerPort = 0; + } +} diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Main.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..0e6dd14 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java @@ -0,0 +1,108 @@ +// 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 java.security.KeyStore.PrivateKeyEntry; + +import com.ctre.phoenix6.hardware.TalonFX; + +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; + +/** + * The methods in this class are called automatically corresponding to each mode, as described in + * the TimedRobot documentation. If you change the name of this class or the package after creating + * this project, you must also update the Main.java file in the project. + */ +public class Robot extends TimedRobot { + private Command m_autonomousCommand; + + private final RobotContainer m_robotContainer; + + private final TalonFX intakeMotor = new TalonFX(10); + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + public Robot() { + // Instantiate our RobotContainer. This will perform all our button bindings, and put our + // autonomous chooser on the dashboard. + m_robotContainer = new RobotContainer(); + } + + /** + * This function is called every 20 ms, no matter the mode. Use this for items like diagnostics + * that you want ran during disabled, autonomous, teleoperated and test. + * + *

This runs after the mode specific periodic functions, but before LiveWindow and + * SmartDashboard integrated updating. + */ + @Override + public void robotPeriodic() { + // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled + // commands, running already-scheduled commands, removing finished or interrupted commands, + // and running subsystem periodic() methods. This must be called from the robot's periodic + // block in order for anything in the Command-based framework to work. + CommandScheduler.getInstance().run(); + intakeMotor.set(.5); + } + + /** This function is called once each time the robot enters Disabled mode. */ + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ + @Override + public void autonomousInit() { + m_autonomousCommand = m_robotContainer.getAutonomousCommand(); + + // schedule the autonomous command (example) + if (m_autonomousCommand != null) { + CommandScheduler.getInstance().schedule(m_autonomousCommand); + } + } + + /** This function is called periodically during autonomous. */ + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() { + // This makes sure that the autonomous stops running when + // teleop starts running. If you want the autonomous to + // continue until interrupted by another command, remove + // this line or comment it out. + if (m_autonomousCommand != null) { + m_autonomousCommand.cancel(); + } + } + + /** This function is called periodically during operator control. */ + @Override + public void teleopPeriodic() {} + + @Override + public void testInit() { + // Cancels all running commands at the start of test mode. + CommandScheduler.getInstance().cancelAll(); + } + + /** This function is called periodically during test mode. */ + @Override + public void testPeriodic() {} + + /** This function is called once when the robot is first started up. */ + @Override + public void simulationInit() {} + + /** This function is called periodically whilst in simulation. */ + @Override + public void simulationPeriodic() {} +} diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/RobotContainer.java new file mode 100644 index 0000000..a33249e --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/RobotContainer.java @@ -0,0 +1,63 @@ +// 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 frc.robot.Constants.OperatorConstants; +import frc.robot.commands.Autos; +import frc.robot.commands.ExampleCommand; +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import edu.wpi.first.wpilibj2.command.button.Trigger; + +/** + * This class is where the bulk of the robot should be declared. Since Command-based is a + * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot} + * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including + * subsystems, commands, and trigger mappings) should be declared here. + */ +public class RobotContainer { + // The robot's subsystems and commands are defined here... + private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem(); + + // Replace with CommandPS4Controller or CommandJoystick if needed + private final CommandXboxController m_driverController = + new CommandXboxController(OperatorConstants.kDriverControllerPort); + + /** The container for the robot. Contains subsystems, OI devices, and commands. */ + public RobotContainer() { + // Configure the trigger bindings + configureBindings(); + } + + /** + * Use this method to define your trigger->command mappings. Triggers can be created via the + * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary + * predicate, or via the named factories in {@link + * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link + * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller + * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight + * joysticks}. + */ + private void configureBindings() { + // Schedule `ExampleCommand` when `exampleCondition` changes to `true` + new Trigger(m_exampleSubsystem::exampleCondition) + .onTrue(new ExampleCommand(m_exampleSubsystem)); + + // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed, + // cancelling on release. + m_driverController.b().whileTrue(m_exampleSubsystem.exampleMethodCommand()); + } + + /** + * Use this to pass the autonomous command to the main {@link Robot} class. + * + * @return the command to run in autonomous + */ + public Command getAutonomousCommand() { + // An example command will be run in autonomous + return Autos.exampleAuto(m_exampleSubsystem); + } +} diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/Autos.java new file mode 100644 index 0000000..107aad7 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/Autos.java @@ -0,0 +1,20 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.Commands; + +public final class Autos { + /** Example static factory for an autonomous command. */ + public static Command exampleAuto(ExampleSubsystem subsystem) { + return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); + } + + private Autos() { + throw new UnsupportedOperationException("This is a utility class!"); + } +} diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/ExampleCommand.java new file mode 100644 index 0000000..3c5b9b4 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/commands/ExampleCommand.java @@ -0,0 +1,43 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; + +/** An example command that uses an example subsystem. */ +public class ExampleCommand extends Command { + @SuppressWarnings("PMD.UnusedPrivateField") + private final ExampleSubsystem m_subsystem; + + /** + * Creates a new ExampleCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ExampleCommand(ExampleSubsystem subsystem) { + m_subsystem = subsystem; + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/subsystems/ExampleSubsystem.java new file mode 100644 index 0000000..6b375da --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/subsystems/ExampleSubsystem.java @@ -0,0 +1,47 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class ExampleSubsystem extends SubsystemBase { + /** Creates a new ExampleSubsystem. */ + public ExampleSubsystem() {} + + /** + * Example command factory method. + * + * @return a command + */ + public Command exampleMethodCommand() { + // Inline construction of command goes here. + // Subsystem::RunOnce implicitly requires `this` subsystem. + return runOnce( + () -> { + /* one-time action goes here */ + }); + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/fuelintake/Fuel Intake/vendordeps/Phoenix6-26.1.0.json b/prototype_projects/fuelintake/Fuel Intake/vendordeps/Phoenix6-26.1.0.json new file mode 100644 index 0000000..dc5dc62 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/vendordeps/Phoenix6-26.1.0.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-26.1.0.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/fuelintake/Fuel Intake/vendordeps/REVLib.json b/prototype_projects/fuelintake/Fuel Intake/vendordeps/REVLib.json new file mode 100644 index 0000000..d35e593 --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/vendordeps/REVLib.json @@ -0,0 +1,133 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2026.0.1", + "frcYear": "2026", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2026.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2026.0.1" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2026.0.1", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.1", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.1", + "libName": "BackendDriver", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.1", + "libName": "REVLibWpi", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/fuelintake/Fuel Intake/vendordeps/WPILibNewCommands.json b/prototype_projects/fuelintake/Fuel Intake/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/fuelintake/Fuel Intake/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} diff --git a/prototype_projects/fuleintake/.gitignore b/prototype_projects/fuleintake/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/fuleintake/.gitignore @@ -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 diff --git a/prototype_projects/fuleintake/.vscode/launch.json b/prototype_projects/fuleintake/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/fuleintake/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/fuleintake/.vscode/settings.json b/prototype_projects/fuleintake/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/fuleintake/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/fuleintake/.wpilib/wpilib_preferences.json b/prototype_projects/fuleintake/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..994eeed --- /dev/null +++ b/prototype_projects/fuleintake/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/prototype_projects/fuleintake/WPILib-License.md b/prototype_projects/fuleintake/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/fuleintake/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/fuleintake/build.gradle b/prototype_projects/fuleintake/build.gradle new file mode 100644 index 0000000..f2ceadb --- /dev/null +++ b/prototype_projects/fuleintake/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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 = false + +// 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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/fuleintake/gradlew b/prototype_projects/fuleintake/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/fuleintake/gradlew @@ -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" "$@" diff --git a/prototype_projects/fuleintake/gradlew.bat b/prototype_projects/fuleintake/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/fuleintake/gradlew.bat @@ -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 diff --git a/prototype_projects/fuleintake/settings.gradle b/prototype_projects/fuleintake/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/fuleintake/settings.gradle @@ -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"); diff --git a/prototype_projects/fuleintake/src/main/deploy/example.txt b/prototype_projects/fuleintake/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/fuleintake/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/fuleintake/src/main/java/frc/robot/Main.java b/prototype_projects/fuleintake/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/fuleintake/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/fuleintake/src/main/java/frc/robot/Robot.java b/prototype_projects/fuleintake/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..5c7b2cf --- /dev/null +++ b/prototype_projects/fuleintake/src/main/java/frc/robot/Robot.java @@ -0,0 +1,57 @@ +// 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.Encoder; +import edu.wpi.first.wpilibj.Joystick; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; + +/** + * This sample program shows how to control a motor using a joystick. In the operator control part + * of the program, the joystick is read and the value is written to the motor. + * + *

Joystick analog values range from -1 to 1 and motor controller inputs also range from -1 to 1 + * making it easy to work together. + * + *

In addition, the encoder value of an encoder connected to ports 0 and 1 is consistently sent + * to the Dashboard. + */ +public class Robot extends TimedRobot { + private static final int kMotorPort = 0; + private static final int kJoystickPort = 0; + private static final int kEncoderPortA = 0; + private static final int kEncoderPortB = 1; + + private final PWMSparkMax m_motor; + private final Joystick m_joystick; + private final Encoder m_encoder; + + /** Called once at the beginning of the robot program. */ + public Robot() { + m_motor = new PWMSparkMax(kMotorPort); + m_joystick = new Joystick(kJoystickPort); + m_encoder = new Encoder(kEncoderPortA, kEncoderPortB); + // Use SetDistancePerPulse to set the multiplier for GetDistance + // This is set up assuming a 6 inch wheel with a 360 CPR encoder. + m_encoder.setDistancePerPulse((Math.PI * 6) / 360.0); + } + + /* + * The RobotPeriodic function is called every control packet no matter the + * robot mode. + */ + @Override + public void robotPeriodic() { + SmartDashboard.putNumber("Encoder", m_encoder.getDistance()); + } + + /** The teleop periodic function is called every control packet in teleop. */ + @Override + public void teleopPeriodic() { + m_motor.set(m_joystick.getY()); + } +} diff --git a/prototype_projects/fuleintake/vendordeps/WPILibNewCommands.json b/prototype_projects/fuleintake/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/fuleintake/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} From 26bfd0d02069a0f6db4936c70898524e36d337f5 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 19:37:30 -0600 Subject: [PATCH 026/161] Add initial Launcher Code --- .../Launcher v1/Launcher v1/.gitignore | 187 ++++++++ .../Launcher v1/.vscode/launch.json | 21 + .../Launcher v1/.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 6 + .../Launcher v1/Launcher v1/WPILib-License.md | 24 + .../Launcher v1/Launcher v1/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + .../Launcher v1/Launcher v1/gradlew | 252 ++++++++++ .../Launcher v1/Launcher v1/gradlew.bat | 94 ++++ .../Launcher v1/Launcher v1/settings.gradle | 30 ++ .../Launcher v1/src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Constants.java | 19 + .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 110 +++++ .../main/java/frc/robot/RobotContainer.java | 63 +++ .../main/java/frc/robot/commands/Autos.java | 20 + .../frc/robot/commands/ExampleCommand.java | 43 ++ .../robot/subsystems/ExampleSubsystem.java | 47 ++ .../vendordeps/Phoenix6-26.1.0.json | 449 ++++++++++++++++++ .../Launcher v1/vendordeps/REVLib.json | 133 ++++++ .../vendordeps/WPILibNewCommands.json | 39 ++ 22 files changed, 1740 insertions(+) create mode 100644 prototype_projects/Launcher v1/Launcher v1/.gitignore create mode 100644 prototype_projects/Launcher v1/Launcher v1/.vscode/launch.json create mode 100644 prototype_projects/Launcher v1/Launcher v1/.vscode/settings.json create mode 100644 prototype_projects/Launcher v1/Launcher v1/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/Launcher v1/Launcher v1/WPILib-License.md create mode 100644 prototype_projects/Launcher v1/Launcher v1/build.gradle create mode 100644 prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/Launcher v1/Launcher v1/gradlew create mode 100644 prototype_projects/Launcher v1/Launcher v1/gradlew.bat create mode 100644 prototype_projects/Launcher v1/Launcher v1/settings.gradle create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/deploy/example.txt create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Constants.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/RobotContainer.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/Autos.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/ExampleCommand.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java create mode 100644 prototype_projects/Launcher v1/Launcher v1/vendordeps/Phoenix6-26.1.0.json create mode 100644 prototype_projects/Launcher v1/Launcher v1/vendordeps/REVLib.json create mode 100644 prototype_projects/Launcher v1/Launcher v1/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/Launcher v1/Launcher v1/.gitignore b/prototype_projects/Launcher v1/Launcher v1/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/.gitignore @@ -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 diff --git a/prototype_projects/Launcher v1/Launcher v1/.vscode/launch.json b/prototype_projects/Launcher v1/Launcher v1/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/Launcher v1/Launcher v1/.vscode/settings.json b/prototype_projects/Launcher v1/Launcher v1/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/Launcher v1/Launcher v1/.wpilib/wpilib_preferences.json b/prototype_projects/Launcher v1/Launcher v1/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..994eeed --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 9577 +} \ No newline at end of file diff --git a/prototype_projects/Launcher v1/Launcher v1/WPILib-License.md b/prototype_projects/Launcher v1/Launcher v1/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/Launcher v1/Launcher v1/build.gradle b/prototype_projects/Launcher v1/Launcher v1/build.gradle new file mode 100644 index 0000000..f2ceadb --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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 = false + +// 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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/Launcher v1/Launcher v1/gradlew b/prototype_projects/Launcher v1/Launcher v1/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/gradlew @@ -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" "$@" diff --git a/prototype_projects/Launcher v1/Launcher v1/gradlew.bat b/prototype_projects/Launcher v1/Launcher v1/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/gradlew.bat @@ -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 diff --git a/prototype_projects/Launcher v1/Launcher v1/settings.gradle b/prototype_projects/Launcher v1/Launcher v1/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/settings.gradle @@ -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"); diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/deploy/example.txt b/prototype_projects/Launcher v1/Launcher v1/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Constants.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..c50ba05 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Constants.java @@ -0,0 +1,19 @@ +// 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; + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + public static class OperatorConstants { + public static final int kDriverControllerPort = 0; + } +} diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Main.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Robot.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..98f39b7 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Robot.java @@ -0,0 +1,110 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import com.revrobotics.spark.SparkMax; +import com.revrobotics.spark.SparkLowLevel.MotorType; + +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.motorcontrol.Spark; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; + +/** + * The methods in this class are called automatically corresponding to each mode, as described in + * the TimedRobot documentation. If you change the name of this class or the package after creating + * this project, you must also update the Main.java file in the project. + */ +public class Robot extends TimedRobot { + private Command m_autonomousCommand; + + private final RobotContainer m_robotContainer; + private final SparkMax motor = new SparkMax(50, MotorType.kBrushless ); + + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + public Robot() { + // Instantiate our RobotContainer. This will perform all our button bindings, and put our + // autonomous chooser on the dashboard. + m_robotContainer = new RobotContainer(); + + } + + /** + * This function is called every 20 ms, no matter the mode. Use this for items like diagnostics + * that you want ran during disabled, autonomous, teleoperated and test. + * + *

This runs after the mode specific periodic functions, but before LiveWindow and + * SmartDashboard integrated updating. + */ + @Override + public void robotPeriodic() { + // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled + // commands, running already-scheduled commands, removing finished or interrupted commands, + // and running subsystem periodic() methods. This must be called from the robot's periodic + // block in order for anything in the Command-based framework to work. + CommandScheduler.getInstance().run(); + + motor.set(0.8); + } + + /** This function is called once each time the robot enters Disabled mode. */ + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ + @Override + public void autonomousInit() { + m_autonomousCommand = m_robotContainer.getAutonomousCommand(); + + // schedule the autonomous command (example) + if (m_autonomousCommand != null) { + CommandScheduler.getInstance().schedule(m_autonomousCommand); + } + } + + /** This function is called periodically during autonomous. */ + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() { + // This makes sure that the autonomous stops running when + // teleop starts running. If you want the autonomous to + // continue until interrupted by another command, remove + // this line or comment it out. + if (m_autonomousCommand != null) { + m_autonomousCommand.cancel(); + } + } + + /** This function is called periodically during operator control. */ + @Override + public void teleopPeriodic() {} + + @Override + public void testInit() { + // Cancels all running commands at the start of test mode. + CommandScheduler.getInstance().cancelAll(); + } + + /** This function is called periodically during test mode. */ + @Override + public void testPeriodic() {} + + /** This function is called once when the robot is first started up. */ + @Override + public void simulationInit() {} + + /** This function is called periodically whilst in simulation. */ + @Override + public void simulationPeriodic() {} +} diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/RobotContainer.java new file mode 100644 index 0000000..a33249e --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/RobotContainer.java @@ -0,0 +1,63 @@ +// 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 frc.robot.Constants.OperatorConstants; +import frc.robot.commands.Autos; +import frc.robot.commands.ExampleCommand; +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import edu.wpi.first.wpilibj2.command.button.Trigger; + +/** + * This class is where the bulk of the robot should be declared. Since Command-based is a + * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot} + * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including + * subsystems, commands, and trigger mappings) should be declared here. + */ +public class RobotContainer { + // The robot's subsystems and commands are defined here... + private final ExampleSubsystem m_exampleSubsystem = new ExampleSubsystem(); + + // Replace with CommandPS4Controller or CommandJoystick if needed + private final CommandXboxController m_driverController = + new CommandXboxController(OperatorConstants.kDriverControllerPort); + + /** The container for the robot. Contains subsystems, OI devices, and commands. */ + public RobotContainer() { + // Configure the trigger bindings + configureBindings(); + } + + /** + * Use this method to define your trigger->command mappings. Triggers can be created via the + * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary + * predicate, or via the named factories in {@link + * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link + * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller + * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight + * joysticks}. + */ + private void configureBindings() { + // Schedule `ExampleCommand` when `exampleCondition` changes to `true` + new Trigger(m_exampleSubsystem::exampleCondition) + .onTrue(new ExampleCommand(m_exampleSubsystem)); + + // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed, + // cancelling on release. + m_driverController.b().whileTrue(m_exampleSubsystem.exampleMethodCommand()); + } + + /** + * Use this to pass the autonomous command to the main {@link Robot} class. + * + * @return the command to run in autonomous + */ + public Command getAutonomousCommand() { + // An example command will be run in autonomous + return Autos.exampleAuto(m_exampleSubsystem); + } +} diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/Autos.java new file mode 100644 index 0000000..107aad7 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/Autos.java @@ -0,0 +1,20 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.Commands; + +public final class Autos { + /** Example static factory for an autonomous command. */ + public static Command exampleAuto(ExampleSubsystem subsystem) { + return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); + } + + private Autos() { + throw new UnsupportedOperationException("This is a utility class!"); + } +} diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/ExampleCommand.java new file mode 100644 index 0000000..3c5b9b4 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/ExampleCommand.java @@ -0,0 +1,43 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; + +/** An example command that uses an example subsystem. */ +public class ExampleCommand extends Command { + @SuppressWarnings("PMD.UnusedPrivateField") + private final ExampleSubsystem m_subsystem; + + /** + * Creates a new ExampleCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ExampleCommand(ExampleSubsystem subsystem) { + m_subsystem = subsystem; + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java new file mode 100644 index 0000000..6b375da --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java @@ -0,0 +1,47 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class ExampleSubsystem extends SubsystemBase { + /** Creates a new ExampleSubsystem. */ + public ExampleSubsystem() {} + + /** + * Example command factory method. + * + * @return a command + */ + public Command exampleMethodCommand() { + // Inline construction of command goes here. + // Subsystem::RunOnce implicitly requires `this` subsystem. + return runOnce( + () -> { + /* one-time action goes here */ + }); + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/prototype_projects/Launcher v1/Launcher v1/vendordeps/Phoenix6-26.1.0.json b/prototype_projects/Launcher v1/Launcher v1/vendordeps/Phoenix6-26.1.0.json new file mode 100644 index 0000000..dc5dc62 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/vendordeps/Phoenix6-26.1.0.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-26.1.0.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Launcher v1/Launcher v1/vendordeps/REVLib.json b/prototype_projects/Launcher v1/Launcher v1/vendordeps/REVLib.json new file mode 100644 index 0000000..d35e593 --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/vendordeps/REVLib.json @@ -0,0 +1,133 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2026.0.1", + "frcYear": "2026", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2026.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2026.0.1" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.1", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2026.0.1", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.1", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.1", + "libName": "BackendDriver", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.1", + "libName": "REVLibWpi", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Launcher v1/Launcher v1/vendordeps/WPILibNewCommands.json b/prototype_projects/Launcher v1/Launcher v1/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/Launcher v1/Launcher v1/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} From 4bad4b78d60d7a8a5c3f7afa3102e72c2dfc102d Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 19:42:57 -0600 Subject: [PATCH 027/161] fixup paths for non-windows machines --- .../launcher_v1}/.gitignore | 0 .../launcher_v1}/.vscode/launch.json | 0 .../launcher_v1}/.vscode/settings.json | 0 .../launcher_v1}/.wpilib/wpilib_preferences.json | 0 .../launcher_v1}/WPILib-License.md | 0 .../launcher_v1}/build.gradle | 0 .../launcher_v1}/gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../Launcher v1 => launcher_v1/launcher_v1}/gradlew | 0 .../launcher_v1}/gradlew.bat | 0 .../launcher_v1}/settings.gradle | 0 .../launcher_v1}/src/main/deploy/example.txt | 0 .../src/main/java/frc/robot/Constants.java | 0 .../launcher_v1}/src/main/java/frc/robot/Main.java | 0 .../launcher_v1}/src/main/java/frc/robot/Robot.java | 0 .../src/main/java/frc/robot/RobotContainer.java | 0 .../src/main/java/frc/robot/commands/Autos.java | 0 .../java/frc/robot/commands/ExampleCommand.java | 0 .../java/frc/robot/subsystems/ExampleSubsystem.java | 0 .../launcher_v1}/vendordeps/Phoenix6-26.1.0.json | 0 .../launcher_v1}/vendordeps/REVLib.json | 0 .../launcher_v1}/vendordeps/WPILibNewCommands.json | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/.gitignore (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/.vscode/launch.json (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/.vscode/settings.json (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/.wpilib/wpilib_preferences.json (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/WPILib-License.md (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/build.gradle (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/gradle/wrapper/gradle-wrapper.jar (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/gradle/wrapper/gradle-wrapper.properties (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/gradlew (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/gradlew.bat (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/settings.gradle (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/deploy/example.txt (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/Constants.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/Main.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/Robot.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/RobotContainer.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/commands/Autos.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/commands/ExampleCommand.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/src/main/java/frc/robot/subsystems/ExampleSubsystem.java (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/vendordeps/Phoenix6-26.1.0.json (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/vendordeps/REVLib.json (100%) rename prototype_projects/{Launcher v1/Launcher v1 => launcher_v1/launcher_v1}/vendordeps/WPILibNewCommands.json (100%) diff --git a/prototype_projects/Launcher v1/Launcher v1/.gitignore b/prototype_projects/launcher_v1/launcher_v1/.gitignore similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/.gitignore rename to prototype_projects/launcher_v1/launcher_v1/.gitignore diff --git a/prototype_projects/Launcher v1/Launcher v1/.vscode/launch.json b/prototype_projects/launcher_v1/launcher_v1/.vscode/launch.json similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/.vscode/launch.json rename to prototype_projects/launcher_v1/launcher_v1/.vscode/launch.json diff --git a/prototype_projects/Launcher v1/Launcher v1/.vscode/settings.json b/prototype_projects/launcher_v1/launcher_v1/.vscode/settings.json similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/.vscode/settings.json rename to prototype_projects/launcher_v1/launcher_v1/.vscode/settings.json diff --git a/prototype_projects/Launcher v1/Launcher v1/.wpilib/wpilib_preferences.json b/prototype_projects/launcher_v1/launcher_v1/.wpilib/wpilib_preferences.json similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/.wpilib/wpilib_preferences.json rename to prototype_projects/launcher_v1/launcher_v1/.wpilib/wpilib_preferences.json diff --git a/prototype_projects/Launcher v1/Launcher v1/WPILib-License.md b/prototype_projects/launcher_v1/launcher_v1/WPILib-License.md similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/WPILib-License.md rename to prototype_projects/launcher_v1/launcher_v1/WPILib-License.md diff --git a/prototype_projects/Launcher v1/Launcher v1/build.gradle b/prototype_projects/launcher_v1/launcher_v1/build.gradle similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/build.gradle rename to prototype_projects/launcher_v1/launcher_v1/build.gradle diff --git a/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.jar rename to prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.jar diff --git a/prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/gradle/wrapper/gradle-wrapper.properties rename to prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.properties diff --git a/prototype_projects/Launcher v1/Launcher v1/gradlew b/prototype_projects/launcher_v1/launcher_v1/gradlew similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/gradlew rename to prototype_projects/launcher_v1/launcher_v1/gradlew diff --git a/prototype_projects/Launcher v1/Launcher v1/gradlew.bat b/prototype_projects/launcher_v1/launcher_v1/gradlew.bat similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/gradlew.bat rename to prototype_projects/launcher_v1/launcher_v1/gradlew.bat diff --git a/prototype_projects/Launcher v1/Launcher v1/settings.gradle b/prototype_projects/launcher_v1/launcher_v1/settings.gradle similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/settings.gradle rename to prototype_projects/launcher_v1/launcher_v1/settings.gradle diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/deploy/example.txt b/prototype_projects/launcher_v1/launcher_v1/src/main/deploy/example.txt similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/deploy/example.txt rename to prototype_projects/launcher_v1/launcher_v1/src/main/deploy/example.txt diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Constants.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Constants.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Constants.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Constants.java diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Main.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Main.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Main.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Main.java diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Robot.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/Robot.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Robot.java diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/RobotContainer.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/RobotContainer.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/RobotContainer.java diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/Autos.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/Autos.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/Autos.java diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/ExampleCommand.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/commands/ExampleCommand.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/ExampleCommand.java diff --git a/prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java rename to prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java diff --git a/prototype_projects/Launcher v1/Launcher v1/vendordeps/Phoenix6-26.1.0.json b/prototype_projects/launcher_v1/launcher_v1/vendordeps/Phoenix6-26.1.0.json similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/vendordeps/Phoenix6-26.1.0.json rename to prototype_projects/launcher_v1/launcher_v1/vendordeps/Phoenix6-26.1.0.json diff --git a/prototype_projects/Launcher v1/Launcher v1/vendordeps/REVLib.json b/prototype_projects/launcher_v1/launcher_v1/vendordeps/REVLib.json similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/vendordeps/REVLib.json rename to prototype_projects/launcher_v1/launcher_v1/vendordeps/REVLib.json diff --git a/prototype_projects/Launcher v1/Launcher v1/vendordeps/WPILibNewCommands.json b/prototype_projects/launcher_v1/launcher_v1/vendordeps/WPILibNewCommands.json similarity index 100% rename from prototype_projects/Launcher v1/Launcher v1/vendordeps/WPILibNewCommands.json rename to prototype_projects/launcher_v1/launcher_v1/vendordeps/WPILibNewCommands.json From 6b8163fca065bbaa9d451cc66958970da70c7fdf Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 20:14:28 -0600 Subject: [PATCH 028/161] Added a arcade PID from dashboard --- .../shuffleboard.json | 41 ++++++++++++------ .../main/java/frc/robot/RobotContainer.java | 2 + .../robot/commands/ArcadeFromDashboard.java | 43 +++++++++++++++++++ .../DifferentailDriveFromDashboard.java | 3 +- .../frc/robot/subsystems/DriveSubsystem.java | 8 +++- 5 files changed, 83 insertions(+), 14 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeFromDashboard.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 98ba112..5ca5ee4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -11,7 +11,7 @@ "vgap": 16.0, "titleType": 0, "tiles": { - "3,1": { + "8,4": { "size": [ 1, 1 @@ -24,7 +24,7 @@ "_showGlyph": false } }, - "4,1": { + "9,4": { "size": [ 1, 1 @@ -37,7 +37,7 @@ "_showGlyph": false } }, - "3,3": { + "3,2": { "size": [ 1, 1 @@ -50,7 +50,7 @@ "_showGlyph": false } }, - "4,3": { + "4,2": { "size": [ 1, 1 @@ -63,7 +63,7 @@ "_showGlyph": false } }, - "4,2": { + "4,1": { "size": [ 1, 1 @@ -76,7 +76,7 @@ "_showGlyph": false } }, - "3,2": { + "3,1": { "size": [ 1, 1 @@ -98,6 +98,8 @@ "_type": "Graph", "_source0": "network_table:///SmartDashboard/Left Target (MPS)", "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", + "_source2": "network_table:///SmartDashboard/Right Speed (MPS)", + "_source3": "network_table:///SmartDashboard/Right Speed (RPS)", "_title": "Graph", "_glyph": 148, "_showGlyph": false, @@ -108,10 +110,12 @@ "Y-axis/Lower bound": -3.0, "Y-axis/Unit": "mps", "Visible data/SmartDashboard/Left Speed (MPS)": true, - "Visible data/SmartDashboard/Left Target (MPS)": true + "Visible data/SmartDashboard/Left Target (MPS)": true, + "Visible data/SmartDashboard/Right Speed (MPS)": true, + "Visible data/SmartDashboard/Right Speed (RPS)": true } }, - "4,4": { + "4,3": { "size": [ 1, 1 @@ -124,7 +128,7 @@ "_showGlyph": false } }, - "3,4": { + "3,3": { "size": [ 1, 1 @@ -143,9 +147,22 @@ 1 ], "content": { - "_type": "Toggle Switch", - "_source0": "network_table:///SmartDashboard/Use Arcade", - "_title": "SmartDashboard/Use Arcade", + "_type": "ComboBox Chooser", + "_source0": "network_table:///SmartDashboard/Drive Commands", + "_title": "SmartDashboard/Drive Commands", + "_glyph": 148, + "_showGlyph": false + } + }, + "6,4": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/DB Arcade Set (MPS)", + "_title": "SmartDashboard/DB Arcade Set (MPS)", "_glyph": 148, "_showGlyph": false } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index be6bb5c..08c6c0b 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -141,6 +141,8 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Left Distance (m)", driveSubsystem.getMotorPositionMeters(true)); SmartDashboard.putNumber("Right Distance (m)", driveSubsystem.getMotorPositionMeters(false)); + + SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); } m_iTickCount++; diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeFromDashboard.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeFromDashboard.java new file mode 100644 index 0000000..f35dc4f --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/ArcadeFromDashboard.java @@ -0,0 +1,43 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.subsystems.DriveSubsystem; + +public class ArcadeFromDashboard extends Command { + private final DriveSubsystem m_subsystem; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeFromDashboard(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + double speed = SmartDashboard.getNumber("DB Arcade Set (MPS)", 0); + m_subsystem.setDifferentialSpeeds( speed, speed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java index 4268bc3..a53bd80 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java @@ -2,6 +2,7 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.subsystems.DriveSubsystem; public class DifferentailDriveFromDashboard extends Command { @@ -12,7 +13,7 @@ public class DifferentailDriveFromDashboard extends Command { * * @param subsystem The subsystem used by this command. */ - public DifferentailDriveFromDashboard(DriveSubsystem subsystem) { + public DifferentailDriveFromDashboard(DriveSubsystem subsystem, CommandXboxController driveController) { m_subsystem = subsystem; // Use addRequirements() here to declare subsystem dependencies. diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index eaebfda..715a0ac 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -35,6 +35,7 @@ import frc.robot.Constants.DrivetrainConstants; import frc.robot.commands.ArcadeDriveCommand; import frc.robot.commands.ArcadeDriveCommandNoPID; +import frc.robot.commands.ArcadeFromDashboard; import frc.robot.commands.DifferentialDriveCommand; public class DriveSubsystem extends SubsystemBase { @@ -103,17 +104,22 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_driveChooser.setDefaultOption("PID Arcade", ArcadeDriveCommand.class); m_driveChooser.addOption("PID Differential", DifferentialDriveCommand.class); m_driveChooser.addOption("NO-PID Arcade", ArcadeDriveCommandNoPID.class); + m_driveChooser.addOption("Dashboard PID Arcade", ArcadeFromDashboard.class); SmartDashboard.putData("Drive Commands", m_driveChooser); // Init Smartdashboard SmartDashboard.putNumber("DB Left Set (MPS)", 0); SmartDashboard.putNumber("DB Right Set (MPS)", 0); + SmartDashboard.putNumber("DB Arcade Set (MPS)", 0); + SmartDashboard.putNumber("Left Target (MPS)", 0); SmartDashboard.putNumber("Right Target (MPS)", 0); SmartDashboard.putNumber("Left Speed (MPS)", getMotorSpeedMPS(true)); SmartDashboard.putNumber("Right Speed (MPS)", getMotorSpeedMPS(false)); SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); + + SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); } private void setConfig(TalonFX motor, InvertedValue Inverted) { @@ -232,7 +238,7 @@ public Pose2d getPose(){ public void resetPose(Pose2d newPose){ m_leftMotor.setPosition(0); m_rightMotor.setPosition(0); - + m_poseEstimator.resetPosition( m_gyro.getRotation2d(), 0, 0, From 5c345ae2ead05a6ab44864ba98e48f1808201eff Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 23 Jan 2026 20:33:38 -0600 Subject: [PATCH 029/161] Combo auto, plus repeatability statistics. --- .../AutoStatistics.txt | 14 +++++ .../pathplanner/autos/SmoothTurnReverseS.auto | 25 +++++++++ .../deploy/pathplanner/paths/2 Meter New.path | 8 +-- .../pathplanner/paths/Reverse S Turn.path | 54 +++++++++++++++++++ .../main/deploy/pathplanner/paths/S Turn.path | 8 +-- .../deploy/pathplanner/paths/Smooth Turn.path | 10 ++-- .../src/main/java/frc/robot/Robot.java | 1 + .../main/java/frc/robot/RobotContainer.java | 9 ++++ 8 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/AutoStatistics.txt create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse S Turn.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/AutoStatistics.txt b/prototype_projects/Experimental_Drivetrain_2026/AutoStatistics.txt new file mode 100644 index 0000000..5d40e72 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/AutoStatistics.txt @@ -0,0 +1,14 @@ +Test 1: +Auto: SmoothTurnReverseS +Rotation Off: 0 degrees (essentially) +Pos Off: 8 inch + +Test 2: +Auto: SmoothTurnReverseS +Rotation Off: 0 degrees (essentially) +Pos Off: 8 inch + +Test 3: +Auto: SmoothTurnReverseS +Rotation Off: 0 degrees (essentially) +Pos Off: 8 inch \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto new file mode 100644 index 0000000..044a55d --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto @@ -0,0 +1,25 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Smooth Turn" + } + }, + { + "type": "path", + "data": { + "pathName": "Reverse S Turn" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path index 0ba9ad5..a1988a4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path @@ -4,12 +4,12 @@ { "anchor": { "x": 0.0, - "y": 0.0 + "y": 8.0 }, "prevControl": null, "nextControl": { "x": 0.9999999999999996, - "y": 0.0 + "y": 8.0 }, "isLocked": false, "linkedName": null @@ -17,11 +17,11 @@ { "anchor": { "x": 2.0, - "y": 0.0 + "y": 8.0 }, "prevControl": { "x": 1.0, - "y": 2.220446049250313e-16 + "y": 8.0 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse S Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse S Turn.path new file mode 100644 index 0000000..b7dff0e --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse S Turn.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.0, + "y": 6.0 + }, + "prevControl": null, + "nextControl": { + "x": 0.43680380386361306, + "y": 6.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.0, + "y": 8.0 + }, + "prevControl": { + "x": 2.0, + "y": 8.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path index c0c3795..a8a0ad7 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path @@ -4,12 +4,12 @@ { "anchor": { "x": 0.0, - "y": 0.0 + "y": 8.0 }, "prevControl": null, "nextControl": { "x": 2.0, - "y": 0.0 + "y": 8.0 }, "isLocked": false, "linkedName": null @@ -17,11 +17,11 @@ { "anchor": { "x": 2.0, - "y": 2.0 + "y": 6.0 }, "prevControl": { "x": 0.0, - "y": 2.0 + "y": 6.0 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path index e4f9623..639102e 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path @@ -4,12 +4,12 @@ { "anchor": { "x": 0.0, - "y": 0.0 + "y": 8.0 }, "prevControl": null, "nextControl": { "x": 2.0, - "y": 0.0 + "y": 8.0 }, "isLocked": false, "linkedName": null @@ -17,11 +17,11 @@ { "anchor": { "x": 2.0, - "y": 2.0 + "y": 6.0 }, "prevControl": { - "x": 2.0, - "y": 0.0 + "x": 1.9999999999999998, + "y": 8.0 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java index 976f67d..a4b186d 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -59,6 +59,7 @@ public void disabledPeriodic() {} /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ @Override public void autonomousInit() { + m_robotContainer.autoInit(); m_autonomousCommand = m_robotContainer.getAutonomousCommand(); // schedule the autonomous command (example) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 08c6c0b..d36a3af 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -152,6 +152,15 @@ public void teleopInit() { configureDefaultCommands(); } + public void autoInit() { + if (m_driveSubsystem.isPresent()) { + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + + m_gyro.reset(); + driveSubsystem.resetPose(new Pose2d()); + } + } + /** * Use this to pass the autonomous command to the main {@link Robot} class. * From ed34a254c9a5bbb1085a5f4bc3b52bb6f801b603 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 24 Jan 2026 09:53:21 -0600 Subject: [PATCH 030/161] Removed the spaces from all of the pathplanner paths --- .../Experimental_Drivetrain_2026/shuffleboard.json | 13 +++++++++++++ .../main/deploy/pathplanner/autos/2MeterAuto.auto | 2 +- .../main/deploy/pathplanner/autos/STurnAuto.auto | 2 +- .../main/deploy/pathplanner/autos/SampleAuto.auto | 2 +- .../deploy/pathplanner/autos/SmoothTurnAuto.auto | 2 +- ...thTurnReverseS.auto => SmoothTurn_ReverseS.auto} | 4 ++-- .../paths/{2 Meter New.path => 2_Meter_New.path} | 0 .../paths/{Example Path.path => Example_Path.path} | 0 .../{Reverse S Turn.path => Reverse_S_Turn.path} | 0 .../pathplanner/paths/{S Turn.path => S_Turn.path} | 0 .../paths/{Smooth Turn.path => Smooth_Turn.path} | 0 11 files changed, 19 insertions(+), 6 deletions(-) rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/{SmoothTurnReverseS.auto => SmoothTurn_ReverseS.auto} (81%) rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/{2 Meter New.path => 2_Meter_New.path} (100%) rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/{Example Path.path => Example_Path.path} (100%) rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/{Reverse S Turn.path => Reverse_S_Turn.path} (100%) rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/{S Turn.path => S_Turn.path} (100%) rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/{Smooth Turn.path => Smooth_Turn.path} (100%) diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json index 5ca5ee4..648c12f 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json @@ -295,6 +295,19 @@ "_glyph": 148, "_showGlyph": false } + }, + "3,4": { + "size": [ + 2, + 1 + ], + "content": { + "_type": "Text View", + "_source0": "network_table:///SmartDashboard/Gyro Degrees", + "_title": "/SmartDashboard/Gyro Degrees", + "_glyph": 148, + "_showGlyph": false + } } } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto index b9dbc81..26adafa 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto @@ -7,7 +7,7 @@ { "type": "path", "data": { - "pathName": "2 Meter New" + "pathName": "2_Meter_New" } } ] diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto index 45002a3..59b73ae 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto @@ -7,7 +7,7 @@ { "type": "path", "data": { - "pathName": "S Turn" + "pathName": "S_Turn" } } ] diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto index 70b7ab2..6460f85 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto @@ -7,7 +7,7 @@ { "type": "path", "data": { - "pathName": "Example Path" + "pathName": "Example_Path" } } ] diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto index 870c422..c79aef4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto @@ -7,7 +7,7 @@ { "type": "path", "data": { - "pathName": "Smooth Turn" + "pathName": "Smooth_Turn" } } ] diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto similarity index 81% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto index 044a55d..119345f 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnReverseS.auto +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto @@ -7,13 +7,13 @@ { "type": "path", "data": { - "pathName": "Smooth Turn" + "pathName": "Smooth_Turn" } }, { "type": "path", "data": { - "pathName": "Reverse S Turn" + "pathName": "Reverse_S_Turn" } } ] diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2_Meter_New.path similarity index 100% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2 Meter New.path rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/2_Meter_New.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path similarity index 100% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example Path.path rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse S Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse_S_Turn.path similarity index 100% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse S Turn.path rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Reverse_S_Turn.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S_Turn.path similarity index 100% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S Turn.path rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/S_Turn.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth_Turn.path similarity index 100% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth Turn.path rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Smooth_Turn.path From acb1d3723330399d1e928801f2bf9b85a896350d Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:01:17 -0600 Subject: [PATCH 031/161] Made comments on the initDefaultCommand clearer --- .../src/main/java/frc/robot/subsystems/DriveSubsystem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 715a0ac..76a4bd4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -170,8 +170,8 @@ public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { ); } - // This takes the current class selected in the drive chooser and attempts to - // initilize a command object from it & run it. + // This takes the current class selected in the drive chooser and attempts to initilize a command object from it & run it. + // The commands must have a constructor with a DriveSubsystem and CommandXboxController as args. public void initDefaultCommand(CommandXboxController Controller) { Class driveClass = m_driveChooser.getSelected(); From b26e2d10403898bcdd5b1d9e7ebf61460e9a277d Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:30:11 -0600 Subject: [PATCH 032/161] Replaced shuffleboard with elastic. --- .../elastic-layout.json | 96 ++++++ .../shuffleboard.json | 322 ------------------ 2 files changed, 96 insertions(+), 322 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json diff --git a/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json b/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json new file mode 100644 index 0000000..a721611 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json @@ -0,0 +1,96 @@ +{ + "version": 1.0, + "grid_size": 128, + "tabs": [ + { + "name": "Toaster Testing", + "grid_layout": { + "layouts": [], + "containers": [ + { + "title": "Drive Commands", + "x": 384.0, + "y": 0.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Drive Commands", + "period": 0.06, + "sort_options": false + } + }, + { + "title": "Left Target (MPS)", + "x": 768.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Left Speed (MPS)", + "x": 768.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Right Target (MPS)", + "x": 896.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Right Speed (MPS)", + "x": 896.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Auto Chooser", + "x": 384.0, + "y": 128.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Auto Chooser", + "period": 0.06, + "sort_options": false + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json b/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json deleted file mode 100644 index 648c12f..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/shuffleboard.json +++ /dev/null @@ -1,322 +0,0 @@ -{ - "tabPane": [ - { - "title": "Teleop Dashboard Testing", - "autoPopulate": false, - "autoPopulatePrefix": "", - "widgetPane": { - "gridSize": 128.0, - "showGrid": true, - "hgap": 16.0, - "vgap": 16.0, - "titleType": 0, - "tiles": { - "8,4": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/DB Left Set (MPS)", - "_title": "/SmartDashboard/DB Left Set (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "9,4": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/DB Right Set (MPS)", - "_title": "SmartDashboard/DB Right Set (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,2": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Speed (MPS)", - "_title": "SmartDashboard/Left Speed (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "4,2": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Speed (MPS)", - "_title": "SmartDashboard/Right Speed (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "4,1": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Target (MPS)", - "_title": "SmartDashboard/Right Target (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,1": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_title": "SmartDashboard/Left Target (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "5,0": { - "size": [ - 8, - 4 - ], - "content": { - "_type": "Graph", - "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", - "_source2": "network_table:///SmartDashboard/Right Speed (MPS)", - "_source3": "network_table:///SmartDashboard/Right Speed (RPS)", - "_title": "Graph", - "_glyph": 148, - "_showGlyph": false, - "Graph/Visible time": 10.0, - "Graph/X-axis auto scrolling": true, - "Y-axis/Automatic bounds": false, - "Y-axis/Upper bound": 3.0, - "Y-axis/Lower bound": -3.0, - "Y-axis/Unit": "mps", - "Visible data/SmartDashboard/Left Speed (MPS)": true, - "Visible data/SmartDashboard/Left Target (MPS)": true, - "Visible data/SmartDashboard/Right Speed (MPS)": true, - "Visible data/SmartDashboard/Right Speed (RPS)": true - } - }, - "4,3": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Speed (RPS)", - "_title": "SmartDashboard/Right Speed (RPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,3": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Speed (RPS)", - "_title": "SmartDashboard/Left Speed (RPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,0": { - "size": [ - 2, - 1 - ], - "content": { - "_type": "ComboBox Chooser", - "_source0": "network_table:///SmartDashboard/Drive Commands", - "_title": "SmartDashboard/Drive Commands", - "_glyph": 148, - "_showGlyph": false - } - }, - "6,4": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/DB Arcade Set (MPS)", - "_title": "SmartDashboard/DB Arcade Set (MPS)", - "_glyph": 148, - "_showGlyph": false - } - } - } - } - }, - { - "title": "Auto Testing", - "autoPopulate": false, - "autoPopulatePrefix": "", - "widgetPane": { - "gridSize": 128.0, - "showGrid": true, - "hgap": 16.0, - "vgap": 16.0, - "titleType": 0, - "tiles": { - "3,2": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Speed (MPS)", - "_title": "/SmartDashboard/Left Speed (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "4,2": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Speed (MPS)", - "_title": "/SmartDashboard/Right Speed (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,0": { - "size": [ - 2, - 1 - ], - "content": { - "_type": "ComboBox Chooser", - "_source0": "network_table:///SmartDashboard/Auto Chooser", - "_title": "/SmartDashboard/Auto Chooser", - "_glyph": 148, - "_showGlyph": false - } - }, - "5,0": { - "size": [ - 8, - 4 - ], - "content": { - "_type": "Graph", - "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_source1": "network_table:///SmartDashboard/Left Speed (MPS)", - "_source2": "network_table:///SmartDashboard/Left Distance (m)", - "_title": "Graph", - "_glyph": 148, - "_showGlyph": false, - "Graph/Visible time": 30.0, - "Graph/X-axis auto scrolling": true, - "Y-axis/Automatic bounds": false, - "Y-axis/Upper bound": 3.0, - "Y-axis/Lower bound": -3.0, - "Y-axis/Unit": "m", - "Visible data/SmartDashboard/Left Distance (m)": true, - "Visible data/SmartDashboard/Left Speed (MPS)": true, - "Visible data/SmartDashboard/Left Target (MPS)": true - } - }, - "3,3": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Distance (m)", - "_title": "SmartDashboard/Left Distance (m)", - "_glyph": 148, - "_showGlyph": false - } - }, - "4,3": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Distance (m)", - "_title": "/SmartDashboard/Right Distance (m)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,1": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Left Target (MPS)", - "_title": "/SmartDashboard/Left Target (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "4,1": { - "size": [ - 1, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Right Target (MPS)", - "_title": "/SmartDashboard/Right Target (MPS)", - "_glyph": 148, - "_showGlyph": false - } - }, - "3,4": { - "size": [ - 2, - 1 - ], - "content": { - "_type": "Text View", - "_source0": "network_table:///SmartDashboard/Gyro Degrees", - "_title": "/SmartDashboard/Gyro Degrees", - "_glyph": 148, - "_showGlyph": false - } - } - } - } - } - ], - "windowGeometry": { - "x": -7.0, - "y": 1.0, - "width": 1934.0, - "height": 844.0 - } -} \ No newline at end of file From f5fb8c5ae4319d0724424370059ab197ea567b96 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 24 Jan 2026 10:58:50 -0600 Subject: [PATCH 033/161] Created PoseTrackerClass --- .../frc/robot/classes/PoseTrackerClass.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java new file mode 100644 index 0000000..e9686b9 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java @@ -0,0 +1,31 @@ +package frc.robot.classes; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; + +// This is the class that manages all of the pose tracking for the robot. +public class PoseTrackerClass { + private final DifferentialDrivePoseEstimator m_drivetrainPoseEstimator; + private final DifferentialDrivePoseEstimator m_limelightPoseEstimator; + + private double m_drivetrainError = 0.0; + private double m_limelightError = 0.0; + private double m_totalError = 0.0; + + /** Creates a new PositionSubsystem. */ + public PoseTrackerClass(DifferentialDrivePoseEstimator drivetrainPoseEstimator, DifferentialDrivePoseEstimator limelightPoseEstimator) { + m_drivetrainPoseEstimator = drivetrainPoseEstimator; + m_limelightPoseEstimator = limelightPoseEstimator; + } + + // This makes the most updated pose2d and returns it. + // TODO: make it actually do the merging n stuf + public Pose2d getPose(){ + return new Pose2d(); + } + + public void periodic() { + // This method will be called once per scheduler + + } +} From 0497437e7afc4e3785dfc0f5b04e77692ff5361f Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:00:42 -0600 Subject: [PATCH 034/161] Updated Elastic & Added robot pose to it --- .../elastic-layout.json | 123 ++++++++++++++++-- .../src/main/java/frc/robot/Robot.java | 1 + .../main/java/frc/robot/RobotContainer.java | 52 ++++++-- .../frc/robot/classes/PoseTrackerClass.java | 31 ----- .../frc/robot/subsystems/DriveSubsystem.java | 1 - .../robot/subsystems/LimelightSubsystem.java | 59 +++++---- 6 files changed, 191 insertions(+), 76 deletions(-) delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json b/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json index a721611..9175fbd 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json +++ b/prototype_projects/Experimental_Drivetrain_2026/elastic-layout.json @@ -9,7 +9,7 @@ "containers": [ { "title": "Drive Commands", - "x": 384.0, + "x": 0.0, "y": 0.0, "width": 256.0, "height": 128.0, @@ -22,8 +22,8 @@ }, { "title": "Left Target (MPS)", - "x": 768.0, - "y": 0.0, + "x": 0.0, + "y": 256.0, "width": 128.0, "height": 128.0, "type": "Text Display", @@ -36,8 +36,8 @@ }, { "title": "Left Speed (MPS)", - "x": 768.0, - "y": 128.0, + "x": 0.0, + "y": 384.0, "width": 128.0, "height": 128.0, "type": "Text Display", @@ -50,8 +50,8 @@ }, { "title": "Right Target (MPS)", - "x": 896.0, - "y": 0.0, + "x": 128.0, + "y": 256.0, "width": 128.0, "height": 128.0, "type": "Text Display", @@ -64,8 +64,8 @@ }, { "title": "Right Speed (MPS)", - "x": 896.0, - "y": 128.0, + "x": 128.0, + "y": 384.0, "width": 128.0, "height": 128.0, "type": "Text Display", @@ -78,7 +78,7 @@ }, { "title": "Auto Chooser", - "x": 384.0, + "x": 0.0, "y": 128.0, "width": 256.0, "height": 128.0, @@ -88,6 +88,109 @@ "period": 0.06, "sort_options": false } + }, + { + "title": "Field", + "x": 384.0, + "y": 0.0, + "width": 640.0, + "height": 384.0, + "type": "Field", + "properties": { + "topic": "/SmartDashboard/Field", + "period": 0.06, + "field_game": "Rebuilt", + "robot_width": 0.85, + "robot_length": 0.85, + "show_other_objects": true, + "show_trajectories": true, + "field_rotation": 0.0, + "robot_color": 4294198070, + "trajectory_color": 4294967295, + "show_robot_outside_widget": true + } + }, + { + "title": "Scheduler", + "x": 1664.0, + "y": 0.0, + "width": 256.0, + "height": 384.0, + "type": "Scheduler", + "properties": { + "topic": "/SmartDashboard/Scheduler", + "period": 0.06 + } + }, + { + "title": "Left Distance (m)", + "x": 0.0, + "y": 512.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Distance (m)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Right Distance (m)", + "x": 128.0, + "y": 512.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Distance (m)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose X (Meter)", + "x": 1024.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose X (Meter)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose Y (Meter)", + "x": 1024.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose Y (Meter)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose Theta (Degrees)", + "x": 1024.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose Theta (Degrees)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } } ] } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java index a4b186d..ed1d320 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -28,6 +28,7 @@ public void robotInit() { // Instantiate our RobotContainer. This will perform all our button bindings, and put our // autonomous chooser on the dashboard. m_robotContainer = new RobotContainer(); + m_robotContainer.InitSmartDashboard(); } /** diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index d36a3af..024ee3d 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -11,12 +11,18 @@ import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; +import edu.wpi.first.math.VecBuilder; +import edu.wpi.first.math.Vector; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import edu.wpi.first.math.numbers.N3; +import edu.wpi.first.wpilibj.smartdashboard.Field2d; 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.CommandScheduler; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Constants.DrivetrainConstants; @@ -43,16 +49,23 @@ public class RobotContainer { private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.kTrackWidthMeters); - // Pose Estimators - private DifferentialDrivePoseEstimator m_DrivePoseEstimator = new DifferentialDrivePoseEstimator( - m_DriveKinematics, - m_gyro.getRotation2d(), - 0, - 0, - new Pose2d()); - - // Sendable Choosers + // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. + private Vector m_drivetrainError = VecBuilder.fill(0.2, 0.2, 0); + private Vector m_limelightError = VecBuilder.fill(.7,.7,9999999); + + private DifferentialDrivePoseEstimator m_PoseEstimator = new DifferentialDrivePoseEstimator( + m_DriveKinematics, + m_gyro.getRotation2d(), + 0, + 0, + new Pose2d(0.0, 8.0, new Rotation2d()), + m_drivetrainError, + m_limelightError + ); + + // Smartdashboard Objects private SendableChooser autoChooser; + private final Field2d m_field = new Field2d(); // Factorys private TalonFXFactory m_TalonFXFactory = new TalonFXFactory(); @@ -68,10 +81,10 @@ public RobotContainer() { Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); Optional rightFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalRightMotorCANID); Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); - m_driveSubsystem = m_DriveSubsystemFactory.construct(m_DrivePoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); + m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); // Init the subsystems - //m_limelightSubsystem = getSubsystem(LimelightSubsystem.class, m_limeLightPoseEstimator); + //m_limelightSubsystem = getSubsystem(LimelightSubsystem.class, m_PoseEstimator); //m_exampleSubsystem = getSubsystem(ExampleSubsystem.class); // Init Auto @@ -127,8 +140,25 @@ private void configureBindings() { // } } + // Populate the SmartDashboard on robot init. + public void InitSmartDashboard() { + // Non-Subsystem Specific Stuff + SmartDashboard.putData(CommandScheduler.getInstance()); + SmartDashboard.putData("Field", m_field); + } + // This function is called every 20mS. public void UpdateSmartDashboard() { + // Non-subsystem specific stuff + if ((m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) { + Pose2d estimatedPos = m_PoseEstimator.getEstimatedPosition(); + m_field.setRobotPose(estimatedPos); + + SmartDashboard.putNumber("Pose X (Meter)", estimatedPos.getX()); + SmartDashboard.putNumber("Pose Y (Meter)", estimatedPos.getY()); + SmartDashboard.putNumber("Pose Theta (Degrees)", estimatedPos.getRotation().getDegrees()); + } + // Drive subsystem if(m_driveSubsystem.isPresent() && (m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) { diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java deleted file mode 100644 index e9686b9..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/classes/PoseTrackerClass.java +++ /dev/null @@ -1,31 +0,0 @@ -package frc.robot.classes; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; - -// This is the class that manages all of the pose tracking for the robot. -public class PoseTrackerClass { - private final DifferentialDrivePoseEstimator m_drivetrainPoseEstimator; - private final DifferentialDrivePoseEstimator m_limelightPoseEstimator; - - private double m_drivetrainError = 0.0; - private double m_limelightError = 0.0; - private double m_totalError = 0.0; - - /** Creates a new PositionSubsystem. */ - public PoseTrackerClass(DifferentialDrivePoseEstimator drivetrainPoseEstimator, DifferentialDrivePoseEstimator limelightPoseEstimator) { - m_drivetrainPoseEstimator = drivetrainPoseEstimator; - m_limelightPoseEstimator = limelightPoseEstimator; - } - - // This makes the most updated pose2d and returns it. - // TODO: make it actually do the merging n stuf - public Pose2d getPose(){ - return new Pose2d(); - } - - public void periodic() { - // This method will be called once per scheduler - - } -} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 76a4bd4..073f6b2 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -305,7 +305,6 @@ public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ @Override public void periodic() { // This method will be called once per scheduler run - double lPositionMeters = getMotorPositionMeters(true); double rPositionMeters = getMotorPositionMeters(false); diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 0008e82..30514d0 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -3,46 +3,59 @@ // the WPILib BSD license file in the root directory of this project. package frc.robot.subsystems; +import com.studica.frc.AHRS; + import edu.wpi.first.math.VecBuilder; +import edu.wpi.first.math.Vector; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.numbers.N3; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; public class LimelightSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; + private final AHRS m_gyro; /** Creates a new PositionSubsystem. */ - public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { + public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { m_poseEstimator = poseEstimator; + m_gyro = gyro; } - /** - * An example method querying a boolean state of the subsystem (for example, a digital sensor). - * - * @return value of some boolean subsystem state, such as a digital sensor. - */ - public boolean exampleCondition() { - // Query some boolean state, such as a digital sensor. - return false; - } + // This is copy and pasted from limelight's documentation for testing. + public void updateOdometry() { + boolean doRejectUpdate = false; - @Override - public void periodic() { - // This method will be called once per scheduler + LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); + LimelightHelpers.PoseEstimate mt2 = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); + + // if our angular velocity is greater than 720 degrees per second, ignore vision updates + if(Math.abs(m_gyro.getRate()) > 720) + { + doRejectUpdate = true; + } - // This is copy and pasted from limelight's documentation for testing. - LimelightHelpers.PoseEstimate limelightMeasurement = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); - if (limelightMeasurement.tagCount >= 2) { // Only trust measurement if we see multiple tags - m_poseEstimator.setVisionMeasurementStdDevs(VecBuilder.fill(0.7, 0.7, 9999999)); - m_poseEstimator.addVisionMeasurement( - limelightMeasurement.pose, - limelightMeasurement.timestampSeconds - ); + if(mt2.tagCount == 0) + { + doRejectUpdate = true; + } + + if(!doRejectUpdate) + { + // A Static Standard Deviation of .7 meters for x & y, it does not trust the theta. (Taken from example) + Vector errorVec = VecBuilder.fill(.7,.7,9999999); + m_poseEstimator.setVisionMeasurementStdDevs(errorVec); + + m_poseEstimator.addVisionMeasurement( + mt2.pose, + mt2.timestampSeconds + ); } } @Override - public void simulationPeriodic() { - // This method will be called once per scheduler run during simulation + public void periodic() { + // This method will be called once per scheduler + updateOdometry(); } } From 2b702d02a1cf7df64bf46b5377a8453c63ae41bd Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:20:05 -0600 Subject: [PATCH 035/161] Create PID controlled launcher projects for Kraken and Neo --- .../{ => src}/vendordeps/Phoenix6-26.1.0.json | 0 2026-Rebuilt/{ => src}/vendordeps/REVLib.json | 0 .../vendordeps/WPILibNewCommands.json | 0 .../.gitignore | 0 .../.vscode/launch.json | 0 .../.vscode/settings.json | 0 .../.wpilib/wpilib_preferences.json | 6 + .../WPILib-License.md | 0 .../launcher_kraken/build.gradle | 107 +++++ .../fuleintake}/.gitignore | 0 .../fuleintake}/.vscode/launch.json | 0 .../fuleintake}/.vscode/settings.json | 0 .../.wpilib/wpilib_preferences.json | 0 .../fuleintake}/WPILib-License.md | 0 .../fuleintake/build.gradle | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../{ => launcher_kraken}/fuleintake/gradlew | 0 .../fuleintake/gradlew.bat | 0 .../fuleintake/settings.gradle | 0 .../fuleintake/src/main/deploy/example.txt | 0 .../src/main/java/frc/robot/Main.java | 0 .../src/main/java/frc/robot/Robot.java | 0 .../vendordeps/WPILibNewCommands.json | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../launcher_v1 => launcher_kraken}/gradlew | 0 .../gradlew.bat | 0 .../settings.gradle | 0 .../src/main/deploy/example.txt | 0 .../src/main/java/frc/robot/Constants.java | 37 ++ .../src/main/java/frc/robot/Main.java | 0 .../src/main/java/frc/robot/Mechanisms.java | 58 +++ .../src/main/java/frc/robot/Robot.java | 105 ++++ .../main/java/frc/robot/sim/PhysicsSim.java | 81 ++++ .../java/frc/robot/sim/TalonFXSimProfile.java | 57 +++ .../vendordeps/Phoenix6-frc2026-latest.json | 449 ++++++++++++++++++ .../vendordeps/WPILibNewCommands.json | 0 prototype_projects/launcher_neo/.gitignore | 187 ++++++++ .../launcher_neo/.vscode/launch.json | 21 + .../launcher_neo/.vscode/settings.json | 60 +++ .../.wpilib/wpilib_preferences.json | 6 + prototype_projects/launcher_neo/README.md | 31 ++ .../launcher_neo/WPILib-License.md | 24 + .../launcher_neo/advantageScope.json | 99 ++++ .../launcher_v1 => launcher_neo}/build.gradle | 0 .../launcher_neo/elastic/launcher.json | 102 ++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + prototype_projects/launcher_neo/gradlew | 252 ++++++++++ prototype_projects/launcher_neo/gradlew.bat | 94 ++++ .../launcher_neo/settings.gradle | 30 ++ .../launcher_neo/shuffleboard.json | 135 ++++++ .../launcher_neo/src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Constants.java | 30 ++ .../src/main/java/frc/robot/Main.java | 29 ++ .../src/main/java/frc/robot/Robot.java | 117 +++++ .../launcher_neo/vendordeps/REVLib.json | 133 ++++++ .../vendordeps/WPILibNewCommands.json | 39 ++ prototype_projects/launcher_v1/.gitignore | 187 ++++++++ .../launcher_v1/.vscode/launch.json | 21 + .../launcher_v1/.vscode/settings.json | 61 +++ .../.wpilib/wpilib_preferences.json | 0 .../launcher_v1/WPILib-License.md | 24 + prototype_projects/launcher_v1/build.gradle | 107 +++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43583 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + prototype_projects/launcher_v1/gradlew | 252 ++++++++++ prototype_projects/launcher_v1/gradlew.bat | 94 ++++ .../launcher_v1/settings.gradle | 30 ++ .../launcher_v1/src/main/deploy/example.txt | 3 + .../src/main/java/frc/robot/Constants.java | 0 .../src/main/java/frc/robot/Main.java | 25 + .../src/main/java/frc/robot/Robot.java | 0 .../main/java/frc/robot/RobotContainer.java | 0 .../main/java/frc/robot/commands/Autos.java | 0 .../frc/robot/commands/ExampleCommand.java | 0 .../robot/subsystems/LauncherSubsystem.java} | 0 .../vendordeps/Phoenix6-26.1.0.json | 0 .../{launcher_v1 => }/vendordeps/REVLib.json | 0 .../vendordeps/WPILibNewCommands.json | 39 ++ 81 files changed, 3149 insertions(+) rename 2026-Rebuilt/{ => src}/vendordeps/Phoenix6-26.1.0.json (100%) rename 2026-Rebuilt/{ => src}/vendordeps/REVLib.json (100%) rename 2026-Rebuilt/{ => src}/vendordeps/WPILibNewCommands.json (100%) rename prototype_projects/{fuleintake => launcher_kraken}/.gitignore (100%) rename prototype_projects/{fuleintake => launcher_kraken}/.vscode/launch.json (100%) rename prototype_projects/{fuleintake => launcher_kraken}/.vscode/settings.json (100%) create mode 100644 prototype_projects/launcher_kraken/.wpilib/wpilib_preferences.json rename prototype_projects/{fuleintake => launcher_kraken}/WPILib-License.md (100%) create mode 100644 prototype_projects/launcher_kraken/build.gradle rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken/fuleintake}/.gitignore (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken/fuleintake}/.vscode/launch.json (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken/fuleintake}/.vscode/settings.json (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/.wpilib/wpilib_preferences.json (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken/fuleintake}/WPILib-License.md (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/build.gradle (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/gradle/wrapper/gradle-wrapper.jar (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/gradle/wrapper/gradle-wrapper.properties (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/gradlew (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/gradlew.bat (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/settings.gradle (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/src/main/deploy/example.txt (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/src/main/java/frc/robot/Main.java (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/src/main/java/frc/robot/Robot.java (100%) rename prototype_projects/{ => launcher_kraken}/fuleintake/vendordeps/WPILibNewCommands.json (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/gradle/wrapper/gradle-wrapper.jar (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/gradle/wrapper/gradle-wrapper.properties (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/gradlew (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/gradlew.bat (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/settings.gradle (100%) rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/src/main/deploy/example.txt (100%) create mode 100644 prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/src/main/java/frc/robot/Main.java (100%) create mode 100644 prototype_projects/launcher_kraken/src/main/java/frc/robot/Mechanisms.java create mode 100644 prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/PhysicsSim.java create mode 100644 prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/TalonFXSimProfile.java create mode 100644 prototype_projects/launcher_kraken/vendordeps/Phoenix6-frc2026-latest.json rename prototype_projects/{launcher_v1/launcher_v1 => launcher_kraken}/vendordeps/WPILibNewCommands.json (100%) create mode 100644 prototype_projects/launcher_neo/.gitignore create mode 100644 prototype_projects/launcher_neo/.vscode/launch.json create mode 100644 prototype_projects/launcher_neo/.vscode/settings.json create mode 100644 prototype_projects/launcher_neo/.wpilib/wpilib_preferences.json create mode 100644 prototype_projects/launcher_neo/README.md create mode 100644 prototype_projects/launcher_neo/WPILib-License.md create mode 100644 prototype_projects/launcher_neo/advantageScope.json rename prototype_projects/{launcher_v1/launcher_v1 => launcher_neo}/build.gradle (100%) create mode 100644 prototype_projects/launcher_neo/elastic/launcher.json create mode 100644 prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/launcher_neo/gradlew create mode 100644 prototype_projects/launcher_neo/gradlew.bat create mode 100644 prototype_projects/launcher_neo/settings.gradle create mode 100644 prototype_projects/launcher_neo/shuffleboard.json create mode 100644 prototype_projects/launcher_neo/src/main/deploy/example.txt create mode 100644 prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java create mode 100644 prototype_projects/launcher_neo/src/main/java/frc/robot/Main.java create mode 100644 prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java create mode 100644 prototype_projects/launcher_neo/vendordeps/REVLib.json create mode 100644 prototype_projects/launcher_neo/vendordeps/WPILibNewCommands.json create mode 100644 prototype_projects/launcher_v1/.gitignore create mode 100644 prototype_projects/launcher_v1/.vscode/launch.json create mode 100644 prototype_projects/launcher_v1/.vscode/settings.json rename prototype_projects/launcher_v1/{launcher_v1 => }/.wpilib/wpilib_preferences.json (100%) create mode 100644 prototype_projects/launcher_v1/WPILib-License.md create mode 100644 prototype_projects/launcher_v1/build.gradle create mode 100644 prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.jar create mode 100644 prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.properties create mode 100644 prototype_projects/launcher_v1/gradlew create mode 100644 prototype_projects/launcher_v1/gradlew.bat create mode 100644 prototype_projects/launcher_v1/settings.gradle create mode 100644 prototype_projects/launcher_v1/src/main/deploy/example.txt rename prototype_projects/launcher_v1/{launcher_v1 => }/src/main/java/frc/robot/Constants.java (100%) create mode 100644 prototype_projects/launcher_v1/src/main/java/frc/robot/Main.java rename prototype_projects/launcher_v1/{launcher_v1 => }/src/main/java/frc/robot/Robot.java (100%) rename prototype_projects/launcher_v1/{launcher_v1 => }/src/main/java/frc/robot/RobotContainer.java (100%) rename prototype_projects/launcher_v1/{launcher_v1 => }/src/main/java/frc/robot/commands/Autos.java (100%) rename prototype_projects/launcher_v1/{launcher_v1 => }/src/main/java/frc/robot/commands/ExampleCommand.java (100%) rename prototype_projects/launcher_v1/{launcher_v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java => src/main/java/frc/robot/subsystems/LauncherSubsystem.java} (100%) rename prototype_projects/launcher_v1/{launcher_v1 => }/vendordeps/Phoenix6-26.1.0.json (100%) rename prototype_projects/launcher_v1/{launcher_v1 => }/vendordeps/REVLib.json (100%) create mode 100644 prototype_projects/launcher_v1/vendordeps/WPILibNewCommands.json diff --git a/2026-Rebuilt/vendordeps/Phoenix6-26.1.0.json b/2026-Rebuilt/src/vendordeps/Phoenix6-26.1.0.json similarity index 100% rename from 2026-Rebuilt/vendordeps/Phoenix6-26.1.0.json rename to 2026-Rebuilt/src/vendordeps/Phoenix6-26.1.0.json diff --git a/2026-Rebuilt/vendordeps/REVLib.json b/2026-Rebuilt/src/vendordeps/REVLib.json similarity index 100% rename from 2026-Rebuilt/vendordeps/REVLib.json rename to 2026-Rebuilt/src/vendordeps/REVLib.json diff --git a/2026-Rebuilt/vendordeps/WPILibNewCommands.json b/2026-Rebuilt/src/vendordeps/WPILibNewCommands.json similarity index 100% rename from 2026-Rebuilt/vendordeps/WPILibNewCommands.json rename to 2026-Rebuilt/src/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/fuleintake/.gitignore b/prototype_projects/launcher_kraken/.gitignore similarity index 100% rename from prototype_projects/fuleintake/.gitignore rename to prototype_projects/launcher_kraken/.gitignore diff --git a/prototype_projects/fuleintake/.vscode/launch.json b/prototype_projects/launcher_kraken/.vscode/launch.json similarity index 100% rename from prototype_projects/fuleintake/.vscode/launch.json rename to prototype_projects/launcher_kraken/.vscode/launch.json diff --git a/prototype_projects/fuleintake/.vscode/settings.json b/prototype_projects/launcher_kraken/.vscode/settings.json similarity index 100% rename from prototype_projects/fuleintake/.vscode/settings.json rename to prototype_projects/launcher_kraken/.vscode/settings.json diff --git a/prototype_projects/launcher_kraken/.wpilib/wpilib_preferences.json b/prototype_projects/launcher_kraken/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..eadec71 --- /dev/null +++ b/prototype_projects/launcher_kraken/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 7762 +} diff --git a/prototype_projects/fuleintake/WPILib-License.md b/prototype_projects/launcher_kraken/WPILib-License.md similarity index 100% rename from prototype_projects/fuleintake/WPILib-License.md rename to prototype_projects/launcher_kraken/WPILib-License.md diff --git a/prototype_projects/launcher_kraken/build.gradle b/prototype_projects/launcher_kraken/build.gradle new file mode 100644 index 0000000..e9b0020 --- /dev/null +++ b/prototype_projects/launcher_kraken/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/launcher_v1/launcher_v1/.gitignore b/prototype_projects/launcher_kraken/fuleintake/.gitignore similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/.gitignore rename to prototype_projects/launcher_kraken/fuleintake/.gitignore diff --git a/prototype_projects/launcher_v1/launcher_v1/.vscode/launch.json b/prototype_projects/launcher_kraken/fuleintake/.vscode/launch.json similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/.vscode/launch.json rename to prototype_projects/launcher_kraken/fuleintake/.vscode/launch.json diff --git a/prototype_projects/launcher_v1/launcher_v1/.vscode/settings.json b/prototype_projects/launcher_kraken/fuleintake/.vscode/settings.json similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/.vscode/settings.json rename to prototype_projects/launcher_kraken/fuleintake/.vscode/settings.json diff --git a/prototype_projects/fuleintake/.wpilib/wpilib_preferences.json b/prototype_projects/launcher_kraken/fuleintake/.wpilib/wpilib_preferences.json similarity index 100% rename from prototype_projects/fuleintake/.wpilib/wpilib_preferences.json rename to prototype_projects/launcher_kraken/fuleintake/.wpilib/wpilib_preferences.json diff --git a/prototype_projects/launcher_v1/launcher_v1/WPILib-License.md b/prototype_projects/launcher_kraken/fuleintake/WPILib-License.md similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/WPILib-License.md rename to prototype_projects/launcher_kraken/fuleintake/WPILib-License.md diff --git a/prototype_projects/fuleintake/build.gradle b/prototype_projects/launcher_kraken/fuleintake/build.gradle similarity index 100% rename from prototype_projects/fuleintake/build.gradle rename to prototype_projects/launcher_kraken/fuleintake/build.gradle diff --git a/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/launcher_kraken/fuleintake/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.jar rename to prototype_projects/launcher_kraken/fuleintake/gradle/wrapper/gradle-wrapper.jar diff --git a/prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/launcher_kraken/fuleintake/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from prototype_projects/fuleintake/gradle/wrapper/gradle-wrapper.properties rename to prototype_projects/launcher_kraken/fuleintake/gradle/wrapper/gradle-wrapper.properties diff --git a/prototype_projects/fuleintake/gradlew b/prototype_projects/launcher_kraken/fuleintake/gradlew similarity index 100% rename from prototype_projects/fuleintake/gradlew rename to prototype_projects/launcher_kraken/fuleintake/gradlew diff --git a/prototype_projects/fuleintake/gradlew.bat b/prototype_projects/launcher_kraken/fuleintake/gradlew.bat similarity index 100% rename from prototype_projects/fuleintake/gradlew.bat rename to prototype_projects/launcher_kraken/fuleintake/gradlew.bat diff --git a/prototype_projects/fuleintake/settings.gradle b/prototype_projects/launcher_kraken/fuleintake/settings.gradle similarity index 100% rename from prototype_projects/fuleintake/settings.gradle rename to prototype_projects/launcher_kraken/fuleintake/settings.gradle diff --git a/prototype_projects/fuleintake/src/main/deploy/example.txt b/prototype_projects/launcher_kraken/fuleintake/src/main/deploy/example.txt similarity index 100% rename from prototype_projects/fuleintake/src/main/deploy/example.txt rename to prototype_projects/launcher_kraken/fuleintake/src/main/deploy/example.txt diff --git a/prototype_projects/fuleintake/src/main/java/frc/robot/Main.java b/prototype_projects/launcher_kraken/fuleintake/src/main/java/frc/robot/Main.java similarity index 100% rename from prototype_projects/fuleintake/src/main/java/frc/robot/Main.java rename to prototype_projects/launcher_kraken/fuleintake/src/main/java/frc/robot/Main.java diff --git a/prototype_projects/fuleintake/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_kraken/fuleintake/src/main/java/frc/robot/Robot.java similarity index 100% rename from prototype_projects/fuleintake/src/main/java/frc/robot/Robot.java rename to prototype_projects/launcher_kraken/fuleintake/src/main/java/frc/robot/Robot.java diff --git a/prototype_projects/fuleintake/vendordeps/WPILibNewCommands.json b/prototype_projects/launcher_kraken/fuleintake/vendordeps/WPILibNewCommands.json similarity index 100% rename from prototype_projects/fuleintake/vendordeps/WPILibNewCommands.json rename to prototype_projects/launcher_kraken/fuleintake/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/launcher_kraken/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.jar rename to prototype_projects/launcher_kraken/gradle/wrapper/gradle-wrapper.jar diff --git a/prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/launcher_kraken/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/gradle/wrapper/gradle-wrapper.properties rename to prototype_projects/launcher_kraken/gradle/wrapper/gradle-wrapper.properties diff --git a/prototype_projects/launcher_v1/launcher_v1/gradlew b/prototype_projects/launcher_kraken/gradlew similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/gradlew rename to prototype_projects/launcher_kraken/gradlew diff --git a/prototype_projects/launcher_v1/launcher_v1/gradlew.bat b/prototype_projects/launcher_kraken/gradlew.bat similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/gradlew.bat rename to prototype_projects/launcher_kraken/gradlew.bat diff --git a/prototype_projects/launcher_v1/launcher_v1/settings.gradle b/prototype_projects/launcher_kraken/settings.gradle similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/settings.gradle rename to prototype_projects/launcher_kraken/settings.gradle diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/deploy/example.txt b/prototype_projects/launcher_kraken/src/main/deploy/example.txt similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/deploy/example.txt rename to prototype_projects/launcher_kraken/src/main/deploy/example.txt diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..497bcd2 --- /dev/null +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java @@ -0,0 +1,37 @@ +// 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; + + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + + public static class LauncherConstants { + public static final int kMotorCANID = 40; + + // These numbers came from the ctre example then tweaked + public static final double kS = 0.1; // A velocity target of 1 rps results in xV output + public static final double kV = 0.12; // Add x V output to overcome static friction + public static final double kP = 0.11; // An error of 1 rotation results in x V output + public static final double kI = 0.0; + public static final double kD = 0.0; // A velocity of 1 rps results in x V output + public static final double kA_linear = 0.01; // Voltage needed to induce a given accel. in the motor shaft + public static final double kA_angular = 0.01; // TODO: We need to measure this! + public static final double kPeakVoltage = 8.0; + + public static final double kMaxVelocityRPS = 6000.0/60.0; + public static final double kMaxAccelerationRPS2 = 50.0; + + public static final double kMotionMagicAcceleration = 50.0; // Higher number --> Faster (50.0 = ~1s to max) + public static final double kMotionMagicJerk = 4000.0; + } +} diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Main.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Main.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Main.java rename to prototype_projects/launcher_kraken/src/main/java/frc/robot/Main.java diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Mechanisms.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Mechanisms.java new file mode 100644 index 0000000..572e396 --- /dev/null +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Mechanisms.java @@ -0,0 +1,58 @@ +package frc.robot; + +import static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.StatusSignal; + +import edu.wpi.first.units.measure.Angle; +import edu.wpi.first.units.measure.AngularVelocity; +import edu.wpi.first.wpilibj.smartdashboard.Mechanism2d; +import edu.wpi.first.wpilibj.smartdashboard.MechanismLigament2d; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj.util.Color; +import edu.wpi.first.wpilibj.util.Color8Bit; + +/** + * Class to keep all the mechanism-specific objects together and out of the main example + */ +public class Mechanisms { + double HEIGHT = 1; // Controls the height of the mech2d SmartDashboard + double WIDTH = 1; // Controls the height of the mech2d SmartDashboard + + Mechanism2d mech = new Mechanism2d(WIDTH, HEIGHT); + // Velocity + MechanismLigament2d VelocityMech = mech. + getRoot("velocityLineReferencePosition", 0.75, 0.5). + append(new MechanismLigament2d("velocityLine", 1,90, 6, new Color8Bit(Color.kAliceBlue))); + + MechanismLigament2d midline = mech. + getRoot("midline", 0.7, 0.5). + append(new MechanismLigament2d("midline", 0.1, 0, 3, new Color8Bit(Color.kCyan))); + + //Position + MechanismLigament2d arm = mech. + getRoot("pivotPoint", 0.25, 0.5). + append(new MechanismLigament2d("arm", .2, 0, 0, new Color8Bit(Color.kAliceBlue))); + + MechanismLigament2d side1 = arm.append(new MechanismLigament2d("side1", 0.15307, 112.5, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side2 = side1.append(new MechanismLigament2d("side2", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side3 = side2.append(new MechanismLigament2d("side3", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side4 = side3.append(new MechanismLigament2d("side4", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side5 = side4.append(new MechanismLigament2d("side5", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side6 = side5.append(new MechanismLigament2d("side6", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side7 = side6.append(new MechanismLigament2d("side7", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + MechanismLigament2d side8 = side7.append(new MechanismLigament2d("side8", 0.15307, 45, 6, new Color8Bit(Color.kAliceBlue))); + + /** + * Runs the mech2d widget in GUI. + * + * This utilizes GUI to simulate and display a TalonFX and exists to allow users to test and understand + * features of our products in simulation using our examples out of the box. Users may modify to have a + * display interface that they find more intuitive or visually appealing. + */ + public void update(StatusSignal position, StatusSignal velocity) { + VelocityMech.setLength(velocity.getValue().in(RotationsPerSecond)/120); + arm.setAngle(position.getValue().in(Rotations) * 360); // Divide by 120 to scale motion to fit in the window + SmartDashboard.putData("mech2d", mech); // Creates mech2d in SmartDashboard + } +} diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..b320ea0 --- /dev/null +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java @@ -0,0 +1,105 @@ +// 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 static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.StatusCode; +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.MotionMagicVelocityVoltage; +import com.ctre.phoenix6.hardware.TalonFX; +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.XboxController; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import frc.robot.Constants.LauncherConstants; + +/** + * The VM is configured to automatically run this class, and to call the functions corresponding to + * each mode, as described in the TimedRobot documentation. If you change the name of this class or + * the package after creating this project, you must also update the build.gradle file in the + * project. + */ +public class Robot extends TimedRobot { + private final TalonFX m_fx = new TalonFX(LauncherConstants.kMotorCANID); + + /* Be able to switch which control request to use based on a button press */ + /* Start at velocity 0, use slot 0 */ + private final MotionMagicVelocityVoltage m_velocityVoltage = new MotionMagicVelocityVoltage(0).withSlot(0); + private final XboxController m_joystick = new XboxController(0); + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + public Robot() { + TalonFXConfiguration configs = new TalonFXConfiguration(); + + /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ + configs.Slot0.kS = LauncherConstants.kS; // To account for friction, add 0.1 V of static feedforward + configs.Slot0.kV = LauncherConstants.kV; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second + configs.Slot0.kP = LauncherConstants.kP; // An error of 1 rotation per second results in 0.11 V output + configs.Slot0.kI = LauncherConstants.kI; // No output for integrated error + configs.Slot0.kD = LauncherConstants.kD; // No output for error derivative + // Peak output of 8 volts + configs.Voltage.withPeakForwardVoltage(Volts.of(8)) + .withPeakReverseVoltage(Volts.of(-8)); + + var motionMagicConfigs = configs.MotionMagic; + motionMagicConfigs.MotionMagicAcceleration = LauncherConstants.kMotionMagicAcceleration; + motionMagicConfigs.MotionMagicJerk = LauncherConstants.kMotionMagicJerk; + + /* Retry config apply up to 5 times, report if failure */ + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = m_fx.getConfigurator().apply(configs); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs, error code: " + status.toString()); + } + + SmartDashboard.putNumber("desired RPS", 0); + SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); + } + + @Override + public void robotPeriodic() { + } + + @Override + public void autonomousInit() {} + + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() {} + + @Override + public void teleopPeriodic() { + double joyValue = m_joystick.getLeftY(); + if (Math.abs(joyValue) < 0.1) joyValue = 0; + + double desiredRotationsPerSecond = joyValue * (6000/60); // Control motor from -6000 to +6000 rpm + + /* Use velocity voltage */ + m_fx.setControl(m_velocityVoltage.withVelocity(desiredRotationsPerSecond)); + + SmartDashboard.putNumber("desired RPS", desiredRotationsPerSecond); + SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); + } + + @Override + public void disabledInit() {} + + @Override + public void disabledPeriodic() {} + + @Override + public void testInit() {} + + @Override + public void testPeriodic() {} +} diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/PhysicsSim.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/PhysicsSim.java new file mode 100644 index 0000000..6000bca --- /dev/null +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/PhysicsSim.java @@ -0,0 +1,81 @@ +package frc.robot.sim; + +import java.util.ArrayList; + +import com.ctre.phoenix6.Utils; +import com.ctre.phoenix6.hardware.TalonFX; + +/** + * Manages physics simulation for CTRE products. + */ +public class PhysicsSim { + private static final PhysicsSim sim = new PhysicsSim(); + + /** + * Gets the robot simulator instance. + */ + public static PhysicsSim getInstance() { + return sim; + } + + /** + * Adds a TalonFX controller to the simulator. + * + * @param talonFX + * The TalonFX device + * @param rotorInertia + * Rotational Inertia of the mechanism at the rotor + */ + public void addTalonFX(TalonFX talonFX, final double rotorInertia) { + if (talonFX != null) { + TalonFXSimProfile simTalonFX = new TalonFXSimProfile(talonFX, rotorInertia); + _simProfiles.add(simTalonFX); + } + } + + /** + * Runs the simulator: + * - enable the robot + * - simulate sensors + */ + public void run() { + // Simulate devices + for (SimProfile simProfile : _simProfiles) { + simProfile.run(); + } + } + + private final ArrayList _simProfiles = new ArrayList(); + + /** + * Holds information about a simulated device. + */ + static class SimProfile { + private double _lastTime; + private boolean _running = false; + + /** + * Runs the simulation profile. + * Implemented by device-specific profiles. + */ + public void run() { + } + + /** + * Returns the time since last call, in seconds. + */ + protected double getPeriod() { + // set the start time if not yet running + if (!_running) { + _lastTime = Utils.getCurrentTimeSeconds(); + _running = true; + } + + double now = Utils.getCurrentTimeSeconds(); + final double period = now - _lastTime; + _lastTime = now; + + return period; + } + } +} \ No newline at end of file diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/TalonFXSimProfile.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/TalonFXSimProfile.java new file mode 100644 index 0000000..0dc9756 --- /dev/null +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/sim/TalonFXSimProfile.java @@ -0,0 +1,57 @@ +package frc.robot.sim; + +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.sim.TalonFXSimState; + +import edu.wpi.first.math.system.plant.DCMotor; +import edu.wpi.first.math.system.plant.LinearSystemId; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.wpilibj.simulation.DCMotorSim; +import frc.robot.sim.PhysicsSim.SimProfile; + +/** + * Holds information about a simulated TalonFX. + */ +class TalonFXSimProfile extends SimProfile { + private static final double kMotorResistance = 0.002; // Assume 2mOhm resistance for voltage drop calculation + private final TalonFXSimState _talonFXSim; + private final DCMotorSim _motorSim; + + /** + * Creates a new simulation profile for a TalonFX device. + * + * @param talonFX + * The TalonFX device + * @param rotorInertia + * Rotational Inertia of the mechanism at the rotor + */ + public TalonFXSimProfile(final TalonFX talonFX, final double rotorInertia) { + var gearbox = DCMotor.getKrakenX60Foc(1); + this._motorSim = new DCMotorSim(LinearSystemId.createDCMotorSystem(gearbox, rotorInertia, 1.0), gearbox); + this._talonFXSim = talonFX.getSimState(); + } + + /** + * Runs the simulation profile. + * + * This uses very rudimentary physics simulation and exists to allow users to + * test features of our products in simulation using our examples out of the + * box. Users may modify this to utilize more accurate physics simulation. + */ + public void run() { + /// DEVICE SPEED SIMULATION + + _motorSim.setInputVoltage(_talonFXSim.getMotorVoltage()); + + _motorSim.update(getPeriod()); + + /// SET SIM PHYSICS INPUTS + final double position_rot = _motorSim.getAngularPositionRotations(); + final double velocity_rps = Units.radiansToRotations(_motorSim.getAngularVelocityRadPerSec()); + + _talonFXSim.setRawRotorPosition(position_rot); + _talonFXSim.setRotorVelocity(velocity_rps); + + _talonFXSim.setSupplyVoltage(12 - _talonFXSim.getSupplyCurrent() * kMotorResistance); + } +} \ No newline at end of file diff --git a/prototype_projects/launcher_kraken/vendordeps/Phoenix6-frc2026-latest.json b/prototype_projects/launcher_kraken/vendordeps/Phoenix6-frc2026-latest.json new file mode 100644 index 0000000..8f6e30f --- /dev/null +++ b/prototype_projects/launcher_kraken/vendordeps/Phoenix6-frc2026-latest.json @@ -0,0 +1,449 @@ +{ + "fileName": "Phoenix6-frc2026-latest.json", + "name": "CTRE-Phoenix (v6)", + "version": "26.1.0", + "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.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "api-cpp", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "linuxathena" + ], + "simMode": "hwsim" + }, + { + "groupId": "com.ctre.phoenix6", + "artifactId": "tools", + "version": "26.1.0", + "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.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "tools-sim", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simTalonSRX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simVictorSPX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simPigeonIMU", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFX", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProTalonFXS", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANcoder", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProPigeon2", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANrange", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdi", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + }, + { + "groupId": "com.ctre.phoenix6.sim", + "artifactId": "simProCANdle", + "version": "26.1.0", + "isJar": false, + "skipInvalidPlatforms": true, + "validPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ], + "cppDependencies": [ + { + "groupId": "com.ctre.phoenix6", + "artifactId": "wpiapi-cpp", + "version": "26.1.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "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.0", + "libName": "CTRE_SimProCANdle", + "headerClassifier": "headers", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxx86-64", + "linuxarm64", + "osxuniversal" + ], + "simMode": "swsim" + } + ] +} \ No newline at end of file diff --git a/prototype_projects/launcher_v1/launcher_v1/vendordeps/WPILibNewCommands.json b/prototype_projects/launcher_kraken/vendordeps/WPILibNewCommands.json similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/vendordeps/WPILibNewCommands.json rename to prototype_projects/launcher_kraken/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/launcher_neo/.gitignore b/prototype_projects/launcher_neo/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/launcher_neo/.gitignore @@ -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 diff --git a/prototype_projects/launcher_neo/.vscode/launch.json b/prototype_projects/launcher_neo/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/launcher_neo/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/launcher_neo/.vscode/settings.json b/prototype_projects/launcher_neo/.vscode/settings.json new file mode 100644 index 0000000..612cdd0 --- /dev/null +++ b/prototype_projects/launcher_neo/.vscode/settings.json @@ -0,0 +1,60 @@ +{ + "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.*", + ] +} diff --git a/prototype_projects/launcher_neo/.wpilib/wpilib_preferences.json b/prototype_projects/launcher_neo/.wpilib/wpilib_preferences.json new file mode 100644 index 0000000..6c8cf0e --- /dev/null +++ b/prototype_projects/launcher_neo/.wpilib/wpilib_preferences.json @@ -0,0 +1,6 @@ +{ + "enableCppIntellisense": false, + "currentLanguage": "java", + "projectYear": "2026", + "teamNumber": 0 +} \ No newline at end of file diff --git a/prototype_projects/launcher_neo/README.md b/prototype_projects/launcher_neo/README.md new file mode 100644 index 0000000..9e5bb97 --- /dev/null +++ b/prototype_projects/launcher_neo/README.md @@ -0,0 +1,31 @@ +# MAXMotion Example + +## Description + +This example shows how to perform both position and velocity closed loop control using MAXMotion on a SPARK motor controller. + +### Topics Covered + +* Configuring a SPARK motor controller +* Position closed loop control with MAXMotion +* Velocity closed loop control with MAXMotion +* Closed loop slots +* Retrieving encoder data +* Resetting encoder position + +## Usage + +This example assumes a SPARK MAX with a free spinning NEO. The PID values are tuned for this and should be adjusted if a different setup is being used. + + + +Deploy the program to your roboRIO and load the included `shuffleboard.json` into Shuffleboard. The Shuffleboard layout provides the following: + +* A toggle to switch between position and velocity control modes +* Input sliders to set target position or velocity +* Output sliders to show actual position and velocity +* A reset button for the encoder position + +### AdvantageScope + +To better visualize the motion profile created by MAXMotion, load the included `advantageScope.json` into AdvantageScope. The AdvantageScope layout graphs the target and actual position/velocity. diff --git a/prototype_projects/launcher_neo/WPILib-License.md b/prototype_projects/launcher_neo/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/launcher_neo/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/launcher_neo/advantageScope.json b/prototype_projects/launcher_neo/advantageScope.json new file mode 100644 index 0000000..38234c2 --- /dev/null +++ b/prototype_projects/launcher_neo/advantageScope.json @@ -0,0 +1,99 @@ +{ + "hubs": [ + { + "x": 496, + "y": 240, + "width": 1100, + "height": 650, + "state": { + "sidebar": { + "width": 193, + "expanded": [ + "/SmartDashboard" + ] + }, + "tabs": { + "selected": 1, + "tabs": [ + { + "type": 0, + "title": "", + "controller": null, + "controllerUUID": "k0nrll5jj791ndnm9k71vwish5qhrwyh", + "renderer": "#/", + "controlsHeight": 0 + }, + { + "type": 1, + "title": "Line Graph", + "controller": { + "leftSources": [ + { + "type": "stepped", + "logKey": "NT:/SmartDashboard/Actual Velocity", + "logType": "Number", + "visible": true, + "options": { + "color": "#2b66a2", + "size": "normal" + } + }, + { + "type": "stepped", + "logKey": "NT:/SmartDashboard/Target Velocity", + "logType": "Number", + "visible": true, + "options": { + "color": "#af2437", + "size": "normal" + } + } + ], + "rightSources": [ + { + "type": "stepped", + "logKey": "NT:/SmartDashboard/Actual Position", + "logType": "Number", + "visible": true, + "options": { + "color": "#e5b31b", + "size": "normal" + } + }, + { + "type": "stepped", + "logKey": "NT:/SmartDashboard/Target Position", + "logType": "Number", + "visible": true, + "options": { + "color": "#80588e", + "size": "normal" + } + } + ], + "discreteSources": [], + "leftLockedRange": null, + "rightLockedRange": null, + "leftUnitConversion": { + "type": null, + "factor": 1 + }, + "rightUnitConversion": { + "type": null, + "factor": 1 + }, + "leftFilter": 0, + "rightFilter": 0 + }, + "controllerUUID": "5y6e5qp2x5cjij2vixdlikkwfwhrgr3j", + "renderer": null, + "controlsHeight": 200 + } + ] + } + } + } + ], + "satellites": [], + "version": "4.0.0-beta-1" +} diff --git a/prototype_projects/launcher_v1/launcher_v1/build.gradle b/prototype_projects/launcher_neo/build.gradle similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/build.gradle rename to prototype_projects/launcher_neo/build.gradle diff --git a/prototype_projects/launcher_neo/elastic/launcher.json b/prototype_projects/launcher_neo/elastic/launcher.json new file mode 100644 index 0000000..abd55ce --- /dev/null +++ b/prototype_projects/launcher_neo/elastic/launcher.json @@ -0,0 +1,102 @@ +{ + "version": 1.0, + "grid_size": 128, + "tabs": [ + { + "name": "Teleoperated", + "grid_layout": { + "layouts": [], + "containers": [ + { + "title": "Actual Velocity", + "x": 0.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Actual Velocity", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Target Velocity", + "x": 128.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Target Velocity", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Reset Encoder", + "x": 256.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Reset Encoder", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Actual Velocity", + "x": 384.0, + "y": 0.0, + "width": 640.0, + "height": 384.0, + "type": "Graph", + "properties": { + "topic": "/SmartDashboard/Actual Velocity", + "period": 0.033, + "data_type": "double", + "time_displayed": 5.0, + "min_value": 0.0, + "max_value": 2000.0, + "color": 4278238420, + "line_width": 2.0 + } + }, + { + "title": "Target Velocity", + "x": 0.0, + "y": 128.0, + "width": 384.0, + "height": 256.0, + "type": "Graph", + "properties": { + "topic": "/SmartDashboard/Target Velocity", + "period": 0.033, + "data_type": "double", + "time_displayed": 5.0, + "min_value": 0.0, + "max_value": 2000.0, + "color": 4278238420, + "line_width": 2.0 + } + } + ] + } + }, + { + "name": "Autonomous", + "grid_layout": { + "layouts": [], + "containers": [] + } + } + ] +} \ No newline at end of file diff --git a/prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/launcher_neo/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/launcher_neo/gradlew b/prototype_projects/launcher_neo/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/launcher_neo/gradlew @@ -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" "$@" diff --git a/prototype_projects/launcher_neo/gradlew.bat b/prototype_projects/launcher_neo/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/launcher_neo/gradlew.bat @@ -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 diff --git a/prototype_projects/launcher_neo/settings.gradle b/prototype_projects/launcher_neo/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/launcher_neo/settings.gradle @@ -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"); diff --git a/prototype_projects/launcher_neo/shuffleboard.json b/prototype_projects/launcher_neo/shuffleboard.json new file mode 100644 index 0000000..15e9980 --- /dev/null +++ b/prototype_projects/launcher_neo/shuffleboard.json @@ -0,0 +1,135 @@ +{ + "tabPane": [ + { + "title": "SmartDashboard", + "autoPopulate": true, + "autoPopulatePrefix": "SmartDashboard/", + "widgetPane": { + "gridSize": 128.0, + "showGrid": true, + "hgap": 16.0, + "vgap": 16.0, + "titleType": 0, + "tiles": { + "0,0": { + "size": [ + 3, + 1 + ], + "content": { + "_type": "Number Slider", + "_source0": "network_table:///SmartDashboard/Target Position", + "_title": "Target Position", + "_glyph": 148, + "_showGlyph": false, + "Slider Settings/Min": 0.0, + "Slider Settings/Max": 100.0, + "Slider Settings/Block increment": 0.0625, + "Visuals/Display value": true, + "Visuals/Orientation": "HORIZONTAL" + } + }, + "4,0": { + "size": [ + 3, + 1 + ], + "content": { + "_type": "Number Slider", + "_source0": "network_table:///SmartDashboard/Target Velocity", + "_title": "Target Velocity", + "_glyph": 148, + "_showGlyph": false, + "Slider Settings/Min": -6000.0, + "Slider Settings/Max": 6000.0, + "Slider Settings/Block increment": 0.0625, + "Visuals/Display value": true, + "Visuals/Orientation": "HORIZONTAL" + } + }, + "3,0": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Toggle Switch", + "_source0": "network_table:///SmartDashboard/Control Mode", + "_title": "Control Mode", + "_glyph": 148, + "_showGlyph": false + } + }, + "0,1": { + "size": [ + 3, + 1 + ], + "content": { + "_type": "Number Slider", + "_source0": "network_table:///SmartDashboard/Actual Position", + "_title": "Actual Position", + "_glyph": 148, + "_showGlyph": false, + "Slider Settings/Min": 0.0, + "Slider Settings/Max": 100.0, + "Slider Settings/Block increment": 0.0625, + "Visuals/Display value": true, + "Visuals/Orientation": "HORIZONTAL" + } + }, + "4,1": { + "size": [ + 3, + 1 + ], + "content": { + "_type": "Number Slider", + "_source0": "network_table:///SmartDashboard/Actual Velocity", + "_title": "Actual Velocity", + "_glyph": 148, + "_showGlyph": false, + "Slider Settings/Min": -6000.0, + "Slider Settings/Max": 6000.0, + "Slider Settings/Block increment": 0.0625, + "Visuals/Display value": true, + "Visuals/Orientation": "HORIZONTAL" + } + }, + "3,1": { + "size": [ + 1, + 1 + ], + "content": { + "_type": "Toggle Button", + "_source0": "network_table:///SmartDashboard/Reset Encoder", + "_title": "Reset Encoder", + "_glyph": 148, + "_showGlyph": false + } + } + } + } + }, + { + "title": "LiveWindow", + "autoPopulate": true, + "autoPopulatePrefix": "LiveWindow/", + "widgetPane": { + "gridSize": 128.0, + "showGrid": true, + "hgap": 16.0, + "vgap": 16.0, + "titleType": 0, + "tiles": {} + } + } + ], + "windowGeometry": { + "x": -8.0, + "y": -8.0, + "width": 1936.0, + "height": 1048.0 + } +} \ No newline at end of file diff --git a/prototype_projects/launcher_neo/src/main/deploy/example.txt b/prototype_projects/launcher_neo/src/main/deploy/example.txt new file mode 100644 index 0000000..70c79b6 --- /dev/null +++ b/prototype_projects/launcher_neo/src/main/deploy/example.txt @@ -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 'FileUtilities.getFilePath' wpilib function +to get a proper path relative to the deploy directory. \ No newline at end of file diff --git a/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java b/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..c63b570 --- /dev/null +++ b/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java @@ -0,0 +1,30 @@ +// 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; + + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + + public static class LauncherConstants { + public static final int kMotorCANID = 50; + + // These numbers came from the ctre example then tweaked + public static final double kP = 0.0001; // An error of 1 rotation results in x V output + public static final double kI = 0.0; + public static final double kD = 0.0; // A velocity of 1 rps results in x V output + public static final double kV = (12.0/40000.0); // (12.0/5767); // Copied from basic REV example! + public static final double kCruiseVelocityRPM = 5000.0; + public static final double kAllowedErrorR = 1.0; + public static final double kMaxAccelerationRPMPS = 1000.0; + } +} diff --git a/prototype_projects/launcher_neo/src/main/java/frc/robot/Main.java b/prototype_projects/launcher_neo/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..5b3238a --- /dev/null +++ b/prototype_projects/launcher_neo/src/main/java/frc/robot/Main.java @@ -0,0 +1,29 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2018 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. + * Unless you know what you are doing, do not modify this file except to + * change the parameter class to the startRobot call. + */ +public final class Main { + private Main() { + } + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java new file mode 100644 index 0000000..e966f46 --- /dev/null +++ b/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java @@ -0,0 +1,117 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +// Based on the REV Robotics MaxMotion example application. + +package frc.robot; + +import edu.wpi.first.wpilibj.TimedRobot; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import frc.robot.Constants.LauncherConstants; + +import com.revrobotics.PersistMode; +import com.revrobotics.RelativeEncoder; +import com.revrobotics.ResetMode; +import com.revrobotics.spark.SparkLowLevel.MotorType; +import com.revrobotics.spark.SparkClosedLoopController; +import com.revrobotics.spark.SparkMax; +import com.revrobotics.spark.SparkBase.ControlType; +import com.revrobotics.spark.config.SparkMaxConfig; +import com.revrobotics.spark.ClosedLoopSlot; +import com.revrobotics.spark.FeedbackSensor; + +public class Robot extends TimedRobot { + private SparkMax motor; + private SparkMaxConfig motorConfig; + private SparkClosedLoopController closedLoopController; + private RelativeEncoder encoder; + + public Robot() { + /* + * Initialize the SPARK MAX and get its encoder and closed loop controller + * objects for later use. + */ + motor = new SparkMax(LauncherConstants.kMotorCANID, MotorType.kBrushless); + closedLoopController = motor.getClosedLoopController(); + encoder = motor.getEncoder(); + + /* + * Create a new SPARK MAX configuration object. This will store the + * configuration parameters for the SPARK MAX that we will set below. + */ + motorConfig = new SparkMaxConfig(); + + /* + * Configure the encoder. For this specific example, we are using the + * integrated encoder of the NEO, and we don't need to configure it. If + * needed, we can adjust values like the position or velocity conversion + * factors. + */ + motorConfig.encoder.velocityConversionFactor(1); + + /* + * Configure the closed loop controller. We want to make sure we set the + * feedback sensor as the primary encoder. + */ + motorConfig.closedLoop + .feedbackSensor(FeedbackSensor.kPrimaryEncoder) + // Set PID values for velocity control in slot 1 + .p(LauncherConstants.kP, ClosedLoopSlot.kSlot1) + .i(LauncherConstants.kI, ClosedLoopSlot.kSlot1) + .d(LauncherConstants.kD, ClosedLoopSlot.kSlot1) + .outputRange(-1, 1, ClosedLoopSlot.kSlot1) + .feedForward + // kV is now in Volts, so we multiply by the nominal voltage (12V) + .kV(LauncherConstants.kV, ClosedLoopSlot.kSlot1); + + motorConfig.closedLoop.maxMotion + // Set MAXMotion parameters for velocity control in slot 1 + .maxAcceleration(LauncherConstants.kMaxAccelerationRPMPS, ClosedLoopSlot.kSlot1) + .cruiseVelocity(6000, ClosedLoopSlot.kSlot1) + .allowedProfileError(1, ClosedLoopSlot.kSlot1); + + /* + * Apply the configuration to the SPARK MAX. + * + * kResetSafeParameters is used to get the SPARK MAX to a known state. This + * is useful in case the SPARK MAX is replaced. + * + * kPersistParameters is used to ensure the configuration is not lost when + * the SPARK MAX loses power. This is useful for power cycles that may occur + * mid-operation. + */ + motor.configure(motorConfig, ResetMode.kResetSafeParameters, PersistMode.kNoPersistParameters); + + // Initialize dashboard values + SmartDashboard.setDefaultNumber("Target Velocity", 0); + SmartDashboard.setDefaultBoolean("Reset Encoder", false); + } + + @Override + public void teleopPeriodic() { + /* + * Get the target velocity from SmartDashboard and set it as the setpoint + * for the closed loop controller with MAXMotionVelocityControl as the + * control type. + */ + double targetVelocity = SmartDashboard.getNumber("Target Velocity", 0); + closedLoopController.setSetpoint(targetVelocity, ControlType.kMAXMotionVelocityControl, + ClosedLoopSlot.kSlot1); + } + + @Override + public void robotPeriodic() { + // Display encoder position and velocity + SmartDashboard.putNumber("Actual Velocity", encoder.getVelocity()); + + if (SmartDashboard.getBoolean("Reset Encoder", false)) { + SmartDashboard.putBoolean("Reset Encoder", false); + // Reset the encoder position to 0 + encoder.setPosition(0); + } + } +} diff --git a/prototype_projects/launcher_neo/vendordeps/REVLib.json b/prototype_projects/launcher_neo/vendordeps/REVLib.json new file mode 100644 index 0000000..4f96af8 --- /dev/null +++ b/prototype_projects/launcher_neo/vendordeps/REVLib.json @@ -0,0 +1,133 @@ +{ + "fileName": "REVLib.json", + "name": "REVLib", + "version": "2026.0.0", + "frcYear": "2026", + "uuid": "3f48eb8c-50fe-43a6-9cb7-44c86353c4cb", + "mavenUrls": [ + "https://maven.revrobotics.com/" + ], + "jsonUrl": "https://software-metadata.revrobotics.com/REVLib-2026.json", + "javaDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-java", + "version": "2026.0.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-cpp", + "version": "2026.0.0", + "libName": "REVLib", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "REVLib-driver", + "version": "2026.0.0", + "libName": "REVLibDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibBackendDriver", + "version": "2026.0.0", + "libName": "BackendDriver", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.revrobotics.frc", + "artifactId": "RevLibWpiBackendDriver", + "version": "2026.0.0", + "libName": "REVLibWpi", + "sharedLibrary": true, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/prototype_projects/launcher_neo/vendordeps/WPILibNewCommands.json b/prototype_projects/launcher_neo/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/launcher_neo/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} diff --git a/prototype_projects/launcher_v1/.gitignore b/prototype_projects/launcher_v1/.gitignore new file mode 100644 index 0000000..34cbaac --- /dev/null +++ b/prototype_projects/launcher_v1/.gitignore @@ -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 diff --git a/prototype_projects/launcher_v1/.vscode/launch.json b/prototype_projects/launcher_v1/.vscode/launch.json new file mode 100644 index 0000000..c9c9713 --- /dev/null +++ b/prototype_projects/launcher_v1/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "wpilib", + "name": "WPILib Desktop Debug", + "request": "launch", + "desktop": true, + }, + { + "type": "wpilib", + "name": "WPILib roboRIO Debug", + "request": "launch", + "desktop": false, + } + ] +} diff --git a/prototype_projects/launcher_v1/.vscode/settings.json b/prototype_projects/launcher_v1/.vscode/settings.json new file mode 100644 index 0000000..5e6ede8 --- /dev/null +++ b/prototype_projects/launcher_v1/.vscode/settings.json @@ -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 +} diff --git a/prototype_projects/launcher_v1/launcher_v1/.wpilib/wpilib_preferences.json b/prototype_projects/launcher_v1/.wpilib/wpilib_preferences.json similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/.wpilib/wpilib_preferences.json rename to prototype_projects/launcher_v1/.wpilib/wpilib_preferences.json diff --git a/prototype_projects/launcher_v1/WPILib-License.md b/prototype_projects/launcher_v1/WPILib-License.md new file mode 100644 index 0000000..eb3061b --- /dev/null +++ b/prototype_projects/launcher_v1/WPILib-License.md @@ -0,0 +1,24 @@ +Copyright (c) 2009-2026 FIRST and other WPILib contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of FIRST, WPILib, nor the names of other WPILib + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/prototype_projects/launcher_v1/build.gradle b/prototype_projects/launcher_v1/build.gradle new file mode 100644 index 0000000..f2ceadb --- /dev/null +++ b/prototype_projects/launcher_v1/build.gradle @@ -0,0 +1,107 @@ +plugins { + id "java" + id "edu.wpi.first.GradleRIO" version "2026.1.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 = false + +// 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('src') { into 'backup/src' } + from('vendordeps') { into 'backup/vendordeps' } + from('build.gradle') { into 'backup' } + 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' +} diff --git a/prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.jar b/prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..a4b76b9530d66f5e68d973ea569d8e19de379189 GIT binary patch literal 43583 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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 GZ~q4|mN%#X literal 0 HcmV?d00001 diff --git a/prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.properties b/prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..34bd9ce --- /dev/null +++ b/prototype_projects/launcher_v1/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/prototype_projects/launcher_v1/gradlew b/prototype_projects/launcher_v1/gradlew new file mode 100644 index 0000000..f5feea6 --- /dev/null +++ b/prototype_projects/launcher_v1/gradlew @@ -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" "$@" diff --git a/prototype_projects/launcher_v1/gradlew.bat b/prototype_projects/launcher_v1/gradlew.bat new file mode 100644 index 0000000..9d21a21 --- /dev/null +++ b/prototype_projects/launcher_v1/gradlew.bat @@ -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 diff --git a/prototype_projects/launcher_v1/settings.gradle b/prototype_projects/launcher_v1/settings.gradle new file mode 100644 index 0000000..25f6f6e --- /dev/null +++ b/prototype_projects/launcher_v1/settings.gradle @@ -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"); diff --git a/prototype_projects/launcher_v1/src/main/deploy/example.txt b/prototype_projects/launcher_v1/src/main/deploy/example.txt new file mode 100644 index 0000000..bb82515 --- /dev/null +++ b/prototype_projects/launcher_v1/src/main/deploy/example.txt @@ -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. \ No newline at end of file diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Constants.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/Constants.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Constants.java rename to prototype_projects/launcher_v1/src/main/java/frc/robot/Constants.java diff --git a/prototype_projects/launcher_v1/src/main/java/frc/robot/Main.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/Main.java new file mode 100644 index 0000000..8776e5d --- /dev/null +++ b/prototype_projects/launcher_v1/src/main/java/frc/robot/Main.java @@ -0,0 +1,25 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import edu.wpi.first.wpilibj.RobotBase; + +/** + * Do NOT add any static variables to this class, or any initialization at all. Unless you know what + * you are doing, do not modify this file except to change the parameter class to the startRobot + * call. + */ +public final class Main { + private Main() {} + + /** + * Main initialization function. Do not perform any initialization here. + * + *

If you change your main robot class, change the parameter type. + */ + public static void main(String... args) { + RobotBase.startRobot(Robot::new); + } +} diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/Robot.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/Robot.java rename to prototype_projects/launcher_v1/src/main/java/frc/robot/Robot.java diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/RobotContainer.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/RobotContainer.java rename to prototype_projects/launcher_v1/src/main/java/frc/robot/RobotContainer.java diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/Autos.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/commands/Autos.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/Autos.java rename to prototype_projects/launcher_v1/src/main/java/frc/robot/commands/Autos.java diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/ExampleCommand.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/commands/ExampleCommand.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/commands/ExampleCommand.java rename to prototype_projects/launcher_v1/src/main/java/frc/robot/commands/ExampleCommand.java diff --git a/prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/prototype_projects/launcher_v1/src/main/java/frc/robot/subsystems/LauncherSubsystem.java similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/src/main/java/frc/robot/subsystems/ExampleSubsystem.java rename to prototype_projects/launcher_v1/src/main/java/frc/robot/subsystems/LauncherSubsystem.java diff --git a/prototype_projects/launcher_v1/launcher_v1/vendordeps/Phoenix6-26.1.0.json b/prototype_projects/launcher_v1/vendordeps/Phoenix6-26.1.0.json similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/vendordeps/Phoenix6-26.1.0.json rename to prototype_projects/launcher_v1/vendordeps/Phoenix6-26.1.0.json diff --git a/prototype_projects/launcher_v1/launcher_v1/vendordeps/REVLib.json b/prototype_projects/launcher_v1/vendordeps/REVLib.json similarity index 100% rename from prototype_projects/launcher_v1/launcher_v1/vendordeps/REVLib.json rename to prototype_projects/launcher_v1/vendordeps/REVLib.json diff --git a/prototype_projects/launcher_v1/vendordeps/WPILibNewCommands.json b/prototype_projects/launcher_v1/vendordeps/WPILibNewCommands.json new file mode 100644 index 0000000..d90630e --- /dev/null +++ b/prototype_projects/launcher_v1/vendordeps/WPILibNewCommands.json @@ -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" + ] + } + ] +} From 50d86744efe86b06cdacc2aa29e427bb35473766 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 24 Jan 2026 14:46:09 -0600 Subject: [PATCH 036/161] Tweak some controller parameters for launcher_neo --- .gitignore | 1 + prototype_projects/launcher_neo/gradlew | 0 .../launcher_neo/src/main/java/frc/robot/Constants.java | 6 +++--- .../launcher_neo/src/main/java/frc/robot/Robot.java | 5 ++--- 4 files changed, 6 insertions(+), 6 deletions(-) mode change 100644 => 100755 prototype_projects/launcher_neo/gradlew diff --git a/.gitignore b/.gitignore index 524f096..2070218 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* replay_pid* +.DS_Store diff --git a/prototype_projects/launcher_neo/gradlew b/prototype_projects/launcher_neo/gradlew old mode 100644 new mode 100755 diff --git a/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java b/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java index c63b570..9e54a86 100644 --- a/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/launcher_neo/src/main/java/frc/robot/Constants.java @@ -22,9 +22,9 @@ public static class LauncherConstants { public static final double kP = 0.0001; // An error of 1 rotation results in x V output public static final double kI = 0.0; public static final double kD = 0.0; // A velocity of 1 rps results in x V output - public static final double kV = (12.0/40000.0); // (12.0/5767); // Copied from basic REV example! - public static final double kCruiseVelocityRPM = 5000.0; - public static final double kAllowedErrorR = 1.0; + public static final double kV = (12.0/40000.0); // Expected value is (12.0/5767) but this yields a huge offset (100rpm setpoint, 700rpm actual) + public static final double kCruiseVelocityRPM = 5700.0; // Note actually needed during velocity control. + public static final double kAllowedErrorR = 10.0; public static final double kMaxAccelerationRPMPS = 1000.0; } } diff --git a/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java index e966f46..3c9393d 100644 --- a/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/launcher_neo/src/main/java/frc/robot/Robot.java @@ -65,14 +65,13 @@ public Robot() { .d(LauncherConstants.kD, ClosedLoopSlot.kSlot1) .outputRange(-1, 1, ClosedLoopSlot.kSlot1) .feedForward - // kV is now in Volts, so we multiply by the nominal voltage (12V) .kV(LauncherConstants.kV, ClosedLoopSlot.kSlot1); motorConfig.closedLoop.maxMotion // Set MAXMotion parameters for velocity control in slot 1 .maxAcceleration(LauncherConstants.kMaxAccelerationRPMPS, ClosedLoopSlot.kSlot1) - .cruiseVelocity(6000, ClosedLoopSlot.kSlot1) - .allowedProfileError(1, ClosedLoopSlot.kSlot1); + .cruiseVelocity(LauncherConstants.kCruiseVelocityRPM, ClosedLoopSlot.kSlot1) + .allowedProfileError(LauncherConstants.kAllowedErrorR, ClosedLoopSlot.kSlot1); /* * Apply the configuration to the SPARK MAX. From b18da3696695f34aac5a361373b0159a3b5694a9 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 27 Jan 2026 19:55:19 -0600 Subject: [PATCH 037/161] Debug Limelight-based pose estimation --- 2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr | 1 + .../src/main/java/frc/robot/RobotContainer.java | 7 +++++-- .../main/java/frc/robot/subsystems/DriveSubsystem.java | 8 +++++--- .../java/frc/robot/subsystems/LimelightSubsystem.java | 5 +++++ 4 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr diff --git a/2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr b/2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr new file mode 100644 index 0000000..2f5a351 --- /dev/null +++ b/2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr @@ -0,0 +1 @@ +{"area_max":100.0,"area_min":0.001,"area_similarity":0.0,"aspect_max":20.0,"aspect_min":0.0,"barcode_type":"qrzx","black_level":0,"blue_balance":1975.0,"botfloorsnap":1,"botlength":0.735,"bottype":"swerve","botwidth":0.735,"calibration_type":0,"classifier_conf":0.1,"classifier_runtime":"cpu","clip_labels":"face,hand,computer,keyboard","contour_grouping":0,"contour_sort_final":0,"convexity_max":100.0,"convexity_min":10.0,"corner_approx":5.0,"crop_focus":0.0,"crop_perspective_h":0.0,"crop_perspective_v":0.0,"crop_x_max":1.0,"crop_x_min":-1.0,"crop_y_max":1.0,"crop_y_min":-1.0,"cross_a_a":1.0,"cross_a_x":0.0,"cross_a_y":0.0,"cross_b_a":1.0,"cross_b_x":0.0,"cross_b_y":0.0,"debugpipe":0,"depthrange_max":100.0,"depthrange_min":0.0,"desc":"Pipeline_Name","desired_contour_region":0,"detector_conf":0.8,"detector_idfilters":"","detector_runtime":"cpu","dilation_steps":0,"direction_filter":0,"dual_close_sort_origin":0,"erosion_steps":0,"exposure":40.0,"fiducial_backend":"umich","fiducial_denoise":0.0,"fiducial_idfilters":"","fiducial_locfilters":"","fiducial_qualitythreshold":2.0,"fiducial_resdiv":2,"fiducial_size":165.1,"fiducial_skip3d":0,"fiducial_type":"aprilClassic36h11","fiducial_vis_mode":"3dbotposefieldspace","flicker":0,"focus":0.0,"force_convex":1,"hue_max":85,"hue_min":55,"image_flip":0,"image_source":0,"img_to_show":0,"intersection_filter":0,"invert_hue":0,"lcgain":6.0,"margin_tv":0.2,"multigroup_max":7,"multigroup_min":1,"multigroup_rejector":0,"nnp_rotate":0,"pipeline_led_enabled":1,"pipeline_led_power":100,"pipeline_res":1,"pipeline_type":"pipe_fiducial","python_snapscript_name":"","quality_focus":0.3,"red_balance":1200.0,"reverse_morpho":0,"roi_x":0.0,"roi_y":0.0,"rsf":0.37,"rspitch":0.0,"rsroll":0.0,"rss":0.0,"rsu":0.4,"rsyaw":0.0,"sat_max":255,"sat_min":70,"send_corners":0,"send_json":0,"tsf":0.0,"tss":0.0,"tsu":0.0,"tv_conf":0.5,"val_max":255,"val_min":70,"x_outlier_miqr":1.5,"y_outlier_miqr":1.5,"yaw_latency_adjustment":0.0,"zsclassifier_conf":0.1} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 024ee3d..122fb09 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -30,6 +30,7 @@ import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; +import frc.robot.subsystems.LimelightSubsystem; import frc.robot.utils.AutoCommands; /** @@ -41,6 +42,7 @@ public class RobotContainer { // The robot's subsystems and commands are defined here... private final Optional m_driveSubsystem; + private final LimelightSubsystem m_limelightSubsystem; // Replace with CommandPS4Controller or CommandJoystick if needed private final CommandXboxController m_driverController = @@ -55,7 +57,7 @@ public class RobotContainer { private DifferentialDrivePoseEstimator m_PoseEstimator = new DifferentialDrivePoseEstimator( m_DriveKinematics, - m_gyro.getRotation2d(), + Rotation2d.fromDegrees(0.0), 0, 0, new Pose2d(0.0, 8.0, new Rotation2d()), @@ -84,7 +86,7 @@ public RobotContainer() { m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); // Init the subsystems - //m_limelightSubsystem = getSubsystem(LimelightSubsystem.class, m_PoseEstimator); + m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_gyro); //m_exampleSubsystem = getSubsystem(ExampleSubsystem.class); // Init Auto @@ -180,6 +182,7 @@ public void UpdateSmartDashboard() { public void teleopInit() { configureDefaultCommands(); + LimelightHelpers.SetIMUMode("limelight", 4); } public void autoInit() { diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 073f6b2..de7409e 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -21,6 +21,7 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.kinematics.ChassisSpeeds; import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds; @@ -98,7 +99,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential ); // Gyro setup - m_gyro.zeroYaw(); + m_gyro.reset(); // Drive Chooser Init m_driveChooser.setDefaultOption("PID Arcade", ArcadeDriveCommand.class); @@ -307,9 +308,10 @@ public void periodic() { // This method will be called once per scheduler run double lPositionMeters = getMotorPositionMeters(true); double rPositionMeters = getMotorPositionMeters(false); - + Rotation2d yaw = m_gyro.getRotation2d(); + m_poseEstimator.update( - m_gyro.getRotation2d(), + yaw, lPositionMeters, rPositionMeters ); diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 30514d0..2515199 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -20,6 +20,8 @@ public class LimelightSubsystem extends SubsystemBase { public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { m_poseEstimator = poseEstimator; m_gyro = gyro; + + LimelightHelpers.SetIMUMode("limelight", 1); } // This is copy and pasted from limelight's documentation for testing. @@ -28,6 +30,9 @@ public void updateOdometry() { LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); LimelightHelpers.PoseEstimate mt2 = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); + if (mt2 == null) { + return; + } // if our angular velocity is greater than 720 degrees per second, ignore vision updates if(Math.abs(m_gyro.getRate()) > 720) From 3b8a575922a5d2ef884b384fa6a7c9626c037198 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 30 Jan 2026 18:20:12 -0600 Subject: [PATCH 038/161] Swaped the sign on the intake for fuel --- .../fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java index 0e6dd14..2276443 100644 --- a/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/fuelintake/Fuel Intake/src/main/java/frc/robot/Robot.java @@ -48,7 +48,7 @@ public void robotPeriodic() { // and running subsystem periodic() methods. This must be called from the robot's periodic // block in order for anything in the Command-based framework to work. CommandScheduler.getInstance().run(); - intakeMotor.set(.5); + intakeMotor.set(-.5); } /** This function is called once each time the robot enters Disabled mode. */ From cc9102de7aaff1b7cccb63c3b47ee1905b332de7 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 31 Jan 2026 15:53:25 -0600 Subject: [PATCH 039/161] Made the limelight zero the gyro orientation on auto & teleop init. --- .../pathplanner/autos/ReverseIntoCorner.auto | 19 +++++ .../src/main/deploy/pathplanner/navgrid.json | 2 +- .../pathplanner/paths/DriveToCorner.path | 54 ++++++++++++++ .../pathplanner/paths/ReverseIntoCorner.path | 70 +++++++++++++++++++ .../src/main/java/frc/robot/Robot.java | 8 ++- .../main/java/frc/robot/RobotContainer.java | 25 +++++-- .../frc/robot/subsystems/DriveSubsystem.java | 3 +- .../robot/subsystems/LimelightSubsystem.java | 52 ++++++++++++-- .../java/frc/robot/utils/LimitedQueue.java | 19 +++++ 9 files changed, 238 insertions(+), 14 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveToCorner.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/LimitedQueue.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto new file mode 100644 index 0000000..19afbc2 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "ReverseIntoCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json index 23e0db9..465fe26 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json @@ -1 +1 @@ -{"field_size":{"x":17.548,"y":8.052},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file +{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveToCorner.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveToCorner.path new file mode 100644 index 0000000..07e6691 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveToCorner.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.2582179487179497, + "y": 5.535038461538461 + }, + "prevControl": null, + "nextControl": { + "x": 2.2931025641025653, + "y": 6.058307692307692 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.7, + "y": 6.5 + }, + "prevControl": { + "x": 2.2465897435897455, + "y": 6.139705128205128 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path new file mode 100644 index 0000000..94faccd --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 3.22, + "y": 6.06 + }, + "prevControl": null, + "nextControl": { + "x": 2.840245730777104, + "y": 6.528957467245401 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0023974358974375, + "y": 6.697858974358974 + }, + "prevControl": { + "x": 2.932653846153847, + "y": 6.70948717948718 + }, + "nextControl": { + "x": 1.534985890056773, + "y": 6.692016330035965 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.7930641025641041, + "y": 7.290897435897436 + }, + "prevControl": { + "x": 1.258340364584852, + "y": 6.825621173876687 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": -62.96913974015706 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java index ed1d320..ca6d4f4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -55,12 +55,16 @@ public void robotPeriodic() { public void disabledInit() {} @Override - public void disabledPeriodic() {} + public void disabledPeriodic() { + LimelightHelpers.SetIMUMode("limelight", 3); + } /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ @Override public void autonomousInit() { + m_robotContainer.enabledInit(); m_robotContainer.autoInit(); + m_autonomousCommand = m_robotContainer.getAutonomousCommand(); // schedule the autonomous command (example) @@ -82,6 +86,8 @@ public void teleopInit() { if (m_autonomousCommand != null) { m_autonomousCommand.cancel(); } + + m_robotContainer.enabledInit(); m_robotContainer.teleopInit(); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 122fb09..5c26df7 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -27,6 +27,7 @@ import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; +import frc.robot.LimelightHelpers.IMUData; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -159,6 +160,8 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Pose X (Meter)", estimatedPos.getX()); SmartDashboard.putNumber("Pose Y (Meter)", estimatedPos.getY()); SmartDashboard.putNumber("Pose Theta (Degrees)", estimatedPos.getRotation().getDegrees()); + + SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); } // Drive subsystem @@ -180,18 +183,28 @@ public void UpdateSmartDashboard() { m_iTickCount++; } + // Move to auto init for competition code. + public void enabledInit() { + double cameraYaw = m_limelightSubsystem.getRobotYaw(); + + m_gyro.reset(); + m_gyro.setAngleAdjustment(-cameraYaw); + + LimelightHelpers.SetIMUMode("limelight", 4); + } + public void teleopInit() { configureDefaultCommands(); - LimelightHelpers.SetIMUMode("limelight", 4); } public void autoInit() { - if (m_driveSubsystem.isPresent()) { - DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + // This causes issues when auto's do not reset odometry!! + // if (m_driveSubsystem.isPresent()) { + // DriveSubsystem driveSubsystem = m_driveSubsystem.get(); - m_gyro.reset(); - driveSubsystem.resetPose(new Pose2d()); - } + // m_gyro.reset(); + // driveSubsystem.resetPose(new Pose2d()); + // } } /** diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index de7409e..de88f0c 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -309,7 +309,8 @@ public void periodic() { double lPositionMeters = getMotorPositionMeters(true); double rPositionMeters = getMotorPositionMeters(false); Rotation2d yaw = m_gyro.getRotation2d(); - + //m_gyro.getAngle() + m_poseEstimator.update( yaw, lPositionMeters, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 2515199..bd9f807 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -3,29 +3,56 @@ // the WPILib BSD license file in the root directory of this project. package frc.robot.subsystems; +import java.util.Arrays; + +import org.ejml.simple.SimpleMatrix; + import com.studica.frc.AHRS; import edu.wpi.first.math.VecBuilder; import edu.wpi.first.math.Vector; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.numbers.N3; +import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; +import frc.robot.LimelightHelpers.IMUData; +import frc.robot.utils.LimitedQueue; public class LimelightSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; private final AHRS m_gyro; + private final LimitedQueue m_YawQue = new LimitedQueue(5); + /** Creates a new PositionSubsystem. */ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { m_poseEstimator = poseEstimator; m_gyro = gyro; + } + + public double getRobotYaw() { + Double[] doubleObjects = m_YawQue.toArray(new Double[0]); + int queSize = doubleObjects.length; + + double[] primitiveDoubles = new double[queSize]; + for (int i = 0; i < queSize; i++) { + primitiveDoubles[i] = doubleObjects[i].doubleValue(); + } + + SimpleMatrix samplesMatrix = new SimpleMatrix(primitiveDoubles); - LimelightHelpers.SetIMUMode("limelight", 1); + double[] weightsArray = new double[queSize]; + Arrays.fill(weightsArray, 1.0); + + SimpleMatrix weightsMatrix = new SimpleMatrix(1, queSize, true, weightsArray); + + double avrg = samplesMatrix.dot(weightsMatrix)/weightsMatrix.elementSum(); + return avrg; } // This is copy and pasted from limelight's documentation for testing. - public void updateOdometry() { + private void updateOdometry() { boolean doRejectUpdate = false; LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); @@ -40,6 +67,10 @@ public void updateOdometry() { doRejectUpdate = true; } + if (Math.abs(m_gyro.getPitch()) > 5) { + doRejectUpdate = true; + } + if(mt2.tagCount == 0) { doRejectUpdate = true; @@ -47,8 +78,16 @@ public void updateOdometry() { if(!doRejectUpdate) { - // A Static Standard Deviation of .7 meters for x & y, it does not trust the theta. (Taken from example) - Vector errorVec = VecBuilder.fill(.7,.7,9999999); + // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. + Vector errorVec; + + // When the robot is disabled, trust the gyro from the limelight fully. + // Otherwise, in all othr modes, trust the gyro yaw. + if (DriverStation.isDisabled()) { + errorVec = VecBuilder.fill(.7,.7,0); + } else { + errorVec = VecBuilder.fill(.7,.7,9999999); + } m_poseEstimator.setVisionMeasurementStdDevs(errorVec); m_poseEstimator.addVisionMeasurement( @@ -60,7 +99,10 @@ public void updateOdometry() { @Override public void periodic() { - // This method will be called once per scheduler + // This method will be called once per scheduler + IMUData limelightData = LimelightHelpers.getIMUData("limelight"); + m_YawQue.add(limelightData.robotYaw); + updateOdometry(); } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/LimitedQueue.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/LimitedQueue.java new file mode 100644 index 0000000..cc0a705 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/utils/LimitedQueue.java @@ -0,0 +1,19 @@ +package frc.robot.utils; + +import java.util.LinkedList; + +// An extention of LinkedList that limits the max number of elements when using add and remove. +public class LimitedQueue extends LinkedList { + private int limit; + + public LimitedQueue(int limit) { + this.limit = limit; + } + + @Override + public boolean add(E o) { + super.add(o); + while (size() > limit) { super.remove(); } + return true; + } +} From 84f18d69d962b27c6ede8b6b85da2246d5616879 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <32313507+dawilson9@users.noreply.github.com> Date: Tue, 3 Feb 2026 19:34:14 -0600 Subject: [PATCH 040/161] Update Limelight odometry code and add new auto commands Auto is still not working correctly when using Limelight to determine robot pose. Teleop is working well and shows good pose estimation, though. Debugging continues... --- .../pathplanner/autos/DriveBwdToEdge.auto | 19 +++++++ .../pathplanner/autos/DriveFwdFromEdge.auto | 19 +++++++ .../deploy/pathplanner/autos/FwdThenBwd.auto | 31 +++++++++++ .../paths/DriveBackwardToCorner.path | 54 +++++++++++++++++++ .../paths/DriveForwardFromCorner.path | 54 +++++++++++++++++++ .../src/main/java/frc/robot/Robot.java | 5 +- .../main/java/frc/robot/RobotContainer.java | 17 ++++-- .../robot/subsystems/LimelightSubsystem.java | 2 + 8 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto new file mode 100644 index 0000000..e93b91b --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveBackwardToCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto new file mode 100644 index 0000000..8582b38 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveForwardFromCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto new file mode 100644 index 0000000..6a60a9c --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto @@ -0,0 +1,31 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveForwardFromCorner" + } + }, + { + "type": "wait", + "data": { + "waitTime": 1.0 + } + }, + { + "type": "path", + "data": { + "pathName": "DriveBackwardToCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path new file mode 100644 index 0000000..ee56cf3 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.5, + "y": 6.3 + }, + "prevControl": null, + "nextControl": { + "x": 2.749847706754774, + "y": 6.291275125824375 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.5, + "y": 6.3 + }, + "prevControl": { + "x": 0.2501522932452258, + "y": 6.308724874175625 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path new file mode 100644 index 0000000..40942ec --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.44, + "y": 6.28 + }, + "prevControl": null, + "nextControl": { + "x": 0.6899999048070625, + "y": 6.2797818338711915 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.44, + "y": 6.28 + }, + "prevControl": { + "x": 2.1900000951929375, + "y": 6.280218166128809 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java index ca6d4f4..e0d27fa 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/Robot.java @@ -52,11 +52,14 @@ public void robotPeriodic() { /** This function is called once each time the robot enters Disabled mode. */ @Override - public void disabledInit() {} + public void disabledInit() { + m_robotContainer.disabledInit(); + } @Override public void disabledPeriodic() { LimelightHelpers.SetIMUMode("limelight", 3); + m_robotContainer.disabledPeriodic(); } /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 5c26df7..ffa0560 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -183,14 +183,12 @@ public void UpdateSmartDashboard() { m_iTickCount++; } + public void disabledInit() {} + // Move to auto init for competition code. public void enabledInit() { - double cameraYaw = m_limelightSubsystem.getRobotYaw(); - - m_gyro.reset(); - m_gyro.setAngleAdjustment(-cameraYaw); - LimelightHelpers.SetIMUMode("limelight", 4); + m_gyro.enableLogging(true); } public void teleopInit() { @@ -207,6 +205,15 @@ public void autoInit() { // } } + // Gets called every disabled tick. + public void disabledPeriodic() { + double cameraYaw = m_limelightSubsystem.getRobotYaw(); + + m_gyro.enableLogging(false); + m_gyro.reset(); + m_gyro.setAngleAdjustment(-cameraYaw); + } + /** * Use this to pass the autonomous command to the main {@link Robot} class. * diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index bd9f807..4e21387 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -29,6 +29,8 @@ public class LimelightSubsystem extends SubsystemBase { public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { m_poseEstimator = poseEstimator; m_gyro = gyro; + + m_gyro.enableLogging(false); } public double getRobotYaw() { From fdf13a0c97139d1a2a3462e3acebb9eec1873682 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <32313507+dawilson9@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:44:01 -0600 Subject: [PATCH 041/161] Got forward drive from position working. We still need to figure out what is needed to make it drive backwards. IE: Does the paths want a backward "distance" or an inversed movment orentation. --- .../.gradle/8.11/checksums/checksums.lock | Bin 17 -> 17 bytes .../.gradle/8.11/checksums/sha1-checksums.bin | Bin 0 -> 18767 bytes .../DriveForwardFromPosMath.png | Bin 0 -> 44138 bytes .../paths/DriveForwardFromCorner.path | 10 +- .../main/java/frc/robot/RobotContainer.java | 31 ++++-- .../robot/commands/DriveForwardFromPos.java | 98 ++++++++++++++++++ 6 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 2025-Reefscape/.gradle/8.11/checksums/sha1-checksums.bin create mode 100644 prototype_projects/Experimental_Drivetrain_2026/DriveForwardFromPosMath.png create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DriveForwardFromPos.java diff --git a/2025-Reefscape/.gradle/8.11/checksums/checksums.lock b/2025-Reefscape/.gradle/8.11/checksums/checksums.lock index 543b153a265faf0faaee708104d3276bcce84492..ee330e1d585941e9e5f7cc22e57f140bc225c7dd 100644 GIT binary patch literal 17 UcmZSHJoVmo0jVV~86bci06H85p8x;= literal 17 TcmZSHJoVmo0jVV~8K3|FIu!(% diff --git a/2025-Reefscape/.gradle/8.11/checksums/sha1-checksums.bin b/2025-Reefscape/.gradle/8.11/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..d2803bcc10040d3602ea6ea3c049ba33a485ec5a GIT binary patch literal 18767 zcmeI%ODIH90LJlau<#Z$%}B(RM+~FUlvp5>M`B9jk*yFLO@@iWNSZuKY(!*-gtf%N zmQrRRO5{-}loB@L&fI&GW@D}YsdLZiJNLVFe%osm1VikXGK8O@``NNX009ILKmY** z5I_I{1Q0*~0R#|0009ILKmdXNBG4dRBwW6X!Km?VVqAidA1Q4@J>IR0t~XrnC=HSZo-)!MB(QO>Iq)LdPq zd|W=`i2wo!AbmXCEG&69v1EF-~#KcCU5IEn}v?rI}m~Y|XfPiU&XJ8L8)S*U6rSp{e=p zL#5T~Zw0Rp2et|`+LM~&oBH-YpLbp?S2g9OBeilX&*pFGBQ675m7g7r>tXeq{R@sD VbLZ%^CFCGaX?gsu$TJ^;`5UWtl3xG- literal 0 HcmV?d00001 diff --git a/prototype_projects/Experimental_Drivetrain_2026/DriveForwardFromPosMath.png b/prototype_projects/Experimental_Drivetrain_2026/DriveForwardFromPosMath.png new file mode 100644 index 0000000000000000000000000000000000000000..82be2724963edbd98b1e94100f31bef83600c964 GIT binary patch literal 44138 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

#sV`eIy%&$Mo+(^rw1Wi)$$Nj zyPj=NMg`Elt)rWR3#>%g#R&A|=&~D&{Q3JxjJKeCM*8(YHUpB!Gvo^36Z4tFKGf_PD z;6LNRM!vb^V<-Df2OGA+x)30oYU1UGu?qtTV(NoMpt(WzvN(GJi?k*2{|1N=+oxHW z6%ZhS#Py2hR<-un{-*KM3x5_F?))w?=>Ml8!~Gs5?Vf%Dlt8`%yZ89y;m-5eVad`a z(QI;U$A8JWZ#H~c)r$c?1A~&J!R7UD7-VCwXhc)sK1A=H?3y^A;IkEoJ=n&C{s~I> zPf>ZVBTb>tVrcu_KFMJ8@6U78&Ji$dL~-2M*qGGm3aMA8&D@LT7*9`2d%v56UZ>An za+G3OnT4)Tf(8y#gJ7@ijprIbaTe_IGTF7Yi=jjp0MYeO9{$H(iTK`^^}mZ0Y0_in zBw`)0ge0GyFO&qF4S#CtNmb(C7zh3p&KzcS@dSkbsGC9E3UQTLM|w>AOumZgc5anKGWN_^{PH2~-{XjWA6@t1q=ww8`CMeT!=W?_ zp@G~-RGs39x$llEx^Iw|{~_J~p}Aon)@4B9d;em5S|?FrfXuP8CGj_O-%0Eq)j>_C z`Lo)xwL#u=-)(!y^{bY4l1y=0 zFhx-1@xFtEmS$9g$_At?gyM?!?x#~9=jP_fBqa_sVF09HAe{X}0nEf++MNCIvf0Tn z*j~=GJvM=1sstwBrtPw)wy(dlQ{4kU)sJCAhYSr95B1!}%qSFvu^ohpbRi23#3oa4 zEf+Nh@Efx*T_#l{Zxu{iK8NpzILZPsr+lVZP)ktTOy=Y$Et2KpEK3-SaU(NZBFQ5P zD`Nd8a#o5BELs5v(p%!=L@dy8b#%;s9lH%0Zjf8<)%R>iSsCku^uVy|l4OJ6XiDO9 zJKe{l+^u$NOYt!QngN-aTDsOsgul4I12hn^BHItXdv^uYJrKeUVrM>TqIbsOBj;WX z**Pd6Fj$GiEwH!V*WL;31^~aLAP4Po@EyyMmy#nWsw|;!UYXU8?2C*pYQtrU*kAy)m^ui8}t7WICFq&;ffx=?R)bKjCd)bkfMA1-2(L!3Raz z`$?mYmbz8FquMD2zYgV1gY>aQq{Hl>HpgfMe!oTkaMBtk@SM;AjtrHvUyU7i2j}CFv ze%ht0R4^UdIaQs*Te}bOs1@obe3m2Y#o1eMtjHJ`fMcWjcdUiw^`hv;kqk+bwBl#S zTc`ek-><-#+tD94{wZ}rXMM{n)7^K$QFJXxyU$Gh7Fe&#KY1{#q@^QnyrpsGhRQhq z=5G(i*|LL5m0kt&ZrKtxY$r`eS-JH6ij^Pdf;iW_^}2SoX9HNCawoKprLeU;GnJbC zZvX3WdxJv7Gt-%uvp}wwr8LmwJ!x1yIPg=#!I)!>&HPy}-9NXK1JQd{m5(-ra*7V6pwh+84rcZQ$oq5MzT7|!qA^y!@cyZ6VbQAYdLhn6zVHdX%iM+swMfg||)go+u#A{J( zz^TGM_X_M?9CbAwNScwg1wrkaKi}ga+lPI$%ii&0*O250B)#ZJBQ?;_xUl+nO&ij` zlz3~%vQSbOxT9%BV9LJF>Qg=DaQhd2AByA(`%+Ygizr#YB{?!8!e)A;m9t2Y6gJv+ zdJthLT2iaL5-dr>AfpvJlG}%u!Iz)dw2dEg1Bi_UCHUwA4{~;TXkhTewr$ClsMBEh z0=)6RdH6)U0P81jXe+zLYTSj8agnY7+7h5iqBa1r_rO4KL_}vkj{4*`#b5*=QmUSS zyb9fuPu>8p%GlcOf_AYcA3bVpOr+UqzMGK8beS;93JSsiksI=c!m0IK+N!GhO`x0@ zIRt|7gr#_(4qF(CBa3|fu>Y6zF@0;3>~Ae$x8k;svZTMCzvgYQHzFlP&)mx6Ew|6H zvr@BkfilNW?4G-S^x8t4baPc#4H0KN>v@?|j?jd^)AjP@#_sO(O>N=9X_54Q z%oL;T0GdUMYX`p{$ZJS_yW)erB|M7X##+aT+X+4{ef+kEwRuVU^4wbwr|V32SL)%P zJzI84F0~C3yy=*?XgQOt>Ak(Tn6dez%<%${`^)Z8Cxy+sHICO^%TS?lwm2S{k-Use zS0~NETH3w4Zgtu2jk!N|+g|Ee@RV0bQAR3js|izYuK zY=g!s!NKk?4PQ;qq8BiT;FzCSl2PYGb#}g=!Hp15FbYjd5%t7(7=%Cw%iFR-PeK<5 zT|}5j$*romvdnMm?{44mcF>qRPSYnp@(3?=AiLLHzOXGe@3ygMRCVr;=@rRzeN26K z`*s@~;hm5DUC?r-#bCROL*XX(c!J0{ICAzb3RSWC1zL0zBOkV!7kKCO#0kuPU^6Yd zyz)SPdO}yX8$G8e=gPWYzLhh*KGo}YFzvUxT%zBjb#djgh0BTcDMdteM~rH?#S}C? zvyi$E&ea2RAGwJ$QmguZ7DZg<);$uQc~V=a{FtHV&cnUFvQKX)JPB21V%f_=c`LPf zjo(7wg=^Q@+$58EN{a7J=>E9q9KYR8(EMm@c5+E4G@dxLXo!})IYa@q0D6LdKi^Y) z8j|Y-tD%1?nOIEkq(w+T_zfawGB>tFjOjk`OJo z3B=2&?&W|rgVCC;US$^s330Ijvs1^NvpZn55a@^u}KK(3NL`F8kPJ zJifL`_owcj(R3BM#kI?VyY^h{@Lr{o}#YM^|*MH;8W0# z;V-~AL5%xatnBvTV0S>Zm%nQDEIWGI!JpB7d@hCr3i_1|(7i;P>W*U7UoS zSX~W;7bCh&guJRH5au{4q9)ywEWqrk!P;zlOh6iPIU$xKrXo7!PehjIhkt+3rNzLq zp9SB_x=TlIyF%-rY*y#M#WNk?uQVP#4l$V_(6Gc`2lb8~1~d>1oc-$~P#O7X^!#$M z#GV8tM-VZ2ks2N7xMwxXF7HDvi`0Mu4A1W>KlbGZ_J%kAmsG>yq{Ho+)7kcp1#jPb z1@~9o%>C>ZjQwGtLCRp7mXx3!jb^To14!~^lAD$^7-}6Y2cHUG_P#+-7Mb-aXQtL zN&1s5W|Oc`QD!j+#>T>>rNzvbMVMJ;G%2(qxsqkBt55x?;!-{HUlXH6{=(8}r?%r# z+F(2*#0Ui6L~uCJxSY$|Uw@NKC4d;U^v@%13&LhP`Qt7DS+B_V(3rfb z$^Y=tivxjo+SI#+!W)|#DYDwpv&QBCS+gXe%Yg!Fh4sAN;Nmn|y&cJ}Pv-nA9=^=U zSuI)?^rWF6?tT`NJgj^Neyj_BEu3k6iN^7mvQK*93QF7#fhXf;!|kGyOYt3>;hbao zdsy_&o6Gcn&^$i-t7O1aB3)N~>4A{t4ka=Q9;|7?=@=)1@*#$Rp;B21v5-lFPVCMk z7&c(BfaXrQvz3=bFO_P?f6xbdFx|q?MjC*CnSOt9SR$eWz5IF40iorRL#L zW|(jslGKP+555A67x5+)^fF9P@ znA3IT;}v|dG;4`D;PuG5JnQ2Aq3J;tp@BL1ZSyDjG}tFrjV+r7=7&gDh_Mz$5Yz#l z!b0E&>2p7Nr=<7DAE=E9O-O+uBY71o6(sFR(+}IwAqK!f`8Rq_f!xve#1!{@neVW$+gmR@6y^1G9V!ObH=Y$nw~Ee|245bXW#i{6dp|}AM?=<3(<7F zk8m?QN{dZ28vVdLU$2s;>Cbvyo;J$iSfu|bQmHMNZjDqEEx*3;+%(uDmk~`)roLw( zofc3vh?H!;epI!c&;5tAXe*!YrtD+bxiKUL9xu@VyB9{gQKKG2A-7Aw@Xf?VK}lKK(fr6;xuw}^dEs<{K=uB-y!sSdUqNw*{OHgh zL&4)=F;|0czA1Qa??ZMP(^A3i^(Z4kQ9N)Z2T)g_NDxX>a>tKiUVsS9S}pw%!)clY z2C&66pNp&iv8NoRw2??M(~{QZ^2*EJPZK)YWcO+?d}XF4x29LDmAtI+vQx3v(oIii zEDt!>u{YQAuEoz8v=1tGK8_eYvS{_L>t0VbT@)?|Ug%D2Y!EcM*V#nrOPnU2T4a=Z zV_(wG^xQa>zoa}3lp7`rQiJVi#HwyG5QWIesv~yuHHEmM`ja_3O+0mV{ZD_MQkcEc ztCcMEGtR-$Dbml-Qnu67gOT%Up|M-`MGhwxjD=dXIB1M84xhGxf}Bi$Bg_{_stGWZ zq*G|=2MpdjzwC-80l5(ybV$gS#b+H5N}gX%_oUvVF`GZx zc20J!ZE}|phJ&t9e|fz7XTgW=-B(r2p}$xZ$1EZbj|%H9TfS^rKRS>HN1uKo7QhE8 z;Y%<)u|aBqo%B3p(-5nzCvpYE*7wMOa4tbX1{eu|MF1Cp-jg*=U-EP78^#MJ;;fn) zjXUYiKmWY*q(#ZTxXA1Bd-8KPzk6kWUF(NN(6!tSSq8~#C_xh#t;U7JunI%eC@zw{s!vYUk%gx zwrlmO-KxY*U!L7&((^jr&k%ZQdOm#zHOQce5gtNfGOxEeyOw}^0sAHM)=0Q+@40*8 zR7YE}!|1&uYABbTo95w3ej)B{;Vcy&fA+@E$o9Jtk(+0q^{;JXxZ;_}c*}k@a;c9k z>vK~u5rg>07Pb12A)+I}%|BB}gertw_&3iE3HjJ=X?k|HqTNc#yf|e*2*L=sn@Vc%w2fS5so})_oILD?pb}R z)P@!oht#PvXUJqZ$ExBSX;;Gq=omkGW2})Mngm=zLX+MMW)x`2W%Tqm6CoiKXJA`c z{p^F}yXQD+?~r`luNU2q$_=t*GrKTC#Cw*uXj2Z){qD^Nu-t|6Xrg-H93=yKaEB1G z7f+ZA>`PNndxBP#{^lreT|)y#&japQ#viUigBCH0Op7TD977Ec-3H4sN{Z;0+Cdcq zg5sWW0ZRP>hyY18W%iu+_F?0h(#{v$CcL53FXCR|(V9%Lzsvrej^a) z%z~v~*APJ`##)}x$WMX53X^_F1uBqCgs7t@)l$kN%)CH%$cgSZ@th;Ga$r5h^d>8ThC;nSx&U}=oDU4OIbe( zaO~Nl3q1cc@YTQ))#w4+W>(ZV@|`AhfHFB8d5Flj;W)E_4G|KbBOU+=h66W(tl{GX2j2O~~vuz@g2f~PGAyi;9fEnpWLg+F#Ih*WQV6;iCu4pgE8mvSa>TuekEzzNd~u%ijdg0L zPEja$FZX%k_7Yv<*1p0L~4i(bNX#W1V6U> zA;+_qS6P^t$VFM}J=P-#jFCM{3-rpUQZ%2V9K`P0<5z>K{lM}Sg>elXnk6PUvL!{pKA3(FS=VmX7{1@ds5@uICnMV_pxvf{OOT zGvg}xZVOj_Vj_amC4MqvfnaxmXVqS;S+w=OG9ng!*nu`vLw)bU=`qY`X8t;$US}|tul+t(<*r(?qNZSla>bOV(*&e`8QC_sh5zL?M(senY=8`E8 zbS9Bbe8PgQbMOv-vdY{II0}I~lPOxcMqZ0$WWJx67=H+c526n+Q`+;}`-&X}rD{#D zJsLi_mOY)<(RBhC?Be6n;9dd+fC!2&=Az7Rk2RC?J(9DMO>gl$Nh0qO%>Q%l5*GLr zh=t*NZ;9gulHEDqBlI9>&7WFh!0J)2X}p}B=Nz3{fM;;&cAe?LWb50x@6;YE;Fz*{ zkMApV zxdNng&ZU8Id-N-Fg>fVRbS1@pp~} z$4vnEK`Kdx>=FnT;ck;5yE6-Yz0nGX9C{a)y7g_OzD;F(dzUI>HARiCQ0~}ft^hf+ zT!D*AqIe^swp;P|@t(f)B7@b%KbI-dPwCdFMu5rhJ#gS!8B8YH`%QJB(Wk#D4z4N=>+4w5*gT(teFIy%%FdF6M6lGoL<2cz)B#Kl*2BKbwe zqSVlNBE%8ulzsBL335kPa2Y)#69-}AG;L;M=Ce>%>a3|*hPH4p2625WYe|f^K6HbX z&rPlWu(RX~i#<4>4r%((e{)<@xKE;@wu0%27ENughOE;P5GprBQ$I7zmz=Wt7yRm+w^`;DJ7-dw$@NF~2Sh?ZqPd#y?3 zlAWvXv{H%l52;*`wf{)168lj=OwDAQDtS=rJ0a7E%o}@q1x!b+LgWS4lqN5o0DT#5NdC2AD(ReCVA?qPm;~2>{ZvJm$E#RWbs=^%e{=dX(suq zkEpkPh2qw^!j_}urO`_RwblA>FdXZ5q~lM(Wj3-2IeZ@~crOgs7Ncef$<4^HF6S|` zzfB%9YuDJ4!zr3vSvha`bmX5fIFBk6sb{7#ryfmN2s5T)o)hDys#2^_9NV0gqhRK+ zL*#)r%cPO(hgTegE(TH20OLj($FWYL+qMo+{&`=!o9+c6wEeCzH+4b<91c+ z=iA&LDWzPcGADRE5y1|+3o7awep^=XtEV$J9>{AkGix!;^ogb zTDM|6NlNnKB)L@&BC|&fQlr27+GDiUE>6CsBJ68hU&h^XSvvzz>A_8?z`le6=MbX% zfJn>3#b&P`@DIqd4Bh);y=UY@T+x$V>83A(@2N*K$5UA;UXKaPe175O=b3}ykEjYP z_AmszER466eL_(2a#ffdvH|eXUlusAhC#ta& zWWke7ngTGE;d&>KnUk>Bv5VOpWZ#14y%U0kB8-`E z_C{SYzLl&FfKlVYV_Pw`jL$6afVvN!>}2eNW#yZ{mY$d2LdBgW`*e7B;@vS0F&kot zKMNANn4EVeSYAX!0N>g=pA}rP2ThbZVJi9d?HgH8p`k*3@Epk8Ke4j&eC1ZvzI0VI zeb33+HG6+aEOPVdP_q4gjz2J_#H)mEhKl0EHa_^VNK;Jn)QvWJtC&txDI2@CH9~9t zz|A(TsjrTKiqQHJJw5gESo>R$|P9QmMI&_vZ2KXYYjUIU|O|2hdHEkkpCp zA~Iztr>fJnW~=JLWX@qJK7OVKrJT7JR?*CQ4zs@^(AsfY8Tq;){yQd7#^GNgNwHOT zWW#LZbD4!+8cLw#5GC< z;;5SVD^q9ylJP+)h0f1V7a;>PRelN4Xdo+v4)1%zN-iT)Vo79YXP;eg%DcPLDJIW0 z+tJ3R0x1-A*ECP4oVHG)NYuhh3Zt5nb>O8nYxhTgEj6-~IIHbb=3^<>H##mXO4ZRxWcp;igFx>n6r?H}eCA+=@HvukX0F`BSUsoiBOT(# z2UHYDmbr1haOz_<5d9Cjm-@TAE&ZaSIUpH&`|%@QiM$?6Cz%BW8?4(*RMt3XpX{n? z-lZn>$x^F_|0bofY+Uh@18;~6Rhujq|AW0l|XpJwk&*DVh$=)JTWhV5-TT+UvbML(4eJp>k@G^l^rZsXq^h@<6A=VJS`)jK>^_Z+kw!Yy)RDYqca>W#HKH@!X?M0QT-dGK!+%>*NaA>) zm)*}yn|wj$S5uxJOy^e##3U-L>NHvYg6sCji6>pJSB|>v3zy<`bK}ULFcuLJS>nCk zc&F<2+raxBfaGH z3Z*?H+@C&usxFy^#&|WE`9UUfK|}ED`SX55&`@!Pi@DC_>TS~8At3M+q7*Vsgp53a zRes1&M@J_)BSW-k(#6R(mTo);XN{+qQbK;%$cOtkq6JRH-`AGXdY*kyS#$Xw{;{7& zQd;>m)71D(t<6T?GPHK4*K};r?`K(E(fjHh*Vla(Yw}P<0Kplrg?x5oPB3mZm>q?~ zeI^76f$eA#>Gg_>i<9x|2ETrOhh(0~y3>TzG1l@OjRU?2S~N7SQCNwMx%hLcb_%o{ zVryrdICm1oY4~KxBd~ZgeT^Z$)&b&)MtrfYJ*k8oQ5!m9dTpFalv=)`J*xpuT<%<(eZg8KI$T zi8U0RhKOqDLIn<7BlO1pfq^ZBAx9tt*}7&W9)P;baRZOJ%riaXkYv~WM&8aw^K!eZ zg!HyL&TdO#87`_ZHJhMRDRSNHWV^E=Z}0=O2G^_U*9;3O-utG<@&~Sf*rfJK$JlMn z)^$R2baXTQgB_(j?UxcH{8+s?wUBWGVYZXr;rZ*=Yf-ll)k=NWKL*Y^D(fXmCGv^G z_Py-hI^)>f$W#{a6#c41i0`Vfq$Cj^8<4sbcj#^Dp|kZ&N=mwDmviMuS6{^bKG=>Q zf9teB^ts#5!GZG&9+NBdInd)PSXO-{86gCC^B*2<`19j~)~2@RczC_`GUWtaB^7fY zNp&8@Ums4d>or@#o#%3KJ-^}g{zvL3B%;b~8QkVR^Ig7s+TiT)OPlxnvNu^%UK>ON zeOLCI=1KormX|mBBo78$;z(NL*`Z>t%FfA%ssqSfL^gsNezkt2Gcqq?CTcZDNbLs{ z`1Fs=0@9;LY4uC#PwY}~@y{rYQD!=X4jl1hl%ZJ~DmVYqNbq3NGJAOo2VsT`!TE{R zPLuO)6C+(khmOaH&zVPNrdA-#^jVO{Bo(V2`NiEW`~#% zH?I%!W+XR^fU`nTurgmAO=d(|@oHUHy!LtPZ@zul7NOoxOwO4_>KFhQOMvJo(|8V- zPD2>pNQ6=X=LA<(l#QnT1z~fSjO4l!jfJ z$U7>_fToqf{(u7KTQOHN;!XsT9El=|g~qX`OHU>sqEkCpKAb4a z=Z^5yrARXV3cLtVD(108lFsh8Q5LeYPPDZNAFq&mY!p z$tP+%ynhr~OFInsp|>GWQV+wfHFepbE?bwz`ggz&*S!lK$(A4hFNR|aT5KBD}h` zx$p0M?Ap9fn$xzvb*mGQaj0^=_knpdbdPS2WvD<8?7ac>PFa?5R%{SoO$| zV(3=7s>8-Y>!LeY>#}hqSE6FU&x`4yH}I=SbqIFB`|uRr3_w;~!oq8bsK1Aj*syG7 zAJ?_u$|nX1H17OO$DY)wzsTs~kIET(RO!?I+FE%^Wg9)AJ99x8;S+ze?rut54aga|Yog+M~9 z{56G2_y&}tjGETnG0s9jMpQEpKM)2g%*uG(EO)x1giQkLhmwHL4#0hGK!_Gcj(DM5 zQO;Yi4|*}YN$KOq840BX?~3@afX`DvUXZR;WUz}#7c(a*M_l&os2vQQp9RvvPIef%6xR7~vI!63pM;6RWpT=|X}2S;m27`H8K`PHC+Seo|UhFWp-iY;)!; z&g688WOAh8+g|hKFmi3BqmXTrSZ>hq@Rd~?^e&B#iXxNq=ox&W>4XPka;0y|iLko& zWH*(ST}l#&_#TX4sjRO*V!zHcs|(^+Tf`-gKfl<)>!)>{?VE@b|C=&G#6{Z$hl?Si z_<>A6kSu;FD4jmN9x_Q{1*(`_x&y|XShrtArh@Z91qlgTu%dlsQN?&$tkM#7L^;Xe z4V$n~SHs5QZ_Jq-mU?+(jb>fbl9p9R78V@wg~q%Bz5KpypDr2Fi13f~?K86@<36!Z zZkCYHWY0c~=MvB=bSHAchVc^yckv0Nrd-sN2j=bWA%rkLCc zF4qT1r~4!ix8$Eok)vCj8b;s)NaaF3w(tJ>b5wWX2|jLH%nBr=-vJ@i=)z-o%~O2J zHm!F<3pR_)NQ0V?eT%FLKAe239x^xXR>&SMqej*XeykKSoCq-6oYlI)@rH2xU`3HZ z=j6FPp9Ztd@m|AQTe4W*;tJY)xCMWGwpref)bBP{FBYh{JXsL?p%TQHNXly0Xbo;9 zufz@^eH}YJJ}loR558-Rpwh+R2*jG-DeBoJT=(0{p9{B|WC z$GZ@!0#X#j$YOx2sJE_RHRZl1fzB04tI%MDZKu~Dd)zGHLAfG+8n~*$;^HSwO*iqL zBsbqwL~6JKeqwk~{i{ml-ELo_wZ)Ut)6)-}lTj4iCnkoe%K?!tF7D5^Ye58tGvnL`>g)I#B`x!0~G$S47C1FiciP+#<|tp({<=jP@00~iskxb;@*^I#*( zgac3twV@Y>q0s@la@Y2oL+b`1t_NvR4Fs#_E4Bo^Yb-eNFn7DsQuoqQNhB02VEm=0 zqToCO1>YSQe}CC%b4$w_2$Lq!H}{v-MwTNBlz(A(Fx51$STF}a9SCdG`+||i(rBke zE<@%9x($!%58^jIetfejx2I=XFB^7$gq;!5x=7ESVx=wK=+lu3yNQV>C1g)+Z*T7> zK@J&T9RxyX6d<(Yrk^4;jU`LSg~#aUP-;^p4A?6V^6~NM5F8lilz>@U_wtliq58r5 zClCkHd5GX?umeN*`gx|Nhwx}-w``DlaO>8($}CD89Q&M{oXndFps0E5{6%G4`LXsH zJOzI4&3lHmhS-R5XS=UEIGnf8S?)V-jU0PGC;%uRl&c@RfD%SKfs|qL75bfL-YPg%_h`8;zep zSXT)%tIe08Bao${97e(6?qSr^V;HGiF@$z8`Z_B*VJX9KLi!u>+=Z4v>Yxb+jgmW8 zI0~4DChr0Q&Zl?+y>g-ff(HnqdmBvf0X*{M)|>U=!pjjydi)5uetq3}LnS2J>>L~@ zKluPgYulax2ri*I{hWt;hh9}x)x*f7J}b?cLvQF8N=QdS_J%!^m6dI3Z{Ow{&o*&m zZ&24+bj8rkudZK0AfLpEh#ST>S@(FtIFFUD1cZdp(?e#;c=;KIGLXds=MzDCr=_J` z{)7(R`kYikl95JLg5KAG6RG2V)fuyfw0D-r^G4ptG(Fv+x`nDWG9d>hEL4E}zK6Mgp=GT@ATj|HGu1Cxy0y)MN09@t!V0089eL1s46gH0V9vd~VnY z&1#>g1b`+e^VaYM10RlN{;K@pG+?wRrIw`Lhwc)5>B`Xp5}*Q>PKfvA(R*w2fg#?u z%{?b4=WT86qthvrD#Ly>J)!5(gE;1LvnA4zB{}GGvXn6&Jim}LPrE{BP$wG zL_XkW|DnBm!whopWn)jVvdQFMj9FD@Co>9h`h8!p>tdC10=uMn?FV?Mz{S7VGZt0m!3a`cN$|3=rD%n zWwgWwq}&Q52S>+na?*x?z$j$gX(Ia2pMn{4)3|U z+-(yq{s0=1DWuT$E-Nj?@n89k5{%(ue0+SkA)_!wgPhVG&U0l?TWJX38+RJ6hdMo$f)D;U`QsN#mrrpUG+|U~du;I4r>^@@$;B?h zrK%~sVcQTs5MYQ_dh693((BomzjtMO_wk23aCTw(H!5BOj3mm1TleZhcELHFD7FhC zoFgCBh!A6%(Tl@QbVHafI zrmf#ouYKhcP}Lk!oq38)4)UYQncOmnf^hdesjW@YEakUYlbI)J^$OV=)#|DolqF$Y z0y2iWPxdnAE()Q$mh)T|Olc?_As!q4{A=lwB?QM2s_&}Ve?H-gobLNrieIQ)S%~SRWWJG;l7(wnhq)NQ^tahKd9Bo6VumQ^iHz z1VC`IQL3Tje8+Cwb|i^!twE}WJZ`99>dO~T{4g{*jEszWC*GdMw5!?jv-l8T1I9Le z98-iIJm4)XDhfZ+f^{YW2tkQTGy7ot;IGMUy9O!>DRNa4td1;qm%0py=P@ot3#)BZe3Go@GvVxJ9iK9Z@Nj`qO4hD^La^ zTzkxoB}h~<u1znuD0xH z_PsOjjm+9Ja*7Tk0?P5L3&BKdl1)KZ?|!>>$UpJ=v5tMv0TE~_`uCshGPF+baw@@* zN4^5RLF7xGswbDTdCX-GO=3?~39O2asOA|a;yq$dtomL%^olCKMYv#nx=x%#Lr2sr zo#lr37|_0w)S=534SGH6vka^wOEwH7Li^Uz@gt{qgPRHWgZ!_Gyylo?k)JPOn{&w0 z(vn&5FnV~~kX)|xP6moE0H@rO%1SD1q3^rMV9;MfZ{ND(iLaRE$Lph_qxluZuvd^dJ>}))dYXZqneEHNz!6w)U|@i2#J6p7_<5E~ zO3oG$mRGHNb)w!QM54KVRARt4bPuia);g4DKrevu7jNPxV`}H|tECWmr36G32kh7) zJigCS?P}jf3mqRa+WlSkET*K90nezj^mnDUwz?SZXh|G5gx5~gsylPLx}AmV%!iCK zGQYwIWso=2;Zo;u3|Rsi=KB|$qJGoCt=0T;l^i~!r)^~e5$G%K+UefhV`#UEcE{Cl zwz(l2DaK;fIhqQF%77Z&iuLt3HXT@25j$S34w)I5(Nr1y81>vMKc^I~l%RQV8KShy zM79lgAmb@LyP!AShVMesr@rhx8a4Fo#`WvfkOh+>N1rwPu+XV(E$mAVq}!qEgSCpH z{+BQ9i1iQ?9JI0mucY4fz;&PadP$SO`!i1?YWaKfQ{pEGgGI&ssQh8TvC~&=Ti3!JAKpOaopO4>KX+ z;ekwdet{QL&v?ycd>vAiS`agxEwJLi93~Unjj9Hkv98}XLN8taZHu2Jgi`vrn@FXm znrrRvU|5vvo^{&UtR>ja30q%GZcZAZ6K10-D_x=(f%pnkA|5ar;T}m)Qpp5e*v*sA ztS`7{g4j;zo%h^w#9Xvski0tQ70?zJZ!P03X5n47lB+Eqe^!h&WO@2&!wRl@F0f*w zo-aDXN>UTCaFw>i^>r(_WDqZjJmij(JMxV2!}xe0c5*E>k#vf}iedIDA)L}SPENI$3s9pUQ?%(x+e=ka3}lpVncOo5o$0YY>mPYM2hxCI~uaF=B iWO*GaG_p6!!ltB%*QWmFA+Z$vPwCK6xpWylkN*dbuBV~^ literal 0 HcmV?d00001 diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path index 40942ec..b806894 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path @@ -3,12 +3,12 @@ "waypoints": [ { "anchor": { - "x": 0.44, + "x": 1.0, "y": 6.28 }, "prevControl": null, "nextControl": { - "x": 0.6899999048070625, + "x": 1.2499999048070625, "y": 6.2797818338711915 }, "isLocked": false, @@ -16,12 +16,12 @@ }, { "anchor": { - "x": 2.44, + "x": 2.252435897435897, "y": 6.28 }, "prevControl": { - "x": 2.1900000951929375, - "y": 6.280218166128809 + "x": 2.0028673041421476, + "y": 6.265319494512134 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index ffa0560..e3f3ba2 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -4,10 +4,12 @@ package frc.robot; +import java.util.ArrayList; import java.util.Optional; import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -28,6 +30,7 @@ import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; import frc.robot.LimelightHelpers.IMUData; +import frc.robot.commands.DriveForwardFromPos; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -67,7 +70,7 @@ public class RobotContainer { ); // Smartdashboard Objects - private SendableChooser autoChooser; + private SendableChooser m_autoChooser; private final Field2d m_field = new Field2d(); // Factorys @@ -102,11 +105,27 @@ public RobotContainer() { private void configureAutos() { // Init Autos (/home/lvuser/deploy/pathplanner/autos) - AutoCommands.getAutoCommands(m_driveSubsystem); + // AutoCommands.getAutoCommands(m_driveSubsystem); + + // // Init Chooser + // m_autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string + m_autoChooser = new SendableChooser(); + + // Custom Autos + m_autoChooser.addOption( + "On-Fly Forward 2m", + new DriveForwardFromPos(m_PoseEstimator, 2) + ); + + // Path Planner Auto's + ArrayList autoNames = AutoCommands.getAutoNames(); + for (String autoName : autoNames) { + PathPlannerAuto auto = new PathPlannerAuto(autoName); + m_autoChooser.addOption(autoName, auto); + } - // Init Chooser - autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string - SmartDashboard.putData("Auto Chooser", autoChooser); + // Add to dashboard + SmartDashboard.putData("Auto Chooser", m_autoChooser); } private void configureDefaultCommands() { @@ -220,6 +239,6 @@ public void disabledPeriodic() { * @return the command to run in autonomous */ public Command getAutonomousCommand() { - return autoChooser.getSelected(); + return m_autoChooser.getSelected(); } } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DriveForwardFromPos.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DriveForwardFromPos.java new file mode 100644 index 0000000..a17ac62 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/DriveForwardFromPos.java @@ -0,0 +1,98 @@ +package frc.robot.commands; + +import java.util.List; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.GoalEndState; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.path.Waypoint; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; + +/** An example command that uses an example subsystem. */ +public class DriveForwardFromPos extends Command { + private final DifferentialDrivePoseEstimator m_poseEstimator; + private double m_targetDistance = 0.0; + + /** + * Creates a new DriveForward2mFromPos. + * + * @param subsystem The subsystem used by this command. + */ + public DriveForwardFromPos(DifferentialDrivePoseEstimator poseEstimator, double targetDistance) + { + m_poseEstimator = poseEstimator; + m_targetDistance = targetDistance; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This is taken and modified from the limelight documentation for + // path creation on the fly: https://pathplanner.dev/pplib-create-a-path-on-the-fly.html + + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + Rotation2d currentRotation = currentPose.getRotation(); + + double currentX = currentPose.getX(); + double currentY = currentPose.getY(); + + // If we think of the direction we want to go as of the hypotonuse of a + // right trinagle, we can calculate the needed distance to travel on + // the (x, y) by calculating for them as the legs of the RT. + double xMod = m_targetDistance * currentRotation.getCos(); + double yMod = m_targetDistance * currentRotation.getSin(); + + double newX = currentX + xMod; + double newY = currentY + yMod; + + // Create a list of waypoints from poses. Each pose represents one waypoint. + // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. + List waypoints = PathPlannerPath.waypointsFromPoses( + new Pose2d(currentX, currentY, currentRotation), + new Pose2d(newX, newY, currentRotation) + ); + + PathConstraints constraints = new PathConstraints( + 1.0, + 1.0, + 2 * Math.PI, + 4 * Math.PI + ); // The constraints for this path. + + // Create the path using the waypoints created above + PathPlannerPath path = new PathPlannerPath( + waypoints, + constraints, + null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. + new GoalEndState(0.0, currentRotation) // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. + ); + + // Prevent the path from being flipped if the coordinates are already correct + path.preventFlipping = true; + + // Create the command version of the path and schedule it + Command followPath = AutoBuilder.followPath(path); + CommandScheduler.getInstance().schedule(followPath); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} From 36b2dcd014023b858e9f9d256cbadf95ddf73e6e Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 7 Feb 2026 09:42:19 -0600 Subject: [PATCH 042/161] Added dual Kraken support in launcher test project --- .../src/main/java/frc/robot/Constants.java | 3 +- .../src/main/java/frc/robot/Robot.java | 30 +- .../vendordeps/Phoenix6-26.1.1.json | 449 ++++++++++++++++++ 3 files changed, 473 insertions(+), 9 deletions(-) create mode 100644 prototype_projects/launcher_neo/vendordeps/Phoenix6-26.1.1.json diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java index 497bcd2..7373aca 100644 --- a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Constants.java @@ -16,7 +16,8 @@ public final class Constants { public static class LauncherConstants { - public static final int kMotorCANID = 40; + public static final int kMotorCANID1= 41; + public static final int kMotorCANID2 = 40; // These numbers came from the ctre example then tweaked public static final double kS = 0.1; // A velocity target of 1 rps results in xV output diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java index b320ea0..49ec765 100644 --- a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java @@ -22,7 +22,8 @@ * project. */ public class Robot extends TimedRobot { - private final TalonFX m_fx = new TalonFX(LauncherConstants.kMotorCANID); + private final TalonFX m_fx1 = new TalonFX(LauncherConstants.kMotorCANID1); + private final TalonFX m_fx2 = new TalonFX(LauncherConstants.kMotorCANID2); /* Be able to switch which control request to use based on a button press */ /* Start at velocity 0, use slot 0 */ @@ -35,6 +36,7 @@ public class Robot extends TimedRobot { */ public Robot() { TalonFXConfiguration configs = new TalonFXConfiguration(); + /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ configs.Slot0.kS = LauncherConstants.kS; // To account for friction, add 0.1 V of static feedforward @@ -53,15 +55,23 @@ public Robot() { /* Retry config apply up to 5 times, report if failure */ StatusCode status = StatusCode.StatusCodeNotInitialized; for (int i = 0; i < 5; ++i) { - status = m_fx.getConfigurator().apply(configs); + status = m_fx1.getConfigurator().apply(configs); if (status.isOK()) break; } if (!status.isOK()) { - System.out.println("Could not apply configs, error code: " + status.toString()); + System.out.println("Could not apply configs 1, error code: " + status.toString()); + } + for (int i = 0; i < 5; ++i) { + status = m_fx2.getConfigurator().apply(configs); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs 2, error code: " + status.toString()); } - SmartDashboard.putNumber("desired RPS", 0); - SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); + SmartDashboard.getNumber("desired RPS", 0); + SmartDashboard.putNumber("current RPS1", m_fx1.getVelocity().getValueAsDouble()); + SmartDashboard.putNumber("current RPS2", m_fx2.getVelocity().getValueAsDouble()); } @Override @@ -84,11 +94,15 @@ public void teleopPeriodic() { double desiredRotationsPerSecond = joyValue * (6000/60); // Control motor from -6000 to +6000 rpm + desiredRotationsPerSecond = SmartDashboard.getNumber("desired RPS", desiredRotationsPerSecond); + SmartDashboard.putNumber("set RPS", desiredRotationsPerSecond); + /* Use velocity voltage */ - m_fx.setControl(m_velocityVoltage.withVelocity(desiredRotationsPerSecond)); + m_fx1.setControl(m_velocityVoltage.withVelocity(desiredRotationsPerSecond)); + m_fx2.setControl(m_velocityVoltage.withVelocity(-desiredRotationsPerSecond)); - SmartDashboard.putNumber("desired RPS", desiredRotationsPerSecond); - SmartDashboard.putNumber("current RPS", m_fx.getVelocity().getValueAsDouble()); + SmartDashboard.putNumber("current RPS1", m_fx1.getVelocity().getValueAsDouble()); + SmartDashboard.putNumber("current RPS2", m_fx2.getVelocity().getValueAsDouble()); } @Override diff --git a/prototype_projects/launcher_neo/vendordeps/Phoenix6-26.1.1.json b/prototype_projects/launcher_neo/vendordeps/Phoenix6-26.1.1.json new file mode 100644 index 0000000..7a0eca0 --- /dev/null +++ b/prototype_projects/launcher_neo/vendordeps/Phoenix6-26.1.1.json @@ -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" + } + ] +} \ No newline at end of file From 73a14ad4b61a280b2987ca1189f6dcd4c570f735 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Feb 2026 10:46:15 -0600 Subject: [PATCH 043/161] Fix a few typos in comments --- .../main/java/frc/robot/subsystems/DriveSubsystem.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java index de88f0c..67ac57b 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -268,7 +268,7 @@ public double getMotorSpeedMPS(boolean bLeft) return MPS; } - // Gets the distance travled by the motor in meters + // Gets the distance traveled by the motor in meters public double getMotorPositionMeters(boolean bLeft) { double posRotations; if (bLeft == true) { @@ -281,12 +281,12 @@ public double getMotorPositionMeters(boolean bLeft) { return posMeters; } - // Returns a robot relative ChassisSpeeds object based on the avrg linear velocity - // in meters per second and avrg anglear velocity in readians per second - // Currently we are asuming that their is no scale for the motors, we cannot find anywhere to set the scale. + // Returns a robot relative ChassisSpeeds object based on the average linear velocity + // in meters per second and average angular velocity in radians per second. + // Currently we are assuming that there is no scale for the motors, we cannot find anywhere to set the scale. public ChassisSpeeds getRobotRelativeSpeeds() { - // Linear Velocity in meters per second + // Linear velocity in meters per second double leftMPS = getMotorSpeedMPS(true); double rightMPS = getMotorSpeedMPS(false); From 52a3fd19f5d62340cfa3819c2b15523021ffeb53 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 7 Feb 2026 12:02:45 -0600 Subject: [PATCH 044/161] Skeleton Robot Code Copied prototype 2026 drivetrain code and added empty skeleton code for all other subsystems --- 2026-Rebuilt/AutoStatistics.txt | 14 + 2026-Rebuilt/DriveForwardFromPosMath.png | Bin 0 -> 44138 bytes 2026-Rebuilt/build.gradle | 6 +- 2026-Rebuilt/elastic-layout.json | 199 ++ .../limelight_pipelines/ToasterConfig.vpr | 1 - .../deploy/pathplanner/autos/2MeterAuto.auto | 19 + .../pathplanner/autos/DriveBwdToEdge.auto | 19 + .../pathplanner/autos/DriveFwdFromEdge.auto | 19 + .../deploy/pathplanner/autos/FwdThenBwd.auto | 31 + .../pathplanner/autos/ReverseIntoCorner.auto | 19 + .../deploy/pathplanner/autos/STurnAuto.auto | 19 + .../deploy/pathplanner/autos/SampleAuto.auto | 19 + .../pathplanner/autos/SmoothTurnAuto.auto | 19 + .../autos/SmoothTurn_ReverseS.auto | 25 + .../src/main/deploy/pathplanner/navgrid.json | 1 + .../deploy/pathplanner/paths/2_Meter_New.path | 54 + .../paths/DriveBackwardToCorner.path | 54 + .../paths/DriveForwardFromCorner.path | 54 + .../pathplanner/paths/DriveToCorner.path | 54 + .../pathplanner/paths/Example_Path.path | 54 + .../pathplanner/paths/ReverseIntoCorner.path | 70 + .../pathplanner/paths/Reverse_S_Turn.path | 54 + .../main/deploy/pathplanner/paths/S_Turn.path | 54 + .../deploy/pathplanner/paths/Smooth_Turn.path | 54 + .../src/main/deploy/pathplanner/settings.json | 36 + .../src/main/java/frc/robot/Constants.java | 96 + .../main/java/frc/robot/LimelightHelpers.java | 1645 +++++++++++++++++ .../src/main/java/frc/robot/Robot.java | 131 +- .../main/java/frc/robot/RobotContainer.java | 266 +++ .../robot/commands/ArcadeDriveCommand.java | 84 + .../commands/ArcadeDriveCommandNoPID.java | 77 + .../robot/commands/ArcadeFromDashboard.java | 43 + .../main/java/frc/robot/commands/Autos.java | 20 + .../DifferentailDriveFromDashboard.java | 45 + .../commands/DifferentialDriveCommand.java | 66 + .../robot/commands/DriveForwardFromPos.java | 98 + .../frc/robot/commands/ExampleCommand.java | 43 + .../robot/factorys/DriveSubsystemFactory.java | 33 + .../frc/robot/factorys/TalonFXFactory.java | 19 + .../robot/subsystems/ClimbL1Subsystem.java | 25 + .../frc/robot/subsystems/DriveSubsystem.java | 325 ++++ .../robot/subsystems/ExampleSubsystem.java | 47 + .../subsystems/IndexerBulkSubsystem.java | 25 + .../frc/robot/subsystems/IntakeSubsystem.java | 25 + .../robot/subsystems/LauncherSubsystem.java | 25 + .../robot/subsystems/LimelightSubsystem.java | 110 ++ .../java/frc/robot/utils/AutoCommands.java | 59 + .../java/frc/robot/utils/LimitedQueue.java | 19 + .../vendordeps/PathplannerLib-2026.1.2.json | 38 + .../{src => }/vendordeps/Phoenix6-26.1.0.json | 0 2026-Rebuilt/{src => }/vendordeps/REVLib.json | 0 2026-Rebuilt/vendordeps/Studica.json | 71 + .../vendordeps/WPILibNewCommands.json | 0 .../Experimental_Drivetrain_2026/build.gradle | 2 +- 54 files changed, 4352 insertions(+), 33 deletions(-) create mode 100644 2026-Rebuilt/AutoStatistics.txt create mode 100644 2026-Rebuilt/DriveForwardFromPosMath.png create mode 100644 2026-Rebuilt/elastic-layout.json delete mode 100644 2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/2_Meter_New.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveToCorner.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/Reverse_S_Turn.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/S_Turn.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/Smooth_Turn.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/settings.json create mode 100644 2026-Rebuilt/src/main/java/frc/robot/Constants.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/LimelightHelpers.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/factorys/TalonFXFactory.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/LimitedQueue.java create mode 100644 2026-Rebuilt/vendordeps/PathplannerLib-2026.1.2.json rename 2026-Rebuilt/{src => }/vendordeps/Phoenix6-26.1.0.json (100%) rename 2026-Rebuilt/{src => }/vendordeps/REVLib.json (100%) create mode 100644 2026-Rebuilt/vendordeps/Studica.json rename 2026-Rebuilt/{src => }/vendordeps/WPILibNewCommands.json (100%) diff --git a/2026-Rebuilt/AutoStatistics.txt b/2026-Rebuilt/AutoStatistics.txt new file mode 100644 index 0000000..5d40e72 --- /dev/null +++ b/2026-Rebuilt/AutoStatistics.txt @@ -0,0 +1,14 @@ +Test 1: +Auto: SmoothTurnReverseS +Rotation Off: 0 degrees (essentially) +Pos Off: 8 inch + +Test 2: +Auto: SmoothTurnReverseS +Rotation Off: 0 degrees (essentially) +Pos Off: 8 inch + +Test 3: +Auto: SmoothTurnReverseS +Rotation Off: 0 degrees (essentially) +Pos Off: 8 inch \ No newline at end of file diff --git a/2026-Rebuilt/DriveForwardFromPosMath.png b/2026-Rebuilt/DriveForwardFromPosMath.png new file mode 100644 index 0000000000000000000000000000000000000000..82be2724963edbd98b1e94100f31bef83600c964 GIT binary patch literal 44138 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

#sV`eIy%&$Mo+(^rw1Wi)$$Nj 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 literal 0 HcmV?d00001 diff --git a/2026-Rebuilt/build.gradle b/2026-Rebuilt/build.gradle index e9b0020..a3a6e39 100644 --- a/2026-Rebuilt/build.gradle +++ b/2026-Rebuilt/build.gradle @@ -1,6 +1,6 @@ plugins { id "java" - id "edu.wpi.first.GradleRIO" version "2026.1.1" + id "edu.wpi.first.GradleRIO" version "2026.2.1" } java { @@ -33,7 +33,7 @@ deploy { 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 + deleteOldFiles = true // Change to true to delete files on roboRIO that no // longer exist in deploy directory of this project } } @@ -48,7 +48,7 @@ def deployArtifact = deploy.targets.roborio.artifacts.frcJava wpi.java.debugJni = false // Set this to true to enable desktop support. -def includeDesktopSupport = true +def includeDesktopSupport = false // Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries. // Also defines JUnit 5. diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json new file mode 100644 index 0000000..9175fbd --- /dev/null +++ b/2026-Rebuilt/elastic-layout.json @@ -0,0 +1,199 @@ +{ + "version": 1.0, + "grid_size": 128, + "tabs": [ + { + "name": "Toaster Testing", + "grid_layout": { + "layouts": [], + "containers": [ + { + "title": "Drive Commands", + "x": 0.0, + "y": 0.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Drive Commands", + "period": 0.06, + "sort_options": false + } + }, + { + "title": "Left Target (MPS)", + "x": 0.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Left Speed (MPS)", + "x": 0.0, + "y": 384.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Right Target (MPS)", + "x": 128.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Right Speed (MPS)", + "x": 128.0, + "y": 384.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Auto Chooser", + "x": 0.0, + "y": 128.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Auto Chooser", + "period": 0.06, + "sort_options": false + } + }, + { + "title": "Field", + "x": 384.0, + "y": 0.0, + "width": 640.0, + "height": 384.0, + "type": "Field", + "properties": { + "topic": "/SmartDashboard/Field", + "period": 0.06, + "field_game": "Rebuilt", + "robot_width": 0.85, + "robot_length": 0.85, + "show_other_objects": true, + "show_trajectories": true, + "field_rotation": 0.0, + "robot_color": 4294198070, + "trajectory_color": 4294967295, + "show_robot_outside_widget": true + } + }, + { + "title": "Scheduler", + "x": 1664.0, + "y": 0.0, + "width": 256.0, + "height": 384.0, + "type": "Scheduler", + "properties": { + "topic": "/SmartDashboard/Scheduler", + "period": 0.06 + } + }, + { + "title": "Left Distance (m)", + "x": 0.0, + "y": 512.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Distance (m)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Right Distance (m)", + "x": 128.0, + "y": 512.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Distance (m)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose X (Meter)", + "x": 1024.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose X (Meter)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose Y (Meter)", + "x": 1024.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose Y (Meter)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose Theta (Degrees)", + "x": 1024.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose Theta (Degrees)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr b/2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr deleted file mode 100644 index 2f5a351..0000000 --- a/2026-Rebuilt/limelight_pipelines/ToasterConfig.vpr +++ /dev/null @@ -1 +0,0 @@ -{"area_max":100.0,"area_min":0.001,"area_similarity":0.0,"aspect_max":20.0,"aspect_min":0.0,"barcode_type":"qrzx","black_level":0,"blue_balance":1975.0,"botfloorsnap":1,"botlength":0.735,"bottype":"swerve","botwidth":0.735,"calibration_type":0,"classifier_conf":0.1,"classifier_runtime":"cpu","clip_labels":"face,hand,computer,keyboard","contour_grouping":0,"contour_sort_final":0,"convexity_max":100.0,"convexity_min":10.0,"corner_approx":5.0,"crop_focus":0.0,"crop_perspective_h":0.0,"crop_perspective_v":0.0,"crop_x_max":1.0,"crop_x_min":-1.0,"crop_y_max":1.0,"crop_y_min":-1.0,"cross_a_a":1.0,"cross_a_x":0.0,"cross_a_y":0.0,"cross_b_a":1.0,"cross_b_x":0.0,"cross_b_y":0.0,"debugpipe":0,"depthrange_max":100.0,"depthrange_min":0.0,"desc":"Pipeline_Name","desired_contour_region":0,"detector_conf":0.8,"detector_idfilters":"","detector_runtime":"cpu","dilation_steps":0,"direction_filter":0,"dual_close_sort_origin":0,"erosion_steps":0,"exposure":40.0,"fiducial_backend":"umich","fiducial_denoise":0.0,"fiducial_idfilters":"","fiducial_locfilters":"","fiducial_qualitythreshold":2.0,"fiducial_resdiv":2,"fiducial_size":165.1,"fiducial_skip3d":0,"fiducial_type":"aprilClassic36h11","fiducial_vis_mode":"3dbotposefieldspace","flicker":0,"focus":0.0,"force_convex":1,"hue_max":85,"hue_min":55,"image_flip":0,"image_source":0,"img_to_show":0,"intersection_filter":0,"invert_hue":0,"lcgain":6.0,"margin_tv":0.2,"multigroup_max":7,"multigroup_min":1,"multigroup_rejector":0,"nnp_rotate":0,"pipeline_led_enabled":1,"pipeline_led_power":100,"pipeline_res":1,"pipeline_type":"pipe_fiducial","python_snapscript_name":"","quality_focus":0.3,"red_balance":1200.0,"reverse_morpho":0,"roi_x":0.0,"roi_y":0.0,"rsf":0.37,"rspitch":0.0,"rsroll":0.0,"rss":0.0,"rsu":0.4,"rsyaw":0.0,"sat_max":255,"sat_min":70,"send_corners":0,"send_json":0,"tsf":0.0,"tss":0.0,"tsu":0.0,"tv_conf":0.5,"val_max":255,"val_min":70,"x_outlier_miqr":1.5,"y_outlier_miqr":1.5,"yaw_latency_adjustment":0.0,"zsclassifier_conf":0.1} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto new file mode 100644 index 0000000..26adafa --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "2_Meter_New" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto new file mode 100644 index 0000000..e93b91b --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveBackwardToCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto new file mode 100644 index 0000000..8582b38 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveForwardFromCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto new file mode 100644 index 0000000..6a60a9c --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto @@ -0,0 +1,31 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveForwardFromCorner" + } + }, + { + "type": "wait", + "data": { + "waitTime": 1.0 + } + }, + { + "type": "path", + "data": { + "pathName": "DriveBackwardToCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto new file mode 100644 index 0000000..19afbc2 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "ReverseIntoCorner" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto new file mode 100644 index 0000000..59b73ae --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "S_Turn" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto new file mode 100644 index 0000000..6460f85 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Example_Path" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto new file mode 100644 index 0000000..c79aef4 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Smooth_Turn" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto new file mode 100644 index 0000000..119345f --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto @@ -0,0 +1,25 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Smooth_Turn" + } + }, + { + "type": "path", + "data": { + "pathName": "Reverse_S_Turn" + } + } + ] + } + }, + "resetOdom": true, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json new file mode 100644 index 0000000..465fe26 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json @@ -0,0 +1 @@ +{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/2_Meter_New.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/2_Meter_New.path new file mode 100644 index 0000000..a1988a4 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/2_Meter_New.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.0, + "y": 8.0 + }, + "prevControl": null, + "nextControl": { + "x": 0.9999999999999996, + "y": 8.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 8.0 + }, + "prevControl": { + "x": 1.0, + "y": 8.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path new file mode 100644 index 0000000..ee56cf3 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveBackwardToCorner.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.5, + "y": 6.3 + }, + "prevControl": null, + "nextControl": { + "x": 2.749847706754774, + "y": 6.291275125824375 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.5, + "y": 6.3 + }, + "prevControl": { + "x": 0.2501522932452258, + "y": 6.308724874175625 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path new file mode 100644 index 0000000..b806894 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForwardFromCorner.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 1.0, + "y": 6.28 + }, + "prevControl": null, + "nextControl": { + "x": 1.2499999048070625, + "y": 6.2797818338711915 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.252435897435897, + "y": 6.28 + }, + "prevControl": { + "x": 2.0028673041421476, + "y": 6.265319494512134 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveToCorner.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveToCorner.path new file mode 100644 index 0000000..07e6691 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveToCorner.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.2582179487179497, + "y": 5.535038461538461 + }, + "prevControl": null, + "nextControl": { + "x": 2.2931025641025653, + "y": 6.058307692307692 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.7, + "y": 6.5 + }, + "prevControl": { + "x": 2.2465897435897455, + "y": 6.139705128205128 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path new file mode 100644 index 0000000..0d78846 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.1486729452054796, + "y": 6.48169948630137 + }, + "prevControl": null, + "nextControl": { + "x": 2.3986729452054796, + "y": 6.48169948630137 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 5.213912671232877, + "y": 6.48169948630137 + }, + "prevControl": { + "x": 4.963912671232877, + "y": 6.48169948630137 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path new file mode 100644 index 0000000..94faccd --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 3.22, + "y": 6.06 + }, + "prevControl": null, + "nextControl": { + "x": 2.840245730777104, + "y": 6.528957467245401 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0023974358974375, + "y": 6.697858974358974 + }, + "prevControl": { + "x": 2.932653846153847, + "y": 6.70948717948718 + }, + "nextControl": { + "x": 1.534985890056773, + "y": 6.692016330035965 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.7930641025641041, + "y": 7.290897435897436 + }, + "prevControl": { + "x": 1.258340364584852, + "y": 6.825621173876687 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": -62.96913974015706 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/Reverse_S_Turn.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Reverse_S_Turn.path new file mode 100644 index 0000000..b7dff0e --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Reverse_S_Turn.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.0, + "y": 6.0 + }, + "prevControl": null, + "nextControl": { + "x": 0.43680380386361306, + "y": 6.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.0, + "y": 8.0 + }, + "prevControl": { + "x": 2.0, + "y": 8.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/S_Turn.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/S_Turn.path new file mode 100644 index 0000000..a8a0ad7 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/S_Turn.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.0, + "y": 8.0 + }, + "prevControl": null, + "nextControl": { + "x": 2.0, + "y": 8.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 6.0 + }, + "prevControl": { + "x": 0.0, + "y": 6.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/Smooth_Turn.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Smooth_Turn.path new file mode 100644 index 0000000..639102e --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Smooth_Turn.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.0, + "y": 8.0 + }, + "prevControl": null, + "nextControl": { + "x": 2.0, + "y": 8.0 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 6.0 + }, + "prevControl": { + "x": 1.9999999999999998, + "y": 8.0 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json new file mode 100644 index 0000000..9479112 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json @@ -0,0 +1,36 @@ +{ + "robotWidth": 0.9, + "robotLength": 0.9, + "holonomicMode": false, + "pathFolders": [ + "New Folder" + ], + "autoFolders": [], + "defaultMaxVel": 1.0, + "defaultMaxAccel": 1.0, + "defaultMaxAngVel": 540.0, + "defaultMaxAngAccel": 720.0, + "defaultNominalVoltage": 12.0, + "robotMass": 74.088, + "robotMOI": 6.883, + "robotTrackwidth": 0.546, + "driveWheelRadius": 0.0508, + "driveGearing": 5.143, + "maxDriveSpeed": 5.45, + "driveMotorType": "krakenX60", + "driveCurrentLimit": 60.0, + "wheelCOF": 1.0, + "flModuleX": 0.273, + "flModuleY": 0.273, + "frModuleX": 0.273, + "frModuleY": -0.273, + "blModuleX": -0.273, + "blModuleY": 0.273, + "brModuleX": -0.273, + "brModuleY": -0.273, + "bumperOffsetX": 0.0, + "bumperOffsetY": 0.0, + "robotFeatures": [ + "{\"name\":\"Rectangle\",\"type\":\"rounded_rect\",\"data\":{\"center\":{\"x\":0.0,\"y\":0.0},\"size\":{\"width\":0.2,\"length\":0.2},\"borderRadius\":0.05,\"strokeWidth\":0.02,\"filled\":false}}" + ] +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java new file mode 100644 index 0000000..2808f3b --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -0,0 +1,96 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot; + +import com.pathplanner.lib.config.ModuleConfig; +import com.pathplanner.lib.config.RobotConfig; + +import edu.wpi.first.math.system.plant.DCMotor; + +/** + * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean + * constants. This class should not be used for any other purpose. All constants should be declared + * globally (i.e. public static). Do not put anything functional in this class. + * + *

It is advised to statically import this class (or one of its inner classes) wherever the + * constants are needed, to reduce verbosity. + */ +public final class Constants { + public static class AutoConstants { + public static final double kMaxDriveVelocityMPS = 40.0; // true max speed of the robot mps + public static final double kWheelCOF = 1.0; // no data for this, bsed it + + public static final double kMassKG = 15.0; + + // Uncommenting this causes the weird x y rotion error. + //public static final double kMOI = (1/12) * kMassKG * ((DrivetrainConstants.kLengthMeters*DrivetrainConstants.kLengthMeters) + (DrivetrainConstants.kWidthMeters*DrivetrainConstants.kWidthMeters)); // Moment of Intertia + public static final double kMOI = kMassKG * (DrivetrainConstants.kTrackWidthMeters/2) * (DrivetrainConstants.kA_angular / DrivetrainConstants.kA_linear); // Moment of Intertia + + public static final double kDriveCurrentLimit = 10.0; // amps + + // These values may change per bot, we might want to populate these on init w/ accurate data + public static final int kNumMotors = 4; // # of motors in a gearbox + + public static final DCMotor kDriveMotor = DCMotor.getKrakenX60(kNumMotors); + public static final ModuleConfig kModuleConfig = new ModuleConfig( + DrivetrainConstants.kWheelRadiusMeters, + kMaxDriveVelocityMPS, + kWheelCOF, + kDriveMotor, + kDriveCurrentLimit, + kNumMotors + ); + + public static final RobotConfig kRobotConfig = new RobotConfig(kMassKG, kMOI, kModuleConfig, DrivetrainConstants.kTrackWidthMeters); + // populate on init possibility end here + } + + public static class OperatorConstants { + public static final int kDriverControllerPort = 0; + public static final double kDriverControllerDeadband = 0.02; // Exclusive + } + + public static class DrivetrainConstants { + public static final int kLeftMotorCANID = 10; + public static final int kOptionalLeftMotorCANID = 11; + + public static final int kRightMotorCANID = 20; + public static final int kOptionalRightMotorCANID = 21; + + public static final double kTurnDivider = 2; + public static final double kSpeedDivider = 2.5; + + // These numbers came from the ctre example then tweaked + public static final double kS = 0.1; // A velocity target of 1 rps results in xV output + public static final double kV = 0.12; // Add x V output to overcome static friction + public static final double kP = 0.11; // An error of 1 rotation results in x V output + public static final double kI = 0.0; + public static final double kD = 0.0; // A velocity of 1 rps results in x V output + public static final double kA_linear = 0.01; // Voltage needed to induce a given accel. in the motor shaft + public static final double kA_angular = 0.01; // TODO: We need to measure this! + public static final double kPeakVoltage = 8.0; + + public static final double kMaxVelocityMPS = 3.0; // 6 mps is the max of the motors during zero load. + public static final double kMaxAccelerationMPS2 = 5.0; // M/S^2 + + public static final double kMotionMagicAcceleration = 100.0; // Higher number --> Faster (50.0 = ~1s to max) + public static final double kMotionMagicJerk = 4000.0; + + // For Auto Potentially + public static boolean kLeftPositiveMovesForward = true; + public static boolean kRightPositiveMovesForward = true; + + // Physical measurements related to the drivetrain. + public static final double kDrivetrainGearRatio = 0.2; + public static final double kWheelRadiusMeters = (4.0 / 2.0) * 0.0254; // Four Inch Wheels + public static final double kWheelCircumference = 2 * Math.PI * DrivetrainConstants.kWheelRadiusMeters; + public static final double kWidthMeters = 0.760; + public static final double kLengthMeters = 0.760; + public static final double kTrackWidthMeters = 29.0 * 0.0254;//0.74; + + // SmartDashboard update frequency for drive subsystem state in 20ms counts. + public static final int kTicksPerUpdate = 5; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/LimelightHelpers.java b/2026-Rebuilt/src/main/java/frc/robot/LimelightHelpers.java new file mode 100644 index 0000000..1dbf387 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/LimelightHelpers.java @@ -0,0 +1,1645 @@ +//LimelightHelpers v1.11 (REQUIRES LLOS 2025.0 OR LATER) + +package frc.robot; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Pose3d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.geometry.Rotation3d; +import edu.wpi.first.math.geometry.Translation2d; +import edu.wpi.first.math.geometry.Translation3d; +import edu.wpi.first.math.util.Units; +import edu.wpi.first.networktables.DoubleArrayEntry; +import edu.wpi.first.networktables.NetworkTable; +import edu.wpi.first.networktables.NetworkTableEntry; +import edu.wpi.first.networktables.NetworkTableInstance; +import edu.wpi.first.networktables.TimestampedDoubleArray; + +/** + * LimelightHelpers provides static methods and classes for interfacing with Limelight vision cameras in FRC. + * This library supports all Limelight features including AprilTag tracking, Neural Networks, and standard color/retroreflective tracking. + */ +public class LimelightHelpers { + + private static final Map doubleArrayEntries = new ConcurrentHashMap<>(); + + /** + * Represents a Color/Retroreflective Target Result extracted from JSON Output + */ + public static class LimelightTarget_Retro { + + @JsonProperty("t6c_ts") + private double[] cameraPose_TargetSpace; + + @JsonProperty("t6r_fs") + private double[] robotPose_FieldSpace; + + @JsonProperty("t6r_ts") + private double[] robotPose_TargetSpace; + + @JsonProperty("t6t_cs") + private double[] targetPose_CameraSpace; + + @JsonProperty("t6t_rs") + private double[] targetPose_RobotSpace; + + public Pose3d getCameraPose_TargetSpace() + { + return toPose3D(cameraPose_TargetSpace); + } + public Pose3d getRobotPose_FieldSpace() + { + return toPose3D(robotPose_FieldSpace); + } + public Pose3d getRobotPose_TargetSpace() + { + return toPose3D(robotPose_TargetSpace); + } + public Pose3d getTargetPose_CameraSpace() + { + return toPose3D(targetPose_CameraSpace); + } + public Pose3d getTargetPose_RobotSpace() + { + return toPose3D(targetPose_RobotSpace); + } + + public Pose2d getCameraPose_TargetSpace2D() + { + return toPose2D(cameraPose_TargetSpace); + } + public Pose2d getRobotPose_FieldSpace2D() + { + return toPose2D(robotPose_FieldSpace); + } + public Pose2d getRobotPose_TargetSpace2D() + { + return toPose2D(robotPose_TargetSpace); + } + public Pose2d getTargetPose_CameraSpace2D() + { + return toPose2D(targetPose_CameraSpace); + } + public Pose2d getTargetPose_RobotSpace2D() + { + return toPose2D(targetPose_RobotSpace); + } + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ts") + public double ts; + + public LimelightTarget_Retro() { + cameraPose_TargetSpace = new double[6]; + robotPose_FieldSpace = new double[6]; + robotPose_TargetSpace = new double[6]; + targetPose_CameraSpace = new double[6]; + targetPose_RobotSpace = new double[6]; + } + + } + + /** + * Represents an AprilTag/Fiducial Target Result extracted from JSON Output + */ + public static class LimelightTarget_Fiducial { + + @JsonProperty("fID") + public double fiducialID; + + @JsonProperty("fam") + public String fiducialFamily; + + @JsonProperty("t6c_ts") + private double[] cameraPose_TargetSpace; + + @JsonProperty("t6r_fs") + private double[] robotPose_FieldSpace; + + @JsonProperty("t6r_ts") + private double[] robotPose_TargetSpace; + + @JsonProperty("t6t_cs") + private double[] targetPose_CameraSpace; + + @JsonProperty("t6t_rs") + private double[] targetPose_RobotSpace; + + public Pose3d getCameraPose_TargetSpace() + { + return toPose3D(cameraPose_TargetSpace); + } + public Pose3d getRobotPose_FieldSpace() + { + return toPose3D(robotPose_FieldSpace); + } + public Pose3d getRobotPose_TargetSpace() + { + return toPose3D(robotPose_TargetSpace); + } + public Pose3d getTargetPose_CameraSpace() + { + return toPose3D(targetPose_CameraSpace); + } + public Pose3d getTargetPose_RobotSpace() + { + return toPose3D(targetPose_RobotSpace); + } + + public Pose2d getCameraPose_TargetSpace2D() + { + return toPose2D(cameraPose_TargetSpace); + } + public Pose2d getRobotPose_FieldSpace2D() + { + return toPose2D(robotPose_FieldSpace); + } + public Pose2d getRobotPose_TargetSpace2D() + { + return toPose2D(robotPose_TargetSpace); + } + public Pose2d getTargetPose_CameraSpace2D() + { + return toPose2D(targetPose_CameraSpace); + } + public Pose2d getTargetPose_RobotSpace2D() + { + return toPose2D(targetPose_RobotSpace); + } + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ts") + public double ts; + + public LimelightTarget_Fiducial() { + cameraPose_TargetSpace = new double[6]; + robotPose_FieldSpace = new double[6]; + robotPose_TargetSpace = new double[6]; + targetPose_CameraSpace = new double[6]; + targetPose_RobotSpace = new double[6]; + } + } + + /** + * Represents a Barcode Target Result extracted from JSON Output + */ + public static class LimelightTarget_Barcode { + + /** + * Barcode family type (e.g. "QR", "DataMatrix", etc.) + */ + @JsonProperty("fam") + public String family; + + /** + * Gets the decoded data content of the barcode + */ + @JsonProperty("data") + public String data; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + @JsonProperty("ta") + public double ta; + + @JsonProperty("pts") + public double[][] corners; + + public LimelightTarget_Barcode() { + } + + public String getFamily() { + return family; + } + } + + /** + * Represents a Neural Classifier Pipeline Result extracted from JSON Output + */ + public static class LimelightTarget_Classifier { + + @JsonProperty("class") + public String className; + + @JsonProperty("classID") + public double classID; + + @JsonProperty("conf") + public double confidence; + + @JsonProperty("zone") + public double zone; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("typ") + public double ty_pixels; + + public LimelightTarget_Classifier() { + } + } + + /** + * Represents a Neural Detector Pipeline Result extracted from JSON Output + */ + public static class LimelightTarget_Detector { + + @JsonProperty("class") + public String className; + + @JsonProperty("classID") + public double classID; + + @JsonProperty("conf") + public double confidence; + + @JsonProperty("ta") + public double ta; + + @JsonProperty("tx") + public double tx; + + @JsonProperty("ty") + public double ty; + + @JsonProperty("txp") + public double tx_pixels; + + @JsonProperty("typ") + public double ty_pixels; + + @JsonProperty("tx_nocross") + public double tx_nocrosshair; + + @JsonProperty("ty_nocross") + public double ty_nocrosshair; + + public LimelightTarget_Detector() { + } + } + + /** + * Limelight Results object, parsed from a Limelight's JSON results output. + */ + public static class LimelightResults { + + public String error; + + @JsonProperty("pID") + public double pipelineID; + + @JsonProperty("tl") + public double latency_pipeline; + + @JsonProperty("cl") + public double latency_capture; + + public double latency_jsonParse; + + @JsonProperty("ts") + public double timestamp_LIMELIGHT_publish; + + @JsonProperty("ts_rio") + public double timestamp_RIOFPGA_capture; + + @JsonProperty("v") + @JsonFormat(shape = Shape.NUMBER) + public boolean valid; + + @JsonProperty("botpose") + public double[] botpose; + + @JsonProperty("botpose_wpired") + public double[] botpose_wpired; + + @JsonProperty("botpose_wpiblue") + public double[] botpose_wpiblue; + + @JsonProperty("botpose_tagcount") + public double botpose_tagcount; + + @JsonProperty("botpose_span") + public double botpose_span; + + @JsonProperty("botpose_avgdist") + public double botpose_avgdist; + + @JsonProperty("botpose_avgarea") + public double botpose_avgarea; + + @JsonProperty("t6c_rs") + public double[] camerapose_robotspace; + + public Pose3d getBotPose3d() { + return toPose3D(botpose); + } + + public Pose3d getBotPose3d_wpiRed() { + return toPose3D(botpose_wpired); + } + + public Pose3d getBotPose3d_wpiBlue() { + return toPose3D(botpose_wpiblue); + } + + public Pose2d getBotPose2d() { + return toPose2D(botpose); + } + + public Pose2d getBotPose2d_wpiRed() { + return toPose2D(botpose_wpired); + } + + public Pose2d getBotPose2d_wpiBlue() { + return toPose2D(botpose_wpiblue); + } + + @JsonProperty("Retro") + public LimelightTarget_Retro[] targets_Retro; + + @JsonProperty("Fiducial") + public LimelightTarget_Fiducial[] targets_Fiducials; + + @JsonProperty("Classifier") + public LimelightTarget_Classifier[] targets_Classifier; + + @JsonProperty("Detector") + public LimelightTarget_Detector[] targets_Detector; + + @JsonProperty("Barcode") + public LimelightTarget_Barcode[] targets_Barcode; + + public LimelightResults() { + botpose = new double[6]; + botpose_wpired = new double[6]; + botpose_wpiblue = new double[6]; + camerapose_robotspace = new double[6]; + targets_Retro = new LimelightTarget_Retro[0]; + targets_Fiducials = new LimelightTarget_Fiducial[0]; + targets_Classifier = new LimelightTarget_Classifier[0]; + targets_Detector = new LimelightTarget_Detector[0]; + targets_Barcode = new LimelightTarget_Barcode[0]; + + } + + + } + + /** + * Represents a Limelight Raw Fiducial result from Limelight's NetworkTables output. + */ + public static class RawFiducial { + public int id = 0; + public double txnc = 0; + public double tync = 0; + public double ta = 0; + public double distToCamera = 0; + public double distToRobot = 0; + public double ambiguity = 0; + + + public RawFiducial(int id, double txnc, double tync, double ta, double distToCamera, double distToRobot, double ambiguity) { + this.id = id; + this.txnc = txnc; + this.tync = tync; + this.ta = ta; + this.distToCamera = distToCamera; + this.distToRobot = distToRobot; + this.ambiguity = ambiguity; + } + } + + /** + * Represents a Limelight Raw Neural Detector result from Limelight's NetworkTables output. + */ + public static class RawDetection { + public int classId = 0; + public double txnc = 0; + public double tync = 0; + public double ta = 0; + public double corner0_X = 0; + public double corner0_Y = 0; + public double corner1_X = 0; + public double corner1_Y = 0; + public double corner2_X = 0; + public double corner2_Y = 0; + public double corner3_X = 0; + public double corner3_Y = 0; + + + public RawDetection(int classId, double txnc, double tync, double ta, + double corner0_X, double corner0_Y, + double corner1_X, double corner1_Y, + double corner2_X, double corner2_Y, + double corner3_X, double corner3_Y ) { + this.classId = classId; + this.txnc = txnc; + this.tync = tync; + this.ta = ta; + this.corner0_X = corner0_X; + this.corner0_Y = corner0_Y; + this.corner1_X = corner1_X; + this.corner1_Y = corner1_Y; + this.corner2_X = corner2_X; + this.corner2_Y = corner2_Y; + this.corner3_X = corner3_X; + this.corner3_Y = corner3_Y; + } + } + + /** + * Represents a 3D Pose Estimate. + */ + public static class PoseEstimate { + public Pose2d pose; + public double timestampSeconds; + public double latency; + public int tagCount; + public double tagSpan; + public double avgTagDist; + public double avgTagArea; + + public RawFiducial[] rawFiducials; + public boolean isMegaTag2; + + /** + * Instantiates a PoseEstimate object with default values + */ + public PoseEstimate() { + this.pose = new Pose2d(); + this.timestampSeconds = 0; + this.latency = 0; + this.tagCount = 0; + this.tagSpan = 0; + this.avgTagDist = 0; + this.avgTagArea = 0; + this.rawFiducials = new RawFiducial[]{}; + this.isMegaTag2 = false; + } + + public PoseEstimate(Pose2d pose, double timestampSeconds, double latency, + int tagCount, double tagSpan, double avgTagDist, + double avgTagArea, RawFiducial[] rawFiducials, boolean isMegaTag2) { + + this.pose = pose; + this.timestampSeconds = timestampSeconds; + this.latency = latency; + this.tagCount = tagCount; + this.tagSpan = tagSpan; + this.avgTagDist = avgTagDist; + this.avgTagArea = avgTagArea; + this.rawFiducials = rawFiducials; + this.isMegaTag2 = isMegaTag2; + } + + } + + /** + * Encapsulates the state of an internal Limelight IMU. + */ + public static class IMUData { + public double robotYaw = 0.0; + public double Roll = 0.0; + public double Pitch = 0.0; + public double Yaw = 0.0; + public double gyroX = 0.0; + public double gyroY = 0.0; + public double gyroZ = 0.0; + public double accelX = 0.0; + public double accelY = 0.0; + public double accelZ = 0.0; + + public IMUData() {} + + public IMUData(double[] imuData) { + if (imuData != null && imuData.length >= 10) { + this.robotYaw = imuData[0]; + this.Roll = imuData[1]; + this.Pitch = imuData[2]; + this.Yaw = imuData[3]; + this.gyroX = imuData[4]; + this.gyroY = imuData[5]; + this.gyroZ = imuData[6]; + this.accelX = imuData[7]; + this.accelY = imuData[8]; + this.accelZ = imuData[9]; + } + } + } + + + private static ObjectMapper mapper; + + /** + * Print JSON Parse time to the console in milliseconds + */ + static boolean profileJSON = false; + + static final String sanitizeName(String name) { + if (name == "" || name == null) { + return "limelight"; + } + return name; + } + + /** + * Takes a 6-length array of pose data and converts it to a Pose3d object. + * Array format: [x, y, z, roll, pitch, yaw] where angles are in degrees. + * @param inData Array containing pose data [x, y, z, roll, pitch, yaw] + * @return Pose3d object representing the pose, or empty Pose3d if invalid data + */ + public static Pose3d toPose3D(double[] inData){ + if(inData.length < 6) + { + //System.err.println("Bad LL 3D Pose Data!"); + return new Pose3d(); + } + return new Pose3d( + new Translation3d(inData[0], inData[1], inData[2]), + new Rotation3d(Units.degreesToRadians(inData[3]), Units.degreesToRadians(inData[4]), + Units.degreesToRadians(inData[5]))); + } + + /** + * Takes a 6-length array of pose data and converts it to a Pose2d object. + * Uses only x, y, and yaw components, ignoring z, roll, and pitch. + * Array format: [x, y, z, roll, pitch, yaw] where angles are in degrees. + * @param inData Array containing pose data [x, y, z, roll, pitch, yaw] + * @return Pose2d object representing the pose, or empty Pose2d if invalid data + */ + public static Pose2d toPose2D(double[] inData){ + if(inData.length < 6) + { + //System.err.println("Bad LL 2D Pose Data!"); + return new Pose2d(); + } + Translation2d tran2d = new Translation2d(inData[0], inData[1]); + Rotation2d r2d = new Rotation2d(Units.degreesToRadians(inData[5])); + return new Pose2d(tran2d, r2d); + } + + /** + * Converts a Pose3d object to an array of doubles in the format [x, y, z, roll, pitch, yaw]. + * Translation components are in meters, rotation components are in degrees. + * + * @param pose The Pose3d object to convert + * @return A 6-element array containing [x, y, z, roll, pitch, yaw] + */ + public static double[] pose3dToArray(Pose3d pose) { + double[] result = new double[6]; + result[0] = pose.getTranslation().getX(); + result[1] = pose.getTranslation().getY(); + result[2] = pose.getTranslation().getZ(); + result[3] = Units.radiansToDegrees(pose.getRotation().getX()); + result[4] = Units.radiansToDegrees(pose.getRotation().getY()); + result[5] = Units.radiansToDegrees(pose.getRotation().getZ()); + return result; + } + + /** + * Converts a Pose2d object to an array of doubles in the format [x, y, z, roll, pitch, yaw]. + * Translation components are in meters, rotation components are in degrees. + * Note: z, roll, and pitch will be 0 since Pose2d only contains x, y, and yaw. + * + * @param pose The Pose2d object to convert + * @return A 6-element array containing [x, y, 0, 0, 0, yaw] + */ + public static double[] pose2dToArray(Pose2d pose) { + double[] result = new double[6]; + result[0] = pose.getTranslation().getX(); + result[1] = pose.getTranslation().getY(); + result[2] = 0; + result[3] = Units.radiansToDegrees(0); + result[4] = Units.radiansToDegrees(0); + result[5] = Units.radiansToDegrees(pose.getRotation().getRadians()); + return result; + } + + private static double extractArrayEntry(double[] inData, int position){ + if(inData.length < position+1) + { + return 0; + } + return inData[position]; + } + + private static PoseEstimate getBotPoseEstimate(String limelightName, String entryName, boolean isMegaTag2) { + DoubleArrayEntry poseEntry = LimelightHelpers.getLimelightDoubleArrayEntry(limelightName, entryName); + + TimestampedDoubleArray tsValue = poseEntry.getAtomic(); + double[] poseArray = tsValue.value; + long timestamp = tsValue.timestamp; + + if (poseArray.length == 0) { + // Handle the case where no data is available + return null; // or some default PoseEstimate + } + + var pose = toPose2D(poseArray); + double latency = extractArrayEntry(poseArray, 6); + int tagCount = (int)extractArrayEntry(poseArray, 7); + double tagSpan = extractArrayEntry(poseArray, 8); + double tagDist = extractArrayEntry(poseArray, 9); + double tagArea = extractArrayEntry(poseArray, 10); + + // Convert server timestamp from microseconds to seconds and adjust for latency + double adjustedTimestamp = (timestamp / 1000000.0) - (latency / 1000.0); + + RawFiducial[] rawFiducials = new RawFiducial[tagCount]; + int valsPerFiducial = 7; + int expectedTotalVals = 11 + valsPerFiducial * tagCount; + + if (poseArray.length != expectedTotalVals) { + // Don't populate fiducials + } else { + for(int i = 0; i < tagCount; i++) { + int baseIndex = 11 + (i * valsPerFiducial); + int id = (int)poseArray[baseIndex]; + double txnc = poseArray[baseIndex + 1]; + double tync = poseArray[baseIndex + 2]; + double ta = poseArray[baseIndex + 3]; + double distToCamera = poseArray[baseIndex + 4]; + double distToRobot = poseArray[baseIndex + 5]; + double ambiguity = poseArray[baseIndex + 6]; + rawFiducials[i] = new RawFiducial(id, txnc, tync, ta, distToCamera, distToRobot, ambiguity); + } + } + + return new PoseEstimate(pose, adjustedTimestamp, latency, tagCount, tagSpan, tagDist, tagArea, rawFiducials, isMegaTag2); + } + + /** + * Gets the latest raw fiducial/AprilTag detection results from NetworkTables. + * + * @param limelightName Name/identifier of the Limelight + * @return Array of RawFiducial objects containing detection details + */ + public static RawFiducial[] getRawFiducials(String limelightName) { + var entry = LimelightHelpers.getLimelightNTTableEntry(limelightName, "rawfiducials"); + var rawFiducialArray = entry.getDoubleArray(new double[0]); + int valsPerEntry = 7; + if (rawFiducialArray.length % valsPerEntry != 0) { + return new RawFiducial[0]; + } + + int numFiducials = rawFiducialArray.length / valsPerEntry; + RawFiducial[] rawFiducials = new RawFiducial[numFiducials]; + + for (int i = 0; i < numFiducials; i++) { + int baseIndex = i * valsPerEntry; + int id = (int) extractArrayEntry(rawFiducialArray, baseIndex); + double txnc = extractArrayEntry(rawFiducialArray, baseIndex + 1); + double tync = extractArrayEntry(rawFiducialArray, baseIndex + 2); + double ta = extractArrayEntry(rawFiducialArray, baseIndex + 3); + double distToCamera = extractArrayEntry(rawFiducialArray, baseIndex + 4); + double distToRobot = extractArrayEntry(rawFiducialArray, baseIndex + 5); + double ambiguity = extractArrayEntry(rawFiducialArray, baseIndex + 6); + + rawFiducials[i] = new RawFiducial(id, txnc, tync, ta, distToCamera, distToRobot, ambiguity); + } + + return rawFiducials; + } + + /** + * Gets the latest raw neural detector results from NetworkTables + * + * @param limelightName Name/identifier of the Limelight + * @return Array of RawDetection objects containing detection details + */ + public static RawDetection[] getRawDetections(String limelightName) { + var entry = LimelightHelpers.getLimelightNTTableEntry(limelightName, "rawdetections"); + var rawDetectionArray = entry.getDoubleArray(new double[0]); + int valsPerEntry = 12; + if (rawDetectionArray.length % valsPerEntry != 0) { + return new RawDetection[0]; + } + + int numDetections = rawDetectionArray.length / valsPerEntry; + RawDetection[] rawDetections = new RawDetection[numDetections]; + + for (int i = 0; i < numDetections; i++) { + int baseIndex = i * valsPerEntry; // Starting index for this detection's data + int classId = (int) extractArrayEntry(rawDetectionArray, baseIndex); + double txnc = extractArrayEntry(rawDetectionArray, baseIndex + 1); + double tync = extractArrayEntry(rawDetectionArray, baseIndex + 2); + double ta = extractArrayEntry(rawDetectionArray, baseIndex + 3); + double corner0_X = extractArrayEntry(rawDetectionArray, baseIndex + 4); + double corner0_Y = extractArrayEntry(rawDetectionArray, baseIndex + 5); + double corner1_X = extractArrayEntry(rawDetectionArray, baseIndex + 6); + double corner1_Y = extractArrayEntry(rawDetectionArray, baseIndex + 7); + double corner2_X = extractArrayEntry(rawDetectionArray, baseIndex + 8); + double corner2_Y = extractArrayEntry(rawDetectionArray, baseIndex + 9); + double corner3_X = extractArrayEntry(rawDetectionArray, baseIndex + 10); + double corner3_Y = extractArrayEntry(rawDetectionArray, baseIndex + 11); + + rawDetections[i] = new RawDetection(classId, txnc, tync, ta, corner0_X, corner0_Y, corner1_X, corner1_Y, corner2_X, corner2_Y, corner3_X, corner3_Y); + } + + return rawDetections; + } + + /** + * Prints detailed information about a PoseEstimate to standard output. + * Includes timestamp, latency, tag count, tag span, average tag distance, + * average tag area, and detailed information about each detected fiducial. + * + * @param pose The PoseEstimate object to print. If null, prints "No PoseEstimate available." + */ + public static void printPoseEstimate(PoseEstimate pose) { + if (pose == null) { + System.out.println("No PoseEstimate available."); + return; + } + + System.out.printf("Pose Estimate Information:%n"); + System.out.printf("Timestamp (Seconds): %.3f%n", pose.timestampSeconds); + System.out.printf("Latency: %.3f ms%n", pose.latency); + System.out.printf("Tag Count: %d%n", pose.tagCount); + System.out.printf("Tag Span: %.2f meters%n", pose.tagSpan); + System.out.printf("Average Tag Distance: %.2f meters%n", pose.avgTagDist); + System.out.printf("Average Tag Area: %.2f%% of image%n", pose.avgTagArea); + System.out.printf("Is MegaTag2: %b%n", pose.isMegaTag2); + System.out.println(); + + if (pose.rawFiducials == null || pose.rawFiducials.length == 0) { + System.out.println("No RawFiducials data available."); + return; + } + + System.out.println("Raw Fiducials Details:"); + for (int i = 0; i < pose.rawFiducials.length; i++) { + RawFiducial fiducial = pose.rawFiducials[i]; + System.out.printf(" Fiducial #%d:%n", i + 1); + System.out.printf(" ID: %d%n", fiducial.id); + System.out.printf(" TXNC: %.2f%n", fiducial.txnc); + System.out.printf(" TYNC: %.2f%n", fiducial.tync); + System.out.printf(" TA: %.2f%n", fiducial.ta); + System.out.printf(" Distance to Camera: %.2f meters%n", fiducial.distToCamera); + System.out.printf(" Distance to Robot: %.2f meters%n", fiducial.distToRobot); + System.out.printf(" Ambiguity: %.2f%n", fiducial.ambiguity); + System.out.println(); + } + } + + public static Boolean validPoseEstimate(PoseEstimate pose) { + return pose != null && pose.rawFiducials != null && pose.rawFiducials.length != 0; + } + + public static NetworkTable getLimelightNTTable(String tableName) { + return NetworkTableInstance.getDefault().getTable(sanitizeName(tableName)); + } + + public static void Flush() { + NetworkTableInstance.getDefault().flush(); + } + + public static NetworkTableEntry getLimelightNTTableEntry(String tableName, String entryName) { + return getLimelightNTTable(tableName).getEntry(entryName); + } + + public static DoubleArrayEntry getLimelightDoubleArrayEntry(String tableName, String entryName) { + String key = tableName + "/" + entryName; + return doubleArrayEntries.computeIfAbsent(key, k -> { + NetworkTable table = getLimelightNTTable(tableName); + return table.getDoubleArrayTopic(entryName).getEntry(new double[0]); + }); + } + + public static double getLimelightNTDouble(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getDouble(0.0); + } + + public static void setLimelightNTDouble(String tableName, String entryName, double val) { + getLimelightNTTableEntry(tableName, entryName).setDouble(val); + } + + public static void setLimelightNTDoubleArray(String tableName, String entryName, double[] val) { + getLimelightNTTableEntry(tableName, entryName).setDoubleArray(val); + } + + public static double[] getLimelightNTDoubleArray(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getDoubleArray(new double[0]); + } + + + public static String getLimelightNTString(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getString(""); + } + + public static String[] getLimelightNTStringArray(String tableName, String entryName) { + return getLimelightNTTableEntry(tableName, entryName).getStringArray(new String[0]); + } + + + public static URL getLimelightURLString(String tableName, String request) { + String urlString = "http://" + sanitizeName(tableName) + ".local:5807/" + request; + URL url; + try { + url = new URL(urlString); + return url; + } catch (MalformedURLException e) { + System.err.println("bad LL URL"); + } + return null; + } + ///// + ///// + + /** + * Does the Limelight have a valid target? + * @param limelightName Name of the Limelight camera ("" for default) + * @return True if a valid target is present, false otherwise + */ + public static boolean getTV(String limelightName) { + return 1.0 == getLimelightNTDouble(limelightName, "tv"); + } + + /** + * Gets the horizontal offset from the crosshair to the target in degrees. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Horizontal offset angle in degrees + */ + public static double getTX(String limelightName) { + return getLimelightNTDouble(limelightName, "tx"); + } + + /** + * Gets the vertical offset from the crosshair to the target in degrees. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Vertical offset angle in degrees + */ + public static double getTY(String limelightName) { + return getLimelightNTDouble(limelightName, "ty"); + } + + /** + * Gets the horizontal offset from the principal pixel/point to the target in degrees. This is the most accurate 2d metric if you are using a calibrated camera and you don't need adjustable crosshair functionality. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Horizontal offset angle in degrees + */ + public static double getTXNC(String limelightName) { + return getLimelightNTDouble(limelightName, "txnc"); + } + + /** + * Gets the vertical offset from the principal pixel/point to the target in degrees. This is the most accurate 2d metric if you are using a calibrated camera and you don't need adjustable crosshair functionality. + * @param limelightName Name of the Limelight camera ("" for default) + * @return Vertical offset angle in degrees + */ + public static double getTYNC(String limelightName) { + return getLimelightNTDouble(limelightName, "tync"); + } + + /** + * Gets the target area as a percentage of the image (0-100%). + * @param limelightName Name of the Limelight camera ("" for default) + * @return Target area percentage (0-100) + */ + public static double getTA(String limelightName) { + return getLimelightNTDouble(limelightName, "ta"); + } + + /** + * T2D is an array that contains several targeting metrcis + * @param limelightName Name of the Limelight camera + * @return Array containing [targetValid, targetCount, targetLatency, captureLatency, tx, ty, txnc, tync, ta, tid, targetClassIndexDetector, + * targetClassIndexClassifier, targetLongSidePixels, targetShortSidePixels, targetHorizontalExtentPixels, targetVerticalExtentPixels, targetSkewDegrees] + */ + public static double[] getT2DArray(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "t2d"); + } + + /** + * Gets the number of targets currently detected. + * @param limelightName Name of the Limelight camera + * @return Number of detected targets + */ + public static int getTargetCount(String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[1]; + } + return 0; + } + + /** + * Gets the classifier class index from the currently running neural classifier pipeline + * @param limelightName Name of the Limelight camera + * @return Class index from classifier pipeline + */ + public static int getClassifierClassIndex (String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[10]; + } + return 0; + } + + /** + * Gets the detector class index from the primary result of the currently running neural detector pipeline. + * @param limelightName Name of the Limelight camera + * @return Class index from detector pipeline + */ + public static int getDetectorClassIndex (String limelightName) { + double[] t2d = getT2DArray(limelightName); + if(t2d.length == 17) + { + return (int)t2d[11]; + } + return 0; + } + + /** + * Gets the current neural classifier result class name. + * @param limelightName Name of the Limelight camera + * @return Class name string from classifier pipeline + */ + public static String getClassifierClass (String limelightName) { + return getLimelightNTString(limelightName, "tcclass"); + } + + /** + * Gets the primary neural detector result class name. + * @param limelightName Name of the Limelight camera + * @return Class name string from detector pipeline + */ + public static String getDetectorClass (String limelightName) { + return getLimelightNTString(limelightName, "tdclass"); + } + + /** + * Gets the pipeline's processing latency contribution. + * @param limelightName Name of the Limelight camera + * @return Pipeline latency in milliseconds + */ + public static double getLatency_Pipeline(String limelightName) { + return getLimelightNTDouble(limelightName, "tl"); + } + + /** + * Gets the capture latency. + * @param limelightName Name of the Limelight camera + * @return Capture latency in milliseconds + */ + public static double getLatency_Capture(String limelightName) { + return getLimelightNTDouble(limelightName, "cl"); + } + + /** + * Gets the active pipeline index. + * @param limelightName Name of the Limelight camera + * @return Current pipeline index (0-9) + */ + public static double getCurrentPipelineIndex(String limelightName) { + return getLimelightNTDouble(limelightName, "getpipe"); + } + + /** + * Gets the current pipeline type. + * @param limelightName Name of the Limelight camera + * @return Pipeline type string (e.g. "retro", "apriltag", etc) + */ + public static String getCurrentPipelineType(String limelightName) { + return getLimelightNTString(limelightName, "getpipetype"); + } + + /** + * Gets the full JSON results dump. + * @param limelightName Name of the Limelight camera + * @return JSON string containing all current results + */ + public static String getJSONDump(String limelightName) { + return getLimelightNTString(limelightName, "json"); + } + + /** + * Switch to getBotPose + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose"); + } + + /** + * Switch to getBotPose_wpiRed + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose_wpiRed(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + } + + /** + * Switch to getBotPose_wpiBlue + * + * @param limelightName + * @return + */ + @Deprecated + public static double[] getBotpose_wpiBlue(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + } + + public static double[] getBotPose(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose"); + } + + public static double[] getBotPose_wpiRed(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + } + + public static double[] getBotPose_wpiBlue(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + } + + public static double[] getBotPose_TargetSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "botpose_targetspace"); + } + + public static double[] getCameraPose_TargetSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "camerapose_targetspace"); + } + + public static double[] getTargetPose_CameraSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "targetpose_cameraspace"); + } + + public static double[] getTargetPose_RobotSpace(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "targetpose_robotspace"); + } + + public static double[] getTargetColor(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "tc"); + } + + public static double getFiducialID(String limelightName) { + return getLimelightNTDouble(limelightName, "tid"); + } + + public static String getNeuralClassID(String limelightName) { + return getLimelightNTString(limelightName, "tclass"); + } + + public static String[] getRawBarcodeData(String limelightName) { + return getLimelightNTStringArray(limelightName, "rawbarcodes"); + } + + ///// + ///// + + public static Pose3d getBotPose3d(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose"); + return toPose3D(poseArray); + } + + /** + * (Not Recommended) Gets the robot's 3D pose in the WPILib Red Alliance Coordinate System. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation in Red Alliance field space + */ + public static Pose3d getBotPose3d_wpiRed(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_wpired"); + return toPose3D(poseArray); + } + + /** + * (Recommended) Gets the robot's 3D pose in the WPILib Blue Alliance Coordinate System. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation in Blue Alliance field space + */ + public static Pose3d getBotPose3d_wpiBlue(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_wpiblue"); + return toPose3D(poseArray); + } + + /** + * Gets the robot's 3D pose with respect to the currently tracked target's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the robot's position and orientation relative to the target + */ + public static Pose3d getBotPose3d_TargetSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "botpose_targetspace"); + return toPose3D(poseArray); + } + + /** + * Gets the camera's 3D pose with respect to the currently tracked target's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the camera's position and orientation relative to the target + */ + public static Pose3d getCameraPose3d_TargetSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "camerapose_targetspace"); + return toPose3D(poseArray); + } + + /** + * Gets the target's 3D pose with respect to the camera's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the target's position and orientation relative to the camera + */ + public static Pose3d getTargetPose3d_CameraSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "targetpose_cameraspace"); + return toPose3D(poseArray); + } + + /** + * Gets the target's 3D pose with respect to the robot's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the target's position and orientation relative to the robot + */ + public static Pose3d getTargetPose3d_RobotSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "targetpose_robotspace"); + return toPose3D(poseArray); + } + + /** + * Gets the camera's 3D pose with respect to the robot's coordinate system. + * @param limelightName Name/identifier of the Limelight + * @return Pose3d object representing the camera's position and orientation relative to the robot + */ + public static Pose3d getCameraPose3d_RobotSpace(String limelightName) { + double[] poseArray = getLimelightNTDoubleArray(limelightName, "camerapose_robotspace"); + return toPose3D(poseArray); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d_wpiBlue(String limelightName) { + + double[] result = getBotPose_wpiBlue(limelightName); + return toPose2D(result); + } + + /** + * Gets the MegaTag1 Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) in the WPILib Blue alliance coordinate system. + * + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiBlue(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_wpiblue", false); + } + + /** + * Gets the MegaTag2 Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) in the WPILib Blue alliance coordinate system. + * Make sure you are calling setRobotOrientation() before calling this method. + * + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiBlue_MegaTag2(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_orb_wpiblue", true); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d_wpiRed(String limelightName) { + + double[] result = getBotPose_wpiRed(limelightName); + return toPose2D(result); + + } + + /** + * Gets the Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) when you are on the RED + * alliance + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiRed(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_wpired", false); + } + + /** + * Gets the Pose2d and timestamp for use with WPILib pose estimator (addVisionMeasurement) when you are on the RED + * alliance + * @param limelightName + * @return + */ + public static PoseEstimate getBotPoseEstimate_wpiRed_MegaTag2(String limelightName) { + return getBotPoseEstimate(limelightName, "botpose_orb_wpired", true); + } + + /** + * Gets the Pose2d for easy use with Odometry vision pose estimator + * (addVisionMeasurement) + * + * @param limelightName + * @return + */ + public static Pose2d getBotPose2d(String limelightName) { + + double[] result = getBotPose(limelightName); + return toPose2D(result); + + } + + /** + * Gets the current IMU data from NetworkTables. + * IMU data is formatted as [robotYaw, Roll, Pitch, Yaw, gyroX, gyroY, gyroZ, accelX, accelY, accelZ]. + * Returns all zeros if data is invalid or unavailable. + * + * @param limelightName Name/identifier of the Limelight + * @return IMUData object containing all current IMU data + */ + public static IMUData getIMUData(String limelightName) { + double[] imuData = getLimelightNTDoubleArray(limelightName, "imu"); + if (imuData == null || imuData.length < 10) { + return new IMUData(); // Returns object with all zeros + } + return new IMUData(imuData); + } + + ///// + ///// + + public static void setPipelineIndex(String limelightName, int pipelineIndex) { + setLimelightNTDouble(limelightName, "pipeline", pipelineIndex); + } + + + public static void setPriorityTagID(String limelightName, int ID) { + setLimelightNTDouble(limelightName, "priorityid", ID); + } + + /** + * Sets LED mode to be controlled by the current pipeline. + * @param limelightName Name of the Limelight camera + */ + public static void setLEDMode_PipelineControl(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 0); + } + + public static void setLEDMode_ForceOff(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 1); + } + + public static void setLEDMode_ForceBlink(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 2); + } + + public static void setLEDMode_ForceOn(String limelightName) { + setLimelightNTDouble(limelightName, "ledMode", 3); + } + + /** + * Enables standard side-by-side stream mode. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_Standard(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 0); + } + + /** + * Enables Picture-in-Picture mode with secondary stream in the corner. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_PiPMain(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 1); + } + + /** + * Enables Picture-in-Picture mode with primary stream in the corner. + * @param limelightName Name of the Limelight camera + */ + public static void setStreamMode_PiPSecondary(String limelightName) { + setLimelightNTDouble(limelightName, "stream", 2); + } + + + /** + * Sets the crop window for the camera. The crop window in the UI must be completely open. + * @param limelightName Name of the Limelight camera + * @param cropXMin Minimum X value (-1 to 1) + * @param cropXMax Maximum X value (-1 to 1) + * @param cropYMin Minimum Y value (-1 to 1) + * @param cropYMax Maximum Y value (-1 to 1) + */ + public static void setCropWindow(String limelightName, double cropXMin, double cropXMax, double cropYMin, double cropYMax) { + double[] entries = new double[4]; + entries[0] = cropXMin; + entries[1] = cropXMax; + entries[2] = cropYMin; + entries[3] = cropYMax; + setLimelightNTDoubleArray(limelightName, "crop", entries); + } + + /** + * Sets 3D offset point for easy 3D targeting. + */ + public static void setFiducial3DOffset(String limelightName, double offsetX, double offsetY, double offsetZ) { + double[] entries = new double[3]; + entries[0] = offsetX; + entries[1] = offsetY; + entries[2] = offsetZ; + setLimelightNTDoubleArray(limelightName, "fiducial_offset_set", entries); + } + + /** + * Sets robot orientation values used by MegaTag2 localization algorithm. + * + * @param limelightName Name/identifier of the Limelight + * @param yaw Robot yaw in degrees. 0 = robot facing red alliance wall in FRC + * @param yawRate (Unnecessary) Angular velocity of robot yaw in degrees per second + * @param pitch (Unnecessary) Robot pitch in degrees + * @param pitchRate (Unnecessary) Angular velocity of robot pitch in degrees per second + * @param roll (Unnecessary) Robot roll in degrees + * @param rollRate (Unnecessary) Angular velocity of robot roll in degrees per second + */ + public static void SetRobotOrientation(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate) { + SetRobotOrientation_INTERNAL(limelightName, yaw, yawRate, pitch, pitchRate, roll, rollRate, true); + } + + public static void SetRobotOrientation_NoFlush(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate) { + SetRobotOrientation_INTERNAL(limelightName, yaw, yawRate, pitch, pitchRate, roll, rollRate, false); + } + + private static void SetRobotOrientation_INTERNAL(String limelightName, double yaw, double yawRate, + double pitch, double pitchRate, + double roll, double rollRate, boolean flush) { + + double[] entries = new double[6]; + entries[0] = yaw; + entries[1] = yawRate; + entries[2] = pitch; + entries[3] = pitchRate; + entries[4] = roll; + entries[5] = rollRate; + setLimelightNTDoubleArray(limelightName, "robot_orientation_set", entries); + if(flush) + { + Flush(); + } + } + + /** + * Configures the IMU mode for MegaTag2 Localization + * + * @param limelightName Name/identifier of the Limelight + * @param mode IMU mode. + */ + public static void SetIMUMode(String limelightName, int mode) { + setLimelightNTDouble(limelightName, "imumode_set", mode); + } + + /** + * Sets the 3D point-of-interest offset for the current fiducial pipeline. + * https://docs.limelightvision.io/docs/docs-limelight/pipeline-apriltag/apriltag-3d#point-of-interest-tracking + * + * @param limelightName Name/identifier of the Limelight + * @param x X offset in meters + * @param y Y offset in meters + * @param z Z offset in meters + */ + public static void SetFidcuial3DOffset(String limelightName, double x, double y, + double z) { + + double[] entries = new double[3]; + entries[0] = x; + entries[1] = y; + entries[2] = z; + setLimelightNTDoubleArray(limelightName, "fiducial_offset_set", entries); + } + + /** + * Overrides the valid AprilTag IDs that will be used for localization. + * Tags not in this list will be ignored for robot pose estimation. + * + * @param limelightName Name/identifier of the Limelight + * @param validIDs Array of valid AprilTag IDs to track + */ + public static void SetFiducialIDFiltersOverride(String limelightName, int[] validIDs) { + double[] validIDsDouble = new double[validIDs.length]; + for (int i = 0; i < validIDs.length; i++) { + validIDsDouble[i] = validIDs[i]; + } + setLimelightNTDoubleArray(limelightName, "fiducial_id_filters_set", validIDsDouble); + } + + /** + * Sets the downscaling factor for AprilTag detection. + * Increasing downscale can improve performance at the cost of potentially reduced detection range. + * + * @param limelightName Name/identifier of the Limelight + * @param downscale Downscale factor. Valid values: 1.0 (no downscale), 1.5, 2.0, 3.0, 4.0. Set to 0 for pipeline control. + */ + public static void SetFiducialDownscalingOverride(String limelightName, float downscale) + { + int d = 0; // pipeline + if (downscale == 1.0) + { + d = 1; + } + if (downscale == 1.5) + { + d = 2; + } + if (downscale == 2) + { + d = 3; + } + if (downscale == 3) + { + d = 4; + } + if (downscale == 4) + { + d = 5; + } + setLimelightNTDouble(limelightName, "fiducial_downscale_set", d); + } + + /** + * Sets the camera pose relative to the robot. + * @param limelightName Name of the Limelight camera + * @param forward Forward offset in meters + * @param side Side offset in meters + * @param up Up offset in meters + * @param roll Roll angle in degrees + * @param pitch Pitch angle in degrees + * @param yaw Yaw angle in degrees + */ + public static void setCameraPose_RobotSpace(String limelightName, double forward, double side, double up, double roll, double pitch, double yaw) { + double[] entries = new double[6]; + entries[0] = forward; + entries[1] = side; + entries[2] = up; + entries[3] = roll; + entries[4] = pitch; + entries[5] = yaw; + setLimelightNTDoubleArray(limelightName, "camerapose_robotspace_set", entries); + } + + ///// + ///// + + public static void setPythonScriptData(String limelightName, double[] outgoingPythonData) { + setLimelightNTDoubleArray(limelightName, "llrobot", outgoingPythonData); + } + + public static double[] getPythonScriptData(String limelightName) { + return getLimelightNTDoubleArray(limelightName, "llpython"); + } + + ///// + ///// + + /** + * Asynchronously take snapshot. + */ + public static CompletableFuture takeSnapshot(String tableName, String snapshotName) { + return CompletableFuture.supplyAsync(() -> { + return SYNCH_TAKESNAPSHOT(tableName, snapshotName); + }); + } + + private static boolean SYNCH_TAKESNAPSHOT(String tableName, String snapshotName) { + URL url = getLimelightURLString(tableName, "capturesnapshot"); + try { + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + if (snapshotName != null && snapshotName != "") { + connection.setRequestProperty("snapname", snapshotName); + } + + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + return true; + } else { + System.err.println("Bad LL Request"); + } + } catch (IOException e) { + System.err.println(e.getMessage()); + } + return false; + } + + /** + * Gets the latest JSON results output and returns a LimelightResults object. + * @param limelightName Name of the Limelight camera + * @return LimelightResults object containing all current target data + */ + public static LimelightResults getLatestResults(String limelightName) { + + long start = System.nanoTime(); + LimelightHelpers.LimelightResults results = new LimelightHelpers.LimelightResults(); + if (mapper == null) { + mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + + try { + results = mapper.readValue(getJSONDump(limelightName), LimelightResults.class); + } catch (JsonProcessingException e) { + results.error = "lljson error: " + e.getMessage(); + } + + long end = System.nanoTime(); + double millis = (end - start) * .000001; + results.latency_jsonParse = millis; + if (profileJSON) { + System.out.printf("lljson: %.2f\r\n", millis); + } + + return results; + } +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/Robot.java b/2026-Rebuilt/src/main/java/frc/robot/Robot.java index 04e2013..e0d27fa 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Robot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Robot.java @@ -4,41 +4,116 @@ package frc.robot; -import edu.wpi.first.util.sendable.SendableRegistry; -import edu.wpi.first.wpilibj.Joystick; import edu.wpi.first.wpilibj.TimedRobot; -import edu.wpi.first.wpilibj.drive.DifferentialDrive; -import edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; /** - * This is a demo program showing the use of the DifferentialDrive class, specifically it contains - * the code necessary to operate a robot with tank drive. + * The VM is configured to automatically run this class, and to call the functions corresponding to + * each mode, as described in the TimedRobot documentation. If you change the name of this class or + * the package after creating this project, you must also update the build.gradle file in the + * project. */ public class Robot extends TimedRobot { - private final DifferentialDrive m_robotDrive; - private final Joystick m_leftStick; - private final Joystick m_rightStick; - - private final PWMSparkMax m_leftMotor = new PWMSparkMax(0); - private final PWMSparkMax m_rightMotor = new PWMSparkMax(1); - - /** Called once at the beginning of the robot program. */ - public Robot() { - // We need to invert one side of the drivetrain so that positive voltages - // result in both sides moving forward. Depending on how your robot's - // gearbox is constructed, you might have to invert the left side instead. - m_rightMotor.setInverted(true); - - m_robotDrive = new DifferentialDrive(m_leftMotor::set, m_rightMotor::set); - m_leftStick = new Joystick(0); - m_rightStick = new Joystick(1); - - SendableRegistry.addChild(m_robotDrive, m_leftMotor); - SendableRegistry.addChild(m_robotDrive, m_rightMotor); + private Command m_autonomousCommand; + + private RobotContainer m_robotContainer; + + /** + * This function is run when the robot is first started up and should be used for any + * initialization code. + */ + @Override + public void robotInit() { + // Instantiate our RobotContainer. This will perform all our button bindings, and put our + // autonomous chooser on the dashboard. + m_robotContainer = new RobotContainer(); + m_robotContainer.InitSmartDashboard(); + } + + /** + * This function is called every 20 ms, no matter the mode. Use this for items like diagnostics + * that you want ran during disabled, autonomous, teleoperated and test. + * + *

This runs after the mode specific periodic functions, but before LiveWindow and + * SmartDashboard integrated updating. + */ + @Override + public void robotPeriodic() { + // Runs the Scheduler. This is responsible for polling buttons, adding newly-scheduled + // commands, running already-scheduled commands, removing finished or interrupted commands, + // and running subsystem periodic() methods. This must be called from the robot's periodic + // block in order for anything in the Command-based framework to work. + CommandScheduler.getInstance().run(); + + // Send subsystem and robot state back to the driver station. + m_robotContainer.UpdateSmartDashboard(); + } + + /** This function is called once each time the robot enters Disabled mode. */ + @Override + public void disabledInit() { + m_robotContainer.disabledInit(); + } + + @Override + public void disabledPeriodic() { + LimelightHelpers.SetIMUMode("limelight", 3); + m_robotContainer.disabledPeriodic(); + } + + /** This autonomous runs the autonomous command selected by your {@link RobotContainer} class. */ + @Override + public void autonomousInit() { + m_robotContainer.enabledInit(); + m_robotContainer.autoInit(); + + m_autonomousCommand = m_robotContainer.getAutonomousCommand(); + + // schedule the autonomous command (example) + if (m_autonomousCommand != null) { + m_autonomousCommand.schedule(); + } + } + + /** This function is called periodically during autonomous. */ + @Override + public void autonomousPeriodic() {} + + @Override + public void teleopInit() { + // This makes sure that the autonomous stops running when + // teleop starts running. If you want the autonomous to + // continue until interrupted by another command, remove + // this line or comment it out. + if (m_autonomousCommand != null) { + m_autonomousCommand.cancel(); + } + + m_robotContainer.enabledInit(); + + m_robotContainer.teleopInit(); } + /** This function is called periodically during operator control. */ @Override - public void teleopPeriodic() { - m_robotDrive.tankDrive(-m_leftStick.getY(), -m_rightStick.getY()); + public void teleopPeriodic() {} + + @Override + public void testInit() { + // Cancels all running commands at the start of test mode. + CommandScheduler.getInstance().cancelAll(); } + + /** This function is called periodically during test mode. */ + @Override + public void testPeriodic() {} + + /** This function is called once when the robot is first started up. */ + @Override + public void simulationInit() {} + + /** This function is called periodically whilst in simulation. */ + @Override + public void simulationPeriodic() {} } diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java new file mode 100644 index 0000000..917b687 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -0,0 +1,266 @@ +// 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 java.util.ArrayList; +import java.util.Optional; + +import com.ctre.phoenix6.hardware.TalonFX; +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.studica.frc.AHRS; +import com.studica.frc.AHRS.NavXComType; + +import edu.wpi.first.math.VecBuilder; +import edu.wpi.first.math.Vector; +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import edu.wpi.first.math.numbers.N3; +import edu.wpi.first.wpilibj.smartdashboard.Field2d; +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.CommandScheduler; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import edu.wpi.first.wpilibj2.command.button.Trigger; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.Constants.OperatorConstants; +import frc.robot.commands.DriveForwardFromPos; +import frc.robot.factorys.DriveSubsystemFactory; +import frc.robot.factorys.TalonFXFactory; +import frc.robot.subsystems.DriveSubsystem; +import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.IndexerBulkSubsystem; +import frc.robot.subsystems.IntakeSubsystem; +import frc.robot.subsystems.ClimbL1Subsystem; +import frc.robot.subsystems.LimelightSubsystem; +import frc.robot.utils.AutoCommands; + +/** + * This class is where the bulk of the robot should be declared. Since Command-based is a + * "declarative" paradigm, very little robot logic should actually be handled in the {@link Robot} + * periodic methods (other than the scheduler calls). Instead, the structure of the robot (including + * subsystems, commands, and trigger mappings) should be declared here. + */ +public class RobotContainer { + // The robot's subsystems and commands are defined here... + private final Optional m_driveSubsystem; + private final Optional m_intakeSubsystem; + private final Optional m_climbL1Subsystem; + private final Optional m_indexerBulkSubsystem; + private final Optional m_launcherSubsystem; + private final LimelightSubsystem m_limelightSubsystem; + + // Replace with CommandPS4Controller or CommandJoystick if needed + private final CommandXboxController m_driverController = + new CommandXboxController(OperatorConstants.kDriverControllerPort); + + private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); + private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.kTrackWidthMeters); + + // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. + private Vector m_drivetrainError = VecBuilder.fill(0.2, 0.2, 0); + private Vector m_limelightError = VecBuilder.fill(.7,.7,9999999); + + private DifferentialDrivePoseEstimator m_PoseEstimator = new DifferentialDrivePoseEstimator( + m_DriveKinematics, + Rotation2d.fromDegrees(0.0), + 0, + 0, + new Pose2d(0.0, 8.0, new Rotation2d()), + m_drivetrainError, + m_limelightError + ); + + // Smartdashboard Objects + private SendableChooser m_autoChooser; + private final Field2d m_field = new Field2d(); + + // Factorys + private TalonFXFactory m_TalonFXFactory = new TalonFXFactory(); + private DriveSubsystemFactory m_DriveSubsystemFactory = new DriveSubsystemFactory(); + + // Keep track of time for SmartDashboard updates. + static int m_iTickCount = 0; + + /** The container for the robot. Contains subsystems, OI devices, and commands. */ + public RobotContainer() { + // Init DriveSubsystem + Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); + Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); + Optional rightFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalRightMotorCANID); + Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); + m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); + + // Init the subsystems + m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_gyro); + m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); + m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); + m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); + m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); + + // Init Auto + configureAutos(); + + // Configure the default commands + configureDefaultCommands(); + + // Configure the trigger bindings + configureBindings(); + } + + // Tom wrote this cool template to make the optional subsystem creation code in + // the constructor above a lot clearer. This is what clever coding looks like. + private static Optional getSubsystem(Class subsystemClass) { + Optional iss; + try { + iss = Optional.ofNullable(subsystemClass.getDeclaredConstructor().newInstance()); + } catch (Exception e) { + iss = Optional.empty(); + } + return iss; + } + + private void configureAutos() { + // Init Autos (/home/lvuser/deploy/pathplanner/autos) + // AutoCommands.getAutoCommands(m_driveSubsystem); + + // // Init Chooser + // m_autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string + m_autoChooser = new SendableChooser(); + + // Custom Autos + m_autoChooser.addOption( + "On-Fly Forward 2m", + new DriveForwardFromPos(m_PoseEstimator, 2) + ); + + // Path Planner Auto's + ArrayList autoNames = AutoCommands.getAutoNames(); + for (String autoName : autoNames) { + PathPlannerAuto auto = new PathPlannerAuto(autoName); + m_autoChooser.addOption(autoName, auto); + } + + // Add to dashboard + SmartDashboard.putData("Auto Chooser", m_autoChooser); + } + + private void configureDefaultCommands() { + if (m_driveSubsystem.isPresent()) + { + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + driveSubsystem.initDefaultCommand(m_driverController); + } + } + + /** + * Use this method to define your trigger->command mappings. Triggers can be created via the + * {@link Trigger#Trigger(java.util.function.BooleanSupplier)} constructor with an arbitrary + * predicate, or via the named factories in {@link + * edu.wpi.first.wpilibj2.command.button.CommandGenericHID}'s subclasses for {@link + * CommandXboxController Xbox}/{@link edu.wpi.first.wpilibj2.command.button.CommandPS4Controller + * PS4} controllers or {@link edu.wpi.first.wpilibj2.command.button.CommandJoystick Flight + * joysticks}. + */ + private void configureBindings() { + // SmartDashboard.putBoolean("Example Subsystem", m_exampleSubsystem.isPresent()); + + // if (m_exampleSubsystem.isPresent()) + // { + // ExampleSubsystem exampleSubsystem = m_exampleSubsystem.get(); + + // // Schedule `ExampleCommand` when `exampleCondition` changes to `true` + // new Trigger(exampleSubsystem::exampleCondition) + // .onTrue(new ExampleCommand(exampleSubsystem)); + + // // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed, + // // cancelling on release. + // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); + // } + } + + // Populate the SmartDashboard on robot init. + public void InitSmartDashboard() { + // Non-Subsystem Specific Stuff + SmartDashboard.putData(CommandScheduler.getInstance()); + SmartDashboard.putData("Field", m_field); + } + + // This function is called every 20mS. + public void UpdateSmartDashboard() { + // Non-subsystem specific stuff + if ((m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) { + Pose2d estimatedPos = m_PoseEstimator.getEstimatedPosition(); + m_field.setRobotPose(estimatedPos); + + SmartDashboard.putNumber("Pose X (Meter)", estimatedPos.getX()); + SmartDashboard.putNumber("Pose Y (Meter)", estimatedPos.getY()); + SmartDashboard.putNumber("Pose Theta (Degrees)", estimatedPos.getRotation().getDegrees()); + + SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); + } + + // Drive subsystem + if(m_driveSubsystem.isPresent() && (m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) + { + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + + SmartDashboard.putNumber("Left Speed (MPS)", driveSubsystem.getMotorSpeedMPS(true)); + SmartDashboard.putNumber("Right Speed (MPS)", driveSubsystem.getMotorSpeedMPS(false)); + SmartDashboard.putNumber("Left Speed (RPS)", driveSubsystem.getMotorSpeedRPS(true)); + SmartDashboard.putNumber("Right Speed (RPS)", driveSubsystem.getMotorSpeedRPS(false)); + + SmartDashboard.putNumber("Left Distance (m)", driveSubsystem.getMotorPositionMeters(true)); + SmartDashboard.putNumber("Right Distance (m)", driveSubsystem.getMotorPositionMeters(false)); + + SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); + } + + m_iTickCount++; + } + + public void disabledInit() {} + + // Move to auto init for competition code. + public void enabledInit() { + LimelightHelpers.SetIMUMode("limelight", 4); + m_gyro.enableLogging(true); + } + + public void teleopInit() { + configureDefaultCommands(); + } + + public void autoInit() { + // This causes issues when auto's do not reset odometry!! + // if (m_driveSubsystem.isPresent()) { + // DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + + // m_gyro.reset(); + // driveSubsystem.resetPose(new Pose2d()); + // } + } + + // Gets called every disabled tick. + public void disabledPeriodic() { + double cameraYaw = m_limelightSubsystem.getRobotYaw(); + + m_gyro.enableLogging(false); + m_gyro.reset(); + m_gyro.setAngleAdjustment(-cameraYaw); + } + + /** + * Use this to pass the autonomous command to the main {@link Robot} class. + * + * @return the command to run in autonomous + */ + public Command getAutonomousCommand() { + return m_autoChooser.getSelected(); + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java new file mode 100644 index 0000000..65eb3bd --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -0,0 +1,84 @@ +// 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.commands; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.Constants.OperatorConstants; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; + +/** An example command that uses an example subsystem. */ +public class ArcadeDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + double speedInput = -m_driveController.getRightY(); + double turnInput = m_driveController.getLeftX(); + + // Set the deadband + if (Math.abs(speedInput) < OperatorConstants.kDriverControllerDeadband) { + speedInput = 0; + } + if (Math.abs(turnInput) < OperatorConstants.kDriverControllerDeadband) { + turnInput = 0; + } + + double leftSpeed = speedInput + turnInput; + double rightSpeed = speedInput - turnInput; + + // Find the maximum possible value of (throttle + turn) along the vector + // that the joystick is pointing, then desaturate the wheel speeds + double greaterInput = Math.max(Math.abs(speedInput), Math.abs(turnInput)); + double lesserInput = Math.min(Math.abs(speedInput), Math.abs(turnInput)); + if (greaterInput == 0.0) { + m_subsystem.setDifferentialSpeeds( + 0, + 0 + ); + } else { + double saturatedInput = (greaterInput + lesserInput) / greaterInput; + leftSpeed /= saturatedInput; + rightSpeed /= saturatedInput; + + m_subsystem.setDifferentialSpeeds( + leftSpeed * DrivetrainConstants.kMaxVelocityMPS, + rightSpeed * DrivetrainConstants.kMaxVelocityMPS + ); + } + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java new file mode 100644 index 0000000..88ee73a --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java @@ -0,0 +1,77 @@ +// 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.commands; +import frc.robot.Constants.OperatorConstants; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; + +/** An example command that uses an example subsystem. */ +public class ArcadeDriveCommandNoPID extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeDriveCommandNoPID(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + double speedInput = -m_driveController.getRightY(); + double turnInput = m_driveController.getLeftX(); + + // Set the deadband + if (Math.abs(speedInput) < OperatorConstants.kDriverControllerDeadband) { + speedInput = 0; + } + if (Math.abs(turnInput) < OperatorConstants.kDriverControllerDeadband) { + turnInput = 0; + } + + double leftSpeed = speedInput + turnInput; + double rightSpeed = speedInput - turnInput; + + // Find the maximum possible value of (throttle + turn) along the vector + // that the joystick is pointing, then desaturate the wheel speeds + double greaterInput = Math.max(Math.abs(speedInput), Math.abs(turnInput)); + double lesserInput = Math.min(Math.abs(speedInput), Math.abs(turnInput)); + if (greaterInput == 0.0) { + m_subsystem.setDifferentialSpeedNoPid(0, 0); + } else { + double saturatedInput = (greaterInput + lesserInput) / greaterInput; + leftSpeed /= saturatedInput; + rightSpeed /= saturatedInput; + + m_subsystem.setDifferentialSpeedNoPid(leftSpeed, rightSpeed); + } + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java new file mode 100644 index 0000000..f35dc4f --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java @@ -0,0 +1,43 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.subsystems.DriveSubsystem; + +public class ArcadeFromDashboard extends Command { + private final DriveSubsystem m_subsystem; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ArcadeFromDashboard(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + double speed = SmartDashboard.getNumber("DB Arcade Set (MPS)", 0); + m_subsystem.setDifferentialSpeeds( speed, speed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java new file mode 100644 index 0000000..107aad7 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java @@ -0,0 +1,20 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.Commands; + +public final class Autos { + /** Example static factory for an autonomous command. */ + public static Command exampleAuto(ExampleSubsystem subsystem) { + return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); + } + + private Autos() { + throw new UnsupportedOperationException("This is a utility class!"); + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java new file mode 100644 index 0000000..a53bd80 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java @@ -0,0 +1,45 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.subsystems.DriveSubsystem; + +public class DifferentailDriveFromDashboard extends Command { + private final DriveSubsystem m_subsystem; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public DifferentailDriveFromDashboard(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + double leftSpeed = SmartDashboard.getNumber("DB Left Set (MPS)", 0); + double rightSpeed = SmartDashboard.getNumber("DB Right Set (MPS)", 0); + + m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java new file mode 100644 index 0000000..16b0322 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -0,0 +1,66 @@ +// Copyright (c) FIRST and other WPILib contributors. +// Open Source Software; you can modify and/or share it under the terms of +// the WPILib BSD license file in the root directory of this project. + +package frc.robot.commands; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.Constants.OperatorConstants; + +/** An example command that uses an example subsystem. */ +public class DifferentialDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + private CommandXboxController m_driveController; + + /** + * Creates a new ArcadeDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public DifferentialDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + // Note: We negate both axis values so that pushing the joystick forwards + // (which makes the readin more negative) increases the speed and twisting clockwise + // turns the robot clockwise. + double leftSpeed = -m_driveController.getLeftY(); + double rightSpeed = -m_driveController.getRightY(); + + // Set the deadband + if (Math.abs(leftSpeed) < OperatorConstants.kDriverControllerDeadband) { + leftSpeed = 0; + } + if (Math.abs(rightSpeed) < OperatorConstants.kDriverControllerDeadband) { + rightSpeed = 0; + } + + leftSpeed *= DrivetrainConstants.kMaxVelocityMPS; + rightSpeed *= DrivetrainConstants.kMaxVelocityMPS; + + m_subsystem.setDifferentialSpeeds( leftSpeed, rightSpeed ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java new file mode 100644 index 0000000..a17ac62 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java @@ -0,0 +1,98 @@ +package frc.robot.commands; + +import java.util.List; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.GoalEndState; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.path.Waypoint; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; + +/** An example command that uses an example subsystem. */ +public class DriveForwardFromPos extends Command { + private final DifferentialDrivePoseEstimator m_poseEstimator; + private double m_targetDistance = 0.0; + + /** + * Creates a new DriveForward2mFromPos. + * + * @param subsystem The subsystem used by this command. + */ + public DriveForwardFromPos(DifferentialDrivePoseEstimator poseEstimator, double targetDistance) + { + m_poseEstimator = poseEstimator; + m_targetDistance = targetDistance; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This is taken and modified from the limelight documentation for + // path creation on the fly: https://pathplanner.dev/pplib-create-a-path-on-the-fly.html + + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + Rotation2d currentRotation = currentPose.getRotation(); + + double currentX = currentPose.getX(); + double currentY = currentPose.getY(); + + // If we think of the direction we want to go as of the hypotonuse of a + // right trinagle, we can calculate the needed distance to travel on + // the (x, y) by calculating for them as the legs of the RT. + double xMod = m_targetDistance * currentRotation.getCos(); + double yMod = m_targetDistance * currentRotation.getSin(); + + double newX = currentX + xMod; + double newY = currentY + yMod; + + // Create a list of waypoints from poses. Each pose represents one waypoint. + // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. + List waypoints = PathPlannerPath.waypointsFromPoses( + new Pose2d(currentX, currentY, currentRotation), + new Pose2d(newX, newY, currentRotation) + ); + + PathConstraints constraints = new PathConstraints( + 1.0, + 1.0, + 2 * Math.PI, + 4 * Math.PI + ); // The constraints for this path. + + // Create the path using the waypoints created above + PathPlannerPath path = new PathPlannerPath( + waypoints, + constraints, + null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. + new GoalEndState(0.0, currentRotation) // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. + ); + + // Prevent the path from being flipped if the coordinates are already correct + path.preventFlipping = true; + + // Create the command version of the path and schedule it + Command followPath = AutoBuilder.followPath(path); + CommandScheduler.getInstance().schedule(followPath); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java new file mode 100644 index 0000000..151624c --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java @@ -0,0 +1,43 @@ +// 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.commands; + +import frc.robot.subsystems.ExampleSubsystem; +import edu.wpi.first.wpilibj2.command.Command; + +/** An example command that uses an example subsystem. */ +public class ExampleCommand extends Command { + @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField", "unused"}) + private final ExampleSubsystem m_subsystem; + + /** + * Creates a new ExampleCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ExampleCommand(ExampleSubsystem subsystem) { + m_subsystem = subsystem; + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java new file mode 100644 index 0000000..afc5b84 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -0,0 +1,33 @@ +package frc.robot.factorys; + +import java.util.Optional; +import com.ctre.phoenix6.hardware.TalonFX; +import com.studica.frc.AHRS; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import frc.robot.subsystems.DriveSubsystem; + +public class DriveSubsystemFactory { + public DriveSubsystemFactory() { + } + + public Optional construct(DifferentialDrivePoseEstimator poseEstimator, + DifferentialDriveKinematics kinematics, + AHRS gyro, Optional rightLead, Optional leftLead, Optional rightFollower, + Optional leftFollower) { + + if (rightLead.isEmpty() || leftLead.isEmpty()) { + return Optional.empty(); + } + + DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, gyro, rightLead.get(), + leftLead.get()); + + if (rightFollower.isPresent() && leftFollower.isPresent()) { + driveSubsystem.setFollowers(rightFollower.get(), leftFollower.get()); + } + + return Optional.of(driveSubsystem); + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/factorys/TalonFXFactory.java b/2026-Rebuilt/src/main/java/frc/robot/factorys/TalonFXFactory.java new file mode 100644 index 0000000..e50c14e --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/factorys/TalonFXFactory.java @@ -0,0 +1,19 @@ +package frc.robot.factorys; + +import java.util.Optional; + +import com.ctre.phoenix6.hardware.TalonFX; + +public class TalonFXFactory { + public TalonFXFactory() {} + + public Optional construct(int CANID) { + TalonFX talon = new TalonFX(CANID); + + if (talon.isConnected()) { + return Optional.of(talon); + } else { + return Optional.empty(); + } + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java new file mode 100644 index 0000000..8c2c8e0 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -0,0 +1,25 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.SubsystemBase; + + +public class ClimbL1Subsystem extends SubsystemBase { + /** Creates a new ClimbL1Subsystem. */ + public ClimbL1Subsystem() { + // TODO: write this + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java new file mode 100644 index 0000000..67ac57b --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -0,0 +1,325 @@ +// 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. + +// https://github.com/CrossTheRoadElec/Phoenix6-Examples/blob/main/java/VelocityClosedLoop/src/main/java/frc/robot/Robot.java +// This is a link to do speed control on the kraken motors. We need something like this. +package frc.robot.subsystems; +import static edu.wpi.first.units.Units.Volts; + +import com.ctre.phoenix6.StatusCode; +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.Follower; +import com.ctre.phoenix6.controls.MotionMagicVelocityVoltage; +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.signals.InvertedValue; +import com.ctre.phoenix6.signals.MotorAlignmentValue; +import com.ctre.phoenix6.signals.NeutralModeValue; +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.controllers.PPLTVController; +import com.studica.frc.AHRS; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.kinematics.ChassisSpeeds; +import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; +import edu.wpi.first.math.kinematics.DifferentialDriveWheelSpeeds; +import edu.wpi.first.util.sendable.SendableRegistry; +import edu.wpi.first.wpilibj.DriverStation; +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.SubsystemBase; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; +import frc.robot.Constants.AutoConstants; +import frc.robot.Constants.DrivetrainConstants; +import frc.robot.commands.ArcadeDriveCommand; +import frc.robot.commands.ArcadeDriveCommandNoPID; +import frc.robot.commands.ArcadeFromDashboard; +import frc.robot.commands.DifferentialDriveCommand; + +public class DriveSubsystem extends SubsystemBase { + private TalonFX m_rightMotor; + private TalonFX m_optionalRightMotor; + + private TalonFX m_leftMotor; + private TalonFX m_optionalLeftMotor; + + /* Start at velocity 0, use slot 0 */ + private final MotionMagicVelocityVoltage m_leftVelocityVoltage = new MotionMagicVelocityVoltage(0);//.withSlot(0); + private final MotionMagicVelocityVoltage m_rightVelocityVoltage = new MotionMagicVelocityVoltage(0);//.withSlot(0); + + private final DifferentialDriveKinematics m_kinematics; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final AHRS m_gyro; + + private final SendableChooser> m_driveChooser = new SendableChooser<>(); + + /** Creates a new DriveSubsystem. */ + public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, AHRS gyro, TalonFX rightMotor, TalonFX leftMotor) { + m_poseEstimator = poseEstimator; + m_kinematics = kinematics; + m_gyro = gyro; + m_rightMotor = rightMotor; + m_leftMotor = leftMotor; + + // Right Motor + setConfig(m_rightMotor, InvertedValue.CounterClockwise_Positive); + SendableRegistry.setName(m_rightMotor, "DriveSubsystem", "rightMotor"); + + // Left Motor + setConfig(m_leftMotor, InvertedValue.Clockwise_Positive); + SendableRegistry.setName(m_leftMotor, "DriveSubsystem", "leftMotor"); + + // Zeroing the encoders + m_leftMotor.setPosition(0); + m_rightMotor.setPosition(0); + + // Init Autobuilder + AutoBuilder.configure( + this::getPose, + this::resetPose, + this::getRobotRelativeSpeeds, + (speeds, feedforwards) -> driveRobotRelative(speeds), + new PPLTVController(0.02), + AutoConstants.kRobotConfig, + () -> { + // Boolean supplier that controls when the path will be mirrored for the red alliance + // This will flip the path being followed to the red side of the field. + // THE ORIGIN WILL REMAIN ON THE BLUE SIDE + + var alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + return alliance.get() == DriverStation.Alliance.Red; + } + return false; + }, + this + ); + + // Gyro setup + m_gyro.reset(); + + // Drive Chooser Init + m_driveChooser.setDefaultOption("PID Arcade", ArcadeDriveCommand.class); + m_driveChooser.addOption("PID Differential", DifferentialDriveCommand.class); + m_driveChooser.addOption("NO-PID Arcade", ArcadeDriveCommandNoPID.class); + m_driveChooser.addOption("Dashboard PID Arcade", ArcadeFromDashboard.class); + SmartDashboard.putData("Drive Commands", m_driveChooser); + + // Init Smartdashboard + SmartDashboard.putNumber("DB Left Set (MPS)", 0); + SmartDashboard.putNumber("DB Right Set (MPS)", 0); + SmartDashboard.putNumber("DB Arcade Set (MPS)", 0); + + SmartDashboard.putNumber("Left Target (MPS)", 0); + SmartDashboard.putNumber("Right Target (MPS)", 0); + SmartDashboard.putNumber("Left Speed (MPS)", getMotorSpeedMPS(true)); + SmartDashboard.putNumber("Right Speed (MPS)", getMotorSpeedMPS(false)); + SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); + SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); + + SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); + } + + private void setConfig(TalonFX motor, InvertedValue Inverted) { + TalonFXConfiguration motorConfig = new TalonFXConfiguration(); + motorConfig.Slot0.kS = DrivetrainConstants.kS; + motorConfig.Slot0.kV = DrivetrainConstants.kV; + motorConfig.Slot0.kA = DrivetrainConstants.kA_linear; + motorConfig.Slot0.kP = DrivetrainConstants.kP; + motorConfig.Slot0.kI = DrivetrainConstants.kI; // No output for integrated error + motorConfig.Slot0.kD = DrivetrainConstants.kD; // A velocity of 1 rps results in 0.1 V output + + motorConfig.MotorOutput.NeutralMode = NeutralModeValue.Brake; + motorConfig.MotorOutput.Inverted = Inverted; + + motorConfig.Voltage.withPeakForwardVoltage(Volts.of(DrivetrainConstants.kPeakVoltage)) + .withPeakReverseVoltage(Volts.of(-DrivetrainConstants.kPeakVoltage)); + + var motionMagicConfigs = motorConfig.MotionMagic; + motionMagicConfigs.MotionMagicAcceleration = DrivetrainConstants.kMotionMagicAcceleration; + motionMagicConfigs.MotionMagicJerk = DrivetrainConstants.kMotionMagicJerk; + + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = motor.getConfigurator().apply(motorConfig); + System.out.println("config attempt #" + (i+1) + ": " + status.toString()); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs, error code: " + status.toString()); + } + } + + public void setFollowers(TalonFX optionalRight, TalonFX optionalLeft) { + // Right Motor + m_optionalRightMotor = optionalRight; + + setConfig(m_optionalRightMotor, InvertedValue.CounterClockwise_Positive); + m_optionalRightMotor.setControl( + new Follower(m_rightMotor.getDeviceID(), MotorAlignmentValue.Aligned) + ); + + // Left Motor + m_optionalLeftMotor = optionalLeft; + + setConfig(m_optionalLeftMotor, InvertedValue.Clockwise_Positive); + m_optionalLeftMotor.setControl( + new Follower(m_leftMotor.getDeviceID(), MotorAlignmentValue.Aligned) + ); + } + + // This takes the current class selected in the drive chooser and attempts to initilize a command object from it & run it. + // The commands must have a constructor with a DriveSubsystem and CommandXboxController as args. + public void initDefaultCommand(CommandXboxController Controller) + { + Class driveClass = m_driveChooser.getSelected(); + + try { + Object driveCommand = driveClass.getDeclaredConstructor(DriveSubsystem.class, CommandXboxController.class).newInstance(this, Controller); + setDefaultCommand((Command) driveCommand); + + System.out.println(String.format("Loaded drive command \"%s\"!", driveClass.getName())); + } catch (Exception e) { + DriverStation.reportWarning( + String.format( + "Failed to load drive command \"%s\"!", driveClass.getName()), + false + ); + + e.printStackTrace(); + } + + // setDefaultCommand(new ArcadeDriveCommand(this, Controller)); + } + + // TODO: Work on a naming scheme for conversion functions + + // This converts rotations of the motor shaft to meters travled. + public double ConvertRotationsToMeters(double rotations) { + return rotations * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; + } + + // This converts meters travled to rotations of the motor shaft. + // This is the inverse function of the one above, calculated it myself. - Owen + public double ConvertMetersToRotations(double meters) { + return (meters / DrivetrainConstants.kDrivetrainGearRatio) / DrivetrainConstants.kWheelCircumference; + } + + // This sets the differential speeds based on a desired MPS speed. + public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) + { + SmartDashboard.putNumber("Left Target (MPS)", leftSpeedMPS); + SmartDashboard.putNumber("Right Target (MPS)", rightSpeedMPS); + + double leftSpeedRPS = ConvertMetersToRotations(leftSpeedMPS); + double rightSpeedRPS = ConvertMetersToRotations(rightSpeedMPS); + + SmartDashboard.putNumber("Left Target (RPS)", leftSpeedRPS); + SmartDashboard.putNumber("Right Target (RPS)", rightSpeedRPS); + + m_leftMotor.setControl(m_leftVelocityVoltage.withVelocity(leftSpeedRPS)); + m_rightMotor.setControl(m_rightVelocityVoltage.withVelocity(rightSpeedRPS)); + } + + // pass in -1 to 1 for the motor speed with no closed loop control. + public void setDifferentialSpeedNoPid(double left, double right) { + m_leftMotor.set(left); + m_rightMotor.set(right); + } + + // Wrapping robot position inside of getposition + public Pose2d getPose(){ + return m_poseEstimator.getEstimatedPosition(); + } + + // Resets the drivetrains pose estimator to zero. + public void resetPose(Pose2d newPose){ + m_leftMotor.setPosition(0); + m_rightMotor.setPosition(0); + + m_poseEstimator.resetPosition( + m_gyro.getRotation2d(), + 0, 0, + newPose + ); + } + + public double getMotorSpeedRPS(boolean bLeft) + { + double RPS; + if (bLeft) + { + RPS = m_leftMotor.getVelocity().getValueAsDouble(); + } + else + { + RPS = m_rightMotor.getVelocity().getValueAsDouble(); + } + return RPS; + } + + public double getMotorSpeedMPS(boolean bLeft) + { + double RPS = getMotorSpeedRPS(bLeft); + double MPS = ConvertRotationsToMeters(RPS); + return MPS; + } + + // Gets the distance traveled by the motor in meters + public double getMotorPositionMeters(boolean bLeft) { + double posRotations; + if (bLeft == true) { + posRotations = m_leftMotor.getPosition().getValueAsDouble(); + } else { + posRotations = m_rightMotor.getPosition().getValueAsDouble(); + } + + double posMeters = ConvertRotationsToMeters(posRotations); + return posMeters; + } + + // Returns a robot relative ChassisSpeeds object based on the average linear velocity + // in meters per second and average angular velocity in radians per second. + // Currently we are assuming that there is no scale for the motors, we cannot find anywhere to set the scale. + public ChassisSpeeds getRobotRelativeSpeeds() + { + // Linear velocity in meters per second + double leftMPS = getMotorSpeedMPS(true); + double rightMPS = getMotorSpeedMPS(false); + + // Make wheelSpeeds object from MPS & converts it to chasis speeds + DifferentialDriveWheelSpeeds wheelSpeeds = new DifferentialDriveWheelSpeeds(leftMPS, rightMPS); + return m_kinematics.toChassisSpeeds(wheelSpeeds); + } + + // Gives the drivetrain a new drive command based on a robot relative + // chassis speed object. + public void driveRobotRelative(ChassisSpeeds relativeChassisSpeed){ + DifferentialDriveWheelSpeeds wheelSpeeds = m_kinematics.toWheelSpeeds(relativeChassisSpeed); + + setDifferentialSpeeds(wheelSpeeds.leftMetersPerSecond, wheelSpeeds.rightMetersPerSecond); + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + double lPositionMeters = getMotorPositionMeters(true); + double rPositionMeters = getMotorPositionMeters(false); + Rotation2d yaw = m_gyro.getRotation2d(); + //m_gyro.getAngle() + + m_poseEstimator.update( + yaw, + lPositionMeters, + rPositionMeters + ); + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java new file mode 100644 index 0000000..6b375da --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java @@ -0,0 +1,47 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.SubsystemBase; + +public class ExampleSubsystem extends SubsystemBase { + /** Creates a new ExampleSubsystem. */ + public ExampleSubsystem() {} + + /** + * Example command factory method. + * + * @return a command + */ + public Command exampleMethodCommand() { + // Inline construction of command goes here. + // Subsystem::RunOnce implicitly requires `this` subsystem. + return runOnce( + () -> { + /* one-time action goes here */ + }); + } + + /** + * An example method querying a boolean state of the subsystem (for example, a digital sensor). + * + * @return value of some boolean subsystem state, such as a digital sensor. + */ + public boolean exampleCondition() { + // Query some boolean state, such as a digital sensor. + return false; + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java new file mode 100644 index 0000000..1c582d7 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -0,0 +1,25 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.SubsystemBase; + + +public class IndexerBulkSubsystem extends SubsystemBase { + /** Creates a new IndexerBulkSubsystem. */ + public IndexerBulkSubsystem() { + // TODO: write this + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java new file mode 100644 index 0000000..00e45b6 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -0,0 +1,25 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.SubsystemBase; + + +public class IntakeSubsystem extends SubsystemBase { + /** Creates a new IntakeSubsystem. */ + public IntakeSubsystem() { + // TODO: write this + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java new file mode 100644 index 0000000..dd1d516 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -0,0 +1,25 @@ +// 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.subsystems; + +import edu.wpi.first.wpilibj2.command.SubsystemBase; + + +public class LauncherSubsystem extends SubsystemBase { + /** Creates a new LauncherSubsystem. */ + public LauncherSubsystem() { + // TODO: write this + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java new file mode 100644 index 0000000..4e21387 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -0,0 +1,110 @@ +// 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.subsystems; +import java.util.Arrays; + +import org.ejml.simple.SimpleMatrix; + +import com.studica.frc.AHRS; + +import edu.wpi.first.math.VecBuilder; +import edu.wpi.first.math.Vector; +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.numbers.N3; +import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import frc.robot.LimelightHelpers; +import frc.robot.LimelightHelpers.IMUData; +import frc.robot.utils.LimitedQueue; + +public class LimelightSubsystem extends SubsystemBase { + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final AHRS m_gyro; + + private final LimitedQueue m_YawQue = new LimitedQueue(5); + + /** Creates a new PositionSubsystem. */ + public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { + m_poseEstimator = poseEstimator; + m_gyro = gyro; + + m_gyro.enableLogging(false); + } + + public double getRobotYaw() { + Double[] doubleObjects = m_YawQue.toArray(new Double[0]); + int queSize = doubleObjects.length; + + double[] primitiveDoubles = new double[queSize]; + for (int i = 0; i < queSize; i++) { + primitiveDoubles[i] = doubleObjects[i].doubleValue(); + } + + SimpleMatrix samplesMatrix = new SimpleMatrix(primitiveDoubles); + + double[] weightsArray = new double[queSize]; + Arrays.fill(weightsArray, 1.0); + + SimpleMatrix weightsMatrix = new SimpleMatrix(1, queSize, true, weightsArray); + + double avrg = samplesMatrix.dot(weightsMatrix)/weightsMatrix.elementSum(); + return avrg; + } + + // This is copy and pasted from limelight's documentation for testing. + private void updateOdometry() { + boolean doRejectUpdate = false; + + LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); + LimelightHelpers.PoseEstimate mt2 = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); + if (mt2 == null) { + return; + } + + // if our angular velocity is greater than 720 degrees per second, ignore vision updates + if(Math.abs(m_gyro.getRate()) > 720) + { + doRejectUpdate = true; + } + + if (Math.abs(m_gyro.getPitch()) > 5) { + doRejectUpdate = true; + } + + if(mt2.tagCount == 0) + { + doRejectUpdate = true; + } + + if(!doRejectUpdate) + { + // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. + Vector errorVec; + + // When the robot is disabled, trust the gyro from the limelight fully. + // Otherwise, in all othr modes, trust the gyro yaw. + if (DriverStation.isDisabled()) { + errorVec = VecBuilder.fill(.7,.7,0); + } else { + errorVec = VecBuilder.fill(.7,.7,9999999); + } + m_poseEstimator.setVisionMeasurementStdDevs(errorVec); + + m_poseEstimator.addVisionMeasurement( + mt2.pose, + mt2.timestampSeconds + ); + } + } + + @Override + public void periodic() { + // This method will be called once per scheduler + IMUData limelightData = LimelightHelpers.getIMUData("limelight"); + m_YawQue.add(limelightData.robotYaw); + + updateOdometry(); + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java b/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java new file mode 100644 index 0000000..5475bf5 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java @@ -0,0 +1,59 @@ +package frc.robot.utils; + +import java.io.File; +import edu.wpi.first.wpilibj.Filesystem; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +import java.util.ArrayList; +import java.util.Optional; + +import com.pathplanner.lib.commands.PathPlannerAuto; + +// This goes to "/home/lvuser/deploy/pathplanner/autos" and grabs the names of all .auto files +// We are asuming that the PathPlannerAuto(string) is the file name of the auto +// We are asuming that the files are always in the "/home/lvuser/deploy/pathplanner/autos" +// We found this information at https://github.com/mjansen4857/pathplanner/wiki/PathPlannerLib:-Java-Usage +public class AutoCommands { + public static ArrayList getAutoNames() { + // Creating an ArrayList so I can fill it with auto file names w/o the extention. + ArrayList autoNames = new ArrayList(); + + // Getting the folder and files. + String deployDirectoryPath = Filesystem.getDeployDirectory().getPath(); + File deployDirectory = new File(deployDirectoryPath+"/pathplanner/autos"); + File[] listOfFiles = deployDirectory.listFiles(); + + // Checking if the files exist + if (listOfFiles != null) { + for (File file : listOfFiles) { + String fullName = file.getName(); // Returns [file_name].[extention] + if (file.isFile()) { + String[] splitName = fullName.split("\\."); // Splitting the file name into seprate parts. + + // If its an auto file then add it to the list. + if (splitName.length > 1 && "auto".equals(splitName[1])) { + autoNames.add(splitName[0]); + System.out.println("FOUND AUTO: "+splitName[0]); + } + } + } + } + + // Returning the new array + return autoNames; + } + + public static ArrayList getAutoCommands(Optional driveSubsystem) { + ArrayList autoCommands = new ArrayList(); + + if (driveSubsystem.isPresent()) { + ArrayList autoNames = getAutoNames(); + for (String autoName : autoNames) { + autoCommands.add(new PathPlannerAuto(autoName)); + } + } + + return autoCommands; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/LimitedQueue.java b/2026-Rebuilt/src/main/java/frc/robot/utils/LimitedQueue.java new file mode 100644 index 0000000..cc0a705 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/LimitedQueue.java @@ -0,0 +1,19 @@ +package frc.robot.utils; + +import java.util.LinkedList; + +// An extention of LinkedList that limits the max number of elements when using add and remove. +public class LimitedQueue extends LinkedList { + private int limit; + + public LimitedQueue(int limit) { + this.limit = limit; + } + + @Override + public boolean add(E o) { + super.add(o); + while (size() > limit) { super.remove(); } + return true; + } +} diff --git a/2026-Rebuilt/vendordeps/PathplannerLib-2026.1.2.json b/2026-Rebuilt/vendordeps/PathplannerLib-2026.1.2.json new file mode 100644 index 0000000..f72fa41 --- /dev/null +++ b/2026-Rebuilt/vendordeps/PathplannerLib-2026.1.2.json @@ -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" + ] + } + ] +} \ No newline at end of file diff --git a/2026-Rebuilt/src/vendordeps/Phoenix6-26.1.0.json b/2026-Rebuilt/vendordeps/Phoenix6-26.1.0.json similarity index 100% rename from 2026-Rebuilt/src/vendordeps/Phoenix6-26.1.0.json rename to 2026-Rebuilt/vendordeps/Phoenix6-26.1.0.json diff --git a/2026-Rebuilt/src/vendordeps/REVLib.json b/2026-Rebuilt/vendordeps/REVLib.json similarity index 100% rename from 2026-Rebuilt/src/vendordeps/REVLib.json rename to 2026-Rebuilt/vendordeps/REVLib.json diff --git a/2026-Rebuilt/vendordeps/Studica.json b/2026-Rebuilt/vendordeps/Studica.json new file mode 100644 index 0000000..b51bf58 --- /dev/null +++ b/2026-Rebuilt/vendordeps/Studica.json @@ -0,0 +1,71 @@ +{ + "fileName": "Studica.json", + "name": "Studica", + "version": "2026.0.0", + "frcYear": "2026", + "uuid": "cb311d09-36e9-4143-a032-55bb2b94443b", + "mavenUrls": [ + "https://dev.studica.com/maven/release/2026/" + ], + "jsonUrl": "https://dev.studica.com/maven/release/2026/json/Studica-2026.0.0.json", + "javaDependencies": [ + { + "groupId": "com.studica.frc", + "artifactId": "Studica-java", + "version": "2026.0.0" + } + ], + "jniDependencies": [ + { + "groupId": "com.studica.frc", + "artifactId": "Studica-driver", + "version": "2026.0.0", + "skipInvalidPlatforms": true, + "isJar": false, + "validPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ], + "cppDependencies": [ + { + "groupId": "com.studica.frc", + "artifactId": "Studica-cpp", + "version": "2026.0.0", + "libName": "Studica", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + }, + { + "groupId": "com.studica.frc", + "artifactId": "Studica-driver", + "version": "2026.0.0", + "libName": "StudicaDriver", + "headerClassifier": "headers", + "sharedLibrary": false, + "skipInvalidPlatforms": true, + "binaryPlatforms": [ + "windowsx86-64", + "linuxarm64", + "linuxx86-64", + "linuxathena", + "linuxarm32", + "osxuniversal" + ] + } + ] +} \ No newline at end of file diff --git a/2026-Rebuilt/src/vendordeps/WPILibNewCommands.json b/2026-Rebuilt/vendordeps/WPILibNewCommands.json similarity index 100% rename from 2026-Rebuilt/src/vendordeps/WPILibNewCommands.json rename to 2026-Rebuilt/vendordeps/WPILibNewCommands.json diff --git a/prototype_projects/Experimental_Drivetrain_2026/build.gradle b/prototype_projects/Experimental_Drivetrain_2026/build.gradle index 478b497..a3a6e39 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/build.gradle +++ b/prototype_projects/Experimental_Drivetrain_2026/build.gradle @@ -1,6 +1,6 @@ plugins { id "java" - id "edu.wpi.first.GradleRIO" version "2026.1.1" + id "edu.wpi.first.GradleRIO" version "2026.2.1" } java { From 04c56ed4d4b6b9b729ab11beb59fe3cab41194a7 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 7 Feb 2026 12:19:54 -0600 Subject: [PATCH 045/161] Added kraken launcher elastic layout. --- .../launcher_kraken/elastic-layout.json | 158 ++++++++++++++++++ .../src/main/java/frc/robot/Robot.java | 1 + 2 files changed, 159 insertions(+) create mode 100644 prototype_projects/launcher_kraken/elastic-layout.json diff --git a/prototype_projects/launcher_kraken/elastic-layout.json b/prototype_projects/launcher_kraken/elastic-layout.json new file mode 100644 index 0000000..56a1b38 --- /dev/null +++ b/prototype_projects/launcher_kraken/elastic-layout.json @@ -0,0 +1,158 @@ +{ + "version": 1.0, + "grid_size": 128, + "tabs": [ + { + "name": "Teleoperated", + "grid_layout": { + "layouts": [], + "containers": [ + { + "title": "Actual Velocity", + "x": 0.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Actual Velocity", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Target Velocity", + "x": 128.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Target Velocity", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Reset Encoder", + "x": 256.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Reset Encoder", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Actual Velocity", + "x": 384.0, + "y": 0.0, + "width": 640.0, + "height": 384.0, + "type": "Graph", + "properties": { + "topic": "/SmartDashboard/Actual Velocity", + "period": 0.033, + "data_type": "double", + "time_displayed": 5.0, + "min_value": 0.0, + "max_value": 4000.0, + "color": 4278238420, + "line_width": 2.0 + } + }, + { + "title": "Target Velocity", + "x": 0.0, + "y": 128.0, + "width": 384.0, + "height": 256.0, + "type": "Graph", + "properties": { + "topic": "/SmartDashboard/Target Velocity", + "period": 0.033, + "data_type": "double", + "time_displayed": 5.0, + "min_value": 0.0, + "max_value": 2000.0, + "color": 4278238420, + "line_width": 2.0 + } + }, + { + "title": "set RPS", + "x": 512.0, + "y": 384.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/set RPS", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "current RPS2", + "x": 768.0, + "y": 384.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/current RPS2", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "current RPS1", + "x": 640.0, + "y": 384.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/current RPS1", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "desired RPS", + "x": 896.0, + "y": 384.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/desired RPS", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + } + ] + } + }, + { + "name": "Autonomous", + "grid_layout": { + "layouts": [], + "containers": [] + } + } + ] +} \ No newline at end of file diff --git a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java index 49ec765..8b4f76c 100644 --- a/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java +++ b/prototype_projects/launcher_kraken/src/main/java/frc/robot/Robot.java @@ -69,6 +69,7 @@ public Robot() { System.out.println("Could not apply configs 2, error code: " + status.toString()); } + SmartDashboard.putNumber("desired RPS", 0); SmartDashboard.getNumber("desired RPS", 0); SmartDashboard.putNumber("current RPS1", m_fx1.getVelocity().getValueAsDouble()); SmartDashboard.putNumber("current RPS2", m_fx2.getVelocity().getValueAsDouble()); From b6b4e013fc194b6346ffedec5e904e9100349e12 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Feb 2026 13:43:28 -0600 Subject: [PATCH 046/161] Updated Constants.java with info from robot specification --- .../src/main/java/frc/robot/Constants.java | 71 +++++++++++++++++++ .../robot/subsystems/ClimbL1Subsystem.java | 2 +- 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 2808f3b..5681f16 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -2,6 +2,35 @@ // 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. +// +// CANIDs and other hardware resource IDs and channels are defined in +// the robot specification document at https://docs.google.com/document/d/1A_Mh49vCdzeZFZrrAAlE3kgAf9tdAOItZ7-rJoq3Ufs/edit?usp=sharing +// +// Current CAN IDs: +// +// 01 - Pneumatics hub +// 10 - Drive left primary +// 11 - Drive left follower +// 20 - Drive right primary +// 21 - Drive right follower +// 30 - Intake roller +// 40 - Launcher flywheel primary motor +// 41 - Launcher flywheel secondary motor +// 42 - Launcher lift belt motor +// 50 - Indexer motor +// 51 - Bulk move belt motor +// +// Current DIO Channels: +// +// 0 - Upper fuel sensor (launcher subsystem) +// 1 - Lower fuel sensor (indexer subsystem) +// +// Current Solenoid Channels: +// +// 0 - Intake retract (extend is passive state via spring) +// 1 - Climb L1 Left +// 2 - Climb L1 Right + package frc.robot; import com.pathplanner.lib.config.ModuleConfig; @@ -93,4 +122,46 @@ public static class DrivetrainConstants { // SmartDashboard update frequency for drive subsystem state in 20ms counts. public static final int kTicksPerUpdate = 5; } + + public static class IntakeConstants { + public static int kIntakeMotorCANID = 30; + + public static int kSolenoidChannel = 0; + + // Raw intake motor speed in range [-1.0,1.0] + public static double kIntakeMotorSpeed = 0.3; + + // Solenoid states required to extend and retract the intake mechanism. + public static int kIntakeSolenoid = 1; + public static boolean kIntakeExtend = true; + public static boolean kIntakeRetract = !kIntakeExtend; + } + + public static class LauncherConstants { + public static int kLauncherFlywheelMotor1CANID = 40; + public static int kLauncherFlywheelMotor2CANID = 41; + public static int kLauncherLiftMotorCANID = 42; + + // Beam break sensor to detect fuel at the top of the lift. + public static final int kUpperFuelSensorChannel = 0; + public static final boolean kUpperFuelSensorIsEmpty = false; + } + + public static class IndexerBulkConstants { + public static int kIndexerMotorCANID = 50; + public static int kBulkMoveMotorCANID = 51; + + // Raw motor speeds in range [-1.0,1.0] + public static final double kBulkMoveMotorSpeed = 0.3; + public static double kIndexerMotorSpeed = 0.3; + + // Beam break sensor to detect fuel at the indexer. + public static final int kLowerFuelSensorChannel = 1; + public static final boolean kLowerFuelSensorIsEmpty = false; + } + + public static class ClimbL1Constants { + public static int kLeftSolenoidChannel = 1; + public static int kRightSolenoidChannel = 2; + } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java index 8c2c8e0..3e719f0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -5,7 +5,7 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; - +import frc.robot.Constants.ClimbL1Constants; public class ClimbL1Subsystem extends SubsystemBase { /** Creates a new ClimbL1Subsystem. */ From 9283396ec5b61ffa93d4ae620198e1fa7b1a08c6 Mon Sep 17 00:00:00 2001 From: 23 - Vanadium Date: Sat, 7 Feb 2026 13:50:22 -0600 Subject: [PATCH 047/161] Defined class interface for intake subsystem Added the framework for various functions inside of the intake subsystem --- .../frc/robot/subsystems/IntakeSubsystem.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index 00e45b6..77ef169 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -5,7 +5,7 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; - +import frc.robot.Constants.IntakeConstants; public class IntakeSubsystem extends SubsystemBase { /** Creates a new IntakeSubsystem. */ @@ -13,6 +13,27 @@ public IntakeSubsystem() { // TODO: write this } + public void start() { + // TODO: implement start + } + public void stop() { + // TODO: implement stop + } + public void extend() { + // TODO: implement extend + } + public void retract() { + // TODO: implement retract + } + public boolean isIntakeStarted() { + // TODO: implement isIntakeStarted + return false; + } + public boolean isIntakeExtended() { + // TODO: implement isIntakeExtended + return false; + } + @Override public void periodic() { // This method will be called once per scheduler run From 70e3c29fe567f7c0c24a8e406f0152ef17397052 Mon Sep 17 00:00:00 2001 From: 23 - Vanadium Date: Sat, 7 Feb 2026 14:23:24 -0600 Subject: [PATCH 048/161] Defined class interface for indexerbulk subsystem Defined the class interface for IndexerBulk subsystem. Also fixed ambiguity in the intake subsystem. --- .../subsystems/IndexerBulkSubsystem.java | 26 +++++++++++++++++++ .../frc/robot/subsystems/IntakeSubsystem.java | 11 ++++++++ 2 files changed, 37 insertions(+) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index 1c582d7..dfb0bf0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -13,6 +13,32 @@ public IndexerBulkSubsystem() { // TODO: write this } +// Runs the belts that transfer the fuel from bulk storage to the indexer. + public void startBulkTransfer() { + // TODO: implement startBulkTransfer + } + +// Stops the belts in bulk storage. + public void stopBulkTransfer() { + //TODO: implement stopBulkTransfer + } + +// Spins the indexer shaft which transfers fuel from the indexer to the launcher. + public void startIndexer() { + // TODO: implement indexing + } + +// Stops spinning the indexer shaft. + public void stopIndexer() { + // TODO: implement stopIndexer + } + +// Returns true if lower fuel sensor detects fuel. + public boolean isFuelPresent() { + // TODO: implement isBeamBroken + return false; + } + @Override public void periodic() { // This method will be called once per scheduler run diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index 77ef169..6d4036a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -13,22 +13,33 @@ public IntakeSubsystem() { // TODO: write this } + // Spins the shaft on the intake that will move fuel into the robot. public void start() { // TODO: implement start } + + // Stops spinning the intake shaft. public void stop() { // TODO: implement stop + + // Extends the intake mechanism over the bumpers and outside of the robot. } public void extend() { // TODO: implement extend } + + // Retracts the intake mechanism over the bumpers and inside of the robot. public void retract() { // TODO: implement retract } + + // Returns true if the intake shaft is spinning. public boolean isIntakeStarted() { // TODO: implement isIntakeStarted return false; } + + // Returns true if the intake is extended outside of the frame perimiter. public boolean isIntakeExtended() { // TODO: implement isIntakeExtended return false; From 377a342eec18b9e6a506225b11b36aa6ba4ec4ec Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Feb 2026 14:24:46 -0600 Subject: [PATCH 049/161] Implement code for L1 climb subsystem --- .../src/main/java/frc/robot/Constants.java | 7 +++ .../robot/subsystems/ClimbL1Subsystem.java | 46 ++++++++++++++++++- .../robot/subsystems/LauncherSubsystem.java | 2 +- 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 5681f16..c7173aa 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -76,6 +76,10 @@ public static class AutoConstants { // populate on init possibility end here } + public static class PneumaticsConstants { + public static final int kPneumaticsHubCANID = 1; + } + public static class OperatorConstants { public static final int kDriverControllerPort = 0; public static final double kDriverControllerDeadband = 0.02; // Exclusive @@ -163,5 +167,8 @@ public static class IndexerBulkConstants { public static class ClimbL1Constants { public static int kLeftSolenoidChannel = 1; public static int kRightSolenoidChannel = 2; + + public static boolean kClimbL1Raise = true; + public static boolean kClimbL1Lower = !kClimbL1Raise; } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java index 3e719f0..895e854 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -5,12 +5,56 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; +import edu.wpi.first.wpilibj.PneumaticsModuleType; +import edu.wpi.first.wpilibj.Solenoid; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.Constants.ClimbL1Constants; +import frc.robot.Constants.PneumaticsConstants; public class ClimbL1Subsystem extends SubsystemBase { + private Solenoid m_LeftSolenoid; + private Solenoid m_RightSolenoid; + private boolean m_bRaised = false; + /** Creates a new ClimbL1Subsystem. */ public ClimbL1Subsystem() { - // TODO: write this + // Create member objects in the constructor in the hope that they throw exceptions + // if underlying hardware is not present and, hence, allow our Optional system to + // work. + m_LeftSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsModuleType.REVPH, + ClimbL1Constants.kLeftSolenoidChannel); + m_RightSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsModuleType.REVPH, + ClimbL1Constants.kLeftSolenoidChannel); + SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); + } + + // Raise the climb arms. + public void raiseArms() + { + m_LeftSolenoid.set(ClimbL1Constants.kClimbL1Raise); + m_RightSolenoid.set(ClimbL1Constants.kClimbL1Raise); + m_bRaised = true; + SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); + } + + // Lower the climb arms. + public void lowerArms() + { + m_LeftSolenoid.set(ClimbL1Constants.kClimbL1Lower); + m_RightSolenoid.set(ClimbL1Constants.kClimbL1Lower); + m_bRaised = false; + SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); + } + + // Determine whether the arms are currently in the raised or lowered position. + // NB: The robot has no way to know the current position of the arms so this merely + // returns the last commanded state! Commands using this method may need to start a + // timer when this state changes to allow for the time taken to move the pneumatics. + public boolean areArmsRaised() + { + return m_bRaised; } @Override diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index dd1d516..b791509 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -5,7 +5,7 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; - +import frc.robot.Constants.LauncherConstants; public class LauncherSubsystem extends SubsystemBase { /** Creates a new LauncherSubsystem. */ From 800bafd6e82f53879562b5a412351d7a7c792ac7 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Feb 2026 15:22:44 -0600 Subject: [PATCH 050/161] Added PneumaticsHub support and replaced deprecated Command.schedule() use --- .../src/main/java/frc/robot/Constants.java | 4 ++++ .../src/main/java/frc/robot/Robot.java | 2 +- .../main/java/frc/robot/RobotContainer.java | 21 +++++++++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index c7173aa..f97f055 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -78,6 +78,10 @@ public static class AutoConstants { public static class PneumaticsConstants { public static final int kPneumaticsHubCANID = 1; + public static final double kMinPneumaticsPressure = 80.0; + public static final double kMaxPneumaticsPressure = 120.0; + + public static final int kTicksPerUpdate = 5; } public static class OperatorConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/Robot.java b/2026-Rebuilt/src/main/java/frc/robot/Robot.java index e0d27fa..3978de7 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Robot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Robot.java @@ -72,7 +72,7 @@ public void autonomousInit() { // schedule the autonomous command (example) if (m_autonomousCommand != null) { - m_autonomousCommand.schedule(); + CommandScheduler.getInstance().schedule(m_autonomousCommand); } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 917b687..80b0ca4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -27,8 +27,10 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; +import edu.wpi.first.wpilibj.PneumaticHub; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; +import frc.robot.Constants.PneumaticsConstants; import frc.robot.commands.DriveForwardFromPos; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; @@ -53,6 +55,7 @@ public class RobotContainer { private final Optional m_climbL1Subsystem; private final Optional m_indexerBulkSubsystem; private final Optional m_launcherSubsystem; + private final Optional m_pneumaticHub; private final LimelightSubsystem m_limelightSubsystem; // Replace with CommandPS4Controller or CommandJoystick if needed @@ -89,6 +92,16 @@ public class RobotContainer { /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { + + // Init pneumatics system. + m_pneumaticHub = getSubsystem(PneumaticHub.class); + if (m_pneumaticHub.isPresent()) + { + PneumaticHub hub = m_pneumaticHub.get(); + hub.enableCompressorAnalog(PneumaticsConstants.kMinPneumaticsPressure, + PneumaticsConstants.kMaxPneumaticsPressure); + } + // Init DriveSubsystem Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); @@ -221,6 +234,14 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); } + // Pneumatics compressor + if(m_pneumaticHub.isPresent() && ((m_iTickCount % PneumaticsConstants.kTicksPerUpdate) == 0)) + { + PneumaticHub hub = m_pneumaticHub.get(); + SmartDashboard.putNumber("Pressure", hub.getPressure(0)); + SmartDashboard.putBoolean("Compressor Running", hub.getCompressor()); + } + m_iTickCount++; } From 58a10858f6354c3252b8e5426fbf97b244d50d92 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 7 Feb 2026 15:48:50 -0600 Subject: [PATCH 051/161] Added a RotateToRotation2D, and started on path finding to the start position of a auto. --- .../deploy/pathplanner/autos/2MeterAuto.auto | 19 ---- .../pathplanner/autos/DriveBwdToEdge.auto | 19 ---- .../pathplanner/autos/DriveFwdFromEdge.auto | 19 ---- .../deploy/pathplanner/autos/FwdThenBwd.auto | 31 ------- .../pathplanner/autos/ReverseIntoCorner.auto | 19 ---- .../deploy/pathplanner/autos/STurnAuto.auto | 19 ---- .../deploy/pathplanner/autos/SampleAuto.auto | 2 +- .../pathplanner/autos/SmoothTurnAuto.auto | 19 ---- .../autos/SmoothTurn_ReverseS.auto | 25 ------ .../src/main/deploy/pathplanner/navgrid.json | 2 +- .../pathplanner/paths/DriveForward.path | 54 ++++++++++++ .../pathplanner/paths/Example_Path.path | 16 ++-- .../main/java/frc/robot/RobotContainer.java | 39 ++++++++- .../robot/commands/RotateToRotation2D.java | 86 +++++++++++++++++++ 14 files changed, 187 insertions(+), 182 deletions(-) delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto delete mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto deleted file mode 100644 index 26adafa..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/2MeterAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "2_Meter_New" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto deleted file mode 100644 index e93b91b..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "DriveBackwardToCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto deleted file mode 100644 index 8582b38..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "DriveForwardFromCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto deleted file mode 100644 index 6a60a9c..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/FwdThenBwd.auto +++ /dev/null @@ -1,31 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "DriveForwardFromCorner" - } - }, - { - "type": "wait", - "data": { - "waitTime": 1.0 - } - }, - { - "type": "path", - "data": { - "pathName": "DriveBackwardToCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto deleted file mode 100644 index 19afbc2..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "ReverseIntoCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto deleted file mode 100644 index 59b73ae..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/STurnAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "S_Turn" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto index 6460f85..39521a1 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto @@ -13,7 +13,7 @@ ] } }, - "resetOdom": true, + "resetOdom": false, "folder": null, "choreoAuto": false } \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto deleted file mode 100644 index c79aef4..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "Smooth_Turn" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto deleted file mode 100644 index 119345f..0000000 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "Smooth_Turn" - } - }, - { - "type": "path", - "data": { - "pathName": "Reverse_S_Turn" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json index 465fe26..0c6a2de 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/navgrid.json @@ -1 +1 @@ -{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file +{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path new file mode 100644 index 0000000..c50991f --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.793115384615386, + "y": 5.430384615384615 + }, + "prevControl": null, + "nextControl": { + "x": 3.793115384615386, + "y": 5.430384615384615 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 4.54897435897436, + "y": 5.430384615384615 + }, + "prevControl": { + "x": 3.54897435897436, + "y": 5.430384615384615 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path index 0d78846..2baefb4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path @@ -3,25 +3,25 @@ "waypoints": [ { "anchor": { - "x": 2.1486729452054796, - "y": 6.48169948630137 + "x": 2.0, + "y": 4.837346153846154 }, "prevControl": null, "nextControl": { - "x": 2.3986729452054796, - "y": 6.48169948630137 + "x": 2.0, + "y": 4.587346153846154 }, "isLocked": false, "linkedName": null }, { "anchor": { - "x": 5.213912671232877, - "y": 6.48169948630137 + "x": 2.0, + "y": 3.814064102564102 }, "prevControl": { - "x": 4.963912671232877, - "y": 6.48169948630137 + "x": 2.0, + "y": 4.064064102564102 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index e3f3ba2..e6e035d 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -10,6 +10,7 @@ import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -25,12 +26,14 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; import frc.robot.LimelightHelpers.IMUData; import frc.robot.commands.DriveForwardFromPos; +import frc.robot.commands.RotateToRotation2D; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -69,6 +72,13 @@ public class RobotContainer { m_limelightError ); + PathConstraints m_constraints = new PathConstraints( + 1.0, + 1.0, + 2 * Math.PI, + 4 * Math.PI + ); // The constraints for this path. + // Smartdashboard Objects private SendableChooser m_autoChooser; private final Field2d m_field = new Field2d(); @@ -117,11 +127,33 @@ private void configureAutos() { new DriveForwardFromPos(m_PoseEstimator, 2) ); + m_autoChooser.addOption( + "Rotate to 0", + new RotateToRotation2D( + m_driveSubsystem.get(), + m_PoseEstimator, + new Rotation2d(0.0), + 1 + ) + ); + // Path Planner Auto's ArrayList autoNames = AutoCommands.getAutoNames(); for (String autoName : autoNames) { - PathPlannerAuto auto = new PathPlannerAuto(autoName); - m_autoChooser.addOption(autoName, auto); + PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); + Pose2d startingPose = plannedAuto.getStartingPose(); + + Command rotationCommand = new RotateToRotation2D( + m_driveSubsystem.get(), + m_PoseEstimator, + startingPose.getRotation(), + 1 + ); + + Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); + Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotationCommand);//, plannedAuto); + + m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); } // Add to dashboard @@ -167,6 +199,9 @@ public void InitSmartDashboard() { // Non-Subsystem Specific Stuff SmartDashboard.putData(CommandScheduler.getInstance()); SmartDashboard.putData("Field", m_field); + SmartDashboard.putNumber("Target Rotation", 0); + SmartDashboard.putNumber("Target Angle Diff Abs", 0); + SmartDashboard.putNumber("Rotation Speed", 0); } // This function is called every 20mS. diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java new file mode 100644 index 0000000..254a175 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -0,0 +1,86 @@ +package frc.robot.commands; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class RotateToRotation2D extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final double m_maxSpeed; + private Rotation2d m_targetRotation; + + // Bounds are [0, 1) in interval notation. This effects the steepness of + // the curve that is used to slow the robot as it approches the target. + private double speedExp = 0.98; + + /** + * Creates a new RotateToRotation2D. + * + * @param driveSubsystem The driveSubsystem for the robot. + * @param poseEstimator The poseEstimator of the robot. + * @param targetRotation The rotation you want the robot to go to. + * @param maxSpeed The max speed the robot is allowed to go in the rotation. + */ + public RotateToRotation2D(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, Rotation2d targetRotation, double maxSpeed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_targetRotation = targetRotation; + m_maxSpeed = maxSpeed; + + SmartDashboard.putNumber("Target Rotation", m_targetRotation.getDegrees()); + + addRequirements(driveSubsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + Rotation2d currentRotation = m_poseEstimator.getEstimatedPosition().getRotation(); + Rotation2d changeInRotation = m_targetRotation.minus(currentRotation); + + double targetDiff = Math.abs(changeInRotation.getDegrees()); + + double speed = ((Math.pow(speedExp, targetDiff)-1)/(Math.pow(speedExp, 180)-1)); + speed *= m_maxSpeed; + speed = Math.max(speed, 0.2); + SmartDashboard.putNumber("Rotation Speed", speed); + + if (changeInRotation.getDegrees() <= 0) { + m_driveSubsystem.setDifferentialSpeeds(speed, -speed); + } else { + m_driveSubsystem.setDifferentialSpeeds(-speed, speed); + } + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + System.out.println("Ended Rotation fix!"); + m_driveSubsystem.setDifferentialSpeeds(0, 0); + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + Rotation2d currentRotation = m_poseEstimator.getEstimatedPosition().getRotation(); + Rotation2d diff = m_targetRotation.minus(currentRotation); + + double currentDiffAbs = Math.abs(diff.getDegrees()); + SmartDashboard.putNumber("Target Angle Diff Abs", currentDiffAbs); + + if (currentDiffAbs <= 0.5) { + return true; + } else { + return false; + } + } +} From f796d6b6392635c61b5c6189371a708ab1867522 Mon Sep 17 00:00:00 2001 From: 23 - Vanadium Date: Mon, 9 Feb 2026 20:36:02 -0600 Subject: [PATCH 052/161] Updated differential drive command to square user inputs --- .../main/java/frc/robot/commands/DifferentialDriveCommand.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java index 16b0322..1a25daf 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -48,6 +48,9 @@ public void execute() { rightSpeed = 0; } + leftSpeed = (leftSpeed < 0) ? (-leftSpeed * leftSpeed) : (leftSpeed * leftSpeed); + rightSpeed = (rightSpeed < 0) ? (-rightSpeed * rightSpeed) : (rightSpeed * rightSpeed); + leftSpeed *= DrivetrainConstants.kMaxVelocityMPS; rightSpeed *= DrivetrainConstants.kMaxVelocityMPS; From 9b8cf2661bb1c90c090d98bbe9fd9b3d7bdfee49 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:47:19 -0600 Subject: [PATCH 053/161] Got pathfind to auto working & a lineup tower test command. --- .../pathplanner/autos/DriveForward.auto | 19 +++++ ...{SampleAuto.auto => SampleHorizontal.auto} | 0 .../deploy/pathplanner/autos/TowerlineUp.auto | 25 ++++++ .../pathplanner/paths/DriveForward.path | 16 ++-- .../pathplanner/paths/Example_Path.path | 4 +- .../pathplanner/paths/LineupToTower.path | 70 ++++++++++++++++ .../main/deploy/pathplanner/paths/wdawda.path | 54 ++++++++++++ .../main/java/frc/robot/RobotContainer.java | 25 +++++- .../java/frc/robot/commands/POTFtoPoint.java | 84 +++++++++++++++++++ 9 files changed, 284 insertions(+), 13 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveForward.auto rename prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/{SampleAuto.auto => SampleHorizontal.auto} (100%) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/TowerlineUp.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/LineupToTower.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wdawda.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/POTFtoPoint.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveForward.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveForward.auto new file mode 100644 index 0000000..983e8ed --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/DriveForward.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveForward" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleHorizontal.auto similarity index 100% rename from prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleAuto.auto rename to prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleHorizontal.auto diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/TowerlineUp.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/TowerlineUp.auto new file mode 100644 index 0000000..5ad17a4 --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/TowerlineUp.auto @@ -0,0 +1,25 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "LineupToTower" + } + }, + { + "type": "named", + "data": { + "name": "RotateTo-180" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path index c50991f..c8313ec 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/DriveForward.path @@ -3,25 +3,25 @@ "waypoints": [ { "anchor": { - "x": 2.793115384615386, - "y": 5.430384615384615 + "x": 2.293102564102565, + "y": 5.896 }, "prevControl": null, "nextControl": { - "x": 3.793115384615386, - "y": 5.430384615384615 + "x": 3.293102564102565, + "y": 5.896 }, "isLocked": false, "linkedName": null }, { "anchor": { - "x": 4.54897435897436, - "y": 5.430384615384615 + "x": 3.6070897435897447, + "y": 5.896 }, "prevControl": { - "x": 3.54897435897436, - "y": 5.430384615384615 + "x": 2.6070897435897447, + "y": 5.896 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path index 2baefb4..64d5745 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/Example_Path.path @@ -4,12 +4,12 @@ { "anchor": { "x": 2.0, - "y": 4.837346153846154 + "y": 4.837 }, "prevControl": null, "nextControl": { "x": 2.0, - "y": 4.587346153846154 + "y": 4.587 }, "isLocked": false, "linkedName": null diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/LineupToTower.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/LineupToTower.path new file mode 100644 index 0000000..56ce83d --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/LineupToTower.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 3.0721923076923088, + "y": 5.116423076923077 + }, + "prevControl": null, + "nextControl": { + "x": 3.130333333333334, + "y": 4.581525641025641 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.7814871794871805, + "y": 3.976858974358975 + }, + "prevControl": { + "x": 3.2001025641025653, + "y": 4.186166666666668 + }, + "nextControl": { + "x": 2.488419497644409, + "y": 3.8303251334375887 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.5721538461538476, + "y": 3.755923076923077 + }, + "prevControl": { + "x": 2.4326410256410247, + "y": 3.767551282051283 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 131.18592516570953 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wdawda.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wdawda.path new file mode 100644 index 0000000..74c7aba --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wdawda.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.5953846153846167, + "y": 6.267615384615385 + }, + "prevControl": null, + "nextControl": { + "x": 1.0256282051282062, + "y": 6.27924358974359 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 4.837 + }, + "prevControl": { + "x": 2.0, + "y": 5.355075362944116 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index e6e035d..33dde95 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -9,6 +9,7 @@ import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.auto.NamedCommands; import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; import com.studica.frc.AHRS; @@ -33,6 +34,7 @@ import frc.robot.Constants.OperatorConstants; import frc.robot.LimelightHelpers.IMUData; import frc.robot.commands.DriveForwardFromPos; +import frc.robot.commands.POTFtoPoint; import frc.robot.commands.RotateToRotation2D; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; @@ -121,6 +123,15 @@ private void configureAutos() { // m_autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string m_autoChooser = new SendableChooser(); + // Named Commands + NamedCommands.registerCommand("RotateTo-180", new RotateToRotation2D( + m_driveSubsystem.get(), + m_PoseEstimator, + Rotation2d.fromDegrees(180), + 1 + ) + ); + // Custom Autos m_autoChooser.addOption( "On-Fly Forward 2m", @@ -137,21 +148,29 @@ private void configureAutos() { ) ); + m_autoChooser.addOption( + "On-The-Fly to (2, 4.837) -90", + new POTFtoPoint( + m_PoseEstimator, + new Pose2d(2, 4.837, Rotation2d.fromDegrees(-90)) + ) + ); + // Path Planner Auto's ArrayList autoNames = AutoCommands.getAutoNames(); for (String autoName : autoNames) { PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); Pose2d startingPose = plannedAuto.getStartingPose(); - Command rotationCommand = new RotateToRotation2D( + Command rotateToStartRot = new RotateToRotation2D( m_driveSubsystem.get(), - m_PoseEstimator, + m_PoseEstimator, startingPose.getRotation(), 1 ); Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); - Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotationCommand);//, plannedAuto); + Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/POTFtoPoint.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/POTFtoPoint.java new file mode 100644 index 0000000..5990ecc --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/POTFtoPoint.java @@ -0,0 +1,84 @@ +package frc.robot.commands; + +import java.util.List; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.GoalEndState; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.path.Waypoint; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; + +/** An example command that uses an example subsystem. */ +public class POTFtoPoint extends Command { + private final DifferentialDrivePoseEstimator m_poseEstimator; + private Pose2d m_targetPose; + + /** + * Creates a new POTFtwoPoints. + * + * @param subsystem The subsystem used by this command. + */ + public POTFtoPoint(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose) + { + m_poseEstimator = poseEstimator; + m_targetPose = targetPose; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This is taken and modified from the limelight documentation for + // path creation on the fly: https://pathplanner.dev/pplib-create-a-path-on-the-fly.html + + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + + // Create a list of waypoints from poses. Each pose represents one waypoint. + // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. + List waypoints = PathPlannerPath.waypointsFromPoses( + currentPose, + m_targetPose + ); + + PathConstraints constraints = new PathConstraints( + 1.0, + 1.0, + 2 * Math.PI, + 4 * Math.PI + ); // The constraints for this path. + + // Create the path using the waypoints created above + PathPlannerPath path = new PathPlannerPath( + waypoints, + constraints, + null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. + new GoalEndState(0.0, m_targetPose.getRotation()) // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. + ); + + // Prevent the path from being flipped if the coordinates are already correct + path.preventFlipping = true; + + // Create the command version of the path and schedule it + Command followPath = AutoBuilder.followPath(path); + CommandScheduler.getInstance().schedule(followPath); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} From 4bbeef3148d82bde51d584d6ef00a994383f0176 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 10 Feb 2026 20:47:50 -0600 Subject: [PATCH 054/161] Got backwards auto working, also added a aim to hub command. --- .../pathplanner/autos/ReverseIntoCorner.auto | 25 ++++++ .../autos/SampleHorziontalBackward.auto | 19 +++++ .../paths/ExamplePathBackwards.path | 54 +++++++++++++ .../pathplanner/paths/ReverseIntoCorner.path | 30 ++------ .../main/deploy/pathplanner/paths/wawd.path | 54 +++++++++++++ .../main/java/frc/robot/RobotContainer.java | 31 +++++++- .../java/frc/robot/commands/AimAtHub.java | 77 +++++++++++++++++++ .../robot/commands/RotateToRotation2D.java | 2 +- 8 files changed, 267 insertions(+), 25 deletions(-) create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wawd.path create mode 100644 prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto new file mode 100644 index 0000000..62253ac --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto @@ -0,0 +1,25 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "ReverseIntoCorner" + } + }, + { + "type": "named", + "data": { + "name": "AimToHub" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto new file mode 100644 index 0000000..a2e63bd --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "ExamplePathBackwards" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path new file mode 100644 index 0000000..928549c --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.0, + "y": 4.837 + }, + "prevControl": null, + "nextControl": { + "x": 2.0, + "y": 4.587 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 3.814064102564102 + }, + "prevControl": { + "x": 2.0, + "y": 4.064064102564102 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path index 94faccd..f5a63f4 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path @@ -3,29 +3,13 @@ "waypoints": [ { "anchor": { - "x": 3.22, - "y": 6.06 + "x": 1.7349487179487189, + "y": 6.104820512820513 }, "prevControl": null, "nextControl": { - "x": 2.840245730777104, - "y": 6.528957467245401 - }, - "isLocked": false, - "linkedName": null - }, - { - "anchor": { - "x": 2.0023974358974375, - "y": 6.697858974358974 - }, - "prevControl": { - "x": 2.932653846153847, - "y": 6.70948717948718 - }, - "nextControl": { - "x": 1.534985890056773, - "y": 6.692016330035965 + "x": 1.5521849008880018, + "y": 6.275400075410516 }, "isLocked": false, "linkedName": null @@ -33,11 +17,11 @@ { "anchor": { "x": 0.7930641025641041, - "y": 7.290897435897436 + "y": 7.162987179487179 }, "prevControl": { - "x": 1.258340364584852, - "y": 6.825621173876687 + "x": 0.9791153846153859, + "y": 6.942051282051282 }, "nextControl": null, "isLocked": false, diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wawd.path b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wawd.path new file mode 100644 index 0000000..8cf8bff --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/deploy/pathplanner/paths/wawd.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 4.607, + "y": 4.035 + }, + "prevControl": null, + "nextControl": { + "x": 5.606999999999999, + "y": 4.035 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 8.304884615384616, + "y": 4.035 + }, + "prevControl": { + "x": 7.304884615384616, + "y": 4.035 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index 33dde95..b88b648 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -22,17 +22,21 @@ import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; 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.SendableChooser; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; +import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; import frc.robot.LimelightHelpers.IMUData; +import frc.robot.commands.AimAtHub; import frc.robot.commands.DriveForwardFromPos; import frc.robot.commands.POTFtoPoint; import frc.robot.commands.RotateToRotation2D; @@ -91,6 +95,7 @@ public class RobotContainer { // Keep track of time for SmartDashboard updates. static int m_iTickCount = 0; + private boolean m_isRed = false; /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { @@ -132,6 +137,14 @@ private void configureAutos() { ) ); + NamedCommands.registerCommand("AimToHub", new AimAtHub( + m_driveSubsystem.get(), + m_PoseEstimator, + 2.0, + m_isRed + ) + ); + // Custom Autos m_autoChooser.addOption( "On-Fly Forward 2m", @@ -166,7 +179,7 @@ private void configureAutos() { m_driveSubsystem.get(), m_PoseEstimator, startingPose.getRotation(), - 1 + 2.0 ); Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); @@ -211,6 +224,17 @@ private void configureBindings() { // // cancelling on release. // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); // } + + m_driverController.y().onTrue(new InstantCommand(() -> CommandScheduler.getInstance().cancelAll())); + + m_driverController.x().onTrue( + new AimAtHub( + m_driveSubsystem.get(), + m_PoseEstimator, + 2.0, + m_isRed + ) + ); } // Populate the SmartDashboard on robot init. @@ -260,6 +284,11 @@ public void disabledInit() {} // Move to auto init for competition code. public void enabledInit() { + Optional alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + m_isRed = alliance.get() == DriverStation.Alliance.Red; + } + LimelightHelpers.SetIMUMode("limelight", 4); m_gyro.enableLogging(true); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java new file mode 100644 index 0000000..ad7cf7d --- /dev/null +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java @@ -0,0 +1,77 @@ +package frc.robot.commands; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class AimAtHub extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final double m_maxSpeed; + private final boolean m_isRed; + + private final Pose2d m_BlueCenter = new Pose2d(4.607, 4.035, new Rotation2d()); + private final Pose2d m_RedCenter = new Pose2d(); + + /** + * Creates a new AimAtHub. + * + * @param driveSubsystem The driveSubsystem for the robot. + * @param poseEstimator The poseEstimator of the robot. + * @param maxSpeed The max speed the robot is allowed to go in the rotation. + * @param isRed Does the robot need to point tword the red or blue goal, default is blue. + */ + public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, double maxSpeed, boolean isRed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_maxSpeed = maxSpeed; + m_isRed = isRed; + + addRequirements(driveSubsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Pose2d targetPose; + if (m_isRed) { + targetPose = m_RedCenter; + } else { + targetPose = m_BlueCenter; + } + + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + double dY = targetPose.getY() - currentPose.getY(); + double dX = targetPose.getX() - currentPose.getX(); + + Rotation2d targetRotation = new Rotation2d(Math.atan2(dY, dX)); + RotateToRotation2D aimCommand = new RotateToRotation2D( + m_driveSubsystem, + m_poseEstimator, + targetRotation, + m_maxSpeed + ); + + CommandScheduler.getInstance().schedule(aimCommand); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java index 254a175..1b20280 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -51,7 +51,7 @@ public void execute() { double speed = ((Math.pow(speedExp, targetDiff)-1)/(Math.pow(speedExp, 180)-1)); speed *= m_maxSpeed; - speed = Math.max(speed, 0.2); + speed = Math.max(speed, 0.3); SmartDashboard.putNumber("Rotation Speed", speed); if (changeInRotation.getDegrees() <= 0) { From 20865765c9519f45a5076cb7af5cf9248a652d84 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Thu, 12 Feb 2026 10:01:25 -0600 Subject: [PATCH 055/161] Removed warnings and reworked alliance fetch --- .../main/java/frc/robot/RobotContainer.java | 22 +++++++++++-------- .../java/frc/robot/commands/AimAtHub.java | 1 - 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java index b88b648..41e0271 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/RobotContainer.java @@ -35,7 +35,6 @@ import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; -import frc.robot.LimelightHelpers.IMUData; import frc.robot.commands.AimAtHub; import frc.robot.commands.DriveForwardFromPos; import frc.robot.commands.POTFtoPoint; @@ -95,7 +94,6 @@ public class RobotContainer { // Keep track of time for SmartDashboard updates. static int m_iTickCount = 0; - private boolean m_isRed = false; /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { @@ -141,7 +139,7 @@ private void configureAutos() { m_driveSubsystem.get(), m_PoseEstimator, 2.0, - m_isRed + isRed() ) ); @@ -232,7 +230,7 @@ private void configureBindings() { m_driveSubsystem.get(), m_PoseEstimator, 2.0, - m_isRed + isRed() ) ); } @@ -280,15 +278,21 @@ public void UpdateSmartDashboard() { m_iTickCount++; } - public void disabledInit() {} - - // Move to auto init for competition code. - public void enabledInit() { + // Checks if the robot is on the blue or red alliance. If it cannot get the data it defaults to blue. + public boolean isRed() { Optional alliance = DriverStation.getAlliance(); if (alliance.isPresent()) { - m_isRed = alliance.get() == DriverStation.Alliance.Red; + return alliance.get() == DriverStation.Alliance.Red; + } else { + System.out.println("Could not fetch alliance! Defaulting to blue!"); + return false; } + } + public void disabledInit() {} + + // Move to auto init for competition code. + public void enabledInit() { LimelightHelpers.SetIMUMode("limelight", 4); m_gyro.enableLogging(true); } diff --git a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java index ad7cf7d..4c18c4e 100644 --- a/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java +++ b/prototype_projects/Experimental_Drivetrain_2026/src/main/java/frc/robot/commands/AimAtHub.java @@ -3,7 +3,6 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.subsystems.DriveSubsystem; From 8784791037eadd7334bd3dbc3a5478a4f6008a33 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 13 Feb 2026 20:26:20 -0600 Subject: [PATCH 056/161] Transfered the experimental drive code to 2026 comp code. --- 2026-Rebuilt/elastic-layout.json | 23 ++- .../pathplanner/autos/DriveForward.auto | 19 +++ .../pathplanner/autos/ReverseIntoCorner.auto | 6 + .../pathplanner/autos/SampleHorizontal.auto | 19 +++ .../autos/SampleHorziontalBackward.auto | 19 +++ .../deploy/pathplanner/autos/TowerlineUp.auto | 25 ++++ .../src/main/deploy/pathplanner/navgrid.json | 2 +- .../pathplanner/paths/DriveForward.path | 54 +++++++ .../paths/ExamplePathBackwards.path | 54 +++++++ .../pathplanner/paths/Example_Path.path | 16 +-- .../pathplanner/paths/LineupToTower.path | 70 +++++++++ .../pathplanner/paths/ReverseIntoCorner.path | 30 +--- .../main/deploy/pathplanner/paths/wawd.path | 54 +++++++ .../main/deploy/pathplanner/paths/wdawda.path | 54 +++++++ .../main/java/frc/robot/RobotContainer.java | 136 ++++++++++++++---- .../java/frc/robot/commands/AimAtHub.java | 76 ++++++++++ .../commands/DifferentialDriveCommand.java | 3 - .../java/frc/robot/commands/POTFtoPoint.java | 84 +++++++++++ .../robot/commands/RotateToRotation2D.java | 86 +++++++++++ .../frc/robot/subsystems/DriveSubsystem.java | 11 ++ 20 files changed, 777 insertions(+), 64 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveForward.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorizontal.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForward.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/wawd.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/wdawda.path create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 9175fbd..c4d970a 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -91,9 +91,9 @@ }, { "title": "Field", - "x": 384.0, + "x": 640.0, "y": 0.0, - "width": 640.0, + "width": 512.0, "height": 384.0, "type": "Field", "properties": { @@ -152,7 +152,7 @@ }, { "title": "Pose X (Meter)", - "x": 1024.0, + "x": 1152.0, "y": 0.0, "width": 128.0, "height": 128.0, @@ -166,7 +166,7 @@ }, { "title": "Pose Y (Meter)", - "x": 1024.0, + "x": 1152.0, "y": 128.0, "width": 128.0, "height": 128.0, @@ -180,7 +180,7 @@ }, { "title": "Pose Theta (Degrees)", - "x": 1024.0, + "x": 1152.0, "y": 256.0, "width": 128.0, "height": 128.0, @@ -191,6 +191,19 @@ "data_type": "double", "show_submit_button": false } + }, + { + "title": "limelight", + "x": 256.0, + "y": 0.0, + "width": 384.0, + "height": 384.0, + "type": "Camera Stream", + "properties": { + "topic": "/CameraPublisher/limelight", + "period": 0.06, + "rotation_turns": 0 + } } ] } diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveForward.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveForward.auto new file mode 100644 index 0000000..983e8ed --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveForward.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "DriveForward" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto index 19afbc2..62253ac 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/ReverseIntoCorner.auto @@ -9,6 +9,12 @@ "data": { "pathName": "ReverseIntoCorner" } + }, + { + "type": "named", + "data": { + "name": "AimToHub" + } } ] } diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorizontal.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorizontal.auto new file mode 100644 index 0000000..39521a1 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorizontal.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "Example_Path" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto new file mode 100644 index 0000000..a2e63bd --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleHorziontalBackward.auto @@ -0,0 +1,19 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "ExamplePathBackwards" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto new file mode 100644 index 0000000..5ad17a4 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto @@ -0,0 +1,25 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "LineupToTower" + } + }, + { + "type": "named", + "data": { + "name": "RotateTo-180" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json index 465fe26..0c6a2de 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json @@ -1 +1 @@ -{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file +{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForward.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForward.path new file mode 100644 index 0000000..c8313ec --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DriveForward.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.293102564102565, + "y": 5.896 + }, + "prevControl": null, + "nextControl": { + "x": 3.293102564102565, + "y": 5.896 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 3.6070897435897447, + "y": 5.896 + }, + "prevControl": { + "x": 2.6070897435897447, + "y": 5.896 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path new file mode 100644 index 0000000..928549c --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ExamplePathBackwards.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.0, + "y": 4.837 + }, + "prevControl": null, + "nextControl": { + "x": 2.0, + "y": 4.587 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 3.814064102564102 + }, + "prevControl": { + "x": 2.0, + "y": 4.064064102564102 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path index 0d78846..64d5745 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/Example_Path.path @@ -3,25 +3,25 @@ "waypoints": [ { "anchor": { - "x": 2.1486729452054796, - "y": 6.48169948630137 + "x": 2.0, + "y": 4.837 }, "prevControl": null, "nextControl": { - "x": 2.3986729452054796, - "y": 6.48169948630137 + "x": 2.0, + "y": 4.587 }, "isLocked": false, "linkedName": null }, { "anchor": { - "x": 5.213912671232877, - "y": 6.48169948630137 + "x": 2.0, + "y": 3.814064102564102 }, "prevControl": { - "x": 4.963912671232877, - "y": 6.48169948630137 + "x": 2.0, + "y": 4.064064102564102 }, "nextControl": null, "isLocked": false, diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path new file mode 100644 index 0000000..56ce83d --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 3.0721923076923088, + "y": 5.116423076923077 + }, + "prevControl": null, + "nextControl": { + "x": 3.130333333333334, + "y": 4.581525641025641 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.7814871794871805, + "y": 3.976858974358975 + }, + "prevControl": { + "x": 3.2001025641025653, + "y": 4.186166666666668 + }, + "nextControl": { + "x": 2.488419497644409, + "y": 3.8303251334375887 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.5721538461538476, + "y": 3.755923076923077 + }, + "prevControl": { + "x": 2.4326410256410247, + "y": 3.767551282051283 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 131.18592516570953 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path index 94faccd..f5a63f4 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ReverseIntoCorner.path @@ -3,29 +3,13 @@ "waypoints": [ { "anchor": { - "x": 3.22, - "y": 6.06 + "x": 1.7349487179487189, + "y": 6.104820512820513 }, "prevControl": null, "nextControl": { - "x": 2.840245730777104, - "y": 6.528957467245401 - }, - "isLocked": false, - "linkedName": null - }, - { - "anchor": { - "x": 2.0023974358974375, - "y": 6.697858974358974 - }, - "prevControl": { - "x": 2.932653846153847, - "y": 6.70948717948718 - }, - "nextControl": { - "x": 1.534985890056773, - "y": 6.692016330035965 + "x": 1.5521849008880018, + "y": 6.275400075410516 }, "isLocked": false, "linkedName": null @@ -33,11 +17,11 @@ { "anchor": { "x": 0.7930641025641041, - "y": 7.290897435897436 + "y": 7.162987179487179 }, "prevControl": { - "x": 1.258340364584852, - "y": 6.825621173876687 + "x": 0.9791153846153859, + "y": 6.942051282051282 }, "nextControl": null, "isLocked": false, diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/wawd.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/wawd.path new file mode 100644 index 0000000..8cf8bff --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/wawd.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 4.607, + "y": 4.035 + }, + "prevControl": null, + "nextControl": { + "x": 5.606999999999999, + "y": 4.035 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 8.304884615384616, + "y": 4.035 + }, + "prevControl": { + "x": 7.304884615384616, + "y": 4.035 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/wdawda.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/wdawda.path new file mode 100644 index 0000000..74c7aba --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/wdawda.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.5953846153846167, + "y": 6.267615384615385 + }, + "prevControl": null, + "nextControl": { + "x": 1.0256282051282062, + "y": 6.27924358974359 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.0, + "y": 4.837 + }, + "prevControl": { + "x": 2.0, + "y": 5.355075362944116 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 80b0ca4..dd03f45 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -9,7 +9,9 @@ import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.auto.NamedCommands; import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -20,18 +22,25 @@ import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; 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.SendableChooser; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.Commands; +import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import edu.wpi.first.wpilibj.PneumaticHub; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; import frc.robot.Constants.PneumaticsConstants; +import frc.robot.commands.AimAtHub; import frc.robot.commands.DriveForwardFromPos; +import frc.robot.commands.POTFtoPoint; +import frc.robot.commands.RotateToRotation2D; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -51,11 +60,11 @@ public class RobotContainer { // The robot's subsystems and commands are defined here... private final Optional m_driveSubsystem; - private final Optional m_intakeSubsystem; - private final Optional m_climbL1Subsystem; - private final Optional m_indexerBulkSubsystem; - private final Optional m_launcherSubsystem; - private final Optional m_pneumaticHub; + // private final Optional m_intakeSubsystem; + // private final Optional m_climbL1Subsystem; + // private final Optional m_indexerBulkSubsystem; + // private final Optional m_launcherSubsystem; + // private final Optional m_pneumaticHub; private final LimelightSubsystem m_limelightSubsystem; // Replace with CommandPS4Controller or CommandJoystick if needed @@ -79,6 +88,13 @@ public class RobotContainer { m_limelightError ); + PathConstraints m_constraints = new PathConstraints( + 1.0, + 1.0, + 2 * Math.PI, + 4 * Math.PI + ); // The constraints for this path. + // Smartdashboard Objects private SendableChooser m_autoChooser; private final Field2d m_field = new Field2d(); @@ -94,13 +110,13 @@ public class RobotContainer { public RobotContainer() { // Init pneumatics system. - m_pneumaticHub = getSubsystem(PneumaticHub.class); - if (m_pneumaticHub.isPresent()) - { - PneumaticHub hub = m_pneumaticHub.get(); - hub.enableCompressorAnalog(PneumaticsConstants.kMinPneumaticsPressure, - PneumaticsConstants.kMaxPneumaticsPressure); - } + // m_pneumaticHub = getSubsystem(PneumaticHub.class); + // if (m_pneumaticHub.isPresent()) + // { + // PneumaticHub hub = m_pneumaticHub.get(); + // hub.enableCompressorAnalog(PneumaticsConstants.kMinPneumaticsPressure, + // PneumaticsConstants.kMaxPneumaticsPressure); + // } // Init DriveSubsystem Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); @@ -111,10 +127,10 @@ public RobotContainer() { // Init the subsystems m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_gyro); - m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); - m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); - m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); - m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); + // m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); + // m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); + // m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); + // m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); // Init Auto configureAutos(); @@ -146,17 +162,64 @@ private void configureAutos() { // m_autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string m_autoChooser = new SendableChooser(); + // Named Commands + NamedCommands.registerCommand("RotateTo-180", new RotateToRotation2D( + m_driveSubsystem.get(), + m_PoseEstimator, + Rotation2d.fromDegrees(180), + 1 + ) + ); + + NamedCommands.registerCommand("AimToHub", new AimAtHub( + m_driveSubsystem.get(), + m_PoseEstimator, + 2.0, + isRed() + ) + ); + // Custom Autos m_autoChooser.addOption( "On-Fly Forward 2m", new DriveForwardFromPos(m_PoseEstimator, 2) ); + m_autoChooser.addOption( + "Rotate to 0", + new RotateToRotation2D( + m_driveSubsystem.get(), + m_PoseEstimator, + new Rotation2d(0.0), + 1 + ) + ); + + m_autoChooser.addOption( + "On-The-Fly to (2, 4.837) -90", + new POTFtoPoint( + m_PoseEstimator, + new Pose2d(2, 4.837, Rotation2d.fromDegrees(-90)) + ) + ); + // Path Planner Auto's ArrayList autoNames = AutoCommands.getAutoNames(); for (String autoName : autoNames) { - PathPlannerAuto auto = new PathPlannerAuto(autoName); - m_autoChooser.addOption(autoName, auto); + PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); + Pose2d startingPose = plannedAuto.getStartingPose(); + + Command rotateToStartRot = new RotateToRotation2D( + m_driveSubsystem.get(), + m_PoseEstimator, + startingPose.getRotation(), + 2.0 + ); + + Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); + Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); + + m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); } // Add to dashboard @@ -195,6 +258,17 @@ private void configureBindings() { // // cancelling on release. // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); // } + + m_driverController.y().onTrue(new InstantCommand(() -> CommandScheduler.getInstance().cancelAll())); + + m_driverController.x().onTrue( + new AimAtHub( + m_driveSubsystem.get(), + m_PoseEstimator, + 2.0, + isRed() + ) + ); } // Populate the SmartDashboard on robot init. @@ -202,6 +276,9 @@ public void InitSmartDashboard() { // Non-Subsystem Specific Stuff SmartDashboard.putData(CommandScheduler.getInstance()); SmartDashboard.putData("Field", m_field); + SmartDashboard.putNumber("Target Rotation", 0); + SmartDashboard.putNumber("Target Angle Diff Abs", 0); + SmartDashboard.putNumber("Rotation Speed", 0); } // This function is called every 20mS. @@ -235,16 +312,27 @@ public void UpdateSmartDashboard() { } // Pneumatics compressor - if(m_pneumaticHub.isPresent() && ((m_iTickCount % PneumaticsConstants.kTicksPerUpdate) == 0)) - { - PneumaticHub hub = m_pneumaticHub.get(); - SmartDashboard.putNumber("Pressure", hub.getPressure(0)); - SmartDashboard.putBoolean("Compressor Running", hub.getCompressor()); - } + // if(m_pneumaticHub.isPresent() && ((m_iTickCount % PneumaticsConstants.kTicksPerUpdate) == 0)) + // { + // PneumaticHub hub = m_pneumaticHub.get(); + // SmartDashboard.putNumber("Pressure", hub.getPressure(0)); + // SmartDashboard.putBoolean("Compressor Running", hub.getCompressor()); + // } m_iTickCount++; } + // Checks if the robot is on the blue or red alliance. If it cannot get the data it defaults to blue. + public boolean isRed() { + Optional alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + return alliance.get() == DriverStation.Alliance.Red; + } else { + System.out.println("Could not fetch alliance! Defaulting to blue!"); + return false; + } + } + public void disabledInit() {} // Move to auto init for competition code. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java new file mode 100644 index 0000000..4c18c4e --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java @@ -0,0 +1,76 @@ +package frc.robot.commands; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class AimAtHub extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final double m_maxSpeed; + private final boolean m_isRed; + + private final Pose2d m_BlueCenter = new Pose2d(4.607, 4.035, new Rotation2d()); + private final Pose2d m_RedCenter = new Pose2d(); + + /** + * Creates a new AimAtHub. + * + * @param driveSubsystem The driveSubsystem for the robot. + * @param poseEstimator The poseEstimator of the robot. + * @param maxSpeed The max speed the robot is allowed to go in the rotation. + * @param isRed Does the robot need to point tword the red or blue goal, default is blue. + */ + public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, double maxSpeed, boolean isRed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_maxSpeed = maxSpeed; + m_isRed = isRed; + + addRequirements(driveSubsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Pose2d targetPose; + if (m_isRed) { + targetPose = m_RedCenter; + } else { + targetPose = m_BlueCenter; + } + + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + double dY = targetPose.getY() - currentPose.getY(); + double dX = targetPose.getX() - currentPose.getX(); + + Rotation2d targetRotation = new Rotation2d(Math.atan2(dY, dX)); + RotateToRotation2D aimCommand = new RotateToRotation2D( + m_driveSubsystem, + m_poseEstimator, + targetRotation, + m_maxSpeed + ); + + CommandScheduler.getInstance().schedule(aimCommand); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java index 1a25daf..16b0322 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java @@ -48,9 +48,6 @@ public void execute() { rightSpeed = 0; } - leftSpeed = (leftSpeed < 0) ? (-leftSpeed * leftSpeed) : (leftSpeed * leftSpeed); - rightSpeed = (rightSpeed < 0) ? (-rightSpeed * rightSpeed) : (rightSpeed * rightSpeed); - leftSpeed *= DrivetrainConstants.kMaxVelocityMPS; rightSpeed *= DrivetrainConstants.kMaxVelocityMPS; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java b/2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java new file mode 100644 index 0000000..5990ecc --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java @@ -0,0 +1,84 @@ +package frc.robot.commands; + +import java.util.List; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.GoalEndState; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.path.Waypoint; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; + +/** An example command that uses an example subsystem. */ +public class POTFtoPoint extends Command { + private final DifferentialDrivePoseEstimator m_poseEstimator; + private Pose2d m_targetPose; + + /** + * Creates a new POTFtwoPoints. + * + * @param subsystem The subsystem used by this command. + */ + public POTFtoPoint(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose) + { + m_poseEstimator = poseEstimator; + m_targetPose = targetPose; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This is taken and modified from the limelight documentation for + // path creation on the fly: https://pathplanner.dev/pplib-create-a-path-on-the-fly.html + + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + + // Create a list of waypoints from poses. Each pose represents one waypoint. + // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. + List waypoints = PathPlannerPath.waypointsFromPoses( + currentPose, + m_targetPose + ); + + PathConstraints constraints = new PathConstraints( + 1.0, + 1.0, + 2 * Math.PI, + 4 * Math.PI + ); // The constraints for this path. + + // Create the path using the waypoints created above + PathPlannerPath path = new PathPlannerPath( + waypoints, + constraints, + null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. + new GoalEndState(0.0, m_targetPose.getRotation()) // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. + ); + + // Prevent the path from being flipped if the coordinates are already correct + path.preventFlipping = true; + + // Create the command version of the path and schedule it + Command followPath = AutoBuilder.followPath(path); + CommandScheduler.getInstance().schedule(followPath); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java new file mode 100644 index 0000000..1b20280 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -0,0 +1,86 @@ +package frc.robot.commands; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class RotateToRotation2D extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final double m_maxSpeed; + private Rotation2d m_targetRotation; + + // Bounds are [0, 1) in interval notation. This effects the steepness of + // the curve that is used to slow the robot as it approches the target. + private double speedExp = 0.98; + + /** + * Creates a new RotateToRotation2D. + * + * @param driveSubsystem The driveSubsystem for the robot. + * @param poseEstimator The poseEstimator of the robot. + * @param targetRotation The rotation you want the robot to go to. + * @param maxSpeed The max speed the robot is allowed to go in the rotation. + */ + public RotateToRotation2D(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, Rotation2d targetRotation, double maxSpeed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_targetRotation = targetRotation; + m_maxSpeed = maxSpeed; + + SmartDashboard.putNumber("Target Rotation", m_targetRotation.getDegrees()); + + addRequirements(driveSubsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + Rotation2d currentRotation = m_poseEstimator.getEstimatedPosition().getRotation(); + Rotation2d changeInRotation = m_targetRotation.minus(currentRotation); + + double targetDiff = Math.abs(changeInRotation.getDegrees()); + + double speed = ((Math.pow(speedExp, targetDiff)-1)/(Math.pow(speedExp, 180)-1)); + speed *= m_maxSpeed; + speed = Math.max(speed, 0.3); + SmartDashboard.putNumber("Rotation Speed", speed); + + if (changeInRotation.getDegrees() <= 0) { + m_driveSubsystem.setDifferentialSpeeds(speed, -speed); + } else { + m_driveSubsystem.setDifferentialSpeeds(-speed, speed); + } + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + System.out.println("Ended Rotation fix!"); + m_driveSubsystem.setDifferentialSpeeds(0, 0); + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + Rotation2d currentRotation = m_poseEstimator.getEstimatedPosition().getRotation(); + Rotation2d diff = m_targetRotation.minus(currentRotation); + + double currentDiffAbs = Math.abs(diff.getDegrees()); + SmartDashboard.putNumber("Target Angle Diff Abs", currentDiffAbs); + + if (currentDiffAbs <= 0.5) { + return true; + } else { + return false; + } + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 67ac57b..918a91c 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -120,6 +120,11 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential SmartDashboard.putNumber("Left Speed (RPS)", getMotorSpeedRPS(true)); SmartDashboard.putNumber("Right Speed (RPS)", getMotorSpeedRPS(false)); + SmartDashboard.putNumber("Left Set (-1-->1)", 0); + SmartDashboard.putNumber("Right Set (-1-->1)", 0); + SmartDashboard.putNumber("Left Get (-1-->1)", 0); + SmartDashboard.putNumber("Right Get (-1-->1)", 0); + SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); } @@ -226,6 +231,9 @@ public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) // pass in -1 to 1 for the motor speed with no closed loop control. public void setDifferentialSpeedNoPid(double left, double right) { + SmartDashboard.putNumber("Left Set (-1-->1)", left); + SmartDashboard.putNumber("Right Set (-1-->1)", right); + m_leftMotor.set(left); m_rightMotor.set(right); } @@ -316,6 +324,9 @@ public void periodic() { lPositionMeters, rPositionMeters ); + + SmartDashboard.putNumber("Left Get (-1-->1)", m_leftMotor.get()); + SmartDashboard.putNumber("Right Get (-1-->1)", m_rightMotor.get()); } @Override From d58bef5152f7161f5e778972ed123239366934bf Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Feb 2026 09:45:05 -0600 Subject: [PATCH 057/161] Add skeleton for Launcher subsystem class interface. --- .../robot/subsystems/LauncherSubsystem.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index b791509..9011cbc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -8,11 +8,68 @@ import frc.robot.Constants.LauncherConstants; public class LauncherSubsystem extends SubsystemBase { + private double m_targetSpeedrpm; + private boolean m_liftRunning; + /** Creates a new LauncherSubsystem. */ public LauncherSubsystem() { // TODO: write this } + // + // Set the speed of the launcher flywheel in revolutions per minute. + // + public void setTargetSpeedrpm(double RPM) + { + m_targetSpeedrpm = RPM; + + // TODO: Populate this! + } + + // + // Get the current launcher flywheel speed in revolutions per minute. + // + public double getCurrentSpeedrpm() + { + // TODO: Populate this! + return 0.0; + } + + // + // Get the current target speed for the launcher flywheel in revolutions + // per minute. + // + public double getTargetSpeedrpm() + { + return m_targetSpeedrpm; + } + + // + // Start the lift mechanism motor. + // + public void startLift() + { + // TODO: Populate this! + } + + // + // Stop the lift mechanism motor. + // + public void stopLift() + { + // TODO: Populate this! + } + + // + // Determine whether or not a fuel is in position beneath the launcher + // entrance. + // + public boolean isFuelAtLauncher() + { + // TODO: Populate this! + return false; + } + @Override public void periodic() { // This method will be called once per scheduler run From 4f68c9995721eec76260111300a66c416e2fb314 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Feb 2026 11:33:18 -0600 Subject: [PATCH 058/161] Continue fleshing out launcher subsystem Code builds cleanly but is currently untested! --- .../src/main/java/frc/robot/Constants.java | 27 +++++ .../robot/subsystems/LauncherSubsystem.java | 104 +++++++++++++++++- 2 files changed, 125 insertions(+), 6 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index f97f055..1d7da01 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -153,6 +153,33 @@ public static class LauncherConstants { // Beam break sensor to detect fuel at the top of the lift. public static final int kUpperFuelSensorChannel = 0; public static final boolean kUpperFuelSensorIsEmpty = false; + + // These numbers came from the ctre example then tweaked + public static final double kS = 0.1; // A velocity target of 1 rps results in xV output + public static final double kV = 0.12; // Add x V output to overcome static friction + public static final double kP = 0.11; // An error of 1 rotation results in x V output + public static final double kI = 0.0; + public static final double kD = 0.0; // A velocity of 1 rps results in x V output + public static final double kA_linear = 0.01; // Voltage needed to induce a given accel. in the motor shaft + public static final double kA_angular = 0.01; // TODO: We need to measure this! + public static final double kPeakVoltage = 8.0; + + public static final double kMaxVelocityRPS = 6000.0/60.0; + public static final double kMaxAccelerationRPS2 = 50.0; + + public static final double kMotionMagicAcceleration = 50.0; // Higher number --> Faster (50.0 = ~1s to max) + public static final double kMotionMagicJerk = 4000.0; + + // Set to false if both flywheel motors drive in the same direction, false if they + // run in opposite directions. + public static final boolean kMotorsDriveInOppositeDirections = true; + + // Set to false if we drive the lead launcher flywheel motor clockwise to operate + // correctly, or true to drive it counterclockwise. + public static final boolean kLauncherMotorForwardIsCCW = true; + + // Frequency at which we send current launcher speed back to the driver station. + public static final int kTicksPerUpdate = 10; } public static class IndexerBulkConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 9011cbc..7b7d40a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -4,16 +4,94 @@ package frc.robot.subsystems; +import static edu.wpi.first.units.Units.*; + +import com.ctre.phoenix6.StatusCode; +import com.ctre.phoenix6.configs.TalonFXConfiguration; +import com.ctre.phoenix6.controls.MotionMagicVelocityVoltage; +import com.ctre.phoenix6.controls.Follower; +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.signals.*; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.Constants.LauncherConstants; public class LauncherSubsystem extends SubsystemBase { private double m_targetSpeedrpm; private boolean m_liftRunning; + private int m_tickCount = 0; + + private TalonFX m_motorLeader; + private TalonFX m_motorFollower; + + /* Be able to switch which control request to use based on a button press */ + /* Start at velocity 0, use slot 0 */ + private final MotionMagicVelocityVoltage m_velocityVoltage = new MotionMagicVelocityVoltage(0).withSlot(0); + + /** Creates a new LauncherSubsystem. + * @throws Exception */ + public LauncherSubsystem() throws Exception { + + m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); + m_motorFollower = new TalonFX(LauncherConstants.kLauncherFlywheelMotor2CANID); + + // Check that the motors exist and throw an exception if they don't. + if(!m_motorLeader.isConnected() || !m_motorFollower.isConnected()) + { + throw new Exception("At least one launcher motor is not present!"); + } + + TalonFXConfiguration configs = new TalonFXConfiguration(); + + /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ + configs.Slot0.kS = LauncherConstants.kS; // To account for friction, add 0.1 V of static feedforward + configs.Slot0.kV = LauncherConstants.kV; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second + configs.Slot0.kP = LauncherConstants.kP; // An error of 1 rotation per second results in 0.11 V output + configs.Slot0.kI = LauncherConstants.kI; // No output for integrated error + configs.Slot0.kD = LauncherConstants.kD; // No output for error derivative + // Peak output of 8 volts + configs.Voltage.withPeakForwardVoltage(Volts.of(8)) + .withPeakReverseVoltage(Volts.of(-8)); + + var motionMagicConfigs = configs.MotionMagic; + motionMagicConfigs.MotionMagicAcceleration = LauncherConstants.kMotionMagicAcceleration; + motionMagicConfigs.MotionMagicJerk = LauncherConstants.kMotionMagicJerk; - /** Creates a new LauncherSubsystem. */ - public LauncherSubsystem() { - // TODO: write this + // Set coast mode so that the flywheel doesn't slam to a halt when the + // motors stop. + configs.MotorOutput.NeutralMode = NeutralModeValue.Coast; + + // Set the basic rotation direction for both motors. Note that this setting + // will be ignored by the follower since we explicitly tell it whether to + // run in the same direction as or the opposite direction from the leader + // when we set up the follow relationship below. + configs.MotorOutput.Inverted = LauncherConstants.kLauncherMotorForwardIsCCW ? + InvertedValue.CounterClockwise_Positive : + InvertedValue.Clockwise_Positive; + + /* Retry config apply up to 5 times, report if failure */ + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = m_motorLeader.getConfigurator().apply(configs); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs 1, error code: " + status.toString()); + } + for (int i = 0; i < 5; ++i) { + status = m_motorFollower.getConfigurator().apply(configs); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs 2, error code: " + status.toString()); + } + + // Set up the follower. Note that setting MotorAlignmentValue tells the system to ignore the + // follower's MotorOutput.Inverted setting and either run the same direction as, or the opposite + // direction from, the leader. + m_motorFollower.setControl(new Follower(m_motorLeader.getDeviceID(), + LauncherConstants.kMotorsDriveInOppositeDirections ? + MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); } // @@ -23,7 +101,13 @@ public void setTargetSpeedrpm(double RPM) { m_targetSpeedrpm = RPM; - // TODO: Populate this! + double desiredRotationsPerSecond = RPM * 60.0; + + SmartDashboard.putNumber("Launcher Set RPM", RPM); + SmartDashboard.putNumber("Launcher Set RPS", desiredRotationsPerSecond); + + /* Use velocity voltage */ + m_motorLeader.setControl(m_velocityVoltage.withVelocity(desiredRotationsPerSecond)); } // @@ -31,8 +115,8 @@ public void setTargetSpeedrpm(double RPM) // public double getCurrentSpeedrpm() { - // TODO: Populate this! - return 0.0; + // Remember to convert motor's revs per second velocity to revs per minute! + return m_motorLeader.getVelocity().getValueAsDouble() * 60.0; } // @@ -73,6 +157,14 @@ public boolean isFuelAtLauncher() @Override public void periodic() { // This method will be called once per scheduler run + m_tickCount++; + + if((m_tickCount % LauncherConstants.kTicksPerUpdate) == 0) + { + double speedRPS = m_motorLeader.getVelocity().getValueAsDouble(); + SmartDashboard.putNumber("Launcher RPM", speedRPS * 60.0); + SmartDashboard.putNumber("Launcher RPS", speedRPS); + } } @Override From 55a773403bd195bc020183d636164c79167cd54c Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Feb 2026 13:11:05 -0600 Subject: [PATCH 059/161] Completed LauncherSubsystem and hopefully fixed optional subsystem handling This builds cleanly but is untested! --- .../src/main/java/frc/robot/Constants.java | 9 ++-- .../main/java/frc/robot/RobotContainer.java | 34 +++++++++------ .../robot/subsystems/LauncherSubsystem.java | 42 +++++++++++++++---- .../frc/robot/utils/PneumaticHubWrapper.java | 39 +++++++++++++++++ 4 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 1d7da01..51432e4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -146,9 +146,12 @@ public static class IntakeConstants { } public static class LauncherConstants { - public static int kLauncherFlywheelMotor1CANID = 40; - public static int kLauncherFlywheelMotor2CANID = 41; - public static int kLauncherLiftMotorCANID = 42; + public static final int kLauncherFlywheelMotor1CANID = 40; + public static final int kLauncherFlywheelMotor2CANID = 41; + public static final int kLauncherLiftMotorCANID = 42; + + // The speed, in range [-1.0, 1.0], to run the lift motor when started. + public static final double kLiftMotorSpeed = 0.3; // Beam break sensor to detect fuel at the top of the lift. public static final int kUpperFuelSensorChannel = 0; diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 80b0ca4..9ee248e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -41,6 +41,7 @@ import frc.robot.subsystems.ClimbL1Subsystem; import frc.robot.subsystems.LimelightSubsystem; import frc.robot.utils.AutoCommands; +import frc.robot.utils.PneumaticHubWrapper; /** * This class is where the bulk of the robot should be declared. Since Command-based is a @@ -55,7 +56,7 @@ public class RobotContainer { private final Optional m_climbL1Subsystem; private final Optional m_indexerBulkSubsystem; private final Optional m_launcherSubsystem; - private final Optional m_pneumaticHub; + private final Optional m_pneumaticHub; private final LimelightSubsystem m_limelightSubsystem; // Replace with CommandPS4Controller or CommandJoystick if needed @@ -92,16 +93,6 @@ public class RobotContainer { /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { - - // Init pneumatics system. - m_pneumaticHub = getSubsystem(PneumaticHub.class); - if (m_pneumaticHub.isPresent()) - { - PneumaticHub hub = m_pneumaticHub.get(); - hub.enableCompressorAnalog(PneumaticsConstants.kMinPneumaticsPressure, - PneumaticsConstants.kMaxPneumaticsPressure); - } - // Init DriveSubsystem Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); @@ -109,13 +100,30 @@ public RobotContainer() { Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); - // Init the subsystems + // Init the subsystems that don't require pneumatics. m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_gyro); m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); - m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); + // Init pneumatics system and subsystems that rely upon it. + m_pneumaticHub = getSubsystem(PneumaticHubWrapper.class); + if (m_pneumaticHub.isPresent()) + { + PneumaticHub hub = m_pneumaticHub.get(); + hub.enableCompressorAnalog(PneumaticsConstants.kMinPneumaticsPressure, + PneumaticsConstants.kMaxPneumaticsPressure); + + m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); + + // TODO: If intake ends up using pneumatics, move its construction here too. + } + else + { + // If there are no pneumatics, there's no climb. + m_climbL1Subsystem = Optional.empty(); + } + // Init Auto configureAutos(); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 7b7d40a..f5688b3 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -12,17 +12,25 @@ import com.ctre.phoenix6.controls.Follower; import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.*; +import com.revrobotics.spark.SparkMax; +import com.revrobotics.spark.SparkBase; +import com.revrobotics.spark.SparkLowLevel.MotorType; + import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; +import edu.wpi.first.wpilibj.DigitalInput; import frc.robot.Constants.LauncherConstants; public class LauncherSubsystem extends SubsystemBase { - private double m_targetSpeedrpm; - private boolean m_liftRunning; + private double m_targetSpeedrpm = 0.0; + private boolean m_liftRunning = false; private int m_tickCount = 0; private TalonFX m_motorLeader; private TalonFX m_motorFollower; + private SparkMax m_motorLift; + + private final DigitalInput m_Sensor = new DigitalInput(LauncherConstants.kUpperFuelSensorChannel); /* Be able to switch which control request to use based on a button press */ /* Start at velocity 0, use slot 0 */ @@ -32,15 +40,23 @@ public class LauncherSubsystem extends SubsystemBase { * @throws Exception */ public LauncherSubsystem() throws Exception { + m_motorLift = new SparkMax(LauncherConstants.kLauncherLiftMotorCANID, MotorType.kBrushless); m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); m_motorFollower = new TalonFX(LauncherConstants.kLauncherFlywheelMotor2CANID); - // Check that the motors exist and throw an exception if they don't. + // Check that the launcher motors exist and throw an exception if they don't. if(!m_motorLeader.isConnected() || !m_motorFollower.isConnected()) { throw new Exception("At least one launcher motor is not present!"); } + // Ensure that the lift motor is present. + SparkBase.Faults Faults = m_motorLift.getFaults(); + if(Faults.can || Faults.firmware || Faults.gateDriver) + { + throw new Exception("Lift motor is not present or is reporting a fault!"); + } + TalonFXConfiguration configs = new TalonFXConfiguration(); /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ @@ -92,6 +108,9 @@ public LauncherSubsystem() throws Exception { m_motorFollower.setControl(new Follower(m_motorLeader.getDeviceID(), LauncherConstants.kMotorsDriveInOppositeDirections ? MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); + + // Configure the fuel sensor. + } // @@ -133,7 +152,8 @@ public double getTargetSpeedrpm() // public void startLift() { - // TODO: Populate this! + m_motorLift.set(LauncherConstants.kLiftMotorSpeed); + m_liftRunning = true; } // @@ -141,7 +161,15 @@ public void startLift() // public void stopLift() { - // TODO: Populate this! + m_motorLift.set(0.0); + m_liftRunning = false; + } + + // + // Determine whether or not the lift motor is running. + public boolean isLiftMotorStarted() + { + return m_liftRunning; } // @@ -150,8 +178,8 @@ public void stopLift() // public boolean isFuelAtLauncher() { - // TODO: Populate this! - return false; + boolean sensorRead = m_Sensor.get(); + return (sensorRead == LauncherConstants.kUpperFuelSensorIsEmpty) ? false : true; } @Override diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java new file mode 100644 index 0000000..40a579f --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java @@ -0,0 +1,39 @@ +// +// A trivial class that wraps PneumaticHub to allow us to throw an exception +// if the device doesn't exist on the CAN bus. +// +package frc.robot.utils; + +import edu.wpi.first.hal.REVPHFaults; +import edu.wpi.first.wpilibj.PneumaticHub; + +public class PneumaticHubWrapper extends PneumaticHub { + private PneumaticHub m_Hub; + + /* @throws Exception */ + public PneumaticHubWrapper() throws Exception { + m_Hub = new PneumaticHub(); + + if (!isAvailable()) + { + throw new Exception("Pneumatic hub is not connected or is malfunctioning."); + } + } + + /* @throws Exception */ + public PneumaticHubWrapper(int module) throws Exception { + m_Hub = new PneumaticHub(module); + + if (!isAvailable()) + { + throw new Exception("Pneumatic hub is not connected or is malfunctioning."); + } + } + + public boolean isAvailable() + { + REVPHFaults Faults = m_Hub.getFaults(); + + return !(Faults.CanWarning || Faults.HardwareFault); + } +} From fe4f7c3bb758ee1e9e845da4c06df5c918ee493c Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Feb 2026 13:40:03 -0600 Subject: [PATCH 060/161] Fleshed out the indexer/bulk transport subsystem. ...and removed unused example command and subsystem. --- .../main/java/frc/robot/commands/Autos.java | 20 -------- .../frc/robot/commands/ExampleCommand.java | 43 ----------------- .../robot/subsystems/ExampleSubsystem.java | 47 ------------------- .../subsystems/IndexerBulkSubsystem.java | 39 +++++++++++---- .../robot/subsystems/LauncherSubsystem.java | 5 ++ 5 files changed, 36 insertions(+), 118 deletions(-) delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java deleted file mode 100644 index 107aad7..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/Autos.java +++ /dev/null @@ -1,20 +0,0 @@ -// 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.commands; - -import frc.robot.subsystems.ExampleSubsystem; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.Commands; - -public final class Autos { - /** Example static factory for an autonomous command. */ - public static Command exampleAuto(ExampleSubsystem subsystem) { - return Commands.sequence(subsystem.exampleMethodCommand(), new ExampleCommand(subsystem)); - } - - private Autos() { - throw new UnsupportedOperationException("This is a utility class!"); - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java deleted file mode 100644 index 151624c..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/ExampleCommand.java +++ /dev/null @@ -1,43 +0,0 @@ -// 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.commands; - -import frc.robot.subsystems.ExampleSubsystem; -import edu.wpi.first.wpilibj2.command.Command; - -/** An example command that uses an example subsystem. */ -public class ExampleCommand extends Command { - @SuppressWarnings({"PMD.UnusedPrivateField", "PMD.SingularField", "unused"}) - private final ExampleSubsystem m_subsystem; - - /** - * Creates a new ExampleCommand. - * - * @param subsystem The subsystem used by this command. - */ - public ExampleCommand(ExampleSubsystem subsystem) { - m_subsystem = subsystem; - // Use addRequirements() here to declare subsystem dependencies. - addRequirements(subsystem); - } - - // Called when the command is initially scheduled. - @Override - public void initialize() {} - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - return false; - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java deleted file mode 100644 index 6b375da..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ExampleSubsystem.java +++ /dev/null @@ -1,47 +0,0 @@ -// 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.subsystems; - -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.SubsystemBase; - -public class ExampleSubsystem extends SubsystemBase { - /** Creates a new ExampleSubsystem. */ - public ExampleSubsystem() {} - - /** - * Example command factory method. - * - * @return a command - */ - public Command exampleMethodCommand() { - // Inline construction of command goes here. - // Subsystem::RunOnce implicitly requires `this` subsystem. - return runOnce( - () -> { - /* one-time action goes here */ - }); - } - - /** - * An example method querying a boolean state of the subsystem (for example, a digital sensor). - * - * @return value of some boolean subsystem state, such as a digital sensor. - */ - public boolean exampleCondition() { - // Query some boolean state, such as a digital sensor. - return false; - } - - @Override - public void periodic() { - // This method will be called once per scheduler run - } - - @Override - public void simulationPeriodic() { - // This method will be called once per scheduler run during simulation - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index dfb0bf0..f68b67b 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -1,3 +1,8 @@ +// +// Subsystem offering low level control of the actuators and sensors +// in the indexer and bulk transport mechanisms. +// + // 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. @@ -5,38 +10,56 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; +import edu.wpi.first.wpilibj.DigitalInput; +import frc.robot.Constants.IndexerBulkConstants; +import com.ctre.phoenix6.hardware.TalonFX; +import com.ctre.phoenix6.hardware.TalonFXS; public class IndexerBulkSubsystem extends SubsystemBase { + private final DigitalInput m_Sensor = new DigitalInput(IndexerBulkConstants.kLowerFuelSensorChannel); + + private TalonFX m_motorIndexer; + private TalonFXS m_motorBulk; + /** Creates a new IndexerBulkSubsystem. */ - public IndexerBulkSubsystem() { - // TODO: write this + public IndexerBulkSubsystem() throws Exception { + m_motorIndexer = new TalonFX(IndexerBulkConstants.kIndexerMotorCANID); + if (!m_motorIndexer.isConnected()) + { + throw new Exception("Indexer motor is not present."); + } + m_motorBulk = new TalonFXS(IndexerBulkConstants.kIndexerMotorCANID); + if (!m_motorBulk.isConnected()) + { + throw new Exception("Bult transport motor is not present."); + } } // Runs the belts that transfer the fuel from bulk storage to the indexer. public void startBulkTransfer() { - // TODO: implement startBulkTransfer + m_motorBulk.set(IndexerBulkConstants.kBulkMoveMotorSpeed); } // Stops the belts in bulk storage. public void stopBulkTransfer() { - //TODO: implement stopBulkTransfer + m_motorBulk.set(0.0); } // Spins the indexer shaft which transfers fuel from the indexer to the launcher. public void startIndexer() { - // TODO: implement indexing + m_motorIndexer.set(IndexerBulkConstants.kIndexerMotorSpeed); } // Stops spinning the indexer shaft. public void stopIndexer() { - // TODO: implement stopIndexer + m_motorIndexer.set(0.0); } // Returns true if lower fuel sensor detects fuel. public boolean isFuelPresent() { - // TODO: implement isBeamBroken - return false; + boolean sensorRead = m_Sensor.get(); + return (sensorRead == IndexerBulkConstants.kLowerFuelSensorIsEmpty) ? false : true; } @Override diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index f5688b3..e3021ba 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -1,3 +1,8 @@ +// +// Subsystem offering low level control of the launcher flywheel and +// fuel lift mechanisms. +// + // 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. From 08061e486c856b4f15eca03109d062798f0e8a9e Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 14 Feb 2026 13:53:03 -0600 Subject: [PATCH 061/161] Tested Auto commands after merge. --- .../deploy/pathplanner/autos/2MeterAuto.auto | 19 -------- .../pathplanner/autos/DriveBwdToEdge.auto | 19 -------- .../pathplanner/autos/DriveFwdFromEdge.auto | 19 -------- .../deploy/pathplanner/autos/FwdThenBwd.auto | 31 ------------ .../deploy/pathplanner/autos/STurnAuto.auto | 19 -------- .../deploy/pathplanner/autos/SampleAuto.auto | 19 -------- .../pathplanner/autos/SmoothTurnAuto.auto | 19 -------- .../autos/SmoothTurn_ReverseS.auto | 25 ---------- .../deploy/pathplanner/autos/TowerlineUp.auto | 25 ---------- .../main/java/frc/robot/RobotContainer.java | 10 +++- .../java/frc/robot/commands/TurnLeftTest.java | 47 +++++++++++++++++++ .../robot/subsystems/LimelightSubsystem.java | 1 + 12 files changed, 56 insertions(+), 197 deletions(-) delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto delete mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto deleted file mode 100644 index 26adafa..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/2MeterAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "2_Meter_New" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto deleted file mode 100644 index e93b91b..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveBwdToEdge.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "DriveBackwardToCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto deleted file mode 100644 index 8582b38..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DriveFwdFromEdge.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "DriveForwardFromCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto deleted file mode 100644 index 6a60a9c..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/FwdThenBwd.auto +++ /dev/null @@ -1,31 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "DriveForwardFromCorner" - } - }, - { - "type": "wait", - "data": { - "waitTime": 1.0 - } - }, - { - "type": "path", - "data": { - "pathName": "DriveBackwardToCorner" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto deleted file mode 100644 index 59b73ae..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/STurnAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "S_Turn" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto deleted file mode 100644 index 6460f85..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SampleAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "Example_Path" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto deleted file mode 100644 index c79aef4..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurnAuto.auto +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "Smooth_Turn" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto deleted file mode 100644 index 119345f..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/SmoothTurn_ReverseS.auto +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "Smooth_Turn" - } - }, - { - "type": "path", - "data": { - "pathName": "Reverse_S_Turn" - } - } - ] - } - }, - "resetOdom": true, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto deleted file mode 100644 index 5ad17a4..0000000 --- a/2026-Rebuilt/src/main/deploy/pathplanner/autos/TowerlineUp.auto +++ /dev/null @@ -1,25 +0,0 @@ -{ - "version": "2025.0", - "command": { - "type": "sequential", - "data": { - "commands": [ - { - "type": "path", - "data": { - "pathName": "LineupToTower" - } - }, - { - "type": "named", - "data": { - "name": "RotateTo-180" - } - } - ] - } - }, - "resetOdom": false, - "folder": null, - "choreoAuto": false -} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index dd03f45..0818547 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -41,6 +41,7 @@ import frc.robot.commands.DriveForwardFromPos; import frc.robot.commands.POTFtoPoint; import frc.robot.commands.RotateToRotation2D; +import frc.robot.commands.TurnLeftTest; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -91,8 +92,8 @@ public class RobotContainer { PathConstraints m_constraints = new PathConstraints( 1.0, 1.0, - 2 * Math.PI, - 4 * Math.PI + (1/2) * Math.PI, // 90 degrees/s + (1/2) * Math.PI ); // The constraints for this path. // Smartdashboard Objects @@ -259,8 +260,13 @@ private void configureBindings() { // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); // } + // Cancel All Active Commands m_driverController.y().onTrue(new InstantCommand(() -> CommandScheduler.getInstance().cancelAll())); + // Turn left to produce stall error. + m_driverController.b().onTrue(new TurnLeftTest(m_driveSubsystem.get())); + + // Aim to Hub m_driverController.x().onTrue( new AimAtHub( m_driveSubsystem.get(), diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java b/2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java new file mode 100644 index 0000000..4e18583 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java @@ -0,0 +1,47 @@ +package frc.robot.commands; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +/** + * Turns the robot left at a fixed speed known to cause a stall. + * This command has no way to stop internally and must be cancled via another way. +*/ +public class TurnLeftTest extends Command { + private final DriveSubsystem m_driveSubsystem; + private final double m_stallSpeed = 0.23; + + /** + * Creates a new TurnLeftTest. + * + * @param driveSubsystem The driveSubsystem for the robot. + */ + public TurnLeftTest(DriveSubsystem driveSubsystem) + { + m_driveSubsystem = driveSubsystem; + addRequirements(driveSubsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + System.out.println("Starting TurnLeftTest! This command must be cancled via an outside method!"); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + m_driveSubsystem.setDifferentialSpeedNoPid(-m_stallSpeed, m_stallSpeed); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + m_driveSubsystem.setDifferentialSpeedNoPid(0, 0); + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 4e21387..0e18871 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -104,6 +104,7 @@ public void periodic() { // This method will be called once per scheduler IMUData limelightData = LimelightHelpers.getIMUData("limelight"); m_YawQue.add(limelightData.robotYaw); + //System.out.println(m_YawQue.toString()); updateOdometry(); } From 4e14e1498abb59ff2992a6937ce18dc29375980a Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 14 Feb 2026 14:05:09 -0600 Subject: [PATCH 062/161] Fixed AimAtHub not accounting for team propperly. --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 9 +++++---- .../src/main/java/frc/robot/commands/AimAtHub.java | 8 +++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 0818547..27ff8f3 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.Optional; +import java.util.function.BooleanSupplier; import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.auto.AutoBuilder; @@ -176,7 +177,7 @@ private void configureAutos() { m_driveSubsystem.get(), m_PoseEstimator, 2.0, - isRed() + isRed ) ); @@ -272,7 +273,7 @@ private void configureBindings() { m_driveSubsystem.get(), m_PoseEstimator, 2.0, - isRed() + isRed ) ); } @@ -329,7 +330,7 @@ public void UpdateSmartDashboard() { } // Checks if the robot is on the blue or red alliance. If it cannot get the data it defaults to blue. - public boolean isRed() { + public BooleanSupplier isRed = () -> { Optional alliance = DriverStation.getAlliance(); if (alliance.isPresent()) { return alliance.get() == DriverStation.Alliance.Red; @@ -337,7 +338,7 @@ public boolean isRed() { System.out.println("Could not fetch alliance! Defaulting to blue!"); return false; } - } + }; public void disabledInit() {} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java index 4c18c4e..067d269 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java @@ -1,5 +1,7 @@ package frc.robot.commands; +import java.util.function.BooleanSupplier; + import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; @@ -12,7 +14,7 @@ public class AimAtHub extends Command { private final DriveSubsystem m_driveSubsystem; private final DifferentialDrivePoseEstimator m_poseEstimator; private final double m_maxSpeed; - private final boolean m_isRed; + private final BooleanSupplier m_isRed; private final Pose2d m_BlueCenter = new Pose2d(4.607, 4.035, new Rotation2d()); private final Pose2d m_RedCenter = new Pose2d(); @@ -25,7 +27,7 @@ public class AimAtHub extends Command { * @param maxSpeed The max speed the robot is allowed to go in the rotation. * @param isRed Does the robot need to point tword the red or blue goal, default is blue. */ - public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, double maxSpeed, boolean isRed) + public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, double maxSpeed, BooleanSupplier isRed) { m_driveSubsystem = driveSubsystem; m_poseEstimator = poseEstimator; @@ -39,7 +41,7 @@ public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator po @Override public void initialize() { Pose2d targetPose; - if (m_isRed) { + if (m_isRed.getAsBoolean()) { targetPose = m_RedCenter; } else { targetPose = m_BlueCenter; From 11eb6748f581c8b3384f42a1fbe18aea5c821672 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Feb 2026 15:26:09 -0600 Subject: [PATCH 063/161] Make intake subsystem dependent upon PneumaticHub being detected. --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 9ee248e..b265b3d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -104,7 +104,6 @@ public RobotContainer() { m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_gyro); m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); - m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); // Init pneumatics system and subsystems that rely upon it. m_pneumaticHub = getSubsystem(PneumaticHubWrapper.class); @@ -115,13 +114,13 @@ public RobotContainer() { PneumaticsConstants.kMaxPneumaticsPressure); m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); - - // TODO: If intake ends up using pneumatics, move its construction here too. + m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); } else { - // If there are no pneumatics, there's no climb. + // If there are no pneumatics, there's no climb or intake. m_climbL1Subsystem = Optional.empty(); + m_intakeSubsystem = Optional.empty(); } // Init Auto From 31a2547879a199234ec54564f3202a8fc854cb03 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 14 Feb 2026 15:38:30 -0600 Subject: [PATCH 064/161] Made a HubUtils class for hub related calculations and added path visulization on the field 2d. --- .../{AutoStatistics.txt => Notes.txt} | 7 ++- .../src/main/java/frc/robot/Constants.java | 7 +++ .../main/java/frc/robot/RobotContainer.java | 14 +++++- .../java/frc/robot/commands/AimAtHub.java | 19 +------- .../main/java/frc/robot/utils/HubUtils.java | 43 +++++++++++++++++++ .../main/java/frc/robot/utils/PoseDiff.java | 14 ++++++ 6 files changed, 84 insertions(+), 20 deletions(-) rename 2026-Rebuilt/{AutoStatistics.txt => Notes.txt} (80%) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/HubUtils.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/PoseDiff.java diff --git a/2026-Rebuilt/AutoStatistics.txt b/2026-Rebuilt/Notes.txt similarity index 80% rename from 2026-Rebuilt/AutoStatistics.txt rename to 2026-Rebuilt/Notes.txt index 5d40e72..1b43cbe 100644 --- a/2026-Rebuilt/AutoStatistics.txt +++ b/2026-Rebuilt/Notes.txt @@ -11,4 +11,9 @@ Pos Off: 8 inch Test 3: Auto: SmoothTurnReverseS Rotation Off: 0 degrees (essentially) -Pos Off: 8 inch \ No newline at end of file +Pos Off: 8 inch + + +Pose for distance testing: +X: 1.52 +Y: 4.26 \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index f97f055..abb8e19 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -36,6 +36,8 @@ import com.pathplanner.lib.config.ModuleConfig; import com.pathplanner.lib.config.RobotConfig; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.system.plant.DCMotor; /** @@ -47,6 +49,11 @@ * constants are needed, to reduce verbosity. */ public final class Constants { + public static class FieldConstants { + public static final Pose2d kBlueHubCenter = new Pose2d(4.607, 4.035, new Rotation2d()); + public static final Pose2d kRedHubCenter = new Pose2d(); + } + public static class AutoConstants { public static final double kMaxDriveVelocityMPS = 40.0; // true max speed of the robot mps public static final double kWheelCOF = 1.0; // no data for this, bsed it diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 27ff8f3..2b472e0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -13,6 +13,7 @@ import com.pathplanner.lib.auto.NamedCommands; import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.util.PathPlannerLogging; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -52,6 +53,7 @@ import frc.robot.subsystems.ClimbL1Subsystem; import frc.robot.subsystems.LimelightSubsystem; import frc.robot.utils.AutoCommands; +import frc.robot.utils.HubUtils; /** * This class is where the bulk of the robot should be declared. Since Command-based is a @@ -93,8 +95,8 @@ public class RobotContainer { PathConstraints m_constraints = new PathConstraints( 1.0, 1.0, - (1/2) * Math.PI, // 90 degrees/s - (1/2) * Math.PI + (1/2) * Math.PI, + 1 * Math.PI ); // The constraints for this path. // Smartdashboard Objects @@ -226,6 +228,11 @@ private void configureAutos() { // Add to dashboard SmartDashboard.putData("Auto Chooser", m_autoChooser); + + // Field wigit update + PathPlannerLogging.setLogActivePathCallback((poses) -> { + m_field.getObject("path").setPoses(poses); + }); } private void configureDefaultCommands() { @@ -286,6 +293,8 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Target Rotation", 0); SmartDashboard.putNumber("Target Angle Diff Abs", 0); SmartDashboard.putNumber("Rotation Speed", 0); + + SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); } // This function is called every 20mS. @@ -300,6 +309,7 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Pose Theta (Degrees)", estimatedPos.getRotation().getDegrees()); SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); + SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); } // Drive subsystem diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java index 067d269..f67d00d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java @@ -3,12 +3,11 @@ import java.util.function.BooleanSupplier; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.subsystems.DriveSubsystem; - +import frc.robot.utils.HubUtils; /** An example command that uses an example subsystem. */ public class AimAtHub extends Command { private final DriveSubsystem m_driveSubsystem; @@ -16,9 +15,6 @@ public class AimAtHub extends Command { private final double m_maxSpeed; private final BooleanSupplier m_isRed; - private final Pose2d m_BlueCenter = new Pose2d(4.607, 4.035, new Rotation2d()); - private final Pose2d m_RedCenter = new Pose2d(); - /** * Creates a new AimAtHub. * @@ -40,18 +36,7 @@ public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator po // Called when the command is initially scheduled. @Override public void initialize() { - Pose2d targetPose; - if (m_isRed.getAsBoolean()) { - targetPose = m_RedCenter; - } else { - targetPose = m_BlueCenter; - } - - Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - double dY = targetPose.getY() - currentPose.getY(); - double dX = targetPose.getX() - currentPose.getX(); - - Rotation2d targetRotation = new Rotation2d(Math.atan2(dY, dX)); + Rotation2d targetRotation = HubUtils.getRobotToHubAngle(m_poseEstimator, m_isRed); RotateToRotation2D aimCommand = new RotateToRotation2D( m_driveSubsystem, m_poseEstimator, diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/HubUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/HubUtils.java new file mode 100644 index 0000000..2799b72 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/HubUtils.java @@ -0,0 +1,43 @@ +package frc.robot.utils; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import frc.robot.Constants.FieldConstants; + +import java.util.function.BooleanSupplier; + +public class HubUtils { + private static Pose2d getHubPose(BooleanSupplier isRedSup) { + Boolean isRed = isRedSup.getAsBoolean(); + if (isRed == true) { + return FieldConstants.kRedHubCenter; + } else { + return FieldConstants.kBlueHubCenter; + } + } + + // Returns the rotation the robot needs to face, field relative, to be looking at the hub. + public static Rotation2d getRobotToHubAngle(DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) { + Pose2d currentPose = poseEstimator.getEstimatedPosition(); + Pose2d hubPose = getHubPose(isRed); + + PoseDiff dPose = new PoseDiff(currentPose, hubPose); + + Rotation2d targetRotation = new Rotation2d(Math.atan2(dPose.y, dPose.x)); + return targetRotation; + } + + // Returns the distance to your team hub in meters. + public static Double getHubDistance(DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) { + Pose2d currentPose = poseEstimator.getEstimatedPosition(); + Pose2d hubPose = getHubPose(isRed); + + PoseDiff length = new PoseDiff(currentPose, hubPose); + + Double lenSq = Math.pow(length.x, 2) + Math.pow(length.y, 2); + Double len = Math.sqrt(lenSq); + + return len; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PoseDiff.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PoseDiff.java new file mode 100644 index 0000000..db1750a --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PoseDiff.java @@ -0,0 +1,14 @@ +package frc.robot.utils; + +import edu.wpi.first.math.geometry.Pose2d; + +public class PoseDiff { + public final double x; + public final double y; + + // pose2 - pose 1 + public PoseDiff(Pose2d pose1, Pose2d pose2) { + this.x = pose2.getX() - pose1.getX(); + this.y = pose2.getY() - pose1.getY(); + } +} \ No newline at end of file From d6f5956de50118f29c54d6c5caf9f7254fb34833 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Mon, 16 Feb 2026 18:50:41 -0600 Subject: [PATCH 065/161] Fleshed out intake subsystem. --- .../src/main/java/frc/robot/Constants.java | 8 ++-- .../robot/subsystems/ClimbL1Subsystem.java | 4 +- .../frc/robot/subsystems/IntakeSubsystem.java | 48 ++++++++++++++----- 3 files changed, 42 insertions(+), 18 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 51432e4..5c23fdd 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -27,7 +27,7 @@ // // Current Solenoid Channels: // -// 0 - Intake retract (extend is passive state via spring) +// 0 - Intake retract // 1 - Climb L1 Left // 2 - Climb L1 Right @@ -37,6 +37,7 @@ import com.pathplanner.lib.config.RobotConfig; import edu.wpi.first.math.system.plant.DCMotor; +import edu.wpi.first.wpilibj.PneumaticsModuleType; /** * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean @@ -77,6 +78,7 @@ public static class AutoConstants { } public static class PneumaticsConstants { + public static final PneumaticsModuleType kHubType = PneumaticsModuleType.REVPH; public static final int kPneumaticsHubCANID = 1; public static final double kMinPneumaticsPressure = 80.0; public static final double kMaxPneumaticsPressure = 120.0; @@ -134,13 +136,11 @@ public static class DrivetrainConstants { public static class IntakeConstants { public static int kIntakeMotorCANID = 30; - public static int kSolenoidChannel = 0; - // Raw intake motor speed in range [-1.0,1.0] public static double kIntakeMotorSpeed = 0.3; // Solenoid states required to extend and retract the intake mechanism. - public static int kIntakeSolenoid = 1; + public static int kIntakeSolenoid = 0; public static boolean kIntakeExtend = true; public static boolean kIntakeRetract = !kIntakeExtend; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java index 895e854..89c4865 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -22,10 +22,10 @@ public ClimbL1Subsystem() { // if underlying hardware is not present and, hence, allow our Optional system to // work. m_LeftSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, - PneumaticsModuleType.REVPH, + PneumaticsConstants.kHubType, ClimbL1Constants.kLeftSolenoidChannel); m_RightSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, - PneumaticsModuleType.REVPH, + PneumaticsConstants.kHubType, ClimbL1Constants.kLeftSolenoidChannel); SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index 6d4036a..dc749bd 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -5,44 +5,68 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; +import edu.wpi.first.wpilibj.Solenoid; +import com.ctre.phoenix6.hardware.TalonFX; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.Constants.IntakeConstants; +import frc.robot.Constants.PneumaticsConstants; public class IntakeSubsystem extends SubsystemBase { + private TalonFX m_motorIntake; + private Solenoid m_solenoid; + private boolean m_motorRunning = false; + private boolean m_Extended = false; + /** Creates a new IntakeSubsystem. */ - public IntakeSubsystem() { - // TODO: write this + public IntakeSubsystem() throws Exception { + m_motorIntake = new TalonFX(IntakeConstants.kIntakeMotorCANID); + if(!m_motorIntake.isConnected()) + { + throw new Exception("Intake motor is not connected!"); + } + + m_solenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsConstants.kHubType, + IntakeConstants.kIntakeSolenoid); + + SmartDashboard.putBoolean("Intake Extended", m_Extended); + SmartDashboard.putBoolean("Intake Running", m_motorRunning); } // Spins the shaft on the intake that will move fuel into the robot. public void start() { - // TODO: implement start + m_motorIntake.set(IntakeConstants.kIntakeMotorSpeed); + m_motorRunning = true; + SmartDashboard.putBoolean("Intake Running", m_motorRunning); } // Stops spinning the intake shaft. public void stop() { - // TODO: implement stop - - // Extends the intake mechanism over the bumpers and outside of the robot. + m_motorIntake.set(0.0); + m_motorRunning = false; + SmartDashboard.putBoolean("Intake Running", m_motorRunning); } public void extend() { - // TODO: implement extend + m_solenoid.set(IntakeConstants.kIntakeExtend); + m_Extended = true; + SmartDashboard.putBoolean("Intake Extended", m_Extended); } // Retracts the intake mechanism over the bumpers and inside of the robot. public void retract() { - // TODO: implement retract + m_solenoid.set(IntakeConstants.kIntakeRetract); + m_Extended = false; + SmartDashboard.putBoolean("Intake Extended", m_Extended); } // Returns true if the intake shaft is spinning. public boolean isIntakeStarted() { - // TODO: implement isIntakeStarted - return false; + return m_motorRunning; } // Returns true if the intake is extended outside of the frame perimiter. public boolean isIntakeExtended() { - // TODO: implement isIntakeExtended - return false; + return m_Extended; } @Override From 868c44b855456cf7993b1b87475397ac9f57969c Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 16 Feb 2026 20:09:50 -0600 Subject: [PATCH 066/161] Fix optional handling for PneumaticHub and launcher subsystems We now read the PneumaticHub firmware version to determine whether or not it's present. If it's 0, we assume the device isn't there. In the launcher subsystem, the SmartDashboard update code in periodic() was still being called even when the motors were not present and this was causing RioLog errors. --- .../main/java/frc/robot/subsystems/LauncherSubsystem.java | 5 ++++- .../src/main/java/frc/robot/utils/PneumaticHubWrapper.java | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index e3021ba..216fd2e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -30,6 +30,7 @@ public class LauncherSubsystem extends SubsystemBase { private double m_targetSpeedrpm = 0.0; private boolean m_liftRunning = false; private int m_tickCount = 0; + private boolean m_configValid = false; private TalonFX m_motorLeader; private TalonFX m_motorFollower; @@ -115,7 +116,9 @@ public LauncherSubsystem() throws Exception { MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); // Configure the fuel sensor. + // TODO: Add this. + m_configValid = true; } // @@ -192,7 +195,7 @@ public void periodic() { // This method will be called once per scheduler run m_tickCount++; - if((m_tickCount % LauncherConstants.kTicksPerUpdate) == 0) + if(m_configValid && ((m_tickCount % LauncherConstants.kTicksPerUpdate) == 0)) { double speedRPS = m_motorLeader.getVelocity().getValueAsDouble(); SmartDashboard.putNumber("Launcher RPM", speedRPS * 60.0); diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java index 40a579f..55b7e96 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java @@ -4,8 +4,9 @@ // package frc.robot.utils; -import edu.wpi.first.hal.REVPHFaults; +import edu.wpi.first.hal.REVPHStickyFaults; import edu.wpi.first.wpilibj.PneumaticHub; +import edu.wpi.first.hal.REVPHVersion; public class PneumaticHubWrapper extends PneumaticHub { private PneumaticHub m_Hub; @@ -32,8 +33,8 @@ public PneumaticHubWrapper(int module) throws Exception { public boolean isAvailable() { - REVPHFaults Faults = m_Hub.getFaults(); + REVPHVersion Version = m_Hub.getVersion(); - return !(Faults.CanWarning || Faults.HardwareFault); + return (Version.firmwareMajor == 0) ? false : true; } } From 170daedc4b7e77182762c9b71040977b1e4a661b Mon Sep 17 00:00:00 2001 From: Recoil Robotics <32313507+dawilson9@users.noreply.github.com> Date: Tue, 17 Feb 2026 20:44:22 -0600 Subject: [PATCH 067/161] Some auto planning + Dead reckoning over bump testing --- .../deploy/pathplanner/paths/GatherS2.path | 54 +++++++++++++++ .../deploy/pathplanner/paths/GatherS4.path | 54 +++++++++++++++ .../src/main/deploy/pathplanner/settings.json | 2 +- .../main/java/frc/robot/RobotContainer.java | 11 ++++ .../robot/commands/ArcadeDriveCommand.java | 4 +- .../frc/robot/commands/DeadreckonForward.java | 65 +++++++++++++++++++ .../frc/robot/subsystems/DriveSubsystem.java | 4 ++ 7 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS2.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS4.path create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS2.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS2.path new file mode 100644 index 0000000..86b39f4 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS2.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 6.607166666666667, + "y": 5.37224358974359 + }, + "prevControl": null, + "nextControl": { + "x": 8.025807692307692, + "y": 5.37224358974359 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 8.049, + "y": 4.093141025641025 + }, + "prevControl": { + "x": 8.025743589743588, + "y": 5.37224358974359 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": "Gather", + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS4.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS4.path new file mode 100644 index 0000000..2781161 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherS4.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 8.049, + "y": 4.093 + }, + "prevControl": null, + "nextControl": { + "x": 7.735102564102567, + "y": 4.3489615384615385 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 5.455974358974361, + "y": 5.395499999999999 + }, + "prevControl": { + "x": 5.979243589743592, + "y": 5.37224358974359 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": "Gather", + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json index 9479112..f9f06f1 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json @@ -3,7 +3,7 @@ "robotLength": 0.9, "holonomicMode": false, "pathFolders": [ - "New Folder" + "Gather" ], "autoFolders": [], "defaultMaxVel": 1.0, diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 2b472e0..2098a3f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -40,6 +40,7 @@ import frc.robot.Constants.OperatorConstants; import frc.robot.Constants.PneumaticsConstants; import frc.robot.commands.AimAtHub; +import frc.robot.commands.DeadreckonForward; import frc.robot.commands.DriveForwardFromPos; import frc.robot.commands.POTFtoPoint; import frc.robot.commands.RotateToRotation2D; @@ -184,6 +185,16 @@ private void configureAutos() { ); // Custom Autos + m_autoChooser.addOption( + "Deadreckon 3m at 3.0", + new DeadreckonForward(m_driveSubsystem.get(), 3, 4.0) + ); + + m_autoChooser.addOption( + "Deadreckon -3m at -1.0", + new DeadreckonForward(m_driveSubsystem.get(), -3, -1.0) + ); + m_autoChooser.addOption( "On-Fly Forward 2m", new DriveForwardFromPos(m_PoseEstimator, 2) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java index 65eb3bd..7bcc2a4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java @@ -37,8 +37,8 @@ public void execute() { // Note: We negate both axis values so that pushing the joystick forwards // (which makes the readin more negative) increases the speed and twisting clockwise // turns the robot clockwise. - double speedInput = -m_driveController.getRightY(); - double turnInput = m_driveController.getLeftX(); + double speedInput = -m_driveController.getLeftY(); + double turnInput = m_driveController.getRightX(); // Set the deadband if (Math.abs(speedInput) < OperatorConstants.kDriverControllerDeadband) { diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java new file mode 100644 index 0000000..018add1 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java @@ -0,0 +1,65 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class DeadreckonForward extends Command { + private final DriveSubsystem m_driveSubsystem; + private final double m_targetDistance; + private final double m_speed; + + private double m_startDistance; + + /** + * Creates a new DriveForward2mFromPos. + * + * @param subsystem The subsystem used by this command. + */ + public DeadreckonForward(DriveSubsystem driveSubsystem, double targetDistance, double speed) + { + m_driveSubsystem = driveSubsystem; + m_targetDistance = targetDistance; + m_speed = speed; + + addRequirements(m_driveSubsystem); + } + + private double avrgDistances() { + double leftPos = m_driveSubsystem.getMotorPositionMeters(true); + double rightPos = m_driveSubsystem.getMotorPositionMeters(false); + return (leftPos + rightPos)/2; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_startDistance = avrgDistances(); + m_driveSubsystem.setDifferentialSpeeds(m_speed, m_speed); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + m_driveSubsystem.setDifferentialSpeeds(m_speed, m_speed); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + m_driveSubsystem.setDifferentialSpeeds(0, 0); + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + double distanceDiff = avrgDistances() - m_startDistance; + System.out.println(String.valueOf(distanceDiff) + " --> " + String.valueOf(m_targetDistance) + " at " + String.valueOf(m_speed)); + + if (distanceDiff >= m_targetDistance) { + return true; + } else { + return false; + } + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 918a91c..7b527cf 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -7,6 +7,8 @@ package frc.robot.subsystems; import static edu.wpi.first.units.Units.Volts; +import java.io.Console; + import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; @@ -216,6 +218,8 @@ public double ConvertMetersToRotations(double meters) { // This sets the differential speeds based on a desired MPS speed. public void setDifferentialSpeeds(double leftSpeedMPS, double rightSpeedMPS) { + //System.out.println("🙀 " + String.valueOf(leftSpeedMPS) + ", " + String.valueOf(rightSpeedMPS)); + SmartDashboard.putNumber("Left Target (MPS)", leftSpeedMPS); SmartDashboard.putNumber("Right Target (MPS)", rightSpeedMPS); From 2e4e8669f1c01dc41a0afa4f17553200e139eeb1 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <32313507+dawilson9@users.noreply.github.com> Date: Fri, 20 Feb 2026 18:38:03 -0600 Subject: [PATCH 068/161] Changed max speed back to 3.0 DMK: Changed max speed back to 3.0 to match Choice description. --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 2098a3f..1f432ce 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -187,7 +187,7 @@ private void configureAutos() { // Custom Autos m_autoChooser.addOption( "Deadreckon 3m at 3.0", - new DeadreckonForward(m_driveSubsystem.get(), 3, 4.0) + new DeadreckonForward(m_driveSubsystem.get(), 3, 3.0) ); m_autoChooser.addOption( From a86c87ce0ec8c8b6833c9f9147a34cf90ec85f9b Mon Sep 17 00:00:00 2001 From: Recoil Robotics <32313507+dawilson9@users.noreply.github.com> Date: Fri, 20 Feb 2026 19:55:22 -0600 Subject: [PATCH 069/161] Remove debug print DMK: Removed a debug print now that we've fixed the problem. --- .../src/main/java/frc/robot/commands/DeadreckonForward.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java index 018add1..e3562b4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java @@ -54,7 +54,7 @@ public void end(boolean interrupted) { @Override public boolean isFinished() { double distanceDiff = avrgDistances() - m_startDistance; - System.out.println(String.valueOf(distanceDiff) + " --> " + String.valueOf(m_targetDistance) + " at " + String.valueOf(m_speed)); + // System.out.println(String.valueOf(distanceDiff) + " --> " + String.valueOf(m_targetDistance) + " at " + String.valueOf(m_speed)); if (distanceDiff >= m_targetDistance) { return true; From 2d21372228cd8a4031cb2435d48f40bcfdcbbe26 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 21 Feb 2026 11:21:31 -0600 Subject: [PATCH 070/161] Implement and bind all trivial commands based on 2026 Robot User Manual --- .../src/main/java/frc/robot/Constants.java | 2 + .../main/java/frc/robot/RobotContainer.java | 52 ++++++++++++++----- .../robot/commands/CancelDriveCommand.java | 50 ++++++++++++++++++ .../robot/commands/ExtendIntakeCommand.java | 52 +++++++++++++++++++ .../frc/robot/commands/LowerClimbCommand.java | 51 ++++++++++++++++++ .../frc/robot/commands/RaiseClimbCommand.java | 51 ++++++++++++++++++ .../robot/commands/RetractIntakeCommand.java | 52 +++++++++++++++++++ .../robot/commands/StartIntakeCommand.java | 52 +++++++++++++++++++ .../frc/robot/commands/StopIntakeCommand.java | 52 +++++++++++++++++++ .../robot/commands/StopLauncherCommand.java | 52 +++++++++++++++++++ .../robot/subsystems/ClimbL1Subsystem.java | 1 - 11 files changed, 453 insertions(+), 14 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ExtendIntakeCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/LowerClimbCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/RaiseClimbCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/RetractIntakeCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StartIntakeCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StopIntakeCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 5c23fdd..7e12316 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -89,6 +89,8 @@ public static class PneumaticsConstants { public static class OperatorConstants { public static final int kDriverControllerPort = 0; public static final double kDriverControllerDeadband = 0.02; // Exclusive + + public static final int kOperatorControllerPort = 1; } public static class DrivetrainConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index b265b3d..e050c02 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -8,7 +8,6 @@ import java.util.Optional; import com.ctre.phoenix6.hardware.TalonFX; -import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.commands.PathPlannerAuto; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -31,7 +30,6 @@ import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; import frc.robot.Constants.PneumaticsConstants; -import frc.robot.commands.DriveForwardFromPos; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -42,6 +40,7 @@ import frc.robot.subsystems.LimelightSubsystem; import frc.robot.utils.AutoCommands; import frc.robot.utils.PneumaticHubWrapper; +import frc.robot.commands.*; /** * This class is where the bulk of the robot should be declared. Since Command-based is a @@ -62,6 +61,8 @@ public class RobotContainer { // Replace with CommandPS4Controller or CommandJoystick if needed private final CommandXboxController m_driverController = new CommandXboxController(OperatorConstants.kDriverControllerPort); + private final CommandXboxController m_operatorController = + new CommandXboxController(OperatorConstants.kOperatorControllerPort); private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.kTrackWidthMeters); @@ -188,20 +189,45 @@ private void configureDefaultCommands() { * joysticks}. */ private void configureBindings() { - // SmartDashboard.putBoolean("Example Subsystem", m_exampleSubsystem.isPresent()); + // Set dashboard indicators showing which subsystems are actually present. + SmartDashboard.putBoolean("Drive Subsystem", m_driveSubsystem.isPresent()); + SmartDashboard.putBoolean("Intake Subsystem", m_intakeSubsystem.isPresent()); + SmartDashboard.putBoolean("ClimbL1 Subsystem", m_climbL1Subsystem.isPresent()); + SmartDashboard.putBoolean("Launcher Subsystem", m_launcherSubsystem.isPresent()); + SmartDashboard.putBoolean("IndexerBulk Subsystem", m_indexerBulkSubsystem.isPresent()); + + // Note that some of our command bindings require that multiple subsystems + // are present. We only enable a binding if all its requirements are met! + // The command bindings here are implemented based on the 2026 Robot User Manual + // found at https://docs.google.com/document/d/1VfiFjz9N2ol3pl7xUKzU2Jam5AbL1xXlS_cHFYYanFM + + // + // Operator Controls + // + if (m_intakeSubsystem.isPresent()) + { + m_operatorController.rightBumper().onTrue(new StartIntakeCommand(m_intakeSubsystem.get())); + m_operatorController.leftBumper().onTrue(new StopIntakeCommand(m_intakeSubsystem.get())); + m_operatorController.povUp().onTrue(new ExtendIntakeCommand(m_intakeSubsystem.get())); + m_operatorController.povDown().onTrue(new RetractIntakeCommand(m_intakeSubsystem.get())); + } - // if (m_exampleSubsystem.isPresent()) - // { - // ExampleSubsystem exampleSubsystem = m_exampleSubsystem.get(); + if (m_climbL1Subsystem.isPresent()) + { + // Operator's manual climb overrides. + m_operatorController.start().onTrue(new RaiseClimbCommand(m_climbL1Subsystem.get())); + m_operatorController.back().onTrue(new LowerClimbCommand(m_climbL1Subsystem.get())); + } - // // Schedule `ExampleCommand` when `exampleCondition` changes to `true` - // new Trigger(exampleSubsystem::exampleCondition) - // .onTrue(new ExampleCommand(exampleSubsystem)); + if (m_launcherSubsystem.isPresent()) + { + // Operator's manual climb overrides. + m_operatorController.b().onTrue(new StopLauncherCommand(m_launcherSubsystem.get())); + + // TODO: Need composite command for manual shoot (spin up flywheel, wait for target, start lift motor) + } - // // Schedule `exampleMethodCommand` when the Xbox controller's B button is pressed, - // // cancelling on release. - // m_driverController.b().whileTrue(exampleSubsystem.exampleMethodCommand()); - // } + // TODO: Write and bind composite commands for driver controls. } // Populate the SmartDashboard on robot init. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java new file mode 100644 index 0000000..b38f1ac --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java @@ -0,0 +1,50 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.DriveSubsystem; + +/** + * A simple command that merely stops any command currently using the + * robot drivetrain. + **/ +public class CancelDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + + /** + * Creates a new CancelDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public CancelDriveCommand(DriveSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ExtendIntakeCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ExtendIntakeCommand.java new file mode 100644 index 0000000..b8a9173 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ExtendIntakeCommand.java @@ -0,0 +1,52 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IntakeSubsystem; + +/** + * + * Extend the intake mechanism. + * + **/ +public class ExtendIntakeCommand extends Command { + private final IntakeSubsystem m_subsystem; + + /** + * Creates a new ExtendIntakeCommand. + * + * @param subsystem The subsystem used by this command. + */ + public ExtendIntakeCommand(IntakeSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This simple command extends the intake mechanism. + m_subsystem.extend(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/LowerClimbCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/LowerClimbCommand.java new file mode 100644 index 0000000..da61a32 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/LowerClimbCommand.java @@ -0,0 +1,51 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.ClimbL1Subsystem; + +/** + * + * Lower the climb L1 mechanism hooks. + * + **/ +public class LowerClimbCommand extends Command { + private final ClimbL1Subsystem m_subsystem; + + /** + * Creates a new LowerClimbCommand. + * + * @param subsystem The subsystem used by this command. + */ + public LowerClimbCommand(ClimbL1Subsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.lowerArms(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RaiseClimbCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RaiseClimbCommand.java new file mode 100644 index 0000000..a5efa76 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RaiseClimbCommand.java @@ -0,0 +1,51 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.ClimbL1Subsystem; + +/** + * + * Raise the climb L1 mechanism hooks. + * + **/ +public class RaiseClimbCommand extends Command { + private final ClimbL1Subsystem m_subsystem; + + /** + * Creates a new RaiseClimbCommand. + * + * @param subsystem The subsystem used by this command. + */ + public RaiseClimbCommand(ClimbL1Subsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.raiseArms(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RetractIntakeCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RetractIntakeCommand.java new file mode 100644 index 0000000..65c3f1b --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RetractIntakeCommand.java @@ -0,0 +1,52 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IntakeSubsystem; + +/** + * + * Retract the intake mechanism. + * + **/ +public class RetractIntakeCommand extends Command { + private final IntakeSubsystem m_subsystem; + + /** + * Creates a new RetractIntakeCommand. + * + * @param subsystem The subsystem used by this command. + */ + public RetractIntakeCommand(IntakeSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This simple command retracts the intake mechanism. + m_subsystem.retract(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartIntakeCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartIntakeCommand.java new file mode 100644 index 0000000..9f233e1 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartIntakeCommand.java @@ -0,0 +1,52 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IntakeSubsystem; + +/** + * + * Start the intake mechanism roller motor. + * + **/ +public class StartIntakeCommand extends Command { + private final IntakeSubsystem m_subsystem; + + /** + * Creates a new StartIntakeCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StartIntakeCommand(IntakeSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This simple command turns on the intake motor at a fixed speed. + m_subsystem.start(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopIntakeCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopIntakeCommand.java new file mode 100644 index 0000000..7213f0c --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopIntakeCommand.java @@ -0,0 +1,52 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IntakeSubsystem; + +/** + * + * Stop the intake mechanism roller motor. + * + **/ +public class StopIntakeCommand extends Command { + private final IntakeSubsystem m_subsystem; + + /** + * Creates a new StopIntakeCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StopIntakeCommand(IntakeSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This simple command turns off the intake motor. + m_subsystem.stop(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java new file mode 100644 index 0000000..b68bbf1 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java @@ -0,0 +1,52 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Stop the launcher lift motor and spin down the flywheel. + * + **/ +public class StopLauncherCommand extends Command { + private final LauncherSubsystem m_subsystem; + + /** + * Creates a new StopLauncherCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StopLauncherCommand(LauncherSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.stopLift(); + m_subsystem.setTargetSpeedrpm(0.0); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end immediately. + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java index 89c4865..9944bf2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -5,7 +5,6 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj.PneumaticsModuleType; import edu.wpi.first.wpilibj.Solenoid; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.Constants.ClimbL1Constants; From 1e4bdb4715ea715ae4dda006762979af1928e039 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 21 Feb 2026 11:22:44 -0600 Subject: [PATCH 071/161] Remove an import for an unused class. --- .../src/main/java/frc/robot/utils/PneumaticHubWrapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java index 55b7e96..5292060 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java @@ -4,7 +4,6 @@ // package frc.robot.utils; -import edu.wpi.first.hal.REVPHStickyFaults; import edu.wpi.first.wpilibj.PneumaticHub; import edu.wpi.first.hal.REVPHVersion; From e39af5764649c1aad61fe510c726f3f25a3f7342 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 21 Feb 2026 12:13:53 -0600 Subject: [PATCH 072/161] Add test command to start flywheel at a fixed rate. --- .../src/main/java/frc/robot/Constants.java | 5 +- .../main/java/frc/robot/RobotContainer.java | 9 ++- .../robot/commands/StartFlywheelCommand.java | 63 +++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 7e12316..786f129 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -89,7 +89,7 @@ public static class PneumaticsConstants { public static class OperatorConstants { public static final int kDriverControllerPort = 0; public static final double kDriverControllerDeadband = 0.02; // Exclusive - + public static final int kOperatorControllerPort = 1; } @@ -185,6 +185,9 @@ public static class LauncherConstants { // Frequency at which we send current launcher speed back to the driver station. public static final int kTicksPerUpdate = 10; + + public static final double kFixedTestSpeed = 3000.0; + public static final double kFlywheelToleranceRPM = 200.0; } public static class IndexerBulkConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index e050c02..91b7b1e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -27,9 +27,6 @@ import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import edu.wpi.first.wpilibj.PneumaticHub; -import frc.robot.Constants.DrivetrainConstants; -import frc.robot.Constants.OperatorConstants; -import frc.robot.Constants.PneumaticsConstants; import frc.robot.factorys.DriveSubsystemFactory; import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; @@ -41,6 +38,7 @@ import frc.robot.utils.AutoCommands; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; +import frc.robot.Constants.*; /** * This class is where the bulk of the robot should be declared. Since Command-based is a @@ -224,6 +222,11 @@ private void configureBindings() { // Operator's manual climb overrides. m_operatorController.b().onTrue(new StopLauncherCommand(m_launcherSubsystem.get())); + // FOR TEST PURPOSES ONLY! + m_operatorController.a().onTrue(new StartFlywheelCommand(m_launcherSubsystem.get(), + LauncherConstants.kFixedTestSpeed, + LauncherConstants.kFlywheelToleranceRPM)); + // TODO: Need composite command for manual shoot (spin up flywheel, wait for target, start lift motor) } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java new file mode 100644 index 0000000..25fa0ac --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java @@ -0,0 +1,63 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Stop the launcher lift motor and spin down the flywheel. + * + **/ +public class StartFlywheelCommand extends Command { + private final LauncherSubsystem m_subsystem; + private final double m_targetSpeedrpm; + private final double m_Tolerancerpm; + + /** + * Creates a new StartFlywheelCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StartFlywheelCommand(LauncherSubsystem subsystem, double TargetSpeedrpm, double Tolerancerpm) + { + m_subsystem = subsystem; + m_targetSpeedrpm = TargetSpeedrpm; + m_Tolerancerpm = Tolerancerpm; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.setTargetSpeedrpm(m_targetSpeedrpm); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end when the flywheel speed is within the tolerance of the target. + double currentSpeed = m_subsystem.getCurrentSpeedrpm(); + if (Math.abs(currentSpeed - m_targetSpeedrpm) <= m_Tolerancerpm) + { + return true; + } + else + { + return false; + } + } +} From 183abdf7f6abc94f837807307d986304da712fdc Mon Sep 17 00:00:00 2001 From: Recoil Robotics <32313507+dawilson9@users.noreply.github.com> Date: Sat, 21 Feb 2026 12:16:37 -0600 Subject: [PATCH 073/161] Made documentation for deadreckon clearer. --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 1f432ce..7f91203 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -186,7 +186,7 @@ private void configureAutos() { // Custom Autos m_autoChooser.addOption( - "Deadreckon 3m at 3.0", + "Deadreckon 3m at 3.0 mps", new DeadreckonForward(m_driveSubsystem.get(), 3, 3.0) ); From d56ded3738091fdea7826962a57ad9c7597a5d6e Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Feb 2026 13:05:59 -0600 Subject: [PATCH 074/161] Added a no drive command, and setup the launcher for a test --- .../src/main/java/frc/robot/Constants.java | 2 +- .../main/java/frc/robot/RobotContainer.java | 3 +- .../frc/robot/commands/NoDriveCommand.java | 53 +++++++++++++++++++ .../frc/robot/subsystems/DriveSubsystem.java | 2 + .../robot/subsystems/LauncherSubsystem.java | 18 +++---- .../robot/subsystems/LimelightSubsystem.java | 3 ++ 6 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 786f129..553f1d0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -181,7 +181,7 @@ public static class LauncherConstants { // Set to false if we drive the lead launcher flywheel motor clockwise to operate // correctly, or true to drive it counterclockwise. - public static final boolean kLauncherMotorForwardIsCCW = true; + public static final boolean kLauncherMotorForwardIsCCW = false; // Frequency at which we send current launcher speed back to the driver station. public static final int kTicksPerUpdate = 10; diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 91b7b1e..8c2dadc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -219,7 +219,7 @@ private void configureBindings() { if (m_launcherSubsystem.isPresent()) { - // Operator's manual climb overrides. + // Operator's manual launcher override. m_operatorController.b().onTrue(new StopLauncherCommand(m_launcherSubsystem.get())); // FOR TEST PURPOSES ONLY! @@ -238,6 +238,7 @@ public void InitSmartDashboard() { // Non-Subsystem Specific Stuff SmartDashboard.putData(CommandScheduler.getInstance()); SmartDashboard.putData("Field", m_field); + SmartDashboard.putNumber("mt2 Tag Count", 0.0); } // This function is called every 20mS. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java new file mode 100644 index 0000000..e4f1ff4 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java @@ -0,0 +1,53 @@ +// 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.commands; +import frc.robot.subsystems.DriveSubsystem; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.button.CommandXboxController; + +/** An example command that uses an example subsystem. */ +public class NoDriveCommand extends Command { + private final DriveSubsystem m_subsystem; + + // Doing this because it needs to have a controller for the drive default command. + @SuppressWarnings("unused") + private CommandXboxController m_driveController; + + /** + * Creates a new NoDriveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public NoDriveCommand(DriveSubsystem subsystem, CommandXboxController driveController) { + m_subsystem = subsystem; + m_driveController = driveController; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + m_subsystem.setDifferentialSpeeds( + 0, + 0 + ); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 67ac57b..153364d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -38,6 +38,7 @@ import frc.robot.commands.ArcadeDriveCommandNoPID; import frc.robot.commands.ArcadeFromDashboard; import frc.robot.commands.DifferentialDriveCommand; +import frc.robot.commands.NoDriveCommand; public class DriveSubsystem extends SubsystemBase { private TalonFX m_rightMotor; @@ -106,6 +107,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_driveChooser.addOption("PID Differential", DifferentialDriveCommand.class); m_driveChooser.addOption("NO-PID Arcade", ArcadeDriveCommandNoPID.class); m_driveChooser.addOption("Dashboard PID Arcade", ArcadeFromDashboard.class); + m_driveChooser.addOption("None", NoDriveCommand.class); SmartDashboard.putData("Drive Commands", m_driveChooser); // Init Smartdashboard diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 216fd2e..0fdd3cc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -34,7 +34,7 @@ public class LauncherSubsystem extends SubsystemBase { private TalonFX m_motorLeader; private TalonFX m_motorFollower; - private SparkMax m_motorLift; + //private SparkMax m_motorLift; private final DigitalInput m_Sensor = new DigitalInput(LauncherConstants.kUpperFuelSensorChannel); @@ -46,7 +46,7 @@ public class LauncherSubsystem extends SubsystemBase { * @throws Exception */ public LauncherSubsystem() throws Exception { - m_motorLift = new SparkMax(LauncherConstants.kLauncherLiftMotorCANID, MotorType.kBrushless); + //m_motorLift = new SparkMax(LauncherConstants.kLauncherLiftMotorCANID, MotorType.kBrushless); m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); m_motorFollower = new TalonFX(LauncherConstants.kLauncherFlywheelMotor2CANID); @@ -57,11 +57,11 @@ public LauncherSubsystem() throws Exception { } // Ensure that the lift motor is present. - SparkBase.Faults Faults = m_motorLift.getFaults(); - if(Faults.can || Faults.firmware || Faults.gateDriver) - { - throw new Exception("Lift motor is not present or is reporting a fault!"); - } + // SparkBase.Faults Faults = m_motorLift.getFaults(); + // if(Faults.can || Faults.firmware || Faults.gateDriver) + // { + // throw new Exception("Lift motor is not present or is reporting a fault!"); + // } TalonFXConfiguration configs = new TalonFXConfiguration(); @@ -160,7 +160,7 @@ public double getTargetSpeedrpm() // public void startLift() { - m_motorLift.set(LauncherConstants.kLiftMotorSpeed); + //m_motorLift.set(LauncherConstants.kLiftMotorSpeed); m_liftRunning = true; } @@ -169,7 +169,7 @@ public void startLift() // public void stopLift() { - m_motorLift.set(0.0); + //m_motorLift.set(0.0); m_liftRunning = false; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 4e21387..66e1a17 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -14,6 +14,7 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.numbers.N3; import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; import frc.robot.LimelightHelpers.IMUData; @@ -62,6 +63,8 @@ private void updateOdometry() { if (mt2 == null) { return; } + + SmartDashboard.putNumber("mt2 Tag Count", mt2.tagCount); // if our angular velocity is greater than 720 degrees per second, ignore vision updates if(Math.abs(m_gyro.getRate()) > 720) From 69782c1e750271644a9f1416072cb81b0112fad0 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 21 Feb 2026 13:17:55 -0600 Subject: [PATCH 075/161] Added Start/StopLiftCommand classes --- .../frc/robot/commands/StartLiftCommand.java | 48 +++++++++++++++++++ .../frc/robot/commands/StopLiftCommand.java | 48 +++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java new file mode 100644 index 0000000..0d99ab8 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java @@ -0,0 +1,48 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Stop the launcher lift motor and spin down the flywheel. + * + **/ +public class StartLiftCommand extends Command { + private final LauncherSubsystem m_subsystem; + + /** + * Creates a new StartLiftCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StartLiftCommand(LauncherSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.startLift(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java new file mode 100644 index 0000000..003b5e1 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java @@ -0,0 +1,48 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Stop the launcher lift motor and spin down the flywheel. + * + **/ +public class StopLiftCommand extends Command { + private final LauncherSubsystem m_subsystem; + + /** + * Creates a new StopLiftCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StopLiftCommand(LauncherSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.stopLift(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} From f8af7fd32565013a5cb7df3dd701dfb7a0e75081 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Feb 2026 14:11:43 -0600 Subject: [PATCH 076/161] Made auto configure check if the drivesubystem existed. --- .../main/java/frc/robot/RobotContainer.java | 144 +++++++++--------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 7f91203..f61cc64 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -159,91 +159,93 @@ private static Optional getSubsystem(Class subsystemClass) { return iss; } + // Init Autos (/home/lvuser/deploy/pathplanner/autos) private void configureAutos() { - // Init Autos (/home/lvuser/deploy/pathplanner/autos) - // AutoCommands.getAutoCommands(m_driveSubsystem); + if (m_driveSubsystem.isPresent()) { + // Init Needed values + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + m_autoChooser = new SendableChooser(); + + // Named Commands + NamedCommands.registerCommand("RotateTo-180", new RotateToRotation2D( + driveSubsystem, + m_PoseEstimator, + Rotation2d.fromDegrees(180), + 1 + ) + ); - // // Init Chooser - // m_autoChooser = AutoBuilder.buildAutoChooser(); // Can make a default by giving a string - m_autoChooser = new SendableChooser(); + NamedCommands.registerCommand("AimToHub", new AimAtHub( + driveSubsystem, + m_PoseEstimator, + 2.0, + isRed + ) + ); - // Named Commands - NamedCommands.registerCommand("RotateTo-180", new RotateToRotation2D( - m_driveSubsystem.get(), - m_PoseEstimator, - Rotation2d.fromDegrees(180), - 1 - ) - ); + // Custom Autos + m_autoChooser.addOption( + "Deadreckon 3m at 3.0 mps", + new DeadreckonForward(driveSubsystem, 3, 3.0) + ); - NamedCommands.registerCommand("AimToHub", new AimAtHub( - m_driveSubsystem.get(), - m_PoseEstimator, - 2.0, - isRed - ) - ); + m_autoChooser.addOption( + "Deadreckon -3m at -1.0", + new DeadreckonForward(driveSubsystem, -3, -1.0) + ); - // Custom Autos - m_autoChooser.addOption( - "Deadreckon 3m at 3.0 mps", - new DeadreckonForward(m_driveSubsystem.get(), 3, 3.0) - ); + m_autoChooser.addOption( + "On-Fly Forward 2m", + new DriveForwardFromPos(m_PoseEstimator, 2) + ); - m_autoChooser.addOption( - "Deadreckon -3m at -1.0", - new DeadreckonForward(m_driveSubsystem.get(), -3, -1.0) - ); + m_autoChooser.addOption( + "Rotate to 0", + new RotateToRotation2D( + driveSubsystem, + m_PoseEstimator, + new Rotation2d(0.0), + 1 + ) + ); - m_autoChooser.addOption( - "On-Fly Forward 2m", - new DriveForwardFromPos(m_PoseEstimator, 2) - ); + m_autoChooser.addOption( + "On-The-Fly to (2, 4.837) -90", + new POTFtoPoint( + m_PoseEstimator, + new Pose2d(2, 4.837, Rotation2d.fromDegrees(-90)) + ) + ); - m_autoChooser.addOption( - "Rotate to 0", - new RotateToRotation2D( - m_driveSubsystem.get(), - m_PoseEstimator, - new Rotation2d(0.0), - 1 - ) - ); + // Path Planner Auto's + ArrayList autoNames = AutoCommands.getAutoNames(); + for (String autoName : autoNames) { + PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); + Pose2d startingPose = plannedAuto.getStartingPose(); - m_autoChooser.addOption( - "On-The-Fly to (2, 4.837) -90", - new POTFtoPoint( - m_PoseEstimator, - new Pose2d(2, 4.837, Rotation2d.fromDegrees(-90)) - ) - ); + Command rotateToStartRot = new RotateToRotation2D( + driveSubsystem, + m_PoseEstimator, + startingPose.getRotation(), + 2.0 + ); - // Path Planner Auto's - ArrayList autoNames = AutoCommands.getAutoNames(); - for (String autoName : autoNames) { - PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); - Pose2d startingPose = plannedAuto.getStartingPose(); + Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); + Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); - Command rotateToStartRot = new RotateToRotation2D( - m_driveSubsystem.get(), - m_PoseEstimator, - startingPose.getRotation(), - 2.0 - ); + m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); + } - Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); - Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); + // Add to dashboard + SmartDashboard.putData("Auto Chooser", m_autoChooser); - m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); + // Field wigit update + PathPlannerLogging.setLogActivePathCallback((poses) -> { + m_field.getObject("path").setPoses(poses); + }); + } else { + DriverStation.reportWarning("Drive Subsystem is not present! No Auto's configured.", null); } - - // Add to dashboard - SmartDashboard.putData("Auto Chooser", m_autoChooser); - - // Field wigit update - PathPlannerLogging.setLogActivePathCallback((poses) -> { - m_field.getObject("path").setPoses(poses); - }); } private void configureDefaultCommands() { From 2649829db361d5a0cb2a0069babb31fba8040187 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Feb 2026 15:40:09 -0600 Subject: [PATCH 077/161] Made red hubcenter accurate, and made a TODO --- 2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json | 2 +- 2026-Rebuilt/src/main/java/frc/robot/Constants.java | 2 +- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json index 0c6a2de..465fe26 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json @@ -1 +1 @@ -{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file +{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 9a188ef..3502482 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -52,7 +52,7 @@ public final class Constants { public static class FieldConstants { public static final Pose2d kBlueHubCenter = new Pose2d(4.607, 4.035, new Rotation2d()); - public static final Pose2d kRedHubCenter = new Pose2d(); + public static final Pose2d kRedHubCenter = new Pose2d(11.9284, 4.035, new Rotation2d()); } public static class AutoConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 36d944c..2882810 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -83,7 +83,7 @@ public class RobotContainer { Rotation2d.fromDegrees(0.0), 0, 0, - new Pose2d(0.0, 8.0, new Rotation2d()), + new Pose2d(0.0, 0.0, new Rotation2d()), m_drivetrainError, m_limelightError ); @@ -160,6 +160,7 @@ private static Optional getSubsystem(Class subsystemClass) { } // Init Autos (/home/lvuser/deploy/pathplanner/autos) + // TODO: Check if the new PathPlannerAuto is mirroring the cords when read by the pathfinder. private void configureAutos() { if (m_driveSubsystem.isPresent()) { // Init Needed values From 592caeb7970677c263a2b15f010c80b01cb65764 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 21 Feb 2026 15:49:23 -0600 Subject: [PATCH 078/161] Add command to keep flywheel at correct speed for launching The TrackHubFlywheelCommand monitors the distance to the hub and adjusts the flywheel speed to ensure that we can score from the current position. --- .../commands/TrackHubFlywheelCommand.java | 78 +++++++++++++++++++ .../java/frc/robot/utils/LauncherUtils.java | 70 +++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java new file mode 100644 index 0000000..56e1c37 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java @@ -0,0 +1,78 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +import java.util.function.BooleanSupplier; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import frc.robot.utils.HubUtils; +import frc.robot.utils.LauncherUtils; + +/** + * + * This command, which runs until interrupted, constantly monitors the + * distance between the robot and the hub and updates the launcher + * flywheel target speed to the correct value for the current position. + * The speed is only modified if the distance is within the range where + * it is physically possible for the robot to successfully launch fuel + * into the hub. + * + **/ +public class TrackHubFlywheelCommand extends Command { + private final LauncherSubsystem m_subsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final BooleanSupplier m_isRed; + private double m_targetSpeedrpm = 0.0; + + /** + * Creates a new TrackHubFlywheelCommand. + * + * @param subsystem The subsystem used by this command. + */ + public TrackHubFlywheelCommand(LauncherSubsystem subsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) + { + m_subsystem = subsystem; + m_poseEstimator = poseEstimator; + m_isRed = isRed; + m_targetSpeedrpm = 0.0; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + // Calculate the current distance to the hub. + double Distance = HubUtils.getHubDistance(m_poseEstimator, m_isRed); + + // Determine flywheel speed to target hub from this distance. + double m_targetSpeedrpm = LauncherUtils.getFlywheelSpeed(Distance); + + // Set new flywheel target speed. + m_subsystem.setTargetSpeedrpm(m_targetSpeedrpm); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // This command never ends. It will be interrupted by the scheduler if + // the operator chooses to run another command that requires the launcher + // subsystem. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java new file mode 100644 index 0000000..a24b303 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java @@ -0,0 +1,70 @@ +package frc.robot.utils; + +public class LauncherUtils { + // + // TODO: This table must be filled in either data determined experimentally + // on the final robot. The first column is the distance from the hub center + // and the second is the flywheel RPM required to successfully launch fuel into + // the hub from that distance. Values must be ordered by distance with the lowest + // distance value first. + // + // This array must have at least 3 rows! + // + // The data here is currently completely fabricated just to allow the code to + // be debugged!!!! + // + private static final double[][] m_DistanceToRPM = { + {1.0, 2000.0}, + {2.0, 2400.0}, + {3.0, 3000.0}, + {4.0, 4000.0}, + }; + // + // Given a distance between the robot and the hub, calculate the + // launcher flywheel speed needed to successfully score fuel from + // that distance. + // + public static double getFlywheelSpeed(double Distancem) + { + double target = 0.0; + + // Look for cases where we're outside the range from which we can + // successfully score. If we're too close, return the minimum + // speed. + if (Distancem <= m_DistanceToRPM[0][0]) + { + return m_DistanceToRPM[0][1]; + } + + // Are we too far away from the hub to score? If so, return the + // maximum speed. + if (Distancem >= m_DistanceToRPM[m_DistanceToRPM.length - 1][0]) + { + return m_DistanceToRPM[m_DistanceToRPM.length - 1][1]; + } + + // Only scan the table if the current distance is higher than + // the minimum from which we can score. In cases where we're closer + // than this, return the minimum launcher speed. + if (Distancem > m_DistanceToRPM[0][0]) + { + for (int i = 0; i < (m_DistanceToRPM.length - 1); i++) + { + if((Distancem > m_DistanceToRPM[i][0]) && (Distancem <= m_DistanceToRPM[i+1][0])) + { + // We found the interval containing the requested distance so determine + // the required target speed using linear interpolation. + target = m_DistanceToRPM[i][1] + + (((m_DistanceToRPM[i+1][1] - m_DistanceToRPM[i][1]) / + (m_DistanceToRPM[i+1][0] - m_DistanceToRPM[i][0])) * + (Distancem - m_DistanceToRPM[i][0])); + + return target; + } + } + } + + // We should never get here but, if we do, return the maximum speed. + return m_DistanceToRPM[m_DistanceToRPM.length - 1][1]; + } +} From c013004fc7dbdce39347243bb63e815ccbe9fb56 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 23 Feb 2026 19:21:47 -0600 Subject: [PATCH 079/161] Corrected the cordinate system for red. --- 2026-Rebuilt/.vscode/settings.json | 3 ++- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 8 ++++++++ .../java/frc/robot/commands/TrackHubFlywheelCommand.java | 3 +-- .../main/java/frc/robot/subsystems/DriveSubsystem.java | 5 ++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/2026-Rebuilt/.vscode/settings.json b/2026-Rebuilt/.vscode/settings.json index 5e6ede8..b20429d 100644 --- a/2026-Rebuilt/.vscode/settings.json +++ b/2026-Rebuilt/.vscode/settings.json @@ -57,5 +57,6 @@ "edu.wpi.first.math.**.proto.*", "edu.wpi.first.math.**.struct.*", ], - "java.dependency.enableDependencyCheckup": false + "java.dependency.enableDependencyCheckup": false, + "search.useIgnoreFiles": true } diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 2882810..028928d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -13,6 +13,7 @@ import com.pathplanner.lib.auto.NamedCommands; import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.util.FlippingUtil; import com.pathplanner.lib.util.PathPlannerLogging; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -224,6 +225,13 @@ private void configureAutos() { PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); Pose2d startingPose = plannedAuto.getStartingPose(); + System.out.println("Normal \"" + autoName + "\" " + startingPose.toString()); + + if (isRed.getAsBoolean() == true) { + startingPose = FlippingUtil.flipFieldPose(startingPose); + System.out.println("Transposed \"" + autoName + "\" " + startingPose.toString()); + } + Command rotateToStartRot = new RotateToRotation2D( driveSubsystem, m_PoseEstimator, diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java index 56e1c37..73d5a28 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/TrackHubFlywheelCommand.java @@ -6,7 +6,6 @@ import java.util.function.BooleanSupplier; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; import frc.robot.utils.HubUtils; import frc.robot.utils.LauncherUtils; @@ -56,7 +55,7 @@ public void execute() { double Distance = HubUtils.getHubDistance(m_poseEstimator, m_isRed); // Determine flywheel speed to target hub from this distance. - double m_targetSpeedrpm = LauncherUtils.getFlywheelSpeed(Distance); + m_targetSpeedrpm = LauncherUtils.getFlywheelSpeed(Distance); // Set new flywheel target speed. m_subsystem.setTargetSpeedrpm(m_targetSpeedrpm); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 87e4a82..262462a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -7,8 +7,6 @@ package frc.robot.subsystems; import static edu.wpi.first.units.Units.Volts; -import java.io.Console; - import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; @@ -94,7 +92,8 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential var alliance = DriverStation.getAlliance(); if (alliance.isPresent()) { - return alliance.get() == DriverStation.Alliance.Red; + DriverStation.Alliance currentAlliance = alliance.get(); + return currentAlliance == DriverStation.Alliance.Red; } return false; }, From a671d7231c32bc51646fbcebd5ab336c17dc77bd Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 23 Feb 2026 20:43:56 -0600 Subject: [PATCH 080/161] Fixed the issue with it crashing on second auto run. --- .../main/java/frc/robot/RobotContainer.java | 23 +----- .../util/PathfindThenAutoCommand.java | 71 +++++++++++++++++++ 2 files changed, 74 insertions(+), 20 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 028928d..d1d3b9a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -12,6 +12,7 @@ import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.auto.NamedCommands; import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.commands.PathfindThenFollowPath; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.util.FlippingUtil; import com.pathplanner.lib.util.PathPlannerLogging; @@ -48,6 +49,7 @@ import frc.robot.utils.HubUtils; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; +import frc.robot.commands.util.PathfindThenAutoCommand; import frc.robot.Constants.*; /** @@ -222,26 +224,7 @@ private void configureAutos() { // Path Planner Auto's ArrayList autoNames = AutoCommands.getAutoNames(); for (String autoName : autoNames) { - PathPlannerAuto plannedAuto = new PathPlannerAuto(autoName); - Pose2d startingPose = plannedAuto.getStartingPose(); - - System.out.println("Normal \"" + autoName + "\" " + startingPose.toString()); - - if (isRed.getAsBoolean() == true) { - startingPose = FlippingUtil.flipFieldPose(startingPose); - System.out.println("Transposed \"" + autoName + "\" " + startingPose.toString()); - } - - Command rotateToStartRot = new RotateToRotation2D( - driveSubsystem, - m_PoseEstimator, - startingPose.getRotation(), - 2.0 - ); - - Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); - Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); - + Command pathfindThenAuto = new PathfindThenAutoCommand(driveSubsystem, m_PoseEstimator, m_constraints, autoName, isRed); m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java new file mode 100644 index 0000000..58a51bc --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java @@ -0,0 +1,71 @@ +package frc.robot.commands.util; + +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.util.FlippingUtil; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.Commands; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.subsystems.DriveSubsystem; + +public class PathfindThenAutoCommand extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final PathConstraints m_constraints; + private final String m_plannedAutoName; + private final BooleanSupplier m_isRed; + + public PathfindThenAutoCommand(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, String plannedAutoName, BooleanSupplier isRed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_constraints = constraints; + + m_plannedAutoName = plannedAutoName; + m_isRed = isRed; + } + + @Override + public void initialize() { + PathPlannerAuto plannedAuto = new PathPlannerAuto(m_plannedAutoName); + Pose2d startingPose = plannedAuto.getStartingPose(); + + if (m_isRed.getAsBoolean() == true) { + startingPose = FlippingUtil.flipFieldPose(startingPose); + } + + Command rotateToStartRot = new RotateToRotation2D( + m_driveSubsystem, + m_poseEstimator, + startingPose.getRotation(), + 2.0 + ); + + Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); + Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); + + CommandScheduler.getInstance().schedule(pathfindThenAuto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} From c0455c16a34270254f925a2901453c306c00694b Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:21:14 -0600 Subject: [PATCH 081/161] Orgnized commands into sub-forlders. --- .../main/java/frc/robot/RobotContainer.java | 21 +++++++++++++++++++ .../ArcadeDriveCommand.java | 2 +- .../ArcadeDriveCommandNoPID.java | 2 +- .../ArcadeFromDashboard.java | 2 +- .../DifferentailDriveFromDashboard.java | 2 +- .../DifferentialDriveCommand.java | 2 +- .../{ => DriveCommands}/NoDriveCommand.java | 2 +- .../{ => DriveCommands}/TurnLeftTest.java | 2 +- .../{ => autos}/DeadreckonForward.java | 2 +- .../{ => autos}/DriveForwardFromPos.java | 2 +- .../commands/{ => autos}/POTFtoPoint.java | 2 +- .../{ => util}/CancelDriveCommand.java | 2 +- .../frc/robot/subsystems/DriveSubsystem.java | 11 +++++----- 13 files changed, 38 insertions(+), 16 deletions(-) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/ArcadeDriveCommand.java (98%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/ArcadeDriveCommandNoPID.java (98%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/ArcadeFromDashboard.java (96%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/DifferentailDriveFromDashboard.java (97%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/DifferentialDriveCommand.java (98%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/NoDriveCommand.java (97%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => DriveCommands}/TurnLeftTest.java (96%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => autos}/DeadreckonForward.java (98%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => autos}/DriveForwardFromPos.java (99%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => autos}/POTFtoPoint.java (98%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{ => util}/CancelDriveCommand.java (97%) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index d1d3b9a..f69c447 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -13,6 +13,7 @@ import com.pathplanner.lib.auto.NamedCommands; import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.commands.PathfindThenFollowPath; +import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.util.FlippingUtil; import com.pathplanner.lib.util.PathPlannerLogging; @@ -34,6 +35,7 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; +import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import edu.wpi.first.wpilibj.PneumaticHub; @@ -49,6 +51,11 @@ import frc.robot.utils.HubUtils; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; +import frc.robot.commands.DriveCommands.TurnLeftTest; +import frc.robot.commands.autos.DeadreckonForward; +import frc.robot.commands.autos.DriveForwardFromPos; +import frc.robot.commands.autos.POTFtoPoint; +import frc.robot.commands.util.CancelDriveCommand; import frc.robot.commands.util.PathfindThenAutoCommand; import frc.robot.Constants.*; @@ -224,14 +231,28 @@ private void configureAutos() { // Path Planner Auto's ArrayList autoNames = AutoCommands.getAutoNames(); for (String autoName : autoNames) { + new PathPlannerAuto(autoName); // init the path for quick loading later. + Command pathfindThenAuto = new PathfindThenAutoCommand(driveSubsystem, m_PoseEstimator, m_constraints, autoName, isRed); m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); } + // Warmup Pathfinder + CommandScheduler.getInstance().schedule( + PathfindingCommand.warmupCommand() + .andThen(new InstantCommand( + () -> m_field.getObject("target").setPose(new Pose2d()) + )) + ); + // Add to dashboard SmartDashboard.putData("Auto Chooser", m_autoChooser); // Field wigit update + PathPlannerLogging.setLogTargetPoseCallback((pose) -> { + m_field.getObject("target").setPose(pose); + }); + PathPlannerLogging.setLogActivePathCallback((poses) -> { m_field.getObject("path").setPoses(poses); }); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java index 7bcc2a4..5cfddce 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java @@ -2,7 +2,7 @@ // 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.commands; +package frc.robot.commands.DriveCommands; import frc.robot.Constants.DrivetrainConstants; import frc.robot.Constants.OperatorConstants; import frc.robot.subsystems.DriveSubsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommandNoPID.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommandNoPID.java index 88ee73a..2e4ade9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeDriveCommandNoPID.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommandNoPID.java @@ -2,7 +2,7 @@ // 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.commands; +package frc.robot.commands.DriveCommands; import frc.robot.Constants.OperatorConstants; import frc.robot.subsystems.DriveSubsystem; import edu.wpi.first.wpilibj2.command.Command; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeFromDashboard.java similarity index 96% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeFromDashboard.java index f35dc4f..6f5ef66 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/ArcadeFromDashboard.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeFromDashboard.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.DriveCommands; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/DifferentailDriveFromDashboard.java similarity index 97% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/DifferentailDriveFromDashboard.java index a53bd80..560a518 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentailDriveFromDashboard.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/DifferentailDriveFromDashboard.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.DriveCommands; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/DifferentialDriveCommand.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/DifferentialDriveCommand.java index 16b0322..992cc3a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DifferentialDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/DifferentialDriveCommand.java @@ -2,7 +2,7 @@ // 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.commands; +package frc.robot.commands.DriveCommands; import frc.robot.subsystems.DriveSubsystem; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/NoDriveCommand.java similarity index 97% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/NoDriveCommand.java index e4f1ff4..b674e34 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/NoDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/NoDriveCommand.java @@ -2,7 +2,7 @@ // 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.commands; +package frc.robot.commands.DriveCommands; import frc.robot.subsystems.DriveSubsystem; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/TurnLeftTest.java similarity index 96% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/TurnLeftTest.java index 4e18583..c5b12c2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/TurnLeftTest.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/TurnLeftTest.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.DriveCommands; import edu.wpi.first.wpilibj2.command.Command; import frc.robot.subsystems.DriveSubsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DeadreckonForward.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autos/DeadreckonForward.java index e3562b4..351521c 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DeadreckonForward.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DeadreckonForward.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.autos; import edu.wpi.first.wpilibj2.command.Command; import frc.robot.subsystems.DriveSubsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DriveForwardFromPos.java similarity index 99% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autos/DriveForwardFromPos.java index a17ac62..8449fe5 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DriveForwardFromPos.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DriveForwardFromPos.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.autos; import java.util.List; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autos/POTFtoPoint.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autos/POTFtoPoint.java index 5990ecc..8944be8 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/POTFtoPoint.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autos/POTFtoPoint.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.autos; import java.util.List; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/CancelDriveCommand.java similarity index 97% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/util/CancelDriveCommand.java index b38f1ac..dcdaefd 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/CancelDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/CancelDriveCommand.java @@ -1,4 +1,4 @@ -package frc.robot.commands; +package frc.robot.commands.util; import edu.wpi.first.wpilibj2.command.Command; import frc.robot.subsystems.DriveSubsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 262462a..42cf5ac 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -16,6 +16,7 @@ import com.ctre.phoenix6.signals.MotorAlignmentValue; import com.ctre.phoenix6.signals.NeutralModeValue; import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.controllers.PPLTVController; import com.studica.frc.AHRS; @@ -34,11 +35,11 @@ import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.Constants.AutoConstants; import frc.robot.Constants.DrivetrainConstants; -import frc.robot.commands.ArcadeDriveCommand; -import frc.robot.commands.ArcadeDriveCommandNoPID; -import frc.robot.commands.ArcadeFromDashboard; -import frc.robot.commands.DifferentialDriveCommand; -import frc.robot.commands.NoDriveCommand; +import frc.robot.commands.DriveCommands.ArcadeDriveCommand; +import frc.robot.commands.DriveCommands.ArcadeDriveCommandNoPID; +import frc.robot.commands.DriveCommands.ArcadeFromDashboard; +import frc.robot.commands.DriveCommands.DifferentialDriveCommand; +import frc.robot.commands.DriveCommands.NoDriveCommand; public class DriveSubsystem extends SubsystemBase { private TalonFX m_rightMotor; From c6e6dab0d1f7725ce3c03abd9e3da3fed0541896 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 24 Feb 2026 20:57:41 -0600 Subject: [PATCH 082/161] Made an auto that scoops up the 8 "corral" balls and shoots them --- .../autos/GatherCorralAndReverse.auto | 31 ++++++++ .../src/main/deploy/pathplanner/navgrid.json | 2 +- .../pathplanner/paths/GatherCorral1.path | 70 +++++++++++++++++++ .../pathplanner/paths/GatherCorral2.path | 54 ++++++++++++++ .../main/java/frc/robot/RobotContainer.java | 16 ++++- .../DriveCommands/ArcadeDriveCommand.java | 2 + 6 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndReverse.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral2.path diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndReverse.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndReverse.auto new file mode 100644 index 0000000..e41fa5b --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndReverse.auto @@ -0,0 +1,31 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "GatherCorral1" + } + }, + { + "type": "path", + "data": { + "pathName": "GatherCorral2" + } + }, + { + "type": "named", + "data": { + "name": "AimToHub" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json index 465fe26..bb9b582 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/navgrid.json @@ -1 +1 @@ -{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file +{"field_size":{"x":16.54,"y":8.07},"nodeSizeMeters":0.3,"grid":[[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,true,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,true,false,false,false,false,false,false,true,true,true,true,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true,true,true,true,true,true,false,false,false,false,false,false,false,false,false,false,false,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true],[true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true,true]]} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path new file mode 100644 index 0000000..77f921b --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 1.7233205128205147, + "y": 4.942 + }, + "prevControl": null, + "nextControl": { + "x": 1.258192307692309, + "y": 4.96525641025641 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.5488717948717963, + "y": 5.883884615384615 + }, + "prevControl": { + "x": 0.49291105769230914, + "y": 5.378784455128205 + }, + "nextControl": { + "x": 0.6048325320512834, + "y": 6.388984775641026 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.479, + "y": 6.849 + }, + "prevControl": { + "x": 0.9442307692307704, + "y": 7.162987179487179 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral2.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral2.path new file mode 100644 index 0000000..a116043 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral2.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 1.4791282051312882, + "y": 6.849025641019939 + }, + "prevControl": null, + "nextControl": { + "x": 1.2706819835318741, + "y": 6.987048004066396 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.6884102564102579, + "y": 7.349038461538462 + }, + "prevControl": { + "x": 1.0488846153846165, + "y": 7.011820512820513 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index f69c447..ac85542 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -102,7 +102,7 @@ public class RobotContainer { 1.0, 1.0, (1/2) * Math.PI, - 1 * Math.PI + (1/4) * Math.PI ); // The constraints for this path. // Smartdashboard Objects @@ -233,8 +233,18 @@ private void configureAutos() { for (String autoName : autoNames) { new PathPlannerAuto(autoName); // init the path for quick loading later. - Command pathfindThenAuto = new PathfindThenAutoCommand(driveSubsystem, m_PoseEstimator, m_constraints, autoName, isRed); - m_autoChooser.addOption("[PF] "+autoName, pathfindThenAuto); + // Checks if the file name starts with "NP_", this is so no path finding + // is used when the auto from the file is ran. + Boolean noPathfind = autoName.split("_")[0] == "NP"; + Command pathfindThenAuto; + + if (noPathfind) { + pathfindThenAuto = new PathPlannerAuto(autoName); + } else { + pathfindThenAuto = new PathfindThenAutoCommand(driveSubsystem, m_PoseEstimator, m_constraints, autoName, isRed); + } + + m_autoChooser.addOption((noPathfind ? "" : "[PF] ") + autoName, pathfindThenAuto); } // Warmup Pathfinder diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java index 5cfddce..3b39dec 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/DriveCommands/ArcadeDriveCommand.java @@ -48,6 +48,8 @@ public void execute() { turnInput = 0; } + turnInput = turnInput / 2.0; + double leftSpeed = speedInput + turnInput; double rightSpeed = speedInput - turnInput; From 15f4ac3d41db1e98f53890f81e3231a6a776e6e2 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 27 Feb 2026 19:10:31 -0600 Subject: [PATCH 083/161] Added new Auto & Saved layout --- 2026-Rebuilt/elastic-layout.json | 170 +++++++++--------- .../autos/GatherCorralAndShoot.auto | 25 +++ .../pathplanner/paths/GatherCorralShoot.path | 70 ++++++++ .../main/java/frc/robot/RobotContainer.java | 1 - 4 files changed, 180 insertions(+), 86 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndShoot.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index c4d970a..71ada17 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -20,62 +20,6 @@ "sort_options": false } }, - { - "title": "Left Target (MPS)", - "x": 0.0, - "y": 256.0, - "width": 128.0, - "height": 128.0, - "type": "Text Display", - "properties": { - "topic": "/SmartDashboard/Left Target (MPS)", - "period": 0.06, - "data_type": "double", - "show_submit_button": false - } - }, - { - "title": "Left Speed (MPS)", - "x": 0.0, - "y": 384.0, - "width": 128.0, - "height": 128.0, - "type": "Text Display", - "properties": { - "topic": "/SmartDashboard/Left Speed (MPS)", - "period": 0.06, - "data_type": "double", - "show_submit_button": false - } - }, - { - "title": "Right Target (MPS)", - "x": 128.0, - "y": 256.0, - "width": 128.0, - "height": 128.0, - "type": "Text Display", - "properties": { - "topic": "/SmartDashboard/Right Target (MPS)", - "period": 0.06, - "data_type": "double", - "show_submit_button": false - } - }, - { - "title": "Right Speed (MPS)", - "x": 128.0, - "y": 384.0, - "width": 128.0, - "height": 128.0, - "type": "Text Display", - "properties": { - "topic": "/SmartDashboard/Right Speed (MPS)", - "period": 0.06, - "data_type": "double", - "show_submit_button": false - } - }, { "title": "Auto Chooser", "x": 0.0, @@ -91,10 +35,10 @@ }, { "title": "Field", - "x": 640.0, + "x": 896.0, "y": 0.0, - "width": 512.0, - "height": 384.0, + "width": 384.0, + "height": 256.0, "type": "Field", "properties": { "topic": "/SmartDashboard/Field", @@ -123,86 +67,142 @@ } }, { - "title": "Left Distance (m)", - "x": 0.0, - "y": 512.0, + "title": "Pose X (Meter)", + "x": 896.0, + "y": 256.0, "width": 128.0, "height": 128.0, "type": "Text Display", "properties": { - "topic": "/SmartDashboard/Left Distance (m)", + "topic": "/SmartDashboard/Pose X (Meter)", "period": 0.06, "data_type": "double", "show_submit_button": false } }, { - "title": "Right Distance (m)", - "x": 128.0, - "y": 512.0, + "title": "Pose Y (Meter)", + "x": 1024.0, + "y": 256.0, "width": 128.0, "height": 128.0, "type": "Text Display", "properties": { - "topic": "/SmartDashboard/Right Distance (m)", + "topic": "/SmartDashboard/Pose Y (Meter)", "period": 0.06, "data_type": "double", "show_submit_button": false } }, { - "title": "Pose X (Meter)", + "title": "Pose Theta (Degrees)", "x": 1152.0, - "y": 0.0, + "y": 256.0, "width": 128.0, "height": 128.0, "type": "Text Display", "properties": { - "topic": "/SmartDashboard/Pose X (Meter)", + "topic": "/SmartDashboard/Pose Theta (Degrees)", "period": 0.06, "data_type": "double", "show_submit_button": false } }, { - "title": "Pose Y (Meter)", - "x": 1152.0, + "title": "limelight", + "x": 512.0, + "y": 0.0, + "width": 384.0, + "height": 384.0, + "type": "Camera Stream", + "properties": { + "topic": "/CameraPublisher/limelight", + "period": 0.06, + "rotation_turns": 0 + } + }, + { + "title": "Left Speed (MPS)", + "x": 256.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Right Speed (MPS)", + "x": 384.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Left Target (MPS)", + "x": 256.0, "y": 128.0, "width": 128.0, "height": 128.0, "type": "Text Display", "properties": { - "topic": "/SmartDashboard/Pose Y (Meter)", + "topic": "/SmartDashboard/Left Target (MPS)", "period": 0.06, "data_type": "double", - "show_submit_button": false + "show_submit_button": true } }, { - "title": "Pose Theta (Degrees)", - "x": 1152.0, + "title": "Right Target (MPS)", + "x": 384.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Hub Distance", + "x": 384.0, "y": 256.0, "width": 128.0, "height": 128.0, "type": "Text Display", "properties": { - "topic": "/SmartDashboard/Pose Theta (Degrees)", + "topic": "/SmartDashboard/Hub Distance", "period": 0.06, "data_type": "double", - "show_submit_button": false + "show_submit_button": true } }, { - "title": "limelight", + "title": "mt2 Tag Count", "x": 256.0, - "y": 0.0, - "width": 384.0, - "height": 384.0, - "type": "Camera Stream", + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", "properties": { - "topic": "/CameraPublisher/limelight", + "topic": "/SmartDashboard/mt2 Tag Count", "period": 0.06, - "rotation_turns": 0 + "data_type": "double", + "show_submit_button": true } } ] diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndShoot.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndShoot.auto new file mode 100644 index 0000000..07f8c4b --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/GatherCorralAndShoot.auto @@ -0,0 +1,25 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "GatherCorralShoot" + } + }, + { + "type": "named", + "data": { + "name": "AimToHub" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path new file mode 100644 index 0000000..87f569e --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 1.7233205128205147, + "y": 4.942 + }, + "prevControl": null, + "nextControl": { + "x": 1.258192307692309, + "y": 4.96525641025641 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.5488717948717963, + "y": 5.883884615384615 + }, + "prevControl": { + "x": 0.49291189105897826, + "y": 5.378784362799069 + }, + "nextControl": { + "x": 0.6048316986846143, + "y": 6.388984867970162 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.6884102564102579, + "y": 6.651346153846154 + }, + "prevControl": { + "x": 0.6608812672599742, + "y": 6.402866467037828 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index ac85542..0dfc17b 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -170,7 +170,6 @@ private static Optional getSubsystem(Class subsystemClass) { } // Init Autos (/home/lvuser/deploy/pathplanner/autos) - // TODO: Check if the new PathPlannerAuto is mirroring the cords when read by the pathfinder. private void configureAutos() { if (m_driveSubsystem.isPresent()) { // Init Needed values From 2b4022e49a7545d30a735e680b78c6ddc405a1f8 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 27 Feb 2026 20:39:44 -0600 Subject: [PATCH 084/161] Added a proof of concept smooth pathfind --- .../paths/GatherCorralShootVel.path | 70 +++++++++++++++++++ .../main/java/frc/robot/RobotContainer.java | 16 ++++- .../util/PathfindThenAutoCommand.java | 2 +- .../robot/subsystems/LimelightSubsystem.java | 18 ++++- 2026-Rebuilt/todo_stuff.txt | 6 ++ 5 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path create mode 100644 2026-Rebuilt/todo_stuff.txt diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path new file mode 100644 index 0000000..5c46ca0 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 1.7233205128205147, + "y": 4.942 + }, + "prevControl": null, + "nextControl": { + "x": 1.258192307692309, + "y": 4.96525641025641 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.5488717948717963, + "y": 5.883884615384615 + }, + "prevControl": { + "x": 0.4929118910589782, + "y": 5.378784362799069 + }, + "nextControl": { + "x": 0.6048316986846143, + "y": 6.388984867970162 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.6884102564102579, + "y": 6.651346153846154 + }, + "prevControl": { + "x": 0.6608812672599742, + "y": 6.402866467037828 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 1.0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 0dfc17b..df511ad 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -15,6 +15,7 @@ import com.pathplanner.lib.commands.PathfindThenFollowPath; import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; import com.pathplanner.lib.util.FlippingUtil; import com.pathplanner.lib.util.PathPlannerLogging; import com.studica.frc.AHRS; @@ -99,8 +100,8 @@ public class RobotContainer { ); PathConstraints m_constraints = new PathConstraints( - 1.0, - 1.0, + 2.0, + 2.0, (1/2) * Math.PI, (1/4) * Math.PI ); // The constraints for this path. @@ -194,6 +195,17 @@ private void configureAutos() { ); // Custom Autos + try { + PathPlannerPath path = PathPlannerPath.fromPathFile("GatherCorralShootVel"); + m_autoChooser.addOption( + "PathFindAndFollowPath Example", + AutoBuilder.pathfindThenFollowPath(path, m_constraints) + ); + } catch (Exception e) { + System.out.println("Failed to load Pathfind and follow path exp!"); + } + + m_autoChooser.addOption( "Deadreckon 3m at 3.0 mps", new DeadreckonForward(driveSubsystem, 3, 3.0) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java index 58a51bc..00696f4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java @@ -45,7 +45,7 @@ public void initialize() { m_driveSubsystem, m_poseEstimator, startingPose.getRotation(), - 2.0 + 3.0 ); Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index f23eb20..9455053 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -3,6 +3,7 @@ // the WPILib BSD license file in the root directory of this project. package frc.robot.subsystems; +import java.io.Console; import java.util.Arrays; import org.ejml.simple.SimpleMatrix; @@ -25,6 +26,7 @@ public class LimelightSubsystem extends SubsystemBase { private final AHRS m_gyro; private final LimitedQueue m_YawQue = new LimitedQueue(5); + private boolean seenApriltag = false; /** Creates a new PositionSubsystem. */ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { @@ -35,6 +37,11 @@ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyr } public double getRobotYaw() { + if (seenApriltag == false) { + System.out.println("No apriltag seen! returning 0!"); + return 0.0; + } + Double[] doubleObjects = m_YawQue.toArray(new Double[0]); int queSize = doubleObjects.length; @@ -81,6 +88,11 @@ private void updateOdometry() { doRejectUpdate = true; } + if (seenApriltag == false && mt2.tagCount >= 2) { + seenApriltag = true; + doRejectUpdate = true; + } + if(!doRejectUpdate) { // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. @@ -105,8 +117,10 @@ private void updateOdometry() { @Override public void periodic() { // This method will be called once per scheduler - IMUData limelightData = LimelightHelpers.getIMUData("limelight"); - m_YawQue.add(limelightData.robotYaw); + if (seenApriltag == true) { + IMUData limelightData = LimelightHelpers.getIMUData("limelight"); + m_YawQue.add(limelightData.robotYaw); + } //System.out.println(m_YawQue.toString()); updateOdometry(); diff --git a/2026-Rebuilt/todo_stuff.txt b/2026-Rebuilt/todo_stuff.txt new file mode 100644 index 0000000..5515a36 --- /dev/null +++ b/2026-Rebuilt/todo_stuff.txt @@ -0,0 +1,6 @@ +pathfind and follow path w/ autos: +1. pop out the first path. +2. pathfind follow path w/ first path in list. +3. profit + +make the path update to the one selected on the gui w/ some sort of selector event \ No newline at end of file From afd42d6e8d8dc83360b3d9aefa7d70c244159bc4 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 27 Feb 2026 20:50:22 -0600 Subject: [PATCH 085/161] Started rewrite. --- .../util/PathfindThenAutoCommand.java | 44 +++++++++++++------ 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java index 00696f4..157dd46 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java @@ -1,10 +1,12 @@ package frc.robot.commands.util; +import java.util.List; import java.util.function.BooleanSupplier; import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; import com.pathplanner.lib.util.FlippingUtil; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; @@ -34,24 +36,38 @@ public PathfindThenAutoCommand(DriveSubsystem driveSubsystem, DifferentialDriveP @Override public void initialize() { - PathPlannerAuto plannedAuto = new PathPlannerAuto(m_plannedAutoName); - Pose2d startingPose = plannedAuto.getStartingPose(); + // PathPlannerAuto plannedAuto = new PathPlannerAuto(m_plannedAutoName); + // Pose2d startingPose = plannedAuto.getStartingPose(); - if (m_isRed.getAsBoolean() == true) { - startingPose = FlippingUtil.flipFieldPose(startingPose); - } + // if (m_isRed.getAsBoolean() == true) { + // startingPose = FlippingUtil.flipFieldPose(startingPose); + // } + + // Command rotateToStartRot = new RotateToRotation2D( + // m_driveSubsystem, + // m_poseEstimator, + // startingPose.getRotation(), + // 3.0 + // ); - Command rotateToStartRot = new RotateToRotation2D( - m_driveSubsystem, - m_poseEstimator, - startingPose.getRotation(), - 3.0 - ); + // Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); + // Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); - Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); - Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); + // CommandScheduler.getInstance().schedule(pathfindThenAuto); - CommandScheduler.getInstance().schedule(pathfindThenAuto); + // TODO: Look into named commands and finish the command rewrite. + try { + List paths = PathPlannerAuto.getPathGroupFromAutoFile(m_plannedAutoName); + + // check if empty, if it isnt then remove first value + // take the first value and plug it into a Pathfindthenfollowpath + // then create a sequenatal command group and add the pathfind to it + // then loop through the rest of the paths and add it to the command group. + + // also check if named commands trasnfer, if not need to figure that out. (trigger?) + } catch (Exception e) { + // do somthing here + } } // Called every time the scheduler runs while the command is scheduled. From 8f01ccabeae1df63fbf403bc59f23a6bc2ef3763 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 28 Feb 2026 14:15:56 -0600 Subject: [PATCH 086/161] Create BulkMoveCommand.java Made bulk move run command. --- .../frc/robot/commands/BulkMoveCommand.java | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java new file mode 100644 index 0000000..0d99ab8 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java @@ -0,0 +1,48 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Stop the launcher lift motor and spin down the flywheel. + * + **/ +public class StartLiftCommand extends Command { + private final LauncherSubsystem m_subsystem; + + /** + * Creates a new StartLiftCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StartLiftCommand(LauncherSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.startLift(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} From c7105f1558fb572443bc534f0020938a3706d110 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 28 Feb 2026 15:53:40 -0600 Subject: [PATCH 087/161] Almost done fixing the issue where the auto freaks out when the degree is too off. --- .../autos/VEL_GatherCorralAndShoot.auto | 31 +++ .../paths/GatherCorralShootVel.path | 2 +- .../paths/GatherCorralVelTest.path | 70 +++++++ .../paths/GatherCorralVelTest2.path | 54 +++++ .../main/java/frc/robot/RobotContainer.java | 106 +++------- .../robot/commands/RotateToRotation2D.java | 6 +- .../commands/autoCommands/CorralAndShoot.java | 85 ++++++++ .../DeadreckonForward.java | 2 +- .../DriveForwardFromPos.java | 2 +- .../{autos => autoCommands}/POTFtoPoint.java | 2 +- .../frc/robot/commands/util/AutoFromList.java | 194 ++++++++++++++++++ .../util/PathfindThenAutoCommand.java | 18 +- .../java/frc/robot/utils/AutoCommands.java | 29 +++ 13 files changed, 513 insertions(+), 88 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/VEL_GatherCorralAndShoot.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest2.path create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java rename 2026-Rebuilt/src/main/java/frc/robot/commands/{autos => autoCommands}/DeadreckonForward.java (97%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{autos => autoCommands}/DriveForwardFromPos.java (98%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{autos => autoCommands}/POTFtoPoint.java (98%) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/VEL_GatherCorralAndShoot.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/VEL_GatherCorralAndShoot.auto new file mode 100644 index 0000000..9ac4b21 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/VEL_GatherCorralAndShoot.auto @@ -0,0 +1,31 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "path", + "data": { + "pathName": "GatherCorralShootVel" + } + }, + { + "type": "path", + "data": { + "pathName": "GatherCorralVelTest" + } + }, + { + "type": "path", + "data": { + "pathName": "GatherCorralVelTest2" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path index 5c46ca0..e1b3068 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShootVel.path @@ -57,7 +57,7 @@ "unlimited": false }, "goalEndState": { - "velocity": 0, + "velocity": 0.5, "rotation": 0.0 }, "reversed": false, diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest.path new file mode 100644 index 0000000..939b881 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.688, + "y": 6.651 + }, + "prevControl": null, + "nextControl": { + "x": 0.7155289891502836, + "y": 6.899479686808326 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.5954102564102572, + "y": 7.453692307692307 + }, + "prevControl": { + "x": 0.7368002260611529, + "y": 7.5411433293019385 + }, + "nextControl": { + "x": 4.107102564102565, + "y": 7.197871794871795 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 2.4791538461538476, + "y": 5.186192307692308 + }, + "prevControl": { + "x": 3.8163974358974375, + "y": 5.174564102564102 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0.5, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest2.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest2.path new file mode 100644 index 0000000..75c80e2 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralVelTest2.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.479, + "y": 5.186 + }, + "prevControl": null, + "nextControl": { + "x": 3.479, + "y": 5.186 + }, + "isLocked": true, + "linkedName": null + }, + { + "anchor": { + "x": 3.5954615384615396, + "y": 5.186 + }, + "prevControl": { + "x": 3.0938000773498056, + "y": 5.186 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index df511ad..b9100bc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -5,6 +5,7 @@ package frc.robot; import java.util.ArrayList; +import java.util.Arrays; import java.util.Optional; import java.util.function.BooleanSupplier; @@ -53,9 +54,11 @@ import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; -import frc.robot.commands.autos.DeadreckonForward; -import frc.robot.commands.autos.DriveForwardFromPos; -import frc.robot.commands.autos.POTFtoPoint; +import frc.robot.commands.autoCommands.CorralAndShoot; +import frc.robot.commands.autoCommands.DeadreckonForward; +import frc.robot.commands.autoCommands.DriveForwardFromPos; +import frc.robot.commands.autoCommands.POTFtoPoint; +import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.commands.util.PathfindThenAutoCommand; import frc.robot.Constants.*; @@ -101,7 +104,7 @@ public class RobotContainer { PathConstraints m_constraints = new PathConstraints( 2.0, - 2.0, + 1.0, (1/2) * Math.PI, (1/4) * Math.PI ); // The constraints for this path. @@ -177,88 +180,25 @@ private void configureAutos() { DriveSubsystem driveSubsystem = m_driveSubsystem.get(); m_autoChooser = new SendableChooser(); - // Named Commands - NamedCommands.registerCommand("RotateTo-180", new RotateToRotation2D( - driveSubsystem, - m_PoseEstimator, - Rotation2d.fromDegrees(180), - 1 + // Init Autos + m_autoChooser.addOption("Corral and Park", + new AutoFromList( + new ArrayList(Arrays.asList( + "GatherCorralShootVel", + "GatherCorralVelTest", + "GatherCorralVelTest2" + )), + m_constraints, + driveSubsystem, + m_PoseEstimator ) ); - NamedCommands.registerCommand("AimToHub", new AimAtHub( - driveSubsystem, - m_PoseEstimator, - 2.0, - isRed - ) + m_autoChooser.addOption("Corral and Shoot", + new CorralAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); - // Custom Autos - try { - PathPlannerPath path = PathPlannerPath.fromPathFile("GatherCorralShootVel"); - m_autoChooser.addOption( - "PathFindAndFollowPath Example", - AutoBuilder.pathfindThenFollowPath(path, m_constraints) - ); - } catch (Exception e) { - System.out.println("Failed to load Pathfind and follow path exp!"); - } - - - m_autoChooser.addOption( - "Deadreckon 3m at 3.0 mps", - new DeadreckonForward(driveSubsystem, 3, 3.0) - ); - - m_autoChooser.addOption( - "Deadreckon -3m at -1.0", - new DeadreckonForward(driveSubsystem, -3, -1.0) - ); - - m_autoChooser.addOption( - "On-Fly Forward 2m", - new DriveForwardFromPos(m_PoseEstimator, 2) - ); - - m_autoChooser.addOption( - "Rotate to 0", - new RotateToRotation2D( - driveSubsystem, - m_PoseEstimator, - new Rotation2d(0.0), - 1 - ) - ); - - m_autoChooser.addOption( - "On-The-Fly to (2, 4.837) -90", - new POTFtoPoint( - m_PoseEstimator, - new Pose2d(2, 4.837, Rotation2d.fromDegrees(-90)) - ) - ); - - // Path Planner Auto's - ArrayList autoNames = AutoCommands.getAutoNames(); - for (String autoName : autoNames) { - new PathPlannerAuto(autoName); // init the path for quick loading later. - - // Checks if the file name starts with "NP_", this is so no path finding - // is used when the auto from the file is ran. - Boolean noPathfind = autoName.split("_")[0] == "NP"; - Command pathfindThenAuto; - - if (noPathfind) { - pathfindThenAuto = new PathPlannerAuto(autoName); - } else { - pathfindThenAuto = new PathfindThenAutoCommand(driveSubsystem, m_PoseEstimator, m_constraints, autoName, isRed); - } - - m_autoChooser.addOption((noPathfind ? "" : "[PF] ") + autoName, pathfindThenAuto); - } - - // Warmup Pathfinder + // Warm up Pathfinder CommandScheduler.getInstance().schedule( PathfindingCommand.warmupCommand() .andThen(new InstantCommand( @@ -378,6 +318,8 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); SmartDashboard.putNumber("mt2 Tag Count", 0.0); + + SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); } // This function is called every 20mS. @@ -393,6 +335,8 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); + + SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); } // Drive subsystem diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java index 1b20280..b12bc8e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -1,5 +1,7 @@ package frc.robot.commands; +import java.io.Console; + import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; @@ -39,7 +41,9 @@ public RotateToRotation2D(DriveSubsystem driveSubsystem, DifferentialDrivePoseEs // Called when the command is initially scheduled. @Override - public void initialize() {} + public void initialize() { + System.out.println("Starting rotation to: " + m_targetRotation.getDegrees()); + } // Called every time the scheduler runs while the command is scheduled. @Override diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java new file mode 100644 index 0000000..4082836 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java @@ -0,0 +1,85 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.util.AutoFromList; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class CorralAndShoot extends Command { + // The sequance of the command, any "*" are place holders for commands. + private final ArrayList m_baseSequence = new ArrayList(Arrays.asList( + "GatherCorralShootVel", + "*" // Aim at hub + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new CorralAndShoot. + */ + public CorralAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_baseSequence) { + if (item instanceof String && (String) item != "*") { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // Init the new sequence + ArrayList sequence = new ArrayList(m_baseSequence); + sequence.set(1, new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed)); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DeadreckonForward.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonForward.java similarity index 97% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/autos/DeadreckonForward.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonForward.java index 351521c..1443d6e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DeadreckonForward.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonForward.java @@ -1,4 +1,4 @@ -package frc.robot.commands.autos; +package frc.robot.commands.autoCommands; import edu.wpi.first.wpilibj2.command.Command; import frc.robot.subsystems.DriveSubsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DriveForwardFromPos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveForwardFromPos.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/autos/DriveForwardFromPos.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveForwardFromPos.java index 8449fe5..f7fbe44 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autos/DriveForwardFromPos.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveForwardFromPos.java @@ -1,4 +1,4 @@ -package frc.robot.commands.autos; +package frc.robot.commands.autoCommands; import java.util.List; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autos/POTFtoPoint.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java similarity index 98% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/autos/POTFtoPoint.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java index 8944be8..767e86f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autos/POTFtoPoint.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java @@ -1,4 +1,4 @@ -package frc.robot.commands.autos; +package frc.robot.commands.autoCommands; import java.util.List; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java new file mode 100644 index 0000000..4175fa2 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -0,0 +1,194 @@ +package frc.robot.commands.util; + +import java.io.Console; +import java.nio.file.Path; +import java.util.List; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.path.PathPoint; +import com.pathplanner.lib.path.RotationTarget; +import com.pathplanner.lib.path.Waypoint; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.Commands; +import edu.wpi.first.wpilibj2.command.ConditionalCommand; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.subsystems.DriveSubsystem; + + +// Auto From Path Names And Commands +public class AutoFromList extends Command { + private final List m_sequence; + private final PathConstraints m_constraints; + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final Boolean m_pathfindToFirstPath; + + /** + * Creates and runs a new auto from a list of path names and commands. + * Any list with a command can only be ran once due to how the scheudler works. + * + * @param sequence A list of path names (strings) and commands to run in order. + */ + public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator) + { + m_sequence = sequence; + m_constraints = constraints; + m_DriveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_pathfindToFirstPath = true; + + warmup(); + } + + public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, boolean pathfindToFirstpath) + { + m_sequence = sequence; + m_constraints = constraints; + m_DriveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_pathfindToFirstPath = pathfindToFirstpath; + + warmup(); + } + + public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, boolean pathfindToFirstpath, boolean doWarmup) + { + m_sequence = sequence; + m_constraints = constraints; + m_DriveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_pathfindToFirstPath = pathfindToFirstpath; + + if (doWarmup == true) { + warmup(); + } + } + + private void warmup() { + for (Object item : m_sequence) { + if (item instanceof String) { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + @Override + public void initialize() { + try { + SequentialCommandGroup precommandGroup = new SequentialCommandGroup(); + SequentialCommandGroup commandGroup = new SequentialCommandGroup(); + Boolean pathFinded = !m_pathfindToFirstPath; // If we want to pathfind this will be set to false. + + for (Object item : m_sequence) { + if (item instanceof Command) { + if (pathFinded == false) { + precommandGroup.addCommands((Command) item); + } else { + commandGroup.addCommands((Command) item); + } + } else if (item instanceof String) { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + + if (pathFinded == false) { + // needed Values + Pose2d pathStartPose = path.getStartingDifferentialPose(); + Rotation2d targetRot = pathStartPose.getRotation(); + BooleanSupplier conditional = () -> { + Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); + double diff = Math.abs((targetRot.minus(currentRot)).getDegrees()); + + return diff <= 45; + }; + + // pathfind command + Command pathfinderCommand = AutoBuilder.pathfindToPose( + pathStartPose, + m_constraints, + path.getIdealStartingState().velocityMPS() + ); + + // path and rotate stuff + Command rotateCommand = new RotateToRotation2D( + m_DriveSubsystem, + m_poseEstimator, + targetRot, + 2.0 + ); + + Command testCommand = new InstantCommand(() -> { + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + + List pathPoses = path.getPathPoses(); + pathPoses.set(0, currentPose); + + List waypoints = PathPlannerPath.waypointsFromPoses(pathPoses); + PathPlannerPath newPath = new PathPlannerPath(waypoints, path.getGlobalConstraints(), path.getIdealStartingState(), path.getGoalEndState()); + Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); + + System.out.println(" -- scheduling everyhting else --"); + System.out.println(" -- scheduling everyhting else --"); + System.out.println(" -- scheduling everyhting else --"); + System.out.println(" -- scheduling everyhting else --"); + CommandScheduler.getInstance().schedule(newPathCommand); + }); + + // decide what to do + Command conditonalCommand = Commands.either( + new InstantCommand(), + rotateCommand, + conditional + ); + + // add to group + precommandGroup.addCommands(pathfinderCommand, conditonalCommand, testCommand); + + // Command pathfinderCommand = AutoBuilder.pathfindThenFollowPath(path, m_constraints); + // commandGroup.addCommands(pathfinderCommand); + + pathFinded = true; + } else { + Command pathCommand = AutoBuilder.followPath(path); + commandGroup.addCommands(pathCommand); + } + } + } + + CommandScheduler.getInstance().schedule(precommandGroup); + } catch (Exception e) { + // do somthing here + System.out.println("Failed to run " + this.getName() + ": " + e.toString()); + } + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java index 157dd46..8fc691f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java @@ -14,6 +14,7 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.commands.RotateToRotation2D; import frc.robot.subsystems.DriveSubsystem; @@ -55,18 +56,31 @@ public void initialize() { // CommandScheduler.getInstance().schedule(pathfindThenAuto); - // TODO: Look into named commands and finish the command rewrite. + // TODO: Look into named commands try { + SequentialCommandGroup commandGroup = new SequentialCommandGroup(); List paths = PathPlannerAuto.getPathGroupFromAutoFile(m_plannedAutoName); // check if empty, if it isnt then remove first value // take the first value and plug it into a Pathfindthenfollowpath - // then create a sequenatal command group and add the pathfind to it + if (!paths.isEmpty()) { + PathPlannerPath path = paths.remove(0); + Command pathfinderCommand = AutoBuilder.pathfindThenFollowPath(path, m_constraints); + commandGroup.addCommands(pathfinderCommand); + } + // then loop through the rest of the paths and add it to the command group. + for (PathPlannerPath path : paths) { + Command pathCommand = AutoBuilder.followPath(path); + commandGroup.addCommands(pathCommand); + } // also check if named commands trasnfer, if not need to figure that out. (trigger?) + + CommandScheduler.getInstance().schedule(commandGroup); } catch (Exception e) { // do somthing here + System.out.println("Failed to run " + m_plannedAutoName + ": " + e.toString()); } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java b/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java index 5475bf5..0b08198 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/AutoCommands.java @@ -15,6 +15,35 @@ // We are asuming that the files are always in the "/home/lvuser/deploy/pathplanner/autos" // We found this information at https://github.com/mjansen4857/pathplanner/wiki/PathPlannerLib:-Java-Usage public class AutoCommands { + public static ArrayList getPathNames() { + // Creating an ArrayList so I can fill it with auto file names w/o the extention. + ArrayList pathNames = new ArrayList(); + + // Getting the folder and files. + String deployDirectoryPath = Filesystem.getDeployDirectory().getPath(); + File deployDirectory = new File(deployDirectoryPath+"/pathplanner/paths"); + File[] listOfFiles = deployDirectory.listFiles(); + + // Checking if the files exist + if (listOfFiles != null) { + for (File file : listOfFiles) { + String fullName = file.getName(); // Returns [file_name].[extention] + if (file.isFile()) { + String[] splitName = fullName.split("\\."); // Splitting the file name into seprate parts. + + // If its an auto file then add it to the list. + if (splitName.length > 1 && "path".equals(splitName[1])) { + pathNames.add(splitName[0]); + System.out.println("FOUND PATH: "+splitName[0]); + } + } + } + } + + // Returning the new array + return pathNames; + } + public static ArrayList getAutoNames() { // Creating an ArrayList so I can fill it with auto file names w/o the extention. ArrayList autoNames = new ArrayList(); From 9af27ec4a359cf2fa99ec0ae980bc33c5e09de91 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:22:06 -0600 Subject: [PATCH 088/161] Created paths for DepoSideAuto A and B --- .../pathplanner/autos/DepoSideAutoPathsA.auto | 67 +++++++++++++++++++ .../pathplanner/autos/DepoSideAutoPathsB.auto | 67 +++++++++++++++++++ .../deploy/pathplanner/paths/DSA_A_Bump.path | 54 +++++++++++++++ .../pathplanner/paths/DSA_B_PickupDepo.path | 54 +++++++++++++++ .../pathplanner/paths/DSA_ParkAtWall.path | 54 +++++++++++++++ .../pathplanner/paths/DSA_PickupBwd.path | 54 +++++++++++++++ .../pathplanner/paths/DSA_PickupFwd.path | 54 +++++++++++++++ .../src/main/deploy/pathplanner/settings.json | 3 +- 8 files changed, 406 insertions(+), 1 deletion(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsA.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsB.auto create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupBwd.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupFwd.path diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsA.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsA.auto new file mode 100644 index 0000000..72bafba --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsA.auto @@ -0,0 +1,67 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "named", + "data": { + "name": "CrossBumpFwd" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_PickupFwd" + } + }, + { + "type": "named", + "data": { + "name": "RotateOtherSide" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_PickupBwd" + } + }, + { + "type": "named", + "data": { + "name": "CrossBumpBwd" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_ParkAtWall" + } + }, + { + "type": "named", + "data": { + "name": "Shoot" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_A_Bump" + } + }, + { + "type": "named", + "data": { + "name": "CrossBumpFwd" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsB.auto b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsB.auto new file mode 100644 index 0000000..d26d255 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/autos/DepoSideAutoPathsB.auto @@ -0,0 +1,67 @@ +{ + "version": "2025.0", + "command": { + "type": "sequential", + "data": { + "commands": [ + { + "type": "named", + "data": { + "name": "CrossBumpFwd" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_PickupFwd" + } + }, + { + "type": "named", + "data": { + "name": "RotateOtherSide" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_PickupBwd" + } + }, + { + "type": "named", + "data": { + "name": "CrossBumpBwd" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_ParkAtWall" + } + }, + { + "type": "named", + "data": { + "name": "Shoot" + } + }, + { + "type": "path", + "data": { + "pathName": "DSA_B_PickupDepo" + } + }, + { + "type": "named", + "data": { + "name": "Shoot" + } + } + ] + } + }, + "resetOdom": false, + "folder": null, + "choreoAuto": false +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path new file mode 100644 index 0000000..f6fd8a4 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.63, + "y": 7.465 + }, + "prevControl": null, + "nextControl": { + "x": 0.7904815091648096, + "y": 7.273308359034138 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 3.5256923076923092, + "y": 5.930397435897436 + }, + "prevControl": { + "x": 2.2220361885581448, + "y": 5.930397435897436 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 1.0, + "rotation": 0.0 + }, + "reversed": false, + "folder": "DepotSideAuto", + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path new file mode 100644 index 0000000..195afa5 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.63, + "y": 7.465 + }, + "prevControl": null, + "nextControl": { + "x": 0.6177871629962063, + "y": 7.215298484961908 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.7581794871794887, + "y": 4.942 + }, + "prevControl": { + "x": 0.2814230769230787, + "y": 5.337358974358976 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": "DepotSideAuto", + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path new file mode 100644 index 0000000..f079cfa --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.3047307692307704, + "y": 6.046679487179488 + }, + "prevControl": null, + "nextControl": { + "x": 1.3861025641025657, + "y": 6.058307692307692 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.6302692307692321, + "y": 7.4653205128205125 + }, + "prevControl": { + "x": 0.7359905971020129, + "y": 7.238774727821696 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0.2, + "rotation": 0.0 + }, + "reversed": true, + "folder": "DepotSideAuto", + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupBwd.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupBwd.path new file mode 100644 index 0000000..9a7b16b --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupBwd.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 7.596, + "y": 5.151 + }, + "prevControl": null, + "nextControl": { + "x": 7.346, + "y": 5.151 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 5.688538461538462, + "y": 5.151 + }, + "prevControl": { + "x": 5.938538461538462, + "y": 5.151 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 1.0, + "rotation": 0.0 + }, + "reversed": true, + "folder": "DepotSideAuto", + "idealStartingState": { + "velocity": 1.0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupFwd.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupFwd.path new file mode 100644 index 0000000..5d3e540 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_PickupFwd.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 6.095525641025643, + "y": 6.116448717948718 + }, + "prevControl": null, + "nextControl": { + "x": 7.363, + "y": 6.3606410256410255 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 7.595564102564104, + "y": 5.151307692307693 + }, + "prevControl": { + "x": 7.595564102564104, + "y": 5.401307692307693 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": "DepotSideAuto", + "idealStartingState": { + "velocity": 1.0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json index f9f06f1..6469045 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json @@ -3,7 +3,8 @@ "robotLength": 0.9, "holonomicMode": false, "pathFolders": [ - "Gather" + "Gather", + "DepotSideAuto" ], "autoFolders": [], "defaultMaxVel": 1.0, From d5e7d7b63691997db21a8ddb8d9ab3171a22c32c Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:22:37 -0600 Subject: [PATCH 089/161] Created Skeleton Depo Side Auto A --- .../main/java/frc/robot/RobotContainer.java | 12 -- .../commands/autoCommands/CorralAndShoot.java | 3 + .../commands/autoCommands/DepoSideAutoA.java | 137 ++++++++++++++++++ .../frc/robot/commands/util/AutoFromList.java | 9 -- 2026-Rebuilt/todo_stuff.txt | 22 ++- 5 files changed, 157 insertions(+), 26 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index b9100bc..b2c8917 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -10,14 +10,8 @@ import java.util.function.BooleanSupplier; import com.ctre.phoenix6.hardware.TalonFX; -import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.auto.NamedCommands; -import com.pathplanner.lib.commands.PathPlannerAuto; -import com.pathplanner.lib.commands.PathfindThenFollowPath; import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.path.PathConstraints; -import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.util.FlippingUtil; import com.pathplanner.lib.util.PathPlannerLogging; import com.studica.frc.AHRS; import com.studica.frc.AHRS.NavXComType; @@ -36,7 +30,6 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; @@ -49,18 +42,13 @@ import frc.robot.subsystems.IntakeSubsystem; import frc.robot.subsystems.ClimbL1Subsystem; import frc.robot.subsystems.LimelightSubsystem; -import frc.robot.utils.AutoCommands; import frc.robot.utils.HubUtils; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; import frc.robot.commands.autoCommands.CorralAndShoot; -import frc.robot.commands.autoCommands.DeadreckonForward; -import frc.robot.commands.autoCommands.DriveForwardFromPos; -import frc.robot.commands.autoCommands.POTFtoPoint; import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.CancelDriveCommand; -import frc.robot.commands.util.PathfindThenAutoCommand; import frc.robot.Constants.*; /** diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java index 4082836..d772184 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java @@ -57,8 +57,11 @@ public CorralAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstima @Override public void initialize() { // Init the new sequence + + // !! DO NOT DO THIS!! LOOK AT "DepoSideAutoA.java" FOR A BETTER REFRENCE !! ArrayList sequence = new ArrayList(m_baseSequence); sequence.set(1, new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed)); + // !! DO NOT DO THIS!! LOOK AT "DepoSideAutoA.java" FOR A BETTER REFRENCE !! // Run the command Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java new file mode 100644 index 0000000..0fba440 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java @@ -0,0 +1,137 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.ExtendIntakeCommand; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.commands.StartIntakeCommand; +import frc.robot.commands.StartLiftCommand; +import frc.robot.commands.StopIntakeCommand; +import frc.robot.commands.StopLiftCommand; +import frc.robot.commands.util.AutoFromList; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class DepoSideAutoA extends Command { + // The sequance of the command, any "*" are place holders for commands. + private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( + "DSA_PickupFwd", + "DSA_PickupBwd", + "DSA_ParkAtWall", + "DSA_A_Bump" + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new DepoSideAutoA. + */ + public DepoSideAutoA(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_preloadPaths) { + if (item instanceof String && (String) item != "*") { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // Get target rotation + Rotation2d targetRotation; + if (m_isRed.getAsBoolean() == true) { + targetRotation = new Rotation2d(0); // on red, aim at blue wall + } else { + targetRotation = new Rotation2d(180); // on blue, aim at red wall + } + + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + new ExtendIntakeCommand(null), // Extend Intake + new InstantCommand(), // Drive Over bump fwd + new InstantCommand(), // Relocate + + // Start Pickup \\ + new StartIntakeCommand(null), // Trigger pickup + new StartLiftCommand(null), // Trigger Lift + "DSA_PickupFwd", + + // End Pickup \\ + new StopIntakeCommand(null), // Disable Pickup + new StopLiftCommand(null), // Disable Lift + + // Ready shoot & travel \\ + new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRotation, 1), // Aim at other wall + "DSA_PickupBwd", + new InstantCommand(), // Spin-up flywheel?? (Might have better location.) + new InstantCommand(), // Drive over bump bwd + new InstantCommand(), // Relocate + "DSA_ParkAtWall", + new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed), // Aim at hub + + // Shoot all balls \\ + new InstantCommand(), // Full engage flywheel or wtv + new StartLiftCommand(null), + + // Ramp down flywheel \\ + new StopLiftCommand(null), + new InstantCommand(), // Disable flywheel + + // Get ready to pickup when auto ends \\ + "DSA_A_Bump", + new InstantCommand(), // Drive over bump fwd + new InstantCommand() // Relocate + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 4175fa2..10c07c8 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -1,7 +1,5 @@ package frc.robot.commands.util; -import java.io.Console; -import java.nio.file.Path; import java.util.List; import java.util.function.BooleanSupplier; @@ -9,8 +7,6 @@ import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.path.PathPoint; -import com.pathplanner.lib.path.RotationTarget; import com.pathplanner.lib.path.Waypoint; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; @@ -19,7 +15,6 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.ConditionalCommand; import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.commands.RotateToRotation2D; @@ -142,10 +137,6 @@ public void initialize() { PathPlannerPath newPath = new PathPlannerPath(waypoints, path.getGlobalConstraints(), path.getIdealStartingState(), path.getGoalEndState()); Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); - System.out.println(" -- scheduling everyhting else --"); - System.out.println(" -- scheduling everyhting else --"); - System.out.println(" -- scheduling everyhting else --"); - System.out.println(" -- scheduling everyhting else --"); CommandScheduler.getInstance().schedule(newPathCommand); }); diff --git a/2026-Rebuilt/todo_stuff.txt b/2026-Rebuilt/todo_stuff.txt index 5515a36..ec5f152 100644 --- a/2026-Rebuilt/todo_stuff.txt +++ b/2026-Rebuilt/todo_stuff.txt @@ -1,6 +1,18 @@ -pathfind and follow path w/ autos: -1. pop out the first path. -2. pathfind follow path w/ first path in list. -3. profit +Depo Side Auto: +1. Deadreackon forward for x meters (over bump) +2. Relocate +3. DSA_PickupFwd +4. Face opponent wall +5. DSA_PickupBwd +6. Deadreckon backward for x meters (over bump) +7. Relocate +8. DSA_ParkAtWall +9. Aim & Shoot -make the path update to the one selected on the gui w/ some sort of selector event \ No newline at end of file +10A. Drive to Bump +11A. Deadreckon Forward +12A. Relocate +13A. Drive to balls + +10B. Pickup Depo +11B. Aim & Shoot \ No newline at end of file From fb1f1ffea8e7d65b13455a3c88568ee98f47a20b Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:23:18 -0600 Subject: [PATCH 090/161] Fixed an issue with the config used in the DepoSideAutoA --- .../java/frc/robot/commands/autoCommands/DepoSideAutoA.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java index 0fba440..4fb87a7 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java @@ -113,7 +113,7 @@ public void initialize() { )); // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, false, false); CommandScheduler.getInstance().schedule(auto); } From 3008ea572135d5eb349f16844d439575f16d1004 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:25:48 -0600 Subject: [PATCH 091/161] Added clarfication comments to DepoSideAutoA --- .../java/frc/robot/commands/autoCommands/DepoSideAutoA.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java index 4fb87a7..83d170a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java @@ -75,6 +75,7 @@ public void initialize() { } // Init the new sequence + // TODO: Replace placeholder InstantCommands with real ones. ArrayList sequence = new ArrayList(Arrays.asList( new ExtendIntakeCommand(null), // Extend Intake new InstantCommand(), // Drive Over bump fwd @@ -83,7 +84,7 @@ public void initialize() { // Start Pickup \\ new StartIntakeCommand(null), // Trigger pickup new StartLiftCommand(null), // Trigger Lift - "DSA_PickupFwd", + "DSA_PickupFwd", // ⚠️⚠️ Might have an issue with location being to far from this path ⚠️⚠️ // End Pickup \\ new StopIntakeCommand(null), // Disable Pickup @@ -95,7 +96,7 @@ public void initialize() { new InstantCommand(), // Spin-up flywheel?? (Might have better location.) new InstantCommand(), // Drive over bump bwd new InstantCommand(), // Relocate - "DSA_ParkAtWall", + "DSA_ParkAtWall", // ⚠️⚠️ Might have an issue with location being to far from this path ⚠️⚠️ new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed), // Aim at hub // Shoot all balls \\ From 3f05a7a561d17982936dd6631bd0a0ecd10fc18a Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 2 Mar 2026 19:27:18 -0600 Subject: [PATCH 092/161] raahhh comments --- .../java/frc/robot/commands/autoCommands/DepoSideAutoA.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java index 83d170a..96c2821 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java @@ -26,7 +26,7 @@ /** An example command that uses an example subsystem. */ public class DepoSideAutoA extends Command { - // The sequance of the command, any "*" are place holders for commands. + // The pathplanner paths that get pre-loaded for quicker load. private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( "DSA_PickupFwd", "DSA_PickupBwd", @@ -51,7 +51,7 @@ public DepoSideAutoA(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimat // warm-up for quick load later on for (Object item : m_preloadPaths) { - if (item instanceof String && (String) item != "*") { + if (item instanceof String) { try { PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); Command command = AutoBuilder.followPath(path); From 9ed571447af535dd760c02155432ceca95971186 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 2 Mar 2026 20:53:14 -0600 Subject: [PATCH 093/161] Got backup into wall working, need to look into drive in a line. --- .../pathplanner/paths/DSA_ParkAtWall.path | 4 +- .../pathplanner/paths/ParkAtWallTest.path | 54 ++++++++++++ .../main/java/frc/robot/RobotContainer.java | 23 +++-- .../commands/autoCommands/BackupAndShoot.java | 78 +++++++++++++++++ .../commands/autoCommands/DSA_BackupTest.java | 85 +++++++++++++++++++ ...dFromPos.java => DriveInALineFromPos.java} | 9 +- .../frc/robot/commands/util/AutoFromList.java | 9 +- 7 files changed, 240 insertions(+), 22 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java rename 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/{DriveForwardFromPos.java => DriveInALineFromPos.java} (88%) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path index f079cfa..b088437 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_ParkAtWall.path @@ -8,8 +8,8 @@ }, "prevControl": null, "nextControl": { - "x": 1.3861025641025657, - "y": 6.058307692307692 + "x": 1.3860289708154356, + "y": 6.046679487179488 }, "isLocked": false, "linkedName": null diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path new file mode 100644 index 0000000..985f521 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.3047307692307704, + "y": 6.046679487179488 + }, + "prevControl": null, + "nextControl": { + "x": 1.3860289708154356, + "y": 6.046679487179488 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 0.6302692307692321, + "y": 7.4653205128205125 + }, + "prevControl": { + "x": 0.7359905971020129, + "y": 7.238774727821696 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0.2, + "rotation": 0.0 + }, + "reversed": true, + "folder": null, + "idealStartingState": { + "velocity": 0.5, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index b2c8917..a7c5111 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -46,7 +46,9 @@ import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; +import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.CorralAndShoot; +import frc.robot.commands.autoCommands.DSA_BackupTest; import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -169,23 +171,18 @@ private void configureAutos() { m_autoChooser = new SendableChooser(); // Init Autos - m_autoChooser.addOption("Corral and Park", - new AutoFromList( - new ArrayList(Arrays.asList( - "GatherCorralShootVel", - "GatherCorralVelTest", - "GatherCorralVelTest2" - )), - m_constraints, - driveSubsystem, - m_PoseEstimator - ) - ); - m_autoChooser.addOption("Corral and Shoot", new CorralAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); + m_autoChooser.addOption("DSA Backup Test", + new DSA_BackupTest(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + ); + + m_autoChooser.addOption("Backup And Shoot", + new BackupAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + ); + // Warm up Pathfinder CommandScheduler.getInstance().schedule( PathfindingCommand.warmupCommand() diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java new file mode 100644 index 0000000..4334576 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java @@ -0,0 +1,78 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.path.PathConstraints; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.util.AutoFromList; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class BackupAndShoot extends Command { + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new BackupAndShoot. + */ + public BackupAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + //new InstantCommand(), // Spin-up flywheel + new DriveInALineFromPos(m_PoseEstimator, 2, true), + + // Shoot all balls \\ + new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed)//, // Aim at hub + //new InstantCommand(), // Full engage flywheel + //new StartLiftCommand(null), + + // Some sort of wait command \\ + + // Ramp down flywheel \\ + //new StopLiftCommand(null), + //new InstantCommand() // Disable flywheel + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, false, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java new file mode 100644 index 0000000..c97d2aa --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java @@ -0,0 +1,85 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.util.AutoFromList; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class DSA_BackupTest extends Command { + private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( + "ParkAtWallTest" + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new DSA_BackupTest. + */ + public DSA_BackupTest(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_preloadPaths) { + if (item instanceof String) { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + "ParkAtWallTest", + new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed) // Aim at hub + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveForwardFromPos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java similarity index 88% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveForwardFromPos.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java index f7fbe44..45c6500 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveForwardFromPos.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java @@ -15,19 +15,21 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; /** An example command that uses an example subsystem. */ -public class DriveForwardFromPos extends Command { +public class DriveInALineFromPos extends Command { private final DifferentialDrivePoseEstimator m_poseEstimator; private double m_targetDistance = 0.0; + private Boolean m_reversed = false; /** * Creates a new DriveForward2mFromPos. * * @param subsystem The subsystem used by this command. */ - public DriveForwardFromPos(DifferentialDrivePoseEstimator poseEstimator, double targetDistance) + public DriveInALineFromPos(DifferentialDrivePoseEstimator poseEstimator, double targetDistance, Boolean reversed) { m_poseEstimator = poseEstimator; m_targetDistance = targetDistance; + m_reversed = reversed; } // Called when the command is initially scheduled. @@ -70,7 +72,8 @@ public void initialize() { waypoints, constraints, null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. - new GoalEndState(0.0, currentRotation) // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. + new GoalEndState(0.0, currentRotation), // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. + m_reversed ); // Prevent the path from being flipped if the coordinates are already correct diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 10c07c8..de8608f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -1,5 +1,6 @@ package frc.robot.commands.util; +import java.io.Console; import java.util.List; import java.util.function.BooleanSupplier; @@ -12,6 +13,7 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; @@ -105,6 +107,8 @@ public void initialize() { // needed Values Pose2d pathStartPose = path.getStartingDifferentialPose(); Rotation2d targetRot = pathStartPose.getRotation(); + System.out.println("Target ROT: " + String.valueOf(targetRot.getDegrees())); + BooleanSupplier conditional = () -> { Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); double diff = Math.abs((targetRot.minus(currentRot)).getDegrees()); @@ -134,7 +138,7 @@ public void initialize() { pathPoses.set(0, currentPose); List waypoints = PathPlannerPath.waypointsFromPoses(pathPoses); - PathPlannerPath newPath = new PathPlannerPath(waypoints, path.getGlobalConstraints(), path.getIdealStartingState(), path.getGoalEndState()); + PathPlannerPath newPath = new PathPlannerPath(waypoints, path.getGlobalConstraints(), path.getIdealStartingState(), path.getGoalEndState(), path.isReversed()); Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); CommandScheduler.getInstance().schedule(newPathCommand); @@ -150,9 +154,6 @@ public void initialize() { // add to group precommandGroup.addCommands(pathfinderCommand, conditonalCommand, testCommand); - // Command pathfinderCommand = AutoBuilder.pathfindThenFollowPath(path, m_constraints); - // commandGroup.addCommands(pathfinderCommand); - pathFinded = true; } else { Command pathCommand = AutoBuilder.followPath(path); From da17a1733c10bd43f015a82f6a7837b578cc8d8c Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Mon, 2 Mar 2026 20:56:56 -0600 Subject: [PATCH 094/161] Tested bulk move code and added test mode interface This also removes the indexer motor which is now driven by the lift motor. --- .../src/main/java/frc/robot/Constants.java | 4 +- .../src/main/java/frc/robot/Robot.java | 6 +- .../main/java/frc/robot/RobotContainer.java | 11 + ...Command.java => StartBulkMoveCommand.java} | 14 +- .../robot/commands/StopBulkMoveCommand.java | 48 +++++ .../subsystems/IndexerBulkSubsystem.java | 66 ++++-- .../robot/subsystems/LauncherSubsystem.java | 4 +- 2026-Rebuilt/testmode.json | 200 ++++++++++++++++++ 8 files changed, 323 insertions(+), 30 deletions(-) rename 2026-Rebuilt/src/main/java/frc/robot/commands/{BulkMoveCommand.java => StartBulkMoveCommand.java} (70%) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java create mode 100644 2026-Rebuilt/testmode.json diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 3502482..8b42660 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -198,12 +198,10 @@ public static class LauncherConstants { } public static class IndexerBulkConstants { - public static int kIndexerMotorCANID = 50; - public static int kBulkMoveMotorCANID = 51; + public static int kBulkMoveMotorCANID = 50; // Raw motor speeds in range [-1.0,1.0] public static final double kBulkMoveMotorSpeed = 0.3; - public static double kIndexerMotorSpeed = 0.3; // Beam break sensor to detect fuel at the indexer. public static final int kLowerFuelSensorChannel = 1; diff --git a/2026-Rebuilt/src/main/java/frc/robot/Robot.java b/2026-Rebuilt/src/main/java/frc/robot/Robot.java index 3978de7..2dbc3e2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Robot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Robot.java @@ -103,14 +103,18 @@ public void teleopPeriodic() {} public void testInit() { // Cancels all running commands at the start of test mode. CommandScheduler.getInstance().cancelAll(); + m_robotContainer.testInit(); } /** This function is called periodically during test mode. */ @Override - public void testPeriodic() {} + public void testPeriodic() { + m_robotContainer.testPeriodic(); + } /** This function is called once when the robot is first started up. */ @Override + public void simulationInit() {} /** This function is called periodically whilst in simulation. */ diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index df511ad..24a599c 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -472,4 +472,15 @@ public void disabledPeriodic() { public Command getAutonomousCommand() { return m_autoChooser.getSelected(); } + + public void testInit() { + + } + + public void testPeriodic() { + if (m_indexerBulkSubsystem.isPresent()) + { + m_indexerBulkSubsystem.get().testPeriodic(); + } + } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java similarity index 70% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java index 0d99ab8..aba9763 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/BulkMoveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java @@ -1,22 +1,22 @@ package frc.robot.commands; import edu.wpi.first.wpilibj2.command.Command; -import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.IndexerBulkSubsystem; /** * - * Stop the launcher lift motor and spin down the flywheel. + * Start bulk move. * **/ -public class StartLiftCommand extends Command { - private final LauncherSubsystem m_subsystem; +public class StartBulkMoveCommand extends Command { + private final IndexerBulkSubsystem m_subsystem; /** - * Creates a new StartLiftCommand. + * Creates a new StartBulkMoveCommand. * * @param subsystem The subsystem used by this command. */ - public StartLiftCommand(LauncherSubsystem subsystem) + public StartBulkMoveCommand(IndexerBulkSubsystem subsystem) { m_subsystem = subsystem; @@ -27,7 +27,7 @@ public StartLiftCommand(LauncherSubsystem subsystem) // Called when the command is initially scheduled. @Override public void initialize() { - m_subsystem.startLift(); + m_subsystem.startBulkTransfer(); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java new file mode 100644 index 0000000..f079f91 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java @@ -0,0 +1,48 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IndexerBulkSubsystem; + +/** + * + * Start bulk move. + * + **/ +public class StopBulkMoveCommand extends Command { + private final IndexerBulkSubsystem m_subsystem; + + /** + * Creates a new StopBulkMoveCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StopBulkMoveCommand(IndexerBulkSubsystem subsystem) + { + m_subsystem = subsystem; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_subsystem.stopBulkTransfer(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index f68b67b..2ec927a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -11,49 +11,61 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; import edu.wpi.first.wpilibj.DigitalInput; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.Constants.IndexerBulkConstants; -import com.ctre.phoenix6.hardware.TalonFX; + +import com.ctre.phoenix6.StatusCode; +import com.ctre.phoenix6.configs.TalonFXSConfiguration; import com.ctre.phoenix6.hardware.TalonFXS; +import com.ctre.phoenix6.signals.MotorArrangementValue; public class IndexerBulkSubsystem extends SubsystemBase { private final DigitalInput m_Sensor = new DigitalInput(IndexerBulkConstants.kLowerFuelSensorChannel); - private TalonFX m_motorIndexer; private TalonFXS m_motorBulk; + private Boolean m_bulkStarted = false; /** Creates a new IndexerBulkSubsystem. */ public IndexerBulkSubsystem() throws Exception { - m_motorIndexer = new TalonFX(IndexerBulkConstants.kIndexerMotorCANID); - if (!m_motorIndexer.isConnected()) - { - throw new Exception("Indexer motor is not present."); - } - m_motorBulk = new TalonFXS(IndexerBulkConstants.kIndexerMotorCANID); + + m_motorBulk = new TalonFXS(IndexerBulkConstants.kBulkMoveMotorCANID); if (!m_motorBulk.isConnected()) { throw new Exception("Bult transport motor is not present."); } + + TalonFXSConfiguration motorConfig = new TalonFXSConfiguration(); + motorConfig.Commutation.MotorArrangement = MotorArrangementValue.Minion_JST; + StatusCode status = StatusCode.StatusCodeNotInitialized; + for (int i = 0; i < 5; ++i) { + status = m_motorBulk.getConfigurator().apply(motorConfig); + System.out.println("bulk transfer config attempt #" + (i+1) + ": " + status.toString()); + if (status.isOK()) break; + } + if (!status.isOK()) { + System.out.println("Could not apply configs for bulk tranfer motor, error code: " + status.toString()); + } + + SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); + SmartDashboard.putBoolean("IndexerBulk FuelPresent", false); + + // Test mode controls + SmartDashboard.putBoolean("IndexerBulk TestBulk", false); } // Runs the belts that transfer the fuel from bulk storage to the indexer. public void startBulkTransfer() { m_motorBulk.set(IndexerBulkConstants.kBulkMoveMotorSpeed); + m_bulkStarted = true; + SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); } // Stops the belts in bulk storage. public void stopBulkTransfer() { m_motorBulk.set(0.0); - } - -// Spins the indexer shaft which transfers fuel from the indexer to the launcher. - public void startIndexer() { - m_motorIndexer.set(IndexerBulkConstants.kIndexerMotorSpeed); - } - -// Stops spinning the indexer shaft. - public void stopIndexer() { - m_motorIndexer.set(0.0); + m_bulkStarted = false; + SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); } // Returns true if lower fuel sensor detects fuel. @@ -65,10 +77,28 @@ public boolean isFuelPresent() { @Override public void periodic() { // This method will be called once per scheduler run + SmartDashboard.putBoolean("IndexerBulk FuelPresent", this.isFuelPresent()); } @Override public void simulationPeriodic() { // This method will be called once per scheduler run during simulation } + + public void testPeriodic() { + // Set the motor states based on the SmartDashboard test controls. + Boolean BulkOn = SmartDashboard.getBoolean("IndexerBulk TestBulk", false); + + // Turn the bulk transfer on or off depending upon test control, only changing the state if the control actually changed. + if(BulkOn) { + if(!m_bulkStarted) { + this.startBulkTransfer(); + } + } + else { + if(m_bulkStarted) { + this.stopBulkTransfer(); + } + } + } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 0fdd3cc..cb96f76 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -128,7 +128,9 @@ public void setTargetSpeedrpm(double RPM) { m_targetSpeedrpm = RPM; - double desiredRotationsPerSecond = RPM * 60.0; + // changed from multiplying to dividing + + double desiredRotationsPerSecond = RPM / 60.0; SmartDashboard.putNumber("Launcher Set RPM", RPM); SmartDashboard.putNumber("Launcher Set RPS", desiredRotationsPerSecond); diff --git a/2026-Rebuilt/testmode.json b/2026-Rebuilt/testmode.json new file mode 100644 index 0000000..598ac72 --- /dev/null +++ b/2026-Rebuilt/testmode.json @@ -0,0 +1,200 @@ +{ + "version": 1.0, + "grid_size": 128, + "tabs": [ + { + "name": "Toaster Testing", + "grid_layout": { + "layouts": [], + "containers": [ + { + "title": "Drive Commands", + "x": 0.0, + "y": 0.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Drive Commands", + "period": 0.06, + "sort_options": false + } + }, + { + "title": "Auto Chooser", + "x": 0.0, + "y": 128.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Auto Chooser", + "period": 0.06, + "sort_options": false + } + }, + { + "title": "Field", + "x": 1280.0, + "y": 0.0, + "width": 640.0, + "height": 640.0, + "type": "Field", + "properties": { + "topic": "/SmartDashboard/Field", + "period": 0.06, + "field_game": "Rebuilt", + "robot_width": 0.85, + "robot_length": 0.85, + "show_other_objects": true, + "show_trajectories": true, + "field_rotation": 0.0, + "robot_color": 4294198070, + "trajectory_color": 4294967295, + "show_robot_outside_widget": true + } + }, + { + "title": "Pose X (Meter)", + "x": 1536.0, + "y": 640.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose X (Meter)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose Y (Meter)", + "x": 1664.0, + "y": 640.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose Y (Meter)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Pose Theta (Degrees)", + "x": 1792.0, + "y": 640.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pose Theta (Degrees)", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "limelight", + "x": 512.0, + "y": 0.0, + "width": 768.0, + "height": 768.0, + "type": "Camera Stream", + "properties": { + "topic": "/CameraPublisher/limelight", + "period": 0.06, + "rotation_turns": 0 + } + }, + { + "title": "Left Speed (MPS)", + "x": 256.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Right Speed (MPS)", + "x": 384.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Speed (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Left Target (MPS)", + "x": 256.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Left Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Right Target (MPS)", + "x": 384.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Right Target (MPS)", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Hub Distance", + "x": 384.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Hub Distance", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "mt2 Tag Count", + "x": 256.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/mt2 Tag Count", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + } + ] + } + } + ] +} \ No newline at end of file From 403fd133a81756449e2c29d335754f6fdff4c239 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 3 Mar 2026 09:57:21 -0600 Subject: [PATCH 095/161] Moved my path modification logic from AutoFromList into a util --- .../commands/autoCommands/BackupAndShoot.java | 2 - .../frc/robot/commands/util/AutoFromList.java | 12 ++---- .../main/java/frc/robot/utils/PathUtils.java | 39 +++++++++++++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java index 4334576..2b7f719 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java @@ -9,8 +9,6 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; import frc.robot.commands.AimAtHub; import frc.robot.commands.util.AutoFromList; import frc.robot.subsystems.DriveSubsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index de8608f..1ede814 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -1,6 +1,5 @@ package frc.robot.commands.util; -import java.io.Console; import java.util.List; import java.util.function.BooleanSupplier; @@ -8,12 +7,10 @@ import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.path.Waypoint; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; @@ -21,7 +18,8 @@ import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.commands.RotateToRotation2D; import frc.robot.subsystems.DriveSubsystem; - +import frc.robot.utils.PathUtils; +import edu.wpi.first.math.Pair; // Auto From Path Names And Commands public class AutoFromList extends Command { @@ -134,11 +132,7 @@ public void initialize() { Command testCommand = new InstantCommand(() -> { Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - List pathPoses = path.getPathPoses(); - pathPoses.set(0, currentPose); - - List waypoints = PathPlannerPath.waypointsFromPoses(pathPoses); - PathPlannerPath newPath = new PathPlannerPath(waypoints, path.getGlobalConstraints(), path.getIdealStartingState(), path.getGoalEndState(), path.isReversed()); + PathPlannerPath newPath = PathUtils.modifyPath(path, new Pair<>(0, currentPose)); Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); CommandScheduler.getInstance().schedule(newPathCommand); diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java new file mode 100644 index 0000000..4ee8c6f --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java @@ -0,0 +1,39 @@ +package frc.robot.utils; + +import java.util.List; + +import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.path.Waypoint; + +import edu.wpi.first.math.Pair; +import edu.wpi.first.math.geometry.Pose2d; + +public class PathUtils { + /** + * Allows you to do the modification of a path w/o needing to do jankyness + * @param basePath The path that is used as a base. + * @param pointsToModify A pair that represents the index of a point on the path, and the replacement value. + * @return The path with the modified positions. + */ + @SafeVarargs + public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair... pointsToModify) { + List pathPoses = basePath.getPathPoses(); + for (Pair point : pointsToModify) { + Integer index = point.getFirst(); + if (pathPoses.size() > index && index >= 0) { + pathPoses.set(index, point.getSecond()); + } + } + + List waypoints = PathPlannerPath.waypointsFromPoses(pathPoses); + PathPlannerPath newPath = new PathPlannerPath( + waypoints, + basePath.getGlobalConstraints(), + basePath.getIdealStartingState(), + basePath.getGoalEndState(), + basePath.isReversed() + ); + + return newPath; + } +} From d393bff1d0932de17715c2fb9a90e0727911ce19 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:46:27 -0600 Subject: [PATCH 096/161] Added driveauto interupt on joystick input > 0.5 --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 9 +++++++++ .../main/java/frc/robot/commands/RotateToRotation2D.java | 7 ++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 13ceaa0..cd9aa3a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -30,6 +30,7 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; @@ -255,6 +256,14 @@ private void configureBindings() { isRed ) ); + + // cancel the current command running on drive subsystem when + // left y or right x is > half and the default command is not running. + Trigger autoCancelLeftY = new Trigger(() -> (Math.abs(m_driverController.getLeftY()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) + .onTrue(new CancelDriveCommand(driveSubsystem)); + + Trigger autoCancelRightX = new Trigger(() -> (Math.abs(m_driverController.getRightX()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) + .onTrue(new CancelDriveCommand(driveSubsystem)); } // diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java index b12bc8e..79df654 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -68,7 +68,12 @@ public void execute() { // Called once the command ends or is interrupted. @Override public void end(boolean interrupted) { - System.out.println("Ended Rotation fix!"); + if (interrupted) { + System.out.println("Rotation Interrupted!"); + } else { + System.out.println("Rotatation Complete!"); + } + m_driveSubsystem.setDifferentialSpeeds(0, 0); } From 657e6050e435eb367543d572a4971489d769dc61 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Tue, 3 Mar 2026 19:43:32 -0600 Subject: [PATCH 097/161] Added subsystem test mode controls --- .../robot/subsystems/ClimbL1Subsystem.java | 17 +++++++ .../frc/robot/subsystems/IntakeSubsystem.java | 33 ++++++++++++ .../robot/subsystems/LauncherSubsystem.java | 50 +++++++++++++------ 3 files changed, 84 insertions(+), 16 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java index 9944bf2..536f3c9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -27,6 +27,7 @@ public ClimbL1Subsystem() { PneumaticsConstants.kHubType, ClimbL1Constants.kLeftSolenoidChannel); SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); + SmartDashboard.putBoolean("ClimbL1 TestRaise", false); } // Raise the climb arms. @@ -61,6 +62,22 @@ public void periodic() { // This method will be called once per scheduler run } + // raise and lowers climb + public void testPeriodic() { + Boolean RaiseClimb = SmartDashboard.getBoolean("ClimbL1 TestRaise", false); + + if(RaiseClimb) { + if(!m_bRaised) { + this.raiseArms(); + } + } + else { + if(m_bRaised) { + this.lowerArms(); + } + } + } + @Override public void simulationPeriodic() { // This method will be called once per scheduler run during simulation diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index dc749bd..f3bd5f2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -31,6 +31,10 @@ public IntakeSubsystem() throws Exception { SmartDashboard.putBoolean("Intake Extended", m_Extended); SmartDashboard.putBoolean("Intake Running", m_motorRunning); + + // Test mode controlls + SmartDashboard.putBoolean("Intake TestExtend", false); + SmartDashboard.putBoolean("Intake TestRun", false); } // Spins the shaft on the intake that will move fuel into the robot. @@ -74,6 +78,35 @@ public void periodic() { // This method will be called once per scheduler run } + public void testPeriodic() { + // Set the motor states based on the SmartDashboard test controls. + Boolean Extend = SmartDashboard.getBoolean("Intake TestExtend", false); + Boolean Run = SmartDashboard.getBoolean("Intake TestRun", false); + + // Turn the intake on or off depending upon test control, only changing the state if the control actually changed. + if(Run) { + if(!m_motorRunning) { + this.start(); + } + } + else { + if(m_motorRunning) { + this.stop(); + } + } + if(Extend) { + if(!m_Extended) { + this.extend(); + } + } + else { + if(m_Extended) { + this.retract(); + } + } + } + + @Override public void simulationPeriodic() { // This method will be called once per scheduler run during simulation diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index cb96f76..ba0f666 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -17,10 +17,6 @@ import com.ctre.phoenix6.controls.Follower; import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.*; -import com.revrobotics.spark.SparkMax; -import com.revrobotics.spark.SparkBase; -import com.revrobotics.spark.SparkLowLevel.MotorType; - import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import edu.wpi.first.wpilibj.DigitalInput; @@ -34,7 +30,7 @@ public class LauncherSubsystem extends SubsystemBase { private TalonFX m_motorLeader; private TalonFX m_motorFollower; - //private SparkMax m_motorLift; + private TalonFX m_motorLift; private final DigitalInput m_Sensor = new DigitalInput(LauncherConstants.kUpperFuelSensorChannel); @@ -46,23 +42,16 @@ public class LauncherSubsystem extends SubsystemBase { * @throws Exception */ public LauncherSubsystem() throws Exception { - //m_motorLift = new SparkMax(LauncherConstants.kLauncherLiftMotorCANID, MotorType.kBrushless); + m_motorLift = new TalonFX(LauncherConstants.kLauncherLiftMotorCANID); m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); m_motorFollower = new TalonFX(LauncherConstants.kLauncherFlywheelMotor2CANID); // Check that the launcher motors exist and throw an exception if they don't. - if(!m_motorLeader.isConnected() || !m_motorFollower.isConnected()) + if(!m_motorLeader.isConnected() || !m_motorFollower.isConnected() || !m_motorLift.isConnected()) { throw new Exception("At least one launcher motor is not present!"); } - // Ensure that the lift motor is present. - // SparkBase.Faults Faults = m_motorLift.getFaults(); - // if(Faults.can || Faults.firmware || Faults.gateDriver) - // { - // throw new Exception("Lift motor is not present or is reporting a fault!"); - // } - TalonFXConfiguration configs = new TalonFXConfiguration(); /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ @@ -117,6 +106,12 @@ public LauncherSubsystem() throws Exception { // Configure the fuel sensor. // TODO: Add this. + SmartDashboard.putNumber("Launcher RPM", 0.0 ); + SmartDashboard.putNumber("Launcher RPS", 0.0); + + // Test mode controls + SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); + SmartDashboard.putNumber("Launcher TestLiftSpeed", 0.0 ); m_configValid = true; } @@ -162,7 +157,7 @@ public double getTargetSpeedrpm() // public void startLift() { - //m_motorLift.set(LauncherConstants.kLiftMotorSpeed); + m_motorLift.set(LauncherConstants.kLiftMotorSpeed); m_liftRunning = true; } @@ -171,10 +166,24 @@ public void startLift() // public void stopLift() { - //m_motorLift.set(0.0); + m_motorLift.set(0.0); m_liftRunning = false; } + public void setLiftSpeed(double speed) + { + m_motorLift.set(speed); + + if(speed == 0.0) + { + m_liftRunning = false; + } + else + { + m_liftRunning = true; + } + } + // // Determine whether or not the lift motor is running. public boolean isLiftMotorStarted() @@ -205,8 +214,17 @@ public void periodic() { } } + public void testPeriodic() { + double launcherrpm = SmartDashboard.getNumber("Launcher TestRPM", 0.0 ); + double liftspeed = SmartDashboard.getNumber("Launcher TestLiftSpeed", 0.0 ); + + this.setLiftSpeed(liftspeed); + this.setTargetSpeedrpm(launcherrpm); + } + @Override public void simulationPeriodic() { // This method will be called once per scheduler run during simulation + } } From 96d11daf696068ae942af7f53b0e200c1476d3d7 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Tue, 3 Mar 2026 19:49:46 -0600 Subject: [PATCH 098/161] Wired up test mode for all subsystems in RobotContainer --- .../src/main/java/frc/robot/RobotContainer.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index cd9aa3a..6a5b1d1 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -4,8 +4,6 @@ package frc.robot; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Optional; import java.util.function.BooleanSupplier; @@ -30,7 +28,6 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; @@ -50,7 +47,6 @@ import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.CorralAndShoot; import frc.robot.commands.autoCommands.DSA_BackupTest; -import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -420,5 +416,17 @@ public void testPeriodic() { { m_indexerBulkSubsystem.get().testPeriodic(); } + if (m_climbL1Subsystem.isPresent()) + { + m_climbL1Subsystem.get().testPeriodic(); + } + if (m_intakeSubsystem.isPresent()) + { + m_intakeSubsystem.get().testPeriodic(); + } + if (m_launcherSubsystem.isPresent()) + { + m_launcherSubsystem.get().testPeriodic(); + } } } From 5eec791723ea8a8f17ac00bd33bcb690ab814db7 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 3 Mar 2026 20:32:40 -0600 Subject: [PATCH 099/161] Worked on tuning RotateToRotation2D and Pathfinding logic in AutoFromList --- .../{ParkAtWallTest.path => ParkAtWall.path} | 16 ++--- .../main/java/frc/robot/RobotContainer.java | 26 +++---- .../robot/commands/RotateToRotation2D.java | 2 +- ...pTest.java => TravelToCornerAndShoot.java} | 8 +-- .../frc/robot/commands/util/AutoFromList.java | 67 +++++++++++++------ 5 files changed, 70 insertions(+), 49 deletions(-) rename 2026-Rebuilt/src/main/deploy/pathplanner/paths/{ParkAtWallTest.path => ParkAtWall.path} (78%) rename 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/{DSA_BackupTest.java => TravelToCornerAndShoot.java} (90%) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWall.path similarity index 78% rename from 2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path rename to 2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWall.path index 985f521..b433301 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWallTest.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ParkAtWall.path @@ -3,13 +3,13 @@ "waypoints": [ { "anchor": { - "x": 2.3047307692307704, - "y": 6.046679487179488 + "x": 1.6070384615384627, + "y": 6.558320512820512 }, "prevControl": null, "nextControl": { - "x": 1.3860289708154356, - "y": 6.046679487179488 + "x": 1.4469923616223426, + "y": 6.750375832719857 }, "isLocked": false, "linkedName": null @@ -33,8 +33,8 @@ "pointTowardsZones": [], "eventMarkers": [], "globalConstraints": { - "maxVelocity": 1.0, - "maxAcceleration": 1.0, + "maxVelocity": 3.0, + "maxAcceleration": 2.0, "maxAngularVelocity": 540.0, "maxAngularAcceleration": 720.0, "nominalVoltage": 12.0, @@ -47,8 +47,8 @@ "reversed": true, "folder": null, "idealStartingState": { - "velocity": 0.5, + "velocity": 0.0, "rotation": 0.0 }, - "useDefaultConstraints": true + "useDefaultConstraints": false } \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index cd9aa3a..6e21efa 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -49,7 +49,7 @@ import frc.robot.commands.DriveCommands.TurnLeftTest; import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.CorralAndShoot; -import frc.robot.commands.autoCommands.DSA_BackupTest; +import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -172,15 +172,11 @@ private void configureAutos() { m_autoChooser = new SendableChooser(); // Init Autos - m_autoChooser.addOption("Corral and Shoot", + m_autoChooser.addOption("[INDEV] Corral and Shoot", new CorralAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); - m_autoChooser.addOption("DSA Backup Test", - new DSA_BackupTest(driveSubsystem, m_PoseEstimator, isRed, m_constraints) - ); - - m_autoChooser.addOption("Backup And Shoot", + m_autoChooser.addOption("[INDEV] Backup And Shoot", new BackupAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); @@ -248,21 +244,21 @@ private void configureBindings() { m_driverController.b().onTrue(new TurnLeftTest(driveSubsystem)); // Aim to Hub + m_driverController.y().onTrue( + new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, isRed) + ); + + // Travel to corner and shoot m_driverController.x().onTrue( - new AimAtHub( - driveSubsystem, - m_PoseEstimator, - 2.0, - isRed - ) + new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); // cancel the current command running on drive subsystem when // left y or right x is > half and the default command is not running. - Trigger autoCancelLeftY = new Trigger(() -> (Math.abs(m_driverController.getLeftY()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) + new Trigger(() -> (Math.abs(m_driverController.getLeftY()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) .onTrue(new CancelDriveCommand(driveSubsystem)); - Trigger autoCancelRightX = new Trigger(() -> (Math.abs(m_driverController.getRightX()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) + new Trigger(() -> (Math.abs(m_driverController.getRightX()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) .onTrue(new CancelDriveCommand(driveSubsystem)); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java index 79df654..d22312b 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -17,7 +17,7 @@ public class RotateToRotation2D extends Command { // Bounds are [0, 1) in interval notation. This effects the steepness of // the curve that is used to slow the robot as it approches the target. - private double speedExp = 0.98; + private double speedExp = 0.99; /** * Creates a new RotateToRotation2D. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java similarity index 90% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java index c97d2aa..7d315cb 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DSA_BackupTest.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java @@ -17,9 +17,9 @@ import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ -public class DSA_BackupTest extends Command { +public class TravelToCornerAndShoot extends Command { private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( - "ParkAtWallTest" + "ParkAtWall" )); // Pass-ins @@ -31,7 +31,7 @@ public class DSA_BackupTest extends Command { /** * Creates a new DSA_BackupTest. */ - public DSA_BackupTest(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + public TravelToCornerAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { m_DriveSubsystem = driveSubsystem; m_PoseEstimator = poseEstimator; m_isRed = isRed; @@ -56,7 +56,7 @@ public DSA_BackupTest(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstima public void initialize() { // Init the new sequence ArrayList sequence = new ArrayList(Arrays.asList( - "ParkAtWallTest", + "ParkAtWall", new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed) // Aim at hub )); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 1ede814..363235a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -19,6 +19,7 @@ import frc.robot.commands.RotateToRotation2D; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.PathUtils; +import frc.robot.utils.PoseDiff; import edu.wpi.first.math.Pair; // Auto From Path Names And Commands @@ -103,16 +104,13 @@ public void initialize() { if (pathFinded == false) { // needed Values - Pose2d pathStartPose = path.getStartingDifferentialPose(); - Rotation2d targetRot = pathStartPose.getRotation(); - System.out.println("Target ROT: " + String.valueOf(targetRot.getDegrees())); + Pose2d pathStartPose = path.getStartingDifferentialPose(); // Accounts for rotation - BooleanSupplier conditional = () -> { - Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); - double diff = Math.abs((targetRot.minus(currentRot)).getDegrees()); + Rotation2d directionRot = pathStartPose.getRotation(); + System.out.println("Direction ROT: " + String.valueOf(directionRot.getDegrees())); - return diff <= 45; - }; + PoseDiff dPose = new PoseDiff(m_poseEstimator.getEstimatedPosition(), pathStartPose); + Rotation2d rotToPoint = new Rotation2d(Math.atan2(dPose.y, dPose.x)); // pathfind command Command pathfinderCommand = AutoBuilder.pathfindToPose( @@ -121,15 +119,7 @@ public void initialize() { path.getIdealStartingState().velocityMPS() ); - // path and rotate stuff - Command rotateCommand = new RotateToRotation2D( - m_DriveSubsystem, - m_poseEstimator, - targetRot, - 2.0 - ); - - Command testCommand = new InstantCommand(() -> { + Command postPathfindCommand = new InstantCommand(() -> { Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); PathPlannerPath newPath = PathUtils.modifyPath(path, new Pair<>(0, currentPose)); @@ -139,14 +129,49 @@ public void initialize() { }); // decide what to do - Command conditonalCommand = Commands.either( + Command conditonalCommand_90 = Commands.either( + new InstantCommand(), + new RotateToRotation2D( + m_DriveSubsystem, + m_poseEstimator, + rotToPoint, + 2.0 + ), + () -> { + Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); + double diff = Math.abs((rotToPoint.minus(currentRot)).getDegrees()); + + if (diff <= 90) { + System.out.println("GREATER THAN 90! ROTATING!!!"); + } + + return diff <= 90; + } + ); + + Command conditonalCommand_45 = Commands.either( new InstantCommand(), - rotateCommand, - conditional + new RotateToRotation2D( + m_DriveSubsystem, + m_poseEstimator, + directionRot, + 2.0 + ), + () -> { + Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); + double diff = Math.abs((directionRot.minus(currentRot)).getDegrees()); + + return diff <= 45; + } ); // add to group - precommandGroup.addCommands(pathfinderCommand, conditonalCommand, testCommand); + precommandGroup.addCommands( + conditonalCommand_90, + pathfinderCommand, + conditonalCommand_45, + postPathfindCommand + ); pathFinded = true; } else { From 44470b8f254f7541bcf83a093730b7308e488e91 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:32:11 -0600 Subject: [PATCH 100/161] Cleanup of recent in-dev files Deleted PathfindThenAutoCommand (replaced by AutoFromList), Added documentation to AutoFromList, and removed unused import warnings. --- .../robot/commands/RotateToRotation2D.java | 2 - .../frc/robot/commands/util/AutoFromList.java | 39 +++++-- .../util/PathfindThenAutoCommand.java | 101 ------------------ .../frc/robot/subsystems/DriveSubsystem.java | 1 - .../robot/subsystems/LimelightSubsystem.java | 1 - .../main/java/frc/robot/utils/PathUtils.java | 3 +- 6 files changed, 32 insertions(+), 115 deletions(-) delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java index d22312b..73ca7cf 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -1,7 +1,5 @@ package frc.robot.commands; -import java.io.Console; - import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 363235a..88755bc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -1,7 +1,6 @@ package frc.robot.commands.util; import java.util.List; -import java.util.function.BooleanSupplier; import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.commands.PathPlannerAuto; @@ -33,8 +32,12 @@ public class AutoFromList extends Command { /** * Creates and runs a new auto from a list of path names and commands. * Any list with a command can only be ran once due to how the scheudler works. + * By default this command pathfinds to the first path and warm-ups the paths itself. * * @param sequence A list of path names (strings) and commands to run in order. + * @param constraints The constraints the pathfinder segment of the auto uses. + * @param driveSubsystem The driveSubsystem, pass-ins for rotation corrections. + * @param poseEstimator The pose estimator, used to get the robots location. */ public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator) { @@ -47,6 +50,17 @@ public AutoFromList(List sequence, PathConstraints constraints, DriveSub warmup(); } + /** + * Creates and runs a new auto from a list of path names and commands. + * Any list with a command can only be ran once due to how the scheudler works. + * By default this command warm-ups the paths itself. + * + * @param sequence A list of path names (strings) and commands to run in order. + * @param constraints The constraints the pathfinder segment of the auto uses. + * @param driveSubsystem The driveSubsystem, pass-ins for rotation corrections. + * @param poseEstimator The pose estimator, used to get the robots location. + * @param pathfindToFirstpath Should the command pathfind to the first path? + */ public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, boolean pathfindToFirstpath) { m_sequence = sequence; @@ -58,6 +72,17 @@ public AutoFromList(List sequence, PathConstraints constraints, DriveSub warmup(); } + /** + * Creates and runs a new auto from a list of path names and commands. + * Any list with a command can only be ran once due to how the scheudler works. + * + * @param sequence A list of path names (strings) and commands to run in order. + * @param constraints The constraints the pathfinder segment of the auto uses. + * @param driveSubsystem The driveSubsystem, pass-ins for rotation corrections. + * @param poseEstimator The pose estimator, used to get the robots location. + * @param pathfindToFirstpath Should the command pathfind to the first path? + * @param doWarmup Should the command warm-up the paths itself? (If instantiated and ran during run-time, you might want this to be set to false) + */ public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, boolean pathfindToFirstpath, boolean doWarmup) { m_sequence = sequence; @@ -129,7 +154,7 @@ public void initialize() { }); // decide what to do - Command conditonalCommand_90 = Commands.either( + Command rotateTwordPathConditional = Commands.either( new InstantCommand(), new RotateToRotation2D( m_DriveSubsystem, @@ -141,15 +166,11 @@ public void initialize() { Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); double diff = Math.abs((rotToPoint.minus(currentRot)).getDegrees()); - if (diff <= 90) { - System.out.println("GREATER THAN 90! ROTATING!!!"); - } - return diff <= 90; } ); - Command conditonalCommand_45 = Commands.either( + Command rotateTwordStartRotationConditional = Commands.either( new InstantCommand(), new RotateToRotation2D( m_DriveSubsystem, @@ -167,9 +188,9 @@ public void initialize() { // add to group precommandGroup.addCommands( - conditonalCommand_90, + rotateTwordPathConditional, pathfinderCommand, - conditonalCommand_45, + rotateTwordStartRotationConditional, postPathfindCommand ); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java deleted file mode 100644 index 8fc691f..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/PathfindThenAutoCommand.java +++ /dev/null @@ -1,101 +0,0 @@ -package frc.robot.commands.util; - -import java.util.List; -import java.util.function.BooleanSupplier; - -import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.commands.PathPlannerAuto; -import com.pathplanner.lib.path.PathConstraints; -import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.util.FlippingUtil; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; -import frc.robot.commands.RotateToRotation2D; -import frc.robot.subsystems.DriveSubsystem; - -public class PathfindThenAutoCommand extends Command { - private final DriveSubsystem m_driveSubsystem; - private final DifferentialDrivePoseEstimator m_poseEstimator; - private final PathConstraints m_constraints; - private final String m_plannedAutoName; - private final BooleanSupplier m_isRed; - - public PathfindThenAutoCommand(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, String plannedAutoName, BooleanSupplier isRed) - { - m_driveSubsystem = driveSubsystem; - m_poseEstimator = poseEstimator; - m_constraints = constraints; - - m_plannedAutoName = plannedAutoName; - m_isRed = isRed; - } - - @Override - public void initialize() { - // PathPlannerAuto plannedAuto = new PathPlannerAuto(m_plannedAutoName); - // Pose2d startingPose = plannedAuto.getStartingPose(); - - // if (m_isRed.getAsBoolean() == true) { - // startingPose = FlippingUtil.flipFieldPose(startingPose); - // } - - // Command rotateToStartRot = new RotateToRotation2D( - // m_driveSubsystem, - // m_poseEstimator, - // startingPose.getRotation(), - // 3.0 - // ); - - // Command pathfindToStartPose = AutoBuilder.pathfindToPose(startingPose, m_constraints); - // Command pathfindThenAuto = Commands.sequence(pathfindToStartPose, rotateToStartRot, plannedAuto); - - // CommandScheduler.getInstance().schedule(pathfindThenAuto); - - // TODO: Look into named commands - try { - SequentialCommandGroup commandGroup = new SequentialCommandGroup(); - List paths = PathPlannerAuto.getPathGroupFromAutoFile(m_plannedAutoName); - - // check if empty, if it isnt then remove first value - // take the first value and plug it into a Pathfindthenfollowpath - if (!paths.isEmpty()) { - PathPlannerPath path = paths.remove(0); - Command pathfinderCommand = AutoBuilder.pathfindThenFollowPath(path, m_constraints); - commandGroup.addCommands(pathfinderCommand); - } - - // then loop through the rest of the paths and add it to the command group. - for (PathPlannerPath path : paths) { - Command pathCommand = AutoBuilder.followPath(path); - commandGroup.addCommands(pathCommand); - } - - // also check if named commands trasnfer, if not need to figure that out. (trigger?) - - CommandScheduler.getInstance().schedule(commandGroup); - } catch (Exception e) { - // do somthing here - System.out.println("Failed to run " + m_plannedAutoName + ": " + e.toString()); - } - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - // The command automatically ends - return true; - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 42cf5ac..7f7d145 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -16,7 +16,6 @@ import com.ctre.phoenix6.signals.MotorAlignmentValue; import com.ctre.phoenix6.signals.NeutralModeValue; import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.controllers.PPLTVController; import com.studica.frc.AHRS; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 9455053..9d125b0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -3,7 +3,6 @@ // the WPILib BSD license file in the root directory of this project. package frc.robot.subsystems; -import java.io.Console; import java.util.Arrays; import org.ejml.simple.SimpleMatrix; diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java index 4ee8c6f..da75047 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java @@ -10,7 +10,8 @@ public class PathUtils { /** - * Allows you to do the modification of a path w/o needing to do jankyness + * Allows you to do the modification of a path w/o needing to do the jankyness yourself. + * * @param basePath The path that is used as a base. * @param pointsToModify A pair that represents the index of a point on the path, and the replacement value. * @return The path with the modified positions. From fa1508fe654c513df420a15463b27a49dcc6259a Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 6 Mar 2026 20:57:38 -0600 Subject: [PATCH 101/161] Got deadreackoing over the bump working --- .../main/java/frc/robot/RobotContainer.java | 12 ++- .../commands/autoCommands/BackupAndShoot.java | 76 ------------------- ...onForward.java => DeadreckonDistance.java} | 13 ++-- .../autoCommands/DriveInALineFromPos.java | 12 ++- 4 files changed, 25 insertions(+), 88 deletions(-) delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java rename 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/{DeadreckonForward.java => DeadreckonDistance.java} (79%) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 54e02c4..3ba3d92 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -44,8 +44,9 @@ import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; -import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.CorralAndShoot; +import frc.robot.commands.autoCommands.DeadreckonDistance; +import frc.robot.commands.autoCommands.DriveInALineFromPos; import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -172,8 +173,13 @@ private void configureAutos() { new CorralAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); - m_autoChooser.addOption("[INDEV] Backup And Shoot", - new BackupAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + // Test Autos + m_autoChooser.addOption("[TEST] Forward 2 Meters Test", + new DeadreckonDistance(driveSubsystem, 3.0, 2.5) + ); + + m_autoChooser.addOption("[TEST] Backup 2 Meters Test", + new DeadreckonDistance(driveSubsystem, 3.0, -2.5) ); // Warm up Pathfinder diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java deleted file mode 100644 index 2b7f719..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java +++ /dev/null @@ -1,76 +0,0 @@ -package frc.robot.commands.autoCommands; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.function.BooleanSupplier; - -import com.pathplanner.lib.path.PathConstraints; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; -import frc.robot.commands.AimAtHub; -import frc.robot.commands.util.AutoFromList; -import frc.robot.subsystems.DriveSubsystem; - -/** An example command that uses an example subsystem. */ -public class BackupAndShoot extends Command { - // Pass-ins - private final DriveSubsystem m_DriveSubsystem; - private final DifferentialDrivePoseEstimator m_PoseEstimator; - private final BooleanSupplier m_isRed; - private final PathConstraints m_constraints; - - /** - * Creates a new BackupAndShoot. - */ - public BackupAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { - m_DriveSubsystem = driveSubsystem; - m_PoseEstimator = poseEstimator; - m_isRed = isRed; - m_constraints = constraints; - } - - // Called when the command is initially scheduled. - @Override - public void initialize() { - // Init the new sequence - ArrayList sequence = new ArrayList(Arrays.asList( - //new InstantCommand(), // Spin-up flywheel - new DriveInALineFromPos(m_PoseEstimator, 2, true), - - // Shoot all balls \\ - new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 2.0, m_isRed)//, // Aim at hub - //new InstantCommand(), // Full engage flywheel - //new StartLiftCommand(null), - - // Some sort of wait command \\ - - // Ramp down flywheel \\ - //new StopLiftCommand(null), - //new InstantCommand() // Disable flywheel - )); - - // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, false, false); - CommandScheduler.getInstance().schedule(auto); - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() { - - } - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) { - - } - - // Returns true when the command should end. - @Override - public boolean isFinished() { - return true; - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonForward.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonDistance.java similarity index 79% rename from 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonForward.java rename to 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonDistance.java index 1443d6e..00bc6a1 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonForward.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonDistance.java @@ -4,19 +4,20 @@ import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ -public class DeadreckonForward extends Command { +public class DeadreckonDistance extends Command { private final DriveSubsystem m_driveSubsystem; - private final double m_targetDistance; - private final double m_speed; + private double m_targetDistance; + private double m_speed; private double m_startDistance; /** - * Creates a new DriveForward2mFromPos. + * Creates a new DeadreckonDistance. + * To reverse please input a negitive speed value but keep targetDistance positive. * * @param subsystem The subsystem used by this command. */ - public DeadreckonForward(DriveSubsystem driveSubsystem, double targetDistance, double speed) + public DeadreckonDistance(DriveSubsystem driveSubsystem, double targetDistance, double speed) { m_driveSubsystem = driveSubsystem; m_targetDistance = targetDistance; @@ -53,7 +54,7 @@ public void end(boolean interrupted) { // Returns true when the command should end. @Override public boolean isFinished() { - double distanceDiff = avrgDistances() - m_startDistance; + double distanceDiff = Math.abs(avrgDistances() - m_startDistance); // System.out.println(String.valueOf(distanceDiff) + " --> " + String.valueOf(m_targetDistance) + " at " + String.valueOf(m_speed)); if (distanceDiff >= m_targetDistance) { diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java index 45c6500..f55c1c0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java @@ -41,6 +41,10 @@ public void initialize() { Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); Rotation2d currentRotation = currentPose.getRotation(); + if (m_reversed == true) { + m_targetDistance = m_targetDistance * -1.0; + } + double currentX = currentPose.getX(); double currentY = currentPose.getY(); @@ -55,9 +59,11 @@ public void initialize() { // Create a list of waypoints from poses. Each pose represents one waypoint. // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. + Pose2d startPose = new Pose2d(currentX, currentY, currentRotation); + Pose2d endPose = new Pose2d(newX, newY, currentRotation); List waypoints = PathPlannerPath.waypointsFromPoses( - new Pose2d(currentX, currentY, currentRotation), - new Pose2d(newX, newY, currentRotation) + startPose, + endPose ); PathConstraints constraints = new PathConstraints( @@ -65,7 +71,7 @@ public void initialize() { 1.0, 2 * Math.PI, 4 * Math.PI - ); // The constraints for this path. + ); // The constraints for this path. // Create the path using the waypoints created above PathPlannerPath path = new PathPlannerPath( From 96a8bac7689c5c6f44ae223be48779582be30366 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Mar 2026 09:21:13 -0600 Subject: [PATCH 102/161] Wired up launcher fuel sensor to SmartDashboard --- .../java/frc/robot/subsystems/LauncherSubsystem.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index ba0f666..92ecbac 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -25,6 +25,7 @@ public class LauncherSubsystem extends SubsystemBase { private double m_targetSpeedrpm = 0.0; private boolean m_liftRunning = false; + private boolean m_HasFuel = false; private int m_tickCount = 0; private boolean m_configValid = false; @@ -104,10 +105,9 @@ public LauncherSubsystem() throws Exception { LauncherConstants.kMotorsDriveInOppositeDirections ? MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); - // Configure the fuel sensor. - // TODO: Add this. SmartDashboard.putNumber("Launcher RPM", 0.0 ); SmartDashboard.putNumber("Launcher RPS", 0.0); + SmartDashboard.putBoolean("Launcher Has Fuel", m_HasFuel); // Test mode controls SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); @@ -198,19 +198,22 @@ public boolean isLiftMotorStarted() public boolean isFuelAtLauncher() { boolean sensorRead = m_Sensor.get(); - return (sensorRead == LauncherConstants.kUpperFuelSensorIsEmpty) ? false : true; + m_HasFuel = (sensorRead == LauncherConstants.kUpperFuelSensorIsEmpty) ? false : true; + return m_HasFuel; } @Override public void periodic() { // This method will be called once per scheduler run m_tickCount++; + if(m_configValid && ((m_tickCount % LauncherConstants.kTicksPerUpdate) == 0)) { double speedRPS = m_motorLeader.getVelocity().getValueAsDouble(); SmartDashboard.putNumber("Launcher RPM", speedRPS * 60.0); SmartDashboard.putNumber("Launcher RPS", speedRPS); + SmartDashboard.putBoolean("Launcher Has Fuel", isFuelAtLauncher()); } } From ac4f2228378527943b526ee71f290b8931006645 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Mar 2026 10:03:49 -0600 Subject: [PATCH 103/161] Move all subsystem SmartDashboard widget creation to top of constructors The hope is that, by creating all SmartDashboard objects prior to the point where the subsystem constructor can throw an exception (if hardware isn't present), we can populate the network tables and work on Elastic GUI setup prior to having all subsystems present on the robot. --- .../main/java/frc/robot/RobotContainer.java | 31 +++++++++++++------ .../robot/subsystems/ClimbL1Subsystem.java | 30 ++++++++++++------ .../subsystems/IndexerBulkSubsystem.java | 14 +++++---- .../frc/robot/subsystems/IntakeSubsystem.java | 29 ++++++++++------- .../robot/subsystems/LauncherSubsystem.java | 18 ++++++----- 5 files changed, 77 insertions(+), 45 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 3ba3d92..58a75d4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -60,8 +60,8 @@ public class RobotContainer { // The robot's subsystems and commands are defined here... private final Optional m_driveSubsystem; - private final Optional m_intakeSubsystem; - private final Optional m_climbL1Subsystem; + private Optional m_intakeSubsystem; + private Optional m_climbL1Subsystem; private final Optional m_indexerBulkSubsystem; private final Optional m_launcherSubsystem; private final Optional m_pneumaticHub; @@ -124,21 +124,32 @@ public RobotContainer() { // Init pneumatics system and subsystems that rely upon it. m_pneumaticHub = getSubsystem(PneumaticHubWrapper.class); - if (m_pneumaticHub.isPresent()) + Boolean bHasPneumatics = m_pneumaticHub.isPresent(); + + if (bHasPneumatics) { PneumaticHub hub = m_pneumaticHub.get(); hub.enableCompressorAnalog(PneumaticsConstants.kMinPneumaticsPressure, PneumaticsConstants.kMaxPneumaticsPressure); - - m_climbL1Subsystem = getSubsystem(ClimbL1Subsystem.class); - m_intakeSubsystem = getSubsystem(IntakeSubsystem.class); } - else - { - // If there are no pneumatics, there's no climb or intake. + + // Instantiate subsystems that rely upon pneumatics. We want to run + // the constructors even if the pneumatic hub is not present so that + // they can create SmartDashboard objects we want to use later. + try { + ClimbL1Subsystem climb = new ClimbL1Subsystem(bHasPneumatics); + m_climbL1Subsystem = Optional.ofNullable(climb); + } catch (Exception e) { m_climbL1Subsystem = Optional.empty(); - m_intakeSubsystem = Optional.empty(); } + + try { + IntakeSubsystem intake = new IntakeSubsystem(bHasPneumatics); + m_intakeSubsystem = Optional.ofNullable(intake); + } catch (Exception e) { + m_intakeSubsystem = Optional.empty(); + } + // Init Auto configureAutos(); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java index 536f3c9..b19916f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/ClimbL1Subsystem.java @@ -15,19 +15,29 @@ public class ClimbL1Subsystem extends SubsystemBase { private Solenoid m_RightSolenoid; private boolean m_bRaised = false; - /** Creates a new ClimbL1Subsystem. */ - public ClimbL1Subsystem() { + /** Creates a new ClimbL1Subsystem. + * @throws Exception */ + public ClimbL1Subsystem(Boolean bHasPneumatics) throws Exception { + + // Create SmartDashboard items regardless of whether or not we instantiate + // the subsystem. + SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); + SmartDashboard.putBoolean("ClimbL1 TestRaise", false); + // Create member objects in the constructor in the hope that they throw exceptions // if underlying hardware is not present and, hence, allow our Optional system to // work. - m_LeftSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, - PneumaticsConstants.kHubType, - ClimbL1Constants.kLeftSolenoidChannel); - m_RightSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, - PneumaticsConstants.kHubType, - ClimbL1Constants.kLeftSolenoidChannel); - SmartDashboard.putBoolean("ClimbL1Raised", m_bRaised); - SmartDashboard.putBoolean("ClimbL1 TestRaise", false); + if (bHasPneumatics) { + m_LeftSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsConstants.kHubType, + ClimbL1Constants.kLeftSolenoidChannel); + m_RightSolenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsConstants.kHubType, + ClimbL1Constants.kLeftSolenoidChannel); + } + else { + throw new Exception("Climb subsystem requires pneumatics which are not present!"); + } } // Raise the climb arms. diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index 2ec927a..84ae285 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -29,6 +29,14 @@ public class IndexerBulkSubsystem extends SubsystemBase { /** Creates a new IndexerBulkSubsystem. */ public IndexerBulkSubsystem() throws Exception { + // Create SmartDashboard items first so that these are populated + // regardless of whether or not the subsystem is present. + SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); + SmartDashboard.putBoolean("IndexerBulk FuelPresent", false); + + // Test mode controls + SmartDashboard.putBoolean("IndexerBulk TestBulk", false); + m_motorBulk = new TalonFXS(IndexerBulkConstants.kBulkMoveMotorCANID); if (!m_motorBulk.isConnected()) { @@ -46,12 +54,6 @@ public IndexerBulkSubsystem() throws Exception { if (!status.isOK()) { System.out.println("Could not apply configs for bulk tranfer motor, error code: " + status.toString()); } - - SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); - SmartDashboard.putBoolean("IndexerBulk FuelPresent", false); - - // Test mode controls - SmartDashboard.putBoolean("IndexerBulk TestBulk", false); } // Runs the belts that transfer the fuel from bulk storage to the indexer. diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index f3bd5f2..ff0f091 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -18,23 +18,30 @@ public class IntakeSubsystem extends SubsystemBase { private boolean m_Extended = false; /** Creates a new IntakeSubsystem. */ - public IntakeSubsystem() throws Exception { + public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { + + // Create SmartDashboard items first so that these exist even + // if we fail to create the subsystem. + SmartDashboard.putBoolean("Intake Extended", m_Extended); + SmartDashboard.putBoolean("Intake Running", m_motorRunning); + + // Test mode controls + SmartDashboard.putBoolean("Intake TestExtend", false); + SmartDashboard.putBoolean("Intake TestRun", false); + m_motorIntake = new TalonFX(IntakeConstants.kIntakeMotorCANID); if(!m_motorIntake.isConnected()) { throw new Exception("Intake motor is not connected!"); } - m_solenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, - PneumaticsConstants.kHubType, - IntakeConstants.kIntakeSolenoid); - - SmartDashboard.putBoolean("Intake Extended", m_Extended); - SmartDashboard.putBoolean("Intake Running", m_motorRunning); - - // Test mode controlls - SmartDashboard.putBoolean("Intake TestExtend", false); - SmartDashboard.putBoolean("Intake TestRun", false); + if(bHasPneumatics) { + m_solenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsConstants.kHubType, + IntakeConstants.kIntakeSolenoid); + } else { + throw new Exception("Intake subsystem requires pneumatics which are not present!"); + } } // Spins the shaft on the intake that will move fuel into the robot. diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 92ecbac..28eec70 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -43,6 +43,16 @@ public class LauncherSubsystem extends SubsystemBase { * @throws Exception */ public LauncherSubsystem() throws Exception { + // Create SmartDashboard items first so that these are populated + // regardless of whether or not the subsystem is present. + SmartDashboard.putNumber("Launcher RPM", 0.0 ); + SmartDashboard.putNumber("Launcher RPS", 0.0); + SmartDashboard.putBoolean("Launcher Has Fuel", m_HasFuel); + + // Test mode controls + SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); + SmartDashboard.putNumber("Launcher TestLiftSpeed", 0.0 ); + m_motorLift = new TalonFX(LauncherConstants.kLauncherLiftMotorCANID); m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); m_motorFollower = new TalonFX(LauncherConstants.kLauncherFlywheelMotor2CANID); @@ -105,14 +115,6 @@ public LauncherSubsystem() throws Exception { LauncherConstants.kMotorsDriveInOppositeDirections ? MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); - SmartDashboard.putNumber("Launcher RPM", 0.0 ); - SmartDashboard.putNumber("Launcher RPS", 0.0); - SmartDashboard.putBoolean("Launcher Has Fuel", m_HasFuel); - - // Test mode controls - SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); - SmartDashboard.putNumber("Launcher TestLiftSpeed", 0.0 ); - m_configValid = true; } From 87b7b6a03f5f70c74f586855e6de28ee58549035 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Mar 2026 10:35:30 -0600 Subject: [PATCH 104/161] Tweak error reporting in RobotContainer to enable simulator runs on mac. --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 58a75d4..bb261c7 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -213,7 +213,13 @@ private void configureAutos() { m_field.getObject("path").setPoses(poses); }); } else { - DriverStation.reportWarning("Drive Subsystem is not present! No Auto's configured.", null); + try { + DriverStation.reportWarning("Drive Subsystem is not present! No Auto's configured.", null); + } catch (Exception e) { + // If using the SimGUI with no drivetrain components on the robot, the prior call throws + // a null pointer exception which is unhelpful. Let's see if this lets us ignore it. + } + } } From 7f9298b165f2ff2f7083cbb63ae9d203c0945644 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 7 Mar 2026 10:37:04 -0600 Subject: [PATCH 105/161] Add test mode/pit test UI to Elastic layout --- 2026-Rebuilt/elastic-layout.json | 222 ++++++++++++++++++++++++++++++- 1 file changed, 220 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 71ada17..3de27b5 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -1,6 +1,6 @@ { "version": 1.0, - "grid_size": 128, + "grid_size": 64, "tabs": [ { "name": "Toaster Testing", @@ -43,7 +43,7 @@ "properties": { "topic": "/SmartDashboard/Field", "period": 0.06, - "field_game": "Rebuilt", + "field_game": "Reefscape", "robot_width": 0.85, "robot_length": 0.85, "show_other_objects": true, @@ -207,6 +207,224 @@ } ] } + }, + { + "name": "Pit Test", + "grid_layout": { + "layouts": [], + "containers": [ + { + "title": "Climb Raise", + "x": 448.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Toggle Switch", + "properties": { + "topic": "/SmartDashboard/ClimbL1 TestRaise", + "period": 0.06, + "data_type": "boolean" + } + }, + { + "title": "ClimbL1Raised", + "x": 448.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/ClimbL1Raised", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Hub Distance", + "x": 192.0, + "y": 128.0, + "width": 192.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Hub Distance", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Fuel Present", + "x": 640.0, + "y": 256.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/IndexerBulk FuelPresent", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Running", + "x": 640.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/IndexerBulk BulkStarted", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Transfer Run", + "x": 640.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Toggle Switch", + "properties": { + "topic": "/SmartDashboard/IndexerBulk TestBulk", + "period": 0.06, + "data_type": "boolean" + } + }, + { + "title": "Intake Extend", + "x": 832.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Toggle Switch", + "properties": { + "topic": "/SmartDashboard/Intake TestExtend", + "period": 0.06, + "data_type": "boolean" + } + }, + { + "title": "Intake Run", + "x": 960.0, + "y": 0.0, + "width": 128.0, + "height": 128.0, + "type": "Toggle Switch", + "properties": { + "topic": "/SmartDashboard/Intake TestRun", + "period": 0.06, + "data_type": "boolean" + } + }, + { + "title": "Running", + "x": 960.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Intake Running", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Extended", + "x": 832.0, + "y": 128.0, + "width": 128.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Intake Extended", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Launcher RPM", + "x": 0.0, + "y": 128.0, + "width": 192.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher RPM", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Set Launcher RPM", + "x": 0.0, + "y": 0.0, + "width": 192.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestRPM", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Set LiftSpeed", + "x": 192.0, + "y": 0.0, + "width": 192.0, + "height": 128.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestLiftSpeed", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Fuel Present", + "x": 0.0, + "y": 256.0, + "width": 192.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Launcher Has Fuel", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + } + ] + } } ] } \ No newline at end of file From 352ce666f31d31c569ac6cf00efaf92a37e68bbb Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 7 Mar 2026 15:29:12 -0600 Subject: [PATCH 106/161] Got the core auto code for going over the bump and back with paths working. --- .../main/java/frc/robot/RobotContainer.java | 29 ++-- .../autoCommands/DeadreckonBumpAndBack.java | 124 ++++++++++++++++++ .../autoCommands/DriveInALineFromPos.java | 107 --------------- .../autoCommands/OnTheFlyToTarget.java | 86 ++++++++++++ .../commands/autoCommands/POTFtoPoint.java | 84 ------------ .../frc/robot/commands/util/AutoFromList.java | 36 +---- .../frc/robot/utils/ConditionalRotation.java | 38 ++++++ .../main/java/frc/robot/utils/PathUtils.java | 81 ++++++++++++ 8 files changed, 352 insertions(+), 233 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OnTheFlyToTarget.java delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/ConditionalRotation.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 3ba3d92..dd9acb0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -45,8 +45,8 @@ import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; import frc.robot.commands.autoCommands.CorralAndShoot; +import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; import frc.robot.commands.autoCommands.DeadreckonDistance; -import frc.robot.commands.autoCommands.DriveInALineFromPos; import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -90,12 +90,13 @@ public class RobotContainer { m_limelightError ); + // The general constraints for most paths. PathConstraints m_constraints = new PathConstraints( 2.0, 1.0, (1/2) * Math.PI, (1/4) * Math.PI - ); // The constraints for this path. + ); // Smartdashboard Objects private SendableChooser m_autoChooser; @@ -169,17 +170,27 @@ private void configureAutos() { m_autoChooser = new SendableChooser(); // Init Autos - m_autoChooser.addOption("[INDEV] Corral and Shoot", - new CorralAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) - ); + // Test Autos - m_autoChooser.addOption("[TEST] Forward 2 Meters Test", - new DeadreckonDistance(driveSubsystem, 3.0, 2.5) + PathConstraints slowConstraints = new PathConstraints( + 1.0, + 1.0, + (1/2) * Math.PI, + (1/4) * Math.PI + ); + + // replace slowConstraints to m_contraints after testing. + m_autoChooser.addOption("[TEST] Deadreckon Over Bump and Back", + new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, isRed) + ); + + m_autoChooser.addOption("[TEST] Forward Test", + new DeadreckonDistance(driveSubsystem, 2.5, 2.0) ); - m_autoChooser.addOption("[TEST] Backup 2 Meters Test", - new DeadreckonDistance(driveSubsystem, 3.0, -2.5) + m_autoChooser.addOption("[TEST] Backup Test", + new DeadreckonDistance(driveSubsystem, 2.5, -2.0) ); // Warm up Pathfinder diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java new file mode 100644 index 0000000..d8a7b80 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -0,0 +1,124 @@ +package frc.robot.commands.autoCommands; + +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.GoalEndState; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.geometry.Translation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; +import frc.robot.subsystems.DriveSubsystem; +import frc.robot.utils.PathUtils; + +/** An example command that uses an example subsystem. */ +public class DeadreckonBumpAndBack extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final PathConstraints m_constraints; + private final BooleanSupplier m_isRed; + + /** + * Creates a new DeadreckonBumpAndBack. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + */ + public DeadreckonBumpAndBack(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, BooleanSupplier isRed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_constraints = constraints; + m_isRed = isRed; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Rotation2d targetRotation; + Double pickupTargetX; + Double lineupTargetX; + if (m_isRed.getAsBoolean() == true) { // Red + targetRotation = Rotation2d.k180deg; + + pickupTargetX = 9.1; + lineupTargetX = 10.88; + } else { // Blue + targetRotation = Rotation2d.kZero; + + pickupTargetX = 7.689; + lineupTargetX = 5.667; + } + + // Deadreckon Over the bump + Command deadreckonFoward = new DeadreckonDistance(m_driveSubsystem, 2.5, 2.0); + Command deadreckonBackward = new DeadreckonDistance(m_driveSubsystem, 2.5, -2.0); + + // Create paths and scheudle other commands + Command lineupSchedule = new InstantCommand(() -> { + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + Rotation2d currentRotation = currentPose.getRotation(); + Double currentY = currentPose.getY(); + + Pose2d lineupTarget = new Pose2d(lineupTargetX, currentY, currentRotation); + + System.out.println(lineupTarget.toString()); + + // Go to the lineup target (backward) + PathPlannerPath lineupPath = PathUtils.OnTheFlyToTarget( + currentPose, + lineupTarget, + m_constraints, + true + ); + Command lineupCommand = AutoBuilder.followPath(lineupPath); + + // Create & Schedule the command group. + CommandScheduler.getInstance().schedule(lineupCommand.andThen(deadreckonBackward)); + }); + + Command pickupScheudle = new InstantCommand(() -> { + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + Rotation2d currentRotation = currentPose.getRotation(); + Double currentY = currentPose.getY(); + + Pose2d pickupTarget = new Pose2d(pickupTargetX, currentY, currentRotation); + + System.out.println(pickupTarget.toString()); + + // Go to the pickup target (forward) + PathPlannerPath pickupPath = PathUtils.OnTheFlyToTarget(currentPose, pickupTarget, m_constraints); + Command pickupCommand = AutoBuilder.followPath(pickupPath); + + // Create & Scheudle the command group + CommandScheduler.getInstance().schedule(pickupCommand.andThen(lineupSchedule)); + }); + + // Create & Schedule the command group. + SequentialCommandGroup initialSequential = deadreckonFoward.andThen(pickupScheudle); + CommandScheduler.getInstance().schedule(initialSequential); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java deleted file mode 100644 index f55c1c0..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DriveInALineFromPos.java +++ /dev/null @@ -1,107 +0,0 @@ -package frc.robot.commands.autoCommands; - -import java.util.List; - -import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.path.GoalEndState; -import com.pathplanner.lib.path.PathConstraints; -import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.path.Waypoint; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; - -/** An example command that uses an example subsystem. */ -public class DriveInALineFromPos extends Command { - private final DifferentialDrivePoseEstimator m_poseEstimator; - private double m_targetDistance = 0.0; - private Boolean m_reversed = false; - - /** - * Creates a new DriveForward2mFromPos. - * - * @param subsystem The subsystem used by this command. - */ - public DriveInALineFromPos(DifferentialDrivePoseEstimator poseEstimator, double targetDistance, Boolean reversed) - { - m_poseEstimator = poseEstimator; - m_targetDistance = targetDistance; - m_reversed = reversed; - } - - // Called when the command is initially scheduled. - @Override - public void initialize() { - // This is taken and modified from the limelight documentation for - // path creation on the fly: https://pathplanner.dev/pplib-create-a-path-on-the-fly.html - - Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - Rotation2d currentRotation = currentPose.getRotation(); - - if (m_reversed == true) { - m_targetDistance = m_targetDistance * -1.0; - } - - double currentX = currentPose.getX(); - double currentY = currentPose.getY(); - - // If we think of the direction we want to go as of the hypotonuse of a - // right trinagle, we can calculate the needed distance to travel on - // the (x, y) by calculating for them as the legs of the RT. - double xMod = m_targetDistance * currentRotation.getCos(); - double yMod = m_targetDistance * currentRotation.getSin(); - - double newX = currentX + xMod; - double newY = currentY + yMod; - - // Create a list of waypoints from poses. Each pose represents one waypoint. - // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. - Pose2d startPose = new Pose2d(currentX, currentY, currentRotation); - Pose2d endPose = new Pose2d(newX, newY, currentRotation); - List waypoints = PathPlannerPath.waypointsFromPoses( - startPose, - endPose - ); - - PathConstraints constraints = new PathConstraints( - 1.0, - 1.0, - 2 * Math.PI, - 4 * Math.PI - ); // The constraints for this path. - - // Create the path using the waypoints created above - PathPlannerPath path = new PathPlannerPath( - waypoints, - constraints, - null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. - new GoalEndState(0.0, currentRotation), // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. - m_reversed - ); - - // Prevent the path from being flipped if the coordinates are already correct - path.preventFlipping = true; - - // Create the command version of the path and schedule it - Command followPath = AutoBuilder.followPath(path); - CommandScheduler.getInstance().schedule(followPath); - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - // The command automatically ends - return true; - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OnTheFlyToTarget.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OnTheFlyToTarget.java new file mode 100644 index 0000000..4289dbd --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OnTheFlyToTarget.java @@ -0,0 +1,86 @@ +package frc.robot.commands.autoCommands; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.utils.PathUtils; + +public class OnTheFlyToTarget extends Command { + private final DifferentialDrivePoseEstimator m_poseEstimator; + private Pose2d m_targetPose; + private final PathConstraints m_constraints; + private final Boolean m_reversed; + private final double m_endVelocity; + + /** + * This creates and schedules a path on the fly to a given target point. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + * @param endVelocity The velocity it should be at the end of the path. + * @param reversed If the robot should run the path in reversed (backward) + */ + public OnTheFlyToTarget(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose, PathConstraints constraints, Double endVelocity, Boolean reversed) + { + m_poseEstimator = poseEstimator; + m_targetPose = targetPose; + m_constraints = constraints; + m_endVelocity = endVelocity; + m_reversed = reversed; + } + + /** + * This creates and schedules a path on the fly to a given target point. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + * @param endVelocity The velocity it should be at the end of the path. + */ + public OnTheFlyToTarget(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose, PathConstraints constraints, Double endVelocity) + { + this(poseEstimator, targetPose, constraints, endVelocity, false); + } + + /** + * This creates and schedules a path on the fly to a given target point. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + * @param reversed If the robot should run the path in reversed (backward) + */ + public OnTheFlyToTarget(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose, PathConstraints constraints, Boolean reversed) + { + this(poseEstimator, targetPose, constraints, 0.0, reversed); + } + + /** + * This creates and schedules a path on the fly to a given target point. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + */ + public OnTheFlyToTarget(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose, PathConstraints constraints) + { + this(poseEstimator, targetPose, constraints, 0.0, false); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + PathPlannerPath path = PathUtils.OnTheFlyToTarget(currentPose, m_targetPose, m_constraints, m_endVelocity, m_reversed); + + // Create the command version of the path and return it + Command followPath = AutoBuilder.followPath(path); + CommandScheduler.getInstance().schedule(followPath); + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java deleted file mode 100644 index 767e86f..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/POTFtoPoint.java +++ /dev/null @@ -1,84 +0,0 @@ -package frc.robot.commands.autoCommands; - -import java.util.List; - -import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.path.GoalEndState; -import com.pathplanner.lib.path.PathConstraints; -import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.path.Waypoint; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; - -/** An example command that uses an example subsystem. */ -public class POTFtoPoint extends Command { - private final DifferentialDrivePoseEstimator m_poseEstimator; - private Pose2d m_targetPose; - - /** - * Creates a new POTFtwoPoints. - * - * @param subsystem The subsystem used by this command. - */ - public POTFtoPoint(DifferentialDrivePoseEstimator poseEstimator, Pose2d targetPose) - { - m_poseEstimator = poseEstimator; - m_targetPose = targetPose; - } - - // Called when the command is initially scheduled. - @Override - public void initialize() { - // This is taken and modified from the limelight documentation for - // path creation on the fly: https://pathplanner.dev/pplib-create-a-path-on-the-fly.html - - Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - - // Create a list of waypoints from poses. Each pose represents one waypoint. - // The rotation component of the pose should be the direction of travel. Do not use holonomic rotation. - List waypoints = PathPlannerPath.waypointsFromPoses( - currentPose, - m_targetPose - ); - - PathConstraints constraints = new PathConstraints( - 1.0, - 1.0, - 2 * Math.PI, - 4 * Math.PI - ); // The constraints for this path. - - // Create the path using the waypoints created above - PathPlannerPath path = new PathPlannerPath( - waypoints, - constraints, - null, // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. - new GoalEndState(0.0, m_targetPose.getRotation()) // Goal end state. You can set a holonomic rotation here. If using a differential drivetrain, the rotation will have no effect. - ); - - // Prevent the path from being flipped if the coordinates are already correct - path.preventFlipping = true; - - // Create the command version of the path and schedule it - Command followPath = AutoBuilder.followPath(path); - CommandScheduler.getInstance().schedule(followPath); - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - // The command automatically ends - return true; - } -} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 88755bc..f4b7745 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -12,11 +12,10 @@ import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; -import frc.robot.commands.RotateToRotation2D; import frc.robot.subsystems.DriveSubsystem; +import frc.robot.utils.ConditionalRotation; import frc.robot.utils.PathUtils; import frc.robot.utils.PoseDiff; import edu.wpi.first.math.Pair; @@ -154,37 +153,8 @@ public void initialize() { }); // decide what to do - Command rotateTwordPathConditional = Commands.either( - new InstantCommand(), - new RotateToRotation2D( - m_DriveSubsystem, - m_poseEstimator, - rotToPoint, - 2.0 - ), - () -> { - Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); - double diff = Math.abs((rotToPoint.minus(currentRot)).getDegrees()); - - return diff <= 90; - } - ); - - Command rotateTwordStartRotationConditional = Commands.either( - new InstantCommand(), - new RotateToRotation2D( - m_DriveSubsystem, - m_poseEstimator, - directionRot, - 2.0 - ), - () -> { - Rotation2d currentRot = m_poseEstimator.getEstimatedPosition().getRotation(); - double diff = Math.abs((directionRot.minus(currentRot)).getDegrees()); - - return diff <= 45; - } - ); + Command rotateTwordPathConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, rotToPoint, 90, 2.0); + Command rotateTwordStartRotationConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, directionRot, 45, 2.0); // add to group precommandGroup.addCommands( diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/ConditionalRotation.java b/2026-Rebuilt/src/main/java/frc/robot/utils/ConditionalRotation.java new file mode 100644 index 0000000..b403bee --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/ConditionalRotation.java @@ -0,0 +1,38 @@ +package frc.robot.utils; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.Commands; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.subsystems.DriveSubsystem; + +public class ConditionalRotation { + /** + * This creates a conditional rotation command, where it only rotates if its outside of the expected error. + * + * @param driveSubsystem The drive subsystem. + * @param poseEstimator The pose estimator. + * @param targetRotation The desired Rotation. + * @param error The maximum accepted error in degrees. + * @param speed The maximum speed the rotation command will go. + */ + public static Command New(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, Rotation2d targetRotation, double error, double speed) { + return Commands.either( + new InstantCommand(), + new RotateToRotation2D( + driveSubsystem, + poseEstimator, + targetRotation, + speed + ), + () -> { + Rotation2d currentRot = poseEstimator.getEstimatedPosition().getRotation(); + double diff = Math.abs((targetRotation.minus(currentRot)).getDegrees()); + + return diff <= error; + } + ); + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java index da75047..1633b02 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java @@ -2,11 +2,15 @@ import java.util.List; +import com.pathplanner.lib.path.GoalEndState; +import com.pathplanner.lib.path.IdealStartingState; +import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; import com.pathplanner.lib.path.Waypoint; import edu.wpi.first.math.Pair; import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; public class PathUtils { /** @@ -37,4 +41,81 @@ public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair waypoints = PathPlannerPath.waypointsFromPoses( + new Pose2d(startPose.getTranslation(), startPose.getRotation().minus(rotateMod)), + new Pose2d(targetPose.getTranslation(), targetPose.getRotation().minus(rotateMod)) + ); + + // Create the path using the waypoints created above + PathPlannerPath path = new PathPlannerPath( + waypoints, + constraints, + new IdealStartingState(0.0, startPose.getRotation()), // The ideal starting state, this is only relevant for pre-planned paths, so can be null for on-the-fly paths. + new GoalEndState(endVelocity, targetPose.getRotation()), + reversed + ); + + // Prevent the path from being flipped if the coordinates are already correct + path.preventFlipping = true; + + // Create the command version of the path and return it + return path; + } + + /** + * This creates a path on the fly to a given target point. + * + * @param startPose The pose the robot will be at the start of the path. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + * @param endVelocity The velocity it should be at the end of the path. + */ + public static PathPlannerPath OnTheFlyToTarget(Pose2d startPose, Pose2d targetPose, PathConstraints constraints, Double endVelocity) + { + return OnTheFlyToTarget(startPose, targetPose, constraints, endVelocity, false); + } + + /** + * This creates a path on the fly to a given target point. + * + * @param startPose The pose the robot will be at the start of the path. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + * @param reversed If the robot should run the path in reversed (backward) + */ + public static PathPlannerPath OnTheFlyToTarget(Pose2d startPose, Pose2d targetPose, PathConstraints constraints, Boolean reversed) + { + return OnTheFlyToTarget(startPose, targetPose, constraints, 0.0, reversed); + } + + /** + * This creates a path on the fly to a given target point. + * + * @param startPose The pose the robot will be at the start of the path. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + */ + public static PathPlannerPath OnTheFlyToTarget(Pose2d startPose, Pose2d targetPose, PathConstraints constraints) + { + return OnTheFlyToTarget(startPose, targetPose, constraints, 0.0, false); + } } From 836e03bb68efdc1a09ac7766a89ecb5437be0221 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Mon, 9 Mar 2026 18:32:32 -0500 Subject: [PATCH 107/161] Added subsystem presence indicators to Pit Test tab in Elastic --- 2026-Rebuilt/elastic-layout.json | 101 ++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 3de27b5..74efba1 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -227,11 +227,11 @@ } }, { - "title": "ClimbL1Raised", + "title": "Raised", "x": 448.0, "y": 128.0, "width": 128.0, - "height": 128.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/ClimbL1Raised", @@ -260,9 +260,9 @@ { "title": "Fuel Present", "x": 640.0, - "y": 256.0, + "y": 192.0, "width": 128.0, - "height": 128.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/IndexerBulk FuelPresent", @@ -279,7 +279,7 @@ "x": 640.0, "y": 128.0, "width": 128.0, - "height": 128.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/IndexerBulk BulkStarted", @@ -335,7 +335,7 @@ "x": 960.0, "y": 128.0, "width": 128.0, - "height": 128.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/Intake Running", @@ -352,7 +352,7 @@ "x": 832.0, "y": 128.0, "width": 128.0, - "height": 128.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/Intake Extended", @@ -411,7 +411,7 @@ "x": 0.0, "y": 256.0, "width": 192.0, - "height": 128.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/Launcher Has Fuel", @@ -422,6 +422,91 @@ "true_icon": "None", "false_icon": "None" } + }, + { + "title": "Subsystem", + "x": 448.0, + "y": 256.0, + "width": 128.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/ClimbL1 Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Drive Subsystem", + "x": 192.0, + "y": 256.0, + "width": 192.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Drive Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Subsystem", + "x": 640.0, + "y": 256.0, + "width": 128.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/IndexerBulk Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Subsystem", + "x": 832.0, + "y": 256.0, + "width": 256.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Intake Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Subsystem", + "x": 0.0, + "y": 320.0, + "width": 192.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Launcher Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } } ] } From 801dac405aa3d9931888a9d82d41777d8c472bd2 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Mon, 9 Mar 2026 19:10:12 -0500 Subject: [PATCH 108/161] Fix up DIOs after indexer sensor was removed --- 2026-Rebuilt/elastic-layout.json | 25 +++---------------- .../src/main/java/frc/robot/Constants.java | 6 +---- .../subsystems/IndexerBulkSubsystem.java | 9 ------- 3 files changed, 5 insertions(+), 35 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 74efba1..752a766 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -257,23 +257,6 @@ "show_submit_button": false } }, - { - "title": "Fuel Present", - "x": 640.0, - "y": 192.0, - "width": 128.0, - "height": 64.0, - "type": "Boolean Box", - "properties": { - "topic": "/SmartDashboard/IndexerBulk FuelPresent", - "period": 0.06, - "data_type": "boolean", - "true_color": 4283215696, - "false_color": 4294198070, - "true_icon": "None", - "false_icon": "None" - } - }, { "title": "Running", "x": 640.0, @@ -426,7 +409,7 @@ { "title": "Subsystem", "x": 448.0, - "y": 256.0, + "y": 320.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -443,7 +426,7 @@ { "title": "Drive Subsystem", "x": 192.0, - "y": 256.0, + "y": 320.0, "width": 192.0, "height": 64.0, "type": "Boolean Box", @@ -460,7 +443,7 @@ { "title": "Subsystem", "x": 640.0, - "y": 256.0, + "y": 320.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -477,7 +460,7 @@ { "title": "Subsystem", "x": 832.0, - "y": 256.0, + "y": 320.0, "width": 256.0, "height": 64.0, "type": "Boolean Box", diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 8b42660..7c64782 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -23,7 +23,7 @@ // Current DIO Channels: // // 0 - Upper fuel sensor (launcher subsystem) -// 1 - Lower fuel sensor (indexer subsystem) +// 1 - // // Current Solenoid Channels: // @@ -202,10 +202,6 @@ public static class IndexerBulkConstants { // Raw motor speeds in range [-1.0,1.0] public static final double kBulkMoveMotorSpeed = 0.3; - - // Beam break sensor to detect fuel at the indexer. - public static final int kLowerFuelSensorChannel = 1; - public static final boolean kLowerFuelSensorIsEmpty = false; } public static class ClimbL1Constants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index 84ae285..ace9406 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -21,7 +21,6 @@ public class IndexerBulkSubsystem extends SubsystemBase { - private final DigitalInput m_Sensor = new DigitalInput(IndexerBulkConstants.kLowerFuelSensorChannel); private TalonFXS m_motorBulk; private Boolean m_bulkStarted = false; @@ -32,7 +31,6 @@ public IndexerBulkSubsystem() throws Exception { // Create SmartDashboard items first so that these are populated // regardless of whether or not the subsystem is present. SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); - SmartDashboard.putBoolean("IndexerBulk FuelPresent", false); // Test mode controls SmartDashboard.putBoolean("IndexerBulk TestBulk", false); @@ -70,16 +68,9 @@ public void stopBulkTransfer() { SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); } -// Returns true if lower fuel sensor detects fuel. - public boolean isFuelPresent() { - boolean sensorRead = m_Sensor.get(); - return (sensorRead == IndexerBulkConstants.kLowerFuelSensorIsEmpty) ? false : true; - } - @Override public void periodic() { // This method will be called once per scheduler run - SmartDashboard.putBoolean("IndexerBulk FuelPresent", this.isFuelPresent()); } @Override From e089c583776b30cb14f879b0d30845c165a67cb7 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 9 Mar 2026 20:42:20 -0500 Subject: [PATCH 109/161] Started working on some of the basic autos --- 2026-Rebuilt/Modified2026Andymark.fmap | 1 + .../pathplanner/paths/LineupToTower.path | 26 ++--- .../main/java/frc/robot/RobotContainer.java | 19 ++++ .../java/frc/robot/commands/WaitCommand.java | 45 +++++++++ .../commands/autoCommands/BackupAndClimb.java | 94 ++++++++++++++++++ .../commands/autoCommands/BackupAndShoot.java | 71 ++++++++++++++ .../autoCommands/BackupAndShootThenClimb.java | 98 +++++++++++++++++++ .../frc/robot/commands/util/AutoFromList.java | 75 +++++++------- 8 files changed, 380 insertions(+), 49 deletions(-) create mode 100644 2026-Rebuilt/Modified2026Andymark.fmap create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/WaitCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java diff --git a/2026-Rebuilt/Modified2026Andymark.fmap b/2026-Rebuilt/Modified2026Andymark.fmap new file mode 100644 index 0000000..0afcca2 --- /dev/null +++ b/2026-Rebuilt/Modified2026Andymark.fmap @@ -0,0 +1 @@ +{"fiducials":[{"family":"apriltag3_36h11_classic","id":1,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,3.604958999999999,1.2246467991473532e-16,-1,0,3.3899913999999995,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":2,"size":165.1,"transform":[-2.220446049250313e-16,-1.0000000000000002,0,3.6423986,1.0000000000000002,-2.220446049250313e-16,0,0.6032558000000003,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":3,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,3.0388438000000004,1.2246467991473532e-16,-1,0,0.35545340000000003,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":4,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,3.0388438000000004,1.2246467991473532e-16,-1,0,-0.0001465999999998857,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":5,"size":165.1,"transform":[-2.220446049250313e-16,1,0,3.6423986,-1,-2.220446049250313e-16,0,-0.6035489999999997,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":6,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,3.604958999999999,1.2246467991473532e-16,-1,0,-3.3902845999999998,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":7,"size":165.1,"transform":[1,0,0,3.679863599999999,0,1,0,-3.3902845999999998,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":8,"size":165.1,"transform":[-2.220446049250313e-16,1,0,3.997998599999999,-1,-2.220446049250313e-16,0,-0.6035489999999997,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":9,"size":165.1,"transform":[1,0,0,4.246156599999999,0,1,0,-0.3557465999999998,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":10,"size":165.1,"transform":[1,0,0,4.246156599999999,0,1,0,-0.0001465999999998857,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":11,"size":165.1,"transform":[-2.220446049250313e-16,-1.0000000000000002,0,3.997998599999999,1.0000000000000002,-2.220446049250313e-16,0,0.6032558000000003,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":12,"size":165.1,"transform":[1,0,0,3.679863599999999,0,1,0,3.3899913999999995,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":13,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,8.240331999999999,1.2246467991473532e-16,-1,0,3.3704079999999994,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":14,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,8.240331999999999,1.2246467991473532e-16,-1,0,2.9386079999999994,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":15,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,8.2399764,1.2246467991473532e-16,-1,0,0.29098820000000014,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":16,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,8.2399764,1.2246467991473532e-16,-1,0,-0.14081180000000026,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":17,"size":165.1,"transform":[1,0,0,-3.6099364000000005,0,1,0,-3.3902845999999998,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":18,"size":165.1,"transform":[-2.220446049250313e-16,1,0,-3.6474014000000006,-1,-2.220446049250313e-16,0,-0.6035489999999997,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":19,"size":165.1,"transform":[1,0,0,-3.0438466,0,1,0,-0.3557465999999998,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":20,"size":165.1,"transform":[1,0,0,-3.0438466,0,1,0,-0.0001465999999998857,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":21,"size":165.1,"transform":[-2.220446049250313e-16,-1.0000000000000002,0,-3.6474014000000006,1.0000000000000002,-2.220446049250313e-16,0,0.6032558000000003,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":22,"size":165.1,"transform":[1,0,0,-3.6099364000000005,0,1,0,3.3899913999999995,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":23,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,-3.6848410000000005,1.2246467991473532e-16,-1,0,3.3899913999999995,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":24,"size":165.1,"transform":[-2.220446049250313e-16,-1.0000000000000002,0,-4.0030014000000005,1.0000000000000002,-2.220446049250313e-16,0,0.6032558000000003,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":25,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,-4.251134,1.2246467991473532e-16,-1,0,0.35545340000000003,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":26,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,-4.251134,1.2246467991473532e-16,-1,0,-0.0001465999999998857,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":27,"size":165.1,"transform":[-2.220446049250313e-16,1,0,-4.0030014000000005,-1,-2.220446049250313e-16,0,-0.6035489999999997,0,0,1,1.12395,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":28,"size":165.1,"transform":[-1,-1.2246467991473532e-16,0,-3.6848410000000005,1.2246467991473532e-16,-1,0,-3.3902845999999998,0,0,1,0.889,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":29,"size":165.1,"transform":[1,0,0,-8.2453094,0,1,0,-3.3707266,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":30,"size":165.1,"transform":[1,0,0,-8.2453094,0,1,0,-2.9389265999999994,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":31,"size":165.1,"transform":[1,0,0,-8.244953800000001,0,1,0,-0.29130679999999964,0,0,1,0.55245,0,0,0,1],"unique":true},{"family":"apriltag3_36h11_classic","id":32,"size":165.1,"transform":[1,0,0,-8.244953800000001,0,1,0,0.14049319999999987,0,0,1,0.55245,0,0,0,1],"unique":true},{"transform":[1,-1.6081226496766364e-16,9.211731732618967e-33,0,1.6081226496766364e-16,1,-1.2325951644078308e-32,2.104153938435746e-16,-9.211731732618965e-33,1.232595164407831e-32,1,0,0,0,0,1],"size":165.1,"id":50,"family":"apriltag3_36h11_classic","unique":1},{"transform":[-1,-1.2246467991473532e-16,3.081487911019576e-33,0.1524,1.2246467991473532e-16,-1,-1.6081226496766364e-16,0.3048,2.2775310466648105e-32,-1.6081226496766364e-16,1,0.375,0,0,0,1],"size":165.1,"id":52,"family":"apriltag3_36h11_classic","unique":1},{"family":"apriltag3_36h11_classic","id":54,"size":165.1,"unique":true,"transform":[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]},{"family":"apriltag3_36h11_classic","id":56,"size":165.1,"unique":true,"transform":[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]}],"type":"frc","fieldlength":16.518,"fieldwidth":8.043,"pngBase64":"data:image/png;base64,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Uk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAMAUExURQAAAP///2VlZWZmZmpqamlpaWhoaGdnZwsGCNrV1y4aLp6KojoqPuro6wICtwICsQMD1gMDyQICpQICkQICbAQEvwkJ7QoK9gkJ4wcHrwQEUhQU7BYW9Q0NlxISxxERuBUV1xYWcCIikT4+/Tc33kVF/hcXPV9fiklJamdnk3FxoFxcfJKSvH9/pLS04AwMDRYWFzExMgMEKAIDEyIjMh0eKnJ0gl1falRVWzM1P1laXywwPigrNjk8R0FEThEVIRgbI09RV4SHjwQFB0dMUwkQGHuBiDU4O2ltcZaZm3R9ggUKDIGGiGJqbXJ2d1pfYCAnKAwrKyIxMTRJSS4/P0ZaWltwcFdoaFFgYGp7e2Rzc5uoqIqOjpKWlklKSpainyImIjpuMlKKRlZ2TgYKAgsLBGFhS1VVRWVlVltbT2xsX3R0a2BgWYeHf2ZmYI6OiIqKhW5uanp6dpKSjpaWkv78kE1LOfzqcxMRBoGAehkWBqSVTyklFTEuITYzJyIdC/HRXDMtGEI9KiknIOK9SbqdP6iOOpiCOHxpL414N7CMIJh5IYtvH7GMKaCAJbqULaiHKWtWGn1kH2FOGEE0EMOcMXRdHVZFFpd6J4RrI7COL45zJks9FJ6BK8ukONWuP2NTJlNGIT41GkY8H1pZVi4kDDcsDzs5NBwZE0dANQcEAiUbFSYfGzsyLTMiIb4CArYCArECAqUCApQCAtMEBHcDAzoCAvcJCVEEBOYMDM0NDbwMDB8CAqwMDJ4MDOwUFPwWFhICAq8cHP0qKsIiIuYqKv01Na0lJYseHlgVFSoNDUAYGHhTU4dfX2dJSZFoaFlAQJxycriQkKWBgXdhYd62toBqamVVVVFGRoB6em9qapyWlmpmZnp2doqGhoaCgpaSkrOxscHBwaWlpZubm5aWlpKSko6OjoqKioaGhoKCgn5+fnp6enZ2dnJycm5ubmJiYl5eXlpaWlZWVlJSUk5OTkNDQzs7OzY2NisrKyYmJiIiIhwcHBISEgICAv////17gRMAAAEAdFJOU////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wBT9wclAAAACXBIWXMAAAsTAAALEwEAmpwYAAC6uUlEQVR4nNR9d4AU9dn/55mZnS2z5doeTSkxhpJiN2JMFBEEC5jYYo0NBDVG42Hhou8vMXdGPTQaFQU0JjFFkxiBKIhiefNG7OVNXpAYBRQO7vZuy+1tnfL8/piZLXe7e7tHkTwHd7tTvt/vzDzzPJ/v074kCWAGQtgNCpp/QgWfc9+rOLvouGD+zNv7X0h/4dDbqXgvCVd86+aUS7/rf1aAjYG9MADCQOLBvVLFvYMOLXEM55sxFE1AUqzQUK673DFtuX2Lrb/taLX2LB54cGEr7dYpXOIQAqi9lb9/1ggy5HvvF5nBQMJj77+r8zq165FfCea3pLU9ASWhAEjAA6Dl7oGD7wCAGwZd000AgJ8N2l5MXHivK99q4onnUioQYgANQzRbmcJAYRvm12G2Gc6d94Pkn7MjT1puWF/ZbJgQvPkhDWLn9XcADDQUMSATJGgF1z2YOwEAkma1SQAgFu7Kn0wAaZCgARDBFe5nYpejITGiYMPglwwg8/xB72muVWIQwDSoHy68Fvv9sA9qs9kX7a3mmPmas6gOmUeXisxA2+J8e8b3b4jW/fznVP51NJky/w2AwsRUfFgLgA4M3m7ybgnmzdFNt99akoVvvv3WOwHjSxIMDGx0t6kB4eEzuHWm9VQCA3cTsGA1AEAyNxR3RRIAKc+RVHBkEUkANJC5r+gG5G8HE1g0n53ElfgxBMHsIxREKBgKhoLFu80NA9ixkA/z/aHocdicyNZPfhvbPNXWmuOLxfkTvfm2C/gRDKgCQFzAkcQFY0goRRepgImR9GAA53UAYFp098DtaLH2l2XJO7MjSm2+1xpLr1DifaydGhpQLBB3T+CaRLcBiJXYce3pAAANpeSfKfns7WX50SKpwj4AzNZRlbQxAAYSDABBIIggggP2h4KhkMmJheKR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"} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path index 56ce83d..7ce59dd 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path @@ -3,29 +3,29 @@ "waypoints": [ { "anchor": { - "x": 3.0721923076923088, - "y": 5.116423076923077 + "x": 2.6321826809015425, + "y": 4.895487179487179 }, "prevControl": null, "nextControl": { - "x": 3.130333333333334, - "y": 4.581525641025641 + "x": 2.6321826809015425, + "y": 4.3574391836798885 }, "isLocked": false, "linkedName": null }, { "anchor": { - "x": 2.7814871794871805, - "y": 3.976858974358975 + "x": 2.2000769230769244, + "y": 3.8954615384615385 }, "prevControl": { - "x": 3.2001025641025653, - "y": 4.186166666666668 + "x": 2.618692307692309, + "y": 4.104769230769231 }, "nextControl": { - "x": 2.488419497644409, - "y": 3.8303251334375887 + "x": 1.907009241234153, + "y": 3.7489276975401524 }, "isLocked": false, "linkedName": null @@ -36,8 +36,8 @@ "y": 3.755923076923077 }, "prevControl": { - "x": 2.4326410256410247, - "y": 3.767551282051283 + "x": 1.8221538461538476, + "y": 3.755923076923077 }, "nextControl": null, "isLocked": false, @@ -63,7 +63,7 @@ "reversed": false, "folder": null, "idealStartingState": { - "velocity": 0, + "velocity": 0.5, "rotation": 0.0 }, "useDefaultConstraints": true diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 6601720..08d3368 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -44,6 +44,9 @@ import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; +import frc.robot.commands.autoCommands.BackupAndClimb; +import frc.robot.commands.autoCommands.BackupAndShoot; +import frc.robot.commands.autoCommands.BackupAndShootThenClimb; import frc.robot.commands.autoCommands.CorralAndShoot; import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; import frc.robot.commands.autoCommands.DeadreckonDistance; @@ -182,6 +185,17 @@ private void configureAutos() { // Init Autos + m_autoChooser.addOption("[INDEV] Basic backup and shoot", + new BackupAndShoot(driveSubsystem, m_PoseEstimator, isRed) + ); + + m_autoChooser.addOption("[INDEV] Backup and climb", + new BackupAndClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + ); + + m_autoChooser.addOption("[INDEV] Backup and shoot then climb", + new BackupAndShootThenClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + ); // Test Autos PathConstraints slowConstraints = new PathConstraints( @@ -283,6 +297,11 @@ private void configureBindings() { new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); + // TEST COMMAND FOR TESTING ACCURACY AFTER BUMP! + m_driverController.leftBumper().onTrue( + new RotateToRotation2D(driveSubsystem, m_PoseEstimator, Rotation2d.kZero, 2.0) + ); + // cancel the current command running on drive subsystem when // left y or right x is > half and the default command is not running. new Trigger(() -> (Math.abs(m_driverController.getLeftY()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/WaitCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/WaitCommand.java new file mode 100644 index 0000000..ac64df9 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/WaitCommand.java @@ -0,0 +1,45 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +/** An example command that uses an example subsystem. */ +public class WaitCommand extends Command { + private final double m_totalCalls; + private double m_callCount; + + /** + * Creates a new WaitCommand. + */ + public WaitCommand(double seconds) + { + m_totalCalls = seconds * 50; // 50 calls per second. + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + System.out.println("Starting timer for " + String.valueOf(m_totalCalls)); + m_callCount = 0; + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + m_callCount++; + System.out.println("Timer is now at call count " + String.valueOf(m_callCount)); + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + System.out.println("Timer is now finished!"); + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + boolean check = m_callCount >= m_totalCalls; + System.out.println(String.valueOf(m_callCount) + " >= " + String.valueOf(m_totalCalls) + ": " + String.valueOf(check)); + + return check; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java new file mode 100644 index 0000000..598df89 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java @@ -0,0 +1,94 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.commands.util.AutoFromList; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class BackupAndClimb extends Command { + private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( + "LineupToTower" + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new DSA_BackupTest. + */ + public BackupAndClimb(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_preloadPaths) { + if (item instanceof String) { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Rotation2d targetRot; + if (m_isRed.getAsBoolean() == true) { + targetRot = Rotation2d.kZero; + } else { + targetRot = Rotation2d.k180deg; + } + + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + new DeadreckonDistance(m_DriveSubsystem, 1.0, -1), + "LineupToTower", + new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 1.0) + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java new file mode 100644 index 0000000..31e7ac9 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java @@ -0,0 +1,71 @@ +package frc.robot.commands.autoCommands; + +import java.util.function.BooleanSupplier; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import frc.robot.commands.AimAtHub; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class BackupAndShoot extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final BooleanSupplier m_isRed; + + /** + * Creates a new BackupAndShoot. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + */ + public BackupAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_isRed = isRed; + } + + // Called when the command is initially scheduled. + // TODO: Implement Launcher! + @Override + public void initialize() { + // This should do the process to make the launcher get up to speed + Command speedUpLauncher = new InstantCommand(() -> System.out.println("Speeding up launcher!")); + + Command deadreckonBackward = new DeadreckonDistance(m_driveSubsystem, 1.5, -2.0); + Command aimCommand = new AimAtHub(m_driveSubsystem, m_poseEstimator, 4.0, m_isRed); + + // This command should only end once the launcher is up to speed. + Command waitForLauncherReady = new InstantCommand(() -> System.out.println("Waiting for launcher ready!")); + + // This command should only end once it is determined for the launcher ot be empty. + Command fireLauncher = new InstantCommand(() -> System.out.println("Launching game peices!")); + + CommandScheduler.getInstance().schedule( + speedUpLauncher + .andThen(deadreckonBackward) + .andThen(aimCommand) + .andThen(waitForLauncherReady) + .andThen(fireLauncher) + ); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java new file mode 100644 index 0000000..4edf96f --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java @@ -0,0 +1,98 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.commands.WaitCommand; +import frc.robot.commands.util.AutoFromList; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class BackupAndShootThenClimb extends Command { + private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( + "LineupToTower" + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new DSA_BackupTest. + */ + public BackupAndShootThenClimb(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_preloadPaths) { + if (item instanceof String) { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Rotation2d targetRot; + if (m_isRed.getAsBoolean() == true) { + targetRot = Rotation2d.kZero; + } else { + targetRot = Rotation2d.k180deg; + } + + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + new DeadreckonDistance(m_DriveSubsystem, 1.5, -2.0), + new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 4.0, m_isRed), + //new WaitCommand(2.0), + "LineupToTower", + new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 1.0) + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index f4b7745..037ff66 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -127,44 +127,47 @@ public void initialize() { PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); if (pathFinded == false) { - // needed Values - Pose2d pathStartPose = path.getStartingDifferentialPose(); // Accounts for rotation - - Rotation2d directionRot = pathStartPose.getRotation(); - System.out.println("Direction ROT: " + String.valueOf(directionRot.getDegrees())); - - PoseDiff dPose = new PoseDiff(m_poseEstimator.getEstimatedPosition(), pathStartPose); - Rotation2d rotToPoint = new Rotation2d(Math.atan2(dPose.y, dPose.x)); - - // pathfind command - Command pathfinderCommand = AutoBuilder.pathfindToPose( - pathStartPose, - m_constraints, - path.getIdealStartingState().velocityMPS() - ); - - Command postPathfindCommand = new InstantCommand(() -> { - Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - - PathPlannerPath newPath = PathUtils.modifyPath(path, new Pair<>(0, currentPose)); - Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); - - CommandScheduler.getInstance().schedule(newPathCommand); + Command createEverythingCommand = new InstantCommand(() -> { + // needed Values + Pose2d pathStartPose = path.getStartingDifferentialPose(); // Accounts for rotation + + Rotation2d directionRot = pathStartPose.getRotation(); + System.out.println("Direction ROT: " + String.valueOf(directionRot.getDegrees())); + + PoseDiff dPose = new PoseDiff(m_poseEstimator.getEstimatedPosition(), pathStartPose); + Rotation2d rotToPoint = new Rotation2d(Math.atan2(dPose.y, dPose.x)); + + // pathfind command + Command pathfinderCommand = AutoBuilder.pathfindToPose( + pathStartPose, + m_constraints, + path.getIdealStartingState().velocityMPS() + ); + + Command postPathfindCommand = new InstantCommand(() -> { + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + + PathPlannerPath newPath = PathUtils.modifyPath(path, new Pair<>(0, currentPose)); + Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); + + CommandScheduler.getInstance().schedule(newPathCommand); + }); + + // decide what to do + Command rotateTwordPathConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, rotToPoint, 90, 2.0); + Command rotateTwordStartRotationConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, directionRot, 45, 2.0); + + // schedule it + CommandScheduler.getInstance().schedule( + rotateTwordStartRotationConditional + .andThen(pathfinderCommand) + .andThen(rotateTwordPathConditional) + .andThen(postPathfindCommand) + ); }); - - // decide what to do - Command rotateTwordPathConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, rotToPoint, 90, 2.0); - Command rotateTwordStartRotationConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, directionRot, 45, 2.0); - - // add to group - precommandGroup.addCommands( - rotateTwordPathConditional, - pathfinderCommand, - rotateTwordStartRotationConditional, - postPathfindCommand - ); - + pathFinded = true; + precommandGroup.addCommands(createEverythingCommand); } else { Command pathCommand = AutoBuilder.followPath(path); commandGroup.addCommands(pathCommand); From 1bedbe56cd458f76cf40b21c28c7fa935360263e Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 10 Mar 2026 20:49:45 -0500 Subject: [PATCH 110/161] Converted AutoFromList to use path on the fly, and fixed an issue with rotation stopping when going to fast. --- .../pathplanner/paths/LineupToTower.path | 2 +- .../frc/robot/commands/util/AutoFromList.java | 41 +++++-------- .../robot/subsystems/LimelightSubsystem.java | 29 ++++++---- .../main/java/frc/robot/utils/PathUtils.java | 57 +++++++++++++++++++ 4 files changed, 90 insertions(+), 39 deletions(-) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path index 7ce59dd..0a8712c 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/LineupToTower.path @@ -63,7 +63,7 @@ "reversed": false, "folder": null, "idealStartingState": { - "velocity": 0.5, + "velocity": 0.0, "rotation": 0.0 }, "useDefaultConstraints": true diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 037ff66..5dd6471 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -129,40 +129,27 @@ public void initialize() { if (pathFinded == false) { Command createEverythingCommand = new InstantCommand(() -> { // needed Values - Pose2d pathStartPose = path.getStartingDifferentialPose(); // Accounts for rotation + Pose2d pathStartPose = path.getStartingDifferentialPose(); + Command rotateTwordPathStart = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, pathStartPose.getRotation(), 45, 2.0); - Rotation2d directionRot = pathStartPose.getRotation(); - System.out.println("Direction ROT: " + String.valueOf(directionRot.getDegrees())); - - PoseDiff dPose = new PoseDiff(m_poseEstimator.getEstimatedPosition(), pathStartPose); - Rotation2d rotToPoint = new Rotation2d(Math.atan2(dPose.y, dPose.x)); - - // pathfind command - Command pathfinderCommand = AutoBuilder.pathfindToPose( - pathStartPose, - m_constraints, - path.getIdealStartingState().velocityMPS() - ); - - Command postPathfindCommand = new InstantCommand(() -> { + // path edits + Command pathOnTheFly = new InstantCommand(() -> { Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - PathPlannerPath newPath = PathUtils.modifyPath(path, new Pair<>(0, currentPose)); - Command newPathCommand = AutoBuilder.followPath(newPath).andThen(commandGroup); + PathPlannerPath newPath = PathUtils.appendToPath(path, 0, currentPose); + Command newPathCommand = AutoBuilder.followPath(newPath); - CommandScheduler.getInstance().schedule(newPathCommand); + // schedule the post first-path stuff + CommandScheduler.getInstance().schedule( + newPathCommand + .andThen(commandGroup) + ); }); - // decide what to do - Command rotateTwordPathConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, rotToPoint, 90, 2.0); - Command rotateTwordStartRotationConditional = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, directionRot, 45, 2.0); - - // schedule it + // schedule the first pre-path stuff CommandScheduler.getInstance().schedule( - rotateTwordStartRotationConditional - .andThen(pathfinderCommand) - .andThen(rotateTwordPathConditional) - .andThen(postPathfindCommand) + rotateTwordPathStart + .andThen(pathOnTheFly) ); }); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 9d125b0..80f2212 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -18,6 +18,7 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; import frc.robot.LimelightHelpers.IMUData; +import frc.robot.LimelightHelpers.PoseEstimate; import frc.robot.utils.LimitedQueue; public class LimelightSubsystem extends SubsystemBase { @@ -65,29 +66,35 @@ private void updateOdometry() { boolean doRejectUpdate = false; LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); - LimelightHelpers.PoseEstimate mt2 = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); - if (mt2 == null) { + PoseEstimate poseEst; + if (seenApriltag == true) { + poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); + } else { + poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); + } + + if (poseEst == null) { return; } - SmartDashboard.putNumber("mt2 Tag Count", mt2.tagCount); + SmartDashboard.putNumber("Tag Count", poseEst.tagCount); // if our angular velocity is greater than 720 degrees per second, ignore vision updates - if(Math.abs(m_gyro.getRate()) > 720) - { - doRejectUpdate = true; - } + // if(Math.abs(m_gyro.getRate()) > 720) + // { + // doRejectUpdate = true; + // } if (Math.abs(m_gyro.getPitch()) > 5) { doRejectUpdate = true; } - if(mt2.tagCount == 0) + if(poseEst.tagCount == 0) { doRejectUpdate = true; } - if (seenApriltag == false && mt2.tagCount >= 2) { + if (seenApriltag == false && poseEst.tagCount >= 2) { seenApriltag = true; doRejectUpdate = true; } @@ -107,8 +114,8 @@ private void updateOdometry() { m_poseEstimator.setVisionMeasurementStdDevs(errorVec); m_poseEstimator.addVisionMeasurement( - mt2.pose, - mt2.timestampSeconds + poseEst.pose, + poseEst.timestampSeconds ); } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java index 1633b02..5ba1a18 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java @@ -1,5 +1,6 @@ package frc.robot.utils; +import java.util.ArrayList; import java.util.List; import com.pathplanner.lib.path.GoalEndState; @@ -11,6 +12,7 @@ import edu.wpi.first.math.Pair; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.geometry.Translation2d; public class PathUtils { /** @@ -42,6 +44,61 @@ public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair baseWaypoints = basePath.getWaypoints(); + List pathWaypoints = basePath.getWaypoints(); + + Translation2d newAnchor = pointToAppend.getTranslation(); + Translation2d prevControl = null; + Translation2d nextControl = null; + + int lastWaypointIndex = pathWaypoints.size()-1; + if (index == -1) { + index = lastWaypointIndex; + } + + if (lastWaypointIndex == index) { + Waypoint prev = pathWaypoints.get(index); + prevControl = prev.anchor(); + pathWaypoints.set(index, new Waypoint(prev.prevControl(), prev.anchor(), newAnchor)); + } else if (index == 0) { + Waypoint next = pathWaypoints.get(index); + nextControl = next.anchor(); + pathWaypoints.set(index, new Waypoint(newAnchor, next.anchor(), next.nextControl())); + } else if (index > 0 && index < lastWaypointIndex) { + Waypoint prev = pathWaypoints.get(index-1); + prevControl = prev.anchor(); + pathWaypoints.set(index-1, new Waypoint(prev.prevControl(), prev.anchor(), newAnchor)); + + Waypoint next = pathWaypoints.get(index); + nextControl = next.anchor(); + pathWaypoints.set(index, new Waypoint(newAnchor, next.anchor(), next.nextControl())); + } + + if (pathWaypoints.size() > index) { + Waypoint point = new Waypoint(prevControl, newAnchor, nextControl); + pathWaypoints.add(index, point); + } + + PathPlannerPath newPath = new PathPlannerPath( + pathWaypoints, + basePath.getGlobalConstraints(), + basePath.getIdealStartingState(), + basePath.getGoalEndState(), + basePath.isReversed() + ); + + return newPath; + } + /** * This creates a path on the fly to a given target point. * From 4acaf3509b0a0ebc930ab81af8c903b2658d6846 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 13 Mar 2026 20:02:06 -0500 Subject: [PATCH 111/161] Made AutoFromList improvments. Made AutoFromList support multiple path start types. Fixed multiple AutoFromList related bugs (RotateToHub stopping all commands) --- .../java/frc/robot/commands/AimAtHub.java | 36 ++----------- .../robot/commands/RotateToRotation2D.java | 4 ++ .../commands/autoCommands/BackupAndClimb.java | 3 +- .../autoCommands/BackupAndShootThenClimb.java | 5 +- .../commands/autoCommands/CorralAndShoot.java | 3 +- .../commands/autoCommands/DepoSideAutoA.java | 3 +- .../autoCommands/TravelToCornerAndShoot.java | 3 +- .../frc/robot/commands/util/AutoFromList.java | 50 +++++++++++++------ .../main/java/frc/robot/utils/PathUtils.java | 17 ++++--- 9 files changed, 65 insertions(+), 59 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java index f67d00d..17642b8 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java @@ -4,15 +4,11 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.HubUtils; /** An example command that uses an example subsystem. */ -public class AimAtHub extends Command { - private final DriveSubsystem m_driveSubsystem; +public class AimAtHub extends RotateToRotation2D { private final DifferentialDrivePoseEstimator m_poseEstimator; - private final double m_maxSpeed; private final BooleanSupplier m_isRed; /** @@ -25,39 +21,17 @@ public class AimAtHub extends Command { */ public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, double maxSpeed, BooleanSupplier isRed) { - m_driveSubsystem = driveSubsystem; + super(driveSubsystem, poseEstimator, Rotation2d.kZero, maxSpeed); + m_poseEstimator = poseEstimator; - m_maxSpeed = maxSpeed; m_isRed = isRed; - - addRequirements(driveSubsystem); } // Called when the command is initially scheduled. @Override public void initialize() { Rotation2d targetRotation = HubUtils.getRobotToHubAngle(m_poseEstimator, m_isRed); - RotateToRotation2D aimCommand = new RotateToRotation2D( - m_driveSubsystem, - m_poseEstimator, - targetRotation, - m_maxSpeed - ); - - CommandScheduler.getInstance().schedule(aimCommand); - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - return true; + super.setTargetRotation(targetRotation); + super.initialize(); } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java index 73ca7cf..22addc3 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateToRotation2D.java @@ -90,4 +90,8 @@ public boolean isFinished() { return false; } } + + protected void setTargetRotation(Rotation2d newRotation) { + m_targetRotation = newRotation; + } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java index 598df89..083c392 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java @@ -15,6 +15,7 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.commands.RotateToRotation2D; import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ @@ -70,7 +71,7 @@ public void initialize() { )); // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); CommandScheduler.getInstance().schedule(auto); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java index 4edf96f..31a3bcd 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShootThenClimb.java @@ -17,6 +17,7 @@ import frc.robot.commands.RotateToRotation2D; import frc.robot.commands.WaitCommand; import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ @@ -68,13 +69,13 @@ public void initialize() { ArrayList sequence = new ArrayList(Arrays.asList( new DeadreckonDistance(m_DriveSubsystem, 1.5, -2.0), new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 4.0, m_isRed), - //new WaitCommand(2.0), + new WaitCommand(2.0), "LineupToTower", new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 1.0) )); // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.REPLACE_FIRST_PATH, false); CommandScheduler.getInstance().schedule(auto); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java index d772184..c9efc48 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/CorralAndShoot.java @@ -14,6 +14,7 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.commands.AimAtHub; import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ @@ -64,7 +65,7 @@ public void initialize() { // !! DO NOT DO THIS!! LOOK AT "DepoSideAutoA.java" FOR A BETTER REFRENCE !! // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); CommandScheduler.getInstance().schedule(auto); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java index 96c2821..998b987 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java @@ -22,6 +22,7 @@ import frc.robot.commands.StopIntakeCommand; import frc.robot.commands.StopLiftCommand; import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ @@ -114,7 +115,7 @@ public void initialize() { )); // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, false, false); + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.NONE, false); CommandScheduler.getInstance().schedule(auto); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java index 7d315cb..f910454 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/TravelToCornerAndShoot.java @@ -14,6 +14,7 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.commands.AimAtHub; import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; /** An example command that uses an example subsystem. */ @@ -61,7 +62,7 @@ public void initialize() { )); // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, true, false); + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); CommandScheduler.getInstance().schedule(auto); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 5dd6471..f971b9f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -7,18 +7,16 @@ import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; +import edu.wpi.first.math.Pair; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; -import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.InstantCommand; +import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.ConditionalRotation; import frc.robot.utils.PathUtils; -import frc.robot.utils.PoseDiff; -import edu.wpi.first.math.Pair; // Auto From Path Names And Commands public class AutoFromList extends Command { @@ -26,7 +24,13 @@ public class AutoFromList extends Command { private final PathConstraints m_constraints; private final DriveSubsystem m_DriveSubsystem; private final DifferentialDrivePoseEstimator m_poseEstimator; - private final Boolean m_pathfindToFirstPath; + private final firstPathType m_pathType; + + public enum firstPathType { + NONE, + GO_TO_FIRST_PATH, + REPLACE_FIRST_PATH, + } /** * Creates and runs a new auto from a list of path names and commands. @@ -44,7 +48,7 @@ public AutoFromList(List sequence, PathConstraints constraints, DriveSub m_constraints = constraints; m_DriveSubsystem = driveSubsystem; m_poseEstimator = poseEstimator; - m_pathfindToFirstPath = true; + m_pathType = firstPathType.GO_TO_FIRST_PATH; warmup(); } @@ -58,15 +62,15 @@ public AutoFromList(List sequence, PathConstraints constraints, DriveSub * @param constraints The constraints the pathfinder segment of the auto uses. * @param driveSubsystem The driveSubsystem, pass-ins for rotation corrections. * @param poseEstimator The pose estimator, used to get the robots location. - * @param pathfindToFirstpath Should the command pathfind to the first path? + * @param goToFirstPath Should the command pathfind to the first path? */ - public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, boolean pathfindToFirstpath) + public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, firstPathType pathType) { m_sequence = sequence; m_constraints = constraints; m_DriveSubsystem = driveSubsystem; m_poseEstimator = poseEstimator; - m_pathfindToFirstPath = pathfindToFirstpath; + m_pathType = pathType; warmup(); } @@ -79,16 +83,16 @@ public AutoFromList(List sequence, PathConstraints constraints, DriveSub * @param constraints The constraints the pathfinder segment of the auto uses. * @param driveSubsystem The driveSubsystem, pass-ins for rotation corrections. * @param poseEstimator The pose estimator, used to get the robots location. - * @param pathfindToFirstpath Should the command pathfind to the first path? + * @param goToFirstPath Should the command go to the first path? * @param doWarmup Should the command warm-up the paths itself? (If instantiated and ran during run-time, you might want this to be set to false) */ - public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, boolean pathfindToFirstpath, boolean doWarmup) + public AutoFromList(List sequence, PathConstraints constraints, DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, firstPathType pathType, boolean doWarmup) { m_sequence = sequence; m_constraints = constraints; m_DriveSubsystem = driveSubsystem; m_poseEstimator = poseEstimator; - m_pathfindToFirstPath = pathfindToFirstpath; + m_pathType = pathType; if (doWarmup == true) { warmup(); @@ -114,32 +118,43 @@ public void initialize() { try { SequentialCommandGroup precommandGroup = new SequentialCommandGroup(); SequentialCommandGroup commandGroup = new SequentialCommandGroup(); - Boolean pathFinded = !m_pathfindToFirstPath; // If we want to pathfind this will be set to false. + Boolean pathFinded = m_pathType == firstPathType.NONE; // If we want to pathfind this will be set to false. for (Object item : m_sequence) { if (item instanceof Command) { if (pathFinded == false) { precommandGroup.addCommands((Command) item); + System.out.println("Added " + item.getClass().getName() + " to preCommandGroup!"); } else { commandGroup.addCommands((Command) item); + System.out.println("Added " + item.getClass().getName() + " to commandGroup!"); } } else if (item instanceof String) { PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); if (pathFinded == false) { - Command createEverythingCommand = new InstantCommand(() -> { + Command createEverythingCommand = Commands.runOnce(() -> { // needed Values Pose2d pathStartPose = path.getStartingDifferentialPose(); Command rotateTwordPathStart = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, pathStartPose.getRotation(), 45, 2.0); // path edits - Command pathOnTheFly = new InstantCommand(() -> { + Command pathOnTheFly = Commands.runOnce(() -> { Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); - PathPlannerPath newPath = PathUtils.appendToPath(path, 0, currentPose); + PathPlannerPath newPath; + if (m_pathType == firstPathType.GO_TO_FIRST_PATH) { + newPath = PathUtils.appendToPath(path, 0, currentPose); + } else if (m_pathType == firstPathType.REPLACE_FIRST_PATH) { + newPath = PathUtils.modifyPath(path, new Pair(0, currentPose)); + } else { + newPath = path; + } + Command newPathCommand = AutoBuilder.followPath(newPath); // schedule the post first-path stuff + System.out.println("Schedueling commandGroup!"); CommandScheduler.getInstance().schedule( newPathCommand .andThen(commandGroup) @@ -147,6 +162,7 @@ public void initialize() { }); // schedule the first pre-path stuff + System.out.println("Schedueling the path on the fly stuff!"); CommandScheduler.getInstance().schedule( rotateTwordPathStart .andThen(pathOnTheFly) @@ -155,6 +171,7 @@ public void initialize() { pathFinded = true; precommandGroup.addCommands(createEverythingCommand); + System.out.println("Added createEverything to preCommandGroup!"); } else { Command pathCommand = AutoBuilder.followPath(path); commandGroup.addCommands(pathCommand); @@ -162,6 +179,7 @@ public void initialize() { } } + System.out.println("Schedueling preCommandGroup!"); CommandScheduler.getInstance().schedule(precommandGroup); } catch (Exception e) { // do somthing here diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java index 5ba1a18..014a832 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java @@ -24,17 +24,23 @@ public class PathUtils { */ @SafeVarargs public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair... pointsToModify) { - List pathPoses = basePath.getPathPoses(); + List pathWaypoints = basePath.getWaypoints(); for (Pair point : pointsToModify) { Integer index = point.getFirst(); - if (pathPoses.size() > index && index >= 0) { - pathPoses.set(index, point.getSecond()); + if (pathWaypoints.size() > index && index >= 0) { + Waypoint oldPoint = pathWaypoints.get(index); + Waypoint newPoint = new Waypoint( + oldPoint.prevControl(), + point.getSecond().getTranslation(), + oldPoint.nextControl() + ); + + pathWaypoints.set(index, newPoint); } } - List waypoints = PathPlannerPath.waypointsFromPoses(pathPoses); PathPlannerPath newPath = new PathPlannerPath( - waypoints, + pathWaypoints, basePath.getGlobalConstraints(), basePath.getIdealStartingState(), basePath.getGoalEndState(), @@ -53,7 +59,6 @@ public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair baseWaypoints = basePath.getWaypoints(); List pathWaypoints = basePath.getWaypoints(); Translation2d newAnchor = pointToAppend.getTranslation(); From bbb9994666ca2d2b88dc8bdf6e6889a98648c754 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 13 Mar 2026 20:52:14 -0500 Subject: [PATCH 112/161] Started on collect from depot and shoot auto --- .../paths/FromDepoTowerLineup.path | 70 +++++++++++++ .../deploy/pathplanner/paths/GatherDepot.path | 70 +++++++++++++ .../main/java/frc/robot/RobotContainer.java | 5 + .../BackupCollectDepoAndShoot.java | 97 +++++++++++++++++++ .../robot/subsystems/LimelightSubsystem.java | 8 +- 5 files changed, 246 insertions(+), 4 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherDepot.path create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path new file mode 100644 index 0000000..51f4fa3 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 0.84, + "y": 7.128 + }, + "prevControl": null, + "nextControl": { + "x": 1.1190910337101736, + "y": 7.418718411702091 + }, + "isLocked": true, + "linkedName": null + }, + { + "anchor": { + "x": 1.8163461538461552, + "y": 6.825769230769231 + }, + "prevControl": { + "x": 1.7045686383647336, + "y": 7.352720375181646 + }, + "nextControl": { + "x": 2.0605384615384628, + "y": 5.674576923076922 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.432615384615386, + "y": 3.744294871794872 + }, + "prevControl": { + "x": 2.864585292835296, + "y": 3.744294871794872 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 6.271077449501154 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherDepot.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherDepot.path new file mode 100644 index 0000000..e7aeec2 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherDepot.path @@ -0,0 +1,70 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 2.1070512820512834, + "y": 4.942 + }, + "prevControl": null, + "nextControl": { + "x": 1.5023846153846168, + "y": 4.965256410256412 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.0140000000000011, + "y": 5.093166666666667 + }, + "prevControl": { + "x": 1.4363182059175275, + "y": 4.95259912183499 + }, + "nextControl": { + "x": -0.03267948717948488, + "y": 5.441551282051282 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 1.0140000000000011, + "y": 7.128102564102565 + }, + "prevControl": { + "x": 0.7349230769230779, + "y": 6.837397435897437 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 08d3368..461a233 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -47,6 +47,7 @@ import frc.robot.commands.autoCommands.BackupAndClimb; import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.BackupAndShootThenClimb; +import frc.robot.commands.autoCommands.BackupCollectDepoAndShoot; import frc.robot.commands.autoCommands.CorralAndShoot; import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; import frc.robot.commands.autoCommands.DeadreckonDistance; @@ -197,6 +198,10 @@ private void configureAutos() { new BackupAndShootThenClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); + m_autoChooser.addOption("[INDEV] Backup and collect from depot then shoot", + new BackupCollectDepoAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + ); + // Test Autos PathConstraints slowConstraints = new PathConstraints( 1.0, diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java new file mode 100644 index 0000000..93e0d44 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java @@ -0,0 +1,97 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.RotateToRotation2D; +import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class BackupCollectDepoAndShoot extends Command { + private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( + "GatherDepot" + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new DSA_BackupTest. + */ + public BackupCollectDepoAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_preloadPaths) { + if (item instanceof String) { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + Rotation2d targetRot; + if (m_isRed.getAsBoolean() == true) { + targetRot = Rotation2d.kZero; + } else { + targetRot = Rotation2d.k180deg; + } + + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + new DeadreckonDistance(m_DriveSubsystem, 0.5, -1.0), + new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 2.0), + "GatherDepot", + new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 3.0, m_isRed) + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 80f2212..cea76e1 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -80,10 +80,10 @@ private void updateOdometry() { SmartDashboard.putNumber("Tag Count", poseEst.tagCount); // if our angular velocity is greater than 720 degrees per second, ignore vision updates - // if(Math.abs(m_gyro.getRate()) > 720) - // { - // doRejectUpdate = true; - // } + if(Math.abs(m_gyro.getRate()) > 80) + { + doRejectUpdate = true; + } if (Math.abs(m_gyro.getPitch()) > 5) { doRejectUpdate = true; From dc84c21e1fcf74680ce8cdd75de39acc88dca5a9 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Mar 2026 10:05:11 -0500 Subject: [PATCH 113/161] Add indexer motor and update test mode to include it --- 2026-Rebuilt/elastic-layout.json | 138 ++++++++++++++---- .../src/main/java/frc/robot/Constants.java | 12 +- .../subsystems/IndexerBulkSubsystem.java | 74 +++++++++- 3 files changed, 191 insertions(+), 33 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 752a766..2b67c00 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -1,6 +1,6 @@ { "version": 1.0, - "grid_size": 64, + "grid_size": 32, "tabs": [ { "name": "Toaster Testing", @@ -229,7 +229,7 @@ { "title": "Raised", "x": 448.0, - "y": 128.0, + "y": 192.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -246,9 +246,9 @@ { "title": "Hub Distance", "x": 192.0, - "y": 128.0, + "y": 96.0, "width": 192.0, - "height": 128.0, + "height": 96.0, "type": "Text Display", "properties": { "topic": "/SmartDashboard/Hub Distance", @@ -260,7 +260,7 @@ { "title": "Running", "x": 640.0, - "y": 128.0, + "y": 192.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -279,7 +279,7 @@ "x": 640.0, "y": 0.0, "width": 128.0, - "height": 128.0, + "height": 96.0, "type": "Toggle Switch", "properties": { "topic": "/SmartDashboard/IndexerBulk TestBulk", @@ -289,10 +289,10 @@ }, { "title": "Intake Extend", - "x": 832.0, + "x": 960.0, "y": 0.0, "width": 128.0, - "height": 128.0, + "height": 96.0, "type": "Toggle Switch", "properties": { "topic": "/SmartDashboard/Intake TestExtend", @@ -302,10 +302,10 @@ }, { "title": "Intake Run", - "x": 960.0, + "x": 1088.0, "y": 0.0, "width": 128.0, - "height": 128.0, + "height": 96.0, "type": "Toggle Switch", "properties": { "topic": "/SmartDashboard/Intake TestRun", @@ -315,8 +315,8 @@ }, { "title": "Running", - "x": 960.0, - "y": 128.0, + "x": 1088.0, + "y": 192.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -332,8 +332,8 @@ }, { "title": "Extended", - "x": 832.0, - "y": 128.0, + "x": 960.0, + "y": 192.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -350,9 +350,9 @@ { "title": "Launcher RPM", "x": 0.0, - "y": 128.0, + "y": 96.0, "width": 192.0, - "height": 128.0, + "height": 96.0, "type": "Text Display", "properties": { "topic": "/SmartDashboard/Launcher RPM", @@ -366,7 +366,7 @@ "x": 0.0, "y": 0.0, "width": 192.0, - "height": 128.0, + "height": 96.0, "type": "Text Display", "properties": { "topic": "/SmartDashboard/Launcher TestRPM", @@ -380,7 +380,7 @@ "x": 192.0, "y": 0.0, "width": 192.0, - "height": 128.0, + "height": 96.0, "type": "Text Display", "properties": { "topic": "/SmartDashboard/Launcher TestLiftSpeed", @@ -392,7 +392,7 @@ { "title": "Fuel Present", "x": 0.0, - "y": 256.0, + "y": 192.0, "width": 192.0, "height": 64.0, "type": "Boolean Box", @@ -409,7 +409,7 @@ { "title": "Subsystem", "x": 448.0, - "y": 320.0, + "y": 352.0, "width": 128.0, "height": 64.0, "type": "Boolean Box", @@ -426,7 +426,7 @@ { "title": "Drive Subsystem", "x": 192.0, - "y": 320.0, + "y": 192.0, "width": 192.0, "height": 64.0, "type": "Boolean Box", @@ -443,8 +443,8 @@ { "title": "Subsystem", "x": 640.0, - "y": 320.0, - "width": 128.0, + "y": 352.0, + "width": 256.0, "height": 64.0, "type": "Boolean Box", "properties": { @@ -459,8 +459,8 @@ }, { "title": "Subsystem", - "x": 832.0, - "y": 320.0, + "x": 960.0, + "y": 352.0, "width": 256.0, "height": 64.0, "type": "Boolean Box", @@ -477,7 +477,7 @@ { "title": "Subsystem", "x": 0.0, - "y": 320.0, + "y": 352.0, "width": 192.0, "height": 64.0, "type": "Boolean Box", @@ -490,6 +490,92 @@ "true_icon": "None", "false_icon": "None" } + }, + { + "title": "Speed", + "x": 640.0, + "y": 256.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/IndexerBulk BulkSpeed", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Speed", + "x": 768.0, + "y": 256.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/IndexerBulk IndexerSpeed", + "period": 0.06, + "data_type": "double", + "show_submit_button": false + } + }, + { + "title": "Indexer Run", + "x": 768.0, + "y": 0.0, + "width": 128.0, + "height": 96.0, + "type": "Toggle Switch", + "properties": { + "topic": "/SmartDashboard/IndexerBulk TestIndexer", + "period": 0.06, + "data_type": "boolean" + } + }, + { + "title": "Running", + "x": 768.0, + "y": 192.0, + "width": 128.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/IndexerBulk IndexerStarted", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Set Speed", + "x": 640.0, + "y": 96.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/IndexerBulk TestBulkSpeed", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Set Speed", + "x": 768.0, + "y": 96.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/IndexerBulk TestIndexerSpeed", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 7c64782..49fed02 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -27,9 +27,10 @@ // // Current Solenoid Channels: // -// 0 - Intake retract -// 1 - Climb L1 Left -// 2 - Climb L1 Right +// 0 - Intake double channel 1 +// 1 - Intake double channel 2 +// 2 - Climb L1 Left +// 3 - Climb L1 Right package frc.robot; @@ -150,6 +151,7 @@ public static class IntakeConstants { // Solenoid states required to extend and retract the intake mechanism. public static int kIntakeSolenoid = 0; + public static int kIntakeSolenoid1 = 0; public static boolean kIntakeExtend = true; public static boolean kIntakeRetract = !kIntakeExtend; } @@ -198,10 +200,12 @@ public static class LauncherConstants { } public static class IndexerBulkConstants { - public static int kBulkMoveMotorCANID = 50; + public static int kIndexerMotorCANID = 50; + public static int kBulkMoveMotorCANID = 51; // Raw motor speeds in range [-1.0,1.0] public static final double kBulkMoveMotorSpeed = 0.3; + public static final double kIndexerMotorSpeed = 0.3; } public static class ClimbL1Constants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index ace9406..cc6389f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -10,12 +10,12 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj.DigitalInput; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.Constants.IndexerBulkConstants; import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXSConfiguration; +import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.hardware.TalonFXS; import com.ctre.phoenix6.signals.MotorArrangementValue; @@ -23,7 +23,11 @@ public class IndexerBulkSubsystem extends SubsystemBase { private TalonFXS m_motorBulk; + private TalonFX m_motorIndexer; private Boolean m_bulkStarted = false; + private Boolean m_indexerStarted = false; + private double m_bulkSpeed = IndexerBulkConstants.kBulkMoveMotorSpeed; + private double m_indexerSpeed = IndexerBulkConstants.kIndexerMotorSpeed; /** Creates a new IndexerBulkSubsystem. */ public IndexerBulkSubsystem() throws Exception { @@ -31,9 +35,15 @@ public IndexerBulkSubsystem() throws Exception { // Create SmartDashboard items first so that these are populated // regardless of whether or not the subsystem is present. SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); + SmartDashboard.putBoolean("IndexerBulk IndexerStarted", m_indexerStarted); + SmartDashboard.putNumber("IndexerBulk BulkSpeed", m_bulkSpeed); + SmartDashboard.putNumber("IndexerBulk IndexerSpeed", m_indexerSpeed); // Test mode controls SmartDashboard.putBoolean("IndexerBulk TestBulk", false); + SmartDashboard.putBoolean("IndexerBulk TestIndexer", false); + SmartDashboard.putNumber("IndexerBulk TestBulkSpeed", m_bulkSpeed); + SmartDashboard.putNumber("IndexerBulk TestIndexerSpeed", m_indexerSpeed); m_motorBulk = new TalonFXS(IndexerBulkConstants.kBulkMoveMotorCANID); if (!m_motorBulk.isConnected()) @@ -41,6 +51,12 @@ public IndexerBulkSubsystem() throws Exception { throw new Exception("Bult transport motor is not present."); } + m_motorIndexer = new TalonFX(IndexerBulkConstants.kIndexerMotorCANID); + if (!m_motorIndexer.isConnected()) + { + throw new Exception("Indexer motor is not present."); + } + TalonFXSConfiguration motorConfig = new TalonFXSConfiguration(); motorConfig.Commutation.MotorArrangement = MotorArrangementValue.Minion_JST; StatusCode status = StatusCode.StatusCodeNotInitialized; @@ -56,7 +72,7 @@ public IndexerBulkSubsystem() throws Exception { // Runs the belts that transfer the fuel from bulk storage to the indexer. public void startBulkTransfer() { - m_motorBulk.set(IndexerBulkConstants.kBulkMoveMotorSpeed); + m_motorBulk.set(m_bulkSpeed); m_bulkStarted = true; SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); } @@ -68,6 +84,39 @@ public void stopBulkTransfer() { SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); } + public void setBulkTransferSpeed(double speed) { + m_bulkSpeed = speed; + if(m_bulkStarted) + { + startBulkTransfer(); + } + SmartDashboard.putNumber("IndexerBulk BulkSpeed", m_bulkSpeed); + } + + // Runs the indexer. + public void startIndexer() { + m_motorBulk.set(m_indexerSpeed); + m_indexerStarted = true; + SmartDashboard.putBoolean("IndexerBulk IndexerStarted", m_indexerStarted); + } + +// Stops the indexer. + public void stopIndexer() { + m_motorIndexer.set(0.0); + m_indexerStarted = false; + SmartDashboard.putBoolean("IndexerBulk IndexerStarted", m_indexerStarted); + } + + public void setIndexerSpeed(double speed) { + m_indexerSpeed = speed; + if(m_indexerStarted) + { + startIndexer(); + } + + SmartDashboard.putNumber("IndexerBulk IndexerSpeed", m_indexerSpeed); + } + @Override public void periodic() { // This method will be called once per scheduler run @@ -80,8 +129,15 @@ public void simulationPeriodic() { public void testPeriodic() { // Set the motor states based on the SmartDashboard test controls. - Boolean BulkOn = SmartDashboard.getBoolean("IndexerBulk TestBulk", false); + Boolean BulkOn = SmartDashboard.getBoolean("IndexerBulk TestBulk", false); + Boolean IndexerOn = SmartDashboard.getBoolean("IndexerBulk TestIndexer", false); + double BulkSpeed = SmartDashboard.getNumber("IndexerBulk TestBulkSpeed", m_bulkSpeed); + double IndexerSpeed = SmartDashboard.getNumber("IndexerBulk TestIndexerSpeed", m_indexerSpeed); + // Set new target speeds for each motor. + setBulkTransferSpeed(BulkSpeed); + setIndexerSpeed(IndexerSpeed); + // Turn the bulk transfer on or off depending upon test control, only changing the state if the control actually changed. if(BulkOn) { if(!m_bulkStarted) { @@ -93,5 +149,17 @@ public void testPeriodic() { this.stopBulkTransfer(); } } + + // Turn the indexer on or off depending upon test control, only changing the state if the control actually changed. + if(IndexerOn) { + if(!m_indexerStarted) { + this.startIndexer(); + } + } + else { + if(m_indexerStarted) { + this.stopIndexer(); + } + } } } From 97b80f47638186cde5f4fa9a6caea47a90d860ad Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 14 Mar 2026 11:06:05 -0500 Subject: [PATCH 114/161] Motor bring up and debug. Inverted indexer motor direction and fixed typo on indexer --- .../src/main/java/frc/robot/Constants.java | 2 +- .../frc/robot/subsystems/IndexerBulkSubsystem.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 49fed02..b0601e6 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -166,7 +166,7 @@ public static class LauncherConstants { // Beam break sensor to detect fuel at the top of the lift. public static final int kUpperFuelSensorChannel = 0; - public static final boolean kUpperFuelSensorIsEmpty = false; + public static final boolean kUpperFuelSensorIsEmpty = true; // These numbers came from the ctre example then tweaked public static final double kS = 0.1; // A velocity target of 1 rps results in xV output diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index cc6389f..25d2b48 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -46,10 +46,13 @@ public IndexerBulkSubsystem() throws Exception { SmartDashboard.putNumber("IndexerBulk TestIndexerSpeed", m_indexerSpeed); m_motorBulk = new TalonFXS(IndexerBulkConstants.kBulkMoveMotorCANID); - if (!m_motorBulk.isConnected()) - { - throw new Exception("Bult transport motor is not present."); - } + + // TODO: Temporarily removed until bulk motor is populated. Reinstate this! + // + // if (!m_motorBulk.isConnected()) + // { + // throw new Exception("Bult transport motor is not present."); + // } m_motorIndexer = new TalonFX(IndexerBulkConstants.kIndexerMotorCANID); if (!m_motorIndexer.isConnected()) @@ -95,7 +98,8 @@ public void setBulkTransferSpeed(double speed) { // Runs the indexer. public void startIndexer() { - m_motorBulk.set(m_indexerSpeed); + // Indexer runs in the negative direction when operating normally so we negate the commanded speed. + m_motorIndexer.set(-m_indexerSpeed); m_indexerStarted = true; SmartDashboard.putBoolean("IndexerBulk IndexerStarted", m_indexerStarted); } From 1ab2fd3845f6c093088fb9739f16bdf8aab6bfef Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 14 Mar 2026 11:29:19 -0500 Subject: [PATCH 115/161] Launcher graph added to elastic Added a launcher graph to elastic that tracks speed. --- 2026-Rebuilt/elastic-layout.json | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 2b67c00..5598b26 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -275,7 +275,7 @@ } }, { - "title": "Transfer Run", + "title": "Bulk Run", "x": 640.0, "y": 0.0, "width": 128.0, @@ -425,8 +425,8 @@ }, { "title": "Drive Subsystem", - "x": 192.0, - "y": 192.0, + "x": 0.0, + "y": 448.0, "width": 192.0, "height": 64.0, "type": "Boolean Box", @@ -478,7 +478,7 @@ "title": "Subsystem", "x": 0.0, "y": 352.0, - "width": 192.0, + "width": 384.0, "height": 64.0, "type": "Boolean Box", "properties": { @@ -576,6 +576,24 @@ "data_type": "double", "show_submit_button": true } + }, + { + "title": "Launcher RPM", + "x": 1248.0, + "y": 0.0, + "width": 640.0, + "height": 416.0, + "type": "Graph", + "properties": { + "topic": "/SmartDashboard/Launcher RPM", + "period": 0.033, + "data_type": "double", + "time_displayed": 15.0, + "min_value": 0.0, + "max_value": 4000.0, + "color": 4278238420, + "line_width": 2.0 + } } ] } From 6a7f589757f506a5ae598065c204ff09e172384f Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Mar 2026 12:20:28 -0500 Subject: [PATCH 116/161] Add test mode dashboard control of launcher PID tuning parameters --- 2026-Rebuilt/elastic-layout.json | 70 ++++++++++++++ .../robot/subsystems/LauncherSubsystem.java | 92 +++++++++++++------ 2 files changed, 136 insertions(+), 26 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 5598b26..77574ab 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -594,6 +594,76 @@ "color": 4278238420, "line_width": 2.0 } + }, + { + "title": "Launcher P", + "x": 224.0, + "y": 448.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestP", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Launcher I", + "x": 352.0, + "y": 448.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestI", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "Launcher D", + "x": 480.0, + "y": 448.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestD", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "MMAccel", + "x": 608.0, + "y": 448.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestMMAccel", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } + }, + { + "title": "MMJerk", + "x": 736.0, + "y": 448.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Launcher TestMMJerk", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 28eec70..1091f5f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -32,6 +32,13 @@ public class LauncherSubsystem extends SubsystemBase { private TalonFX m_motorLeader; private TalonFX m_motorFollower; private TalonFX m_motorLift; + private TalonFXConfiguration m_MotorConfigs = new TalonFXConfiguration(); + + private double m_P = LauncherConstants.kP; + private double m_I = LauncherConstants.kI; + private double m_D = LauncherConstants.kD; + private double m_MMAccel = LauncherConstants.kMotionMagicAcceleration; + private double m_MMJerk = LauncherConstants.kMotionMagicJerk; private final DigitalInput m_Sensor = new DigitalInput(LauncherConstants.kUpperFuelSensorChannel); @@ -52,6 +59,11 @@ public LauncherSubsystem() throws Exception { // Test mode controls SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); SmartDashboard.putNumber("Launcher TestLiftSpeed", 0.0 ); + SmartDashboard.putNumber("Launcher TestP", m_P ); + SmartDashboard.putNumber("Launcher TestI", m_I ); + SmartDashboard.putNumber("Launcher TestD", m_D ); + SmartDashboard.putNumber("Launcher TestMMAccel", m_MMAccel ); + SmartDashboard.putNumber("Launcher TestMMJerk", m_MMJerk ); m_motorLift = new TalonFX(LauncherConstants.kLauncherLiftMotorCANID); m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); @@ -62,35 +74,34 @@ public LauncherSubsystem() throws Exception { { throw new Exception("At least one launcher motor is not present!"); } - - TalonFXConfiguration configs = new TalonFXConfiguration(); - /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ - configs.Slot0.kS = LauncherConstants.kS; // To account for friction, add 0.1 V of static feedforward - configs.Slot0.kV = LauncherConstants.kV; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second - configs.Slot0.kP = LauncherConstants.kP; // An error of 1 rotation per second results in 0.11 V output - configs.Slot0.kI = LauncherConstants.kI; // No output for integrated error - configs.Slot0.kD = LauncherConstants.kD; // No output for error derivative - // Peak output of 8 volts - configs.Voltage.withPeakForwardVoltage(Volts.of(8)) - .withPeakReverseVoltage(Volts.of(-8)); - - var motionMagicConfigs = configs.MotionMagic; - motionMagicConfigs.MotionMagicAcceleration = LauncherConstants.kMotionMagicAcceleration; - motionMagicConfigs.MotionMagicJerk = LauncherConstants.kMotionMagicJerk; + setMotorPIDConfigs(m_MotorConfigs); // Set coast mode so that the flywheel doesn't slam to a halt when the // motors stop. - configs.MotorOutput.NeutralMode = NeutralModeValue.Coast; + m_MotorConfigs.MotorOutput.NeutralMode = NeutralModeValue.Coast; // Set the basic rotation direction for both motors. Note that this setting // will be ignored by the follower since we explicitly tell it whether to // run in the same direction as or the opposite direction from the leader // when we set up the follow relationship below. - configs.MotorOutput.Inverted = LauncherConstants.kLauncherMotorForwardIsCCW ? - InvertedValue.CounterClockwise_Positive : - InvertedValue.Clockwise_Positive; + m_MotorConfigs.MotorOutput.Inverted = LauncherConstants.kLauncherMotorForwardIsCCW ? + InvertedValue.CounterClockwise_Positive : + InvertedValue.Clockwise_Positive; + applyMotorConfigs(m_MotorConfigs); + + // Set up the follower. Note that setting MotorAlignmentValue tells the system to ignore the + // follower's MotorOutput.Inverted setting and either run the same direction as, or the opposite + // direction from, the leader. + m_motorFollower.setControl(new Follower(m_motorLeader.getDeviceID(), + LauncherConstants.kMotorsDriveInOppositeDirections ? + MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); + m_configValid = true; + } + + public void applyMotorConfigs(TalonFXConfiguration configs) + { /* Retry config apply up to 5 times, report if failure */ StatusCode status = StatusCode.StatusCodeNotInitialized; for (int i = 0; i < 5; ++i) { @@ -107,15 +118,23 @@ public LauncherSubsystem() throws Exception { if (!status.isOK()) { System.out.println("Could not apply configs 2, error code: " + status.toString()); } + } - // Set up the follower. Note that setting MotorAlignmentValue tells the system to ignore the - // follower's MotorOutput.Inverted setting and either run the same direction as, or the opposite - // direction from, the leader. - m_motorFollower.setControl(new Follower(m_motorLeader.getDeviceID(), - LauncherConstants.kMotorsDriveInOppositeDirections ? - MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); + public void setMotorPIDConfigs(TalonFXConfiguration configs) + { + /* Voltage-based velocity requires a velocity feed forward to account for the back-emf of the motor */ + configs.Slot0.kS = LauncherConstants.kS; // To account for friction, add 0.1 V of static feedforward + configs.Slot0.kV = LauncherConstants.kV; // Kraken X60 is a 500 kV motor, 500 rpm per V = 8.333 rps per V, 1/8.33 = 0.12 volts / rotation per second + configs.Slot0.kP = m_P; // An error of 1 rotation per second results in 0.11 V output + configs.Slot0.kI = m_I; // No output for integrated error + configs.Slot0.kD = m_D; // No output for error derivative + // Peak output of 8 volts + configs.Voltage.withPeakForwardVoltage(Volts.of(8)) + .withPeakReverseVoltage(Volts.of(-8)); - m_configValid = true; + var motionMagicConfigs = configs.MotionMagic; + motionMagicConfigs.MotionMagicAcceleration = m_MMAccel; + motionMagicConfigs.MotionMagicJerk = m_MMJerk; } // @@ -220,6 +239,27 @@ public void periodic() { } public void testPeriodic() { + + double NewP = SmartDashboard.getNumber("Launcher TestP", m_P ); + double NewI = SmartDashboard.getNumber("Launcher TestI", m_I ); + double NewD = SmartDashboard.getNumber("Launcher TestD", m_D ); + double NewMMAccel = SmartDashboard.getNumber("Launcher TestMMAccel", m_MMAccel ); + double NewMMJerk = SmartDashboard.getNumber("Launcher TestMMJerk", m_MMJerk ); + + // Did any of the PID tuning parameters change? + if ((NewP != m_P) || (NewI != m_I) || (NewD != m_D) || (NewMMAccel != m_MMAccel) || (NewMMJerk != m_MMJerk)) + { + // Yes - something changed. Update the motor configuration to reflect the new tuning parameters. + m_P = NewP; + m_I = NewI; + m_D = NewD; + m_MMAccel = NewMMAccel; + m_MMJerk = NewMMJerk; + + setMotorPIDConfigs(m_MotorConfigs); + applyMotorConfigs(m_MotorConfigs); + } + double launcherrpm = SmartDashboard.getNumber("Launcher TestRPM", 0.0 ); double liftspeed = SmartDashboard.getNumber("Launcher TestLiftSpeed", 0.0 ); From e959b92d8e81a9ebda84799b72b63602b26f813e Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 14 Mar 2026 14:57:49 -0500 Subject: [PATCH 117/161] Update LauncherUtils with characterization data --- .../java/frc/robot/utils/LauncherUtils.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java index a24b303..d0398b2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java @@ -2,23 +2,17 @@ public class LauncherUtils { // - // TODO: This table must be filled in either data determined experimentally - // on the final robot. The first column is the distance from the hub center - // and the second is the flywheel RPM required to successfully launch fuel into - // the hub from that distance. Values must be ordered by distance with the lowest - // distance value first. - // - // This array must have at least 3 rows! - // - // The data here is currently completely fabricated just to allow the code to - // be debugged!!!! + // Characterization data for the launcher. This table links shooting + // distance to known-good launcher speeds. Distances are from the centre + // of the robot base to the centre of the hub. // private static final double[][] m_DistanceToRPM = { - {1.0, 2000.0}, - {2.0, 2400.0}, - {3.0, 3000.0}, - {4.0, 4000.0}, + {2.44, 2470.0}, + {3.12, 2700.0}, + {3.81, 2800.0}, + {5.21, 3300.0}, }; + // // Given a distance between the robot and the hub, calculate the // launcher flywheel speed needed to successfully score fuel from From ea625a700915d1cb6d356ea8d4814667c22cce73 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:00:08 -0500 Subject: [PATCH 118/161] Converted to pidgeon and autos --- .../paths/FromDepoTowerLineup.path | 12 +- .../src/main/java/frc/robot/Constants.java | 12 ++ .../main/java/frc/robot/RobotContainer.java | 47 +++++-- .../BackupCollectDepoAndShoot.java | 10 -- .../autoCommands/DepoAndShootThenClimb.java | 91 +++++++++++++ .../frc/robot/commands/util/AutoFromList.java | 7 +- .../robot/factorys/DriveSubsystemFactory.java | 6 +- .../frc/robot/subsystems/DriveSubsystem.java | 16 +-- .../robot/subsystems/LimelightSubsystem.java | 88 ++++++------ .../main/java/frc/robot/utils/PathUtils.java | 32 ++++- .../src/main/java/frc/robot/utils/Pigeon.java | 127 ++++++++++++++++++ 11 files changed, 363 insertions(+), 85 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path index 51f4fa3..fadb07c 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path @@ -16,16 +16,16 @@ }, { "anchor": { - "x": 1.8163461538461552, - "y": 6.825769230769231 + "x": 2.455292587776331, + "y": 7.128 }, "prevControl": { - "x": 1.7045686383647336, - "y": 7.352720375181646 + "x": 1.6768530559167736, + "y": 8.024384915474641 }, "nextControl": { - "x": 2.0605384615384628, - "y": 5.674576923076922 + "x": 3.226908926479677, + "y": 6.239472094826452 }, "isLocked": false, "linkedName": null diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 7c64782..05fe253 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -9,6 +9,7 @@ // Current CAN IDs: // // 01 - Pneumatics hub +// 02 - Pigeon 2 // 10 - Drive left primary // 11 - Drive left follower // 20 - Drive right primary @@ -53,6 +54,17 @@ public final class Constants { public static class FieldConstants { public static final Pose2d kBlueHubCenter = new Pose2d(4.607, 4.035, new Rotation2d()); public static final Pose2d kRedHubCenter = new Pose2d(11.9284, 4.035, new Rotation2d()); + + public static final double kFieldWidth = 16.540988; // meters, x axis. + public static final double kFieldLength = 8.069326; // meters, y axis. + } + + public static class RobotConstants { + public static final int kPigeon2CANID = 2; + public static final boolean kDoPigeonWarn = true; + public static final double kPigeonYawOffset = -5.295877933502197; // degrees (-360, 360) + public static final double kPigeonPitchOffset = 0.7246352434158325; // degrees (-360, 360) + public static final double kPigeonRollOffset = -0.49318647384643555; // degrees (-360, 360) } public static class AutoConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 461a233..a1c40b1 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -7,6 +7,7 @@ import java.util.Optional; import java.util.function.BooleanSupplier; +import com.ctre.phoenix6.hardware.Pigeon2; import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.path.PathConstraints; @@ -41,6 +42,7 @@ import frc.robot.subsystems.ClimbL1Subsystem; import frc.robot.subsystems.LimelightSubsystem; import frc.robot.utils.HubUtils; +import frc.robot.utils.Pigeon; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; @@ -51,6 +53,7 @@ import frc.robot.commands.autoCommands.CorralAndShoot; import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; import frc.robot.commands.autoCommands.DeadreckonDistance; +import frc.robot.commands.autoCommands.DepoAndShootThenClimb; import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -62,6 +65,8 @@ * subsystems, commands, and trigger mappings) should be declared here. */ public class RobotContainer { + private final Pigeon m_pigeon; + // The robot's subsystems and commands are defined here... private final Optional m_driveSubsystem; private Optional m_intakeSubsystem; @@ -77,7 +82,6 @@ public class RobotContainer { private final CommandXboxController m_operatorController = new CommandXboxController(OperatorConstants.kOperatorControllerPort); - private final AHRS m_gyro = new AHRS(NavXComType.kMXP_SPI); private final DifferentialDriveKinematics m_DriveKinematics = new DifferentialDriveKinematics(DrivetrainConstants.kTrackWidthMeters); // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. @@ -115,15 +119,18 @@ public class RobotContainer { /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { + // Init Pigeon + m_pigeon = new Pigeon(RobotConstants.kPigeon2CANID); + // Init DriveSubsystem Optional rightLead = m_TalonFXFactory.construct(DrivetrainConstants.kRightMotorCANID); Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); Optional rightFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalRightMotorCANID); Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); - m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_gyro, rightLead, leftLead, rightFollower, leftFollower); + m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_pigeon, rightLead, leftLead, rightFollower, leftFollower); // Init the subsystems that don't require pneumatics. - m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_gyro); + m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_pigeon); m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); @@ -202,6 +209,10 @@ private void configureAutos() { new BackupCollectDepoAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) ); + m_autoChooser.addOption("[INDEV] Depo Collect, shoot, then climb", + new DepoAndShootThenClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + ); + // Test Autos PathConstraints slowConstraints = new PathConstraints( 1.0, @@ -293,7 +304,7 @@ private void configureBindings() { m_driverController.b().onTrue(new TurnLeftTest(driveSubsystem)); // Aim to Hub - m_driverController.y().onTrue( + m_driverController.rightBumper().onTrue( new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, isRed) ); @@ -363,6 +374,14 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); SmartDashboard.putNumber("mt2 Tag Count", 0.0); + SmartDashboard.putNumber("Yaw", 0.0); + SmartDashboard.putNumber("Pitch", 0.0); + SmartDashboard.putNumber("Roll", 0.0); + + SmartDashboard.putNumber("Yaw Rate", 0.0); + SmartDashboard.putNumber("Pitch Rate", 0.0); + SmartDashboard.putNumber("Roll Rate", 0.0); + SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); } @@ -377,6 +396,14 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Pose Y (Meter)", estimatedPos.getY()); SmartDashboard.putNumber("Pose Theta (Degrees)", estimatedPos.getRotation().getDegrees()); + SmartDashboard.putNumber("Yaw", m_pigeon.getYaw()); + SmartDashboard.putNumber("Pitch", m_pigeon.getPitch()); + SmartDashboard.putNumber("Roll", m_pigeon.getRoll()); + + SmartDashboard.putNumber("Yaw Rate", m_pigeon.getYawRate()); + SmartDashboard.putNumber("Pitch Rate", 0.0); + SmartDashboard.putNumber("Roll Rate", 0.0); + SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); @@ -396,7 +423,7 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Left Distance (m)", driveSubsystem.getMotorPositionMeters(true)); SmartDashboard.putNumber("Right Distance (m)", driveSubsystem.getMotorPositionMeters(false)); - SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); + SmartDashboard.putNumber("Gyro Degrees", m_pigeon.getYaw()); } // Pneumatics compressor @@ -426,7 +453,6 @@ public void disabledInit() {} // Move to auto init for competition code. public void enabledInit() { LimelightHelpers.SetIMUMode("limelight", 4); - m_gyro.enableLogging(true); } public void teleopInit() { @@ -447,9 +473,12 @@ public void autoInit() { public void disabledPeriodic() { double cameraYaw = m_limelightSubsystem.getRobotYaw(); - m_gyro.enableLogging(false); - m_gyro.reset(); - m_gyro.setAngleAdjustment(-cameraYaw); + // m_gyro.enableLogging(false); + // m_gyro.reset(); + // m_gyro.setAngleAdjustment(-cameraYaw); + + m_pigeon.reset(); + m_pigeon.setYawOffset(cameraYaw); } /** diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java index 93e0d44..f0969b1 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupCollectDepoAndShoot.java @@ -10,11 +10,9 @@ import com.pathplanner.lib.path.PathPlannerPath; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.commands.AimAtHub; -import frc.robot.commands.RotateToRotation2D; import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; @@ -57,17 +55,9 @@ public BackupCollectDepoAndShoot(DriveSubsystem driveSubsystem, DifferentialDriv // Called when the command is initially scheduled. @Override public void initialize() { - Rotation2d targetRot; - if (m_isRed.getAsBoolean() == true) { - targetRot = Rotation2d.kZero; - } else { - targetRot = Rotation2d.k180deg; - } - // Init the new sequence ArrayList sequence = new ArrayList(Arrays.asList( new DeadreckonDistance(m_DriveSubsystem, 0.5, -1.0), - new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 2.0), "GatherDepot", new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 3.0, m_isRed) )); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java new file mode 100644 index 0000000..12eb014 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java @@ -0,0 +1,91 @@ +package frc.robot.commands.autoCommands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.commands.PathPlannerAuto; +import com.pathplanner.lib.path.PathConstraints; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.WaitCommand; +import frc.robot.commands.util.AutoFromList; +import frc.robot.commands.util.AutoFromList.firstPathType; +import frc.robot.subsystems.DriveSubsystem; + +/** An example command that uses an example subsystem. */ +public class DepoAndShootThenClimb extends Command { + private final ArrayList m_preloadPaths = new ArrayList(Arrays.asList( + "GatherDepot", + "FromDepoTowerLineup" + )); + + // Pass-ins + private final DriveSubsystem m_DriveSubsystem; + private final DifferentialDrivePoseEstimator m_PoseEstimator; + private final BooleanSupplier m_isRed; + private final PathConstraints m_constraints; + + /** + * Creates a new DSA_BackupTest. + */ + public DepoAndShootThenClimb(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, PathConstraints constraints) { + m_DriveSubsystem = driveSubsystem; + m_PoseEstimator = poseEstimator; + m_isRed = isRed; + m_constraints = constraints; + + // warm-up for quick load later on + for (Object item : m_preloadPaths) { + if (item instanceof String) { + try { + PathPlannerPath path = PathPlannerPath.fromPathFile((String) item); + Command command = AutoBuilder.followPath(path); + new PathPlannerAuto(command); + } catch (Exception e) { + System.out.println(e); + } + } + } + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // Init the new sequence + ArrayList sequence = new ArrayList(Arrays.asList( + new DeadreckonDistance(m_DriveSubsystem, 0.5, -1.0), + "GatherDepot", + new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 3.0, m_isRed), + new WaitCommand(2.0), + "FromDepoTowerLineup" + )); + + // Run the command + Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); + CommandScheduler.getInstance().schedule(auto); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index f971b9f..38a34fc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -6,10 +6,12 @@ import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; +import com.pathplanner.lib.util.PathPlannerLogging; import edu.wpi.first.math.Pair; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.Commands; @@ -17,6 +19,7 @@ import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.ConditionalRotation; import frc.robot.utils.PathUtils; +import frc.robot.utils.PoseDiff; // Auto From Path Names And Commands public class AutoFromList extends Command { @@ -136,7 +139,9 @@ public void initialize() { Command createEverythingCommand = Commands.runOnce(() -> { // needed Values Pose2d pathStartPose = path.getStartingDifferentialPose(); - Command rotateTwordPathStart = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, pathStartPose.getRotation(), 45, 2.0); + PoseDiff dPose = new PoseDiff(m_poseEstimator.getEstimatedPosition(), pathStartPose); + Rotation2d targetRotation = new Rotation2d(Math.atan2(dPose.y, dPose.x)); + Command rotateTwordPathStart = ConditionalRotation.New(m_DriveSubsystem, m_poseEstimator, targetRotation, 45, 2.0); // path edits Command pathOnTheFly = Commands.runOnce(() -> { diff --git a/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java index afc5b84..bb8eff9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java +++ b/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -2,11 +2,11 @@ import java.util.Optional; import com.ctre.phoenix6.hardware.TalonFX; -import com.studica.frc.AHRS; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.kinematics.DifferentialDriveKinematics; import frc.robot.subsystems.DriveSubsystem; +import frc.robot.utils.Pigeon; public class DriveSubsystemFactory { public DriveSubsystemFactory() { @@ -14,14 +14,14 @@ public DriveSubsystemFactory() { public Optional construct(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, - AHRS gyro, Optional rightLead, Optional leftLead, Optional rightFollower, + Pigeon pigeon, Optional rightLead, Optional leftLead, Optional rightFollower, Optional leftFollower) { if (rightLead.isEmpty() || leftLead.isEmpty()) { return Optional.empty(); } - DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, gyro, rightLead.get(), + DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, pigeon, rightLead.get(), leftLead.get()); if (rightFollower.isPresent() && leftFollower.isPresent()) { diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 7f7d145..5aa29d4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -39,6 +39,7 @@ import frc.robot.commands.DriveCommands.ArcadeFromDashboard; import frc.robot.commands.DriveCommands.DifferentialDriveCommand; import frc.robot.commands.DriveCommands.NoDriveCommand; +import frc.robot.utils.Pigeon; public class DriveSubsystem extends SubsystemBase { private TalonFX m_rightMotor; @@ -53,15 +54,15 @@ public class DriveSubsystem extends SubsystemBase { private final DifferentialDriveKinematics m_kinematics; private final DifferentialDrivePoseEstimator m_poseEstimator; - private final AHRS m_gyro; + private final Pigeon m_pigeon; private final SendableChooser> m_driveChooser = new SendableChooser<>(); /** Creates a new DriveSubsystem. */ - public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, AHRS gyro, TalonFX rightMotor, TalonFX leftMotor) { + public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, Pigeon pigeon, TalonFX rightMotor, TalonFX leftMotor) { m_poseEstimator = poseEstimator; m_kinematics = kinematics; - m_gyro = gyro; + m_pigeon = pigeon; m_rightMotor = rightMotor; m_leftMotor = leftMotor; @@ -101,7 +102,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential ); // Gyro setup - m_gyro.reset(); + //m_pigeon.reset(); // Drive Chooser Init m_driveChooser.setDefaultOption("PID Arcade", ArcadeDriveCommand.class); @@ -128,7 +129,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential SmartDashboard.putNumber("Left Get (-1-->1)", 0); SmartDashboard.putNumber("Right Get (-1-->1)", 0); - SmartDashboard.putNumber("Gyro Degrees", m_gyro.getRotation2d().getDegrees()); + SmartDashboard.putNumber("Gyro Degrees", m_pigeon.getYaw()); } private void setConfig(TalonFX motor, InvertedValue Inverted) { @@ -254,7 +255,7 @@ public void resetPose(Pose2d newPose){ m_rightMotor.setPosition(0); m_poseEstimator.resetPosition( - m_gyro.getRotation2d(), + m_pigeon.getRotation2d(), 0, 0, newPose ); @@ -321,8 +322,7 @@ public void periodic() { // This method will be called once per scheduler run double lPositionMeters = getMotorPositionMeters(true); double rPositionMeters = getMotorPositionMeters(false); - Rotation2d yaw = m_gyro.getRotation2d(); - //m_gyro.getAngle() + Rotation2d yaw = m_pigeon.getRotation2d(); m_poseEstimator.update( yaw, diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index cea76e1..b9e4abe 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -7,37 +7,35 @@ import org.ejml.simple.SimpleMatrix; -import com.studica.frc.AHRS; - import edu.wpi.first.math.VecBuilder; import edu.wpi.first.math.Vector; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; +import frc.robot.Constants.FieldConstants; import frc.robot.LimelightHelpers.IMUData; import frc.robot.LimelightHelpers.PoseEstimate; import frc.robot.utils.LimitedQueue; +import frc.robot.utils.Pigeon; public class LimelightSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; - private final AHRS m_gyro; + private final Pigeon m_pigeon; private final LimitedQueue m_YawQue = new LimitedQueue(5); - private boolean seenApriltag = false; + private boolean firstApriltagSeen = false; /** Creates a new PositionSubsystem. */ - public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, AHRS gyro) { + public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, Pigeon pigeon) { m_poseEstimator = poseEstimator; - m_gyro = gyro; - - m_gyro.enableLogging(false); + m_pigeon = pigeon; } public double getRobotYaw() { - if (seenApriltag == false) { + if (firstApriltagSeen == false) { System.out.println("No apriltag seen! returning 0!"); return 0.0; } @@ -63,11 +61,9 @@ public double getRobotYaw() { // This is copy and pasted from limelight's documentation for testing. private void updateOdometry() { - boolean doRejectUpdate = false; - - LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); PoseEstimate poseEst; - if (seenApriltag == true) { + if (firstApriltagSeen == true) { + LimelightHelpers.SetRobotOrientation("limelight", m_pigeon.getYaw(), 0, m_pigeon.getPitch(), 0, m_pigeon.getRoll(), 0); poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); } else { poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); @@ -77,53 +73,53 @@ private void updateOdometry() { return; } + /// Invalidate the vision measurements if some parameters are not met \\\ + + // If theirs no detected tags SmartDashboard.putNumber("Tag Count", poseEst.tagCount); - - // if our angular velocity is greater than 720 degrees per second, ignore vision updates - if(Math.abs(m_gyro.getRate()) > 80) + if(poseEst.tagCount == 0) { - doRejectUpdate = true; + return; } - if (Math.abs(m_gyro.getPitch()) > 5) { - doRejectUpdate = true; + // Make sure that the estimated position is within field bounds. + Pose2d estimatedPose = poseEst.pose; + if ( + estimatedPose.getX() < 0.0 || estimatedPose.getX() > FieldConstants.kFieldWidth + || estimatedPose.getY() < 0.0 || estimatedPose.getY() > FieldConstants.kFieldLength + ) { + return; } - if(poseEst.tagCount == 0) - { - doRejectUpdate = true; + // Init the mt2 process once a apriltag is first seen via mt1 and a good rotation is set. + if (firstApriltagSeen == false && poseEst.tagCount >= 2 && poseEst.isMegaTag2 == false) { + firstApriltagSeen = true; } - if (seenApriltag == false && poseEst.tagCount >= 2) { - seenApriltag = true; - doRejectUpdate = true; - } + /// Actually do the vision measurements \\\ - if(!doRejectUpdate) - { - // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. - Vector errorVec; - - // When the robot is disabled, trust the gyro from the limelight fully. - // Otherwise, in all othr modes, trust the gyro yaw. - if (DriverStation.isDisabled()) { - errorVec = VecBuilder.fill(.7,.7,0); - } else { - errorVec = VecBuilder.fill(.7,.7,9999999); - } - m_poseEstimator.setVisionMeasurementStdDevs(errorVec); - - m_poseEstimator.addVisionMeasurement( - poseEst.pose, - poseEst.timestampSeconds - ); + // A Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. + Vector errorVec; + + // Only trust the yaw from the guess if its not via mt2. + // TODO: Look into scaling these based off of the ambuguity and size of the tags. + if (poseEst.isMegaTag2 == false) { + errorVec = VecBuilder.fill(.7,.7,0); + } else { + errorVec = VecBuilder.fill(.7,.7,9999999); } + + m_poseEstimator.setVisionMeasurementStdDevs(errorVec); + m_poseEstimator.addVisionMeasurement( + poseEst.pose, + poseEst.timestampSeconds + ); } @Override public void periodic() { // This method will be called once per scheduler - if (seenApriltag == true) { + if (firstApriltagSeen == true) { IMUData limelightData = LimelightHelpers.getIMUData("limelight"); m_YawQue.add(limelightData.robotYaw); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java index 014a832..41f85e3 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PathUtils.java @@ -15,6 +15,34 @@ import edu.wpi.first.math.geometry.Translation2d; public class PathUtils { + public static List deepCopyWaypoints(List base) { + List newWaypoints = new ArrayList<>(); + for (Waypoint w : base) { + Translation2d prev_o = w.prevControl(); + Translation2d anchor_o = w.anchor(); + Translation2d next_o = w.nextControl(); + + Translation2d prev = null; + if (prev_o != null) { + prev = new Translation2d(prev_o.getX(), prev_o.getY()); + } + + Translation2d anchor = null; + if (anchor_o != null) { + anchor = new Translation2d(anchor_o.getX(), anchor_o.getY()); + } + + Translation2d next = null; + if (next_o != null) { + next = new Translation2d(next_o.getX(), next_o.getY()); + } + + newWaypoints.add(new Waypoint(prev, anchor, next)); + } + + return newWaypoints; + } + /** * Allows you to do the modification of a path w/o needing to do the jankyness yourself. * @@ -24,7 +52,7 @@ public class PathUtils { */ @SafeVarargs public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair... pointsToModify) { - List pathWaypoints = basePath.getWaypoints(); + List pathWaypoints = deepCopyWaypoints(basePath.getWaypoints()); for (Pair point : pointsToModify) { Integer index = point.getFirst(); if (pathWaypoints.size() > index && index >= 0) { @@ -59,7 +87,7 @@ public static PathPlannerPath modifyPath(PathPlannerPath basePath, Pair pathWaypoints = basePath.getWaypoints(); + List pathWaypoints = deepCopyWaypoints(basePath.getWaypoints()); Translation2d newAnchor = pointToAppend.getTranslation(); Translation2d prevControl = null; diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java b/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java new file mode 100644 index 0000000..96f3594 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java @@ -0,0 +1,127 @@ +// Taken and modified from CTRE's example +// https://github.com/CrossTheRoadElec/Phoenix5-Examples/blob/d70cab6060617bbed5e207c2eaf8747af09a15f6/Java%20General/Pigeon2/src/main/java/frc/robot/subsystems/PigeonSubsystem.java +package frc.robot.utils; + +import com.ctre.phoenix6.configs.Pigeon2Configuration; +import com.ctre.phoenix6.hardware.Pigeon2; + +import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.wpilibj.DriverStation; +import frc.robot.Constants.RobotConstants; + +public class Pigeon { + private final Pigeon2 m_pigeon2; + private boolean m_exists; + private double m_yawOffset = 0; + + public Pigeon(int PigeonCanId) { + m_pigeon2 = new Pigeon2(PigeonCanId); + m_exists = m_pigeon2.isConnected(); + + if (m_exists == false) { + DriverStation.reportWarning("Pigeon on canid2 does not exist! Default values will be returned.", true); + } else { + Pigeon2Configuration config = new Pigeon2Configuration(); + config.MountPose.MountPoseYaw = RobotConstants.kPigeonYawOffset; + config.MountPose.MountPosePitch = RobotConstants.kPigeonPitchOffset; + config.MountPose.MountPoseRoll = RobotConstants.kPigeonRollOffset; + m_pigeon2.getConfigurator().apply(config); + + m_pigeon2.reset(); + } + } + + private void dosntExist() { + if (RobotConstants.kDoPigeonWarn) { + DriverStation.reportWarning("Pigeon on canid 2 does not exist, returning default value!", false); + } + } + + public void reset() { + if (m_exists) { + m_pigeon2.reset(); + } else { + dosntExist(); + } + } + + public Rotation2d getRotation2d() { + if (m_exists) { + return m_pigeon2.getRotation2d().rotateBy(new Rotation2d(m_yawOffset * (Math.PI/180))); + } else { + dosntExist(); + return Rotation2d.kZero; + } + } + + public double getYaw() { + if (m_exists) { + return m_pigeon2.getYaw().getValueAsDouble() + m_yawOffset; + } else { + dosntExist(); + return 0.0; + } + } + + // I dont think offset is needed for this. + public double getYawRate() { + if (m_exists) { + return m_pigeon2.getAngularVelocityZWorld().getValueAsDouble(); + } else { + dosntExist(); + return 0.0; + } + } + + public double getPitch() { + if (m_exists) { + return m_pigeon2.getPitch().getValueAsDouble(); + } else { + dosntExist(); + return 0.0; + } + } + + public double getRoll() { + if (m_exists) { + return m_pigeon2.getRoll().getValueAsDouble(); + } else { + dosntExist(); + return 0.0; + } + } + + public void setYaw(double yaw) { + if (m_exists) { + m_pigeon2.setYaw(yaw-m_yawOffset); + } else { + dosntExist(); + } + } + + public double getUpTime() { + if (m_exists) { + return m_pigeon2.getUpTime().getValueAsDouble(); + } else { + dosntExist(); + return -1; + } + } + + public double getTemp() { + if (m_exists) { + return m_pigeon2.getTemperature().getValueAsDouble(); + } else { + dosntExist(); + return -1; + } + } + + public void setYawOffset(double degrees) { + m_yawOffset = degrees; + } + + public double getYawOffset() { + return m_yawOffset; + } +} From 44ea01bc878bcc08b6e56313b6ab57595a36a34b Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 14 Mar 2026 15:32:21 -0500 Subject: [PATCH 119/161] Made BackupAndClimb be in the correct location for climbup --- .../paths/FromDepoTowerLineup.path | 24 ++++--------------- .../commands/autoCommands/BackupAndClimb.java | 5 +++- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path index fadb07c..02a2950 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/FromDepoTowerLineup.path @@ -8,36 +8,20 @@ }, "prevControl": null, "nextControl": { - "x": 1.1190910337101736, - "y": 7.418718411702091 + "x": 1.148715910576948, + "y": 6.868956593296325 }, "isLocked": true, "linkedName": null }, - { - "anchor": { - "x": 2.455292587776331, - "y": 7.128 - }, - "prevControl": { - "x": 1.6768530559167736, - "y": 8.024384915474641 - }, - "nextControl": { - "x": 3.226908926479677, - "y": 6.239472094826452 - }, - "isLocked": false, - "linkedName": null - }, { "anchor": { "x": 1.432615384615386, "y": 3.744294871794872 }, "prevControl": { - "x": 2.864585292835296, - "y": 3.744294871794872 + "x": 4.000377113133939, + "y": 3.7578283485045514 }, "nextControl": null, "isLocked": false, diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java index 083c392..18f542c 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndClimb.java @@ -14,6 +14,7 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.commands.RotateToRotation2D; +import frc.robot.commands.WaitCommand; import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.AutoFromList.firstPathType; import frc.robot.subsystems.DriveSubsystem; @@ -67,7 +68,9 @@ public void initialize() { ArrayList sequence = new ArrayList(Arrays.asList( new DeadreckonDistance(m_DriveSubsystem, 1.0, -1), "LineupToTower", - new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 1.0) + new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 1.0), + new WaitCommand(0.2), + new DeadreckonDistance(m_DriveSubsystem, 0.5, 1.0) )); // Run the command From de21d226eb8127c0166cb5be2e51efa9f7851632 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Tue, 17 Mar 2026 18:18:45 -0500 Subject: [PATCH 120/161] Changed lift speed to max --- 2026-Rebuilt/src/main/java/frc/robot/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 39aa79a..8d13f12 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -174,7 +174,7 @@ public static class LauncherConstants { public static final int kLauncherLiftMotorCANID = 42; // The speed, in range [-1.0, 1.0], to run the lift motor when started. - public static final double kLiftMotorSpeed = 0.3; + public static final double kLiftMotorSpeed = 1.0; // Beam break sensor to detect fuel at the top of the lift. public static final int kUpperFuelSensorChannel = 0; From aa7d9f13d08a00831a6d66874bd48f0914d7d96e Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Tue, 17 Mar 2026 18:21:19 -0500 Subject: [PATCH 121/161] Added RangeLauncherCommand that spins the flywheel to correct rate for hub distance --- .../java/frc/robot/commands/AimAtHub.java | 2 +- .../robot/commands/RangeLauncherCommand.java | 75 +++++++++++++++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java index 17642b8..66e2fe9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/AimAtHub.java @@ -17,7 +17,7 @@ public class AimAtHub extends RotateToRotation2D { * @param driveSubsystem The driveSubsystem for the robot. * @param poseEstimator The poseEstimator of the robot. * @param maxSpeed The max speed the robot is allowed to go in the rotation. - * @param isRed Does the robot need to point tword the red or blue goal, default is blue. + * @param isRed Does the robot need to point towards the red or blue goal, default is blue. */ public AimAtHub(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, double maxSpeed, BooleanSupplier isRed) { diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java new file mode 100644 index 0000000..cb201fe --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java @@ -0,0 +1,75 @@ +package frc.robot.commands; + +import java.util.function.BooleanSupplier; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.utils.HubUtils; +import frc.robot.utils.LauncherUtils; + + +/** + * + * Stop the launcher lift motor and spin down the flywheel. + * + **/ +public class RangeLauncherCommand extends Command { + private final BooleanSupplier m_isRed; + private final LauncherSubsystem m_subsystem; + private double m_tolerancerpm; + private double m_targetSpeedrpm; + private final DifferentialDrivePoseEstimator m_poseEstimator; + + /** + * Creates a new RangeLauncherCommand. + * + * @param subsystem The subsystem used by this command. + */ + public RangeLauncherCommand(LauncherSubsystem subsystem, DifferentialDrivePoseEstimator poseEstimator, double Tolerancerpm, BooleanSupplier isRed) + { + m_subsystem = subsystem; + m_tolerancerpm = Tolerancerpm; + m_poseEstimator = poseEstimator; + m_isRed = isRed; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_subsystem); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + double distance = HubUtils.getHubDistance(m_poseEstimator, m_isRed); + m_targetSpeedrpm = LauncherUtils.getFlywheelSpeed(distance); + + m_subsystem.setTargetSpeedrpm(m_targetSpeedrpm); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + + } + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end when the flywheel speed is within the tolerance of the target. + double currentSpeed = m_subsystem.getCurrentSpeedrpm(); + if (Math.abs(currentSpeed - m_targetSpeedrpm) <= m_tolerancerpm) + { + return true; + } + else + { + return false; + } + } +} From f7140a2012f7e698be093d08329c7b1829547dc1 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Tue, 17 Mar 2026 18:33:08 -0500 Subject: [PATCH 122/161] Added indexer control to bulk move commands --- .../main/java/frc/robot/commands/StartBulkMoveCommand.java | 3 ++- .../main/java/frc/robot/commands/StopBulkMoveCommand.java | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java index aba9763..298c353 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartBulkMoveCommand.java @@ -5,7 +5,7 @@ /** * - * Start bulk move. + * Start bulk and indexer motors. * **/ public class StartBulkMoveCommand extends Command { @@ -28,6 +28,7 @@ public StartBulkMoveCommand(IndexerBulkSubsystem subsystem) @Override public void initialize() { m_subsystem.startBulkTransfer(); + m_subsystem.startIndexer(); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java index f079f91..e4e04fa 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopBulkMoveCommand.java @@ -5,7 +5,7 @@ /** * - * Start bulk move. + * Stop bulk move and indexer motors. * **/ public class StopBulkMoveCommand extends Command { @@ -28,8 +28,9 @@ public StopBulkMoveCommand(IndexerBulkSubsystem subsystem) @Override public void initialize() { m_subsystem.stopBulkTransfer(); + m_subsystem.stopIndexer(); } - + // Called every time the scheduler runs while the command is scheduled. @Override public void execute() { From e085a2197cfa4fdbdee37f068e6f074601354261 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Tue, 17 Mar 2026 18:41:46 -0500 Subject: [PATCH 123/161] Uncommented bulk move subsystem motor present check --- .../frc/robot/subsystems/IndexerBulkSubsystem.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index 25d2b48..f2ae97f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -46,13 +46,11 @@ public IndexerBulkSubsystem() throws Exception { SmartDashboard.putNumber("IndexerBulk TestIndexerSpeed", m_indexerSpeed); m_motorBulk = new TalonFXS(IndexerBulkConstants.kBulkMoveMotorCANID); - - // TODO: Temporarily removed until bulk motor is populated. Reinstate this! - // - // if (!m_motorBulk.isConnected()) - // { - // throw new Exception("Bult transport motor is not present."); - // } + + if (!m_motorBulk.isConnected()) + { + throw new Exception("Bult transport motor is not present."); + } m_motorIndexer = new TalonFX(IndexerBulkConstants.kIndexerMotorCANID); if (!m_motorIndexer.isConnected()) From f649dbabbc12fb0f422de066c19c0c9567e5ab4b Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Tue, 17 Mar 2026 19:17:02 -0500 Subject: [PATCH 124/161] Implement turn/range/shoot command --- .../src/main/java/frc/robot/Constants.java | 2 +- .../main/java/frc/robot/RobotContainer.java | 15 ++++ .../robot/commands/RotateAndShootCommand.java | 73 +++++++++++++++++++ .../frc/robot/commands/StartShootCommand.java | 55 ++++++++++++++ .../frc/robot/commands/StopShootCommand.java | 54 ++++++++++++++ 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 8d13f12..5851ffd 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -208,7 +208,7 @@ public static class LauncherConstants { public static final int kTicksPerUpdate = 10; public static final double kFixedTestSpeed = 3000.0; - public static final double kFlywheelToleranceRPM = 200.0; + public static final double kFlywheelToleranceRPM = 100.0; } public static class IndexerBulkConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index a1c40b1..4014298 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -308,6 +308,21 @@ private void configureBindings() { new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, isRed) ); + // Range launcher, turn to face hub and shoot all fuel. + if (m_launcherSubsystem.isPresent() & m_indexerBulkSubsystem.isPresent()) + { + LauncherSubsystem launcher = m_launcherSubsystem.get(); + IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); + + // This is intended to keep shooting until the button is released. + m_driverController.y().whileTrue(new RotateAndShootCommand(driveSubsystem, + launcher, + indexer, + m_PoseEstimator, + isRed, + LauncherConstants.kFlywheelToleranceRPM)); + } + // Travel to corner and shoot m_driverController.x().onTrue( new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java new file mode 100644 index 0000000..c7fdc61 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java @@ -0,0 +1,73 @@ +package frc.robot.commands; + +import java.util.function.BooleanSupplier; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; +import frc.robot.commands.AimAtHub; +import frc.robot.commands.RangeLauncherCommand; +import frc.robot.commands.StartShootCommand; +import frc.robot.subsystems.DriveSubsystem; +import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.IndexerBulkSubsystem; + +/** An example command that uses an example subsystem. */ +public class RotateAndShootCommand extends Command { + private final DriveSubsystem m_driveSubsystem; + private final LauncherSubsystem m_launcherSubsystem; + private final IndexerBulkSubsystem m_indexerSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final BooleanSupplier m_isRed; + private final double m_flywheelTolerance; + + /** + * Creates a new BackupAndShoot. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + */ + public RotateAndShootCommand(DriveSubsystem driveSubsystem, LauncherSubsystem launcherSubsystem, IndexerBulkSubsystem indexerSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, double flywheelTolerance) + { + m_driveSubsystem = driveSubsystem; + m_launcherSubsystem = launcherSubsystem; + m_indexerSubsystem = indexerSubsystem; + m_poseEstimator = poseEstimator; + m_flywheelTolerance = flywheelTolerance; + m_isRed = isRed; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // This should do the process to make the launcher get up to speed + Command setLauncherSpeedCommand = new RangeLauncherCommand(m_launcherSubsystem, m_poseEstimator, m_flywheelTolerance, m_isRed); + Command aimAtHubCommand = new AimAtHub(m_driveSubsystem, m_poseEstimator, 4.0, m_isRed); + Command startShootCommand = new StartShootCommand(m_launcherSubsystem, m_indexerSubsystem); + + ParallelCommandGroup TurnAndSet = new ParallelCommandGroup(setLauncherSpeedCommand, aimAtHubCommand); + + CommandScheduler.getInstance().schedule( + TurnAndSet + .andThen(startShootCommand) + ); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command only ends when one of the subsystems it uses has another + // command scheduled on it. + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java new file mode 100644 index 0000000..256bbc6 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java @@ -0,0 +1,55 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IndexerBulkSubsystem; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Start shooting fuel by starting the launcher lift motor and both motors in the indexer/bulk subsystem. + * + **/ +public class StartShootCommand extends Command { + private final LauncherSubsystem m_Launcher; + private final IndexerBulkSubsystem m_IndexerBulk; + + /** + * Creates a new StartShootCommand. + * + * @param subsystem The subsystem used by this command. + */ + public StartShootCommand(LauncherSubsystem launcher, IndexerBulkSubsystem indexerbulk) + { + m_Launcher = launcher; + m_IndexerBulk = indexerbulk; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_Launcher); + addRequirements(m_IndexerBulk); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_IndexerBulk.startBulkTransfer(); + m_IndexerBulk.startIndexer(); + m_Launcher.startLift(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // This command only ends when another command is scheduled on the + // subsystem. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java new file mode 100644 index 0000000..f7ab030 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java @@ -0,0 +1,54 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IndexerBulkSubsystem; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Start shooting fuel by starting the launcher lift motor and both motors in the indexer/bulk subsystem. + * + **/ +public class StopShootCommand extends Command { + private final LauncherSubsystem m_Launcher; + private final IndexerBulkSubsystem m_IndexerBulk; + + /** + * Stops shooting by stopping the lift motor and both motors in bulk/indexer. + * + * @param subsystem The subsystem used by this command. + */ + public StopShootCommand(LauncherSubsystem launcher, IndexerBulkSubsystem indexerbulk) + { + m_Launcher = launcher; + m_IndexerBulk = indexerbulk; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_Launcher); + addRequirements(m_IndexerBulk); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_IndexerBulk.stopBulkTransfer(); + m_IndexerBulk.stopIndexer(); + m_Launcher.stopLift(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // This command ends immediately. + @Override + public boolean isFinished() { + return true; + } +} From a6dd42ab4c94b6ae7c2dcd03746ca3a9c3ad5a5f Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Tue, 17 Mar 2026 19:34:36 -0500 Subject: [PATCH 125/161] Rearrange PID controls for launcher in test mode Elastic layout --- 2026-Rebuilt/elastic-layout.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 77574ab..5bcea39 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -597,8 +597,8 @@ }, { "title": "Launcher P", - "x": 224.0, - "y": 448.0, + "x": 0.0, + "y": 608.0, "width": 128.0, "height": 96.0, "type": "Text Display", @@ -611,8 +611,8 @@ }, { "title": "Launcher I", - "x": 352.0, - "y": 448.0, + "x": 128.0, + "y": 608.0, "width": 128.0, "height": 96.0, "type": "Text Display", @@ -625,8 +625,8 @@ }, { "title": "Launcher D", - "x": 480.0, - "y": 448.0, + "x": 256.0, + "y": 608.0, "width": 128.0, "height": 96.0, "type": "Text Display", @@ -639,8 +639,8 @@ }, { "title": "MMAccel", - "x": 608.0, - "y": 448.0, + "x": 0.0, + "y": 704.0, "width": 128.0, "height": 96.0, "type": "Text Display", @@ -653,8 +653,8 @@ }, { "title": "MMJerk", - "x": 736.0, - "y": 448.0, + "x": 128.0, + "y": 704.0, "width": 128.0, "height": 96.0, "type": "Text Display", From 1c8af24aa3776b316f0bc5a4832edf417bada0e7 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:43:08 -0500 Subject: [PATCH 126/161] wooo!!! autos!!!!! --- .../deploy/pathplanner/paths/ContinuousJ.path | 86 ++++++++++++++++++ .../main/java/frc/robot/RobotContainer.java | 7 +- .../autoCommands/DeadreckonBumpAndBack.java | 13 ++- .../autoCommands/DepoAndShootThenClimb.java | 27 ++++-- .../autoCommands/OverBumpContinousJ.java | 89 +++++++++++++++++++ .../frc/robot/commands/util/AutoFromList.java | 1 - 6 files changed, 213 insertions(+), 10 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/ContinuousJ.path create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/ContinuousJ.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ContinuousJ.path new file mode 100644 index 0000000..0c2ae1f --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/ContinuousJ.path @@ -0,0 +1,86 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 6.304833333333335, + "y": 5.430384615384615 + }, + "prevControl": null, + "nextControl": { + "x": 6.554833333333335, + "y": 5.430384615384615 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 7.654, + "y": 4.755948717948717 + }, + "prevControl": { + "x": 7.654, + "y": 5.477740925098693 + }, + "nextControl": { + "x": 7.654, + "y": 4.0836931462226715 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 7.654, + "y": 3.418705128205129 + }, + "prevControl": { + "x": 7.654, + "y": 3.943430491892358 + }, + "nextControl": { + "x": 7.654, + "y": 2.8939797645179 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": 5.735051282051284, + "y": 2.8838076923076925 + }, + "prevControl": { + "x": 5.985051282051284, + "y": 2.8838076923076925 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index a1c40b1..54a1f93 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -54,6 +54,7 @@ import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; import frc.robot.commands.autoCommands.DeadreckonDistance; import frc.robot.commands.autoCommands.DepoAndShootThenClimb; +import frc.robot.commands.autoCommands.OverBumpContinousJ; import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; @@ -222,10 +223,14 @@ private void configureAutos() { ); // replace slowConstraints to m_contraints after testing. - m_autoChooser.addOption("[TEST] Deadreckon Over Bump and Back", + m_autoChooser.addOption("[INDEV] Deadreckon Over Bump and Back", new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, isRed) ); + m_autoChooser.addOption("[INDEV] Continous J into nutreal and back", + new OverBumpContinousJ(driveSubsystem, m_PoseEstimator, isRed) + ); + m_autoChooser.addOption("[TEST] Forward Test", new DeadreckonDistance(driveSubsystem, 2.5, 2.0) ); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java index d8a7b80..ab06083 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -15,6 +15,7 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; +import frc.robot.commands.AimAtHub; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.PathUtils; @@ -82,7 +83,13 @@ public void initialize() { Command lineupCommand = AutoBuilder.followPath(lineupPath); // Create & Schedule the command group. - CommandScheduler.getInstance().schedule(lineupCommand.andThen(deadreckonBackward)); + CommandScheduler.getInstance().schedule( + lineupCommand + .andThen(deadreckonBackward) + .andThen(new AimAtHub(m_driveSubsystem, m_poseEstimator, 2.0, m_isRed)) + .andThen(new DeadreckonDistance(m_driveSubsystem, 0.75, -1.0)) + .andThen(new AimAtHub(m_driveSubsystem, m_poseEstimator, 2.0, m_isRed)) + ); }); Command pickupScheudle = new InstantCommand(() -> { @@ -103,8 +110,8 @@ public void initialize() { }); // Create & Schedule the command group. - SequentialCommandGroup initialSequential = deadreckonFoward.andThen(pickupScheudle); - CommandScheduler.getInstance().schedule(initialSequential); + //SequentialCommandGroup initialSequential = deadreckonFoward.andThen(pickupScheudle); + CommandScheduler.getInstance().schedule(deadreckonFoward); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java index 12eb014..0433192 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoAndShootThenClimb.java @@ -10,9 +10,12 @@ import com.pathplanner.lib.path.PathPlannerPath; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.Commands; import frc.robot.commands.AimAtHub; +import frc.robot.commands.RotateToRotation2D; import frc.robot.commands.WaitCommand; import frc.robot.commands.util.AutoFromList; import frc.robot.commands.util.AutoFromList.firstPathType; @@ -57,18 +60,32 @@ public DepoAndShootThenClimb(DriveSubsystem driveSubsystem, DifferentialDrivePos // Called when the command is initially scheduled. @Override public void initialize() { + Rotation2d targetRot; + if (m_isRed.getAsBoolean() == true) { + targetRot = Rotation2d.kZero; + } else { + targetRot = Rotation2d.k180deg; + } + // Init the new sequence - ArrayList sequence = new ArrayList(Arrays.asList( + ArrayList sequence2 = new ArrayList(Arrays.asList( + "FromDepoTowerLineup", + new RotateToRotation2D(m_DriveSubsystem, m_PoseEstimator, targetRot, 1.0), + new WaitCommand(0.2), + new DeadreckonDistance(m_DriveSubsystem, 0.5, 1.0) + )); + Command auto2 = new AutoFromList(sequence2, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.REPLACE_FIRST_PATH, false); + + ArrayList sequence1 = new ArrayList(Arrays.asList( new DeadreckonDistance(m_DriveSubsystem, 0.5, -1.0), "GatherDepot", new AimAtHub(m_DriveSubsystem, m_PoseEstimator, 3.0, m_isRed), new WaitCommand(2.0), - "FromDepoTowerLineup" + Commands.runOnce(() -> {CommandScheduler.getInstance().schedule(auto2);}) )); + Command auto1 = new AutoFromList(sequence1, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); - // Run the command - Command auto = new AutoFromList(sequence, m_constraints, m_DriveSubsystem, m_PoseEstimator, firstPathType.GO_TO_FIRST_PATH, false); - CommandScheduler.getInstance().schedule(auto); + CommandScheduler.getInstance().schedule(auto1); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java new file mode 100644 index 0000000..4b5e50d --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java @@ -0,0 +1,89 @@ +package frc.robot.commands.autoCommands; + +import java.util.function.BooleanSupplier; + +import com.pathplanner.lib.auto.AutoBuilder; +import com.pathplanner.lib.path.PathPlannerPath; + +import edu.wpi.first.math.Pair; +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import edu.wpi.first.math.geometry.Pose2d; +import edu.wpi.first.wpilibj.DriverStation; +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.InstantCommand; +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; +import frc.robot.commands.AimAtHub; +import frc.robot.subsystems.DriveSubsystem; +import frc.robot.utils.PathUtils; + +/** An example command that uses an example subsystem. */ +public class OverBumpContinousJ extends Command { + private final DriveSubsystem m_driveSubsystem; + private final DifferentialDrivePoseEstimator m_poseEstimator; + private final BooleanSupplier m_isRed; + + /** + * Creates a new OverBumpContinousJ. + * + * @param poseEstimator The pose estimator to get the location of the robot. + * @param targetPose The pose the robot will make a point to go to. + * @param constraints The constraints the robot will follow while following the path. + */ + public OverBumpContinousJ(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) + { + m_driveSubsystem = driveSubsystem; + m_poseEstimator = poseEstimator; + m_isRed = isRed; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + // Deadreckon Over the bump + Command deadreckonFoward1 = new DeadreckonDistance(m_driveSubsystem, 2.5, 2.0); + Command deadreckonFoward2 = new DeadreckonDistance(m_driveSubsystem, 2.5, 2.0); + + // Create paths and scheudle other commands + Command pickupScheudle = new InstantCommand(() -> { + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + + try { + PathPlannerPath ContJ = PathPlannerPath.fromPathFile("ContinuousJ"); + PathPlannerPath editedPath = PathUtils.modifyPath(ContJ, new Pair(0, currentPose)); + //PathPlannerPath editedPath = PathUtils.appendToPath(ContJ, 0, currentPose); + Command pathCommand = AutoBuilder.followPath(editedPath); + + // Create & Scheudle the command group + CommandScheduler.getInstance().schedule( + pathCommand + .andThen(deadreckonFoward2) + .andThen(new AimAtHub(m_driveSubsystem, m_poseEstimator, 2.0, m_isRed)) + .andThen(new DeadreckonDistance(m_driveSubsystem, 0.75, -1.0)) + .andThen(new AimAtHub(m_driveSubsystem, m_poseEstimator, 2.0, m_isRed)) + ); + } catch (Exception e) { + DriverStation.reportError(e.toString(), true); + } + }); + + // Create & Schedule the command group. + //SequentialCommandGroup initialSequential = deadreckonFoward1.andThen(pickupScheudle); + CommandScheduler.getInstance().schedule(pickupScheudle); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command automatically ends + return true; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java index 38a34fc..6c9a5f2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/util/AutoFromList.java @@ -6,7 +6,6 @@ import com.pathplanner.lib.commands.PathPlannerAuto; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; -import com.pathplanner.lib.util.PathPlannerLogging; import edu.wpi.first.math.Pair; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; From ab1dd286f428de3bda1088eccc5d7cec21a6cfef Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 17 Mar 2026 20:56:01 -0500 Subject: [PATCH 127/161] Uncommented thing. --- .../robot/commands/autoCommands/DeadreckonBumpAndBack.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java index ab06083..b7b9aaf 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -110,8 +110,8 @@ public void initialize() { }); // Create & Schedule the command group. - //SequentialCommandGroup initialSequential = deadreckonFoward.andThen(pickupScheudle); - CommandScheduler.getInstance().schedule(deadreckonFoward); + SequentialCommandGroup initialSequential = deadreckonFoward.andThen(pickupScheudle); + CommandScheduler.getInstance().schedule(initialSequential); } // Called every time the scheduler runs while the command is scheduled. From 386627f967f12cf0d0a8752ee1e3b46ac73cebf4 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Thu, 19 Mar 2026 19:35:21 -0500 Subject: [PATCH 128/161] Compressor pneumatic debug --- 2026-Rebuilt/elastic-layout.json | 48 +++++++++++++++++++ .../src/main/java/frc/robot/Constants.java | 2 +- .../main/java/frc/robot/RobotContainer.java | 14 +++--- .../frc/robot/utils/PneumaticHubWrapper.java | 3 +- 4 files changed, 59 insertions(+), 8 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 5bcea39..c60dacb 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -664,6 +664,54 @@ "data_type": "double", "show_submit_button": true } + }, + { + "title": "Pneumatic Subsystem", + "x": 736.0, + "y": 480.0, + "width": 192.0, + "height": 96.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Pneumatic Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Compressor Running", + "x": 928.0, + "y": 480.0, + "width": 128.0, + "height": 96.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Compressor Running", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } + }, + { + "title": "Pressure", + "x": 1056.0, + "y": 480.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Pressure", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 5851ffd..b279b0e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -101,7 +101,7 @@ public static class PneumaticsConstants { public static final PneumaticsModuleType kHubType = PneumaticsModuleType.REVPH; public static final int kPneumaticsHubCANID = 1; public static final double kMinPneumaticsPressure = 80.0; - public static final double kMaxPneumaticsPressure = 120.0; + public static final double kMaxPneumaticsPressure = 115.0; public static final int kTicksPerUpdate = 5; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 29bb266..68532e9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -293,6 +293,8 @@ private void configureBindings() { SmartDashboard.putBoolean("ClimbL1 Subsystem", m_climbL1Subsystem.isPresent()); SmartDashboard.putBoolean("Launcher Subsystem", m_launcherSubsystem.isPresent()); SmartDashboard.putBoolean("IndexerBulk Subsystem", m_indexerBulkSubsystem.isPresent()); + SmartDashboard.putBoolean("Pneumatic Subsystem", m_pneumaticHub.isPresent()); + // Note that some of our command bindings require that multiple subsystems // are present. We only enable a binding if all its requirements are met! @@ -447,12 +449,12 @@ public void UpdateSmartDashboard() { } // Pneumatics compressor - // if(m_pneumaticHub.isPresent() && ((m_iTickCount % PneumaticsConstants.kTicksPerUpdate) == 0)) - // { - // PneumaticHub hub = m_pneumaticHub.get(); - // SmartDashboard.putNumber("Pressure", hub.getPressure(0)); - // SmartDashboard.putBoolean("Compressor Running", hub.getCompressor()); - // } + if(m_pneumaticHub.isPresent() && ((m_iTickCount % PneumaticsConstants.kTicksPerUpdate) == 0)) + { + PneumaticHub hub = m_pneumaticHub.get(); + SmartDashboard.putNumber("Pressure", hub.getPressure(0)); + SmartDashboard.putBoolean("Compressor Running", hub.getCompressor()); + } m_iTickCount++; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java index 5292060..2c6a539 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java @@ -5,6 +5,7 @@ package frc.robot.utils; import edu.wpi.first.wpilibj.PneumaticHub; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.hal.REVPHVersion; public class PneumaticHubWrapper extends PneumaticHub { @@ -13,7 +14,7 @@ public class PneumaticHubWrapper extends PneumaticHub { /* @throws Exception */ public PneumaticHubWrapper() throws Exception { m_Hub = new PneumaticHub(); - + if (!isAvailable()) { throw new Exception("Pneumatic hub is not connected or is malfunctioning."); From 6c12d7b9b0728edd3f0688ac350b24eaea5393a3 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Thu, 19 Mar 2026 20:28:02 -0500 Subject: [PATCH 129/161] Debugged intake solonoid --- 2026-Rebuilt/elastic-layout.json | 26 ++++++++++++---- .../src/main/java/frc/robot/Constants.java | 9 +++--- .../frc/robot/subsystems/IntakeSubsystem.java | 30 +++++++++++++++---- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index c60dacb..c0f9436 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -667,10 +667,10 @@ }, { "title": "Pneumatic Subsystem", - "x": 736.0, - "y": 480.0, - "width": 192.0, - "height": 96.0, + "x": 640.0, + "y": 576.0, + "width": 256.0, + "height": 64.0, "type": "Boolean Box", "properties": { "topic": "/SmartDashboard/Pneumatic Subsystem", @@ -684,7 +684,7 @@ }, { "title": "Compressor Running", - "x": 928.0, + "x": 640.0, "y": 480.0, "width": 128.0, "height": 96.0, @@ -701,7 +701,7 @@ }, { "title": "Pressure", - "x": 1056.0, + "x": 768.0, "y": 480.0, "width": 128.0, "height": 96.0, @@ -712,6 +712,20 @@ "data_type": "double", "show_submit_button": true } + }, + { + "title": "Set Speed", + "x": 960.0, + "y": 96.0, + "width": 128.0, + "height": 96.0, + "type": "Text Display", + "properties": { + "topic": "/SmartDashboard/Intake TestSpeed", + "period": 0.06, + "data_type": "double", + "show_submit_button": true + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index b279b0e..5641f01 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -42,6 +42,7 @@ import edu.wpi.first.math.geometry.Rotation2d; import edu.wpi.first.math.system.plant.DCMotor; import edu.wpi.first.wpilibj.PneumaticsModuleType; +import edu.wpi.first.wpilibj.DoubleSolenoid; /** * The Constants class provides a convenient place for teams to hold robot-wide numerical or boolean @@ -162,10 +163,10 @@ public static class IntakeConstants { public static double kIntakeMotorSpeed = 0.3; // Solenoid states required to extend and retract the intake mechanism. - public static int kIntakeSolenoid = 0; - public static int kIntakeSolenoid1 = 0; - public static boolean kIntakeExtend = true; - public static boolean kIntakeRetract = !kIntakeExtend; + public static int kIntakeSolenoidForward = 15; + public static int kIntakeSolenoidReverse = 13; + public static DoubleSolenoid.Value kIntakeExtend = DoubleSolenoid.Value.kForward; + public static DoubleSolenoid.Value kIntakeRetract = DoubleSolenoid.Value.kReverse; } public static class LauncherConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index ff0f091..430c6f2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -5,7 +5,7 @@ package frc.robot.subsystems; import edu.wpi.first.wpilibj2.command.SubsystemBase; -import edu.wpi.first.wpilibj.Solenoid; +import edu.wpi.first.wpilibj.DoubleSolenoid; import com.ctre.phoenix6.hardware.TalonFX; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import frc.robot.Constants.IntakeConstants; @@ -13,9 +13,10 @@ public class IntakeSubsystem extends SubsystemBase { private TalonFX m_motorIntake; - private Solenoid m_solenoid; + private DoubleSolenoid m_solenoid; private boolean m_motorRunning = false; private boolean m_Extended = false; + private double m_MotorSpeed = IntakeConstants.kIntakeMotorSpeed; /** Creates a new IntakeSubsystem. */ public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { @@ -28,6 +29,7 @@ public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { // Test mode controls SmartDashboard.putBoolean("Intake TestExtend", false); SmartDashboard.putBoolean("Intake TestRun", false); + SmartDashboard.putNumber("Intake TestSpeed", m_MotorSpeed); m_motorIntake = new TalonFX(IntakeConstants.kIntakeMotorCANID); if(!m_motorIntake.isConnected()) @@ -36,9 +38,10 @@ public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { } if(bHasPneumatics) { - m_solenoid = new Solenoid(PneumaticsConstants.kPneumaticsHubCANID, - PneumaticsConstants.kHubType, - IntakeConstants.kIntakeSolenoid); + m_solenoid = new DoubleSolenoid(PneumaticsConstants.kPneumaticsHubCANID, + PneumaticsConstants.kHubType, + IntakeConstants.kIntakeSolenoidForward, + IntakeConstants.kIntakeSolenoidReverse); } else { throw new Exception("Intake subsystem requires pneumatics which are not present!"); } @@ -46,7 +49,7 @@ public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { // Spins the shaft on the intake that will move fuel into the robot. public void start() { - m_motorIntake.set(IntakeConstants.kIntakeMotorSpeed); + m_motorIntake.set(m_MotorSpeed); m_motorRunning = true; SmartDashboard.putBoolean("Intake Running", m_motorRunning); } @@ -70,6 +73,11 @@ public void retract() { SmartDashboard.putBoolean("Intake Extended", m_Extended); } + // Retracts the intake mechanism over the bumpers and inside of the robot. + public void pneumatics_off() { + m_solenoid.set(DoubleSolenoid.Value.kOff); + } + // Returns true if the intake shaft is spinning. public boolean isIntakeStarted() { return m_motorRunning; @@ -80,6 +88,13 @@ public boolean isIntakeExtended() { return m_Extended; } + public void setIntakeSpeed(double speed) { + m_MotorSpeed = speed; + if(m_motorRunning) + { + start(); + } + } @Override public void periodic() { // This method will be called once per scheduler run @@ -89,6 +104,9 @@ public void testPeriodic() { // Set the motor states based on the SmartDashboard test controls. Boolean Extend = SmartDashboard.getBoolean("Intake TestExtend", false); Boolean Run = SmartDashboard.getBoolean("Intake TestRun", false); + double Speed = SmartDashboard.getNumber("Intake TestSpeed", m_MotorSpeed); + + setIntakeSpeed(Speed); // Turn the intake on or off depending upon test control, only changing the state if the control actually changed. if(Run) { From b33bdc66960b83ce4f19564ccd40fcdf8ef76101 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Thu, 19 Mar 2026 20:52:32 -0500 Subject: [PATCH 130/161] Started a investigative rewrite of limelightSubsystem --- .../src/main/java/frc/robot/Robot.java | 2 +- .../main/java/frc/robot/RobotContainer.java | 42 +++++++++-- .../autoCommands/DeadreckonBumpAndBack.java | 12 ++- .../robot/subsystems/LimelightSubsystem.java | 73 +++---------------- .../src/main/java/frc/robot/utils/Pigeon.java | 10 +++ 5 files changed, 65 insertions(+), 74 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Robot.java b/2026-Rebuilt/src/main/java/frc/robot/Robot.java index 2dbc3e2..c5edec4 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Robot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Robot.java @@ -58,7 +58,7 @@ public void disabledInit() { @Override public void disabledPeriodic() { - LimelightHelpers.SetIMUMode("limelight", 3); + //LimelightHelpers.SetIMUMode("limelight", 3); m_robotContainer.disabledPeriodic(); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 29bb266..f65f1ef 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -224,7 +224,7 @@ private void configureAutos() { // replace slowConstraints to m_contraints after testing. m_autoChooser.addOption("[INDEV] Deadreckon Over Bump and Back", - new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, isRed) + new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, isRed, m_pigeon) ); m_autoChooser.addOption("[INDEV] Continous J into nutreal and back", @@ -403,9 +403,11 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Roll Rate", 0.0); SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); + SmartDashboard.putBoolean("Pidgeon Accurate", m_pigeon.isAccurate()); } // This function is called every 20mS. + private boolean oldPigeonValue = false; public void UpdateSmartDashboard() { // Non-subsystem specific stuff if ((m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) { @@ -424,10 +426,23 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Pitch Rate", 0.0); SmartDashboard.putNumber("Roll Rate", 0.0); - SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); + //SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); + + boolean pigeonAccuracy = m_pigeon.isAccurate(); + boolean dashboardAccuracy = SmartDashboard.getBoolean("Pidgeon Accurate", pigeonAccuracy); + + if (pigeonAccuracy != dashboardAccuracy) { + if (pigeonAccuracy == oldPigeonValue) { + m_pigeon.setAccuracy(dashboardAccuracy); + pigeonAccuracy = dashboardAccuracy; + } else { + SmartDashboard.putBoolean("Pidgeon Accurate", pigeonAccuracy); + } + } + oldPigeonValue = pigeonAccuracy; } // Drive subsystem @@ -491,14 +506,25 @@ public void autoInit() { // Gets called every disabled tick. public void disabledPeriodic() { - double cameraYaw = m_limelightSubsystem.getRobotYaw(); - - // m_gyro.enableLogging(false); - // m_gyro.reset(); - // m_gyro.setAngleAdjustment(-cameraYaw); + // Get Starting Orientation + Double robotYaw; // Degree + if (isRed.getAsBoolean() == true) { + robotYaw = 180.0; + } else { + robotYaw = 0.0; + } + // Reset Pidgeon m_pigeon.reset(); - m_pigeon.setYawOffset(cameraYaw); + m_pigeon.setYawOffset(robotYaw); + m_pigeon.setAccuracy(true); + + // Reset Limelight + LimelightHelpers.SetIMUMode("limelight", 1); + LimelightHelpers.SetRobotOrientation("limelight", robotYaw, 0, 0, 0, 0, 0); + + // Reset Pose Estimator + m_PoseEstimator.resetRotation(new Rotation2d(robotYaw * (Math.PI/180))); } /** diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java index b7b9aaf..6a2da70 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -18,6 +18,7 @@ import frc.robot.commands.AimAtHub; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.PathUtils; +import frc.robot.utils.Pigeon; /** An example command that uses an example subsystem. */ public class DeadreckonBumpAndBack extends Command { @@ -25,6 +26,7 @@ public class DeadreckonBumpAndBack extends Command { private final DifferentialDrivePoseEstimator m_poseEstimator; private final PathConstraints m_constraints; private final BooleanSupplier m_isRed; + private final Pigeon m_pigeon; /** * Creates a new DeadreckonBumpAndBack. @@ -33,12 +35,13 @@ public class DeadreckonBumpAndBack extends Command { * @param targetPose The pose the robot will make a point to go to. * @param constraints The constraints the robot will follow while following the path. */ - public DeadreckonBumpAndBack(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, BooleanSupplier isRed) + public DeadreckonBumpAndBack(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, BooleanSupplier isRed, Pigeon pigeon) { m_driveSubsystem = driveSubsystem; m_poseEstimator = poseEstimator; m_constraints = constraints; m_isRed = isRed; + m_pigeon = pigeon; } // Called when the command is initially scheduled. @@ -110,8 +113,11 @@ public void initialize() { }); // Create & Schedule the command group. - SequentialCommandGroup initialSequential = deadreckonFoward.andThen(pickupScheudle); - CommandScheduler.getInstance().schedule(initialSequential); + CommandScheduler.getInstance().schedule( + deadreckonFoward + .andThen(new InstantCommand(() -> m_pigeon.setAccuracy(false))) + //.andThen(pickupScheudle) + ); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index b9e4abe..a29e1da 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -3,9 +3,6 @@ // the WPILib BSD license file in the root directory of this project. package frc.robot.subsystems; -import java.util.Arrays; - -import org.ejml.simple.SimpleMatrix; import edu.wpi.first.math.VecBuilder; import edu.wpi.first.math.Vector; @@ -16,69 +13,35 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; import frc.robot.Constants.FieldConstants; -import frc.robot.LimelightHelpers.IMUData; import frc.robot.LimelightHelpers.PoseEstimate; -import frc.robot.utils.LimitedQueue; import frc.robot.utils.Pigeon; public class LimelightSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; private final Pigeon m_pigeon; - private final LimitedQueue m_YawQue = new LimitedQueue(5); - private boolean firstApriltagSeen = false; - /** Creates a new PositionSubsystem. */ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, Pigeon pigeon) { m_poseEstimator = poseEstimator; m_pigeon = pigeon; } - public double getRobotYaw() { - if (firstApriltagSeen == false) { - System.out.println("No apriltag seen! returning 0!"); - return 0.0; - } - - Double[] doubleObjects = m_YawQue.toArray(new Double[0]); - int queSize = doubleObjects.length; - - double[] primitiveDoubles = new double[queSize]; - for (int i = 0; i < queSize; i++) { - primitiveDoubles[i] = doubleObjects[i].doubleValue(); - } - - SimpleMatrix samplesMatrix = new SimpleMatrix(primitiveDoubles); - - double[] weightsArray = new double[queSize]; - Arrays.fill(weightsArray, 1.0); - - SimpleMatrix weightsMatrix = new SimpleMatrix(1, queSize, true, weightsArray); - - double avrg = samplesMatrix.dot(weightsMatrix)/weightsMatrix.elementSum(); - return avrg; - } - // This is copy and pasted from limelight's documentation for testing. private void updateOdometry() { - PoseEstimate poseEst; - if (firstApriltagSeen == true) { - LimelightHelpers.SetRobotOrientation("limelight", m_pigeon.getYaw(), 0, m_pigeon.getPitch(), 0, m_pigeon.getRoll(), 0); - poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight"); - } else { - poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); - } + LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); + PoseEstimate poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight");; + /// Invalidate the vision measurements if some parameters are not met \\\ if (poseEst == null) { return; } - /// Invalidate the vision measurements if some parameters are not met \\\ - - // If theirs no detected tags + // If detected tags are not enough SmartDashboard.putNumber("Tag Count", poseEst.tagCount); - if(poseEst.tagCount == 0) - { + if( + (poseEst.isMegaTag2 == true && poseEst.tagCount < 1) + || (poseEst.isMegaTag2 == false && poseEst.tagCount < 2 ) + ) { return; } @@ -92,22 +55,15 @@ private void updateOdometry() { } // Init the mt2 process once a apriltag is first seen via mt1 and a good rotation is set. - if (firstApriltagSeen == false && poseEst.tagCount >= 2 && poseEst.isMegaTag2 == false) { - firstApriltagSeen = true; + if (poseEst.tagCount > 1) { + return; } /// Actually do the vision measurements \\\ // A Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. - Vector errorVec; - - // Only trust the yaw from the guess if its not via mt2. // TODO: Look into scaling these based off of the ambuguity and size of the tags. - if (poseEst.isMegaTag2 == false) { - errorVec = VecBuilder.fill(.7,.7,0); - } else { - errorVec = VecBuilder.fill(.7,.7,9999999); - } + Vector errorVec = VecBuilder.fill(.7,.7,9999999); m_poseEstimator.setVisionMeasurementStdDevs(errorVec); m_poseEstimator.addVisionMeasurement( @@ -118,13 +74,6 @@ private void updateOdometry() { @Override public void periodic() { - // This method will be called once per scheduler - if (firstApriltagSeen == true) { - IMUData limelightData = LimelightHelpers.getIMUData("limelight"); - m_YawQue.add(limelightData.robotYaw); - } - //System.out.println(m_YawQue.toString()); - updateOdometry(); } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java b/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java index 96f3594..b327c0e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java @@ -14,6 +14,8 @@ public class Pigeon { private boolean m_exists; private double m_yawOffset = 0; + private boolean m_isAccurate = false; + public Pigeon(int PigeonCanId) { m_pigeon2 = new Pigeon2(PigeonCanId); m_exists = m_pigeon2.isConnected(); @@ -124,4 +126,12 @@ public void setYawOffset(double degrees) { public double getYawOffset() { return m_yawOffset; } + + public boolean isAccurate() { + return m_isAccurate; + } + + public void setAccuracy(boolean isAccurate) { + m_isAccurate = isAccurate; + } } From 3b14419c9e94c702c0d53ffac382df8de98cde29 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Fri, 20 Mar 2026 14:36:03 -0500 Subject: [PATCH 131/161] Made mt1 vispose w/ ambiguty --- .../main/java/frc/robot/RobotContainer.java | 29 ++++++++--------- .../frc/robot/subsystems/DriveSubsystem.java | 1 - .../robot/subsystems/LimelightSubsystem.java | 32 +++++++++++-------- .../frc/robot/utils/PneumaticHubWrapper.java | 1 - 4 files changed, 31 insertions(+), 32 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index af2b4d9..d2374f6 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -7,13 +7,10 @@ import java.util.Optional; import java.util.function.BooleanSupplier; -import com.ctre.phoenix6.hardware.Pigeon2; import com.ctre.phoenix6.hardware.TalonFX; import com.pathplanner.lib.commands.PathfindingCommand; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.util.PathPlannerLogging; -import com.studica.frc.AHRS; -import com.studica.frc.AHRS.NavXComType; import edu.wpi.first.math.VecBuilder; import edu.wpi.first.math.Vector; @@ -50,7 +47,6 @@ import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.BackupAndShootThenClimb; import frc.robot.commands.autoCommands.BackupCollectDepoAndShoot; -import frc.robot.commands.autoCommands.CorralAndShoot; import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; import frc.robot.commands.autoCommands.DeadreckonDistance; import frc.robot.commands.autoCommands.DepoAndShootThenClimb; @@ -131,7 +127,7 @@ public RobotContainer() { m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_pigeon, rightLead, leftLead, rightFollower, leftFollower); // Init the subsystems that don't require pneumatics. - m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator, m_pigeon); + m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator); m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); @@ -509,24 +505,25 @@ public void autoInit() { // Gets called every disabled tick. public void disabledPeriodic() { // Get Starting Orientation - Double robotYaw; // Degree - if (isRed.getAsBoolean() == true) { - robotYaw = 180.0; - } else { - robotYaw = 0.0; - } + // Double robotYaw; // Degree + // if (isRed.getAsBoolean() == true) { + // robotYaw = 180.0; + // } else { + // robotYaw = 0.0; + // } // Reset Pidgeon + Double robotYaw = m_PoseEstimator.getEstimatedPosition().getRotation().getDegrees(); m_pigeon.reset(); m_pigeon.setYawOffset(robotYaw); m_pigeon.setAccuracy(true); - // Reset Limelight - LimelightHelpers.SetIMUMode("limelight", 1); - LimelightHelpers.SetRobotOrientation("limelight", robotYaw, 0, 0, 0, 0, 0); + // // Reset Limelight + // LimelightHelpers.SetIMUMode("limelight", 1); + // LimelightHelpers.SetRobotOrientation("limelight", robotYaw, 0, 0, 0, 0, 0); - // Reset Pose Estimator - m_PoseEstimator.resetRotation(new Rotation2d(robotYaw * (Math.PI/180))); + // // Reset Pose Estimator + // m_PoseEstimator.resetRotation(new Rotation2d(robotYaw * (Math.PI/180))); } /** diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 5aa29d4..0b45a35 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -17,7 +17,6 @@ import com.ctre.phoenix6.signals.NeutralModeValue; import com.pathplanner.lib.auto.AutoBuilder; import com.pathplanner.lib.controllers.PPLTVController; -import com.studica.frc.AHRS; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index a29e1da..d12a8ed 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -9,27 +9,24 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.numbers.N3; +import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; import frc.robot.Constants.FieldConstants; import frc.robot.LimelightHelpers.PoseEstimate; -import frc.robot.utils.Pigeon; public class LimelightSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; - private final Pigeon m_pigeon; /** Creates a new PositionSubsystem. */ - public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator, Pigeon pigeon) { + public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { m_poseEstimator = poseEstimator; - m_pigeon = pigeon; } // This is copy and pasted from limelight's documentation for testing. private void updateOdometry() { - LimelightHelpers.SetRobotOrientation("limelight", m_poseEstimator.getEstimatedPosition().getRotation().getDegrees(), 0, 0, 0, 0, 0); - PoseEstimate poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2("limelight");; + PoseEstimate poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); /// Invalidate the vision measurements if some parameters are not met \\\ if (poseEst == null) { @@ -38,10 +35,7 @@ private void updateOdometry() { // If detected tags are not enough SmartDashboard.putNumber("Tag Count", poseEst.tagCount); - if( - (poseEst.isMegaTag2 == true && poseEst.tagCount < 1) - || (poseEst.isMegaTag2 == false && poseEst.tagCount < 2 ) - ) { + if(poseEst.tagCount < 2 || poseEst.rawFiducials.length > 0) { return; } @@ -54,17 +48,27 @@ private void updateOdometry() { return; } - // Init the mt2 process once a apriltag is first seen via mt1 and a good rotation is set. - if (poseEst.tagCount > 1) { + // Make sure that the abiguity of the primary target is not to high + Double bestTargetAmbiguity = poseEst.rawFiducials[0].ambiguity; + if (bestTargetAmbiguity > 0.2) { return; } /// Actually do the vision measurements \\\ // A Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. - // TODO: Look into scaling these based off of the ambuguity and size of the tags. - Vector errorVec = VecBuilder.fill(.7,.7,9999999); + // TODO: Look into scaling these based off of the ambuguity and size of the tags. -- Kinda done (3/20/2025) + Vector errorVec; + double stdDev = 0.5 + bestTargetAmbiguity; + + // Trusting the yaw when disabled to get our robot orientation. + if (DriverStation.isDisabled()) { + errorVec = VecBuilder.fill(stdDev, stdDev,0); + } else { + errorVec = VecBuilder.fill(stdDev, stdDev,9999999); + } + // Add the measurements to the pose estimator m_poseEstimator.setVisionMeasurementStdDevs(errorVec); m_poseEstimator.addVisionMeasurement( poseEst.pose, diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java index 2c6a539..ea5b166 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/PneumaticHubWrapper.java @@ -5,7 +5,6 @@ package frc.robot.utils; import edu.wpi.first.wpilibj.PneumaticHub; -import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.hal.REVPHVersion; public class PneumaticHubWrapper extends PneumaticHub { From 5633477a5ba5d2243de1d3c858bebf322ae69b93 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Sat, 21 Mar 2026 09:42:56 -0500 Subject: [PATCH 132/161] Added Elastic indicator indicating within scoring distance of hub --- 2026-Rebuilt/elastic-layout.json | 17 ++++++++++++++ .../src/main/java/frc/robot/Constants.java | 1 + .../main/java/frc/robot/RobotContainer.java | 10 ++++++++ .../java/frc/robot/utils/LauncherUtils.java | 23 +++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index c0f9436..48b6536 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -204,6 +204,23 @@ "data_type": "double", "show_submit_button": true } + }, + { + "title": "Safe To Shoot", + "x": 0.0, + "y": 256.0, + "width": 256.0, + "height": 128.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Launcher SafeToShoot", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 5641f01..67df364 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -207,6 +207,7 @@ public static class LauncherConstants { // Frequency at which we send current launcher speed back to the driver station. public static final int kTicksPerUpdate = 10; + public static final int kTicksPerDistanceUpdate = 45; public static final double kFixedTestSpeed = 3000.0; public static final double kFlywheelToleranceRPM = 100.0; diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index d2374f6..470715e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -53,6 +53,7 @@ import frc.robot.commands.autoCommands.OverBumpContinousJ; import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; +import frc.robot.utils.LauncherUtils; import frc.robot.Constants.*; /** @@ -392,6 +393,8 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); SmartDashboard.putNumber("mt2 Tag Count", 0.0); + SmartDashboard.putBoolean("Launcher SafeToShoot", false); + SmartDashboard.putNumber("Yaw", 0.0); SmartDashboard.putNumber("Pitch", 0.0); SmartDashboard.putNumber("Roll", 0.0); @@ -467,6 +470,13 @@ public void UpdateSmartDashboard() { SmartDashboard.putBoolean("Compressor Running", hub.getCompressor()); } + // Safe-to-shoot indicator. + if(m_launcherSubsystem.isPresent() && ((m_iTickCount % LauncherConstants.kTicksPerDistanceUpdate) == 0)) + { + Boolean bCanShoot = LauncherUtils.canScoreFromHere(m_PoseEstimator, isRed); + SmartDashboard.putBoolean("Launcher SafeToShoot", bCanShoot); + } + m_iTickCount++; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java index d0398b2..7f8132e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java @@ -1,5 +1,10 @@ package frc.robot.utils; +import java.util.function.BooleanSupplier; + +import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; +import frc.robot.utils.HubUtils; + public class LauncherUtils { // // Characterization data for the launcher. This table links shooting @@ -13,6 +18,24 @@ public class LauncherUtils { {5.21, 3300.0}, }; + // + // Return the minimum robot-to-hub distance from which we know we + // can score fuel. + // + public static double getMinShootingDistance() { + return m_DistanceToRPM[0][0]; + } + + public static Boolean canScoreFromHere(DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) { + // How far are we from our alliance hub? + double distance = HubUtils.getHubDistance(poseEstimator, isRed); + + // This doesn't take into consideration which part of the field we are in so will + // report true even in the neutral zone. We assume the driver is aware enough of the + // robot position to know this! + return ((distance >= m_DistanceToRPM[0][0]) && (distance <= m_DistanceToRPM[m_DistanceToRPM.length - 1][0])); + } + // // Given a distance between the robot and the hub, calculate the // launcher flywheel speed needed to successfully score fuel from From d4ceb0db133879a7a445505661c0c53fc841409c Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 21 Mar 2026 10:08:14 -0500 Subject: [PATCH 133/161] Reverse intake motor direction after robot testing --- .../src/main/java/frc/robot/subsystems/IntakeSubsystem.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index 430c6f2..f570832 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -49,7 +49,7 @@ public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { // Spins the shaft on the intake that will move fuel into the robot. public void start() { - m_motorIntake.set(m_MotorSpeed); + m_motorIntake.set(-m_MotorSpeed); m_motorRunning = true; SmartDashboard.putBoolean("Intake Running", m_motorRunning); } @@ -107,7 +107,7 @@ public void testPeriodic() { double Speed = SmartDashboard.getNumber("Intake TestSpeed", m_MotorSpeed); setIntakeSpeed(Speed); - + // Turn the intake on or off depending upon test control, only changing the state if the control actually changed. if(Run) { if(!m_motorRunning) { From 7b05afc2338386993302873494d176ad318392a7 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 21 Mar 2026 10:08:37 -0500 Subject: [PATCH 134/161] Speed up bulk move after robot testing --- 2026-Rebuilt/elastic-layout.json | 2 +- 2026-Rebuilt/src/main/java/frc/robot/Constants.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 48b6536..70d42ae 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -732,7 +732,7 @@ }, { "title": "Set Speed", - "x": 960.0, + "x": 1088.0, "y": 96.0, "width": 128.0, "height": 96.0, diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 67df364..e660113 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -160,7 +160,7 @@ public static class IntakeConstants { public static int kIntakeMotorCANID = 30; // Raw intake motor speed in range [-1.0,1.0] - public static double kIntakeMotorSpeed = 0.3; + public static double kIntakeMotorSpeed = 0.6; // Solenoid states required to extend and retract the intake mechanism. public static int kIntakeSolenoidForward = 15; @@ -218,7 +218,7 @@ public static class IndexerBulkConstants { public static int kBulkMoveMotorCANID = 51; // Raw motor speeds in range [-1.0,1.0] - public static final double kBulkMoveMotorSpeed = 0.3; + public static final double kBulkMoveMotorSpeed = 0.5; public static final double kIndexerMotorSpeed = 0.3; } From 76f85090e16a5b4f043f46bc18c332dd6a549bf5 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:29:42 -0500 Subject: [PATCH 135/161] Tested new limelight pose & started on start pose --- .../pathplanner/paths/TestPointsGet.path | 54 +++++++++++ .../src/main/java/frc/robot/Constants.java | 24 +++++ .../src/main/java/frc/robot/Robot.java | 2 +- .../main/java/frc/robot/RobotContainer.java | 91 +++++++++++-------- .../robot/factorys/DriveSubsystemFactory.java | 6 +- .../frc/robot/subsystems/DriveSubsystem.java | 17 +--- .../robot/subsystems/LimelightSubsystem.java | 52 ++++++++++- 7 files changed, 191 insertions(+), 55 deletions(-) create mode 100644 2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path new file mode 100644 index 0000000..a1bba48 --- /dev/null +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path @@ -0,0 +1,54 @@ +{ + "version": "2025.0", + "waypoints": [ + { + "anchor": { + "x": 12.956, + "y": 2.884 + }, + "prevControl": null, + "nextControl": { + "x": -87.04400000000024, + "y": 2.8840000000000123 + }, + "isLocked": false, + "linkedName": null + }, + { + "anchor": { + "x": -0.044, + "y": 0.0 + }, + "prevControl": { + "x": -1.044, + "y": 1.2246467991473532e-16 + }, + "nextControl": null, + "isLocked": false, + "linkedName": null + } + ], + "rotationTargets": [], + "constraintZones": [], + "pointTowardsZones": [], + "eventMarkers": [], + "globalConstraints": { + "maxVelocity": 1.0, + "maxAcceleration": 1.0, + "maxAngularVelocity": 540.0, + "maxAngularAcceleration": 720.0, + "nominalVoltage": 12.0, + "unlimited": false + }, + "goalEndState": { + "velocity": 0, + "rotation": 0.0 + }, + "reversed": false, + "folder": null, + "idealStartingState": { + "velocity": 0, + "rotation": 0.0 + }, + "useDefaultConstraints": true +} \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 5641f01..f510914 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -35,11 +35,14 @@ package frc.robot; +import java.util.Map; + import com.pathplanner.lib.config.ModuleConfig; import com.pathplanner.lib.config.RobotConfig; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; +import edu.wpi.first.math.geometry.Translation2d; import edu.wpi.first.math.system.plant.DCMotor; import edu.wpi.first.wpilibj.PneumaticsModuleType; import edu.wpi.first.wpilibj.DoubleSolenoid; @@ -67,6 +70,27 @@ public static class RobotConstants { public static final double kPigeonYawOffset = -5.295877933502197; // degrees (-360, 360) public static final double kPigeonPitchOffset = 0.7246352434158325; // degrees (-360, 360) public static final double kPigeonRollOffset = -0.49318647384643555; // degrees (-360, 360) + + public static enum kStartingNames { + DEPOT_SIDE, + HUB, + OUTPOST_SIDE + } + + public static final Map> kStartingPositions = Map.ofEntries( + Map.entry(kStartingNames.DEPOT_SIDE, Map.ofEntries( + Map.entry(true, new Pose2d(new Translation2d(12.956, 2.884), Rotation2d.k180deg)), // red + Map.entry(false, new Pose2d(new Translation2d(3.607, 5.186), Rotation2d.kZero)) // blue + )), + Map.entry(kStartingNames.HUB, Map.ofEntries( + Map.entry(true, new Pose2d(new Translation2d(), Rotation2d.k180deg)), // red + Map.entry(false, new Pose2d(new Translation2d(), Rotation2d.kZero)) // blue + )), + Map.entry(kStartingNames.OUTPOST_SIDE, Map.ofEntries( + Map.entry(true, new Pose2d(new Translation2d(), Rotation2d.k180deg)), // red + Map.entry(false, new Pose2d(new Translation2d(), Rotation2d.kZero)) // blue + )) + ); } public static class AutoConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/Robot.java b/2026-Rebuilt/src/main/java/frc/robot/Robot.java index c5edec4..24985be 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Robot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Robot.java @@ -47,7 +47,7 @@ public void robotPeriodic() { CommandScheduler.getInstance().run(); // Send subsystem and robot state back to the driver station. - m_robotContainer.UpdateSmartDashboard(); + m_robotContainer.periodic(); } /** This function is called once each time the robot enters Disabled mode. */ diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index d2374f6..ac73add 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -54,6 +54,7 @@ import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.Constants.*; +import frc.robot.Constants.RobotConstants.kStartingNames; /** * This class is where the bulk of the robot should be declared. Since Command-based is a @@ -105,6 +106,7 @@ public class RobotContainer { // Smartdashboard Objects private SendableChooser m_autoChooser; + private SendableChooser m_startingChooser; private final Field2d m_field = new Field2d(); // Factorys @@ -124,7 +126,7 @@ public RobotContainer() { Optional leftLead = m_TalonFXFactory.construct(DrivetrainConstants.kLeftMotorCANID); Optional rightFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalRightMotorCANID); Optional leftFollower = m_TalonFXFactory.construct(DrivetrainConstants.kOptionalLeftMotorCANID); - m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_pigeon, rightLead, leftLead, rightFollower, leftFollower); + m_driveSubsystem = m_DriveSubsystemFactory.construct(m_PoseEstimator, m_DriveKinematics, m_pigeon, rightLead, leftLead, rightFollower, leftFollower, m_isRed); // Init the subsystems that don't require pneumatics. m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator); @@ -191,23 +193,23 @@ private void configureAutos() { // Init Autos m_autoChooser.addOption("[INDEV] Basic backup and shoot", - new BackupAndShoot(driveSubsystem, m_PoseEstimator, isRed) + new BackupAndShoot(driveSubsystem, m_PoseEstimator, m_isRed) ); m_autoChooser.addOption("[INDEV] Backup and climb", - new BackupAndClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + new BackupAndClimb(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) ); m_autoChooser.addOption("[INDEV] Backup and shoot then climb", - new BackupAndShootThenClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + new BackupAndShootThenClimb(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) ); m_autoChooser.addOption("[INDEV] Backup and collect from depot then shoot", - new BackupCollectDepoAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + new BackupCollectDepoAndShoot(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) ); m_autoChooser.addOption("[INDEV] Depo Collect, shoot, then climb", - new DepoAndShootThenClimb(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + new DepoAndShootThenClimb(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) ); // Test Autos @@ -220,11 +222,11 @@ private void configureAutos() { // replace slowConstraints to m_contraints after testing. m_autoChooser.addOption("[INDEV] Deadreckon Over Bump and Back", - new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, isRed, m_pigeon) + new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, m_isRed, m_pigeon) ); m_autoChooser.addOption("[INDEV] Continous J into nutreal and back", - new OverBumpContinousJ(driveSubsystem, m_PoseEstimator, isRed) + new OverBumpContinousJ(driveSubsystem, m_PoseEstimator, m_isRed) ); m_autoChooser.addOption("[TEST] Forward Test", @@ -308,7 +310,7 @@ private void configureBindings() { // Aim to Hub m_driverController.rightBumper().onTrue( - new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, isRed) + new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, m_isRed) ); // Range launcher, turn to face hub and shoot all fuel. @@ -322,13 +324,13 @@ private void configureBindings() { launcher, indexer, m_PoseEstimator, - isRed, + m_isRed, LauncherConstants.kFlywheelToleranceRPM)); } // Travel to corner and shoot m_driverController.x().onTrue( - new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, isRed, m_constraints) + new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) ); // TEST COMMAND FOR TESTING ACCURACY AFTER BUMP! @@ -389,7 +391,7 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Target Angle Diff Abs", 0); SmartDashboard.putNumber("Rotation Speed", 0); - SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); + SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, m_isRed)); SmartDashboard.putNumber("mt2 Tag Count", 0.0); SmartDashboard.putNumber("Yaw", 0.0); @@ -402,11 +404,33 @@ public void InitSmartDashboard() { SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); SmartDashboard.putBoolean("Pidgeon Accurate", m_pigeon.isAccurate()); + + m_startingChooser = new SendableChooser(); + for (kStartingNames startingName : kStartingNames.values()) { + m_startingChooser.addOption(startingName.name(), startingName); + } + SmartDashboard.putData("Starting Position", m_startingChooser); + } + + // This function is called every 20mS. + private boolean oldIsRed; + private kStartingNames oldStartEnum; + public void periodic() { + UpdateSmartDashboard(); + + boolean isRed = m_isRed.getAsBoolean(); + kStartingNames startEnum = m_startingChooser.getSelected(); + if ((isRed != oldIsRed) || (startEnum != null && (startEnum != oldStartEnum))) { + oldIsRed = isRed; + oldStartEnum = startEnum; + + Pose2d startingPose = RobotConstants.kStartingPositions.get(startEnum).get(m_isRed.getAsBoolean()); + m_PoseEstimator.resetPose(startingPose); + } } - // This function is called every 20mS. private boolean oldPigeonValue = false; - public void UpdateSmartDashboard() { + private void UpdateSmartDashboard() { // Non-subsystem specific stuff if ((m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) { Pose2d estimatedPos = m_PoseEstimator.getEstimatedPosition(); @@ -425,7 +449,7 @@ public void UpdateSmartDashboard() { SmartDashboard.putNumber("Roll Rate", 0.0); //SmartDashboard.putNumber("Limelight robotYaw", m_limelightSubsystem.getRobotYaw()); - SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, isRed)); + SmartDashboard.putNumber("Hub Distance", HubUtils.getHubDistance(m_PoseEstimator, m_isRed)); SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); @@ -471,7 +495,7 @@ public void UpdateSmartDashboard() { } // Checks if the robot is on the blue or red alliance. If it cannot get the data it defaults to blue. - public BooleanSupplier isRed = () -> { + public BooleanSupplier m_isRed = () -> { Optional alliance = DriverStation.getAlliance(); if (alliance.isPresent()) { return alliance.get() == DriverStation.Alliance.Red; @@ -481,11 +505,17 @@ public void UpdateSmartDashboard() { } }; - public void disabledInit() {} + private int disabledTick = 0; + public void disabledInit() { + disabledTick = 0; + LimelightHelpers.SetIMUMode("limelight", 3); + m_limelightSubsystem.setAllowJumps(true); + } // Move to auto init for competition code. public void enabledInit() { - LimelightHelpers.SetIMUMode("limelight", 4); + LimelightHelpers.SetIMUMode("limelight", 3); + m_limelightSubsystem.setAllowJumps(false); } public void teleopInit() { @@ -504,26 +534,15 @@ public void autoInit() { // Gets called every disabled tick. public void disabledPeriodic() { - // Get Starting Orientation - // Double robotYaw; // Degree - // if (isRed.getAsBoolean() == true) { - // robotYaw = 180.0; - // } else { - // robotYaw = 0.0; - // } - // Reset Pidgeon - Double robotYaw = m_PoseEstimator.getEstimatedPosition().getRotation().getDegrees(); - m_pigeon.reset(); - m_pigeon.setYawOffset(robotYaw); - m_pigeon.setAccuracy(true); - - // // Reset Limelight - // LimelightHelpers.SetIMUMode("limelight", 1); - // LimelightHelpers.SetRobotOrientation("limelight", robotYaw, 0, 0, 0, 0, 0); + if ((disabledTick % 5) == 0) { + Double robotYaw = m_limelightSubsystem.getRobotYaw(); + m_pigeon.reset(); + m_pigeon.setYawOffset(robotYaw); + m_pigeon.setAccuracy(true); + } - // // Reset Pose Estimator - // m_PoseEstimator.resetRotation(new Rotation2d(robotYaw * (Math.PI/180))); + disabledTick += 1; } /** diff --git a/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java b/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java index bb8eff9..0453ffe 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java +++ b/2026-Rebuilt/src/main/java/frc/robot/factorys/DriveSubsystemFactory.java @@ -1,6 +1,8 @@ package frc.robot.factorys; import java.util.Optional; +import java.util.function.BooleanSupplier; + import com.ctre.phoenix6.hardware.TalonFX; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; @@ -15,14 +17,14 @@ public DriveSubsystemFactory() { public Optional construct(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, Pigeon pigeon, Optional rightLead, Optional leftLead, Optional rightFollower, - Optional leftFollower) { + Optional leftFollower, BooleanSupplier isRed) { if (rightLead.isEmpty() || leftLead.isEmpty()) { return Optional.empty(); } DriveSubsystem driveSubsystem = new DriveSubsystem(poseEstimator, kinematics, pigeon, rightLead.get(), - leftLead.get()); + leftLead.get(), isRed); if (rightFollower.isPresent() && leftFollower.isPresent()) { driveSubsystem.setFollowers(rightFollower.get(), leftFollower.get()); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 0b45a35..43833f2 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -7,6 +7,8 @@ package frc.robot.subsystems; import static edu.wpi.first.units.Units.Volts; +import java.util.function.BooleanSupplier; + import com.ctre.phoenix6.StatusCode; import com.ctre.phoenix6.configs.TalonFXConfiguration; import com.ctre.phoenix6.controls.Follower; @@ -58,7 +60,7 @@ public class DriveSubsystem extends SubsystemBase { private final SendableChooser> m_driveChooser = new SendableChooser<>(); /** Creates a new DriveSubsystem. */ - public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, Pigeon pigeon, TalonFX rightMotor, TalonFX leftMotor) { + public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, DifferentialDriveKinematics kinematics, Pigeon pigeon, TalonFX rightMotor, TalonFX leftMotor, BooleanSupplier isRed) { m_poseEstimator = poseEstimator; m_kinematics = kinematics; m_pigeon = pigeon; @@ -85,18 +87,7 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential (speeds, feedforwards) -> driveRobotRelative(speeds), new PPLTVController(0.02), AutoConstants.kRobotConfig, - () -> { - // Boolean supplier that controls when the path will be mirrored for the red alliance - // This will flip the path being followed to the red side of the field. - // THE ORIGIN WILL REMAIN ON THE BLUE SIDE - - var alliance = DriverStation.getAlliance(); - if (alliance.isPresent()) { - DriverStation.Alliance currentAlliance = alliance.get(); - return currentAlliance == DriverStation.Alliance.Red; - } - return false; - }, + isRed, this ); diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index d12a8ed..356760e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -4,6 +4,10 @@ package frc.robot.subsystems; +import java.util.Arrays; + +import org.ejml.simple.SimpleMatrix; + import edu.wpi.first.math.VecBuilder; import edu.wpi.first.math.Vector; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; @@ -14,17 +18,45 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; import frc.robot.Constants.FieldConstants; +import frc.robot.LimelightHelpers.IMUData; import frc.robot.LimelightHelpers.PoseEstimate; +import frc.robot.utils.LimitedQueue; public class LimelightSubsystem extends SubsystemBase { private final DifferentialDrivePoseEstimator m_poseEstimator; + private final LimitedQueue m_YawQue = new LimitedQueue(5); + private boolean m_allowJumps = true; /** Creates a new PositionSubsystem. */ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { m_poseEstimator = poseEstimator; } - // This is copy and pasted from limelight's documentation for testing. + public double getRobotYaw() { + if (m_YawQue.isEmpty()) { + System.out.println("No yaws to avrg! returning 0!"); + return 0.0; + } + + Double[] doubleObjects = m_YawQue.toArray(new Double[0]); + int queSize = doubleObjects.length; + + double[] primitiveDoubles = new double[queSize]; + for (int i = 0; i < queSize; i++) { + primitiveDoubles[i] = doubleObjects[i].doubleValue(); + } + + SimpleMatrix samplesMatrix = new SimpleMatrix(primitiveDoubles); + + double[] weightsArray = new double[queSize]; + Arrays.fill(weightsArray, 1.0); + + SimpleMatrix weightsMatrix = new SimpleMatrix(1, queSize, true, weightsArray); + + double avrg = samplesMatrix.dot(weightsMatrix)/weightsMatrix.elementSum(); + return avrg; + } + private void updateOdometry() { PoseEstimate poseEst = LimelightHelpers.getBotPoseEstimate_wpiBlue("limelight"); @@ -33,14 +65,16 @@ private void updateOdometry() { return; } + Pose2d estimatedPose = poseEst.pose; + Pose2d currentPose = m_poseEstimator.getEstimatedPosition(); + // If detected tags are not enough SmartDashboard.putNumber("Tag Count", poseEst.tagCount); - if(poseEst.tagCount < 2 || poseEst.rawFiducials.length > 0) { + if(poseEst.tagCount < 2 || poseEst.rawFiducials.length <= 0) { return; } // Make sure that the estimated position is within field bounds. - Pose2d estimatedPose = poseEst.pose; if ( estimatedPose.getX() < 0.0 || estimatedPose.getX() > FieldConstants.kFieldWidth || estimatedPose.getY() < 0.0 || estimatedPose.getY() > FieldConstants.kFieldLength @@ -48,6 +82,11 @@ private void updateOdometry() { return; } + double distanceDiff = currentPose.getTranslation().getDistance(estimatedPose.getTranslation()); + if (m_allowJumps == false && distanceDiff > 2.0) { + return; + } + // Make sure that the abiguity of the primary target is not to high Double bestTargetAmbiguity = poseEst.rawFiducials[0].ambiguity; if (bestTargetAmbiguity > 0.2) { @@ -79,5 +118,12 @@ private void updateOdometry() { @Override public void periodic() { updateOdometry(); + + IMUData limelightData = LimelightHelpers.getIMUData("limelight"); + m_YawQue.add(limelightData.robotYaw); + } + + public void setAllowJumps(boolean allowJumps) { + m_allowJumps = allowJumps; } } From 0aa8c33f1e84816fecaba02e5dc8cbfabd55cf21 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:30:37 -0500 Subject: [PATCH 136/161] Fixed some isRed naming issues --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 0a3fd21..d5912d3 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -497,7 +497,7 @@ private void UpdateSmartDashboard() { // Safe-to-shoot indicator. if(m_launcherSubsystem.isPresent() && ((m_iTickCount % LauncherConstants.kTicksPerDistanceUpdate) == 0)) { - Boolean bCanShoot = LauncherUtils.canScoreFromHere(m_PoseEstimator, isRed); + Boolean bCanShoot = LauncherUtils.canScoreFromHere(m_PoseEstimator, m_isRed); SmartDashboard.putBoolean("Launcher SafeToShoot", bCanShoot); } From a0e1c8dea9a7cdbbf530c085b82ed671f88520a8 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Mar 2026 11:40:47 -0500 Subject: [PATCH 137/161] Orgnized some locations of code --- .../main/java/frc/robot/RobotContainer.java | 86 +++++++++---------- .../autoCommands/DeadreckonBumpAndBack.java | 3 +- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index d5912d3..c29d8b9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -117,6 +117,17 @@ public class RobotContainer { // Keep track of time for SmartDashboard updates. static int m_iTickCount = 0; + // Checks if the robot is on the blue or red alliance. If it cannot get the data it defaults to blue. + public BooleanSupplier m_isRed = () -> { + Optional alliance = DriverStation.getAlliance(); + if (alliance.isPresent()) { + return alliance.get() == DriverStation.Alliance.Red; + } else { + System.out.println("Could not fetch alliance! Defaulting to blue!"); + return false; + } + }; + /** The container for the robot. Contains subsystems, OI devices, and commands. */ public RobotContainer() { // Init Pigeon @@ -406,7 +417,7 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Roll Rate", 0.0); SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); - SmartDashboard.putBoolean("Pidgeon Accurate", m_pigeon.isAccurate()); + // SmartDashboard.putBoolean("Pidgeon Accurate", m_pigeon.isAccurate()); m_startingChooser = new SendableChooser(); for (kStartingNames startingName : kStartingNames.values()) { @@ -420,19 +431,9 @@ public void InitSmartDashboard() { private kStartingNames oldStartEnum; public void periodic() { UpdateSmartDashboard(); - - boolean isRed = m_isRed.getAsBoolean(); - kStartingNames startEnum = m_startingChooser.getSelected(); - if ((isRed != oldIsRed) || (startEnum != null && (startEnum != oldStartEnum))) { - oldIsRed = isRed; - oldStartEnum = startEnum; - - Pose2d startingPose = RobotConstants.kStartingPositions.get(startEnum).get(m_isRed.getAsBoolean()); - m_PoseEstimator.resetPose(startingPose); - } } - private boolean oldPigeonValue = false; + //private boolean oldPigeonValue = false; private void UpdateSmartDashboard() { // Non-subsystem specific stuff if ((m_iTickCount % DrivetrainConstants.kTicksPerUpdate) == 0) { @@ -456,18 +457,18 @@ private void UpdateSmartDashboard() { SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); - boolean pigeonAccuracy = m_pigeon.isAccurate(); - boolean dashboardAccuracy = SmartDashboard.getBoolean("Pidgeon Accurate", pigeonAccuracy); - - if (pigeonAccuracy != dashboardAccuracy) { - if (pigeonAccuracy == oldPigeonValue) { - m_pigeon.setAccuracy(dashboardAccuracy); - pigeonAccuracy = dashboardAccuracy; - } else { - SmartDashboard.putBoolean("Pidgeon Accurate", pigeonAccuracy); - } - } - oldPigeonValue = pigeonAccuracy; + // boolean pigeonAccuracy = m_pigeon.isAccurate(); + // boolean dashboardAccuracy = SmartDashboard.getBoolean("Pidgeon Accurate", pigeonAccuracy); + + // if (pigeonAccuracy != dashboardAccuracy) { + // if (pigeonAccuracy == oldPigeonValue) { + // m_pigeon.setAccuracy(dashboardAccuracy); + // pigeonAccuracy = dashboardAccuracy; + // } else { + // SmartDashboard.putBoolean("Pidgeon Accurate", pigeonAccuracy); + // } + // } + // oldPigeonValue = pigeonAccuracy; } // Drive subsystem @@ -504,24 +505,6 @@ private void UpdateSmartDashboard() { m_iTickCount++; } - // Checks if the robot is on the blue or red alliance. If it cannot get the data it defaults to blue. - public BooleanSupplier m_isRed = () -> { - Optional alliance = DriverStation.getAlliance(); - if (alliance.isPresent()) { - return alliance.get() == DriverStation.Alliance.Red; - } else { - System.out.println("Could not fetch alliance! Defaulting to blue!"); - return false; - } - }; - - private int disabledTick = 0; - public void disabledInit() { - disabledTick = 0; - LimelightHelpers.SetIMUMode("limelight", 3); - m_limelightSubsystem.setAllowJumps(true); - } - // Move to auto init for competition code. public void enabledInit() { LimelightHelpers.SetIMUMode("limelight", 3); @@ -542,6 +525,13 @@ public void autoInit() { // } } + private int disabledTick = 0; + public void disabledInit() { + disabledTick = 0; + LimelightHelpers.SetIMUMode("limelight", 3); + m_limelightSubsystem.setAllowJumps(true); + } + // Gets called every disabled tick. public void disabledPeriodic() { // Reset Pidgeon @@ -549,7 +539,17 @@ public void disabledPeriodic() { Double robotYaw = m_limelightSubsystem.getRobotYaw(); m_pigeon.reset(); m_pigeon.setYawOffset(robotYaw); - m_pigeon.setAccuracy(true); + } + + // Check the side + boolean isRed = m_isRed.getAsBoolean(); + kStartingNames startEnum = m_startingChooser.getSelected(); + if ((isRed != oldIsRed) || (startEnum != null && (startEnum != oldStartEnum))) { + oldIsRed = isRed; + oldStartEnum = startEnum; + + Pose2d startingPose = RobotConstants.kStartingPositions.get(startEnum).get(m_isRed.getAsBoolean()); + m_PoseEstimator.resetPose(startingPose); } disabledTick += 1; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java index 6a2da70..f4dbbb0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -115,8 +115,7 @@ public void initialize() { // Create & Schedule the command group. CommandScheduler.getInstance().schedule( deadreckonFoward - .andThen(new InstantCommand(() -> m_pigeon.setAccuracy(false))) - //.andThen(pickupScheudle) + .andThen(pickupScheudle) ); } From 04b915f7bf668f974a82f7aee37cb1f56c497b8a Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Mar 2026 12:10:04 -0500 Subject: [PATCH 138/161] Fixed some issues with refreshing start position --- .../main/java/frc/robot/RobotContainer.java | 33 +++++++++++++------ .../robot/subsystems/LimelightSubsystem.java | 4 +-- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index c29d8b9..145e6e1 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -419,7 +419,8 @@ public void InitSmartDashboard() { SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); // SmartDashboard.putBoolean("Pidgeon Accurate", m_pigeon.isAccurate()); - m_startingChooser = new SendableChooser(); + m_startingChooser = new SendableChooser(); + m_startingChooser.setDefaultOption("NONE", null); for (kStartingNames startingName : kStartingNames.values()) { m_startingChooser.addOption(startingName.name(), startingName); } @@ -427,8 +428,6 @@ public void InitSmartDashboard() { } // This function is called every 20mS. - private boolean oldIsRed; - private kStartingNames oldStartEnum; public void periodic() { UpdateSmartDashboard(); } @@ -533,23 +532,37 @@ public void disabledInit() { } // Gets called every disabled tick. + private boolean oldIsRed; + private kStartingNames oldStartEnum; public void disabledPeriodic() { // Reset Pidgeon if ((disabledTick % 5) == 0) { Double robotYaw = m_limelightSubsystem.getRobotYaw(); - m_pigeon.reset(); - m_pigeon.setYawOffset(robotYaw); + if (robotYaw != null) { + m_pigeon.reset(); + m_pigeon.setYawOffset(robotYaw); + } } // Check the side boolean isRed = m_isRed.getAsBoolean(); kStartingNames startEnum = m_startingChooser.getSelected(); - if ((isRed != oldIsRed) || (startEnum != null && (startEnum != oldStartEnum))) { - oldIsRed = isRed; - oldStartEnum = startEnum; + if (startEnum != null) { + if ((isRed != oldIsRed) || (startEnum != oldStartEnum)) { + oldIsRed = isRed; + oldStartEnum = startEnum; - Pose2d startingPose = RobotConstants.kStartingPositions.get(startEnum).get(m_isRed.getAsBoolean()); - m_PoseEstimator.resetPose(startingPose); + Pose2d startingPose = RobotConstants.kStartingPositions.get(startEnum).get(m_isRed.getAsBoolean()); + + m_pigeon.reset(); + m_pigeon.setYawOffset(startingPose.getRotation().getDegrees()); + + m_PoseEstimator.resetPose(startingPose); + + System.out.println("Reset starting pose!"); + } + } else if(startEnum != oldStartEnum) { + oldStartEnum = null; } disabledTick += 1; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 356760e..dd343b0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -32,10 +32,10 @@ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { m_poseEstimator = poseEstimator; } - public double getRobotYaw() { + public Double getRobotYaw() { if (m_YawQue.isEmpty()) { System.out.println("No yaws to avrg! returning 0!"); - return 0.0; + return null; } Double[] doubleObjects = m_YawQue.toArray(new Double[0]); From f15b0e9f1fb227d693e87caa48c2959aeb265041 Mon Sep 17 00:00:00 2001 From: Recoil Robotics <111537871+Capyblapy@users.noreply.github.com> Date: Sat, 21 Mar 2026 15:23:19 -0500 Subject: [PATCH 139/161] Made the pidgeon only update if its outside of a degree of agrement --- .../pathplanner/paths/TestPointsGet.path | 8 +++--- .../src/main/java/frc/robot/Constants.java | 8 +++--- .../main/java/frc/robot/RobotContainer.java | 28 ++++++++++++++----- .../robot/subsystems/LimelightSubsystem.java | 23 ++++++++------- .../src/main/java/frc/robot/utils/Pigeon.java | 5 +++- 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path index a1bba48..c07333a 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path @@ -3,13 +3,13 @@ "waypoints": [ { "anchor": { - "x": 12.956, - "y": 2.884 + "x": 12.945, + "y": 4.0 }, "prevControl": null, "nextControl": { - "x": -87.04400000000024, - "y": 2.8840000000000123 + "x": -87.05500000000019, + "y": 4.000000000000012 }, "isLocked": false, "linkedName": null diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 0ffd0b4..0ee67b0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -83,12 +83,12 @@ public static enum kStartingNames { Map.entry(false, new Pose2d(new Translation2d(3.607, 5.186), Rotation2d.kZero)) // blue )), Map.entry(kStartingNames.HUB, Map.ofEntries( - Map.entry(true, new Pose2d(new Translation2d(), Rotation2d.k180deg)), // red - Map.entry(false, new Pose2d(new Translation2d(), Rotation2d.kZero)) // blue + Map.entry(true, new Pose2d(new Translation2d(12.945, 4.0), Rotation2d.k180deg)), // red + Map.entry(false, new Pose2d(new Translation2d(3.561, 4.0), Rotation2d.kZero)) // blue )), Map.entry(kStartingNames.OUTPOST_SIDE, Map.ofEntries( - Map.entry(true, new Pose2d(new Translation2d(), Rotation2d.k180deg)), // red - Map.entry(false, new Pose2d(new Translation2d(), Rotation2d.kZero)) // blue + Map.entry(true, new Pose2d(new Translation2d(12.979, 5.163), Rotation2d.k180deg)), // red + Map.entry(false, new Pose2d(new Translation2d(3.6, 2.9), Rotation2d.kZero)) // blue )) ); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 145e6e1..dbb0fca 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -85,7 +85,7 @@ public class RobotContainer { // A Static Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. private Vector m_drivetrainError = VecBuilder.fill(0.2, 0.2, 0); - private Vector m_limelightError = VecBuilder.fill(.7,.7,9999999); + private Vector m_limelightError = VecBuilder.fill(.7,.7,9999999); // This gets updated per report private DifferentialDrivePoseEstimator m_PoseEstimator = new DifferentialDrivePoseEstimator( m_DriveKinematics, @@ -536,11 +536,14 @@ public void disabledInit() { private kStartingNames oldStartEnum; public void disabledPeriodic() { // Reset Pidgeon - if ((disabledTick % 5) == 0) { + if ((disabledTick % 20) == 0) { Double robotYaw = m_limelightSubsystem.getRobotYaw(); if (robotYaw != null) { - m_pigeon.reset(); - m_pigeon.setYawOffset(robotYaw); + Rotation2d currentRotation = m_pigeon.getRotation2d(); + if (Math.abs(robotYaw - currentRotation.getDegrees()) > 1) { + m_pigeon.reset(); + m_pigeon.setYawOffset(robotYaw); + } } } @@ -555,9 +558,20 @@ public void disabledPeriodic() { Pose2d startingPose = RobotConstants.kStartingPositions.get(startEnum).get(m_isRed.getAsBoolean()); m_pigeon.reset(); - m_pigeon.setYawOffset(startingPose.getRotation().getDegrees()); - - m_PoseEstimator.resetPose(startingPose); + m_pigeon.setYawOffset(-startingPose.getRotation().getDegrees()); + + m_limelightSubsystem.resetYawQue(); + + if (m_driveSubsystem.isPresent()) { + DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + driveSubsystem.resetPose(startingPose); + } else { + m_PoseEstimator.resetPosition( + m_pigeon.getRotation2d(), + 0, 0, + startingPose + ); + } System.out.println("Reset starting pose!"); } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index dd343b0..df7ba8e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -18,7 +18,6 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; import frc.robot.Constants.FieldConstants; -import frc.robot.LimelightHelpers.IMUData; import frc.robot.LimelightHelpers.PoseEstimate; import frc.robot.utils.LimitedQueue; @@ -34,7 +33,6 @@ public LimelightSubsystem(DifferentialDrivePoseEstimator poseEstimator) { public Double getRobotYaw() { if (m_YawQue.isEmpty()) { - System.out.println("No yaws to avrg! returning 0!"); return null; } @@ -97,33 +95,34 @@ private void updateOdometry() { // A Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. // TODO: Look into scaling these based off of the ambuguity and size of the tags. -- Kinda done (3/20/2025) - Vector errorVec; double stdDev = 0.5 + bestTargetAmbiguity; + Vector errorVec = VecBuilder.fill(stdDev, stdDev,9999999); // Trusting the yaw when disabled to get our robot orientation. - if (DriverStation.isDisabled()) { - errorVec = VecBuilder.fill(stdDev, stdDev,0); - } else { - errorVec = VecBuilder.fill(stdDev, stdDev,9999999); - } + // if (DriverStation.isDisabled()) { + // errorVec = VecBuilder.fill(stdDev, stdDev,0); + // } // Add the measurements to the pose estimator m_poseEstimator.setVisionMeasurementStdDevs(errorVec); m_poseEstimator.addVisionMeasurement( - poseEst.pose, + estimatedPose, poseEst.timestampSeconds ); + + m_YawQue.add(estimatedPose.getRotation().getDegrees()); } @Override public void periodic() { updateOdometry(); - - IMUData limelightData = LimelightHelpers.getIMUData("limelight"); - m_YawQue.add(limelightData.robotYaw); } public void setAllowJumps(boolean allowJumps) { m_allowJumps = allowJumps; } + + public void resetYawQue() { + m_YawQue.clear(); + } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java b/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java index b327c0e..1c0ed71 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/Pigeon.java @@ -49,7 +49,10 @@ public void reset() { public Rotation2d getRotation2d() { if (m_exists) { - return m_pigeon2.getRotation2d().rotateBy(new Rotation2d(m_yawOffset * (Math.PI/180))); + Rotation2d readRotation = m_pigeon2.getRotation2d(); + Rotation2d offset = new Rotation2d(m_yawOffset * (Math.PI/180)); + Rotation2d newRotation = readRotation.rotateBy(offset); + return newRotation; } else { dosntExist(); return Rotation2d.kZero; From 804e8152ddc8de38ebb84acad6774a997f8a5ae5 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Sat, 21 Mar 2026 15:27:16 -0500 Subject: [PATCH 140/161] Ensure lift motor control in test mode matches other similar, fixed speed motors --- 2026-Rebuilt/elastic-layout.json | 21 +++++++++--- .../robot/subsystems/LauncherSubsystem.java | 32 +++++++++++++------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 70d42ae..3479bc7 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -262,8 +262,8 @@ }, { "title": "Hub Distance", - "x": 192.0, - "y": 96.0, + "x": 0.0, + "y": 192.0, "width": 192.0, "height": 96.0, "type": "Text Display", @@ -395,7 +395,7 @@ { "title": "Set LiftSpeed", "x": 192.0, - "y": 0.0, + "y": 96.0, "width": 192.0, "height": 96.0, "type": "Text Display", @@ -408,7 +408,7 @@ }, { "title": "Fuel Present", - "x": 0.0, + "x": 192.0, "y": 192.0, "width": 192.0, "height": 64.0, @@ -743,6 +743,19 @@ "data_type": "double", "show_submit_button": true } + }, + { + "title": "Lift Run", + "x": 192.0, + "y": 0.0, + "width": 192.0, + "height": 96.0, + "type": "Toggle Switch", + "properties": { + "topic": "/SmartDashboard/Launcher TestLiftRun", + "period": 0.06, + "data_type": "boolean" + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 1091f5f..b9bd0b9 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -40,6 +40,8 @@ public class LauncherSubsystem extends SubsystemBase { private double m_MMAccel = LauncherConstants.kMotionMagicAcceleration; private double m_MMJerk = LauncherConstants.kMotionMagicJerk; + private double m_listSpeed = LauncherConstants.kLiftMotorSpeed; + private final DigitalInput m_Sensor = new DigitalInput(LauncherConstants.kUpperFuelSensorChannel); /* Be able to switch which control request to use based on a button press */ @@ -58,7 +60,8 @@ public LauncherSubsystem() throws Exception { // Test mode controls SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); - SmartDashboard.putNumber("Launcher TestLiftSpeed", 0.0 ); + SmartDashboard.putNumber("Launcher TestLiftSpeed", LauncherConstants.kLiftMotorSpeed); + SmartDashboard.putBoolean("Launcher TestLiftRun", false); SmartDashboard.putNumber("Launcher TestP", m_P ); SmartDashboard.putNumber("Launcher TestI", m_I ); SmartDashboard.putNumber("Launcher TestD", m_D ); @@ -178,7 +181,7 @@ public double getTargetSpeedrpm() // public void startLift() { - m_motorLift.set(LauncherConstants.kLiftMotorSpeed); + m_motorLift.set(m_listSpeed); m_liftRunning = true; } @@ -193,15 +196,11 @@ public void stopLift() public void setLiftSpeed(double speed) { - m_motorLift.set(speed); + m_listSpeed = speed; - if(speed == 0.0) - { - m_liftRunning = false; - } - else + if(m_liftRunning) { - m_liftRunning = true; + startLift(); } } @@ -262,9 +261,22 @@ public void testPeriodic() { double launcherrpm = SmartDashboard.getNumber("Launcher TestRPM", 0.0 ); double liftspeed = SmartDashboard.getNumber("Launcher TestLiftSpeed", 0.0 ); - + Boolean liftRun = SmartDashboard.getBoolean("Launcher TestLiftRun", false); + this.setLiftSpeed(liftspeed); this.setTargetSpeedrpm(launcherrpm); + + // Turn the intake on or off depending upon test control, only changing the state if the control actually changed. + if(liftRun) { + if(!m_liftRunning) { + this.startLift(); + } + } + else { + if(m_liftRunning) { + this.stopLift(); + } + } } @Override From bf35c79ed6fa5071358351d84500080f94a8cee2 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 23 Mar 2026 19:58:55 -0500 Subject: [PATCH 141/161] Added lift subsystem --- .../deploy/pathplanner/paths/DSA_A_Bump.path | 2 +- .../pathplanner/paths/DSA_B_PickupDepo.path | 2 +- .../pathplanner/paths/GatherCorral1.path | 2 +- .../pathplanner/paths/GatherCorralShoot.path | 2 +- .../pathplanner/paths/TestPointsGet.path | 2 +- .../src/main/deploy/pathplanner/settings.json | 6 +- .../src/main/java/frc/robot/Constants.java | 8 +- .../main/java/frc/robot/RobotContainer.java | 84 ++++++-------- .../robot/subsystems/LauncherSubsystem.java | 1 + .../frc/robot/subsystems/LiftSubsystem.java | 106 ++++++++++++++++++ 10 files changed, 150 insertions(+), 65 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path index f6fd8a4..0079ae4 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_A_Bump.path @@ -8,7 +8,7 @@ }, "prevControl": null, "nextControl": { - "x": 0.7904815091648096, + "x": 0.7904815091648099, "y": 7.273308359034138 }, "isLocked": false, diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path index 195afa5..4eac969 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/DSA_B_PickupDepo.path @@ -20,7 +20,7 @@ "y": 4.942 }, "prevControl": { - "x": 0.2814230769230787, + "x": 0.28142307692307866, "y": 5.337358974358976 }, "nextControl": null, diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path index 77f921b..73db8e3 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorral1.path @@ -20,7 +20,7 @@ "y": 5.883884615384615 }, "prevControl": { - "x": 0.49291105769230914, + "x": 0.4929110576923091, "y": 5.378784455128205 }, "nextControl": { diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path index 87f569e..b090433 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/GatherCorralShoot.path @@ -20,7 +20,7 @@ "y": 5.883884615384615 }, "prevControl": { - "x": 0.49291189105897826, + "x": 0.4929118910589782, "y": 5.378784362799069 }, "nextControl": { diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path b/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path index c07333a..4e93b16 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path +++ b/2026-Rebuilt/src/main/deploy/pathplanner/paths/TestPointsGet.path @@ -8,7 +8,7 @@ }, "prevControl": null, "nextControl": { - "x": -87.05500000000019, + "x": -87.0550000000002, "y": 4.000000000000012 }, "isLocked": false, diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json index 6469045..5430712 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json @@ -14,7 +14,7 @@ "defaultNominalVoltage": 12.0, "robotMass": 74.088, "robotMOI": 6.883, - "robotTrackwidth": 0.546, + "robotTrackwidth": 0.7874, "driveWheelRadius": 0.0508, "driveGearing": 5.143, "maxDriveSpeed": 5.45, @@ -31,7 +31,5 @@ "brModuleY": -0.273, "bumperOffsetX": 0.0, "bumperOffsetY": 0.0, - "robotFeatures": [ - "{\"name\":\"Rectangle\",\"type\":\"rounded_rect\",\"data\":{\"center\":{\"x\":0.0,\"y\":0.0},\"size\":{\"width\":0.2,\"length\":0.2},\"borderRadius\":0.05,\"strokeWidth\":0.02,\"filled\":false}}" - ] + "robotFeatures": [] } \ No newline at end of file diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 0ee67b0..0244198 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -67,9 +67,9 @@ public static class FieldConstants { public static class RobotConstants { public static final int kPigeon2CANID = 2; public static final boolean kDoPigeonWarn = true; - public static final double kPigeonYawOffset = -5.295877933502197; // degrees (-360, 360) - public static final double kPigeonPitchOffset = 0.7246352434158325; // degrees (-360, 360) - public static final double kPigeonRollOffset = -0.49318647384643555; // degrees (-360, 360) + public static final double kPigeonYawOffset = -90.00460052490234; // degrees (-360, 360) + public static final double kPigeonPitchOffset = 1.5642017126083374; // degrees (-360, 360) + public static final double kPigeonRollOffset = 89.49134826660156; // degrees (-360, 360) public static enum kStartingNames { DEPOT_SIDE, @@ -231,7 +231,7 @@ public static class LauncherConstants { // Frequency at which we send current launcher speed back to the driver station. public static final int kTicksPerUpdate = 10; - public static final int kTicksPerDistanceUpdate = 45; + public static final int kTicksPerDistanceUpdate = 12; public static final double kFixedTestSpeed = 3000.0; public static final double kFlywheelToleranceRPM = 100.0; diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index dbb0fca..178b5dc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -203,52 +203,16 @@ private void configureAutos() { m_autoChooser = new SendableChooser(); // Init Autos + m_autoChooser.setDefaultOption("NONE", new CancelDriveCommand(driveSubsystem)); m_autoChooser.addOption("[INDEV] Basic backup and shoot", new BackupAndShoot(driveSubsystem, m_PoseEstimator, m_isRed) ); - m_autoChooser.addOption("[INDEV] Backup and climb", - new BackupAndClimb(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) - ); - - m_autoChooser.addOption("[INDEV] Backup and shoot then climb", - new BackupAndShootThenClimb(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) - ); - m_autoChooser.addOption("[INDEV] Backup and collect from depot then shoot", new BackupCollectDepoAndShoot(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) ); - m_autoChooser.addOption("[INDEV] Depo Collect, shoot, then climb", - new DepoAndShootThenClimb(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) - ); - - // Test Autos - PathConstraints slowConstraints = new PathConstraints( - 1.0, - 1.0, - (1/2) * Math.PI, - (1/4) * Math.PI - ); - - // replace slowConstraints to m_contraints after testing. - m_autoChooser.addOption("[INDEV] Deadreckon Over Bump and Back", - new DeadreckonBumpAndBack(driveSubsystem, m_PoseEstimator, slowConstraints, m_isRed, m_pigeon) - ); - - m_autoChooser.addOption("[INDEV] Continous J into nutreal and back", - new OverBumpContinousJ(driveSubsystem, m_PoseEstimator, m_isRed) - ); - - m_autoChooser.addOption("[TEST] Forward Test", - new DeadreckonDistance(driveSubsystem, 2.5, 2.0) - ); - - m_autoChooser.addOption("[TEST] Backup Test", - new DeadreckonDistance(driveSubsystem, 2.5, -2.0) - ); - // Warm up Pathfinder CommandScheduler.getInstance().schedule( PathfindingCommand.warmupCommand() @@ -325,25 +289,32 @@ private void configureBindings() { new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, m_isRed) ); - // Range launcher, turn to face hub and shoot all fuel. - if (m_launcherSubsystem.isPresent() & m_indexerBulkSubsystem.isPresent()) - { + // Range launcher, turn to face hub and shoot all fuel + if (m_launcherSubsystem.isPresent()) { LauncherSubsystem launcher = m_launcherSubsystem.get(); - IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); - - // This is intended to keep shooting until the button is released. - m_driverController.y().whileTrue(new RotateAndShootCommand(driveSubsystem, - launcher, - indexer, - m_PoseEstimator, - m_isRed, - LauncherConstants.kFlywheelToleranceRPM)); + m_operatorController.y().onTrue(new TrackHubFlywheelCommand(launcher, m_PoseEstimator, m_isRed)); + m_operatorController.a().onTrue(new StopLauncherCommand(launcher)); + m_operatorController.x().onTrue(new StartLiftCommand(launcher)); + m_operatorController.b().onTrue(new StopLiftCommand(launcher)); + + if (m_indexerBulkSubsystem.isPresent()) + { + IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); + + // This is intended to keep shooting until the button is released. + m_driverController.y().whileTrue(new RotateAndShootCommand(driveSubsystem, + launcher, + indexer, + m_PoseEstimator, + m_isRed, + LauncherConstants.kFlywheelToleranceRPM)); + } } // Travel to corner and shoot - m_driverController.x().onTrue( - new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) - ); + // m_driverController.x().onTrue( + // new TravelToCornerAndShoot(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) + // ); // TEST COMMAND FOR TESTING ACCURACY AFTER BUMP! m_driverController.leftBumper().onTrue( @@ -416,6 +387,8 @@ public void InitSmartDashboard() { SmartDashboard.putNumber("Pitch Rate", 0.0); SmartDashboard.putNumber("Roll Rate", 0.0); + SmartDashboard.putNumber("Auto Wait Time", 0.0); + SmartDashboard.putBoolean("Enabled", DriverStation.isEnabled()); // SmartDashboard.putBoolean("Pidgeon Accurate", m_pigeon.isAccurate()); @@ -529,6 +502,13 @@ public void disabledInit() { disabledTick = 0; LimelightHelpers.SetIMUMode("limelight", 3); m_limelightSubsystem.setAllowJumps(true); + + if(m_launcherSubsystem.isPresent()) + { + LauncherSubsystem launcher = m_launcherSubsystem.get(); + launcher.stopLift(); + launcher.setTargetSpeedrpm(0.0); + } } // Gets called every disabled tick. diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index b9bd0b9..541af75 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -18,6 +18,7 @@ import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.*; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.SubsystemBase; import edu.wpi.first.wpilibj.DigitalInput; import frc.robot.Constants.LauncherConstants; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java new file mode 100644 index 0000000..ca4c0c9 --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java @@ -0,0 +1,106 @@ +// +// Subsystem offering low level control of the launcher flywheel and +// fuel lift mechanisms. +// + +// 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.subsystems; + +import com.ctre.phoenix6.hardware.TalonFX; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import edu.wpi.first.wpilibj2.command.SubsystemBase; +import frc.robot.Constants.LauncherConstants; + +public class LiftSubsystem extends SubsystemBase { + private boolean m_liftRunning = false; + + private TalonFX m_motorLift; + private double m_liftSpeed = LauncherConstants.kLiftMotorSpeed; + + /** Creates a new LiftSubsystem. + * @throws Exception */ + public LiftSubsystem() throws Exception { + + // Test mode controls + SmartDashboard.putNumber("Launcher TestLiftSpeed", LauncherConstants.kLiftMotorSpeed); + SmartDashboard.putBoolean("Launcher TestLiftRun", false); + + + m_motorLift = new TalonFX(LauncherConstants.kLauncherLiftMotorCANID); + + // Check that the launcher motors exist and throw an exception if they don't. + if(!m_motorLift.isConnected()) + { + throw new Exception("Lift motor is not present!"); + } + } + + // + // Start the lift mechanism motor. + // + public void startLift() + { + m_motorLift.set(m_liftSpeed); + m_liftRunning = true; + } + + // + // Stop the lift mechanism motor. + // + public void stopLift() + { + m_motorLift.set(0.0); + m_liftRunning = false; + } + + public void setLiftSpeed(double speed) + { + m_liftSpeed = speed; + + if(m_liftRunning) + { + startLift(); + } + } + + // + // Determine whether or not the lift motor is running. + public boolean isLiftMotorStarted() + { + return m_liftRunning; + } + + @Override + public void periodic() { + // This method will be called once per scheduler run + } + + public void testPeriodic() { + + double liftspeed = SmartDashboard.getNumber("Launcher TestLiftSpeed", 0.0 ); + Boolean liftRun = SmartDashboard.getBoolean("Launcher TestLiftRun", false); + + this.setLiftSpeed(liftspeed); + + // Turn the intake on or off depending upon test control, only changing the state if the control actually changed. + if(liftRun) { + if(!m_liftRunning) { + this.startLift(); + } + } + else { + if(m_liftRunning) { + this.stopLift(); + } + } + } + + @Override + public void simulationPeriodic() { + // This method will be called once per scheduler run during simulation + + } +} From cb22808ba475ac87cfa8a07fc4515959651a72bf Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Mon, 23 Mar 2026 20:10:43 -0500 Subject: [PATCH 142/161] Update lift-related commands after Lift/Launcher subsystem split --- .../robot/commands/RangeLauncherCommand.java | 2 +- .../robot/commands/StartFlywheelCommand.java | 2 +- .../frc/robot/commands/StartLiftCommand.java | 8 +-- .../frc/robot/commands/StartShootCommand.java | 14 ++--- .../robot/commands/StopLauncherCommand.java | 16 +++-- .../frc/robot/commands/StopLiftCommand.java | 6 +- .../frc/robot/commands/StopShootCommand.java | 12 ++-- .../robot/subsystems/LauncherSubsystem.java | 60 +------------------ 8 files changed, 33 insertions(+), 87 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java index cb201fe..3a1b8df 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RangeLauncherCommand.java @@ -11,7 +11,7 @@ /** * - * Stop the launcher lift motor and spin down the flywheel. + * Stop the launcher motor and spin down the flywheel. * **/ public class RangeLauncherCommand extends Command { diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java index 25fa0ac..e80559e 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartFlywheelCommand.java @@ -5,7 +5,7 @@ /** * - * Stop the launcher lift motor and spin down the flywheel. + * Start the launcher flywheel and get it up to the target speed. * **/ public class StartFlywheelCommand extends Command { diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java index 0d99ab8..f439a66 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartLiftCommand.java @@ -1,22 +1,22 @@ package frc.robot.commands; import edu.wpi.first.wpilibj2.command.Command; -import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; /** * - * Stop the launcher lift motor and spin down the flywheel. + * Start the launcher lift motor. * **/ public class StartLiftCommand extends Command { - private final LauncherSubsystem m_subsystem; + private final LiftSubsystem m_subsystem; /** * Creates a new StartLiftCommand. * * @param subsystem The subsystem used by this command. */ - public StartLiftCommand(LauncherSubsystem subsystem) + public StartLiftCommand(LiftSubsystem subsystem) { m_subsystem = subsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java index 256bbc6..b84be80 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StartShootCommand.java @@ -2,15 +2,15 @@ import edu.wpi.first.wpilibj2.command.Command; import frc.robot.subsystems.IndexerBulkSubsystem; -import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; /** * - * Start shooting fuel by starting the launcher lift motor and both motors in the indexer/bulk subsystem. + * Start shooting fuel by starting the lift motor and both motors in the indexer/bulk subsystem. * **/ public class StartShootCommand extends Command { - private final LauncherSubsystem m_Launcher; + private final LiftSubsystem m_Lift; private final IndexerBulkSubsystem m_IndexerBulk; /** @@ -18,13 +18,13 @@ public class StartShootCommand extends Command { * * @param subsystem The subsystem used by this command. */ - public StartShootCommand(LauncherSubsystem launcher, IndexerBulkSubsystem indexerbulk) + public StartShootCommand(LiftSubsystem lift, IndexerBulkSubsystem indexerbulk) { - m_Launcher = launcher; + m_Lift = lift; m_IndexerBulk = indexerbulk; // Use addRequirements() here to declare subsystem dependencies. - addRequirements(m_Launcher); + addRequirements(m_Lift); addRequirements(m_IndexerBulk); } @@ -33,7 +33,7 @@ public StartShootCommand(LauncherSubsystem launcher, IndexerBulkSubsystem indexe public void initialize() { m_IndexerBulk.startBulkTransfer(); m_IndexerBulk.startIndexer(); - m_Launcher.startLift(); + m_Lift.startLift(); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java index b68bbf1..b1d587c 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java @@ -1,6 +1,7 @@ package frc.robot.commands; import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LiftSubsystem; import frc.robot.subsystems.LauncherSubsystem; /** @@ -9,26 +10,29 @@ * **/ public class StopLauncherCommand extends Command { - private final LauncherSubsystem m_subsystem; + private final LiftSubsystem m_lift; + private final LauncherSubsystem m_launcher; /** * Creates a new StopLauncherCommand. * * @param subsystem The subsystem used by this command. */ - public StopLauncherCommand(LauncherSubsystem subsystem) + public StopLauncherCommand(LauncherSubsystem launcher, LiftSubsystem lift) { - m_subsystem = subsystem; + m_lift = lift; + m_launcher = launcher. // Use addRequirements() here to declare subsystem dependencies. - addRequirements(m_subsystem); + addRequirements(m_lift); + addRequirements(m_launcher); } // Called when the command is initially scheduled. @Override public void initialize() { - m_subsystem.stopLift(); - m_subsystem.setTargetSpeedrpm(0.0); + m_lift.stopLift(); + m_launcher.setTargetSpeedrpm(0.0); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java index 003b5e1..8a1b875 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLiftCommand.java @@ -1,7 +1,7 @@ package frc.robot.commands; import edu.wpi.first.wpilibj2.command.Command; -import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; /** * @@ -9,14 +9,14 @@ * **/ public class StopLiftCommand extends Command { - private final LauncherSubsystem m_subsystem; + private final LiftSubsystem m_subsystem; /** * Creates a new StopLiftCommand. * * @param subsystem The subsystem used by this command. */ - public StopLiftCommand(LauncherSubsystem subsystem) + public StopLiftCommand(LiftSubsystem subsystem) { m_subsystem = subsystem; diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java index f7ab030..610d807 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopShootCommand.java @@ -2,7 +2,7 @@ import edu.wpi.first.wpilibj2.command.Command; import frc.robot.subsystems.IndexerBulkSubsystem; -import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; /** * @@ -10,7 +10,7 @@ * **/ public class StopShootCommand extends Command { - private final LauncherSubsystem m_Launcher; + private final LiftSubsystem m_Lift; private final IndexerBulkSubsystem m_IndexerBulk; /** @@ -18,13 +18,13 @@ public class StopShootCommand extends Command { * * @param subsystem The subsystem used by this command. */ - public StopShootCommand(LauncherSubsystem launcher, IndexerBulkSubsystem indexerbulk) + public StopShootCommand(LiftSubsystem lift, IndexerBulkSubsystem indexerbulk) { - m_Launcher = launcher; + m_Lift = lift; m_IndexerBulk = indexerbulk; // Use addRequirements() here to declare subsystem dependencies. - addRequirements(m_Launcher); + addRequirements(m_Lift); addRequirements(m_IndexerBulk); } @@ -33,7 +33,7 @@ public StopShootCommand(LauncherSubsystem launcher, IndexerBulkSubsystem indexer public void initialize() { m_IndexerBulk.stopBulkTransfer(); m_IndexerBulk.stopIndexer(); - m_Launcher.stopLift(); + m_Lift.stopLift(); } // Called every time the scheduler runs while the command is scheduled. diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 541af75..2876e71 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -25,14 +25,12 @@ public class LauncherSubsystem extends SubsystemBase { private double m_targetSpeedrpm = 0.0; - private boolean m_liftRunning = false; private boolean m_HasFuel = false; private int m_tickCount = 0; private boolean m_configValid = false; private TalonFX m_motorLeader; private TalonFX m_motorFollower; - private TalonFX m_motorLift; private TalonFXConfiguration m_MotorConfigs = new TalonFXConfiguration(); private double m_P = LauncherConstants.kP; @@ -41,8 +39,6 @@ public class LauncherSubsystem extends SubsystemBase { private double m_MMAccel = LauncherConstants.kMotionMagicAcceleration; private double m_MMJerk = LauncherConstants.kMotionMagicJerk; - private double m_listSpeed = LauncherConstants.kLiftMotorSpeed; - private final DigitalInput m_Sensor = new DigitalInput(LauncherConstants.kUpperFuelSensorChannel); /* Be able to switch which control request to use based on a button press */ @@ -61,20 +57,17 @@ public LauncherSubsystem() throws Exception { // Test mode controls SmartDashboard.putNumber("Launcher TestRPM", 0.0 ); - SmartDashboard.putNumber("Launcher TestLiftSpeed", LauncherConstants.kLiftMotorSpeed); - SmartDashboard.putBoolean("Launcher TestLiftRun", false); SmartDashboard.putNumber("Launcher TestP", m_P ); SmartDashboard.putNumber("Launcher TestI", m_I ); SmartDashboard.putNumber("Launcher TestD", m_D ); SmartDashboard.putNumber("Launcher TestMMAccel", m_MMAccel ); SmartDashboard.putNumber("Launcher TestMMJerk", m_MMJerk ); - m_motorLift = new TalonFX(LauncherConstants.kLauncherLiftMotorCANID); m_motorLeader = new TalonFX(LauncherConstants.kLauncherFlywheelMotor1CANID); m_motorFollower = new TalonFX(LauncherConstants.kLauncherFlywheelMotor2CANID); // Check that the launcher motors exist and throw an exception if they don't. - if(!m_motorLeader.isConnected() || !m_motorFollower.isConnected() || !m_motorLift.isConnected()) + if(!m_motorLeader.isConnected() || !m_motorFollower.isConnected()) { throw new Exception("At least one launcher motor is not present!"); } @@ -177,41 +170,6 @@ public double getTargetSpeedrpm() return m_targetSpeedrpm; } - // - // Start the lift mechanism motor. - // - public void startLift() - { - m_motorLift.set(m_listSpeed); - m_liftRunning = true; - } - - // - // Stop the lift mechanism motor. - // - public void stopLift() - { - m_motorLift.set(0.0); - m_liftRunning = false; - } - - public void setLiftSpeed(double speed) - { - m_listSpeed = speed; - - if(m_liftRunning) - { - startLift(); - } - } - - // - // Determine whether or not the lift motor is running. - public boolean isLiftMotorStarted() - { - return m_liftRunning; - } - // // Determine whether or not a fuel is in position beneath the launcher // entrance. @@ -261,23 +219,7 @@ public void testPeriodic() { } double launcherrpm = SmartDashboard.getNumber("Launcher TestRPM", 0.0 ); - double liftspeed = SmartDashboard.getNumber("Launcher TestLiftSpeed", 0.0 ); - Boolean liftRun = SmartDashboard.getBoolean("Launcher TestLiftRun", false); - - this.setLiftSpeed(liftspeed); this.setTargetSpeedrpm(launcherrpm); - - // Turn the intake on or off depending upon test control, only changing the state if the control actually changed. - if(liftRun) { - if(!m_liftRunning) { - this.startLift(); - } - } - else { - if(m_liftRunning) { - this.stopLift(); - } - } } @Override From bb2621e53ab261fa34aa3afc524bb228ba244a48 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 23 Mar 2026 20:16:40 -0500 Subject: [PATCH 143/161] Fixed the broken code!! --- .../main/java/frc/robot/RobotContainer.java | 56 +++++++++++-------- .../robot/commands/RotateAndShootCommand.java | 10 ++-- .../robot/commands/StopLauncherCommand.java | 8 +-- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 178b5dc..5ff873d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -34,6 +34,7 @@ import frc.robot.factorys.TalonFXFactory; import frc.robot.subsystems.DriveSubsystem; import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; import frc.robot.subsystems.IndexerBulkSubsystem; import frc.robot.subsystems.IntakeSubsystem; import frc.robot.subsystems.ClimbL1Subsystem; @@ -43,15 +44,8 @@ import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; -import frc.robot.commands.autoCommands.BackupAndClimb; import frc.robot.commands.autoCommands.BackupAndShoot; -import frc.robot.commands.autoCommands.BackupAndShootThenClimb; import frc.robot.commands.autoCommands.BackupCollectDepoAndShoot; -import frc.robot.commands.autoCommands.DeadreckonBumpAndBack; -import frc.robot.commands.autoCommands.DeadreckonDistance; -import frc.robot.commands.autoCommands.DepoAndShootThenClimb; -import frc.robot.commands.autoCommands.OverBumpContinousJ; -import frc.robot.commands.autoCommands.TravelToCornerAndShoot; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.utils.LauncherUtils; import frc.robot.Constants.*; @@ -72,6 +66,7 @@ public class RobotContainer { private Optional m_climbL1Subsystem; private final Optional m_indexerBulkSubsystem; private final Optional m_launcherSubsystem; + private final Optional m_liftSubsystem; private final Optional m_pneumaticHub; private final LimelightSubsystem m_limelightSubsystem; @@ -144,6 +139,7 @@ public RobotContainer() { m_limelightSubsystem = new LimelightSubsystem(m_PoseEstimator); m_launcherSubsystem = getSubsystem(LauncherSubsystem.class); m_indexerBulkSubsystem = getSubsystem(IndexerBulkSubsystem.class); + m_liftSubsystem = getSubsystem(LiftSubsystem.class); // Init pneumatics system and subsystems that rely upon it. m_pneumaticHub = getSubsystem(PneumaticHubWrapper.class); @@ -266,6 +262,7 @@ private void configureBindings() { SmartDashboard.putBoolean("Intake Subsystem", m_intakeSubsystem.isPresent()); SmartDashboard.putBoolean("ClimbL1 Subsystem", m_climbL1Subsystem.isPresent()); SmartDashboard.putBoolean("Launcher Subsystem", m_launcherSubsystem.isPresent()); + SmartDashboard.putBoolean("Lift Subsystem", m_liftSubsystem.isPresent()); SmartDashboard.putBoolean("IndexerBulk Subsystem", m_indexerBulkSubsystem.isPresent()); SmartDashboard.putBoolean("Pneumatic Subsystem", m_pneumaticHub.isPresent()); @@ -293,21 +290,30 @@ private void configureBindings() { if (m_launcherSubsystem.isPresent()) { LauncherSubsystem launcher = m_launcherSubsystem.get(); m_operatorController.y().onTrue(new TrackHubFlywheelCommand(launcher, m_PoseEstimator, m_isRed)); - m_operatorController.a().onTrue(new StopLauncherCommand(launcher)); - m_operatorController.x().onTrue(new StartLiftCommand(launcher)); - m_operatorController.b().onTrue(new StopLiftCommand(launcher)); - - if (m_indexerBulkSubsystem.isPresent()) - { - IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); - - // This is intended to keep shooting until the button is released. - m_driverController.y().whileTrue(new RotateAndShootCommand(driveSubsystem, - launcher, - indexer, - m_PoseEstimator, - m_isRed, - LauncherConstants.kFlywheelToleranceRPM)); + + if (m_liftSubsystem.isPresent()) { + LiftSubsystem lift = m_liftSubsystem.get(); + + m_operatorController.a().onTrue(new StopLauncherCommand(launcher).alongWith(new StopLiftCommand(lift))); + + m_operatorController.x().onTrue(new StartLiftCommand(lift)); + m_operatorController.b().onTrue(new StopLiftCommand(lift)); + + if (m_indexerBulkSubsystem.isPresent()) + { + IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); + + // This is intended to keep shooting until the button is released. + m_driverController.y().whileTrue(new RotateAndShootCommand(driveSubsystem, + launcher, + lift, + indexer, + m_PoseEstimator, + m_isRed, + LauncherConstants.kFlywheelToleranceRPM)); + } + } else { + m_operatorController.a().onTrue(new StopLauncherCommand(launcher)); } } @@ -503,10 +509,14 @@ public void disabledInit() { LimelightHelpers.SetIMUMode("limelight", 3); m_limelightSubsystem.setAllowJumps(true); + if (m_liftSubsystem.isPresent()) { + LiftSubsystem lift = m_liftSubsystem.get(); + lift.stopLift(); + } + if(m_launcherSubsystem.isPresent()) { LauncherSubsystem launcher = m_launcherSubsystem.get(); - launcher.stopLift(); launcher.setTargetSpeedrpm(0.0); } } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java index c7fdc61..07b8be8 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java @@ -6,17 +6,16 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; -import frc.robot.commands.AimAtHub; -import frc.robot.commands.RangeLauncherCommand; -import frc.robot.commands.StartShootCommand; import frc.robot.subsystems.DriveSubsystem; import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; import frc.robot.subsystems.IndexerBulkSubsystem; /** An example command that uses an example subsystem. */ public class RotateAndShootCommand extends Command { private final DriveSubsystem m_driveSubsystem; private final LauncherSubsystem m_launcherSubsystem; + private final LiftSubsystem m_liftSubsystem; private final IndexerBulkSubsystem m_indexerSubsystem; private final DifferentialDrivePoseEstimator m_poseEstimator; private final BooleanSupplier m_isRed; @@ -29,10 +28,11 @@ public class RotateAndShootCommand extends Command { * @param targetPose The pose the robot will make a point to go to. * @param constraints The constraints the robot will follow while following the path. */ - public RotateAndShootCommand(DriveSubsystem driveSubsystem, LauncherSubsystem launcherSubsystem, IndexerBulkSubsystem indexerSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, double flywheelTolerance) + public RotateAndShootCommand(DriveSubsystem driveSubsystem, LauncherSubsystem launcherSubsystem, LiftSubsystem liftSubsystem, IndexerBulkSubsystem indexerSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, double flywheelTolerance) { m_driveSubsystem = driveSubsystem; m_launcherSubsystem = launcherSubsystem; + m_liftSubsystem = liftSubsystem; m_indexerSubsystem = indexerSubsystem; m_poseEstimator = poseEstimator; m_flywheelTolerance = flywheelTolerance; @@ -45,7 +45,7 @@ public void initialize() { // This should do the process to make the launcher get up to speed Command setLauncherSpeedCommand = new RangeLauncherCommand(m_launcherSubsystem, m_poseEstimator, m_flywheelTolerance, m_isRed); Command aimAtHubCommand = new AimAtHub(m_driveSubsystem, m_poseEstimator, 4.0, m_isRed); - Command startShootCommand = new StartShootCommand(m_launcherSubsystem, m_indexerSubsystem); + Command startShootCommand = new StartShootCommand(m_liftSubsystem, m_indexerSubsystem); ParallelCommandGroup TurnAndSet = new ParallelCommandGroup(setLauncherSpeedCommand, aimAtHubCommand); diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java index b1d587c..0e04e34 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/StopLauncherCommand.java @@ -10,7 +10,6 @@ * **/ public class StopLauncherCommand extends Command { - private final LiftSubsystem m_lift; private final LauncherSubsystem m_launcher; /** @@ -18,20 +17,17 @@ public class StopLauncherCommand extends Command { * * @param subsystem The subsystem used by this command. */ - public StopLauncherCommand(LauncherSubsystem launcher, LiftSubsystem lift) + public StopLauncherCommand(LauncherSubsystem launcher) { - m_lift = lift; - m_launcher = launcher. + m_launcher = launcher; // Use addRequirements() here to declare subsystem dependencies. - addRequirements(m_lift); addRequirements(m_launcher); } // Called when the command is initially scheduled. @Override public void initialize() { - m_lift.stopLift(); m_launcher.setTargetSpeedrpm(0.0); } From 4529f0f345f6a4d7ee65b1c87983f5cd356db637 Mon Sep 17 00:00:00 2001 From: Dave Wilson Date: Mon, 23 Mar 2026 20:22:51 -0500 Subject: [PATCH 144/161] Fixed up test mode following split of Launcher and Lift subsystems --- 2026-Rebuilt/elastic-layout.json | 37 ++++++++++++++----- .../frc/robot/subsystems/LiftSubsystem.java | 8 ++-- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 3479bc7..5df567e 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -393,14 +393,14 @@ } }, { - "title": "Set LiftSpeed", - "x": 192.0, + "title": "Lift Speed", + "x": 256.0, "y": 96.0, - "width": 192.0, + "width": 128.0, "height": 96.0, "type": "Text Display", "properties": { - "topic": "/SmartDashboard/Launcher TestLiftSpeed", + "topic": "/SmartDashboard/Lift TestLiftSpeed", "period": 0.06, "data_type": "double", "show_submit_button": true @@ -408,8 +408,8 @@ }, { "title": "Fuel Present", - "x": 192.0, - "y": 192.0, + "x": 0.0, + "y": 288.0, "width": 192.0, "height": 64.0, "type": "Boolean Box", @@ -495,7 +495,7 @@ "title": "Subsystem", "x": 0.0, "y": 352.0, - "width": 384.0, + "width": 192.0, "height": 64.0, "type": "Boolean Box", "properties": { @@ -746,16 +746,33 @@ }, { "title": "Lift Run", - "x": 192.0, + "x": 256.0, "y": 0.0, - "width": 192.0, + "width": 128.0, "height": 96.0, "type": "Toggle Switch", "properties": { - "topic": "/SmartDashboard/Launcher TestLiftRun", + "topic": "/SmartDashboard/Lift TestLiftRun", "period": 0.06, "data_type": "boolean" } + }, + { + "title": "Subsystem", + "x": 256.0, + "y": 352.0, + "width": 128.0, + "height": 64.0, + "type": "Boolean Box", + "properties": { + "topic": "/SmartDashboard/Lift Subsystem", + "period": 0.06, + "data_type": "boolean", + "true_color": 4283215696, + "false_color": 4294198070, + "true_icon": "None", + "false_icon": "None" + } } ] } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java index ca4c0c9..898dfd5 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java @@ -25,8 +25,8 @@ public class LiftSubsystem extends SubsystemBase { public LiftSubsystem() throws Exception { // Test mode controls - SmartDashboard.putNumber("Launcher TestLiftSpeed", LauncherConstants.kLiftMotorSpeed); - SmartDashboard.putBoolean("Launcher TestLiftRun", false); + SmartDashboard.putNumber("Lift TestLiftSpeed", LauncherConstants.kLiftMotorSpeed); + SmartDashboard.putBoolean("Lift TestLiftRun", false); m_motorLift = new TalonFX(LauncherConstants.kLauncherLiftMotorCANID); @@ -80,8 +80,8 @@ public void periodic() { public void testPeriodic() { - double liftspeed = SmartDashboard.getNumber("Launcher TestLiftSpeed", 0.0 ); - Boolean liftRun = SmartDashboard.getBoolean("Launcher TestLiftRun", false); + double liftspeed = SmartDashboard.getNumber("Lift TestLiftSpeed", 0.0 ); + Boolean liftRun = SmartDashboard.getBoolean("Lift TestLiftRun", false); this.setLiftSpeed(liftspeed); From db3af5acc819705d3e40df58e1b512e97512a85d Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Mon, 23 Mar 2026 20:59:43 -0500 Subject: [PATCH 145/161] Updated BackupAndShoot to have launcher and lift --- .../src/main/deploy/pathplanner/settings.json | 2 +- .../src/main/java/frc/robot/Constants.java | 7 +-- .../main/java/frc/robot/RobotContainer.java | 11 ++--- .../commands/autoCommands/BackupAndShoot.java | 47 +++++++++++++------ 4 files changed, 42 insertions(+), 25 deletions(-) diff --git a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json index 5430712..8fa1e36 100644 --- a/2026-Rebuilt/src/main/deploy/pathplanner/settings.json +++ b/2026-Rebuilt/src/main/deploy/pathplanner/settings.json @@ -14,7 +14,7 @@ "defaultNominalVoltage": 12.0, "robotMass": 74.088, "robotMOI": 6.883, - "robotTrackwidth": 0.7874, + "robotTrackwidth": 0.787, "driveWheelRadius": 0.0508, "driveGearing": 5.143, "maxDriveSpeed": 5.45, diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 0244198..942449f 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -172,9 +172,10 @@ public static class DrivetrainConstants { public static final double kDrivetrainGearRatio = 0.2; public static final double kWheelRadiusMeters = (4.0 / 2.0) * 0.0254; // Four Inch Wheels public static final double kWheelCircumference = 2 * Math.PI * DrivetrainConstants.kWheelRadiusMeters; - public static final double kWidthMeters = 0.760; - public static final double kLengthMeters = 0.760; - public static final double kTrackWidthMeters = 29.0 * 0.0254;//0.74; + public static final double kBumpersMeters = 0.0889; + public static final double kWidthMeters = 0.8636-kBumpersMeters; // width w/ bumpers - bumpers + public static final double kLengthMeters = 0.8636-kBumpersMeters; + public static final double kTrackWidthMeters = kLengthMeters;//29.0 * 0.0254;//0.74; // SmartDashboard update frequency for drive subsystem state in 20ms counts. public static final int kTicksPerUpdate = 5; diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 5ff873d..65b62ef 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -193,16 +193,18 @@ private static Optional getSubsystem(Class subsystemClass) { // Init Autos (/home/lvuser/deploy/pathplanner/autos) private void configureAutos() { - if (m_driveSubsystem.isPresent()) { + if (m_driveSubsystem.isPresent() && m_launcherSubsystem.isPresent() && m_liftSubsystem.isPresent()) { // Init Needed values DriveSubsystem driveSubsystem = m_driveSubsystem.get(); + LauncherSubsystem launcherSubsystem = m_launcherSubsystem.get(); + LiftSubsystem liftSubsystem = m_liftSubsystem.get(); m_autoChooser = new SendableChooser(); // Init Autos m_autoChooser.setDefaultOption("NONE", new CancelDriveCommand(driveSubsystem)); m_autoChooser.addOption("[INDEV] Basic backup and shoot", - new BackupAndShoot(driveSubsystem, m_PoseEstimator, m_isRed) + new BackupAndShoot(driveSubsystem, launcherSubsystem, liftSubsystem, m_PoseEstimator, m_isRed) ); m_autoChooser.addOption("[INDEV] Backup and collect from depot then shoot", @@ -278,12 +280,9 @@ private void configureBindings() { // Cancel All Drive Commands m_driverController.back().onTrue(new CancelDriveCommand(driveSubsystem)); - // Turn left to produce stall error. - m_driverController.b().onTrue(new TurnLeftTest(driveSubsystem)); - // Aim to Hub m_driverController.rightBumper().onTrue( - new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, m_isRed) + new AimAtHub(driveSubsystem, m_PoseEstimator, 3.0, m_isRed) ); // Range launcher, turn to face hub and shoot all fuel diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java index 31e7ac9..88967b0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java @@ -6,12 +6,20 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.InstantCommand; -import frc.robot.commands.AimAtHub; +import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; +import edu.wpi.first.wpilibj2.command.ParallelRaceGroup; +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.subsystems.DriveSubsystem; +import frc.robot.subsystems.LauncherSubsystem; +import frc.robot.subsystems.LiftSubsystem; +import frc.robot.commands.*; +import frc.robot.Constants.*; /** An example command that uses an example subsystem. */ public class BackupAndShoot extends Command { private final DriveSubsystem m_driveSubsystem; + private final LauncherSubsystem m_launcherSubsystem; + private final LiftSubsystem m_liftSubsystem; private final DifferentialDrivePoseEstimator m_poseEstimator; private final BooleanSupplier m_isRed; @@ -22,36 +30,45 @@ public class BackupAndShoot extends Command { * @param targetPose The pose the robot will make a point to go to. * @param constraints The constraints the robot will follow while following the path. */ - public BackupAndShoot(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) + public BackupAndShoot(DriveSubsystem driveSubsystem, LauncherSubsystem launcherSubsystem, LiftSubsystem liftSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) { m_driveSubsystem = driveSubsystem; + m_launcherSubsystem = launcherSubsystem; + m_liftSubsystem = liftSubsystem; m_poseEstimator = poseEstimator; m_isRed = isRed; } // Called when the command is initially scheduled. - // TODO: Implement Launcher! + // TODO: Indexer Implemntation needed @Override public void initialize() { // This should do the process to make the launcher get up to speed - Command speedUpLauncher = new InstantCommand(() -> System.out.println("Speeding up launcher!")); + Command rangeLauncher = new RangeLauncherCommand(m_launcherSubsystem, m_poseEstimator, LauncherConstants.kFlywheelToleranceRPM, m_isRed); + Command keepSpeedCommand1 = new TrackHubFlywheelCommand(m_launcherSubsystem, m_poseEstimator, m_isRed); + Command keepSpeedCommand2 = new TrackHubFlywheelCommand(m_launcherSubsystem, m_poseEstimator, m_isRed); Command deadreckonBackward = new DeadreckonDistance(m_driveSubsystem, 1.5, -2.0); Command aimCommand = new AimAtHub(m_driveSubsystem, m_poseEstimator, 4.0, m_isRed); - // This command should only end once the launcher is up to speed. - Command waitForLauncherReady = new InstantCommand(() -> System.out.println("Waiting for launcher ready!")); + Command startLift = new StartLiftCommand(m_liftSubsystem); - // This command should only end once it is determined for the launcher ot be empty. - Command fireLauncher = new InstantCommand(() -> System.out.println("Launching game peices!")); - - CommandScheduler.getInstance().schedule( - speedUpLauncher - .andThen(deadreckonBackward) - .andThen(aimCommand) - .andThen(waitForLauncherReady) - .andThen(fireLauncher) + SequentialCommandGroup fullComboCommand = new SequentialCommandGroup( + new ParallelRaceGroup( + new ParallelCommandGroup( + rangeLauncher, + keepSpeedCommand1 + ), + new SequentialCommandGroup( + deadreckonBackward, + aimCommand, + startLift // Replace with the combo launcher, indexer, mover + ) + ), + keepSpeedCommand2 ); + + CommandScheduler.getInstance().schedule(fullComboCommand); } // Called every time the scheduler runs while the command is scheduled. From 0af3243b154e4d101c0a559c80d33dc1c7af3212 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 24 Mar 2026 18:27:30 -0500 Subject: [PATCH 146/161] BackupAndShoot is ready for testing --- .../main/java/frc/robot/RobotContainer.java | 15 +++- .../commands/WaitForFlywheelAtTarget.java | 50 +++++++++++ .../commands/autoCommands/BackupAndShoot.java | 88 ------------------- 3 files changed, 62 insertions(+), 91 deletions(-) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/WaitForFlywheelAtTarget.java delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 65b62ef..911104d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -27,6 +27,8 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.InstantCommand; +import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; +import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import edu.wpi.first.wpilibj2.command.button.Trigger; import edu.wpi.first.wpilibj.PneumaticHub; @@ -44,8 +46,8 @@ import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; import frc.robot.commands.DriveCommands.TurnLeftTest; -import frc.robot.commands.autoCommands.BackupAndShoot; import frc.robot.commands.autoCommands.BackupCollectDepoAndShoot; +import frc.robot.commands.autoCommands.DeadreckonDistance; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.utils.LauncherUtils; import frc.robot.Constants.*; @@ -202,9 +204,16 @@ private void configureAutos() { // Init Autos m_autoChooser.setDefaultOption("NONE", new CancelDriveCommand(driveSubsystem)); - m_autoChooser.addOption("[INDEV] Basic backup and shoot", - new BackupAndShoot(driveSubsystem, launcherSubsystem, liftSubsystem, m_PoseEstimator, m_isRed) + new ParallelCommandGroup( + new TrackHubFlywheelCommand(launcherSubsystem, m_PoseEstimator, m_isRed), + new SequentialCommandGroup( + new DeadreckonDistance(driveSubsystem, 1.5, -2.0), + new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, m_isRed), + new WaitForFlywheelAtTarget(launcherSubsystem, LauncherConstants.kFlywheelToleranceRPM), + new StartLiftCommand(liftSubsystem) // Replace with the combo launcher, indexer, mover command later + ) + ) ); m_autoChooser.addOption("[INDEV] Backup and collect from depot then shoot", diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/WaitForFlywheelAtTarget.java b/2026-Rebuilt/src/main/java/frc/robot/commands/WaitForFlywheelAtTarget.java new file mode 100644 index 0000000..449373c --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/WaitForFlywheelAtTarget.java @@ -0,0 +1,50 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.LauncherSubsystem; + +/** + * + * Start the launcher flywheel and get it up to the target speed. + * + **/ +public class WaitForFlywheelAtTarget extends Command { + private final LauncherSubsystem m_subsystem; + private final double m_toleranceRPM; + + /** + * Creates a new WaitForFlywheelAtTarget. + * + * @param subsystem The subsystem used by this command. + */ + public WaitForFlywheelAtTarget(LauncherSubsystem subsystem, double toleranceRPM) + { + m_subsystem = subsystem; + m_toleranceRPM = toleranceRPM; + } + + // Called when the command is initially scheduled. + @Override + public void initialize() {} + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() {} + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) {} + + // Returns true when the command should end. + @Override + public boolean isFinished() { + // The command signals end when the flywheel speed is within the tolerance of the target. + double targetSpeed = m_subsystem.getTargetSpeedrpm(); + double currentSpeed = m_subsystem.getCurrentSpeedrpm(); + if (Math.abs(currentSpeed - targetSpeed) <= m_toleranceRPM) { + return true; + } else { + return false; + } + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java deleted file mode 100644 index 88967b0..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/BackupAndShoot.java +++ /dev/null @@ -1,88 +0,0 @@ -package frc.robot.commands.autoCommands; - -import java.util.function.BooleanSupplier; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; -import edu.wpi.first.wpilibj2.command.ParallelRaceGroup; -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; -import frc.robot.subsystems.DriveSubsystem; -import frc.robot.subsystems.LauncherSubsystem; -import frc.robot.subsystems.LiftSubsystem; -import frc.robot.commands.*; -import frc.robot.Constants.*; - -/** An example command that uses an example subsystem. */ -public class BackupAndShoot extends Command { - private final DriveSubsystem m_driveSubsystem; - private final LauncherSubsystem m_launcherSubsystem; - private final LiftSubsystem m_liftSubsystem; - private final DifferentialDrivePoseEstimator m_poseEstimator; - private final BooleanSupplier m_isRed; - - /** - * Creates a new BackupAndShoot. - * - * @param poseEstimator The pose estimator to get the location of the robot. - * @param targetPose The pose the robot will make a point to go to. - * @param constraints The constraints the robot will follow while following the path. - */ - public BackupAndShoot(DriveSubsystem driveSubsystem, LauncherSubsystem launcherSubsystem, LiftSubsystem liftSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed) - { - m_driveSubsystem = driveSubsystem; - m_launcherSubsystem = launcherSubsystem; - m_liftSubsystem = liftSubsystem; - m_poseEstimator = poseEstimator; - m_isRed = isRed; - } - - // Called when the command is initially scheduled. - // TODO: Indexer Implemntation needed - @Override - public void initialize() { - // This should do the process to make the launcher get up to speed - Command rangeLauncher = new RangeLauncherCommand(m_launcherSubsystem, m_poseEstimator, LauncherConstants.kFlywheelToleranceRPM, m_isRed); - Command keepSpeedCommand1 = new TrackHubFlywheelCommand(m_launcherSubsystem, m_poseEstimator, m_isRed); - Command keepSpeedCommand2 = new TrackHubFlywheelCommand(m_launcherSubsystem, m_poseEstimator, m_isRed); - - Command deadreckonBackward = new DeadreckonDistance(m_driveSubsystem, 1.5, -2.0); - Command aimCommand = new AimAtHub(m_driveSubsystem, m_poseEstimator, 4.0, m_isRed); - - Command startLift = new StartLiftCommand(m_liftSubsystem); - - SequentialCommandGroup fullComboCommand = new SequentialCommandGroup( - new ParallelRaceGroup( - new ParallelCommandGroup( - rangeLauncher, - keepSpeedCommand1 - ), - new SequentialCommandGroup( - deadreckonBackward, - aimCommand, - startLift // Replace with the combo launcher, indexer, mover - ) - ), - keepSpeedCommand2 - ); - - CommandScheduler.getInstance().schedule(fullComboCommand); - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - // The command automatically ends - return true; - } -} From 347b4ef98c172bfe97d2509d9ccbe3a1392222f1 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 24 Mar 2026 21:14:16 -0500 Subject: [PATCH 147/161] Increase indexer motor speed --- 2026-Rebuilt/src/main/java/frc/robot/Constants.java | 2 +- .../java/frc/robot/subsystems/IndexerBulkSubsystem.java | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 942449f..56c10ef 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -244,7 +244,7 @@ public static class IndexerBulkConstants { // Raw motor speeds in range [-1.0,1.0] public static final double kBulkMoveMotorSpeed = 0.5; - public static final double kIndexerMotorSpeed = 0.3; + public static final double kIndexerMotorSpeed = 0.5; } public static class ClimbL1Constants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index f2ae97f..cc0ca23 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -46,11 +46,10 @@ public IndexerBulkSubsystem() throws Exception { SmartDashboard.putNumber("IndexerBulk TestIndexerSpeed", m_indexerSpeed); m_motorBulk = new TalonFXS(IndexerBulkConstants.kBulkMoveMotorCANID); - - if (!m_motorBulk.isConnected()) - { + if (!m_motorBulk.isConnected()) + { throw new Exception("Bult transport motor is not present."); - } + } m_motorIndexer = new TalonFX(IndexerBulkConstants.kIndexerMotorCANID); if (!m_motorIndexer.isConnected()) From d050073fb0ada75b31917778c3cd75ba92a48b86 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 24 Mar 2026 21:14:55 -0500 Subject: [PATCH 148/161] Update dashboard layout --- 2026-Rebuilt/elastic-layout.json | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 5df567e..3dde974 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -43,7 +43,7 @@ "properties": { "topic": "/SmartDashboard/Field", "period": 0.06, - "field_game": "Reefscape", + "field_game": "Rebuilt", "robot_width": 0.85, "robot_length": 0.85, "show_other_objects": true, @@ -208,7 +208,7 @@ { "title": "Safe To Shoot", "x": 0.0, - "y": 256.0, + "y": 384.0, "width": 256.0, "height": 128.0, "type": "Boolean Box", @@ -221,6 +221,19 @@ "true_icon": "None", "false_icon": "None" } + }, + { + "title": "Starting Position", + "x": 0.0, + "y": 256.0, + "width": 256.0, + "height": 128.0, + "type": "ComboBox Chooser", + "properties": { + "topic": "/SmartDashboard/Starting Position", + "period": 0.06, + "sort_options": false + } } ] } From 5f3d58bcb4e62f9b23c9063b14fa80bfff41f706 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Tue, 24 Mar 2026 21:27:14 -0500 Subject: [PATCH 149/161] Fix test mode for lift subsystem --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 911104d..6a70d3a 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -610,5 +610,9 @@ public void testPeriodic() { { m_launcherSubsystem.get().testPeriodic(); } + if (m_liftSubsystem.isPresent()) + { + m_liftSubsystem.get().testPeriodic(); + } } } From 62ac265c0ae739f0d92550c5b5f541f5682ade96 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:33:06 -0500 Subject: [PATCH 150/161] Made all subsystems with motors set speed to 0 on init --- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 1 - .../src/main/java/frc/robot/subsystems/DriveSubsystem.java | 4 +++- .../main/java/frc/robot/subsystems/IndexerBulkSubsystem.java | 3 +++ .../src/main/java/frc/robot/subsystems/IntakeSubsystem.java | 1 + .../src/main/java/frc/robot/subsystems/LauncherSubsystem.java | 3 ++- .../src/main/java/frc/robot/subsystems/LiftSubsystem.java | 2 ++ .../main/java/frc/robot/subsystems/LimelightSubsystem.java | 1 - 2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java | 1 - 8 files changed, 11 insertions(+), 5 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index 6a70d3a..c17c329 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -45,7 +45,6 @@ import frc.robot.utils.Pigeon; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; -import frc.robot.commands.DriveCommands.TurnLeftTest; import frc.robot.commands.autoCommands.BackupCollectDepoAndShoot; import frc.robot.commands.autoCommands.DeadreckonDistance; import frc.robot.commands.util.CancelDriveCommand; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index 43833f2..df7681b 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -68,11 +68,13 @@ public DriveSubsystem(DifferentialDrivePoseEstimator poseEstimator, Differential m_leftMotor = leftMotor; // Right Motor - setConfig(m_rightMotor, InvertedValue.CounterClockwise_Positive); + setConfig(m_rightMotor, InvertedValue.CounterClockwise_Positive); + m_rightMotor.set(0.0); SendableRegistry.setName(m_rightMotor, "DriveSubsystem", "rightMotor"); // Left Motor setConfig(m_leftMotor, InvertedValue.Clockwise_Positive); + m_leftMotor.set(0.0); SendableRegistry.setName(m_leftMotor, "DriveSubsystem", "leftMotor"); // Zeroing the encoders diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index cc0ca23..2ebea54 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -57,6 +57,9 @@ public IndexerBulkSubsystem() throws Exception { throw new Exception("Indexer motor is not present."); } + m_motorBulk.set(0.0); + m_motorIndexer.set(0.0); + TalonFXSConfiguration motorConfig = new TalonFXSConfiguration(); motorConfig.Commutation.MotorArrangement = MotorArrangementValue.Minion_JST; StatusCode status = StatusCode.StatusCodeNotInitialized; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index f570832..51337ee 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -36,6 +36,7 @@ public IntakeSubsystem(Boolean bHasPneumatics) throws Exception { { throw new Exception("Intake motor is not connected!"); } + m_motorIntake.set(0.0); if(bHasPneumatics) { m_solenoid = new DoubleSolenoid(PneumaticsConstants.kPneumaticsHubCANID, diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java index 2876e71..d801903 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LauncherSubsystem.java @@ -18,7 +18,6 @@ import com.ctre.phoenix6.hardware.TalonFX; import com.ctre.phoenix6.signals.*; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; -import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.SubsystemBase; import edu.wpi.first.wpilibj.DigitalInput; import frc.robot.Constants.LauncherConstants; @@ -94,6 +93,8 @@ public LauncherSubsystem() throws Exception { LauncherConstants.kMotorsDriveInOppositeDirections ? MotorAlignmentValue.Opposed : MotorAlignmentValue.Aligned)); + m_motorLeader.set(0.0); + m_configValid = true; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java index 898dfd5..9c30d7d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LiftSubsystem.java @@ -36,6 +36,8 @@ public LiftSubsystem() throws Exception { { throw new Exception("Lift motor is not present!"); } + + m_motorLift.set(0.0); } // diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index df7ba8e..6d4fb1d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -13,7 +13,6 @@ import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.numbers.N3; -import edu.wpi.first.wpilibj.DriverStation; import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; import edu.wpi.first.wpilibj2.command.SubsystemBase; import frc.robot.LimelightHelpers; diff --git a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java index 7f8132e..6b4ebb6 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java +++ b/2026-Rebuilt/src/main/java/frc/robot/utils/LauncherUtils.java @@ -3,7 +3,6 @@ import java.util.function.BooleanSupplier; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import frc.robot.utils.HubUtils; public class LauncherUtils { // From 243b8d78a65602daf480d465e3418e3826b2af52 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:38:39 -0500 Subject: [PATCH 151/161] Made all motors be set to 0 on disabled init --- .../src/main/java/frc/robot/RobotContainer.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index c17c329..c198429 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -516,6 +516,23 @@ public void disabledInit() { LimelightHelpers.SetIMUMode("limelight", 3); m_limelightSubsystem.setAllowJumps(true); + // Disable all motors on disabled init + if (m_driveSubsystem.isPresent()) { + DriveSubsystem drive = m_driveSubsystem.get(); + drive.setDifferentialSpeedNoPid(0,0); + } + + if (m_intakeSubsystem.isPresent()) { + IntakeSubsystem intake = m_intakeSubsystem.get(); + intake.stop(); + } + + if (m_indexerBulkSubsystem.isPresent()) { + IndexerBulkSubsystem indexBulk = m_indexerBulkSubsystem.get(); + indexBulk.stopBulkTransfer(); + indexBulk.stopIndexer(); + } + if (m_liftSubsystem.isPresent()) { LiftSubsystem lift = m_liftSubsystem.get(); lift.stopLift(); From 80869b942069b2d705441ef49ed6a5fb51e7cc06 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Wed, 25 Mar 2026 17:52:00 -0500 Subject: [PATCH 152/161] Theoretically got RotateToShoot working on hold Y --- .../src/main/java/frc/robot/Constants.java | 2 + .../main/java/frc/robot/RobotContainer.java | 52 +++++++------ .../robot/commands/RotateAndShootCommand.java | 73 ------------------- 3 files changed, 32 insertions(+), 95 deletions(-) delete mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index 56c10ef..d14fe84 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -91,6 +91,8 @@ public static enum kStartingNames { Map.entry(false, new Pose2d(new Translation2d(3.6, 2.9), Rotation2d.kZero)) // blue )) ); + + public static final double kRotateToHubSpeed = 3.0; } public static class AutoConstants { diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index c198429..b7e50f3 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -45,7 +45,6 @@ import frc.robot.utils.Pigeon; import frc.robot.utils.PneumaticHubWrapper; import frc.robot.commands.*; -import frc.robot.commands.autoCommands.BackupCollectDepoAndShoot; import frc.robot.commands.autoCommands.DeadreckonDistance; import frc.robot.commands.util.CancelDriveCommand; import frc.robot.utils.LauncherUtils; @@ -194,11 +193,12 @@ private static Optional getSubsystem(Class subsystemClass) { // Init Autos (/home/lvuser/deploy/pathplanner/autos) private void configureAutos() { - if (m_driveSubsystem.isPresent() && m_launcherSubsystem.isPresent() && m_liftSubsystem.isPresent()) { + if (m_driveSubsystem.isPresent() && m_launcherSubsystem.isPresent() && m_liftSubsystem.isPresent() && m_indexerBulkSubsystem.isPresent()) { // Init Needed values DriveSubsystem driveSubsystem = m_driveSubsystem.get(); LauncherSubsystem launcherSubsystem = m_launcherSubsystem.get(); LiftSubsystem liftSubsystem = m_liftSubsystem.get(); + IndexerBulkSubsystem indexerBulkSubsystem = m_indexerBulkSubsystem.get(); m_autoChooser = new SendableChooser(); // Init Autos @@ -208,17 +208,13 @@ private void configureAutos() { new TrackHubFlywheelCommand(launcherSubsystem, m_PoseEstimator, m_isRed), new SequentialCommandGroup( new DeadreckonDistance(driveSubsystem, 1.5, -2.0), - new AimAtHub(driveSubsystem, m_PoseEstimator, 4.0, m_isRed), + new AimAtHub(driveSubsystem, m_PoseEstimator, RobotConstants.kRotateToHubSpeed, m_isRed), new WaitForFlywheelAtTarget(launcherSubsystem, LauncherConstants.kFlywheelToleranceRPM), - new StartLiftCommand(liftSubsystem) // Replace with the combo launcher, indexer, mover command later + new StartShootCommand(liftSubsystem, indexerBulkSubsystem) ) ) ); - m_autoChooser.addOption("[INDEV] Backup and collect from depot then shoot", - new BackupCollectDepoAndShoot(driveSubsystem, m_PoseEstimator, m_isRed, m_constraints) - ); - // Warm up Pathfinder CommandScheduler.getInstance().schedule( PathfindingCommand.warmupCommand() @@ -285,12 +281,9 @@ private void configureBindings() { if (m_driveSubsystem.isPresent()) { DriveSubsystem driveSubsystem = m_driveSubsystem.get(); - // Cancel All Drive Commands - m_driverController.back().onTrue(new CancelDriveCommand(driveSubsystem)); - - // Aim to Hub + // Aim to Hub (TESTING?) m_driverController.rightBumper().onTrue( - new AimAtHub(driveSubsystem, m_PoseEstimator, 3.0, m_isRed) + new AimAtHub(driveSubsystem, m_PoseEstimator, RobotConstants.kRotateToHubSpeed, m_isRed) ); // Range launcher, turn to face hub and shoot all fuel @@ -301,8 +294,6 @@ private void configureBindings() { if (m_liftSubsystem.isPresent()) { LiftSubsystem lift = m_liftSubsystem.get(); - m_operatorController.a().onTrue(new StopLauncherCommand(launcher).alongWith(new StopLiftCommand(lift))); - m_operatorController.x().onTrue(new StartLiftCommand(lift)); m_operatorController.b().onTrue(new StopLiftCommand(lift)); @@ -310,14 +301,28 @@ private void configureBindings() { { IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); + m_operatorController.a().onTrue( + new StopShootCommand(lift, indexer) + .andThen(new StopLauncherCommand(launcher)) + ); + + // This is intended to keep shooting until the button is released. - m_driverController.y().whileTrue(new RotateAndShootCommand(driveSubsystem, - launcher, - lift, - indexer, - m_PoseEstimator, - m_isRed, - LauncherConstants.kFlywheelToleranceRPM)); + m_driverController.y().whileTrue( + new ParallelCommandGroup( + new TrackHubFlywheelCommand(launcher, m_PoseEstimator, m_isRed), + new SequentialCommandGroup( + new AimAtHub(driveSubsystem, m_PoseEstimator, RobotConstants.kRotateToHubSpeed, m_isRed), + new WaitForFlywheelAtTarget(launcher, LauncherConstants.kFlywheelToleranceRPM), + new StartShootCommand(lift, indexer) + ) + ) + ); + + m_driverController.y().onFalse( + new StopShootCommand(lift, indexer) + .andThen(new StopLauncherCommand(launcher)) + ); } } else { m_operatorController.a().onTrue(new StopLauncherCommand(launcher)); @@ -341,6 +346,9 @@ private void configureBindings() { new Trigger(() -> (Math.abs(m_driverController.getRightX()) > 0.5) && (driveSubsystem.getCurrentCommand().getClass() != driveSubsystem.getDefaultCommand().getClass())) .onTrue(new CancelDriveCommand(driveSubsystem)); + + // Also do it on back press + m_driverController.back().onTrue(new CancelDriveCommand(driveSubsystem)); } // diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java b/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java deleted file mode 100644 index 07b8be8..0000000 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/RotateAndShootCommand.java +++ /dev/null @@ -1,73 +0,0 @@ -package frc.robot.commands; - -import java.util.function.BooleanSupplier; - -import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; -import edu.wpi.first.wpilibj2.command.Command; -import edu.wpi.first.wpilibj2.command.CommandScheduler; -import edu.wpi.first.wpilibj2.command.ParallelCommandGroup; -import frc.robot.subsystems.DriveSubsystem; -import frc.robot.subsystems.LauncherSubsystem; -import frc.robot.subsystems.LiftSubsystem; -import frc.robot.subsystems.IndexerBulkSubsystem; - -/** An example command that uses an example subsystem. */ -public class RotateAndShootCommand extends Command { - private final DriveSubsystem m_driveSubsystem; - private final LauncherSubsystem m_launcherSubsystem; - private final LiftSubsystem m_liftSubsystem; - private final IndexerBulkSubsystem m_indexerSubsystem; - private final DifferentialDrivePoseEstimator m_poseEstimator; - private final BooleanSupplier m_isRed; - private final double m_flywheelTolerance; - - /** - * Creates a new BackupAndShoot. - * - * @param poseEstimator The pose estimator to get the location of the robot. - * @param targetPose The pose the robot will make a point to go to. - * @param constraints The constraints the robot will follow while following the path. - */ - public RotateAndShootCommand(DriveSubsystem driveSubsystem, LauncherSubsystem launcherSubsystem, LiftSubsystem liftSubsystem, IndexerBulkSubsystem indexerSubsystem, DifferentialDrivePoseEstimator poseEstimator, BooleanSupplier isRed, double flywheelTolerance) - { - m_driveSubsystem = driveSubsystem; - m_launcherSubsystem = launcherSubsystem; - m_liftSubsystem = liftSubsystem; - m_indexerSubsystem = indexerSubsystem; - m_poseEstimator = poseEstimator; - m_flywheelTolerance = flywheelTolerance; - m_isRed = isRed; - } - - // Called when the command is initially scheduled. - @Override - public void initialize() { - // This should do the process to make the launcher get up to speed - Command setLauncherSpeedCommand = new RangeLauncherCommand(m_launcherSubsystem, m_poseEstimator, m_flywheelTolerance, m_isRed); - Command aimAtHubCommand = new AimAtHub(m_driveSubsystem, m_poseEstimator, 4.0, m_isRed); - Command startShootCommand = new StartShootCommand(m_liftSubsystem, m_indexerSubsystem); - - ParallelCommandGroup TurnAndSet = new ParallelCommandGroup(setLauncherSpeedCommand, aimAtHubCommand); - - CommandScheduler.getInstance().schedule( - TurnAndSet - .andThen(startShootCommand) - ); - } - - // Called every time the scheduler runs while the command is scheduled. - @Override - public void execute() {} - - // Called once the command ends or is interrupted. - @Override - public void end(boolean interrupted) {} - - // Returns true when the command should end. - @Override - public boolean isFinished() { - // The command only ends when one of the subsystems it uses has another - // command scheduled on it. - return false; - } -} From 08ddd2ea7e4d1ba84eb27a25b17adfc247d601e1 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:03:38 -0500 Subject: [PATCH 153/161] Update elastic-layout.json --- 2026-Rebuilt/elastic-layout.json | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/2026-Rebuilt/elastic-layout.json b/2026-Rebuilt/elastic-layout.json index 3dde974..d140cf3 100644 --- a/2026-Rebuilt/elastic-layout.json +++ b/2026-Rebuilt/elastic-layout.json @@ -35,10 +35,10 @@ }, { "title": "Field", - "x": 896.0, + "x": 1152.0, "y": 0.0, - "width": 384.0, - "height": 256.0, + "width": 640.0, + "height": 384.0, "type": "Field", "properties": { "topic": "/SmartDashboard/Field", @@ -54,22 +54,10 @@ "show_robot_outside_widget": true } }, - { - "title": "Scheduler", - "x": 1664.0, - "y": 0.0, - "width": 256.0, - "height": 384.0, - "type": "Scheduler", - "properties": { - "topic": "/SmartDashboard/Scheduler", - "period": 0.06 - } - }, { "title": "Pose X (Meter)", - "x": 896.0, - "y": 256.0, + "x": 1792.0, + "y": 0.0, "width": 128.0, "height": 128.0, "type": "Text Display", @@ -82,8 +70,8 @@ }, { "title": "Pose Y (Meter)", - "x": 1024.0, - "y": 256.0, + "x": 1792.0, + "y": 128.0, "width": 128.0, "height": 128.0, "type": "Text Display", @@ -96,7 +84,7 @@ }, { "title": "Pose Theta (Degrees)", - "x": 1152.0, + "x": 1792.0, "y": 256.0, "width": 128.0, "height": 128.0, @@ -112,7 +100,7 @@ "title": "limelight", "x": 512.0, "y": 0.0, - "width": 384.0, + "width": 640.0, "height": 384.0, "type": "Camera Stream", "properties": { From d3b10916f26ef8845a2f152a0052aaf7bde0855c Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Thu, 26 Mar 2026 18:32:06 -0500 Subject: [PATCH 154/161] Remove redundant TODOs and unused imports --- 2026-Rebuilt/src/main/java/frc/robot/Constants.java | 4 ++-- 2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java | 7 +++---- .../robot/commands/autoCommands/DeadreckonBumpAndBack.java | 3 --- .../src/main/java/frc/robot/subsystems/DriveSubsystem.java | 2 -- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index d14fe84..a1ef30d 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -157,7 +157,7 @@ public static class DrivetrainConstants { public static final double kI = 0.0; public static final double kD = 0.0; // A velocity of 1 rps results in x V output public static final double kA_linear = 0.01; // Voltage needed to induce a given accel. in the motor shaft - public static final double kA_angular = 0.01; // TODO: We need to measure this! + public static final double kA_angular = 0.01; public static final double kPeakVoltage = 8.0; public static final double kMaxVelocityMPS = 3.0; // 6 mps is the max of the motors during zero load. @@ -215,7 +215,7 @@ public static class LauncherConstants { public static final double kI = 0.0; public static final double kD = 0.0; // A velocity of 1 rps results in x V output public static final double kA_linear = 0.01; // Voltage needed to induce a given accel. in the motor shaft - public static final double kA_angular = 0.01; // TODO: We need to measure this! + public static final double kA_angular = 0.01; public static final double kPeakVoltage = 8.0; public static final double kMaxVelocityRPS = 6000.0/60.0; diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index b7e50f3..2b85ced 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -294,6 +294,7 @@ private void configureBindings() { if (m_liftSubsystem.isPresent()) { LiftSubsystem lift = m_liftSubsystem.get(); + // TODO: IMPORTANT - These should be Start/StopShootCommand since we have bulk move now. m_operatorController.x().onTrue(new StartLiftCommand(lift)); m_operatorController.b().onTrue(new StopLiftCommand(lift)); @@ -369,6 +370,8 @@ private void configureBindings() { m_operatorController.back().onTrue(new LowerClimbCommand(m_climbL1Subsystem.get())); } + // TODO: IMPORTANT - these buttons are already bound above. I suspect the following + // block needs to be removed. if (m_launcherSubsystem.isPresent()) { // Operator's manual launcher override. @@ -378,11 +381,7 @@ private void configureBindings() { m_operatorController.a().onTrue(new StartFlywheelCommand(m_launcherSubsystem.get(), LauncherConstants.kFixedTestSpeed, LauncherConstants.kFlywheelToleranceRPM)); - - // TODO: Need composite command for manual shoot (spin up flywheel, wait for target, start lift motor) } - - // TODO: Write and bind composite commands for driver controls. } // Populate the SmartDashboard on robot init. diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java index f4dbbb0..324eebc 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -3,18 +3,15 @@ import java.util.function.BooleanSupplier; import com.pathplanner.lib.auto.AutoBuilder; -import com.pathplanner.lib.path.GoalEndState; import com.pathplanner.lib.path.PathConstraints; import com.pathplanner.lib.path.PathPlannerPath; import edu.wpi.first.math.estimator.DifferentialDrivePoseEstimator; import edu.wpi.first.math.geometry.Pose2d; import edu.wpi.first.math.geometry.Rotation2d; -import edu.wpi.first.math.geometry.Translation2d; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.commands.AimAtHub; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.PathUtils; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java index df7681b..e2a1a39 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/DriveSubsystem.java @@ -196,8 +196,6 @@ public void initDefaultCommand(CommandXboxController Controller) // setDefaultCommand(new ArcadeDriveCommand(this, Controller)); } - // TODO: Work on a naming scheme for conversion functions - // This converts rotations of the motor shaft to meters travled. public double ConvertRotationsToMeters(double rotations) { return rotations * DrivetrainConstants.kDrivetrainGearRatio * DrivetrainConstants.kWheelCircumference; From fa8ec911d7492445aa90a4e0ba316e2c14c3e5ef Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:35:11 -0500 Subject: [PATCH 155/161] Updated operator x & b to use shoot command --- .../src/main/java/frc/robot/RobotContainer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index b7e50f3..9b1aaca 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -293,14 +293,13 @@ private void configureBindings() { if (m_liftSubsystem.isPresent()) { LiftSubsystem lift = m_liftSubsystem.get(); - - m_operatorController.x().onTrue(new StartLiftCommand(lift)); - m_operatorController.b().onTrue(new StopLiftCommand(lift)); - if (m_indexerBulkSubsystem.isPresent()) - { + if (m_indexerBulkSubsystem.isPresent()) { IndexerBulkSubsystem indexer = m_indexerBulkSubsystem.get(); + m_operatorController.x().onTrue(new StartShootCommand(lift, indexer)); + m_operatorController.b().onTrue(new StopShootCommand(lift, indexer)); + m_operatorController.a().onTrue( new StopShootCommand(lift, indexer) .andThen(new StopLauncherCommand(launcher)) @@ -323,6 +322,9 @@ private void configureBindings() { new StopShootCommand(lift, indexer) .andThen(new StopLauncherCommand(launcher)) ); + } else { + m_operatorController.x().onTrue(new StartLiftCommand(lift)); + m_operatorController.b().onTrue(new StopLiftCommand(lift)); } } else { m_operatorController.a().onTrue(new StopLauncherCommand(launcher)); From 40ba4cedc82c44d2cda012441e4434bd40986ff7 Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Thu, 26 Mar 2026 18:45:39 -0500 Subject: [PATCH 156/161] More tidying --- .../commands/autoCommands/DeadreckonBumpAndBack.java | 10 +--------- .../frc/robot/commands/autoCommands/DepoSideAutoA.java | 1 - .../commands/autoCommands/OverBumpContinousJ.java | 2 +- .../java/frc/robot/subsystems/LimelightSubsystem.java | 1 - 4 files changed, 2 insertions(+), 12 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java index 324eebc..2a9e443 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DeadreckonBumpAndBack.java @@ -15,7 +15,6 @@ import frc.robot.commands.AimAtHub; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.PathUtils; -import frc.robot.utils.Pigeon; /** An example command that uses an example subsystem. */ public class DeadreckonBumpAndBack extends Command { @@ -23,7 +22,6 @@ public class DeadreckonBumpAndBack extends Command { private final DifferentialDrivePoseEstimator m_poseEstimator; private final PathConstraints m_constraints; private final BooleanSupplier m_isRed; - private final Pigeon m_pigeon; /** * Creates a new DeadreckonBumpAndBack. @@ -32,29 +30,23 @@ public class DeadreckonBumpAndBack extends Command { * @param targetPose The pose the robot will make a point to go to. * @param constraints The constraints the robot will follow while following the path. */ - public DeadreckonBumpAndBack(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, BooleanSupplier isRed, Pigeon pigeon) + public DeadreckonBumpAndBack(DriveSubsystem driveSubsystem, DifferentialDrivePoseEstimator poseEstimator, PathConstraints constraints, BooleanSupplier isRed) { m_driveSubsystem = driveSubsystem; m_poseEstimator = poseEstimator; m_constraints = constraints; m_isRed = isRed; - m_pigeon = pigeon; } // Called when the command is initially scheduled. @Override public void initialize() { - Rotation2d targetRotation; Double pickupTargetX; Double lineupTargetX; if (m_isRed.getAsBoolean() == true) { // Red - targetRotation = Rotation2d.k180deg; - pickupTargetX = 9.1; lineupTargetX = 10.88; } else { // Blue - targetRotation = Rotation2d.kZero; - pickupTargetX = 7.689; lineupTargetX = 5.667; } diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java index 998b987..d4916fa 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/DepoSideAutoA.java @@ -76,7 +76,6 @@ public void initialize() { } // Init the new sequence - // TODO: Replace placeholder InstantCommands with real ones. ArrayList sequence = new ArrayList(Arrays.asList( new ExtendIntakeCommand(null), // Extend Intake new InstantCommand(), // Drive Over bump fwd diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java index 4b5e50d..9100852 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/autoCommands/OverBumpContinousJ.java @@ -12,7 +12,7 @@ import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.InstantCommand; -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; +//import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.commands.AimAtHub; import frc.robot.subsystems.DriveSubsystem; import frc.robot.utils.PathUtils; diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java index 6d4fb1d..c0bd0b6 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/LimelightSubsystem.java @@ -93,7 +93,6 @@ private void updateOdometry() { /// Actually do the vision measurements \\\ // A Standard Deviation, in the form of [x, y, theta]ᵀ in meters and radians. - // TODO: Look into scaling these based off of the ambuguity and size of the tags. -- Kinda done (3/20/2025) double stdDev = 0.5 + bestTargetAmbiguity; Vector errorVec = VecBuilder.fill(stdDev, stdDev,9999999); From b8318da1eabc806aed0a9c60dd200dac296210a6 Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Thu, 26 Mar 2026 18:47:20 -0500 Subject: [PATCH 157/161] Fixed the double bindings --- .../src/main/java/frc/robot/RobotContainer.java | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index be29f0d..b20f757 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -370,19 +370,6 @@ private void configureBindings() { m_operatorController.start().onTrue(new RaiseClimbCommand(m_climbL1Subsystem.get())); m_operatorController.back().onTrue(new LowerClimbCommand(m_climbL1Subsystem.get())); } - - // TODO: IMPORTANT - these buttons are already bound above. I suspect the following - // block needs to be removed. - if (m_launcherSubsystem.isPresent()) - { - // Operator's manual launcher override. - m_operatorController.b().onTrue(new StopLauncherCommand(m_launcherSubsystem.get())); - - // FOR TEST PURPOSES ONLY! - m_operatorController.a().onTrue(new StartFlywheelCommand(m_launcherSubsystem.get(), - LauncherConstants.kFixedTestSpeed, - LauncherConstants.kFlywheelToleranceRPM)); - } } // Populate the SmartDashboard on robot init. From 4e7ac56cfee71bdfdf995f0ad77a40c5807dbeaf Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Thu, 26 Mar 2026 19:16:59 -0500 Subject: [PATCH 158/161] Committed PDF version of Robot User Manual --- 2026-Rebuilt/user_manual/Robot-Manual-2026.pdf | Bin 0 -> 405095 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 2026-Rebuilt/user_manual/Robot-Manual-2026.pdf diff --git a/2026-Rebuilt/user_manual/Robot-Manual-2026.pdf b/2026-Rebuilt/user_manual/Robot-Manual-2026.pdf new file mode 100644 index 0000000000000000000000000000000000000000..7afe30129c87eb258c1bf128916ab0128103ed4d GIT binary patch literal 405095 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
&Ky+hWqG2+6UgHA<$WH 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 z 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

8z$ko#$9LBW* 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

FPj2_)E%*kpt7O}^ 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 Date: Thu, 26 Mar 2026 19:51:50 -0500 Subject: [PATCH 159/161] Changed turn a tad bit less sensitive --- 2026-Rebuilt/src/main/java/frc/robot/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2026-Rebuilt/src/main/java/frc/robot/Constants.java b/2026-Rebuilt/src/main/java/frc/robot/Constants.java index a1ef30d..82ca6c0 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/Constants.java +++ b/2026-Rebuilt/src/main/java/frc/robot/Constants.java @@ -147,7 +147,7 @@ public static class DrivetrainConstants { public static final int kRightMotorCANID = 20; public static final int kOptionalRightMotorCANID = 21; - public static final double kTurnDivider = 2; + public static final double kTurnDivider = 2.5; public static final double kSpeedDivider = 2.5; // These numbers came from the ctre example then tweaked From c936f18cd37d7f5162d1a3db8102e9947e15bcde Mon Sep 17 00:00:00 2001 From: Capyblapy <111537871+Capyblapy@users.noreply.github.com> Date: Thu, 26 Mar 2026 20:03:14 -0500 Subject: [PATCH 160/161] Finished testing and added a way to reverse bulk --- .../main/java/frc/robot/RobotContainer.java | 3 ++ .../frc/robot/commands/ReverseIndexBulk.java | 50 +++++++++++++++++++ .../subsystems/IndexerBulkSubsystem.java | 13 +++++ 3 files changed, 66 insertions(+) create mode 100644 2026-Rebuilt/src/main/java/frc/robot/commands/ReverseIndexBulk.java diff --git a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java index b20f757..10638f7 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java +++ b/2026-Rebuilt/src/main/java/frc/robot/RobotContainer.java @@ -305,6 +305,9 @@ private void configureBindings() { .andThen(new StopLauncherCommand(launcher)) ); + m_operatorController.rightStick().whileTrue(new ReverseIndexBulk(indexer)); + m_operatorController.rightStick().onFalse(new StopShootCommand(lift, indexer)); + // This is intended to keep shooting until the button is released. m_driverController.y().whileTrue( diff --git a/2026-Rebuilt/src/main/java/frc/robot/commands/ReverseIndexBulk.java b/2026-Rebuilt/src/main/java/frc/robot/commands/ReverseIndexBulk.java new file mode 100644 index 0000000..e1e22de --- /dev/null +++ b/2026-Rebuilt/src/main/java/frc/robot/commands/ReverseIndexBulk.java @@ -0,0 +1,50 @@ +package frc.robot.commands; + +import edu.wpi.first.wpilibj2.command.Command; +import frc.robot.subsystems.IndexerBulkSubsystem; + +/** + * + * Start shooting fuel by starting the lift motor and both motors in the indexer/bulk subsystem. + * + **/ +public class ReverseIndexBulk extends Command { + private final IndexerBulkSubsystem m_IndexerBulk; + + /** + * Creates a new ReverseIndexBulk. + * + * @param subsystem The subsystem used by this command. + */ + public ReverseIndexBulk(IndexerBulkSubsystem indexerbulk) + { + m_IndexerBulk = indexerbulk; + + // Use addRequirements() here to declare subsystem dependencies. + addRequirements(m_IndexerBulk); + } + + // Called when the command is initially scheduled. + @Override + public void initialize() { + m_IndexerBulk.reverseBulkTransfer(); + m_IndexerBulk.reverseIndexer(); + } + + // Called every time the scheduler runs while the command is scheduled. + @Override + public void execute() { + } + + // Called once the command ends or is interrupted. + @Override + public void end(boolean interrupted) { + } + + // This command only ends when another command is scheduled on the + // subsystem. + @Override + public boolean isFinished() { + return false; + } +} diff --git a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java index 2ebea54..6b5c93c 100644 --- a/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java +++ b/2026-Rebuilt/src/main/java/frc/robot/subsystems/IndexerBulkSubsystem.java @@ -80,6 +80,12 @@ public void startBulkTransfer() { SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); } + public void reverseBulkTransfer() { + m_motorBulk.set(-m_bulkSpeed/2); + m_bulkStarted = true; + SmartDashboard.putBoolean("IndexerBulk BulkStarted", m_bulkStarted); + } + // Stops the belts in bulk storage. public void stopBulkTransfer() { m_motorBulk.set(0.0); @@ -104,6 +110,13 @@ public void startIndexer() { SmartDashboard.putBoolean("IndexerBulk IndexerStarted", m_indexerStarted); } + public void reverseIndexer() { + // Indexer runs in the negative direction when operating normally so we dont the commanded speed. + m_motorIndexer.set(m_indexerSpeed/2); + m_indexerStarted = true; + SmartDashboard.putBoolean("IndexerBulk IndexerStarted", m_indexerStarted); + } + // Stops the indexer. public void stopIndexer() { m_motorIndexer.set(0.0); From 39a739fe2bcf0901cf63041996c59c66c0c81f2b Mon Sep 17 00:00:00 2001 From: Capyblapy Date: Thu, 26 Mar 2026 20:13:26 -0500 Subject: [PATCH 161/161] User manual update --- .../user_manual/Robot-Manual-2026.pdf | Bin 405095 -> 407215 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/2026-Rebuilt/user_manual/Robot-Manual-2026.pdf b/2026-Rebuilt/user_manual/Robot-Manual-2026.pdf index 7afe30129c87eb258c1bf128916ab0128103ed4d..e201d899f8abe7e780f3cbfd49e807ac048c8db9 100644 GIT binary patch delta 59836 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 z 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 F{~!1kT{Hjy delta 57685 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