Initial commit of magicbot code base
This commit is contained in:
parent
5986bc8f92
commit
2c7b6eb5c1
|
|
@ -1 +0,0 @@
|
|||
@tywilly
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
|
||||
|
||||
name: Java CI with Gradle
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
- name: Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build javadoc
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
[submodule "lib/Posty"]
|
||||
path = lib/Posty
|
||||
url = git@github.com:FairportRobotics/Posty.git
|
||||
[submodule "lib/RoboLib"]
|
||||
path = lib/RoboLib
|
||||
url = git@github.com:FairportRobotics/RoboLib
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
// 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,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
}
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"enableCppIntellisense": false,
|
||||
"currentLanguage": "java",
|
||||
"projectYear": "2026",
|
||||
"teamNumber": 578
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
"""
|
||||
LimelightHelpers.py – stub for the community limelightlib-python library.
|
||||
|
||||
Replace this file with the real LimelightHelpers.py from:
|
||||
https://github.com/LimelightVision/limelightlib-python
|
||||
|
||||
The following methods must be verified to exist in the real library before
|
||||
any Limelight-dependent code is run on the robot (see PLAN.txt section 3):
|
||||
- getBotPoseEstimate_wpiBlue_MegaTag2()
|
||||
- SetIMUMode()
|
||||
- getTargetPose_CameraSpace()
|
||||
- SetRobotOrientation()
|
||||
- SetFiducialIDFiltersOverride()
|
||||
- setPipelineIndex()
|
||||
- getTV()
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from wpimath.geometry import Pose2d
|
||||
|
||||
|
||||
@dataclass
|
||||
class PoseEstimate:
|
||||
pose: Pose2d = field(default_factory=Pose2d)
|
||||
timestampSeconds: float = 0.0
|
||||
tagCount: int = 0
|
||||
isMegaTag2: bool = False
|
||||
|
||||
|
||||
# ── Pose estimation ────────────────────────────────────────────────────────────
|
||||
|
||||
def getBotPoseEstimate_wpiBlue_MegaTag2(limelightName: str) -> PoseEstimate | None:
|
||||
"""Return None (stub — no camera connected in sim)."""
|
||||
return None
|
||||
|
||||
|
||||
def getBotPoseEstimate_wpiBlue(limelightName: str) -> PoseEstimate | None:
|
||||
return None
|
||||
|
||||
|
||||
# ── Robot orientation / IMU ────────────────────────────────────────────────────
|
||||
|
||||
def SetRobotOrientation(
|
||||
limelightName: str,
|
||||
yaw: float,
|
||||
yawRate: float,
|
||||
pitch: float,
|
||||
pitchRate: float,
|
||||
roll: float,
|
||||
rollRate: float,
|
||||
) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def SetIMUMode(limelightName: str, mode: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
# ── Target information ─────────────────────────────────────────────────────────
|
||||
|
||||
def getTV(limelightName: str) -> bool:
|
||||
"""Return False — no targets visible in stub."""
|
||||
return False
|
||||
|
||||
|
||||
def getTargetPose_CameraSpace(limelightName: str) -> list[float]:
|
||||
"""Return empty list — no target in stub."""
|
||||
return []
|
||||
|
||||
|
||||
# ── Pipeline / filter control ──────────────────────────────────────────────────
|
||||
|
||||
def setPipelineIndex(limelightName: str, pipelineIndex: int) -> None:
|
||||
pass
|
||||
|
||||
|
||||
def SetFiducialIDFiltersOverride(limelightName: str, validIDs: list[int]) -> None:
|
||||
pass
|
||||
114
TODOs.md
114
TODOs.md
|
|
@ -1,57 +1,57 @@
|
|||
# Top Priority (for manual shooting functionality by RIT)
|
||||
|
||||
These are the jobs to be completed first, to ensure we have minimal functionality for RIT
|
||||
|
||||
- Add subsystems to robot
|
||||
- Add subsystems to the RobotContainer X
|
||||
|
||||
- Updates to subsystems X
|
||||
- Update launcher wheel to a Neo/SparkMax X
|
||||
|
||||
- Define basic commands for manual fire mode
|
||||
- Y/Top button: Deploy the intake (and run the rollers) X
|
||||
- Could be a single command
|
||||
- Could be 2 commands in sequence
|
||||
|
||||
- B/Right button: Reverse the intake X
|
||||
- Unclear if this should touch the deploy motor. ATM suggest leaving the deploy motor alone
|
||||
|
||||
- A/Bottom button: Retract the intake (and stop the rollers) X
|
||||
|
||||
- D-pad: Set deflector to pre-programmed angle
|
||||
- Suggestion: Implement this once, and make the angle an member variable of the command X
|
||||
|
||||
- Both Triggers: Spin up flywheel (if not already spun up) and then start the kicker. X
|
||||
- Re: Sensing flywheel speed
|
||||
- Could be a time offset (i.e. wait for N seconds for the motor to spin up)
|
||||
- Ideally, check the encoder speed (will need the encoders for auto launch)
|
||||
|
||||
- Define unique IDs and channels for all devices in Constants.java
|
||||
|
||||
- Test all motors and reverse directions if required
|
||||
- Direction flags are present in Constants.java Particular values of concern are marked with TODO comments
|
||||
|
||||
# Secondary priority
|
||||
|
||||
These are to be completed after the top priority tasks. Currently, they focus on getting automatic targeting working.
|
||||
|
||||
- Integrate limelight positioning
|
||||
|
||||
- Integrate automatic aiming
|
||||
|
||||
- Advanced movement functions:
|
||||
- L Bumper: "Nudging" mode:
|
||||
- On press:
|
||||
- Briefly move the robot forward then stop
|
||||
- Trigger nudge at 1 to 2 hz (to be determined, control via constant)
|
||||
- Duty cycle (i.e. what percentage of the time the robot is actively moving) is undefined. Control via constant
|
||||
- On release:
|
||||
- Return to normal driving mode
|
||||
|
||||
- R Bumper: "Trench Maneuver"
|
||||
- On button press/enter:
|
||||
- Move deflector to lowest position
|
||||
- Deploy the intake, no need to start the rollers if not started
|
||||
- On button release/exit:
|
||||
- Return the deflector to its previous state
|
||||
- Restore intake to previous state
|
||||
# Top Priority (for manual shooting functionality by RIT)
|
||||
|
||||
These are the jobs to be completed first, to ensure we have minimal functionality for RIT
|
||||
|
||||
- Add subsystems to robot
|
||||
- Add subsystems to the RobotContainer X
|
||||
|
||||
- Updates to subsystems X
|
||||
- Update launcher wheel to a Neo/SparkMax X
|
||||
|
||||
- Define basic commands for manual fire mode
|
||||
- Y/Top button: Deploy the intake (and run the rollers) X
|
||||
- Could be a single command
|
||||
- Could be 2 commands in sequence
|
||||
|
||||
- B/Right button: Reverse the intake X
|
||||
- Unclear if this should touch the deploy motor. ATM suggest leaving the deploy motor alone
|
||||
|
||||
- A/Bottom button: Retract the intake (and stop the rollers) X
|
||||
|
||||
- D-pad: Set deflector to pre-programmed angle
|
||||
- Suggestion: Implement this once, and make the angle an member variable of the command X
|
||||
|
||||
- Both Triggers: Spin up flywheel (if not already spun up) and then start the kicker. X
|
||||
- Re: Sensing flywheel speed
|
||||
- Could be a time offset (i.e. wait for N seconds for the motor to spin up)
|
||||
- Ideally, check the encoder speed (will need the encoders for auto launch)
|
||||
|
||||
- Define unique IDs and channels for all devices in Constants.java
|
||||
|
||||
- Test all motors and reverse directions if required
|
||||
- Direction flags are present in Constants.java Particular values of concern are marked with TODO comments
|
||||
|
||||
# Secondary priority
|
||||
|
||||
These are to be completed after the top priority tasks. Currently, they focus on getting automatic targeting working.
|
||||
|
||||
- Integrate limelight positioning
|
||||
|
||||
- Integrate automatic aiming
|
||||
|
||||
- Advanced movement functions:
|
||||
- L Bumper: "Nudging" mode:
|
||||
- On press:
|
||||
- Briefly move the robot forward then stop
|
||||
- Trigger nudge at 1 to 2 hz (to be determined, control via constant)
|
||||
- Duty cycle (i.e. what percentage of the time the robot is actively moving) is undefined. Control via constant
|
||||
- On release:
|
||||
- Return to normal driving mode
|
||||
|
||||
- R Bumper: "Trench Maneuver"
|
||||
- On button press/enter:
|
||||
- Move deflector to lowest position
|
||||
- Deploy the intake, no need to start the rollers if not started
|
||||
- On button release/exit:
|
||||
- Return the deflector to its previous state
|
||||
- Restore intake to previous state
|
||||
|
|
|
|||
|
|
@ -1,24 +0,0 @@
|
|||
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.
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
"""
|
||||
autonomous/basic_auto.py
|
||||
|
||||
Fallback MagicBot AutonomousStateMachine used when PathPlanner is unavailable.
|
||||
Deploys the intake, homes the turret, then stops.
|
||||
"""
|
||||
|
||||
import magicbot
|
||||
from magicbot.state_machine import state, timed_state
|
||||
|
||||
from components.drive import DriveComponent
|
||||
from components.intake import IntakeComponent
|
||||
from components.turret import TurretComponent
|
||||
|
||||
|
||||
class BasicAuto(magicbot.AutonomousStateMachine):
|
||||
"""Simple fallback autonomous: deploy intake → home turret → idle."""
|
||||
|
||||
MODE_NAME = "Basic Auto"
|
||||
DEFAULT = False
|
||||
|
||||
# MagicBot injects these
|
||||
drive: DriveComponent
|
||||
intake: IntakeComponent
|
||||
turret: TurretComponent
|
||||
|
||||
@timed_state(first=True, duration=2.0, next_state="home_turret")
|
||||
def deploy_intake(self) -> None:
|
||||
self.intake.deploy()
|
||||
|
||||
@timed_state(duration=3.0, next_state="idle")
|
||||
def home_turret(self) -> None:
|
||||
self.intake.stop_deploy()
|
||||
self.turret.home_turret()
|
||||
|
||||
@state
|
||||
def idle(self) -> None:
|
||||
self.drive.stop_drive()
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
"""
|
||||
autonomous/chassis_align_shoot.py
|
||||
|
||||
commands2.Command that replicates AutoShootCommandChassisTurret.java.
|
||||
|
||||
Uses a PID controller to camera-centre the robot on the HUB AprilTags and
|
||||
dead-reckoning as a fallback. Fires the kicker when centred and launcher is
|
||||
up to speed.
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
import commands2
|
||||
from robotpy_apriltag import AprilTagField, AprilTagFieldLayout
|
||||
from wpilib import DriverStation
|
||||
from wpimath.controller import PIDController
|
||||
from wpimath.geometry import Pose3d
|
||||
|
||||
import constants
|
||||
import LimelightHelpers
|
||||
import utils
|
||||
from components.drive import DriveComponent
|
||||
from components.hopper import HopperComponent
|
||||
from components.turret import TurretComponent
|
||||
|
||||
|
||||
class ChassisAlignShootCommand(commands2.Command):
|
||||
"""
|
||||
Aligns the robot chassis and fires the launcher using camera feedback.
|
||||
Registered with PathPlanner as "ChassisAlignShoot".
|
||||
"""
|
||||
|
||||
_field_tags = AprilTagFieldLayout.loadField(AprilTagField.k2026RebuiltWelded)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
drive: DriveComponent,
|
||||
hopper: HopperComponent,
|
||||
turret: TurretComponent,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._drive = drive
|
||||
self._hopper = hopper
|
||||
self._turret = turret
|
||||
|
||||
self._tag_filters: list[int] = []
|
||||
self._closest_tag: Pose3d | None = None
|
||||
|
||||
# Camera centering PID (units: degrees)
|
||||
self._camera_controller = PIDController(0.15, 0.0, 0.0)
|
||||
self._camera_controller.setTolerance(0.2)
|
||||
self._camera_controller.setSetpoint(0)
|
||||
|
||||
# Dead-reckoning fallback PID (units: radians)
|
||||
self._dead_reckoning_controller = PIDController(math.pi * 0.1, 0, 0.0)
|
||||
self._dead_reckoning_controller.setTolerance(0.2)
|
||||
self._dead_reckoning_controller.enableContinuousInput(-math.pi, math.pi)
|
||||
|
||||
self._chassis_rotate_speed = math.pi * 0.1
|
||||
|
||||
def initialize(self) -> None:
|
||||
alliance = DriverStation.getAlliance()
|
||||
if alliance == DriverStation.Alliance.kBlue:
|
||||
self._tag_filters = constants.CameraConstants.IDFilters.BLUE_HUB_SHOOTING_IDS
|
||||
else:
|
||||
self._tag_filters = constants.CameraConstants.IDFilters.RED_HUB_SHOOTING_IDS
|
||||
|
||||
self._turret.set_launcher(3000)
|
||||
self._turret.set_target_elevation(constants.ShooterConstants.DEFLECTOR_STORED_ANGLE)
|
||||
self._hopper.spindexer_on()
|
||||
# Warm-up the camera PID
|
||||
self._camera_controller.calculate(-100)
|
||||
|
||||
# Switch to HUB-tracking pipeline
|
||||
LimelightHelpers.setPipelineIndex(
|
||||
constants.CameraConstants.BACK_CAMERA_NAME,
|
||||
constants.CameraConstants.BACK_HUB_TRACKING_3D_PIPELINE_NUMBER,
|
||||
)
|
||||
LimelightHelpers.SetFiducialIDFiltersOverride(
|
||||
constants.CameraConstants.BACK_CAMERA_NAME, self._tag_filters
|
||||
)
|
||||
|
||||
# Find the closest HUB AprilTag for dead-reckoning
|
||||
bot_pose = self._drive.get_bot_pose()
|
||||
tag_poses: list[Pose3d] = [
|
||||
pose
|
||||
for tag_id in self._tag_filters
|
||||
if (pose := self._field_tags.getTagPose(tag_id)) is not None
|
||||
]
|
||||
if tag_poses:
|
||||
# Find nearest tag by distance
|
||||
def _dist(tag: Pose3d) -> float:
|
||||
delta = bot_pose.translation().toTranslation2d() - tag.translation().toTranslation2d()
|
||||
return math.hypot(delta.X(), delta.Y())
|
||||
self._closest_tag = min(tag_poses, key=_dist)
|
||||
|
||||
delta = (
|
||||
bot_pose.translation().toTranslation2d()
|
||||
- self._closest_tag.translation().toTranslation2d()
|
||||
)
|
||||
self._dead_reckoning_controller.setSetpoint(
|
||||
math.atan2(delta.Y(), delta.X())
|
||||
)
|
||||
|
||||
def execute(self) -> None:
|
||||
has_target = LimelightHelpers.getTV(constants.CameraConstants.BACK_CAMERA_NAME)
|
||||
|
||||
if not has_target:
|
||||
# ── Dead-reckoning fallback ──────────────────────────────────
|
||||
# (Chassis rotation was commented out in Java source; preserved here)
|
||||
# bot_pose = self._drive.get_bot_pose()
|
||||
# self._drive.rotate_chassis(
|
||||
# -self._dead_reckoning_controller.calculate(
|
||||
# bot_pose.rotation().toRotation2d().radians()
|
||||
# )
|
||||
# )
|
||||
pass
|
||||
else:
|
||||
# ── Camera centering ─────────────────────────────────────────
|
||||
targets_pose = LimelightHelpers.getTargetPose_CameraSpace(
|
||||
constants.CameraConstants.BACK_CAMERA_NAME
|
||||
)
|
||||
if targets_pose and len(targets_pose) >= 3:
|
||||
distance_z = targets_pose[2]
|
||||
tx = targets_pose[0]
|
||||
|
||||
turret_angle = (
|
||||
utils.calculate_turret_angle_from_camera_tag_distance(distance_z)
|
||||
* constants.ShooterConstants.TURRET_GEAR_RATIO
|
||||
)
|
||||
self._turret.set_turret_motor_rotation(-turret_angle)
|
||||
|
||||
self._drive.rotate_chassis(
|
||||
-self._camera_controller.calculate(tx)
|
||||
)
|
||||
|
||||
# Fire when centred and launcher is up to speed
|
||||
if (
|
||||
self._turret.is_launcher_up_to_speed()
|
||||
and self._camera_controller.atSetpoint()
|
||||
):
|
||||
self._hopper.feed_kicker()
|
||||
else:
|
||||
pass # Waiting to fire
|
||||
|
||||
def isFinished(self) -> bool:
|
||||
return False
|
||||
|
||||
def end(self, interrupted: bool) -> None:
|
||||
self._turret.set_launcher(0)
|
||||
self._hopper.stop_kicker()
|
||||
self._hopper.spindexer_off()
|
||||
self._drive.stop_drive()
|
||||
|
||||
LimelightHelpers.setPipelineIndex(
|
||||
constants.CameraConstants.BACK_CAMERA_NAME,
|
||||
constants.CameraConstants.BACK_LOCALIZATION_PIPELINE_NUMBER,
|
||||
)
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
autonomous/turret_shoot.py
|
||||
|
||||
commands2.Command that replicates AutoTurretShootCommand.java.
|
||||
|
||||
Uses distance-based ballistics (Utils.get_hood_angle/launcher_rpm_for_distance)
|
||||
to set the turret launcher speed and hood angle, then fires once ready.
|
||||
"""
|
||||
|
||||
import commands2
|
||||
from wpilib import DriverStation
|
||||
|
||||
import constants
|
||||
import utils
|
||||
from components.drive import DriveComponent
|
||||
from components.hopper import HopperComponent
|
||||
from components.intake import IntakeComponent
|
||||
from components.turret import TurretComponent
|
||||
|
||||
|
||||
class TurretShootCommand(commands2.Command):
|
||||
"""
|
||||
Distance-based auto-shoot command.
|
||||
Registered with PathPlanner as "TurretShoot".
|
||||
"""
|
||||
|
||||
_WAIT_SECONDS: float = 1.5
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hopper: HopperComponent,
|
||||
turret: TurretComponent,
|
||||
intake: IntakeComponent,
|
||||
drive: DriveComponent,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self._hopper = hopper
|
||||
self._turret = turret
|
||||
self._intake = intake
|
||||
self._drive = drive
|
||||
|
||||
self._wait_timer = commands2.WaitCommand(self._WAIT_SECONDS)
|
||||
self._wait_started = False
|
||||
|
||||
def initialize(self) -> None:
|
||||
self._hopper.spindexer_on()
|
||||
self._wait_timer = commands2.WaitCommand(self._WAIT_SECONDS)
|
||||
self._wait_timer.schedule()
|
||||
self._wait_started = True
|
||||
|
||||
def execute(self) -> None:
|
||||
turret_target = self._turret.get_turret_target_pose()
|
||||
bot_pose = self._drive.get_bot_pose()
|
||||
|
||||
if turret_target is not None:
|
||||
target_2d = turret_target.toPose2d().translation()
|
||||
bot_2d = bot_pose.translation().toTranslation2d()
|
||||
distance = target_2d.distance(bot_2d)
|
||||
|
||||
self._turret.set_target_elevation(utils.get_hood_angle_for_distance(distance))
|
||||
self._turret.set_launcher(utils.get_launcher_rpm_for_distance(distance))
|
||||
|
||||
if self._turret.is_launcher_up_to_speed() and self._wait_timer.isFinished():
|
||||
self._hopper.feed_kicker()
|
||||
else:
|
||||
self._hopper.stop_kicker()
|
||||
|
||||
def isFinished(self) -> bool:
|
||||
return False
|
||||
|
||||
def end(self, interrupted: bool) -> None:
|
||||
if self._wait_started:
|
||||
self._wait_timer.cancel()
|
||||
|
||||
self._hopper.spindexer_off()
|
||||
self._hopper.stop_kicker()
|
||||
self._turret.set_launcher(0)
|
||||
self._turret.set_target_elevation(constants.ShooterConstants.DEFLECTOR_STORED_ANGLE)
|
||||
|
||||
# Restore turret target to hub for the current alliance
|
||||
alliance = DriverStation.getAlliance()
|
||||
if alliance == DriverStation.Alliance.kBlue:
|
||||
self._turret.set_turret_target_pose(constants.FieldPoses.BLUE_HUB_POSE)
|
||||
elif alliance == DriverStation.Alliance.kRed:
|
||||
self._turret.set_turret_target_pose(constants.FieldPoses.RED_HUB_POSE)
|
||||
141
build.gradle
141
build.gradle
|
|
@ -1,141 +0,0 @@
|
|||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2026.2.1"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
def ROBOT_MAIN_CLASS = "frc.robot.Main"
|
||||
|
||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||
// This is added by GradleRIO's backing project DeployUtils.
|
||||
deploy {
|
||||
targets {
|
||||
roborio(getTargetTypeClass('RoboRIO')) {
|
||||
// Team number is loaded either from the .wpilib/wpilib_preferences.json
|
||||
// or from command line. If not found an exception will be thrown.
|
||||
// You can use getTeamOrDefault(team) instead of getTeamNumber if you
|
||||
// want to store a team number in this file.
|
||||
team = project.frc.getTeamNumber()
|
||||
debug = project.frc.getDebugOrDefault(false)
|
||||
|
||||
artifacts {
|
||||
// First part is artifact name, 2nd is artifact type
|
||||
// getTargetTypeClass is a shortcut to get the class type using a string
|
||||
|
||||
frcJava(getArtifactTypeClass('FRCJavaArtifact')) {
|
||||
}
|
||||
|
||||
// Static files artifact
|
||||
frcStaticFileDeploy(getArtifactTypeClass('FileTreeArtifact')) {
|
||||
files = project.fileTree('src/main/deploy')
|
||||
directory = '/home/lvuser/deploy'
|
||||
deleteOldFiles = false // Change to true to delete files on roboRIO that no
|
||||
// longer exist in deploy directory of this project
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def deployArtifact = deploy.targets.roborio.artifacts.frcJava
|
||||
|
||||
// Set to true to use debug for all targets including JNI, which will drastically impact
|
||||
// performance.
|
||||
wpi.java.debugJni = false
|
||||
|
||||
// Set this to true to enable desktop support.
|
||||
def includeDesktopSupport = true
|
||||
|
||||
// Defining my dependencies. In this case, WPILib (+ friends), and vendor libraries.
|
||||
// Also defines JUnit 5.
|
||||
dependencies {
|
||||
annotationProcessor wpi.java.deps.wpilibAnnotations()
|
||||
implementation wpi.java.deps.wpilib()
|
||||
implementation wpi.java.vendor.java()
|
||||
|
||||
roborioDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.roborio)
|
||||
roborioDebug wpi.java.vendor.jniDebug(wpi.platforms.roborio)
|
||||
|
||||
roborioRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.roborio)
|
||||
roborioRelease wpi.java.vendor.jniRelease(wpi.platforms.roborio)
|
||||
|
||||
nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
|
||||
nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
|
||||
simulationDebug wpi.sim.enableDebug()
|
||||
|
||||
nativeRelease wpi.java.deps.wpilibJniRelease(wpi.platforms.desktop)
|
||||
nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
|
||||
simulationRelease wpi.sim.enableRelease()
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter:5.10.1'
|
||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
|
||||
}
|
||||
|
||||
// Simulation configuration (e.g. environment variables).
|
||||
wpi.sim.addGui().defaultEnabled = true
|
||||
wpi.sim.addDriverstation()
|
||||
|
||||
// Setting up my Jar File. In this case, adding all libraries into the main jar ('fat jar')
|
||||
// in order to make them all available at runtime. Also adding the manifest so WPILib
|
||||
// knows where to look for our Robot Class.
|
||||
jar {
|
||||
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||
from('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)
|
||||
|
||||
def saveCommitTask = tasks.register("saveCommit") {
|
||||
println "Current Version: " + getCheckedOutGitCommitHash();
|
||||
|
||||
def deployFolder = "$projectDir/src/main/deploy/"
|
||||
def commitFile = new FileWriter(deployFolder + "versionfile.txt");
|
||||
doLast {
|
||||
commitFile.write(getCheckedOutGitCommitHash() + " - " + new Date().toString());
|
||||
commitFile.close();
|
||||
println "versionfile.txt written";
|
||||
}
|
||||
}
|
||||
|
||||
def getCheckedOutGitCommitHash() {
|
||||
def gitFolder = "$projectDir/.git/"
|
||||
def takeFromHash = 12
|
||||
/*
|
||||
* '.git/HEAD' contains either
|
||||
* in case of detached head: the currently checked out commit hash
|
||||
* otherwise: a reference to a file containing the current commit hash
|
||||
*/
|
||||
def head = new File(gitFolder + "HEAD").text.split(":") // .git/HEAD
|
||||
def isCommit = head.length == 1 // e5a7c79edabbf7dd39888442df081b1c9d8e88fd
|
||||
// def isRef = head.length > 1 // ref: refs/heads/master
|
||||
|
||||
if(isCommit) return head[0].trim().take(takeFromHash) // e5a7c79edabb
|
||||
|
||||
def refHead = new File(gitFolder + head[1].trim()) // .git/refs/heads/master
|
||||
refHead.text.trim().take takeFromHash
|
||||
}
|
||||
|
||||
// Configure string concat to always inline compile
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs.add '-XDstringConcat=inline'
|
||||
dependsOn saveCommitTask
|
||||
}
|
||||
|
||||
|
||||
apply from: 'libs.gradle'
|
||||
|
|
@ -0,0 +1,359 @@
|
|||
"""
|
||||
components/controller.py – MagicBot-compatible Xbox controller wrapper.
|
||||
|
||||
XboxController wraps wpilib.XboxController to provide:
|
||||
- Deadband-corrected joystick axes
|
||||
- Edge-detection helpers (was_pressed / pressed) for every button
|
||||
- Integration with MagicBot's component injection system (``port`` attribute)
|
||||
"""
|
||||
|
||||
import wpilib
|
||||
|
||||
|
||||
class XboxController:
|
||||
"""
|
||||
MagicBot component that wraps a wpilib.XboxController.
|
||||
|
||||
MagicBot injects the ``port`` attribute before ``setup()`` is called,
|
||||
so declare it at class level — its value is overridden per-robot in
|
||||
``MyRobot`` via the ``driver_controller_port`` prefixed variable.
|
||||
|
||||
Joystick values are deadband-corrected and cached each loop in
|
||||
``execute()`` so all code within a single loop sees consistent axis values.
|
||||
|
||||
Button helpers follow two patterns:
|
||||
- ``*_pressed()`` – True while the button is held down.
|
||||
- ``*_was_pressed()`` – True on the loop after the button was released
|
||||
(one-shot, resets immediately after reading).
|
||||
"""
|
||||
|
||||
#: Whether to apply deadband correction to raw joystick values.
|
||||
correct_for_deadband: bool = True
|
||||
#: Deadband radius; inputs within ±deadband map to 0.
|
||||
deadband: float = 0.1
|
||||
#: USB port number; injected by MagicBot from ``driver_controller_port``.
|
||||
port: int
|
||||
#: Cached left-stick X axis value (deadband-corrected).
|
||||
left_x: float = 0.0
|
||||
#: Cached left-stick Y axis value (deadband-corrected).
|
||||
left_y: float = 0.0
|
||||
#: Cached right-stick X axis value (deadband-corrected).
|
||||
right_x: float = 0.0
|
||||
#: Cached right-stick Y axis value (deadband-corrected).
|
||||
right_y: float = 0.0
|
||||
|
||||
def setup(self) -> None:
|
||||
"""
|
||||
Setup the Xbox controller.
|
||||
This method is called once when the robot is initialized.
|
||||
"""
|
||||
self.this_controller = wpilib.XboxController(self.port)
|
||||
controller_buttons = [
|
||||
"A",
|
||||
"B",
|
||||
"X",
|
||||
"Y",
|
||||
"DPad_Up",
|
||||
"DPad_Down",
|
||||
"DPad_Left",
|
||||
"DPad_Right",
|
||||
"Left_Bumper",
|
||||
"Right_Bumper",
|
||||
"Left_Trigger",
|
||||
"Right_Trigger",
|
||||
"Start",
|
||||
"Back",
|
||||
]
|
||||
self.button_is_pressed = {button: False for button in controller_buttons}
|
||||
self.button_was_pressed = {button: False for button in controller_buttons}
|
||||
|
||||
def _button_pressed(self, button_name: str, pressed: bool) -> bool:
|
||||
"""
|
||||
Generic method to check if a button is pressed.
|
||||
:param button_name: The name of the button to check.
|
||||
:param pressed: The current state of the button (True if pressed, False otherwise).
|
||||
"""
|
||||
if self.button_is_pressed[button_name] and not pressed:
|
||||
self.button_was_pressed[button_name] = True
|
||||
self.button_is_pressed[button_name] = pressed
|
||||
return pressed
|
||||
|
||||
def _button_was_pressed(self, button_name: str) -> bool:
|
||||
"""
|
||||
Generic method to check if a button was pressed since the last check.
|
||||
:param button_name: The name of the button to check.
|
||||
:return: True if the button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
if self.button_was_pressed[button_name]:
|
||||
self.button_was_pressed[button_name] = False
|
||||
return True
|
||||
return False
|
||||
|
||||
def _corrected_joystick_value(self, raw_value: float) -> float:
|
||||
"""
|
||||
Apply deadband correction to a joystick value.
|
||||
:param raw_value: The raw joystick value.
|
||||
:return: The corrected joystick value.
|
||||
"""
|
||||
if not self.correct_for_deadband:
|
||||
return raw_value
|
||||
if abs(raw_value) < self.deadband:
|
||||
return 0.0
|
||||
return (raw_value / abs(raw_value)) * (
|
||||
(abs(raw_value) - self.deadband) / (1 - self.deadband)
|
||||
)
|
||||
|
||||
def execute(self) -> None:
|
||||
"""
|
||||
Capture the current state of all buttons to track presses.
|
||||
This method should be called at the end of each control loop iteration.
|
||||
"""
|
||||
self.a_button_pressed()
|
||||
self.b_button_pressed()
|
||||
self.x_button_pressed()
|
||||
self.y_button_pressed()
|
||||
self.dpad_up_pressed()
|
||||
self.dpad_down_pressed()
|
||||
self.dpad_left_pressed()
|
||||
self.dpad_right_pressed()
|
||||
self.left_bumper_pressed()
|
||||
self.right_bumper_pressed()
|
||||
self.left_trigger_pressed()
|
||||
self.right_trigger_pressed()
|
||||
self.start_button_pressed()
|
||||
self.back_button_pressed()
|
||||
self.left_y = self._corrected_joystick_value(self.this_controller.getLeftY())
|
||||
self.left_x = self._corrected_joystick_value(self.this_controller.getLeftX())
|
||||
self.right_y = self._corrected_joystick_value(self.this_controller.getRightY())
|
||||
self.right_x = self._corrected_joystick_value(self.this_controller.getRightX())
|
||||
|
||||
def a_button_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the A button is pressed.
|
||||
|
||||
:return: True if the A button is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("A", self.this_controller.getAButton())
|
||||
|
||||
def a_button_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the A button was pressed since the last check.
|
||||
|
||||
:return: True if the A button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("A")
|
||||
|
||||
def b_button_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the B button is pressed.
|
||||
:return: True if the B button is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("B", self.this_controller.getBButton())
|
||||
|
||||
def b_button_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the B button was pressed since the last check.
|
||||
|
||||
:return: True if the B button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("B")
|
||||
|
||||
def x_button_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the X button is pressed.
|
||||
|
||||
:return: True if the X button is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("X", self.this_controller.getXButton())
|
||||
|
||||
def x_button_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the X button was pressed since the last check.
|
||||
|
||||
:return: True if the X button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("X")
|
||||
|
||||
def y_button_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the Y button is pressed.
|
||||
|
||||
:return: True if the Y button is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("Y", self.this_controller.getYButton())
|
||||
|
||||
def y_button_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the Y button was pressed since the last check.
|
||||
|
||||
:return: True if the Y button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Y")
|
||||
|
||||
def dpad_up_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad is pressed up.
|
||||
|
||||
:return: True if the D-pad is pressed up, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("DPad_Up", self.this_controller.getPOV() == 0)
|
||||
|
||||
def dpad_up_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad was pressed up since the last check.
|
||||
|
||||
:return: True if the the D-pad was pressed up since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("DPad_Up")
|
||||
|
||||
def dpad_down_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad is pressed down.
|
||||
|
||||
:return: True if the D-pad is pressed down, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("DPad_Down", self.this_controller.getPOV() == 180)
|
||||
|
||||
def dpad_down_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad was pressed down since the last check.
|
||||
|
||||
:return: True if the the D-pad was pressed down since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("DPad_Down")
|
||||
|
||||
def dpad_left_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad is pressed left.
|
||||
|
||||
:return: True if the D-pad is pressed left, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("DPad_Left", self.this_controller.getPOV() == 270)
|
||||
|
||||
def dpad_left_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad was pressed left since the last check.
|
||||
|
||||
:return: True if the the D-pad was pressed left since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("DPad_Left")
|
||||
|
||||
def dpad_right_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad is pressed right.
|
||||
|
||||
:return: True if the D-pad is pressed right, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("DPad_Right", self.this_controller.getPOV() == 90)
|
||||
|
||||
def dpad_right_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the D-pad was pressed right since the last check.
|
||||
|
||||
:return: True if the the D-pad was pressed right since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("DPad_Right")
|
||||
|
||||
def left_bumper_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the left bumper is pressed.
|
||||
|
||||
:return: True if the left bumper is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("Left_Bumper", self.this_controller.getLeftBumper())
|
||||
|
||||
def left_bumper_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the left bumper was pressed since the last check.
|
||||
|
||||
:return: True if the left bumper was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Left_Bumper")
|
||||
|
||||
def right_bumper_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the right bumper is pressed.
|
||||
|
||||
:return: True if the right bumper is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed(
|
||||
"Right_Bumper", self.this_controller.getRightBumper()
|
||||
)
|
||||
|
||||
def right_bumper_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the right bumper was pressed since the last check.
|
||||
|
||||
:return: True if the right bumper was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Right_Bumper")
|
||||
|
||||
def left_trigger_pressed(self) -> float:
|
||||
"""
|
||||
Get the value of the left trigger.
|
||||
|
||||
:return: The value of the left trigger, ranging from 0.0 to 1.0.
|
||||
"""
|
||||
self._button_pressed(
|
||||
"Left_Trigger", self.this_controller.getLeftTriggerAxis() >= 0.5
|
||||
)
|
||||
return self.this_controller.getLeftTriggerAxis()
|
||||
|
||||
def left_trigger_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the left trigger was pressed since the last check.
|
||||
|
||||
:return: True if the left trigger was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Left_Trigger")
|
||||
|
||||
def right_trigger_pressed(self) -> float:
|
||||
"""
|
||||
Get the value of the right trigger.
|
||||
|
||||
:return: The value of the right trigger, ranging from 0.0 to 1.0.
|
||||
"""
|
||||
self._button_pressed(
|
||||
"Right_Trigger", self.this_controller.getRightTriggerAxis() >= 0.5
|
||||
)
|
||||
return self.this_controller.getRightTriggerAxis()
|
||||
|
||||
def right_trigger_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the right trigger was pressed since the last check.
|
||||
|
||||
:return: True if the right trigger was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Right_Trigger")
|
||||
|
||||
def start_button_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the start button is pressed.
|
||||
|
||||
:return: True if the start button is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("Start", self.this_controller.getStartButton())
|
||||
|
||||
def start_button_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the start button was pressed since the last check.
|
||||
|
||||
:return: True if the start button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Start")
|
||||
|
||||
def back_button_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the back button is pressed.
|
||||
|
||||
:return: True if the back button is pressed, False otherwise.
|
||||
"""
|
||||
return self._button_pressed("Back", self.this_controller.getBackButton())
|
||||
|
||||
def back_button_was_pressed(self) -> bool:
|
||||
"""
|
||||
Check if the back button was pressed since the last check.
|
||||
|
||||
:return: True if the back button was pressed since the last check, False otherwise.
|
||||
"""
|
||||
return self._button_was_pressed("Back")
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
"""
|
||||
components/drive.py – DriveSubsystem ported to MagicBot component.
|
||||
|
||||
Owns four SwerveModule instances. All swerve math uses standard wpimath.
|
||||
Integrates with PathPlannerLib and Limelight vision.
|
||||
"""
|
||||
|
||||
import math
|
||||
import os
|
||||
|
||||
import magicbot
|
||||
from pathplannerlib.auto import AutoBuilder
|
||||
from pathplannerlib.config import PIDConstants, RobotConfig
|
||||
from pathplannerlib.controller import PPHolonomicDriveController
|
||||
from pathplannerlib.logging import PathPlannerLogging
|
||||
from phoenix6.hardware import Pigeon2
|
||||
from wpilib import DriverStation, RobotState, SendableChooser, SmartDashboard, getDeployDirectory
|
||||
from wpimath.estimator import SwerveDrive4PoseEstimator
|
||||
from wpimath.geometry import Pose2d, Pose3d
|
||||
from wpimath.kinematics import (
|
||||
ChassisSpeeds,
|
||||
SwerveDrive4Kinematics,
|
||||
)
|
||||
|
||||
import constants
|
||||
import LimelightHelpers
|
||||
from components.swerve_module import SwerveModule
|
||||
|
||||
|
||||
class DriveComponent:
|
||||
"""
|
||||
MagicBot component that drives four swerve modules and fuses vision
|
||||
measurements via a SwerveDrive4PoseEstimator.
|
||||
"""
|
||||
|
||||
def setup(self) -> None:
|
||||
# ── Swerve modules ─────────────────────────────────────────────────
|
||||
self._front_left = SwerveModule(
|
||||
name="Front Left",
|
||||
drive_id=constants.SwerveDriveIDs.FRONT_LEFT_DRIVE_ID,
|
||||
steer_id=constants.SwerveDriveIDs.FRONT_LEFT_STEER_ID,
|
||||
encoder_id=constants.SwerveDriveIDs.FRONT_LEFT_ENCODER_ID,
|
||||
steer_offset_rotations=constants.SwerveDriveOffsets.FRONT_LEFT_MOTOR_OFFSET,
|
||||
drive_inverted=False,
|
||||
canbus="Drive",
|
||||
)
|
||||
self._front_right = SwerveModule(
|
||||
name="Front Right",
|
||||
drive_id=constants.SwerveDriveIDs.FRONT_RIGHT_DRIVE_ID,
|
||||
steer_id=constants.SwerveDriveIDs.FRONT_RIGHT_STEER_ID,
|
||||
encoder_id=constants.SwerveDriveIDs.FRONT_RIGHT_ENCODER_ID,
|
||||
steer_offset_rotations=constants.SwerveDriveOffsets.FRONT_RIGHT_MOTOR_OFFSET,
|
||||
drive_inverted=True, # Front Right is inverted
|
||||
canbus="Drive",
|
||||
)
|
||||
self._back_left = SwerveModule(
|
||||
name="Back Left",
|
||||
drive_id=constants.SwerveDriveIDs.BACK_LEFT_DRIVE_ID,
|
||||
steer_id=constants.SwerveDriveIDs.BACK_LEFT_STEER_ID,
|
||||
encoder_id=constants.SwerveDriveIDs.BACK_LEFT_ENCODER_ID,
|
||||
steer_offset_rotations=constants.SwerveDriveOffsets.BACK_LEFT_MOTOR_OFFSET,
|
||||
drive_inverted=False,
|
||||
canbus="Drive",
|
||||
)
|
||||
self._back_right = SwerveModule(
|
||||
name="Back Right",
|
||||
drive_id=constants.SwerveDriveIDs.BACK_RIGHT_DRIVE_ID,
|
||||
steer_id=constants.SwerveDriveIDs.BACK_RIGHT_STEER_ID,
|
||||
encoder_id=constants.SwerveDriveIDs.BACK_RIGHT_ENCODER_ID,
|
||||
steer_offset_rotations=constants.SwerveDriveOffsets.BACK_RIGHT_MOTOR_OFFSET,
|
||||
drive_inverted=True, # Back Right is inverted
|
||||
canbus="Drive",
|
||||
)
|
||||
self._modules = [
|
||||
self._front_left,
|
||||
self._front_right,
|
||||
self._back_left,
|
||||
self._back_right,
|
||||
]
|
||||
|
||||
# ── Kinematics ─────────────────────────────────────────────────────
|
||||
self._kinematics = SwerveDrive4Kinematics(
|
||||
constants.SwerveDriveModuleLocations.FRONT_LEFT,
|
||||
constants.SwerveDriveModuleLocations.FRONT_RIGHT,
|
||||
constants.SwerveDriveModuleLocations.BACK_LEFT,
|
||||
constants.SwerveDriveModuleLocations.BACK_RIGHT,
|
||||
)
|
||||
|
||||
# ── Gyro ───────────────────────────────────────────────────────────
|
||||
self._pigeon = Pigeon2(constants.ExtraIDEntities.PIGEON_ID, "Drive")
|
||||
|
||||
# ── Pose estimator ─────────────────────────────────────────────────
|
||||
self._pose_estimator = SwerveDrive4PoseEstimator(
|
||||
self._kinematics,
|
||||
self._pigeon.getRotation2d(),
|
||||
self._module_positions(),
|
||||
Pose2d(),
|
||||
)
|
||||
# 3 std-dev values: (x_std, y_std, heading_std)
|
||||
self._pose_estimator.setVisionMeasurementStdDevs((0.7, 0.7, 0.1))
|
||||
|
||||
# ── Desired chassis speeds (reset each loop) ────────────────────────
|
||||
self._desired_speeds = ChassisSpeeds()
|
||||
|
||||
# ── PathPlanner target pose (for @feedback) ────────────────────────
|
||||
self._pp_target_pose = Pose2d()
|
||||
|
||||
# ── PathPlanner / AutoBuilder ──────────────────────────────────────
|
||||
# _DriveSubsystemAdapter is imported from robot.py at runtime to
|
||||
# avoid circular imports; it is passed in via inject_drive_adapter().
|
||||
self._drive_adapter = None
|
||||
self._auto_chooser: SendableChooser | None = None
|
||||
|
||||
def inject_drive_adapter(self, adapter, robot_config: RobotConfig) -> None:
|
||||
"""
|
||||
Called by robot.py after all objects are constructed.
|
||||
Finalises AutoBuilder configuration and builds the auto chooser.
|
||||
"""
|
||||
AutoBuilder.configure(
|
||||
self.get_robot_pose_2d, # pose supplier
|
||||
self.set_pose, # pose resetter
|
||||
self.get_robot_relative_speeds, # speeds supplier
|
||||
lambda speeds, ff: self.set_chassis_speeds(speeds), # consumer (no negation)
|
||||
PPHolonomicDriveController(
|
||||
PIDConstants(5, 0, 0),
|
||||
PIDConstants(math.pi, 0, 0),
|
||||
),
|
||||
robot_config,
|
||||
self._is_red_alliance, # flip-path predicate
|
||||
adapter, # dummy Subsystem
|
||||
)
|
||||
|
||||
# Build auto chooser manually so a bad path file skips that auto instead
|
||||
# of crashing the entire chooser (PathPlanner throws ZeroDivisionError on
|
||||
# paths with consecutive rotation targets at the same point).
|
||||
autos_dir = os.path.join(getDeployDirectory(), "pathplanner", "autos")
|
||||
self._auto_chooser = SendableChooser()
|
||||
self._auto_chooser.setDefaultOption("Do Nothing", None)
|
||||
if os.path.isdir(autos_dir):
|
||||
for filename in os.listdir(autos_dir):
|
||||
auto_name = filename.removesuffix(".auto")
|
||||
try:
|
||||
self._auto_chooser.addOption(auto_name, AutoBuilder.buildAuto(auto_name))
|
||||
except Exception as build_err:
|
||||
SmartDashboard.putString(f"Auto/{auto_name} error", str(build_err))
|
||||
SmartDashboard.putData("Auto Chooser", self._auto_chooser)
|
||||
|
||||
PathPlannerLogging.setLogTargetPoseCallback(
|
||||
lambda pose: setattr(self, "_pp_target_pose", pose)
|
||||
)
|
||||
|
||||
# ── Public drive API ───────────────────────────────────────────────────────
|
||||
|
||||
def set_chassis_speeds_field_relative(
|
||||
self, vx: float, vy: float, omega: float
|
||||
) -> None:
|
||||
"""
|
||||
Convert joystick inputs (with quadratic scaling) to robot-relative
|
||||
ChassisSpeeds and store them to be applied in execute().
|
||||
"""
|
||||
scaled_vx = vx * abs(vx) * constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY
|
||||
scaled_vy = vy * abs(vy) * constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY
|
||||
scaled_omega = omega * abs(omega) * constants.RobotChassisLimits.MAX_ROBOT_ANGULAR_VELOCITY
|
||||
|
||||
self._desired_speeds = ChassisSpeeds.fromFieldRelativeSpeeds(
|
||||
scaled_vx,
|
||||
scaled_vy,
|
||||
scaled_omega,
|
||||
self._pigeon.getRotation2d(),
|
||||
)
|
||||
|
||||
def set_chassis_speeds(self, speeds: ChassisSpeeds) -> None:
|
||||
"""Direct robot-relative speed input (used by PathPlanner consumer)."""
|
||||
self._desired_speeds = speeds
|
||||
|
||||
def stop_drive(self) -> None:
|
||||
self._desired_speeds = ChassisSpeeds()
|
||||
|
||||
def rotate_chassis(self, rot_speed: float) -> None:
|
||||
self._desired_speeds = ChassisSpeeds.fromRobotRelativeSpeeds(
|
||||
0, 0, rot_speed, self._pigeon.getRotation2d()
|
||||
)
|
||||
|
||||
def get_bot_pose(self) -> Pose3d:
|
||||
return Pose3d(self._pose_estimator.getEstimatedPosition())
|
||||
|
||||
def get_robot_pose_2d(self) -> Pose2d:
|
||||
return self._pose_estimator.getEstimatedPosition()
|
||||
|
||||
def get_robot_relative_speeds(self) -> ChassisSpeeds:
|
||||
states = self._module_states()
|
||||
return self._kinematics.toChassisSpeeds(states)
|
||||
|
||||
def set_pose(self, pose: Pose2d) -> None:
|
||||
self._pose_estimator.resetPosition(
|
||||
self._pigeon.getRotation2d(),
|
||||
self._module_positions(),
|
||||
pose,
|
||||
)
|
||||
|
||||
def set_brake_mode(self, brake: bool) -> None:
|
||||
from phoenix6.configs import MotorOutputConfigs
|
||||
from phoenix6.signals import NeutralModeValue
|
||||
mode = NeutralModeValue.BRAKE if brake else NeutralModeValue.COAST
|
||||
for module in self._modules:
|
||||
cfg = MotorOutputConfigs().with_neutral_mode(mode)
|
||||
module._drive_motor.configurator.apply(cfg)
|
||||
module._steer_motor.configurator.apply(cfg)
|
||||
|
||||
def get_auto_command(self):
|
||||
if self._auto_chooser is not None:
|
||||
return self._auto_chooser.getSelected()
|
||||
return None
|
||||
|
||||
# ── @feedback properties ───────────────────────────────────────────────────
|
||||
|
||||
@magicbot.feedback
|
||||
def robot_x(self) -> float:
|
||||
return self._pose_estimator.getEstimatedPosition().X()
|
||||
|
||||
@magicbot.feedback
|
||||
def robot_y(self) -> float:
|
||||
return self._pose_estimator.getEstimatedPosition().Y()
|
||||
|
||||
@magicbot.feedback
|
||||
def robot_heading_degrees(self) -> float:
|
||||
return self._pose_estimator.getEstimatedPosition().rotation().degrees()
|
||||
|
||||
@magicbot.feedback
|
||||
def pathplanner_target_x(self) -> float:
|
||||
return self._pp_target_pose.X()
|
||||
|
||||
@magicbot.feedback
|
||||
def pathplanner_target_y(self) -> float:
|
||||
return self._pp_target_pose.Y()
|
||||
|
||||
# ── MagicBot lifecycle ─────────────────────────────────────────────────────
|
||||
|
||||
def execute(self) -> None:
|
||||
# Apply desired speeds through kinematics
|
||||
module_states = self._kinematics.toSwerveModuleStates(self._desired_speeds)
|
||||
|
||||
# Desaturate wheel speeds to enforce linear velocity limit
|
||||
SwerveDrive4Kinematics.desaturateWheelSpeeds(
|
||||
module_states,
|
||||
constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY,
|
||||
)
|
||||
|
||||
# Send states to modules
|
||||
for module, state in zip(self._modules, module_states):
|
||||
module.set_desired_state(state)
|
||||
|
||||
# Reset desired speeds so the robot stops if nothing sets them this loop
|
||||
self._desired_speeds = ChassisSpeeds()
|
||||
|
||||
# Update pose estimator with gyro + module positions
|
||||
self._pose_estimator.update(
|
||||
self._pigeon.getRotation2d(),
|
||||
self._module_positions(),
|
||||
)
|
||||
|
||||
heading_deg = self.get_robot_pose_2d().rotation().degrees()
|
||||
|
||||
# Update Limelight orientation so MegaTag2 knows where the robot is facing
|
||||
LimelightHelpers.SetRobotOrientation(
|
||||
constants.CameraConstants.FRONT_CAMERA_NAME, heading_deg, 0, 0, 0, 0, 0
|
||||
)
|
||||
LimelightHelpers.SetRobotOrientation(
|
||||
constants.CameraConstants.BACK_CAMERA_NAME, heading_deg, 0, 0, 0, 0, 0
|
||||
)
|
||||
|
||||
# IMU mode: 1 when disabled (external), 4 when enabled (fused)
|
||||
imu_mode = 1 if RobotState.isDisabled() else 4
|
||||
LimelightHelpers.SetIMUMode(constants.CameraConstants.FRONT_CAMERA_NAME, imu_mode)
|
||||
LimelightHelpers.SetIMUMode(constants.CameraConstants.BACK_CAMERA_NAME, imu_mode)
|
||||
|
||||
# MegaTag2 vision fusion
|
||||
front_estimate = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(
|
||||
constants.CameraConstants.FRONT_CAMERA_NAME
|
||||
)
|
||||
back_estimate = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(
|
||||
constants.CameraConstants.BACK_CAMERA_NAME
|
||||
)
|
||||
|
||||
if front_estimate is not None and front_estimate.tagCount >= 2:
|
||||
self._pose_estimator.addVisionMeasurement(
|
||||
front_estimate.pose,
|
||||
front_estimate.timestampSeconds,
|
||||
)
|
||||
|
||||
if back_estimate is not None and back_estimate.tagCount >= 2:
|
||||
self._pose_estimator.addVisionMeasurement(
|
||||
back_estimate.pose,
|
||||
back_estimate.timestampSeconds,
|
||||
)
|
||||
|
||||
# Publish per-module telemetry
|
||||
for module in self._modules:
|
||||
module.publish_telemetry()
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
def _module_positions(self):
|
||||
fl, fr, bl, br = self._modules
|
||||
return (fl.get_position(), fr.get_position(), bl.get_position(), br.get_position())
|
||||
|
||||
def _module_states(self):
|
||||
fl, fr, bl, br = self._modules
|
||||
return (fl.get_state(), fr.get_state(), bl.get_state(), br.get_state())
|
||||
|
||||
@staticmethod
|
||||
def _is_red_alliance() -> bool:
|
||||
alliance = DriverStation.getAlliance()
|
||||
if alliance:
|
||||
return alliance == DriverStation.Alliance.kRed
|
||||
return False
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
"""
|
||||
components/hopper.py – HopperSubsystem ported to MagicBot component.
|
||||
|
||||
Hardware:
|
||||
- TalonFX spindexer motor
|
||||
- TalonFX kicker motor
|
||||
"""
|
||||
|
||||
import magicbot
|
||||
from phoenix6.configs import MotorOutputConfigs, Slot0Configs, TalonFXConfiguration
|
||||
from phoenix6.hardware import TalonFX
|
||||
|
||||
import constants
|
||||
|
||||
|
||||
class HopperComponent:
|
||||
"""MagicBot component that controls the hopper (spindexer + kicker)."""
|
||||
|
||||
def setup(self) -> None:
|
||||
"""
|
||||
MagicBot lifecycle hook — instantiate and configure all hopper hardware.
|
||||
|
||||
Called once by MagicBot after all component objects are created but
|
||||
before the robot enters any enabled mode.
|
||||
"""
|
||||
# ── Spindexer ──────────────────────────────────────────────────────
|
||||
self._spindexer_motor = TalonFX(constants.HopperConstants.SPINDEXER_MOTOR_ID)
|
||||
spindexer_cfg = TalonFXConfiguration()
|
||||
spindexer_cfg.motor_output = MotorOutputConfigs().with_inverted(
|
||||
constants.HopperConstants.SPINDEXER_MOTOR_DIRECTION
|
||||
)
|
||||
spindexer_cfg.slot0 = Slot0Configs().with_k_p(0).with_k_i(0).with_k_d(0).with_k_s(0)
|
||||
self._spindexer_motor.configurator.apply(spindexer_cfg)
|
||||
|
||||
# ── Kicker ─────────────────────────────────────────────────────────
|
||||
self._kicker_motor = TalonFX(constants.HopperConstants.KICKER_MOTOR_ID)
|
||||
kicker_cfg = TalonFXConfiguration()
|
||||
kicker_cfg.motor_output = MotorOutputConfigs().with_inverted(
|
||||
constants.HopperConstants.KICKER_MOTOR_DIRECTION
|
||||
)
|
||||
kicker_cfg.slot0 = Slot0Configs().with_k_p(0).with_k_i(0).with_k_d(0).with_k_s(0)
|
||||
self._kicker_motor.configurator.apply(kicker_cfg)
|
||||
|
||||
self._kicker_velocity = self._kicker_motor.get_velocity()
|
||||
|
||||
# ── Public API ─────────────────────────────────────────────────────────────
|
||||
|
||||
def feed_kicker(self) -> None:
|
||||
"""Drive the kicker motor forward at 75 % output to push a note into the launcher."""
|
||||
self._kicker_motor.set(0.75)
|
||||
|
||||
def reverse_kicker(self) -> None:
|
||||
"""Drive the kicker motor in reverse at 50 % output to un-jam a stuck note."""
|
||||
self._kicker_motor.set(-0.5)
|
||||
|
||||
def stop_kicker(self) -> None:
|
||||
"""Stop the kicker motor."""
|
||||
self._kicker_motor.stop_motor()
|
||||
|
||||
def spindexer_on(self) -> None:
|
||||
"""Drive the spindexer forward at 75 % output to advance notes toward the kicker."""
|
||||
self._spindexer_motor.set(0.75)
|
||||
|
||||
def spindexer_reverse(self) -> None:
|
||||
"""Drive the spindexer in reverse at 75 % output to clear a jam."""
|
||||
self._spindexer_motor.set(-0.75)
|
||||
|
||||
def spindexer_off(self) -> None:
|
||||
"""Stop the spindexer motor."""
|
||||
self._spindexer_motor.stop_motor()
|
||||
|
||||
# ── Telemetry ──────────────────────────────────────────────────────────────
|
||||
|
||||
@magicbot.feedback
|
||||
def kicker_speed_rps(self) -> float:
|
||||
return self._kicker_velocity.refresh().value_as_double
|
||||
|
||||
# ── MagicBot lifecycle ─────────────────────────────────────────────────────
|
||||
|
||||
def execute(self) -> None:
|
||||
# No periodic logic required; all control is driven by external callers.
|
||||
pass
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
"""
|
||||
components/intake.py – IntakeSubsystem ported to MagicBot component.
|
||||
|
||||
Hardware:
|
||||
- TalonFX intake motor (Phoenix 6)
|
||||
- WPI_TalonSRX deploy motor (Phoenix 5) with forward/reverse limit switches
|
||||
"""
|
||||
|
||||
import wpilib
|
||||
from phoenix5 import LimitSwitchNormal, LimitSwitchSource, WPI_TalonSRX
|
||||
from phoenix6.configs import MotorOutputConfigs, TalonFXConfiguration
|
||||
from phoenix6.hardware import TalonFX
|
||||
|
||||
import constants
|
||||
|
||||
|
||||
class IntakeComponent:
|
||||
"""MagicBot component that controls the intake and deploy mechanism."""
|
||||
|
||||
def setup(self) -> None:
|
||||
# ── Intake motor (Phoenix 6 TalonFX) ───────────────────────────────
|
||||
self._intake_motor = TalonFX(constants.IntakeConstants.INTAKE_MOTOR_ID)
|
||||
intake_cfg = TalonFXConfiguration()
|
||||
intake_cfg.motor_output = MotorOutputConfigs().with_inverted(
|
||||
constants.IntakeConstants.INTAKE_MOTOR_DIRECTION
|
||||
)
|
||||
self._intake_motor.configurator.apply(intake_cfg)
|
||||
|
||||
# ── Deploy motor (Phoenix 5 WPI_TalonSRX) ──────────────────────────
|
||||
self._deploy_motor = WPI_TalonSRX(constants.IntakeConstants.DEPLOY_MOTOR_ID)
|
||||
self._deploy_motor.configForwardLimitSwitchSource(
|
||||
LimitSwitchSource.FeedbackConnector, LimitSwitchNormal.NormallyOpen
|
||||
)
|
||||
self._deploy_motor.configReverseLimitSwitchSource(
|
||||
LimitSwitchSource.FeedbackConnector, LimitSwitchNormal.NormallyOpen
|
||||
)
|
||||
self._deploy_motor.setInverted(constants.IntakeConstants.DEPLOY_MOTOR_INVERTED)
|
||||
|
||||
# Controller reference — injected by robot.py after setup
|
||||
self._controller: wpilib.XboxController | None = None
|
||||
|
||||
# ── Public API ─────────────────────────────────────────────────────────────
|
||||
|
||||
def set_controller(self, controller: wpilib.XboxController) -> None:
|
||||
"""Inject the driver Xbox controller for rumble feedback."""
|
||||
self._controller = controller
|
||||
|
||||
def deploy(self) -> None:
|
||||
"""Run the deploy motor forward briefly (call once; timing handled externally)."""
|
||||
self._deploy_motor.set(1.0)
|
||||
|
||||
def stop_deploy(self) -> None:
|
||||
self._deploy_motor.stopMotor()
|
||||
|
||||
def reset_deploy(self) -> None:
|
||||
"""Retract the intake deploy mechanism."""
|
||||
self._deploy_motor.set(-1.0)
|
||||
|
||||
def set_speed(self, speed: float) -> None:
|
||||
self._intake_motor.set(speed)
|
||||
|
||||
def stop_intake(self) -> None:
|
||||
self._intake_motor.stopMotor()
|
||||
if self._controller is not None:
|
||||
self._controller.setRumble(wpilib.XboxController.RumbleType.kBothRumble, 0.0)
|
||||
|
||||
def intake(self) -> None:
|
||||
"""Toggle intake on/off with controller rumble feedback."""
|
||||
if self._intake_motor.get() == 0:
|
||||
self.set_speed(-0.5)
|
||||
if self._controller is not None:
|
||||
self._controller.setRumble(wpilib.XboxController.RumbleType.kBothRumble, 0.5)
|
||||
else:
|
||||
self._intake_motor.stopMotor()
|
||||
if self._controller is not None:
|
||||
self._controller.setRumble(wpilib.XboxController.RumbleType.kBothRumble, 0.0)
|
||||
|
||||
def reverse_intake(self) -> None:
|
||||
self.set_speed(0.5)
|
||||
|
||||
# ── MagicBot lifecycle ─────────────────────────────────────────────────────
|
||||
|
||||
def execute(self) -> None:
|
||||
pass
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
"""
|
||||
components/swerve_module.py – Plain Python class (NOT a MagicBot component).
|
||||
|
||||
Four instances are owned by DriveComponent. Encapsulates all per-module hardware:
|
||||
- phoenix6 TalonFX drive motor
|
||||
- phoenix6 TalonFX steer motor
|
||||
- phoenix6 CANcoder
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
import ntcore
|
||||
from phoenix6.configs import (
|
||||
CANcoderConfiguration,
|
||||
FeedbackConfigs,
|
||||
MagnetSensorConfigs,
|
||||
MotorOutputConfigs,
|
||||
Slot0Configs,
|
||||
TalonFXConfiguration,
|
||||
)
|
||||
from phoenix6.controls import PositionVoltage, VelocityVoltage
|
||||
from phoenix6.hardware import CANcoder, TalonFX
|
||||
from phoenix6.signals import (
|
||||
FeedbackSensorSourceValue,
|
||||
InvertedValue,
|
||||
SensorDirectionValue,
|
||||
)
|
||||
from wpimath.geometry import Rotation2d
|
||||
from wpimath.kinematics import SwerveModulePosition, SwerveModuleState
|
||||
|
||||
# Physical constants shared by all modules
|
||||
GEAR_RATIO: float = 8.14
|
||||
WHEEL_DIAMETER_METERS: float = 0.1016 # 4 inches
|
||||
WHEEL_CIRCUMFERENCE_METERS: float = WHEEL_DIAMETER_METERS * 3.14159265358979
|
||||
|
||||
|
||||
class SwerveModule:
|
||||
"""
|
||||
Plain Python class (not a MagicBot component).
|
||||
Encapsulates a single swerve module: drive motor, steer motor, CANcoder.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
drive_id: int,
|
||||
steer_id: int,
|
||||
encoder_id: int,
|
||||
steer_offset_rotations: float,
|
||||
drive_inverted: bool,
|
||||
canbus: str = "Drive",
|
||||
) -> None:
|
||||
self._name = name
|
||||
|
||||
# ── CANcoder ───────────────────────────────────────────────────────
|
||||
self._encoder = CANcoder(encoder_id, canbus)
|
||||
encoder_cfg = CANcoderConfiguration()
|
||||
encoder_cfg.magnet_sensor = (
|
||||
MagnetSensorConfigs()
|
||||
.with_magnet_offset(steer_offset_rotations)
|
||||
.with_sensor_direction(SensorDirectionValue.COUNTER_CLOCKWISE_POSITIVE)
|
||||
)
|
||||
self._encoder.configurator.apply(encoder_cfg)
|
||||
|
||||
# ── Drive motor (TalonFX) ──────────────────────────────────────────
|
||||
self._drive_motor = TalonFX(drive_id, canbus)
|
||||
drive_cfg = TalonFXConfiguration()
|
||||
drive_cfg.slot0 = (
|
||||
Slot0Configs()
|
||||
.with_k_p(0.1)
|
||||
.with_k_i(0.0)
|
||||
.with_k_d(0.01)
|
||||
.with_k_v(0.2)
|
||||
)
|
||||
drive_cfg.motor_output = MotorOutputConfigs().with_inverted(
|
||||
InvertedValue.CLOCKWISE_POSITIVE if drive_inverted else InvertedValue.COUNTER_CLOCKWISE_POSITIVE
|
||||
)
|
||||
self._drive_motor.configurator.apply(drive_cfg)
|
||||
self._drive_velocity_signal = self._drive_motor.get_velocity()
|
||||
self._drive_position_signal = self._drive_motor.get_position()
|
||||
|
||||
# ── Steer motor (TalonFX) ──────────────────────────────────────────
|
||||
self._steer_motor = TalonFX(steer_id, canbus)
|
||||
steer_cfg = TalonFXConfiguration()
|
||||
steer_cfg.slot0 = (
|
||||
Slot0Configs()
|
||||
.with_k_p(20)
|
||||
.with_k_i(0)
|
||||
.with_k_d(0.0)
|
||||
.with_k_v(0)
|
||||
)
|
||||
# Use the CANcoder as the absolute feedback source for the steer motor
|
||||
steer_cfg.feedback = (
|
||||
FeedbackConfigs()
|
||||
.with_feedback_remote_sensor_id(encoder_id)
|
||||
.with_feedback_sensor_source(FeedbackSensorSourceValue.REMOTE_CANCODER)
|
||||
)
|
||||
self._steer_motor.configurator.apply(steer_cfg)
|
||||
self._steer_position_signal = self._steer_motor.get_position()
|
||||
|
||||
# Controls
|
||||
self._drive_control = VelocityVoltage(0)
|
||||
self._steer_control = PositionVoltage(0)
|
||||
|
||||
# Desired state (for telemetry)
|
||||
self._desired_state = SwerveModuleState(0, Rotation2d())
|
||||
|
||||
# ── NetworkTables telemetry entries ────────────────────────────────
|
||||
inst = ntcore.NetworkTableInstance.getDefault()
|
||||
tbl = inst.getTable(f"SwerveModules/{name}")
|
||||
self._nt_desired_speed = tbl.getDoubleTopic("desired_speed_mps").publish()
|
||||
self._nt_desired_angle = tbl.getDoubleTopic("desired_angle_deg").publish()
|
||||
self._nt_actual_speed = tbl.getDoubleTopic("actual_speed_mps").publish()
|
||||
self._nt_actual_angle = tbl.getDoubleTopic("actual_angle_deg").publish()
|
||||
|
||||
# ── Public API ─────────────────────────────────────────────────────────────
|
||||
|
||||
def set_desired_state(self, state: SwerveModuleState) -> None:
|
||||
"""Optimize the state and apply drive velocity + steer position controls."""
|
||||
state.optimize(self._get_steer_angle()) # mutates in-place; returns None in WPILib 2026
|
||||
self._desired_state = state
|
||||
|
||||
# Drive: convert m/s → rotations/s
|
||||
drive_rps = (state.speed / WHEEL_CIRCUMFERENCE_METERS) * GEAR_RATIO
|
||||
self._drive_motor.set_control(self._drive_control.with_velocity(drive_rps))
|
||||
|
||||
# Steer: position in rotations (CANcoder feedback is in rotations)
|
||||
steer_rotations = state.angle.radians() / (2 * math.pi)
|
||||
self._steer_motor.set_control(self._steer_control.with_position(steer_rotations))
|
||||
|
||||
def get_state(self) -> SwerveModuleState:
|
||||
"""Return current speed (m/s) and angle from motor signals."""
|
||||
velocity_rps = self._drive_velocity_signal.refresh().value_as_double
|
||||
speed_mps = (velocity_rps / GEAR_RATIO) * WHEEL_CIRCUMFERENCE_METERS
|
||||
return SwerveModuleState(speed_mps, self._get_steer_angle())
|
||||
|
||||
def get_position(self) -> SwerveModulePosition:
|
||||
"""Return current distance (m) and angle for odometry update."""
|
||||
position_rotations = self._drive_position_signal.refresh().value_as_double
|
||||
distance_meters = (position_rotations / GEAR_RATIO) * WHEEL_CIRCUMFERENCE_METERS
|
||||
return SwerveModulePosition(distance_meters, self._get_steer_angle())
|
||||
|
||||
def publish_telemetry(self) -> None:
|
||||
"""Write module telemetry to NetworkTables. Called each loop by DriveComponent."""
|
||||
actual = self.get_state()
|
||||
self._nt_desired_speed.set(self._desired_state.speed)
|
||||
self._nt_desired_angle.set(self._desired_state.angle.degrees())
|
||||
self._nt_actual_speed.set(actual.speed)
|
||||
self._nt_actual_angle.set(actual.angle.degrees())
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
def _get_steer_angle(self) -> Rotation2d:
|
||||
rotations = self._steer_position_signal.refresh().value_as_double
|
||||
return Rotation2d.fromRotations(rotations)
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
"""
|
||||
components/turret.py – TurretSubsystem ported to MagicBot component.
|
||||
|
||||
Hardware:
|
||||
- TalonFX turret motor (Phoenix 6)
|
||||
- SparkMax launcher motor (REV, brushless)
|
||||
- DigitalInput limit switch
|
||||
- Servo hood
|
||||
"""
|
||||
|
||||
import enum
|
||||
import math
|
||||
|
||||
import magicbot
|
||||
import wpilib
|
||||
from phoenix6.configs import (
|
||||
CurrentLimitsConfigs,
|
||||
FeedbackConfigs,
|
||||
MotorOutputConfigs,
|
||||
Slot0Configs,
|
||||
SoftwareLimitSwitchConfigs,
|
||||
TalonFXConfiguration,
|
||||
)
|
||||
from phoenix6.controls import PositionVoltage
|
||||
from phoenix6.hardware import TalonFX
|
||||
from phoenix6.signals import InvertedValue
|
||||
from rev import (
|
||||
ClosedLoopSlot,
|
||||
FeedbackSensor,
|
||||
PersistMode,
|
||||
ResetMode,
|
||||
SparkBase,
|
||||
SparkLowLevel,
|
||||
SparkMax,
|
||||
SparkMaxConfig,
|
||||
)
|
||||
from wpimath.geometry import Pose3d, Rotation2d
|
||||
|
||||
import constants
|
||||
|
||||
|
||||
class TurretState(enum.Enum):
|
||||
INIT = enum.auto()
|
||||
HOMING = enum.auto()
|
||||
READY = enum.auto()
|
||||
|
||||
|
||||
class TurretComponent:
|
||||
"""MagicBot component that controls the turret, launcher, and hood."""
|
||||
|
||||
def setup(self) -> None:
|
||||
# ── State ──────────────────────────────────────────────────────────
|
||||
self._turret_state = TurretState.INIT
|
||||
self._turret_offset_rotations: float = 0.0
|
||||
self._forward_limit: float = 0.0
|
||||
self._reverse_limit: float = 0.0
|
||||
self._launcher_setpoint_rpm: float = 0.0
|
||||
|
||||
# ── Limit switch ───────────────────────────────────────────────────
|
||||
self._turret_limit_switch = wpilib.DigitalInput(
|
||||
constants.ShooterConstants.TURRET_LIMIT_CHANNEL
|
||||
)
|
||||
|
||||
# ── Turret motor (TalonFX) ─────────────────────────────────────────
|
||||
self._turret_motor = TalonFX(constants.ShooterConstants.TURRET_MOTOR_ID)
|
||||
turret_cfg = TalonFXConfiguration()
|
||||
turret_cfg.slot0 = (
|
||||
Slot0Configs()
|
||||
.with_k_p(6)
|
||||
.with_k_i(0)
|
||||
.with_k_d(0.3)
|
||||
.with_k_s(0)
|
||||
)
|
||||
turret_cfg.motor_output = MotorOutputConfigs().with_inverted(
|
||||
InvertedValue.CLOCKWISE_POSITIVE
|
||||
)
|
||||
turret_cfg.current_limits = CurrentLimitsConfigs().with_stator_current_limit(50)
|
||||
turret_cfg.software_limit_switch = (
|
||||
SoftwareLimitSwitchConfigs()
|
||||
.with_forward_soft_limit_enable(False)
|
||||
.with_reverse_soft_limit_enable(False)
|
||||
)
|
||||
turret_cfg.feedback = FeedbackConfigs().with_feedback_rotor_offset(0)
|
||||
self._turret_motor.configurator.apply(turret_cfg)
|
||||
|
||||
self._turret_position_signal = self._turret_motor.get_position()
|
||||
self._turret_error_signal = self._turret_motor.get_closed_loop_error()
|
||||
self._turret_control = PositionVoltage(0)
|
||||
|
||||
# ── Launcher motor (SparkMax / REV NEO) ────────────────────────────
|
||||
self._launcher_motor = SparkMax(
|
||||
constants.ShooterConstants.LAUNCHER_MOTOR_ID,
|
||||
SparkLowLevel.MotorType.kBrushless,
|
||||
)
|
||||
launcher_cfg = SparkMaxConfig()
|
||||
# Apply equivalent of REV_NEO preset manually
|
||||
launcher_cfg.inverted(constants.ShooterConstants.LAUNCHER_MOTOR_INVERTED)
|
||||
launcher_cfg.voltageCompensation(10)
|
||||
launcher_cfg.closedLoop.P(0.0002).I(0.000001).D(0.0005)
|
||||
launcher_cfg.closedLoop.feedForward.kS(0.2).kV(0.0).kA(0.0)
|
||||
launcher_cfg.closedLoop.setFeedbackSensor(FeedbackSensor.kPrimaryEncoder)
|
||||
launcher_cfg.closedLoop.positionWrappingEnabled(False)
|
||||
self._launcher_motor.configure(
|
||||
launcher_cfg,
|
||||
ResetMode.kResetSafeParameters,
|
||||
PersistMode.kPersistParameters,
|
||||
)
|
||||
self._launcher_controller = self._launcher_motor.getClosedLoopController()
|
||||
|
||||
# ── Hood servo ─────────────────────────────────────────────────────
|
||||
self._hood = wpilib.Servo(constants.ShooterConstants.HOOD_SERVO_CHANNEL)
|
||||
|
||||
self._turret_target_pose: Pose3d = Pose3d()
|
||||
|
||||
# ── Public API ─────────────────────────────────────────────────────────────
|
||||
|
||||
def set_launcher(self, speed_rpm: float) -> None:
|
||||
self._launcher_setpoint_rpm = speed_rpm
|
||||
if speed_rpm == 0:
|
||||
self._launcher_motor.stopMotor()
|
||||
return
|
||||
self._launcher_controller.setSetpoint(
|
||||
speed_rpm, SparkBase.ControlType.kVelocity, ClosedLoopSlot.kSlot0
|
||||
)
|
||||
|
||||
def is_launcher_up_to_speed(self) -> bool:
|
||||
# Currently always returns True (same as Java source)
|
||||
return True
|
||||
|
||||
def set_target_elevation(self, elev: float) -> None:
|
||||
pos = abs((elev - 300) / 300)
|
||||
self._hood.set(pos)
|
||||
|
||||
def home_turret(self) -> None:
|
||||
if self._turret_state != TurretState.INIT:
|
||||
return
|
||||
self._turret_motor.set(constants.ShooterConstants.HOMING_SPEED)
|
||||
self._turret_state = TurretState.HOMING
|
||||
|
||||
def is_turret_ready(self) -> bool:
|
||||
return self._turret_state == TurretState.READY
|
||||
|
||||
def get_turret_angle_robot_relative(self) -> float:
|
||||
return self._get_turret_motor_position() / constants.ShooterConstants.TURRET_GEAR_RATIO
|
||||
|
||||
def set_turret_target_pose(self, target_pose: Pose3d) -> None:
|
||||
self._turret_target_pose = target_pose
|
||||
|
||||
def get_turret_target_pose(self) -> Pose3d:
|
||||
return self._turret_target_pose
|
||||
|
||||
def set_turret_field_relative(self, robot_pose, pos: float) -> None:
|
||||
"""Set turret angle field-relative, accounting for robot heading."""
|
||||
if self._turret_state != TurretState.READY:
|
||||
return
|
||||
|
||||
corrected_pos = -pos # Flip angle to match CCW positive
|
||||
robot_rotations = robot_pose.rotation().toRotation2d().radians() / (2 * math.pi)
|
||||
turret_angle = (
|
||||
Rotation2d.fromRotations(corrected_pos)
|
||||
+ Rotation2d.fromRotations(robot_rotations)
|
||||
- Rotation2d.fromRotations(0.5)
|
||||
)
|
||||
self.set_turret_robot_relative(turret_angle.radians() / (2 * math.pi))
|
||||
|
||||
def set_turret_robot_relative(self, pos: float) -> None:
|
||||
if self._turret_state != TurretState.READY:
|
||||
return
|
||||
corrected_pos = -pos # Flip angle to match CCW positive
|
||||
self.set_turret_motor_rotation(
|
||||
corrected_pos * constants.ShooterConstants.TURRET_GEAR_RATIO
|
||||
)
|
||||
|
||||
def set_turret_motor_rotation(self, pos: float) -> None:
|
||||
pos_with_offset = pos + self._turret_offset_rotations
|
||||
self._turret_motor.set_control(self._turret_control.with_position(pos_with_offset))
|
||||
|
||||
def is_turret_at_target(self) -> bool:
|
||||
return abs(self._turret_error_signal.refresh().value_as_double) <= 0.1
|
||||
|
||||
# ── Feedback properties ────────────────────────────────────────────────────
|
||||
|
||||
@magicbot.feedback
|
||||
def turret_state(self) -> str:
|
||||
return self._turret_state.name
|
||||
|
||||
@magicbot.feedback
|
||||
def turret_angle_robot_relative(self) -> float:
|
||||
return self.get_turret_angle_robot_relative()
|
||||
|
||||
@magicbot.feedback
|
||||
def turret_position_error(self) -> float:
|
||||
return self._turret_error_signal.refresh().value_as_double
|
||||
|
||||
@magicbot.feedback
|
||||
def launcher_speed_rpm(self) -> float:
|
||||
return self._launcher_motor.getEncoder().getVelocity()
|
||||
|
||||
@magicbot.feedback
|
||||
def turret_limit_switch(self) -> bool:
|
||||
return self._turret_limit_switch.get()
|
||||
|
||||
# ── MagicBot lifecycle ─────────────────────────────────────────────────────
|
||||
|
||||
def execute(self) -> None:
|
||||
# Homing state machine
|
||||
if self._turret_state == TurretState.HOMING:
|
||||
if self._turret_limit_switch.get(): # Switch tripped → homed
|
||||
self._turret_motor.stopMotor()
|
||||
raw_pos = self._turret_position_signal.refresh().value_as_double
|
||||
if wpilib.RobotBase.isReal():
|
||||
self._turret_offset_rotations = raw_pos - 1.323
|
||||
else:
|
||||
self._turret_offset_rotations = 0.0
|
||||
|
||||
self._turret_state = TurretState.READY
|
||||
self._forward_limit = 1.5 + self._turret_offset_rotations
|
||||
self._reverse_limit = -1.5 + self._turret_offset_rotations
|
||||
|
||||
# Enable software limits now that homing is complete
|
||||
limit_cfg = (
|
||||
SoftwareLimitSwitchConfigs()
|
||||
.with_forward_soft_limit_enable(True)
|
||||
.with_forward_soft_limit_threshold(self._forward_limit)
|
||||
.with_reverse_soft_limit_enable(True)
|
||||
.with_reverse_soft_limit_threshold(self._reverse_limit)
|
||||
)
|
||||
self._turret_motor.configurator.apply(limit_cfg)
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
def _get_turret_motor_position(self) -> float:
|
||||
return self._turret_position_signal.refresh().value_as_double - self._turret_offset_rotations
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
"""
|
||||
constants.py – robot-wide constants for Castor 2026 (Python/MagicBot port).
|
||||
|
||||
All Java "public static final" fields become Python class-level attributes.
|
||||
"""
|
||||
|
||||
import enum
|
||||
import math
|
||||
|
||||
from phoenix6.signals import InvertedValue
|
||||
from robotpy_apriltag import AprilTagField, AprilTagFieldLayout
|
||||
from wpimath.geometry import (
|
||||
Pose3d,
|
||||
Rotation3d,
|
||||
Transform3d,
|
||||
Translation2d,
|
||||
Translation3d,
|
||||
)
|
||||
|
||||
|
||||
class OperatorConstants:
|
||||
CONTROLLER_PORT: int = 0
|
||||
|
||||
|
||||
class CameraConstants:
|
||||
|
||||
class IDFilters:
|
||||
RED_HUB_SHOOTING_IDS: list[int] = [8, 9, 10, 11]
|
||||
BLUE_HUB_SHOOTING_IDS: list[int] = [27, 26, 25, 24]
|
||||
|
||||
BACK_CAMERA_NAME: str = "limelight-back"
|
||||
BACK_LOCALIZATION_PIPELINE_NUMBER: int = 0
|
||||
BACK_HUB_TRACKING_2D_PIPELINE_NUMBER: int = 1
|
||||
BACK_HUB_TRACKING_3D_PIPELINE_NUMBER: int = 2
|
||||
|
||||
FRONT_CAMERA_NAME: str = "limelight-front"
|
||||
FRONT_LOCALIZATION_PIPELINE_NUMBER: int = 0
|
||||
|
||||
BLUE_ZONE_COOR: list[float] = [0, 3.5]
|
||||
RED_ZONE_COOR: list[float] = [13, 16]
|
||||
NEUTRAL_ZONE_COOR: list[float] = [5.5, 11]
|
||||
NEUTRAL1_ZONE_COOR: list[float] = [5.5, 11, 0, 3]
|
||||
NEUTRAL2_ZONE_COOR: list[float] = [5.5, 11, 5, 8]
|
||||
BLUE1_ZONE_COOR: list[float] = [0, 3.5, 0, 3]
|
||||
BLUE2_ZONE_COOR: list[float] = [0, 3.5, 5, 8]
|
||||
RED1_ZONE_COOR: list[float] = [13, 16, 0, 3]
|
||||
RED2_ZONE_COOR: list[float] = [13, 16, 5, 8]
|
||||
|
||||
|
||||
# Swerve encoder offsets as of 3/2/26
|
||||
class SwerveDriveOffsets:
|
||||
FRONT_LEFT_MOTOR_OFFSET: float = -0.336426
|
||||
FRONT_RIGHT_MOTOR_OFFSET: float = 0.108887
|
||||
BACK_LEFT_MOTOR_OFFSET: float = -0.492432
|
||||
BACK_RIGHT_MOTOR_OFFSET: float = 0.470215
|
||||
|
||||
|
||||
# CAN ID numbering convention:
|
||||
# 1x = Front Left, 2x = Front Right, 3x = Back Left, 4x = Back Right
|
||||
# Single-digit IDs are non-motor devices (e.g. Pigeon2)
|
||||
class SwerveDriveIDs:
|
||||
FRONT_LEFT_STEER_ID: int = 11
|
||||
FRONT_LEFT_DRIVE_ID: int = 12
|
||||
FRONT_LEFT_ENCODER_ID: int = 13
|
||||
|
||||
FRONT_RIGHT_STEER_ID: int = 21
|
||||
FRONT_RIGHT_DRIVE_ID: int = 22
|
||||
FRONT_RIGHT_ENCODER_ID: int = 23
|
||||
|
||||
BACK_LEFT_STEER_ID: int = 31
|
||||
BACK_LEFT_DRIVE_ID: int = 32
|
||||
BACK_LEFT_ENCODER_ID: int = 33
|
||||
|
||||
BACK_RIGHT_STEER_ID: int = 41
|
||||
BACK_RIGHT_DRIVE_ID: int = 42
|
||||
BACK_RIGHT_ENCODER_ID: int = 43
|
||||
|
||||
|
||||
class RobotChassisLimits:
|
||||
# Max linear velocity (m/s)
|
||||
MAX_ROBOT_LINEAR_VELOCITY: float = 3.0
|
||||
# Max linear acceleration (m/s²)
|
||||
MAX_ROBOT_LINEAR_VELOCITY_ACCEL: float = 2.0
|
||||
# Max angular velocity (rad/s)
|
||||
MAX_ROBOT_ANGULAR_VELOCITY: float = math.pi
|
||||
# Max angular acceleration (rad/s²)
|
||||
MAX_ROBOT_ANGULAR_VELOCITY_ACCEL: float = math.pi
|
||||
|
||||
|
||||
class ExtraIDEntities:
|
||||
PIGEON_ID: int = 1
|
||||
|
||||
|
||||
class IntakeConstants:
|
||||
DEPLOY_MOTOR_ID: int = 17
|
||||
DEPLOY_MOTOR_INVERTED: bool = True # TODO: Test this
|
||||
|
||||
INTAKE_MOTOR_ID: int = 2
|
||||
INTAKE_MOTOR_DIRECTION: InvertedValue = InvertedValue.CLOCKWISE_POSITIVE # TODO: Test this
|
||||
|
||||
|
||||
class ShooterConstants:
|
||||
LAUNCHER_MOTOR_ID: int = 3
|
||||
LAUNCHER_MOTOR_INVERTED: bool = False
|
||||
|
||||
TURRET_MOTOR_ID: int = 4
|
||||
TURRET_MOTOR_DIRECTION: InvertedValue = InvertedValue.CLOCKWISE_POSITIVE
|
||||
TURRET_LIMIT_CHANNEL: int = 9
|
||||
|
||||
# Plain floats (degrees) replacing edu.wpi.first.units.Degrees.of(x)
|
||||
LIMIT_AZIMUTH_POS: float = 165.0 # degrees
|
||||
LIMIT_AZIMUTH_NEG: float = 5.0 # degrees
|
||||
|
||||
HOMING_SPEED: float = 0.05
|
||||
TURRET_GEAR_RATIO: float = 6.0
|
||||
|
||||
HOOD_SERVO_CHANNEL: int = 0
|
||||
HOOD_SERVO_INVERTED: bool = False # TODO: Test this
|
||||
HOOD_ENCODER_ID: int = 4
|
||||
|
||||
TARGET_ELEVATION_DIF: float = 1.0 # degrees
|
||||
LIMIT_ELEVATION_POS: float = 90.0 # degrees
|
||||
LIMIT_ELEVATION_NEG: float = 0.0 # degrees
|
||||
|
||||
DEFLECTOR_STORED_ANGLE: float = 0.0
|
||||
DEFLECTOR_SET_ANGLE1: float = 100.0
|
||||
DEFLECTOR_SET_ANGLE2: float = 200.0
|
||||
DEFLECTOR_SET_ANGLE3: float = 300.0
|
||||
DEFLECTOR_SERVO_RATIO: float = 1.0
|
||||
|
||||
|
||||
class HopperConstants:
|
||||
KICKER_MOTOR_ID: int = 9
|
||||
KICKER_MOTOR_DIRECTION: InvertedValue = InvertedValue.CLOCKWISE_POSITIVE
|
||||
|
||||
SPINDEXER_MOTOR_ID: int = 8
|
||||
SPINDEXER_MOTOR_DIRECTION: InvertedValue = InvertedValue.COUNTER_CLOCKWISE_POSITIVE
|
||||
|
||||
|
||||
# ── Swerve module Translation2d locations ────────────────────────────────────
|
||||
# Robot is 22" × 22"; modules are at the corners.
|
||||
# Half of 22" = 11" = 0.2794 m from robot centre to each module.
|
||||
# WPILib convention: +X is forward, +Y is to the left.
|
||||
class SwerveDriveModuleLocations:
|
||||
_HALF: float = 0.2794 # metres (11 inches)
|
||||
|
||||
FRONT_LEFT: Translation2d = Translation2d( _HALF, _HALF)
|
||||
FRONT_RIGHT: Translation2d = Translation2d( _HALF, -_HALF)
|
||||
BACK_LEFT: Translation2d = Translation2d(-_HALF, _HALF)
|
||||
BACK_RIGHT: Translation2d = Translation2d(-_HALF, -_HALF)
|
||||
|
||||
|
||||
# ── April-tag field layout (loaded once at import time) ───────────────────────
|
||||
_field_tags = AprilTagFieldLayout.loadField(AprilTagField.k2026RebuiltWelded)
|
||||
|
||||
|
||||
class FieldPoses:
|
||||
BLUE_HUB_POSE: Pose3d = _field_tags.getTagPose(26).transformBy(
|
||||
Transform3d(Translation3d(-0.5207, 0, 0), Rotation3d())
|
||||
)
|
||||
RED_HUB_POSE: Pose3d = _field_tags.getTagPose(10).transformBy(
|
||||
Transform3d(Translation3d(-0.5207, 0, 0), Rotation3d())
|
||||
)
|
||||
|
||||
# Passing targets — left/right from driver's perspective;
|
||||
# origin at blue side of field; rotations are zero (don't matter).
|
||||
BLUE_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(1.99, 6.35, 0, Rotation3d())
|
||||
BLUE_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(1.99, 1.72, 0, Rotation3d())
|
||||
BLUE_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(8.27, 6.35, 0, Rotation3d())
|
||||
BLUE_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(8.27, 1.72, 0, Rotation3d())
|
||||
|
||||
RED_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(14.55, 1.72, 0, Rotation3d())
|
||||
RED_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(14.55, 6.35, 0, Rotation3d())
|
||||
RED_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(8.27, 1.72, 0, Rotation3d())
|
||||
RED_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE: Pose3d = Pose3d(8.27, 6.35, 0, Rotation3d())
|
||||
|
||||
|
||||
# ── Shooting-region boundary lines ───────────────────────────────────────────
|
||||
class ShootingRegionDimensions:
|
||||
BLUE_ALLIANCE_ZONE_REGION_X_MAX: float = 3.5
|
||||
RED_ALLIANCE_ZONE_REGION_X_MIN: float = 13.0
|
||||
NEUTRAL_ZONE_REGION_X_MIN: float = 5.5
|
||||
NEUTRAL_ZONE_REGION_X_MAX: float = 11.0
|
||||
BLUE_RIGHT_REGION_Y_MAX: float = 3.0
|
||||
RED_LEFT_REGION_Y_MAX: float = 3.0
|
||||
BLUE_LEFT_REGION_Y_MIN: float = 5.0
|
||||
RED_RIGHT_REGION_Y_MIN: float = 5.0
|
||||
|
||||
|
||||
# ── Shooting regions (Java enum → Python enum.Enum) ───────────────────────────
|
||||
class ShootingRegion(enum.Enum):
|
||||
NON_SHOOTING_REGION = enum.auto()
|
||||
BLUE_OWN_ALLIANCE_ZONE = enum.auto()
|
||||
BLUE_LEFT_NEUTRAL_ZONE = enum.auto()
|
||||
BLUE_RIGHT_NEUTRAL_ZONE = enum.auto()
|
||||
BLUE_LEFT_OPPONENT_ALLIANCE_ZONE = enum.auto()
|
||||
BLUE_RIGHT_OPPONENT_ALLIANCE_ZONE = enum.auto()
|
||||
RED_OWN_ALLIANCE_ZONE = enum.auto()
|
||||
RED_LEFT_NEUTRAL_ZONE = enum.auto()
|
||||
RED_RIGHT_NEUTRAL_ZONE = enum.auto()
|
||||
RED_LEFT_OPPONENT_ALLIANCE_ZONE = enum.auto()
|
||||
RED_RIGHT_OPPONENT_ALLIANCE_ZONE = enum.auto()
|
||||
|
|
@ -1,3 +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
|
||||
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.
|
||||
|
|
@ -1,88 +1,88 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "1.1 Hub to Shoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "ChassisAlignShoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "1.2 Shoot to Depot Path"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "RunIntake"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "1.3 Depot to Shoot Path"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "ChassisAlignShoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "1.1 Hub to Shoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "ChassisAlignShoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "1.2 Shoot to Depot Path"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "RunIntake"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "1.3 Depot to Shoot Path"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "ChassisAlignShoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "9.1 Chaos Monkey Path"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "9.1 Chaos Monkey Path"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. Hub. shoot 8. E-Hub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "M. Depot. "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. Hub. shoot 8. E-Hub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "M. Depot. "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. L-Tre. Preload."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "M. Depot. "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. L-Tre. Preload."
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "M. Depot. "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,25 +1,25 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. R-Trench. E-Hub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "M. Depot. "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. R-Trench. E-Hub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "M. Depot. "
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "HUB_START"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "HUB_START"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "LEFT_TRENCH_START"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "LEFT_TRENCH_START"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "RIGHT_TRENCH_START"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "RIGHT_TRENCH_START"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Relay. L-Tr."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Relay. L-Tr."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Relay. R-Tr."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "Relay. R-Tr."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,38 +1,38 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. Hub. shoot 8. E-Hub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "TurretShoot"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. Hub. shoot 8. E-Hub"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "deadline",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "wait",
|
||||
"data": {
|
||||
"waitTime": 10.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "TurretShoot"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. L-Tre. Preload."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. L-Tre. Preload."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. R-Trench. E-Hub"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"command": {
|
||||
"type": "sequential",
|
||||
"data": {
|
||||
"commands": [
|
||||
{
|
||||
"type": "path",
|
||||
"data": {
|
||||
"pathName": "S. R-Trench. E-Hub"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"resetOdom": true,
|
||||
"folder": null,
|
||||
"choreoAuto": false
|
||||
}
|
||||
|
|
@ -1,58 +1,58 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.5,
|
||||
"y": 4.0
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 1.5,
|
||||
"maxAngularVelocity": 540.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -177.9047474356738
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
<<<<<<< HEAD:src/main/deploy/pathplanner/paths/Hub to Depot.path
|
||||
"rotation": -179.99999999992184
|
||||
=======
|
||||
"rotation": -179.69626968995792
|
||||
>>>>>>> c2fa27aa5cc22124b930645e802b8176658edb7a:src/main/deploy/pathplanner/paths/1.1 Hub to Shoot Path.path
|
||||
},
|
||||
"useDefaultConstraints": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.5,
|
||||
"y": 4.0
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 1.5,
|
||||
"maxAngularVelocity": 540.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -177.9047474356738
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
<<<<<<< HEAD:src/main/deploy/pathplanner/paths/Hub to Depot.path
|
||||
"rotation": -179.99999999992184
|
||||
=======
|
||||
"rotation": -179.69626968995792
|
||||
>>>>>>> c2fa27aa5cc22124b930645e802b8176658edb7a:src/main/deploy/pathplanner/paths/1.1 Hub to Shoot Path.path
|
||||
},
|
||||
"useDefaultConstraints": false
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.75,
|
||||
"y": 4.0
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.75,
|
||||
"y": 4.0
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 177.4888349270938
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": -179.0393266954795
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.75,
|
||||
"y": 4.0
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.75,
|
||||
"y": 4.0
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 177.4888349270938
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": -179.0393266954795
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.2144854970378125,
|
||||
"y": 3.8554998234204434
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1.0,
|
||||
"y": 6.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.2166471375173105,
|
||||
"y": 5.875244167248359
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -178.09121133641756
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.4910281334858283
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.2144854970378125,
|
||||
"y": 3.8554998234204434
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1.0,
|
||||
"y": 6.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.2166471375173105,
|
||||
"y": 5.875244167248359
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -178.09121133641756
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.4910281334858283
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1.0,
|
||||
"y": 6.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 1.453699105174549,
|
||||
"y": 6.084627986890304
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.266577414275921,
|
||||
"y": 3.829411518660614
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 1.5,
|
||||
"maxAngularVelocity": 100.0,
|
||||
"maxAngularAcceleration": 100.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -179.02897806892076
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": -179.69626968995792
|
||||
},
|
||||
"useDefaultConstraints": false
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 1.0,
|
||||
"y": 6.0
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 1.453699105174549,
|
||||
"y": 6.084627986890304
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.0,
|
||||
"y": 4.0
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.266577414275921,
|
||||
"y": 3.829411518660614
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 1.5,
|
||||
"maxAcceleration": 1.5,
|
||||
"maxAngularVelocity": 100.0,
|
||||
"maxAngularAcceleration": 100.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -179.02897806892076
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": -179.69626968995792
|
||||
},
|
||||
"useDefaultConstraints": false
|
||||
}
|
||||
|
|
@ -1,102 +1,102 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5184925161825644,
|
||||
"y": 7.5345006466771025
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.489963675146704,
|
||||
"y": 7.219438447522688
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.6,
|
||||
"y": 6.812200117368956
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.532870181778978,
|
||||
"y": 7.8099443669167
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.650893142287796,
|
||||
"y": 6.055780073270545
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.6,
|
||||
"y": 0.9617601315610045
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.654625343431328,
|
||||
"y": 1.468826273060325
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.527819365080411,
|
||||
"y": 0.2917349428743933
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 0.5,
|
||||
"y": 0.6692650602433468
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.096874747061515,
|
||||
"y": 0.6440356562159093
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 1.2332261810856255,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.7516108262639798,
|
||||
"rotationDegrees": 0.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "",
|
||||
"waypointRelativePos": 0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": null
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -1.2282908533168928
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": -0.1533900770684255
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5184925161825644,
|
||||
"y": 7.5345006466771025
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.489963675146704,
|
||||
"y": 7.219438447522688
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.6,
|
||||
"y": 6.812200117368956
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.532870181778978,
|
||||
"y": 7.8099443669167
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.650893142287796,
|
||||
"y": 6.055780073270545
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.6,
|
||||
"y": 0.9617601315610045
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.654625343431328,
|
||||
"y": 1.468826273060325
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.527819365080411,
|
||||
"y": 0.2917349428743933
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 0.5,
|
||||
"y": 0.6692650602433468
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.096874747061515,
|
||||
"y": 0.6440356562159093
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 1.2332261810856255,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.7516108262639798,
|
||||
"rotationDegrees": 0.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "",
|
||||
"waypointRelativePos": 0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": null
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -1.2282908533168928
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": -0.1533900770684255
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.519556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.769556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.519556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.269556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.519556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.769556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.519556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.269556041182133,
|
||||
"y": 4.059804750409042
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.25,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.75,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.25,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.75,
|
||||
"y": 7.423545951843262
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,107 +1,107 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.4727349397590364,
|
||||
"y": 4.013144578313253
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.2818883684167575,
|
||||
"y": 4.174630138679796
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 0.751734939759036,
|
||||
"y": 4.942
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.975638554216867,
|
||||
"y": 6.362602409638553
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 0.40641026098477545,
|
||||
"y": 4.54117671213702
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 0.751734939759036,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 0.41241207330734936,
|
||||
"y": 6.876706525398199
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 1.1342048192771081,
|
||||
"y": 7.433518072289157
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.4727349397590364,
|
||||
"y": 4.013144578313253
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.161409638554217,
|
||||
"y": 4.1989156626506015
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 1.0308661417322806,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.7754330708661374,
|
||||
"rotationDegrees": 90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 3.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.4727349397590364,
|
||||
"y": 4.013144578313253
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.2818883684167575,
|
||||
"y": 4.174630138679796
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 0.751734939759036,
|
||||
"y": 4.942
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.975638554216867,
|
||||
"y": 6.362602409638553
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 0.40641026098477545,
|
||||
"y": 4.54117671213702
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 0.751734939759036,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 0.41241207330734936,
|
||||
"y": 6.876706525398199
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 1.1342048192771081,
|
||||
"y": 7.433518072289157
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.4727349397590364,
|
||||
"y": 4.013144578313253
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.161409638554217,
|
||||
"y": 4.1989156626506015
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 1.0308661417322806,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.7754330708661374,
|
||||
"rotationDegrees": 90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 3.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,54 +1,54 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.25,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.75,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.25,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 4.0,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.75,
|
||||
"y": 0.6236959156237152
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,193 +1,193 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5383012048192777,
|
||||
"y": 7.4553734939759035
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.538301204819281,
|
||||
"y": 7.4553734939759035
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.67990361445783,
|
||||
"y": 7.269602409638554
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.475661648641639,
|
||||
"y": 7.413773209038217
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.884145580274021,
|
||||
"y": 7.125431610238891
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.67990361445783,
|
||||
"y": 1.0845180722891563
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.619269708198755,
|
||||
"y": 1.3270536973254914
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.743952438085447,
|
||||
"y": 0.828322777778649
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.641771084337348,
|
||||
"y": 0.9206024096385546
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.662532454300786,
|
||||
"y": 1.1697388491997742
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.62100971437391,
|
||||
"y": 0.6714659700773349
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.663626506024096,
|
||||
"y": 7.19310843373494
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.649759001118466,
|
||||
"y": 6.943493345433587
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.677494010929727,
|
||||
"y": 7.442723522036293
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.876831325301204,
|
||||
"y": 7.19310843373494
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.125590622853701,
|
||||
"y": 7.217984363490191
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 5.628072027748707,
|
||||
"y": 7.168232503979689
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.745698795180723,
|
||||
"y": 0.9206024096385546
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 5.857502194055715,
|
||||
"y": 1.1442092073885324
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.5,
|
||||
"rotationDegrees": 0.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.0672199170124472,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 2.0863070539419084,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 2.962655601659752,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 3.9983402489627107,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 5.02406639004149,
|
||||
"rotationDegrees": -90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot Headed R-Tr",
|
||||
"waypointRelativePos": 1.0302729528535988,
|
||||
"endWaypointRelativePos": 2.2094292803970026,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot Headed R-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot headed L-Tr",
|
||||
"waypointRelativePos": 3.1503722084366608,
|
||||
"endWaypointRelativePos": 4.281885856079398,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot headed L-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot Headed R-Tr",
|
||||
"waypointRelativePos": 5.067990074441674,
|
||||
"endWaypointRelativePos": 6.0,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot Headed R-Tr"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -90.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5383012048192777,
|
||||
"y": 7.4553734939759035
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.538301204819281,
|
||||
"y": 7.4553734939759035
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.67990361445783,
|
||||
"y": 7.269602409638554
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.475661648641639,
|
||||
"y": 7.413773209038217
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.884145580274021,
|
||||
"y": 7.125431610238891
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.67990361445783,
|
||||
"y": 1.0845180722891563
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.619269708198755,
|
||||
"y": 1.3270536973254914
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.743952438085447,
|
||||
"y": 0.828322777778649
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.641771084337348,
|
||||
"y": 0.9206024096385546
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.662532454300786,
|
||||
"y": 1.1697388491997742
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.62100971437391,
|
||||
"y": 0.6714659700773349
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.663626506024096,
|
||||
"y": 7.19310843373494
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.649759001118466,
|
||||
"y": 6.943493345433587
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.677494010929727,
|
||||
"y": 7.442723522036293
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.876831325301204,
|
||||
"y": 7.19310843373494
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.125590622853701,
|
||||
"y": 7.217984363490191
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 5.628072027748707,
|
||||
"y": 7.168232503979689
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.745698795180723,
|
||||
"y": 0.9206024096385546
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 5.857502194055715,
|
||||
"y": 1.1442092073885324
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.5,
|
||||
"rotationDegrees": 0.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.0672199170124472,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 2.0863070539419084,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 2.962655601659752,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 3.9983402489627107,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 5.02406639004149,
|
||||
"rotationDegrees": -90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot Headed R-Tr",
|
||||
"waypointRelativePos": 1.0302729528535988,
|
||||
"endWaypointRelativePos": 2.2094292803970026,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot Headed R-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot headed L-Tr",
|
||||
"waypointRelativePos": 3.1503722084366608,
|
||||
"endWaypointRelativePos": 4.281885856079398,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot headed L-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot Headed R-Tr",
|
||||
"waypointRelativePos": 5.067990074441674,
|
||||
"endWaypointRelativePos": 6.0,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot Headed R-Tr"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": -90.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,197 +1,197 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.4618072289156623,
|
||||
"y": 0.680192771084337
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.4618072289156725,
|
||||
"y": 0.680192771084337
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.395783132530121,
|
||||
"y": 0.8768915662650603
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.47916753759839,
|
||||
"y": 0.6593895606880393
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 8.040518072289156,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.668975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.691609840125085,
|
||||
"y": 7.387443181134999
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.64634196710383,
|
||||
"y": 6.889496577901146
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.761975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.011975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.511975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.761975903614458,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.011975903614458,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.511975903614458,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.8440481927710834,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.020824888067715,
|
||||
"y": 0.8531028227756465
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 5.667271497474452,
|
||||
"y": 1.2066562133689316
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.8440481927710834,
|
||||
"y": 6.9964096385542165
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 5.885147939597421,
|
||||
"y": 6.74981115759618
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.5,
|
||||
"rotationDegrees": 0.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.0406639004149303,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.917012448132766,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 3.0904564315352623,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 3.91867219917012,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 5.063900414937716,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 6.0,
|
||||
"rotationDegrees": 90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot headed L-Tr",
|
||||
"waypointRelativePos": 1.0302729528536159,
|
||||
"endWaypointRelativePos": 2.4357320099255366,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot headed L-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot Headed R-Tr",
|
||||
"waypointRelativePos": 2.9836228287841102,
|
||||
"endWaypointRelativePos": 4.103225806451647,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot Headed R-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot headed L-Tr",
|
||||
"waypointRelativePos": 5.079900744416814,
|
||||
"endWaypointRelativePos": 6.0,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot headed L-Tr"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 90.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.4618072289156623,
|
||||
"y": 0.680192771084337
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 4.4618072289156725,
|
||||
"y": 0.680192771084337
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.395783132530121,
|
||||
"y": 0.8768915662650603
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.47916753759839,
|
||||
"y": 0.6593895606880393
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 8.040518072289156,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 7.668975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.691609840125085,
|
||||
"y": 7.387443181134999
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 7.64634196710383,
|
||||
"y": 6.889496577901146
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.761975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.011975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.511975903614458,
|
||||
"y": 7.138469879518072
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 6.761975903614458,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 7.011975903614458,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 6.511975903614458,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.8440481927710834,
|
||||
"y": 1.029879518072289
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 6.020824888067715,
|
||||
"y": 0.8531028227756465
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 5.667271497474452,
|
||||
"y": 1.2066562133689316
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 5.8440481927710834,
|
||||
"y": 6.9964096385542165
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 5.885147939597421,
|
||||
"y": 6.74981115759618
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.5,
|
||||
"rotationDegrees": 0.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.0406639004149303,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 1.917012448132766,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 3.0904564315352623,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 3.91867219917012,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 5.063900414937716,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 6.0,
|
||||
"rotationDegrees": 90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot headed L-Tr",
|
||||
"waypointRelativePos": 1.0302729528536159,
|
||||
"endWaypointRelativePos": 2.4357320099255366,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot headed L-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot Headed R-Tr",
|
||||
"waypointRelativePos": 2.9836228287841102,
|
||||
"endWaypointRelativePos": 4.103225806451647,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot Headed R-Tr"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Shoot headed L-Tr",
|
||||
"waypointRelativePos": 5.079900744416814,
|
||||
"endWaypointRelativePos": 6.0,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot headed L-Tr"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 90.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,87 +1,87 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.48366265060241,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.2365697261897557,
|
||||
"y": 4.040231163533364
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.084915662650602,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.084915662650602,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 3.084915662650602,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.677383349903843,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.4274139067638107,
|
||||
"y": 4.006125511257969
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.7905511811023622,
|
||||
"rotationDegrees": 180.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 2.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.48366265060241,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.2365697261897557,
|
||||
"y": 4.040231163533364
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.084915662650602,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.084915662650602,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 3.084915662650602,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.677383349903843,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 2.4274139067638107,
|
||||
"y": 4.006125511257969
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.7905511811023622,
|
||||
"rotationDegrees": 180.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 2.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,82 +1,82 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.48366265060241,
|
||||
"y": 7.466301204819277
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.3666907204976515,
|
||||
"y": 7.245354225732512
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.1723373493975906,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.8772891566265066,
|
||||
"y": 4.024072289156626
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 2.421654288011768,
|
||||
"y": 3.9837489460910525
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.1723373493975906,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.8226506024096385,
|
||||
"y": 3.9912891566265065
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 2.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.48366265060241,
|
||||
"y": 7.466301204819277
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 3.3666907204976515,
|
||||
"y": 7.245354225732512
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.1723373493975906,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.8772891566265066,
|
||||
"y": 4.024072289156626
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 2.421654288011768,
|
||||
"y": 3.9837489460910525
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.1723373493975906,
|
||||
"y": 4.00221686746988
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.8226506024096385,
|
||||
"y": 3.9912891566265065
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 2.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,87 +1,87 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5273734939759036,
|
||||
"y": 0.5272048192771093
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.478313253012048,
|
||||
"y": 0.8003975903614468
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.128626506024096,
|
||||
"y": 3.892939759036145
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.9085087310435527,
|
||||
"y": 3.77441480327739
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 2.3487442810046395,
|
||||
"y": 4.0114647147949
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.473,
|
||||
"y": 4.013
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.2270325224750227,
|
||||
"y": 4.057721359549996
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.8686614173228185,
|
||||
"rotationDegrees": 180.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 2.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5273734939759036,
|
||||
"y": 0.5272048192771093
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.478313253012048,
|
||||
"y": 0.8003975903614468
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 2.128626506024096,
|
||||
"y": 3.892939759036145
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 1.9085087310435527,
|
||||
"y": 3.77441480327739
|
||||
},
|
||||
"nextControl": {
|
||||
"x": 2.3487442810046395,
|
||||
"y": 4.0114647147949
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.473,
|
||||
"y": 4.013
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.2270325224750227,
|
||||
"y": 4.057721359549996
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.8686614173228185,
|
||||
"rotationDegrees": 180.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [
|
||||
{
|
||||
"name": "Shoot 8",
|
||||
"waypointRelativePos": 2.0,
|
||||
"endWaypointRelativePos": null,
|
||||
"command": {
|
||||
"type": "named",
|
||||
"data": {
|
||||
"name": "Shoot preload"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 180.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,91 +1,91 @@
|
|||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5164457831325304,
|
||||
"y": 0.5599879518072293
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.716570175215442,
|
||||
"y": 2.6055674399847426
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5164457831325304,
|
||||
"y": 3.958506024096385
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.3576574884732078,
|
||||
"y": 2.7315170387830205
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.24787401574803541,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.29574803149607193,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.3398425196850417,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.38267716535433216,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.4305511811023681,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.465826771653542,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.5099212598425222,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.5363779527559113,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.5565354330708714,
|
||||
"rotationDegrees": -90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
{
|
||||
"version": "2025.0",
|
||||
"waypoints": [
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5164457831325304,
|
||||
"y": 0.5599879518072293
|
||||
},
|
||||
"prevControl": null,
|
||||
"nextControl": {
|
||||
"x": 2.716570175215442,
|
||||
"y": 2.6055674399847426
|
||||
},
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
},
|
||||
{
|
||||
"anchor": {
|
||||
"x": 3.5164457831325304,
|
||||
"y": 3.958506024096385
|
||||
},
|
||||
"prevControl": {
|
||||
"x": 3.3576574884732078,
|
||||
"y": 2.7315170387830205
|
||||
},
|
||||
"nextControl": null,
|
||||
"isLocked": false,
|
||||
"linkedName": null
|
||||
}
|
||||
],
|
||||
"rotationTargets": [
|
||||
{
|
||||
"waypointRelativePos": 0.24787401574803541,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.29574803149607193,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.3398425196850417,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.38267716535433216,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.4305511811023681,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.465826771653542,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.5099212598425222,
|
||||
"rotationDegrees": -90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.5363779527559113,
|
||||
"rotationDegrees": 90.0
|
||||
},
|
||||
{
|
||||
"waypointRelativePos": 0.5565354330708714,
|
||||
"rotationDegrees": -90.0
|
||||
}
|
||||
],
|
||||
"constraintZones": [],
|
||||
"pointTowardsZones": [],
|
||||
"eventMarkers": [],
|
||||
"globalConstraints": {
|
||||
"maxVelocity": 3.0,
|
||||
"maxAcceleration": 3.0,
|
||||
"maxAngularVelocity": 360.0,
|
||||
"maxAngularAcceleration": 720.0,
|
||||
"nominalVoltage": 12.0,
|
||||
"unlimited": false
|
||||
},
|
||||
"goalEndState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"reversed": false,
|
||||
"folder": null,
|
||||
"idealStartingState": {
|
||||
"velocity": 0,
|
||||
"rotation": 0.0
|
||||
},
|
||||
"useDefaultConstraints": true
|
||||
}
|
||||
|
|
@ -1,32 +1,32 @@
|
|||
{
|
||||
"robotWidth": 0.8763,
|
||||
"robotLength": 0.8763,
|
||||
"holonomicMode": true,
|
||||
"pathFolders": [],
|
||||
"autoFolders": [],
|
||||
"defaultMaxVel": 3.0,
|
||||
"defaultMaxAccel": 3.0,
|
||||
"defaultMaxAngVel": 360.0,
|
||||
"defaultMaxAngAccel": 720.0,
|
||||
"defaultNominalVoltage": 12.0,
|
||||
"robotMass": 44.4521,
|
||||
"robotMOI": 6.883,
|
||||
"robotTrackwidth": 0.546,
|
||||
"driveWheelRadius": 0.051,
|
||||
"driveGearing": 8.14,
|
||||
"maxDriveSpeed": 3.9,
|
||||
"driveMotorType": "krakenX60",
|
||||
"driveCurrentLimit": 60.0,
|
||||
"wheelCOF": 1.2,
|
||||
"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": []
|
||||
{
|
||||
"robotWidth": 0.8763,
|
||||
"robotLength": 0.8763,
|
||||
"holonomicMode": true,
|
||||
"pathFolders": [],
|
||||
"autoFolders": [],
|
||||
"defaultMaxVel": 3.0,
|
||||
"defaultMaxAccel": 3.0,
|
||||
"defaultMaxAngVel": 360.0,
|
||||
"defaultMaxAngAccel": 720.0,
|
||||
"defaultNominalVoltage": 12.0,
|
||||
"robotMass": 44.4521,
|
||||
"robotMOI": 6.883,
|
||||
"robotTrackwidth": 0.546,
|
||||
"driveWheelRadius": 0.051,
|
||||
"driveGearing": 8.14,
|
||||
"maxDriveSpeed": 3.9,
|
||||
"driveMotorType": "krakenX60",
|
||||
"driveCurrentLimit": 60.0,
|
||||
"wheelCOF": 1.2,
|
||||
"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": []
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
"""
|
||||
genie.py – Thin MagicRobot subclass that integrates commands2.CommandScheduler.
|
||||
|
||||
GenieRobot bridges MagicBot's component-injection lifecycle with the
|
||||
commands2/PathPlannerLib command-based pattern by running the
|
||||
CommandScheduler once per robot loop iteration.
|
||||
"""
|
||||
|
||||
import commands2
|
||||
import magicbot
|
||||
|
||||
|
||||
class GenieRobot(magicbot.MagicRobot):
|
||||
"""
|
||||
MagicRobot subclass that runs the commands2 CommandScheduler each loop.
|
||||
|
||||
Inherit from this instead of MagicRobot whenever PathPlannerLib commands
|
||||
or other commands2 commands need to execute.
|
||||
"""
|
||||
|
||||
def robotPeriodic(self) -> None:
|
||||
"""Run the CommandScheduler every loop, then delegate to MagicRobot."""
|
||||
commands2.CommandScheduler.getInstance().run()
|
||||
return super().robotPeriodic()
|
||||
|
||||
def scheduleCommand(self, command: commands2.Command) -> None:
|
||||
"""
|
||||
Schedule a commands2 Command to run via the CommandScheduler.
|
||||
Used to kick off PathPlanner autos and named commands.
|
||||
|
||||
:param command: The command to schedule.
|
||||
"""
|
||||
commands2.CommandScheduler.getInstance().schedule(command)
|
||||
|
||||
def disabledPeriodic(self) -> None:
|
||||
"""Called periodically while the robot is disabled. No-op by default."""
|
||||
pass
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
frcYear = 2026
|
||||
wpiVersion = 2026.2.1
|
||||
|
||||
ctreVersion = 26.1.0
|
||||
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
|||
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
|
||||
|
|
@ -1,252 +0,0 @@
|
|||
#!/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" "$@"
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
@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
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit f3e38dc7ec323ba5cca8293a6df8de677d067d4d
|
||||
|
|
@ -1 +0,0 @@
|
|||
Subproject commit c0478b01a526712b8308ac329017857177a3c876
|
||||
11
libs.gradle
11
libs.gradle
|
|
@ -1,11 +0,0 @@
|
|||
build{
|
||||
dependsOn ':lib:Posty:lib:build'
|
||||
dependsOn ':lib:RoboLib:lib:build'
|
||||
}
|
||||
|
||||
dependencies{
|
||||
// Team 578 libraries
|
||||
implementation project(':lib:Posty:lib')
|
||||
implementation project(':lib:RoboLib:lib')
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
# Use this configuration file to control what RobotPy packages are installed
|
||||
# on your RoboRIO
|
||||
#
|
||||
|
||||
[tool.robotpy]
|
||||
|
||||
# Version of robotpy this project depends on
|
||||
robotpy_version = "2026.2.2"
|
||||
|
||||
# Which optional robotpy components should be installed?
|
||||
# -> equivalent to `pip install robotpy[extra1, ...]
|
||||
components = [
|
||||
#"all",
|
||||
"apriltag",
|
||||
"commands2", # Needed for PathPlanner + GenieRobot pattern
|
||||
# "cscore",
|
||||
# "romi",
|
||||
# "sim",
|
||||
# "xrp",
|
||||
]
|
||||
|
||||
# Other pip packages to install, such as vendor packages (each element
|
||||
# is equivalent to a line in requirements.txt)
|
||||
requires = [
|
||||
"robotpy-rev", # SparkMax (launcher motor)
|
||||
"robotpy-ctre", # WPI_TalonSRX (deploy motor, Phoenix 5), TalonFX (drive, turret, hopper), CANcoder, Pigeon2
|
||||
"robotpy-pathplannerlib", # Path following
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
target-version = "py312"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "W", "I"] # pycodestyle, pyflakes, isort
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
"""
|
||||
robot.py – Main robot file for Castor 2026 (Python/MagicBot port).
|
||||
|
||||
MyRobot extends GenieRobot (which extends MagicRobot and also runs the
|
||||
CommandScheduler each loop so PathPlannerLib commands work seamlessly).
|
||||
"""
|
||||
|
||||
import commands2
|
||||
import wpilib
|
||||
from pathplannerlib.auto import NamedCommands
|
||||
from pathplannerlib.config import RobotConfig
|
||||
|
||||
import constants
|
||||
from autonomous.chassis_align_shoot import ChassisAlignShootCommand
|
||||
from autonomous.turret_shoot import TurretShootCommand
|
||||
from components.controller import XboxController
|
||||
from components.drive import DriveComponent
|
||||
from components.hopper import HopperComponent
|
||||
from components.intake import IntakeComponent
|
||||
from components.turret import TurretComponent
|
||||
from genie import GenieRobot
|
||||
|
||||
|
||||
class _DriveSubsystemAdapter(commands2.Subsystem):
|
||||
"""
|
||||
Satisfies AutoBuilder.configure()'s subsystem requirement parameter.
|
||||
DriveComponent is not a commands2.Subsystem, so this adapter bridges the gap.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
class MyRobot(GenieRobot):
|
||||
# ── MagicBot component declarations (framework auto-injects instances) ──
|
||||
driver_controller: XboxController
|
||||
# Prefixed variable: MagicBot strips "driver_controller_" and injects
|
||||
# `port` into the XboxController component before its setup() runs.
|
||||
driver_controller_port: int = constants.OperatorConstants.CONTROLLER_PORT
|
||||
drive: DriveComponent
|
||||
hopper: HopperComponent
|
||||
intake: IntakeComponent
|
||||
turret: TurretComponent
|
||||
|
||||
def createObjects(self) -> None:
|
||||
"""
|
||||
Called by MagicBot before any component setup() methods.
|
||||
Class-level prefixed variables (e.g. driver_controller_port) are
|
||||
injected into components automatically after this method returns.
|
||||
"""
|
||||
# Tracks the active A/X turret-shoot command so it can be cancelled
|
||||
self._shoot_cmd: TurretShootCommand | None = None
|
||||
|
||||
def _post_setup(self) -> None:
|
||||
"""
|
||||
Called after all component setup() methods have run (from robotInit).
|
||||
Wire button bindings and PathPlanner named commands here because
|
||||
component objects are fully constructed at this point.
|
||||
"""
|
||||
# Pass the underlying wpilib controller to intake for rumble feedback
|
||||
self.intake.set_controller(self.driver_controller.this_controller)
|
||||
|
||||
# ── PathPlanner named commands ─────────────────────────────────────
|
||||
NamedCommands.registerCommand(
|
||||
"ChassisAlignShoot",
|
||||
ChassisAlignShootCommand(self.drive, self.hopper, self.turret),
|
||||
)
|
||||
NamedCommands.registerCommand(
|
||||
"TurretShoot",
|
||||
TurretShootCommand(self.hopper, self.turret, self.intake, self.drive),
|
||||
)
|
||||
NamedCommands.registerCommand(
|
||||
"RunIntake",
|
||||
commands2.FunctionalCommand(
|
||||
onInit=self.intake.intake,
|
||||
onExecute=lambda: None,
|
||||
onEnd=lambda interrupted: self.intake.stop_intake(),
|
||||
isFinished=lambda: False,
|
||||
),
|
||||
)
|
||||
# Aliases used in PathPlanner auto files
|
||||
NamedCommands.registerCommand(
|
||||
"Shoot preload",
|
||||
TurretShootCommand(self.hopper, self.turret, self.intake, self.drive),
|
||||
)
|
||||
NamedCommands.registerCommand(
|
||||
"Shoot Headed R-Tr",
|
||||
ChassisAlignShootCommand(self.drive, self.hopper, self.turret),
|
||||
)
|
||||
NamedCommands.registerCommand(
|
||||
"Shoot headed L-Tr",
|
||||
ChassisAlignShootCommand(self.drive, self.hopper, self.turret),
|
||||
)
|
||||
|
||||
# ── AutoBuilder / auto chooser ─────────────────────────────────────
|
||||
try:
|
||||
robot_config = RobotConfig.fromGUISettings()
|
||||
drive_adapter = _DriveSubsystemAdapter()
|
||||
self.drive.inject_drive_adapter(drive_adapter, robot_config)
|
||||
except Exception as e:
|
||||
print(f"[robot.py] AutoBuilder configuration failed: {e}")
|
||||
|
||||
def teleopPeriodic(self) -> None:
|
||||
# ── Drive ──────────────────────────────────────────────────────────
|
||||
self.drive.set_chassis_speeds_field_relative(
|
||||
-self.driver_controller.left_y,
|
||||
-self.driver_controller.left_x,
|
||||
-self.driver_controller.right_x,
|
||||
)
|
||||
|
||||
# ── One-shot actions (fire when button is released) ────────────────
|
||||
if self.driver_controller.left_bumper_was_pressed():
|
||||
self.turret.home_turret()
|
||||
|
||||
if self.driver_controller.right_bumper_was_pressed():
|
||||
self.intake.intake()
|
||||
|
||||
if self.driver_controller.y_button_was_pressed():
|
||||
self.scheduleCommand(
|
||||
commands2.SequentialCommandGroup(
|
||||
commands2.InstantCommand(self.intake.deploy),
|
||||
commands2.WaitCommand(2.0),
|
||||
commands2.InstantCommand(self.intake.stop_deploy),
|
||||
)
|
||||
)
|
||||
|
||||
# ── Held actions ───────────────────────────────────────────────────
|
||||
if self.driver_controller.start_button_pressed():
|
||||
self.intake.reset_deploy()
|
||||
|
||||
if self.driver_controller.b_button_pressed():
|
||||
self.intake.reverse_intake()
|
||||
self.hopper.reverse_kicker()
|
||||
|
||||
# A or X held → schedule turret-shoot command; cancel when released
|
||||
shooting = (
|
||||
self.driver_controller.a_button_pressed()
|
||||
or self.driver_controller.x_button_pressed()
|
||||
)
|
||||
if shooting:
|
||||
if self._shoot_cmd is None or self._shoot_cmd.isFinished():
|
||||
self._shoot_cmd = TurretShootCommand(
|
||||
self.hopper, self.turret, self.intake, self.drive
|
||||
)
|
||||
self.scheduleCommand(self._shoot_cmd)
|
||||
elif self._shoot_cmd is not None and not self._shoot_cmd.isFinished():
|
||||
self._shoot_cmd.cancel()
|
||||
self._shoot_cmd = None
|
||||
|
||||
def autonomousInit(self) -> None:
|
||||
auto_cmd = self.drive.get_auto_command()
|
||||
if auto_cmd is not None:
|
||||
self.scheduleCommand(auto_cmd)
|
||||
|
||||
def disabledInit(self) -> None:
|
||||
self.drive.set_brake_mode(True)
|
||||
|
||||
def robotInit(self) -> None:
|
||||
super().robotInit()
|
||||
self.drive.set_brake_mode(False)
|
||||
self._post_setup()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
wpilib.run(MyRobot)
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
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");
|
||||
|
||||
include ':lib:Posty:lib'
|
||||
include ':lib:RoboLib:lib'
|
||||
105
simgui-ds.json
105
simgui-ds.json
|
|
@ -1,105 +0,0 @@
|
|||
{
|
||||
"Keyboard 0 Settings": {
|
||||
"window": {
|
||||
"visible": true
|
||||
}
|
||||
},
|
||||
"keyboardJoysticks": [
|
||||
{
|
||||
"axisConfig": [
|
||||
{
|
||||
"decKey": 65,
|
||||
"incKey": 68
|
||||
},
|
||||
{
|
||||
"decKey": 83,
|
||||
"incKey": 87
|
||||
},
|
||||
{
|
||||
"decayRate": 0.009999999776482582,
|
||||
"keyRate": 0.009999999776482582
|
||||
},
|
||||
{},
|
||||
{
|
||||
"decKey": 81,
|
||||
"incKey": 69
|
||||
}
|
||||
],
|
||||
"axisCount": 5,
|
||||
"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
|
||||
}
|
||||
],
|
||||
"robotJoysticks": [
|
||||
{
|
||||
"guid": "Keyboard0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,220 +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;
|
||||
|
||||
import com.ctre.phoenix6.signals.InvertedValue;
|
||||
|
||||
import edu.wpi.first.apriltag.AprilTagFieldLayout;
|
||||
import edu.wpi.first.apriltag.AprilTagFields;
|
||||
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.Transform2d;
|
||||
import edu.wpi.first.math.geometry.Transform3d;
|
||||
import edu.wpi.first.units.measure.Angle;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
|
||||
public static class CameraConstanst {
|
||||
|
||||
public static class IDFilters {
|
||||
|
||||
public static final int[] RED_HUB_SHOOTING_IDS = new int[]{8, 9, 10, 11};
|
||||
public static final int[] BLUE_HUB_SHOOTING_IDS = new int[]{27, 26, 25, 24};
|
||||
}
|
||||
|
||||
public static final String BACK_CAMERA_NAME = "limelight-back";
|
||||
public static final int BACK_LOCALIZATION_PIPELINE_NUMBER = 0;
|
||||
public static final int BACK_HUB_TRACKING_2D_PIPELINE_NUMBER = 1;
|
||||
public static final int BACK_HUB_TRACKING_3D_PIPELINE_NUMBER = 2;
|
||||
|
||||
public static final String FRONT_CAMERA_NAME = "limelight-front";
|
||||
public static final int FRONT_LOCALIZATION_PIPELINE_NUMBER = 0;
|
||||
public static final double[] BLUE_ZONE_COOR = new double[]{0, 3.5};
|
||||
public static final double[] RED_ZONE_COOR = new double[]{13, 16};
|
||||
public static final double[] NEUTRAL_ZONE_COOR = new double[]{5.5, 11};
|
||||
public static final double[] NEUTRAL1_ZONE_COOR = new double[]{5.5, 11, 0, 3};
|
||||
public static final double[] NEUTRAL2_ZONE_COOR = new double[]{5.5, 11, 5, 8};
|
||||
public static final double[] BLUE1_ZONE_COOR = new double[]{0, 3.5, 0, 3};
|
||||
public static final double[] BLUE2_ZONE_COOR = new double[]{0, 3.5, 5, 8};
|
||||
public static final double[] RED1_ZONE_COOR = new double[]{13, 16, 0, 3};
|
||||
public static final double[] RED2_ZONE_COOR = new double[]{13, 16, 5, 8};
|
||||
|
||||
}
|
||||
|
||||
public static class AdvantageKitConstants {
|
||||
|
||||
public enum RobotType {
|
||||
SIM,
|
||||
REAL,
|
||||
REPLAY
|
||||
}
|
||||
public static final RobotType CURRENT_MODE = RobotType.REAL;
|
||||
}
|
||||
// Swerve offsets as of 3/2/26
|
||||
|
||||
public static class SwerveDriveOffsets {
|
||||
|
||||
public static final float FRONT_LEFT_MOTOR_OFFSET = -0.336426f;
|
||||
public static final float FRONT_RIGHT_MOTOR_OFFSET = 0.108887f;
|
||||
public static final float BACK_LEFT_MOTOR_OFFSET = -0.492432f;
|
||||
public static final float BACK_RIGHT_MOTOR_OFFSET = 0.470215f;
|
||||
}
|
||||
|
||||
/*
|
||||
* Numbers starting with 1 (E.g. 11, 12, 13) are in the Front Left of the robot
|
||||
* Numbers starting with 2 (E.g. 21, 22, 23) are in the Front Right of the robot
|
||||
* Numbers starting with 3 (E.g. 31, 32, 33) are in the Back Left of the robot
|
||||
* Numbers starting with 4 (E.g. 41, 42, 43) are in the Back Right of the robot
|
||||
* Laters numbers will be added for more subsystems
|
||||
* Single diget numbers (E.g. 1, 2, 3) are extra, non-motor, pieces that require IDs, such as the Pigeon
|
||||
*/
|
||||
public static class SwerveDriveIDs {
|
||||
|
||||
public static final int FRONT_LEFT_STEER_ID = 11;
|
||||
public static final int FRONT_LEFT_DRIVE_ID = 12;
|
||||
public static final int FRONT_LEFT_ENCODER_ID = 13;
|
||||
public static final int FRONT_RIGHT_STEER_ID = 21;
|
||||
public static final int FRONT_RIGHT_DRIVE_ID = 22;
|
||||
public static final int FRONT_RIGHT_ENCODER_ID = 23;
|
||||
public static final int BACK_LEFT_STEER_ID = 31;
|
||||
public static final int BACK_LEFT_DRIVE_ID = 32;
|
||||
public static final int BACK_LEFT_ENCODER_ID = 33;
|
||||
public static final int BACK_RIGHT_STEER_ID = 41;
|
||||
public static final int BACK_RIGHT_DRIVE_ID = 42;
|
||||
public static final int BACK_RIGHT_ENCODER_ID = 43;
|
||||
}
|
||||
|
||||
public static class RobotChassisLimits {
|
||||
// Max velocity in meters per second
|
||||
|
||||
public static final double MAX_ROBOT_LINEAR_VELOCITY = 3;
|
||||
// In meters per second squared
|
||||
public static final double MAX_ROBOT_LINEAR_VELOCITY_ACCEL = 2;
|
||||
|
||||
// In radians per second
|
||||
public static final double MAX_ROBOT_ANGULAR_VELOCITY = Math.PI;
|
||||
// In radians per second squared
|
||||
public static final double MAX_ROBOT_ANGULAR_VELOCITY_ACCEL = Math.PI;
|
||||
}
|
||||
|
||||
//Bird
|
||||
public static class ExtraIDEntities {
|
||||
|
||||
public static final int PIGEON_ID = 1;
|
||||
}
|
||||
|
||||
public static class IntakeConstants {
|
||||
|
||||
public static final int DEPLOY_MOTOR_ID = 17;
|
||||
public static final boolean DEPLOY_MOTOR_INVERTED = true; // TODO: Test this
|
||||
|
||||
public static final int INTAKE_MOTOR_ID = 2;
|
||||
public static final InvertedValue INTAKE_MOTOR_DIRECTION = InvertedValue.Clockwise_Positive; // TODO: Test this
|
||||
}
|
||||
|
||||
public static class ShooterConstants {
|
||||
|
||||
public static final int LAUNCHER_MOTOR_ID = 3;
|
||||
public static final boolean LAUNCHER_MOTOR_INVERTED = false;
|
||||
|
||||
public static final int TURRET_MOTOR_ID = 4;
|
||||
public static final InvertedValue TURRET_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
|
||||
public static final int TURRET_LIMIT_CHANNEL = 9;
|
||||
public static final Angle LIMIT_AXIMUTH_POS = edu.wpi.first.units.Units.Degrees.of(165);
|
||||
public static final Angle LIMIT_AXIMUTH_NEG = edu.wpi.first.units.Units.Degrees.of(5);
|
||||
public static final double HOMING_SPEED = .05;
|
||||
public static final double TURRET_GEAR_RATIO = 6;
|
||||
|
||||
public static final int HOOD_SERVO_CHANNEL = 0;
|
||||
public static final boolean HOOD_SERVO_INVERTED = false; // TODO: Test this
|
||||
public static final int HOOD_ENCODER_ID = 4;
|
||||
public static final Angle TARGET_ELEVATION_DIF = edu.wpi.first.units.Units.Degrees.of(1);
|
||||
public static final Angle LIMIT_ELEVATION_POS = edu.wpi.first.units.Units.Degrees.of(90);
|
||||
public static final Angle LIMIT_ELEVATION_NEG = edu.wpi.first.units.Units.Degrees.of(0);
|
||||
public static final double DEFLECTOR_STORED_ANGLE = 0;
|
||||
public static final double DEFLECTOR_SET_ANGLE1 = 100;
|
||||
public static final double DEFLECTOR_SET_ANGLE2 = 200;
|
||||
public static final double DEFLECTOR_SET_ANGLE3 = 300;
|
||||
public static final double DEFLECTOR_SERVO_RATIO = 1.0;
|
||||
}
|
||||
|
||||
public static class HopperConstants {
|
||||
|
||||
public static final int KICKER_MOTOR_ID = 9;
|
||||
public static final InvertedValue KICKER_MOTOR_DIRECTION = InvertedValue.Clockwise_Positive;
|
||||
|
||||
public static final int SPINDEXER_MOTOR_ID = 8;
|
||||
public static final InvertedValue SPINDEXER_MOTOR_DIRECTION = InvertedValue.CounterClockwise_Positive;
|
||||
}
|
||||
|
||||
public static class FieldPoses {
|
||||
|
||||
private static AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
|
||||
|
||||
public static Pose3d BLUE_HUB_POSE = fieldTags.getTagPose(26).get().transformBy(new Transform3d(new Transform2d(-0.5207, 0, Rotation2d.kZero)));
|
||||
public static Pose3d RED_HUB_POSE = fieldTags.getTagPose(10).get().transformBy(new Transform3d(new Transform2d(-0.5207, 0, Rotation2d.kZero)));
|
||||
|
||||
// These are the field targets for passing fuel to the Alliance Zone or to the Neutral Zone from the opponent's side.
|
||||
// Left/Right are from driver's perspective. Coordinates assume origin at blue side of field.
|
||||
// Rotation are zero because they don't matter.
|
||||
public static Pose3d BLUE_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE = new Pose3d(1.99, 6.35, 0, new Rotation3d());
|
||||
public static Pose3d BLUE_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE = new Pose3d(1.99, 1.72, 0, new Rotation3d());
|
||||
public static Pose3d BLUE_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE = new Pose3d(8.27, 6.35, 0, new Rotation3d());
|
||||
public static Pose3d BLUE_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE = new Pose3d(8.27, 1.72, 0, new Rotation3d());
|
||||
|
||||
public static Pose3d RED_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE = new Pose3d(14.55, 1.72, 0, new Rotation3d());
|
||||
public static Pose3d RED_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE = new Pose3d(14.55, 6.35, 0, new Rotation3d());
|
||||
public static Pose3d RED_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE = new Pose3d(8.27, 1.72, 0, new Rotation3d());
|
||||
public static Pose3d RED_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE = new Pose3d(8.27, 6.35, 0, new Rotation3d());
|
||||
|
||||
|
||||
}
|
||||
|
||||
// These represent the dividing lines for the regions in our shooting strategy.
|
||||
public static class ShootingRegionDimensions {
|
||||
|
||||
public static double BLUE_ALLIANCE_ZONE_REGION_X_MAX = 3.5;
|
||||
public static double RED_ALLIANCE_ZONE_REGION_X_MIN = 13.0;
|
||||
public static double NEUTRAL_ZONE_REGION_X_MIN = 5.5;
|
||||
public static double NEUTRAL_ZONE_REGION_X_MAX = 11.0;
|
||||
public static double BLUE_RIGHT_REGION_Y_MAX = 3.0;
|
||||
public static double RED_LEFT_REGION_Y_MAX = 3.0; // same meaning as the previous one, but from red perspective
|
||||
public static double BLUE_LEFT_REGION_Y_MIN = 5.0;
|
||||
public static double RED_RIGHT_REGION_Y_MIN = 5.0; // same meaning as the previous one, but from red perspective
|
||||
|
||||
}
|
||||
|
||||
// Regions that define the AutoTurret shooting behaviors.
|
||||
// Color ID in the name reflects robot's alliance since region definitions vary by alliance.
|
||||
// Left/Right are from driver's perspective.
|
||||
public enum ShootingRegion {
|
||||
NON_SHOOTING_REGION, // Any part of the field that's not in one of the regions
|
||||
BLUE_OWN_ALLIANCE_ZONE,
|
||||
BLUE_LEFT_NEUTRAL_ZONE,
|
||||
BLUE_RIGHT_NEUTRAL_ZONE,
|
||||
BLUE_LEFT_OPPONENT_ALLIANCE_ZONE,
|
||||
BLUE_RIGHT_OPPONENT_ALLIANCE_ZONE,
|
||||
RED_OWN_ALLIANCE_ZONE,
|
||||
RED_LEFT_NEUTRAL_ZONE,
|
||||
RED_RIGHT_NEUTRAL_ZONE,
|
||||
RED_LEFT_OPPONENT_ALLIANCE_ZONE,
|
||||
RED_RIGHT_OPPONENT_ALLIANCE_ZONE
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +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;
|
||||
|
||||
import edu.wpi.first.wpilibj.RobotBase;
|
||||
|
||||
/**
|
||||
* Do NOT add any static variables to this class, or any initialization at all. Unless you know what
|
||||
* you are doing, do not modify this file except to change the parameter class to the startRobot
|
||||
* call.
|
||||
*/
|
||||
public final class Main {
|
||||
private Main() {}
|
||||
|
||||
/**
|
||||
* Main initialization function. Do not perform any initialization here.
|
||||
*
|
||||
* <p>If you change your main robot class, change the parameter type.
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
RobotBase.startRobot(Robot::new);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,188 +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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Scanner;
|
||||
|
||||
import org.fairportrobotics.frc.posty.PostyManager;
|
||||
import org.littletonrobotics.junction.LoggedRobot;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
import org.littletonrobotics.junction.networktables.NT4Publisher;
|
||||
import org.littletonrobotics.junction.wpilog.WPILOGWriter;
|
||||
|
||||
import com.ctre.phoenix6.swerve.SwerveModule;
|
||||
|
||||
import edu.wpi.first.wpilibj.Filesystem;
|
||||
import edu.wpi.first.wpilibj.PowerDistribution;
|
||||
import edu.wpi.first.wpilibj.PowerDistribution.ModuleType;
|
||||
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 LoggedRobot {
|
||||
private Command m_autonomousCommand;
|
||||
|
||||
private RobotContainer m_robotContainer;
|
||||
|
||||
public static String getVersion() {
|
||||
try {
|
||||
Scanner scan = new Scanner(new File(Filesystem.getDeployDirectory().getAbsolutePath() + "/versionfile.txt"));
|
||||
String ver = scan.nextLine();
|
||||
scan.close();
|
||||
|
||||
return ver;
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is run when the robot is first started up and should be used
|
||||
* for any
|
||||
* initialization code.
|
||||
*/
|
||||
@Override
|
||||
public void robotInit() {
|
||||
|
||||
String swVersion = getVersion();
|
||||
Logger.recordMetadata("ProjectName", "MyProject"); // Set a metadata value
|
||||
Logger.recordMetadata("Software Version", swVersion);
|
||||
|
||||
if (isReal()) {
|
||||
Logger.addDataReceiver(new WPILOGWriter()); // Log to a USB stick ("/U/logs")
|
||||
Logger.addDataReceiver(new NT4Publisher()); // Publish data to NetworkTables
|
||||
new PowerDistribution(1, ModuleType.kRev); // Enables power distribution logging
|
||||
} else {
|
||||
setUseTiming(false); // Run as fast as possible
|
||||
// String logPath = LogFileUtil.findReplayLog(); // Pull the replay log from AdvantageScope (or prompt the user)
|
||||
// Logger.setReplaySource(new WPILOGReader(logPath)); // Read replay log
|
||||
// Logger.addDataReceiver(new WPILOGWriter(LogFileUtil.addPathSuffix(logPath, "_sim"))); // Save outputs to a new log
|
||||
Logger.addDataReceiver(new NT4Publisher()); // Publish data to NetworkTables
|
||||
}
|
||||
|
||||
// Logger.disableDeterministicTimestamps() // See "Deterministic Timestamps" in
|
||||
// the "Understanding Data Flow" page
|
||||
Logger.start(); // Start logging! No more data receivers, replay sources, or metadata values may
|
||||
// be added.
|
||||
|
||||
// Print out software version
|
||||
Logger.recordOutput("Software Version", swVersion);
|
||||
System.out.println("Robot Software Version: " + swVersion);
|
||||
|
||||
// Instantiate our RobotContainer. This will perform all our button bindings,
|
||||
// and put our
|
||||
// autonomous chooser on the dashboard.
|
||||
m_robotContainer = new RobotContainer();
|
||||
|
||||
// Collect Posty tests
|
||||
PostyManager.getInstance().collectTests();
|
||||
|
||||
// Run all POST tests after robot has been initialized
|
||||
PostyManager.getInstance().runAllPOSTs();
|
||||
|
||||
|
||||
m_robotContainer.driveSubsystem.driveSystem.setBrakeMode(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* This runs after the mode specific periodic functions, but before LiveWindow
|
||||
* and
|
||||
* SmartDashboard integrated updating.
|
||||
*/
|
||||
@Override
|
||||
public void robotPeriodic() {
|
||||
// Runs the Scheduler. This is responsible for polling buttons, adding
|
||||
// newly-scheduled
|
||||
// commands, running already-scheduled commands, removing finished or
|
||||
// interrupted commands,
|
||||
// and running subsystem periodic() methods. This must be called from the
|
||||
// robot's periodic
|
||||
// block in order for anything in the Command-based framework to work.
|
||||
CommandScheduler.getInstance().run();
|
||||
}
|
||||
|
||||
/** This function is called once each time the robot enters Disabled mode. */
|
||||
@Override
|
||||
public void disabledInit() {
|
||||
m_robotContainer.driveSubsystem.driveSystem.setBrakeMode(true);
|
||||
}
|
||||
|
||||
@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() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +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;
|
||||
|
||||
import com.pathplanner.lib.auto.NamedCommands;
|
||||
|
||||
import edu.wpi.first.wpilibj.GenericHID.RumbleType;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||
import edu.wpi.first.wpilibj2.command.button.Trigger;
|
||||
import frc.robot.Constants.OperatorConstants;
|
||||
import frc.robot.commands.AutoShootCommandChassisTurret;
|
||||
import frc.robot.commands.AutoTurretCommand;
|
||||
import frc.robot.commands.AutoTurretShootCommand;
|
||||
import frc.robot.commands.Reverse;
|
||||
import frc.robot.commands.SetDeflectorCommand;
|
||||
import frc.robot.subsystems.DriveSubsystem;
|
||||
import frc.robot.subsystems.HopperSubsystem;
|
||||
import frc.robot.subsystems.IntakeSubsystem;
|
||||
import frc.robot.subsystems.TurretSubsystem;
|
||||
|
||||
/**
|
||||
* 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...
|
||||
// Replace with CommandPS4Controller or CommandJoystick if needed
|
||||
|
||||
private final CommandXboxController m_driverController
|
||||
= new CommandXboxController(OperatorConstants.kDriverControllerPort);
|
||||
|
||||
// private final CommandPS4Controller m_driverController = new CommandPS4Controller(OperatorConstants.kDriverControllerPort);
|
||||
public final DriveSubsystem driveSubsystem = new DriveSubsystem(m_driverController);
|
||||
|
||||
public final IntakeSubsystem intakeSubsystem = new IntakeSubsystem();
|
||||
|
||||
public final TurretSubsystem turretSubsystem = new TurretSubsystem();
|
||||
|
||||
public final HopperSubsystem hopperSubsystem = new HopperSubsystem();
|
||||
|
||||
/**
|
||||
* The container for the robot. Contains subsystems, OI devices, and
|
||||
* commands.
|
||||
*/
|
||||
public RobotContainer() {
|
||||
|
||||
// turretSubsystem.setDefaultCommand(new AutoTurretCommand(turretSubsystem, driveSubsystem));
|
||||
// turretSubsystem.homeTurret();
|
||||
// Configure the trigger bindings
|
||||
configureBindings();
|
||||
|
||||
NamedCommands.registerCommand("ChassisAlignShoot", new AutoShootCommandChassisTurret(driveSubsystem, hopperSubsystem, turretSubsystem));
|
||||
NamedCommands.registerCommand("RunIntake", intakeSubsystem.intake(m_driverController.getHID()));
|
||||
NamedCommands.registerCommand("TurretShoot", new AutoTurretShootCommand(hopperSubsystem, turretSubsystem, intakeSubsystem, driveSubsystem));
|
||||
|
||||
turretSubsystem.setDefaultCommand(new AutoTurretCommand(turretSubsystem, driveSubsystem));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
// m_driverController.povDown().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE));
|
||||
// m_driverController.povLeft().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE1));
|
||||
// m_driverController.povRight().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE3));
|
||||
// m_driverController.povUp().onTrue(new SetDeflectorCommand(turretSubsystem, Constants.ShooterConstants.DEFLECTOR_SET_ANGLE2));
|
||||
|
||||
//m_driverController.back().whileTrue(new AutoShootCommandChassisTurretPathPlanner(driveSubsystem, hopperSubsystem, turretSubsystem));
|
||||
m_driverController.leftBumper().onTrue(Commands.runOnce(() -> turretSubsystem.homeTurret(), turretSubsystem));
|
||||
m_driverController.rightBumper().onTrue(Commands.parallel(intakeSubsystem.intake(m_driverController.getHID())));
|
||||
m_driverController.start().whileTrue(intakeSubsystem.resetDeploy());
|
||||
m_driverController.a().whileTrue((new AutoTurretShootCommand(hopperSubsystem, turretSubsystem, intakeSubsystem, driveSubsystem)));
|
||||
m_driverController.x().whileTrue((new AutoTurretShootCommand(hopperSubsystem, turretSubsystem, intakeSubsystem, driveSubsystem)));
|
||||
m_driverController.b().whileTrue(new Reverse(intakeSubsystem, hopperSubsystem, m_driverController.getHID()));
|
||||
m_driverController.y().onTrue(intakeSubsystem.deploy());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Commands.parallel(intakeSubsystem.deploy(), Commands.run(() -> {
|
||||
turretSubsystem.homeTurret();
|
||||
}, turretSubsystem), driveSubsystem.getAutoCommand());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
package frc.robot;
|
||||
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.Constants.ShootingRegion;
|
||||
import frc.robot.Constants.ShootingRegionDimensions;
|
||||
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.units.measure.Angle;
|
||||
|
||||
public class Utils {
|
||||
|
||||
/**
|
||||
* Calculates the needed angle of the turret for a distance from the HUB.
|
||||
* @param distanceToTag
|
||||
* @return number of rotations of the turret, robot relative
|
||||
*/
|
||||
public static double calculateTurretAngleFromCameraTagDistance(double distanceToTag){
|
||||
|
||||
// Calculate turret Angle
|
||||
double cameraDistanceToTarget = distanceToTag + .6;
|
||||
double cameraToShootDistance = 0.26035;
|
||||
// a^2 + b^2 = c^2
|
||||
double shooterDistanceToTarget = Math
|
||||
.sqrt(Math.pow(cameraDistanceToTarget, 2) + Math.pow(cameraToShootDistance, 2));
|
||||
double angleAtShooter = Math.acos(cameraToShootDistance / shooterDistanceToTarget);
|
||||
double robotTurretAngle = (Math.PI / 2) - angleAtShooter;
|
||||
double robotTurretRotations = (robotTurretAngle / Math.PI);
|
||||
|
||||
return robotTurretRotations;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Determines the region for the robot based on its location and alliance.
|
||||
* Assumes the robot is a 27" square. Thresholds based on observations from simulator.
|
||||
* @param robotPose: the robot's pose
|
||||
* @param alliance: the red/blue alliance of the robot, as a sanity check
|
||||
* @return the robot's shooting region
|
||||
*/
|
||||
public static ShootingRegion findRobotShootingRegion(Pose3d robotPose, Alliance alliance){
|
||||
ShootingRegion region = Constants.ShootingRegion.NON_SHOOTING_REGION; // the default return value if robot isn't in a valid region
|
||||
double robotX = robotPose.getX();
|
||||
double robotY = robotPose.getY();
|
||||
|
||||
// Receommended: Add a sanity check for invalid robot poses.
|
||||
|
||||
if (alliance == Alliance.Blue) {
|
||||
if (robotX < Constants.ShootingRegionDimensions.BLUE_ALLIANCE_ZONE_REGION_X_MAX) {
|
||||
region = Constants.ShootingRegion.BLUE_OWN_ALLIANCE_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MIN &&
|
||||
robotX < Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MAX &&
|
||||
robotY > Constants.ShootingRegionDimensions.BLUE_LEFT_REGION_Y_MIN) {
|
||||
region = Constants.ShootingRegion.BLUE_LEFT_NEUTRAL_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MIN &&
|
||||
robotX < Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MAX &&
|
||||
robotY < Constants.ShootingRegionDimensions.BLUE_RIGHT_REGION_Y_MAX) {
|
||||
region = Constants.ShootingRegion.BLUE_RIGHT_NEUTRAL_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN &&
|
||||
robotY > Constants.ShootingRegionDimensions.BLUE_LEFT_REGION_Y_MIN) {
|
||||
region = Constants.ShootingRegion.BLUE_LEFT_OPPONENT_ALLIANCE_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN &&
|
||||
robotY < Constants.ShootingRegionDimensions.BLUE_RIGHT_REGION_Y_MAX) {
|
||||
region = Constants.ShootingRegion.BLUE_RIGHT_OPPONENT_ALLIANCE_ZONE;
|
||||
}
|
||||
}
|
||||
else if (alliance == Alliance.Red) {
|
||||
if (robotX > Constants.ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN) {
|
||||
region = Constants.ShootingRegion.RED_OWN_ALLIANCE_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MIN &&
|
||||
robotX < Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MAX &&
|
||||
robotY < Constants.ShootingRegionDimensions.RED_LEFT_REGION_Y_MAX) {
|
||||
region = Constants.ShootingRegion.RED_LEFT_NEUTRAL_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MIN &&
|
||||
robotX < Constants.ShootingRegionDimensions.NEUTRAL_ZONE_REGION_X_MAX &&
|
||||
robotY > Constants.ShootingRegionDimensions.RED_RIGHT_REGION_Y_MIN) {
|
||||
region = Constants.ShootingRegion.RED_RIGHT_NEUTRAL_ZONE;
|
||||
}
|
||||
else if (robotX < Constants.ShootingRegionDimensions.BLUE_ALLIANCE_ZONE_REGION_X_MAX &&
|
||||
robotY < Constants.ShootingRegionDimensions.RED_LEFT_REGION_Y_MAX) {
|
||||
region = Constants.ShootingRegion.RED_LEFT_OPPONENT_ALLIANCE_ZONE;
|
||||
}
|
||||
else if (robotX > Constants.ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN &&
|
||||
robotY > Constants.ShootingRegionDimensions.RED_RIGHT_REGION_Y_MIN) {
|
||||
region = Constants.ShootingRegion.RED_RIGHT_OPPONENT_ALLIANCE_ZONE;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.recordOutput("Utils-ShootingRegion", region);
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
public static double getHoodAngleForDistance(double distanceInMeters){
|
||||
if(distanceInMeters >= 4){
|
||||
return 200;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static double getLauncherRPMForDistance(double distanceInMeters){
|
||||
return Math.min((667.557*distanceInMeters) + 1500.699, 5000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the appropriate shooting target for the robot based on its alliance
|
||||
* and its current region on the field. There are 10 possible targets:
|
||||
* Scoring hub, 2x passing from Neutral Zone, 2x passing from opponent's Alliance Zone,
|
||||
* and these exist for both red and blue alliances.
|
||||
* Right/left are from driver's perspective.
|
||||
* @param region: the identifier of the robot's current field region
|
||||
* @param alliance: the red/blue alliance of the robot, as a sanity check
|
||||
* @return the shooting target for a robot with the provided properties. Returns all-zero
|
||||
* Pose3d object if the region/alliance combination is invalid.
|
||||
*/
|
||||
public static Pose3d findShootingTarget(ShootingRegion region, Alliance alliance){
|
||||
|
||||
Pose3d shootingTarget = new Pose3d();
|
||||
if (alliance == Alliance.Blue) {
|
||||
switch (region) {
|
||||
case BLUE_OWN_ALLIANCE_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.BLUE_HUB_POSE;
|
||||
break;
|
||||
case BLUE_LEFT_NEUTRAL_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.BLUE_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
case BLUE_RIGHT_NEUTRAL_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.BLUE_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
case BLUE_LEFT_OPPONENT_ALLIANCE_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.BLUE_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
case BLUE_RIGHT_OPPONENT_ALLIANCE_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.BLUE_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (alliance == Alliance.Red) {
|
||||
switch (region) {
|
||||
case RED_OWN_ALLIANCE_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.RED_HUB_POSE;
|
||||
break;
|
||||
case RED_LEFT_NEUTRAL_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.RED_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
case RED_RIGHT_NEUTRAL_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.RED_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
case RED_LEFT_OPPONENT_ALLIANCE_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.RED_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
case RED_RIGHT_OPPONENT_ALLIANCE_ZONE:
|
||||
shootingTarget = Constants.FieldPoses.RED_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return shootingTarget;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
package frc.robot.commands;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import edu.wpi.first.apriltag.AprilTagFieldLayout;
|
||||
import edu.wpi.first.apriltag.AprilTagFields;
|
||||
import edu.wpi.first.math.controller.PIDController;
|
||||
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.Transform2d;
|
||||
import edu.wpi.first.math.geometry.Transform3d;
|
||||
import edu.wpi.first.math.geometry.Translation2d;
|
||||
import edu.wpi.first.math.geometry.Translation3d;
|
||||
import edu.wpi.first.units.Units;
|
||||
import edu.wpi.first.units.measure.Angle;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.Utils;
|
||||
import frc.robot.subsystems.DriveSubsystem;
|
||||
import frc.robot.subsystems.HopperSubsystem;
|
||||
import frc.robot.subsystems.TurretSubsystem;
|
||||
|
||||
public class AutoShootCommandChassisTurret extends Command{
|
||||
|
||||
// For Chassis Control
|
||||
private DriveSubsystem driveSubsystem;
|
||||
|
||||
private HopperSubsystem hopperSubsystem;
|
||||
private TurretSubsystem turretSubsystem;
|
||||
|
||||
private PIDController cameraAutoCenterController;
|
||||
private PIDController deadreckoningAutoCenterController;
|
||||
|
||||
private int[] tagFilters;
|
||||
|
||||
private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
|
||||
|
||||
private Pose3d closestTag;
|
||||
|
||||
private final double chassisRotateSpeed = Math.PI * 0.1;
|
||||
|
||||
public AutoShootCommandChassisTurret(DriveSubsystem driveSubsystem, HopperSubsystem hopperSubsystem, TurretSubsystem turretSubsystem)
|
||||
{
|
||||
this.driveSubsystem = driveSubsystem;
|
||||
this.hopperSubsystem = hopperSubsystem;
|
||||
this.turretSubsystem = turretSubsystem;
|
||||
|
||||
this.addRequirements(driveSubsystem, hopperSubsystem, turretSubsystem);
|
||||
|
||||
cameraAutoCenterController = new PIDController(0.15, 0.0, 0.0);
|
||||
cameraAutoCenterController.setTolerance(0.2); // Units degrees
|
||||
cameraAutoCenterController.setSetpoint(0);
|
||||
|
||||
|
||||
deadreckoningAutoCenterController = new PIDController(Math.PI * 0.1, 0, 0.0);
|
||||
deadreckoningAutoCenterController.setTolerance(0.2); // Units is rotations
|
||||
deadreckoningAutoCenterController.enableContinuousInput(-Math.PI, Math.PI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
DriverStation.getAlliance().ifPresent((aliance) -> {
|
||||
if (aliance == Alliance.Blue) {
|
||||
tagFilters = Constants.CameraConstanst.IDFilters.BLUE_HUB_SHOOTING_IDS;
|
||||
} else {
|
||||
tagFilters = Constants.CameraConstanst.IDFilters.RED_HUB_SHOOTING_IDS;
|
||||
}
|
||||
});
|
||||
|
||||
turretSubsystem.setLauncher(3000);
|
||||
turretSubsystem.setTargetElevation(Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE);
|
||||
hopperSubsystem.spindexerOn();
|
||||
cameraAutoCenterController.calculate(-100);
|
||||
|
||||
// Change to HUB tracking pipeline
|
||||
LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME, Constants.CameraConstanst.BACK_HUB_TRACKING_3D_PIPELINE_NUMBER);
|
||||
LimelightHelpers.SetFiducialIDFiltersOverride(Constants.CameraConstanst.BACK_CAMERA_NAME, tagFilters);
|
||||
|
||||
Pose3d botPose = driveSubsystem.getBotPose();
|
||||
// Find closest target to us
|
||||
List<Pose3d> tagPoses = Arrays.stream(tagFilters).mapToObj(tagId -> fieldTags.getTagPose(tagId).get()).toList();
|
||||
closestTag = botPose.nearest(tagPoses);
|
||||
Logger.recordOutput("AutoAlign-ClosestAprilTagPose", closestTag);
|
||||
|
||||
Translation2d delta = botPose.getTranslation().toTranslation2d().minus(closestTag.getTranslation().toTranslation2d());
|
||||
Logger.recordOutput("AutoAlign-ClosestAprilTagTransform", delta);
|
||||
|
||||
deadreckoningAutoCenterController.setSetpoint(delta.getAngle().plus(Rotation2d.kZero).getRadians());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
// Need to compute shoot speed and angle
|
||||
|
||||
Logger.recordOutput("AutoAlign-CenteringError", cameraAutoCenterController.getError());
|
||||
|
||||
// No april tag in camera view. Rotate towards our theoretical closest tag
|
||||
if(!LimelightHelpers.getTV(Constants.CameraConstanst.BACK_CAMERA_NAME)){
|
||||
Logger.recordOutput("AutoAlignState-Tracking", "Deadreckoning");
|
||||
|
||||
Pose3d botPose = driveSubsystem.getBotPose();
|
||||
//driveSubsystem.rotateChassis(-deadreckoningAutoCenterController.calculate(botPose.getRotation().toRotation2d().getRadians()));
|
||||
}
|
||||
else // We have an april tag, center it to the camera frame
|
||||
{
|
||||
Logger.recordOutput("AutoAlignState-Tracking", "Camera");
|
||||
// [tx, ty, tz, pitch, yaw, roll]
|
||||
double[] targetsPose = LimelightHelpers.getTargetPose_CameraSpace(Constants.CameraConstanst.BACK_CAMERA_NAME);
|
||||
if(targetsPose.length >= 1){
|
||||
Logger.recordOutput("AutoAlign-Target Distance", targetsPose[2]);
|
||||
|
||||
// Calculate turret Angle
|
||||
double turretAngle = Utils.calculateTurretAngleFromCameraTagDistance(targetsPose[2]) * Constants.ShooterConstants.TURRET_GEAR_RATIO;
|
||||
turretSubsystem.setTurretMotorRotation(-turretAngle);
|
||||
|
||||
driveSubsystem.rotateChassis(-cameraAutoCenterController.calculate(targetsPose[0])); // This may need to be negated
|
||||
}
|
||||
}
|
||||
|
||||
// If robot is centered on HUB and shooter is up to speed. Run the kicker
|
||||
if(turretSubsystem.isLauncherUpToSpeed() && cameraAutoCenterController.atSetpoint()){
|
||||
Logger.recordOutput("AutoAlignState-Shoot", "FIRE!");
|
||||
hopperSubsystem.feedKicker();
|
||||
}else{
|
||||
Logger.recordOutput("AutoAlignState-Shoot", "Waiting");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(boolean interrupted) {
|
||||
turretSubsystem.setLauncher(0);
|
||||
|
||||
hopperSubsystem.stopKicker();
|
||||
hopperSubsystem.spindexerOff();
|
||||
|
||||
driveSubsystem.stopDrive();
|
||||
|
||||
LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME, Constants.CameraConstanst.BACK_LOCALIZATION_PIPELINE_NUMBER);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,130 +0,0 @@
|
|||
package frc.robot.commands;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import com.pathplanner.lib.auto.AutoBuilder;
|
||||
import com.pathplanner.lib.path.PathConstraints;
|
||||
import edu.wpi.first.apriltag.AprilTagFieldLayout;
|
||||
import edu.wpi.first.apriltag.AprilTagFields;
|
||||
import edu.wpi.first.math.geometry.Pose2d;
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.math.geometry.Translation2d;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.CommandScheduler;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.subsystems.DriveSubsystem;
|
||||
import frc.robot.subsystems.HopperSubsystem;
|
||||
import frc.robot.subsystems.TurretSubsystem;
|
||||
|
||||
public class AutoShootCommandChassisTurretPathPlanner extends Command {
|
||||
|
||||
// For Chassis Control
|
||||
private DriveSubsystem driveSubsystem;
|
||||
|
||||
private HopperSubsystem hopperSubsystem;
|
||||
private TurretSubsystem turretSubsystem;
|
||||
|
||||
private int[] tagFilters;
|
||||
|
||||
private AprilTagFieldLayout fieldTags = AprilTagFieldLayout.loadField(AprilTagFields.k2026RebuiltWelded);
|
||||
|
||||
private Pose3d closestTag;
|
||||
private Pose2d targetPPPose;
|
||||
|
||||
private Command pathFollowCommand;
|
||||
|
||||
public AutoShootCommandChassisTurretPathPlanner(DriveSubsystem driveSubsystem, HopperSubsystem hopperSubsystem,
|
||||
TurretSubsystem turretSubsystem) {
|
||||
this.driveSubsystem = driveSubsystem;
|
||||
this.hopperSubsystem = hopperSubsystem;
|
||||
this.turretSubsystem = turretSubsystem;
|
||||
|
||||
this.addRequirements(driveSubsystem, hopperSubsystem, turretSubsystem);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
|
||||
DriverStation.getAlliance().ifPresent((aliance) -> {
|
||||
Pose3d targetHub;
|
||||
if (aliance == Alliance.Blue) {
|
||||
tagFilters = Constants.CameraConstanst.IDFilters.BLUE_HUB_SHOOTING_IDS;
|
||||
targetHub = Constants.FieldPoses.BLUE_HUB_POSE;
|
||||
} else {
|
||||
tagFilters = Constants.CameraConstanst.IDFilters.RED_HUB_SHOOTING_IDS;
|
||||
targetHub = Constants.FieldPoses.RED_HUB_POSE;
|
||||
}
|
||||
|
||||
Pose3d botPose = driveSubsystem.getBotPose();
|
||||
// Find closest target to us
|
||||
List<Pose3d> tagPoses = Arrays.stream(tagFilters).mapToObj(tagId -> fieldTags.getTagPose(tagId).get())
|
||||
.toList();
|
||||
closestTag = botPose.nearest(tagPoses);
|
||||
Logger.recordOutput("AutoAlignPP-ClosestAprilTagPose", closestTag);
|
||||
|
||||
Translation2d delta = botPose.getTranslation().toTranslation2d()
|
||||
.minus(closestTag.getTranslation().toTranslation2d());
|
||||
Logger.recordOutput("AutoAlignPP-ClosestAprilTagTransform", delta);
|
||||
|
||||
// Add 180 because we want the back of the robot to face the HUB
|
||||
// deadreckoningAutoCenterController.setSetpoint(delta.getAngle().plus(Rotation2d.k180deg).getRadians());
|
||||
|
||||
// Translate back 1 meter from HUB
|
||||
Translation2d newTrans = targetHub.getTranslation().toTranslation2d()
|
||||
.plus(new Translation2d(1.5, delta.getAngle()));
|
||||
targetPPPose = new Pose2d(newTrans, delta.getAngle());
|
||||
Logger.recordOutput("AutoAlignPP-PPTargetPose", targetPPPose);
|
||||
|
||||
pathFollowCommand = AutoBuilder.pathfindToPose(targetPPPose,
|
||||
new PathConstraints(Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY,
|
||||
Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY_ACCEL,
|
||||
Constants.RobotChassisLimits.MAX_ROBOT_ANGULAR_VELOCITY,
|
||||
Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY_ACCEL));
|
||||
|
||||
CommandScheduler.getInstance().schedule(pathFollowCommand);
|
||||
});
|
||||
|
||||
turretSubsystem.setLauncher(5500);
|
||||
hopperSubsystem.spindexerOn();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
|
||||
// If robot is centered on HUB and shooter is up to speed. Run the kicker
|
||||
if (turretSubsystem.isLauncherUpToSpeed() && pathFollowCommand.isFinished()) {
|
||||
Logger.recordOutput("AutoAlignState-Shoot", "FIRE!");
|
||||
hopperSubsystem.feedKicker();
|
||||
} else {
|
||||
Logger.recordOutput("AutoAlignState-Shoot", "Waiting");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(boolean interrupted) {
|
||||
CommandScheduler.getInstance().cancel(pathFollowCommand);
|
||||
turretSubsystem.setLauncher(0);
|
||||
|
||||
hopperSubsystem.stopKicker();
|
||||
hopperSubsystem.spindexerOff();
|
||||
|
||||
driveSubsystem.stopDrive();
|
||||
|
||||
LimelightHelpers.setPipelineIndex(Constants.CameraConstanst.BACK_CAMERA_NAME,
|
||||
Constants.CameraConstanst.BACK_LOCALIZATION_PIPELINE_NUMBER);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package frc.robot.commands;
|
||||
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import edu.wpi.first.apriltag.AprilTagFieldLayout;
|
||||
import edu.wpi.first.apriltag.AprilTagFields;
|
||||
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.Transform2d;
|
||||
import edu.wpi.first.math.geometry.Transform3d;
|
||||
import edu.wpi.first.math.geometry.Translation2d;
|
||||
import edu.wpi.first.math.geometry.Translation3d;
|
||||
import edu.wpi.first.units.Units;
|
||||
import edu.wpi.first.units.measure.Angle;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.Constants.ShootingRegion;
|
||||
import frc.robot.Utils;
|
||||
import frc.robot.subsystems.DriveSubsystem;
|
||||
import frc.robot.subsystems.TurretSubsystem;
|
||||
|
||||
public class AutoTurretCommand extends Command {
|
||||
|
||||
private final Translation2d CENTER_TURRET_TO_ROBOT = new Translation2d(-0.1335024, -0.1824736);
|
||||
|
||||
private TurretSubsystem turretSubsystem;
|
||||
private DriveSubsystem driveSubsystem;
|
||||
|
||||
private Alliance alliance;
|
||||
|
||||
public AutoTurretCommand(TurretSubsystem turretSubsystem, DriveSubsystem driveSubsystem) {
|
||||
this.turretSubsystem = turretSubsystem;
|
||||
this.driveSubsystem = driveSubsystem;
|
||||
|
||||
addRequirements(turretSubsystem); // Not adding drive as we don't wan't the drive command to be de-scheduled
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
// Perform auto-home
|
||||
turretSubsystem.homeTurret();
|
||||
|
||||
DriverStation.getAlliance().ifPresent((aliance) -> {
|
||||
if (aliance == Alliance.Blue) {
|
||||
turretSubsystem.setTurretTargetPose(Constants.FieldPoses.BLUE_HUB_POSE);
|
||||
aliance = Alliance.Blue;
|
||||
} else {
|
||||
turretSubsystem.setTurretTargetPose(Constants.FieldPoses.RED_HUB_POSE);
|
||||
aliance = Alliance.Red;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
|
||||
ShootingRegion shootingRegion = Utils.findRobotShootingRegion(driveSubsystem.getBotPose(), DriverStation.getAlliance().get());
|
||||
|
||||
if(shootingRegion != ShootingRegion.NON_SHOOTING_REGION){
|
||||
Pose3d targetPose = Utils.findShootingTarget(shootingRegion, DriverStation.getAlliance().get());
|
||||
|
||||
turretSubsystem.setTurretTargetPose(targetPose);
|
||||
}
|
||||
|
||||
Logger.recordOutput("AutoTurret-ScoringTarget", turretSubsystem.getTurretTargetPose());
|
||||
|
||||
Pose3d botPose = driveSubsystem.getBotPose();
|
||||
Pose3d turretPose = botPose.plus(new Transform3d(new Translation3d(CENTER_TURRET_TO_ROBOT),
|
||||
new Rotation3d(Rotation2d.fromRotations(turretSubsystem.getTurretAngleRobotRelative() + 0.5))));
|
||||
Logger.recordOutput("AutoTurret-TurretPose", turretPose);
|
||||
|
||||
Translation2d targetTranslation = turretSubsystem.getTurretTargetPose().getTranslation().toTranslation2d().minus(turretPose.getTranslation().toTranslation2d());
|
||||
Logger.recordOutput("AutoTurret-Translation", targetTranslation);
|
||||
|
||||
if(turretSubsystem.isTurretReady()){
|
||||
turretSubsystem.setTurretFieldRelative(botPose, targetTranslation.getAngle().getRotations());
|
||||
// turretSubsystem.setTurretRobotRelative(0.25);
|
||||
// turretSubsystem.setTurretMotorRotation(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(boolean interrupted) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
package frc.robot.commands;
|
||||
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.units.Units;
|
||||
import edu.wpi.first.units.measure.Angle;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
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 frc.robot.Constants;
|
||||
import frc.robot.Utils;
|
||||
import frc.robot.subsystems.DriveSubsystem;
|
||||
import frc.robot.subsystems.HopperSubsystem;
|
||||
import frc.robot.subsystems.IntakeSubsystem;
|
||||
import frc.robot.subsystems.TurretSubsystem;
|
||||
|
||||
public class AutoTurretShootCommand extends Command{
|
||||
|
||||
private HopperSubsystem hopperSubsystem;
|
||||
private TurretSubsystem turretSubsystem;
|
||||
private IntakeSubsystem intakeSubsystem;
|
||||
private DriveSubsystem driveSubsystem;
|
||||
|
||||
private Command waitCommand = Commands.waitSeconds(1.5);
|
||||
|
||||
private Alliance alliance;
|
||||
public AutoTurretShootCommand(HopperSubsystem hopperSubsystem, TurretSubsystem turretSubsystem, IntakeSubsystem intakeSubsystem, DriveSubsystem driveSubsystem){
|
||||
this.hopperSubsystem = hopperSubsystem;
|
||||
this.turretSubsystem = turretSubsystem;
|
||||
this.intakeSubsystem = intakeSubsystem;
|
||||
this.driveSubsystem = driveSubsystem;
|
||||
|
||||
addRequirements(hopperSubsystem, intakeSubsystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
hopperSubsystem.spindexerOn();
|
||||
CommandScheduler.getInstance().schedule(waitCommand);
|
||||
alliance = DriverStation.getAlliance().get();
|
||||
Logger.recordOutput("AutoTurretShoot-State", "SHOOTING");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
double distance = turretSubsystem.getTurretTargetPose().toPose2d().getTranslation().getDistance(driveSubsystem.getBotPose().getTranslation().toTranslation2d());
|
||||
Logger.recordOutput("AutoTurretShoot-DistanceToTarget(Meters)", distance);
|
||||
|
||||
turretSubsystem.setTargetElevation(Utils.getHoodAngleForDistance(distance));
|
||||
turretSubsystem.setLauncher(Utils.getLauncherRPMForDistance(distance));
|
||||
|
||||
if(turretSubsystem.isLauncherUpToSpeed() && waitCommand.isFinished()){
|
||||
hopperSubsystem.feedKicker();
|
||||
}else{
|
||||
hopperSubsystem.stopKicker();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(boolean interrupted) {
|
||||
waitCommand.cancel();
|
||||
hopperSubsystem.spindexerOff();
|
||||
hopperSubsystem.stopKicker();
|
||||
|
||||
turretSubsystem.setLauncher(0);
|
||||
turretSubsystem.setTargetElevation(Constants.ShooterConstants.DEFLECTOR_STORED_ANGLE);
|
||||
|
||||
Logger.recordOutput("AutoTurretShoot-State", "NOT SHOOTING");
|
||||
|
||||
DriverStation.getAlliance().ifPresent((aliance) -> {
|
||||
if (aliance == Alliance.Blue) {
|
||||
turretSubsystem.setTurretTargetPose(Constants.FieldPoses.BLUE_HUB_POSE);
|
||||
} else {
|
||||
turretSubsystem.setTurretTargetPose(Constants.FieldPoses.RED_HUB_POSE);
|
||||
}
|
||||
});
|
||||
|
||||
// turretSubsystem.setTurretMotorRotation(-0.34); // Return to 0 after MIAMI VALLEY
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,12 +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;
|
||||
|
||||
public final class Autos {
|
||||
|
||||
private Autos() {
|
||||
throw new UnsupportedOperationException("This is a utility class!");
|
||||
}
|
||||
}
|
||||
|
|
@ -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"})
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +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 edu.wpi.first.wpilibj.XboxController;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import frc.robot.subsystems.HopperSubsystem;
|
||||
import frc.robot.subsystems.IntakeSubsystem;
|
||||
|
||||
/**
|
||||
* An example command that uses an example subsystem.
|
||||
*/
|
||||
public class Reverse extends Command {
|
||||
|
||||
private IntakeSubsystem intakeSubsystem;
|
||||
private HopperSubsystem hopperSubsystem;
|
||||
private XboxController m_XboxController;
|
||||
|
||||
/**
|
||||
* Creates a new ExampleCommand.
|
||||
*
|
||||
* @param subsystem The subsystem used by this command.
|
||||
*/
|
||||
public Reverse(IntakeSubsystem intakeSubsystem, HopperSubsystem hopperSubsystem, XboxController m_XboxController) {
|
||||
this.intakeSubsystem = intakeSubsystem;
|
||||
this.hopperSubsystem = hopperSubsystem;
|
||||
this.m_XboxController = m_XboxController;
|
||||
}
|
||||
|
||||
// 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() {
|
||||
intakeSubsystem.reverseIntake();
|
||||
hopperSubsystem.spindexerReverse();
|
||||
hopperSubsystem.reverseKicker();
|
||||
}
|
||||
|
||||
// Called once the command ends or is interrupted.
|
||||
@Override
|
||||
public void end(boolean interrupted) {
|
||||
hopperSubsystem.stopKicker();
|
||||
hopperSubsystem.spindexerOff();
|
||||
intakeSubsystem.stopIntake(m_XboxController);
|
||||
}
|
||||
|
||||
// Returns true when the command should end.
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +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.TurretSubsystem;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
|
||||
/** An example command that uses an example subsystem. **/
|
||||
public class SetDeflectorCommand extends Command {
|
||||
private final TurretSubsystem m_subsystem;
|
||||
private double deployAngle;
|
||||
|
||||
public SetDeflectorCommand(TurretSubsystem subsystem, double deployAngle) {
|
||||
m_subsystem = subsystem;
|
||||
this.deployAngle = deployAngle;
|
||||
}
|
||||
|
||||
// Called when the command is initially scheduled.
|
||||
@Override
|
||||
public void initialize() {
|
||||
m_subsystem.setTargetElevation(deployAngle);
|
||||
}
|
||||
|
||||
// Returns true when the command should end.
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
package frc.robot.commands;
|
||||
|
||||
import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import edu.wpi.first.apriltag.AprilTagFieldLayout;
|
||||
import edu.wpi.first.apriltag.AprilTagFields;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.DriverStation.Alliance;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.subsystems.DriveSubsystem;
|
||||
|
||||
public class ZoneCheck extends Command {
|
||||
private Zone zone;
|
||||
private DriveSubsystem driveSubsystem;
|
||||
|
||||
public ZoneCheck(DriveSubsystem driveSubsystem)
|
||||
{
|
||||
this.driveSubsystem = driveSubsystem;
|
||||
}
|
||||
|
||||
public enum Zone {
|
||||
Blue,
|
||||
Red,
|
||||
Neutral,
|
||||
INIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
zone = Zone.INIT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
getZone();
|
||||
Logger.recordOutput("FieldZone", zone);
|
||||
DriverStation.getAlliance().ifPresent((aliance) -> {
|
||||
if (aliance == Alliance.Blue) {
|
||||
switch (zone) {
|
||||
case Blue:
|
||||
System.out.println("BLUE");
|
||||
break;
|
||||
case Neutral:
|
||||
System.out.println("NEUTRAL");
|
||||
break;
|
||||
case Red:
|
||||
System.out.println("RED");
|
||||
break;
|
||||
default:
|
||||
System.out.println("****");
|
||||
}
|
||||
} else {
|
||||
switch (zone) {
|
||||
case Blue:
|
||||
System.out.println("BLUE");
|
||||
break;
|
||||
case Neutral:
|
||||
System.out.println("NEUTRAL");
|
||||
break;
|
||||
case Red:
|
||||
System.out.println("RED");
|
||||
break;
|
||||
default:
|
||||
System.out.println("****");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFinished() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void getZone() {
|
||||
if (driveSubsystem.getBotPose().getX() >= Constants.CameraConstanst.RED_ZONE_COOR[0]) {
|
||||
zone = Zone.Red;
|
||||
} else if (driveSubsystem.getBotPose().getX() >= Constants.CameraConstanst.NEUTRAL_ZONE_COOR[0]) {
|
||||
zone = Zone.Neutral;
|
||||
} else {
|
||||
zone = Zone.Blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
package frc.robot.subsystems;
|
||||
|
||||
import static org.fairportrobotics.frc.posty.assertions.Assertions.assertThat;
|
||||
|
||||
import org.fairportrobotics.frc.posty.TestableSubsystem;
|
||||
import org.fairportrobotics.frc.posty.test.PostTest;
|
||||
import org.fairportrobotics.frc.robolib.drivesystems.swerve.SwerveBuilder;
|
||||
import org.fairportrobotics.frc.robolib.drivesystems.swerve.SwerveDriveSystem;
|
||||
import org.fairportrobotics.frc.robolib.drivesystems.swerve.SwerveModule;
|
||||
import org.fairportrobotics.frc.robolib.vision.limelight.LimelightHelpers;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import com.pathplanner.lib.auto.AutoBuilder;
|
||||
import com.pathplanner.lib.config.PIDConstants;
|
||||
import com.pathplanner.lib.config.RobotConfig;
|
||||
import com.pathplanner.lib.controllers.PPHolonomicDriveController;
|
||||
import com.pathplanner.lib.util.PathPlannerLogging;
|
||||
|
||||
import edu.wpi.first.math.VecBuilder;
|
||||
import edu.wpi.first.math.geometry.Pose2d;
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.math.geometry.Translation2d;
|
||||
import edu.wpi.first.math.kinematics.ChassisSpeeds;
|
||||
import edu.wpi.first.wpilibj.DriverStation;
|
||||
import edu.wpi.first.wpilibj.RobotState;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
|
||||
import frc.robot.Constants;
|
||||
|
||||
public class DriveSubsystem extends TestableSubsystem {
|
||||
|
||||
private SendableChooser<Command> autoChooser;
|
||||
|
||||
private SwerveBuilder swerveBuilder = new SwerveBuilder();
|
||||
public SwerveDriveSystem driveSystem;
|
||||
|
||||
private double driveP = 0.1;
|
||||
private double driveI = 0.0;
|
||||
private double driveD = 0.01;
|
||||
private double driveKV = 0.2;
|
||||
|
||||
private double steerP = 20;
|
||||
private double steerI = 0;
|
||||
private double steerD = 0.0;
|
||||
private double steerKV = 0;
|
||||
|
||||
public DriveSubsystem(CommandXboxController xboxController) {
|
||||
|
||||
driveSystem = swerveBuilder
|
||||
.withCanbusName("Drive")
|
||||
.withPigeonId(Constants.ExtraIDEntities.PIGEON_ID)
|
||||
.withMaxLinearVelocity(Constants.RobotChassisLimits.MAX_ROBOT_LINEAR_VELOCITY)
|
||||
.withMaxAngularVelocity(Constants.RobotChassisLimits.MAX_ROBOT_ANGULAR_VELOCITY)
|
||||
.withSwerveModule(
|
||||
swerveBuilder.new SwerveModuleBuilder()
|
||||
.withDriveMotorId(Constants.SwerveDriveIDs.FRONT_LEFT_DRIVE_ID)
|
||||
.withDriveKP(driveP)
|
||||
.withDriveKI(driveI)
|
||||
.withDriveKD(driveD)
|
||||
.withDriveKV(driveKV)
|
||||
.withSteerMotorId(Constants.SwerveDriveIDs.FRONT_LEFT_STEER_ID)
|
||||
.withSteerKP(steerP)
|
||||
.withSteerKI(steerI)
|
||||
.withSteerKD(steerD)
|
||||
.withSteerKV(steerKV)
|
||||
// If the offsets don't work, contact Tyler W or Dom G
|
||||
.withSteerOffset(Constants.SwerveDriveOffsets.FRONT_LEFT_MOTOR_OFFSET)
|
||||
.withSteerEncoderId(Constants.SwerveDriveIDs.FRONT_LEFT_ENCODER_ID)
|
||||
.withModuleLocation(new Translation2d(1, 1))
|
||||
.withModuleName("Front Left")
|
||||
.withGearRatio(8.14)
|
||||
.withWheelDiameter(0.1016)
|
||||
.build())
|
||||
.withSwerveModule(
|
||||
swerveBuilder.new SwerveModuleBuilder()
|
||||
.withDriveMotorId(Constants.SwerveDriveIDs.FRONT_RIGHT_DRIVE_ID)
|
||||
.withDriveKP(driveP)
|
||||
.withDriveKI(driveI)
|
||||
.withDriveKD(driveD)
|
||||
.withDriveKV(driveKV)
|
||||
.withDriveInverted()
|
||||
.withSteerMotorId(Constants.SwerveDriveIDs.FRONT_RIGHT_STEER_ID)
|
||||
.withSteerKP(steerP)
|
||||
.withSteerKI(steerI)
|
||||
.withSteerKD(steerD)
|
||||
.withSteerKV(steerKV)
|
||||
.withSteerOffset(Constants.SwerveDriveOffsets.FRONT_RIGHT_MOTOR_OFFSET)
|
||||
.withSteerEncoderId(Constants.SwerveDriveIDs.FRONT_RIGHT_ENCODER_ID)
|
||||
.withModuleLocation(new Translation2d(1, -1))
|
||||
.withModuleName("Front Right")
|
||||
.withGearRatio(8.14)
|
||||
.withWheelDiameter(0.1016)
|
||||
.build())
|
||||
.withSwerveModule(
|
||||
swerveBuilder.new SwerveModuleBuilder()
|
||||
.withDriveMotorId(Constants.SwerveDriveIDs.BACK_LEFT_DRIVE_ID)
|
||||
.withDriveKP(driveP)
|
||||
.withDriveKI(driveI)
|
||||
.withDriveKD(driveD)
|
||||
.withDriveKV(driveKV)
|
||||
.withSteerMotorId(Constants.SwerveDriveIDs.BACK_LEFT_STEER_ID)
|
||||
.withSteerKP(steerP)
|
||||
.withSteerKI(steerI)
|
||||
.withSteerKD(steerD)
|
||||
.withSteerKV(steerKV)
|
||||
.withSteerOffset(Constants.SwerveDriveOffsets.BACK_LEFT_MOTOR_OFFSET)
|
||||
.withSteerEncoderId(Constants.SwerveDriveIDs.BACK_LEFT_ENCODER_ID)
|
||||
.withModuleLocation(new Translation2d(-1, 1))
|
||||
.withModuleName("Back Left")
|
||||
.withGearRatio(8.14)
|
||||
.withWheelDiameter(0.1016)
|
||||
.build())
|
||||
.withSwerveModule(
|
||||
swerveBuilder.new SwerveModuleBuilder()
|
||||
.withDriveMotorId(Constants.SwerveDriveIDs.BACK_RIGHT_DRIVE_ID)
|
||||
.withDriveKP(driveP)
|
||||
.withDriveKI(driveI)
|
||||
.withDriveKD(driveD)
|
||||
.withDriveKV(driveKV)
|
||||
.withDriveInverted()
|
||||
.withSteerMotorId(Constants.SwerveDriveIDs.BACK_RIGHT_STEER_ID)
|
||||
.withSteerKP(steerP)
|
||||
.withSteerKI(steerI)
|
||||
.withSteerKD(steerD)
|
||||
.withSteerKV(steerKV)
|
||||
.withSteerOffset(Constants.SwerveDriveOffsets.BACK_RIGHT_MOTOR_OFFSET)
|
||||
.withSteerEncoderId(Constants.SwerveDriveIDs.BACK_RIGHT_ENCODER_ID)
|
||||
.withModuleLocation(new Translation2d(-1, -1))
|
||||
.withModuleName("Back Right")
|
||||
.withGearRatio(8.14)
|
||||
.withWheelDiameter(0.1016)
|
||||
.build())
|
||||
.build();
|
||||
|
||||
// Set vision measurement confidence values
|
||||
driveSystem.getPoseEstimator().setVisionMeasurementStdDevs(VecBuilder.fill(0.7, 0.7, 0.7, 0.1));
|
||||
|
||||
this.setDefaultCommand(Commands.run(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
driveSystem.setChassisSpeedsFromJoystickFieldRelative(
|
||||
-(xboxController.getLeftY() * Math.abs(xboxController.getLeftY())),
|
||||
-(xboxController.getLeftX() * Math.abs(xboxController.getLeftX())),
|
||||
-(xboxController.getRawAxis(4) * Math.abs(xboxController.getRawAxis(4))));
|
||||
|
||||
Logger.recordOutput("RequestedSwerveState", driveSystem.getRequestedModuleStates());
|
||||
Logger.recordOutput("ActualSwerveState", driveSystem.getActualModuleStates());
|
||||
}
|
||||
|
||||
}, this));
|
||||
|
||||
RobotConfig config;
|
||||
try {
|
||||
config = RobotConfig.fromGUISettings();
|
||||
|
||||
AutoBuilder.configure(
|
||||
driveSystem::getRobotPose2d,
|
||||
driveSystem::setPose2d,
|
||||
driveSystem::getRobotRelativeSpeeds,
|
||||
(speeds, feedforwards) -> {driveSystem.setChassisSpeed(ChassisSpeeds.fromRobotRelativeSpeeds(-speeds.vxMetersPerSecond, -speeds.vyMetersPerSecond, -speeds.omegaRadiansPerSecond, driveSystem.getRobotHeading()), new Translation2d());},
|
||||
new PPHolonomicDriveController(
|
||||
new PIDConstants(5, 0, 0),
|
||||
new PIDConstants(Math.PI, 0, 0)),
|
||||
config,
|
||||
() -> {
|
||||
var alliance = DriverStation.getAlliance();
|
||||
if (alliance.isPresent()) {
|
||||
return alliance.get() == DriverStation.Alliance.Red;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
this);
|
||||
|
||||
autoChooser = AutoBuilder.buildAutoChooser();
|
||||
autoChooser.setDefaultOption("Do Nothing", Commands.none());
|
||||
SmartDashboard.putData("Auto Chooser", autoChooser);
|
||||
|
||||
// PathPlannerLogging.setLogActivePathCallback((List<Pose2d> pose) -> {});
|
||||
PathPlannerLogging.setLogTargetPoseCallback((Pose2d targetPose) -> { Logger.recordOutput("PathPlanner-TargetPose", targetPose);});
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void periodic() {
|
||||
super.periodic();
|
||||
driveSystem.periodic();
|
||||
|
||||
Logger.recordOutput("RobotPose", driveSystem.getRobotPose3d());
|
||||
|
||||
LimelightHelpers.SetRobotOrientation(Constants.CameraConstanst.FRONT_CAMERA_NAME, driveSystem.getRobotPose2d().getRotation().getDegrees(), 0, 0, 0, 0, 0);
|
||||
LimelightHelpers.SetRobotOrientation(Constants.CameraConstanst.BACK_CAMERA_NAME, driveSystem.getRobotPose2d().getRotation().getDegrees(), 0, 0, 0, 0, 0);
|
||||
|
||||
// MegaTag 2 impl
|
||||
if(RobotState.isDisabled()){
|
||||
LimelightHelpers.SetIMUMode(Constants.CameraConstanst.FRONT_CAMERA_NAME, 1);
|
||||
LimelightHelpers.SetIMUMode(Constants.CameraConstanst.BACK_CAMERA_NAME, 1);
|
||||
}else{
|
||||
LimelightHelpers.SetIMUMode(Constants.CameraConstanst.FRONT_CAMERA_NAME, 4);
|
||||
LimelightHelpers.SetIMUMode(Constants.CameraConstanst.BACK_CAMERA_NAME, 4);
|
||||
}
|
||||
|
||||
LimelightHelpers.PoseEstimate frontTag = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.CameraConstanst.FRONT_CAMERA_NAME);
|
||||
LimelightHelpers.PoseEstimate backTag = LimelightHelpers.getBotPoseEstimate_wpiBlue_MegaTag2(Constants.CameraConstanst.BACK_CAMERA_NAME);
|
||||
|
||||
if(frontTag.tagCount >= 2){
|
||||
driveSystem.getPoseEstimator().addVisionMeasurement(new Pose3d(frontTag.pose), frontTag.timestampSeconds);
|
||||
Logger.recordOutput("FrontPose-Estimate", frontTag.pose);
|
||||
Logger.recordOutput("FrontPose-IsMegaTag2", frontTag.isMegaTag2);
|
||||
}
|
||||
|
||||
if(backTag.tagCount >= 2){
|
||||
driveSystem.getPoseEstimator().addVisionMeasurement(new Pose3d(backTag.pose), backTag.timestampSeconds);
|
||||
Logger.recordOutput("BackPose-Estimate", backTag.pose);
|
||||
Logger.recordOutput("BackPose-IsMegaTag2", frontTag.isMegaTag2);
|
||||
}
|
||||
|
||||
|
||||
// MegaTag 1 Impl
|
||||
// LimelightHelpers.PoseEstimate frontCameraPose = LimelightHelpers.getBotPoseEstimate_wpiBlue(Constants.CameraConstanst.FRONT_CAMERA_NAME);
|
||||
// if (frontCameraPose.tagCount >= 2) {
|
||||
// driveSystem.getPoseEstimator().addVisionMeasurement(new Pose3d(frontCameraPose.pose), frontCameraPose.timestampSeconds);
|
||||
// Logger.recordOutput("FrontPoseEstimate", frontCameraPose.pose);
|
||||
// }
|
||||
// LimelightHelpers.PoseEstimate backCameraPose = LimelightHelpers.getBotPoseEstimate_wpiBlue(Constants.CameraConstanst.BACK_CAMERA_NAME);
|
||||
// if (backCameraPose.tagCount >= 2) {
|
||||
// driveSystem.getPoseEstimator().addVisionMeasurement(new Pose3d(backCameraPose.pose), backCameraPose.timestampSeconds);
|
||||
// Logger.recordOutput("BackPoseEstimate", backCameraPose.pose);
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulationPeriodic() {
|
||||
super.simulationPeriodic();
|
||||
driveSystem.simulationPeriodic();
|
||||
}
|
||||
|
||||
public Command getAutoCommand() {
|
||||
return autoChooser.getSelected();
|
||||
}
|
||||
|
||||
public void stopDrive() {
|
||||
driveSystem.setChassisSpeed(ChassisSpeeds.fromRobotRelativeSpeeds(0, 0, 0, driveSystem.getGyro().getRotation2d()), Translation2d.kZero);
|
||||
}
|
||||
|
||||
public void rotateChassis(double rotSpeed) {
|
||||
driveSystem.setChassisSpeed(ChassisSpeeds.fromRobotRelativeSpeeds(0, 0, rotSpeed, driveSystem.getGyro().getRotation2d()), Translation2d.kZero);
|
||||
}
|
||||
|
||||
public Pose3d getBotPose() {
|
||||
return driveSystem.getRobotPose3d();
|
||||
}
|
||||
|
||||
@PostTest()
|
||||
public void DriveSubsystem_CanDevicesConnected() {
|
||||
|
||||
SwerveModule[] modules = driveSystem.getModules();
|
||||
|
||||
for (int i = 0; i < modules.length; i++) {
|
||||
assertThat(modules[i].getDriveMotor().isConnected())
|
||||
.as(modules[i].getModuleName() + " drive motor is not connected").isTrue();
|
||||
assertThat(modules[i].getSteerMotor().isConnected())
|
||||
.as(modules[i].getModuleName() + " steer motor is not connected").isTrue();
|
||||
assertThat(modules[i].getSteerEncoder().isConnected())
|
||||
.as(modules[i].getModuleName() + " CANCoder is not connected").isTrue();
|
||||
}
|
||||
|
||||
assertThat(driveSystem.getGyro().isConnected()).as("Pigeon is not connected").isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,60 +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 org.fairportrobotics.frc.posty.TestableSubsystem;
|
||||
import org.fairportrobotics.frc.posty.test.PostTest;
|
||||
import static org.fairportrobotics.frc.posty.assertions.Assertions.*;
|
||||
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
|
||||
public class ExampleSubsystem extends TestableSubsystem {
|
||||
/** 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
|
||||
}
|
||||
|
||||
@PostTest(name = "A friendly name", enabled = true)
|
||||
public void myFailingPostTest(){
|
||||
assertThat(true).isFalse();
|
||||
}
|
||||
|
||||
@PostTest(enabled = true)
|
||||
public void myPassingPostTest(){
|
||||
assertThat("Hello World").endWith("World");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,114 +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 org.fairportrobotics.frc.posty.TestableSubsystem;
|
||||
import static org.fairportrobotics.frc.posty.assertions.Assertions.assertThat;
|
||||
import org.fairportrobotics.frc.posty.test.PostTest;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
|
||||
import com.ctre.phoenix6.StatusSignal;
|
||||
import com.ctre.phoenix6.configs.MotorOutputConfigs;
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import com.ctre.phoenix6.configs.TalonFXConfiguration;
|
||||
import com.ctre.phoenix6.controls.VelocityVoltage;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
|
||||
import edu.wpi.first.units.Units;
|
||||
import edu.wpi.first.units.measure.AngularVelocity;
|
||||
import edu.wpi.first.wpilibj.GenericHID.RumbleType;
|
||||
import edu.wpi.first.wpilibj.XboxController;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import frc.robot.Constants;
|
||||
|
||||
public class HopperSubsystem extends TestableSubsystem {
|
||||
|
||||
private TalonFX spindexerMotor;
|
||||
|
||||
private TalonFX kickerMotor;
|
||||
private VelocityVoltage kickerControl = new VelocityVoltage(0);
|
||||
private StatusSignal<AngularVelocity> kickerVelocity;
|
||||
|
||||
/**
|
||||
* Creates a new HopperSubsystem.
|
||||
*/
|
||||
public HopperSubsystem() {
|
||||
spindexerMotor = new TalonFX(Constants.HopperConstants.SPINDEXER_MOTOR_ID);
|
||||
spindexerMotor.getConfigurator().apply(
|
||||
new TalonFXConfiguration()
|
||||
.withMotorOutput(
|
||||
new MotorOutputConfigs()
|
||||
.withInverted(Constants.HopperConstants.SPINDEXER_MOTOR_DIRECTION))
|
||||
.withSlot0(
|
||||
new Slot0Configs()
|
||||
.withKP(0)
|
||||
.withKI(0)
|
||||
.withKD(0)
|
||||
.withKS(0)));
|
||||
|
||||
kickerMotor = new TalonFX(Constants.HopperConstants.KICKER_MOTOR_ID);
|
||||
kickerMotor.getConfigurator().apply(
|
||||
new TalonFXConfiguration()
|
||||
.withMotorOutput(
|
||||
new MotorOutputConfigs()
|
||||
.withInverted(Constants.HopperConstants.KICKER_MOTOR_DIRECTION)
|
||||
)
|
||||
.withSlot0(new Slot0Configs()
|
||||
.withKP(0)
|
||||
.withKI(0)
|
||||
.withKD(0)
|
||||
.withKS(0)
|
||||
));
|
||||
kickerVelocity = kickerMotor.getVelocity();
|
||||
}
|
||||
|
||||
public void feedKicker() {
|
||||
//kickerMotor.setControl(kickerControl.withVelocity(1000));
|
||||
kickerMotor.set(0.75);
|
||||
}
|
||||
|
||||
public void reverseKicker() {
|
||||
//kickerMotor.setControl(kickerControl.withVelocity(-500));
|
||||
kickerMotor.set(-0.5);
|
||||
}
|
||||
|
||||
public void stopKicker() {
|
||||
kickerMotor.stopMotor();
|
||||
}
|
||||
|
||||
public void spindexerOn() {
|
||||
spindexerMotor.set(0.75);
|
||||
}
|
||||
|
||||
public void spindexerReverse() {
|
||||
spindexerMotor.set(-0.75);
|
||||
}
|
||||
|
||||
public void spindexerOff() {
|
||||
spindexerMotor.stopMotor();
|
||||
}
|
||||
|
||||
public Command spinny() {
|
||||
return this.runOnce(() -> {
|
||||
if (spindexerMotor.get() == 0) {
|
||||
spindexerOn();
|
||||
} else {
|
||||
spindexerOff();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void periodic() {
|
||||
Logger.recordOutput("HopperSubsystem-KickerSpeed(Rotations/sec)", kickerVelocity.refresh().getValue().in(Units.RotationsPerSecond));
|
||||
}
|
||||
|
||||
@PostTest(enabled = true)
|
||||
public void hopperSystem_CANDevicesConnected() {
|
||||
assertThat(kickerMotor.isConnected()).as("Kicker motor not connected!").isTrue();
|
||||
assertThat(spindexerMotor.isConnected()).as("Spindexer motor not connected!").isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,93 +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 org.fairportrobotics.frc.posty.TestableSubsystem;
|
||||
import static org.fairportrobotics.frc.posty.assertions.Assertions.assertThat;
|
||||
import org.fairportrobotics.frc.posty.test.PostTest;
|
||||
import static org.fairportrobotics.frc.robolib.motors.Utils.SetMotorDirection;
|
||||
|
||||
import com.ctre.phoenix.motorcontrol.LimitSwitchNormal;
|
||||
import com.ctre.phoenix.motorcontrol.LimitSwitchSource;
|
||||
import com.ctre.phoenix.motorcontrol.can.WPI_TalonSRX;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
|
||||
import edu.wpi.first.wpilibj.XboxController;
|
||||
import edu.wpi.first.wpilibj.GenericHID.RumbleType;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
import frc.robot.Constants;
|
||||
|
||||
public class IntakeSubsystem extends TestableSubsystem {
|
||||
|
||||
/**
|
||||
* Creates a new ExampleSubsystem.
|
||||
*/
|
||||
|
||||
private TalonFX intakeMotor;
|
||||
private WPI_TalonSRX deployMotor;
|
||||
|
||||
public IntakeSubsystem() {
|
||||
intakeMotor = new TalonFX(Constants.IntakeConstants.INTAKE_MOTOR_ID);
|
||||
SetMotorDirection(intakeMotor, Constants.IntakeConstants.INTAKE_MOTOR_DIRECTION);
|
||||
|
||||
deployMotor = new WPI_TalonSRX(Constants.IntakeConstants.DEPLOY_MOTOR_ID);
|
||||
deployMotor.configForwardLimitSwitchSource(LimitSwitchSource.FeedbackConnector, LimitSwitchNormal.NormallyOpen);
|
||||
deployMotor.configReverseLimitSwitchSource(LimitSwitchSource.FeedbackConnector, LimitSwitchNormal.NormallyOpen);
|
||||
deployMotor.setInverted(Constants.IntakeConstants.DEPLOY_MOTOR_INVERTED);
|
||||
}
|
||||
|
||||
public Command deploy() {
|
||||
return Commands.sequence(
|
||||
Commands.deadline(
|
||||
Commands.waitSeconds(2),
|
||||
this.runOnce(
|
||||
() -> {
|
||||
deployMotor.set(1);
|
||||
} // Bump this speed up if intake doesn't deploy
|
||||
)
|
||||
),
|
||||
this.runOnce(() -> deployMotor.stopMotor())
|
||||
);
|
||||
}
|
||||
|
||||
public Command resetDeploy() {
|
||||
return this.runEnd(() -> deployMotor.set(-1), () -> deployMotor.stopMotor());
|
||||
}
|
||||
|
||||
public void setSpeed(double speed) {
|
||||
intakeMotor.set(speed);
|
||||
}
|
||||
|
||||
public Command stopIntake(XboxController m_XboxController) {
|
||||
return this.runOnce(() -> {
|
||||
intakeMotor.stopMotor();
|
||||
m_XboxController.setRumble(RumbleType.kBothRumble, .0);
|
||||
});
|
||||
}
|
||||
|
||||
public Command intake(XboxController m_XboxController) {
|
||||
return this.runOnce(() -> {
|
||||
if (intakeMotor.get() == 0) {
|
||||
setSpeed(-.5);
|
||||
m_XboxController.setRumble(RumbleType.kBothRumble, .5);
|
||||
} else {
|
||||
intakeMotor.stopMotor();
|
||||
m_XboxController.setRumble(RumbleType.kBothRumble, .0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Command reverseIntake() {
|
||||
return this.runEnd(() -> setSpeed(.5), () -> {
|
||||
intakeMotor.stopMotor();
|
||||
});
|
||||
}
|
||||
|
||||
@PostTest(enabled = true)
|
||||
public void IntakeSubsystem_CANDevicesConnected() {
|
||||
assertThat(intakeMotor.isConnected()).as("Intake motor not connected!").isTrue();
|
||||
assertThat(deployMotor.isAlive()).as("Deploy controller not connected!").isTrue();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,318 +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 org.fairportrobotics.frc.posty.TestableSubsystem;
|
||||
import org.fairportrobotics.frc.posty.test.PostTest;
|
||||
import org.littletonrobotics.junction.Logger;
|
||||
import org.littletonrobotics.junction.ConsoleSource.RoboRIO;
|
||||
|
||||
import static org.fairportrobotics.frc.posty.assertions.Assertions.*;
|
||||
|
||||
import com.ctre.phoenix6.controls.PositionVoltage;
|
||||
import com.ctre.phoenix6.StatusSignal;
|
||||
import com.ctre.phoenix6.configs.CurrentLimitsConfigs;
|
||||
import com.ctre.phoenix6.configs.FeedbackConfigs;
|
||||
import com.ctre.phoenix6.configs.MotorOutputConfigs;
|
||||
import com.ctre.phoenix6.configs.Slot0Configs;
|
||||
import com.ctre.phoenix6.configs.SoftwareLimitSwitchConfigs;
|
||||
import com.ctre.phoenix6.configs.TalonFXConfiguration;
|
||||
import com.ctre.phoenix6.hardware.TalonFX;
|
||||
import com.ctre.phoenix6.signals.ForwardLimitValue;
|
||||
import com.ctre.phoenix6.signals.InvertedValue;
|
||||
import com.ctre.phoenix6.signals.ReverseLimitValue;
|
||||
import com.ctre.phoenix6.sim.TalonFXSimState;
|
||||
import com.revrobotics.PersistMode;
|
||||
import com.revrobotics.ResetMode;
|
||||
import com.revrobotics.spark.ClosedLoopSlot;
|
||||
import com.revrobotics.spark.FeedbackSensor;
|
||||
import com.revrobotics.spark.SparkClosedLoopController;
|
||||
import com.revrobotics.spark.SparkMax;
|
||||
import com.revrobotics.spark.SparkBase.ControlType;
|
||||
import com.revrobotics.spark.SparkLowLevel.MotorType;
|
||||
import com.revrobotics.spark.config.SparkMaxConfig;
|
||||
|
||||
import frc.robot.Constants;
|
||||
import frc.robot.Robot;
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.math.geometry.Rotation2d;
|
||||
import edu.wpi.first.units.AngleUnit;
|
||||
import edu.wpi.first.units.Units;
|
||||
import edu.wpi.first.units.measure.Angle;
|
||||
import edu.wpi.first.wpilibj.DigitalInput;
|
||||
import edu.wpi.first.wpilibj.Servo;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.Commands;
|
||||
|
||||
public class TurretSubsystem extends TestableSubsystem {
|
||||
public enum TurretState {
|
||||
INIT,
|
||||
HOMING,
|
||||
READY;
|
||||
}
|
||||
|
||||
private final boolean LOGGING = true;
|
||||
private TurretState turretState;
|
||||
private DigitalInput turretLimitSwitch;
|
||||
private TalonFX turretMotor;
|
||||
private PositionVoltage turretControlMode = new PositionVoltage(0);
|
||||
private TalonFXSimState turretSim;
|
||||
private StatusSignal<Angle> turretMotorPosition;
|
||||
private StatusSignal<ForwardLimitValue> turretMotorForwardLimit;
|
||||
private StatusSignal<ReverseLimitValue> turretMotorReverseLimit;
|
||||
private StatusSignal<Double> turretPositionError;
|
||||
private double forwardLimit = 0;
|
||||
private double reverseLimit = 0;
|
||||
|
||||
private SparkMax launcherMotor;
|
||||
private SparkClosedLoopController launcherControler;
|
||||
|
||||
private double turretOffsetInRotations = 0;
|
||||
|
||||
private Servo hood;
|
||||
|
||||
private Pose3d turretTarget;
|
||||
|
||||
public TurretSubsystem() {
|
||||
|
||||
// Turret configuration
|
||||
turretLimitSwitch = new DigitalInput(Constants.ShooterConstants.TURRET_LIMIT_CHANNEL);
|
||||
turretMotor = new TalonFX(Constants.ShooterConstants.TURRET_MOTOR_ID);
|
||||
turretMotor.getConfigurator().apply(
|
||||
new TalonFXConfiguration()
|
||||
.withSlot0(
|
||||
new Slot0Configs()
|
||||
.withKP(6)
|
||||
.withKI(0)
|
||||
.withKD(0.3)
|
||||
.withKS(0)
|
||||
)
|
||||
.withMotorOutput(
|
||||
new MotorOutputConfigs()
|
||||
.withInverted(InvertedValue.Clockwise_Positive)
|
||||
)
|
||||
.withCurrentLimits(
|
||||
new CurrentLimitsConfigs()
|
||||
.withStatorCurrentLimit(50)
|
||||
)
|
||||
.withSoftwareLimitSwitch(new SoftwareLimitSwitchConfigs().withForwardSoftLimitEnable(false).withReverseSoftLimitEnable(false))
|
||||
.withFeedback(
|
||||
new FeedbackConfigs()
|
||||
.withFeedbackRotorOffset(0)
|
||||
)
|
||||
);
|
||||
turretMotorPosition = turretMotor.getPosition();
|
||||
turretMotorForwardLimit = turretMotor.getForwardLimit();
|
||||
turretMotorReverseLimit = turretMotor.getReverseLimit();
|
||||
turretPositionError = turretMotor.getClosedLoopError();
|
||||
|
||||
turretSim = turretMotor.getSimState();
|
||||
|
||||
// Launcher configuration
|
||||
launcherMotor = new SparkMax(Constants.ShooterConstants.LAUNCHER_MOTOR_ID, MotorType.kBrushless);
|
||||
SparkMaxConfig config = new SparkMaxConfig().apply((SparkMaxConfig) SparkMaxConfig.Presets.REV_NEO);
|
||||
config.inverted(Constants.ShooterConstants.LAUNCHER_MOTOR_INVERTED);
|
||||
config.voltageCompensation(10);
|
||||
config.closedLoop.p(0.0002).i(0.000001).d(0.0005); // I = 0.0000001
|
||||
config.closedLoop.feedForward.kS(0.2).kV(0.000).kA(0.000);
|
||||
// config.closedLoop.allowedClosedLoopError(10, ClosedLoopSlot.kSlot0);
|
||||
config.closedLoop.feedbackSensor(FeedbackSensor.kPrimaryEncoder);
|
||||
config.closedLoop.positionWrappingEnabled(false);
|
||||
// config.closedLoopRampRate(0.5);
|
||||
// config.smartCurrentLimit(5, 50);
|
||||
launcherMotor.configure(config, ResetMode.kResetSafeParameters, PersistMode.kPersistParameters);
|
||||
launcherControler = launcherMotor.getClosedLoopController();
|
||||
|
||||
// Hood configuration
|
||||
hood = new Servo(Constants.ShooterConstants.HOOD_SERVO_CHANNEL);
|
||||
turretState = TurretState.INIT;
|
||||
}
|
||||
|
||||
public void setLauncher(double speed) {
|
||||
if(speed == 0)
|
||||
{
|
||||
launcherMotor.stopMotor();
|
||||
return;
|
||||
}
|
||||
launcherControler.setSetpoint(speed, ControlType.kVelocity, ClosedLoopSlot.kSlot0);
|
||||
}
|
||||
|
||||
public boolean isLauncherUpToSpeed() {
|
||||
// Valid if velcity is within 10% of setpoint.
|
||||
// May need to lower this
|
||||
return true;
|
||||
// return Math.abs(launcherControler.getSetpoint() - launcherMotor.getEncoder().getVelocity()) >= launcherControler.getSetpoint() * 0.03;
|
||||
}
|
||||
|
||||
public void setTargetElevation(double elev)
|
||||
{
|
||||
double pos = Math.abs((elev - 300)/300);
|
||||
Logger.recordOutput("ShooterHood-Angle", pos);
|
||||
hood.set(pos);
|
||||
}
|
||||
|
||||
public Command revSpeedCommand()
|
||||
{
|
||||
return this.runOnce(() -> setLauncher(-.5));
|
||||
}
|
||||
|
||||
public Command setShooter(int speedRPM){
|
||||
return Commands.runEnd(() -> {
|
||||
setLauncher(speedRPM);
|
||||
}, () -> {
|
||||
launcherMotor.stopMotor();
|
||||
}, this);
|
||||
}
|
||||
|
||||
public void homeTurret()
|
||||
{
|
||||
if(turretState != TurretState.INIT){
|
||||
return;
|
||||
}
|
||||
turretMotor.set(Constants.ShooterConstants.HOMING_SPEED);
|
||||
turretState = TurretState.HOMING;
|
||||
}
|
||||
|
||||
public boolean isTurretReady(){
|
||||
return turretState == TurretState.READY;
|
||||
}
|
||||
|
||||
public void turretRotateDir(double speed)
|
||||
{
|
||||
turretMotor.set(speed);
|
||||
}
|
||||
|
||||
public double getTurretAngleRobotRelative()
|
||||
{
|
||||
return getTurretMotorPosition() / Constants.ShooterConstants.TURRET_GEAR_RATIO;
|
||||
}
|
||||
|
||||
public void setTurretTargetPose(Pose3d targetPose){
|
||||
turretTarget = targetPose;
|
||||
}
|
||||
|
||||
public Pose3d getTurretTargetPose(){
|
||||
return turretTarget;
|
||||
}
|
||||
|
||||
private double getTurretMotorPosition(){
|
||||
return turretMotorPosition.refresh().getValueAsDouble() - turretOffsetInRotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void periodic() {
|
||||
if (turretState == TurretState.HOMING) {
|
||||
if (turretLimitSwitch.get()) { // Turret has tripped the switch
|
||||
turretMotor.stopMotor();
|
||||
turretOffsetInRotations = (turretMotorPosition.refresh().getValueAsDouble() - 1.323);
|
||||
if (!Robot.isReal()) {
|
||||
turretOffsetInRotations = 0; // Flip turret around
|
||||
}
|
||||
turretState = TurretState.READY;
|
||||
forwardLimit = (1.5 + turretOffsetInRotations);
|
||||
reverseLimit = (-1.5 + turretOffsetInRotations);
|
||||
Logger.recordOutput("TurretSubsystem-TurretForwardLimit", forwardLimit);
|
||||
Logger.recordOutput("TurretSubsystem-TurretReverseLimit", reverseLimit);
|
||||
turretMotor.getConfigurator().apply(
|
||||
new SoftwareLimitSwitchConfigs()
|
||||
.withForwardSoftLimitEnable(true)
|
||||
.withForwardSoftLimitThreshold(forwardLimit)
|
||||
.withReverseSoftLimitEnable(true)
|
||||
.withReverseSoftLimitThreshold(reverseLimit));
|
||||
// setTurretRobotRelative(0);
|
||||
// setTurretMotorRotation(-0.34); // Return to 0 after MIAMI VALLEY
|
||||
}
|
||||
}
|
||||
|
||||
if (LOGGING) {
|
||||
Logger.recordOutput("TurretSubsystem-TurretLimitSwitch", turretLimitSwitch.get());
|
||||
Logger.recordOutput("TurretSubsystem-Launcher Speed (RPM)", launcherMotor.getEncoder().getVelocity());
|
||||
Logger.recordOutput("TurretSubsystem-TurretState", turretState);
|
||||
Logger.recordOutput("TurretSubsystem-TurretPositionRobotRelative", getTurretAngleRobotRelative());
|
||||
Logger.recordOutput("TurretSubsystem-TurretMotorPositionWithOffset", getTurretMotorPosition());
|
||||
Logger.recordOutput("TurretSubsystem-TurretMotorPositionRaw",
|
||||
turretMotorPosition.refresh().getValue().in(Units.Rotations));
|
||||
Logger.recordOutput("TurretSubsystem-TurretRequestedPosRaw",
|
||||
turretControlMode.getPositionMeasure().in(Units.Rotations));
|
||||
Logger.recordOutput("TurretSubsystem-TurretRequestedPos", getRequestedPosTurretRelative());
|
||||
Logger.recordOutput("TurretSubsystem-TurretOffset", turretOffsetInRotations);
|
||||
Logger.recordOutput("TurretSubsystem-TurretForwardLimitHit", turretMotorForwardLimit.refresh().getValue());
|
||||
Logger.recordOutput("TurretSubsystem-TurretReverseLimitHit", turretMotorReverseLimit.refresh().getValue());
|
||||
Logger.recordOutput("TurretSubsystem-TurretPositionError", turretPositionError.refresh().getValueAsDouble());
|
||||
Logger.recordOutput("TurretSubsystem-LauncherSetpoint(RPM)", launcherControler.getSetpoint());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setTurretFieldRelative(Pose3d robotPose, double pos)
|
||||
{
|
||||
if(turretState != TurretState.READY)
|
||||
{
|
||||
// Not ready to set angle
|
||||
return;
|
||||
}
|
||||
|
||||
double correctedPos = -pos; // Flip angle to match CCW positive. Add 0.5 to flip around
|
||||
|
||||
double robotRotations = robotPose.getRotation().toRotation2d().getRotations();
|
||||
|
||||
Rotation2d turretAngle = Rotation2d.fromRotations(correctedPos).plus(Rotation2d.fromRotations(robotRotations)).minus(Rotation2d.fromRotations(0.5));
|
||||
|
||||
Logger.recordOutput("TurretSubsystem-TurretFieldTarget", turretAngle.getRotations());
|
||||
|
||||
setTurretRobotRelative(((turretAngle.getRotations())));
|
||||
}
|
||||
|
||||
public void setTurretRobotRelative(double pos)
|
||||
{
|
||||
if(turretState != TurretState.READY)
|
||||
{
|
||||
// Not ready to set angle
|
||||
return;
|
||||
}
|
||||
|
||||
double correctedPos = -pos; // Flip angle to match CCW positive
|
||||
|
||||
setTurretMotorRotation(correctedPos * Constants.ShooterConstants.TURRET_GEAR_RATIO);
|
||||
}
|
||||
|
||||
public void setTurretMotorRotation(double pos){
|
||||
double posWithOffset = pos + turretOffsetInRotations;
|
||||
|
||||
Logger.recordOutput("Blah", posWithOffset);
|
||||
|
||||
if(Robot.isSimulation()){
|
||||
if(posWithOffset >= forwardLimit){
|
||||
turretSim.setForwardLimit(true);
|
||||
} else {
|
||||
turretSim.setForwardLimit(false);
|
||||
}
|
||||
|
||||
if(posWithOffset <= reverseLimit){
|
||||
turretSim.setReverseLimit(true);
|
||||
} else {
|
||||
turretSim.setReverseLimit(false);
|
||||
}
|
||||
}
|
||||
|
||||
turretMotor.setControl(turretControlMode.withPosition(posWithOffset));
|
||||
turretSim.setRawRotorPosition(-posWithOffset);
|
||||
}
|
||||
|
||||
public boolean isTurretAtTarget(){
|
||||
return Math.abs(turretPositionError.refresh().getValueAsDouble()) <= 0.1;
|
||||
}
|
||||
|
||||
private double getRequestedPosTurretRelative() {
|
||||
return (turretControlMode.getPositionMeasure().in(Units.Rotations) - turretOffsetInRotations) / Constants.ShooterConstants.TURRET_GEAR_RATIO;
|
||||
}
|
||||
|
||||
@PostTest()
|
||||
public void TurretSubsystem_CANDevicesConnected(){
|
||||
assertThat(launcherMotor.getFaults().can).as("Launcher motor not connected!").isFalse();
|
||||
assertThat(turretMotor.isConnected()).as("Turret motor not connected!").isTrue();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
"""
|
||||
utils.py – pure math utilities for Castor 2026 (Python/MagicBot port).
|
||||
|
||||
Direct translation of Utils.java. No framework dependencies.
|
||||
"""
|
||||
|
||||
import math
|
||||
|
||||
from wpilib import DriverStation
|
||||
from wpimath.geometry import Pose3d
|
||||
|
||||
from constants import FieldPoses, ShootingRegion, ShootingRegionDimensions
|
||||
|
||||
|
||||
def calculate_turret_angle_from_camera_tag_distance(distance_to_tag: float) -> float:
|
||||
"""
|
||||
Calculates the turret rotation (in rotations, robot-relative) needed
|
||||
to aim at the HUB given the camera's measured distance to the tag.
|
||||
|
||||
:param distance_to_tag: camera distance to the AprilTag (metres)
|
||||
:return: turret angle in rotations (robot-relative)
|
||||
"""
|
||||
camera_distance_to_target = distance_to_tag + 0.6
|
||||
camera_to_shoot_distance = 0.26035
|
||||
|
||||
# Pythagorean theorem
|
||||
shooter_distance_to_target = math.sqrt(
|
||||
camera_distance_to_target**2 + camera_to_shoot_distance**2
|
||||
)
|
||||
angle_at_shooter = math.acos(camera_to_shoot_distance / shooter_distance_to_target)
|
||||
robot_turret_angle = (math.pi / 2) - angle_at_shooter
|
||||
robot_turret_rotations = robot_turret_angle / math.pi
|
||||
|
||||
return robot_turret_rotations
|
||||
|
||||
|
||||
def find_robot_shooting_region(
|
||||
robot_pose: Pose3d,
|
||||
alliance: DriverStation.Alliance,
|
||||
) -> ShootingRegion:
|
||||
"""
|
||||
Determines the shooting region for the robot based on its pose and alliance.
|
||||
|
||||
:param robot_pose: current robot pose
|
||||
:param alliance: robot's alliance (Blue or Red)
|
||||
:return: the matching ShootingRegion enum value
|
||||
"""
|
||||
region = ShootingRegion.NON_SHOOTING_REGION
|
||||
robot_x = robot_pose.X()
|
||||
robot_y = robot_pose.Y()
|
||||
|
||||
# Local aliases to keep condition lines under 120 chars
|
||||
D = ShootingRegionDimensions
|
||||
in_neutral_x = D.NEUTRAL_ZONE_REGION_X_MIN < robot_x < D.NEUTRAL_ZONE_REGION_X_MAX
|
||||
|
||||
if alliance == DriverStation.Alliance.kBlue:
|
||||
if robot_x < ShootingRegionDimensions.BLUE_ALLIANCE_ZONE_REGION_X_MAX:
|
||||
region = ShootingRegion.BLUE_OWN_ALLIANCE_ZONE
|
||||
elif (
|
||||
in_neutral_x
|
||||
and robot_y > ShootingRegionDimensions.BLUE_LEFT_REGION_Y_MIN
|
||||
):
|
||||
region = ShootingRegion.BLUE_LEFT_NEUTRAL_ZONE
|
||||
elif (
|
||||
in_neutral_x
|
||||
and robot_y < ShootingRegionDimensions.BLUE_RIGHT_REGION_Y_MAX
|
||||
):
|
||||
region = ShootingRegion.BLUE_RIGHT_NEUTRAL_ZONE
|
||||
elif (
|
||||
robot_x > ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN
|
||||
and robot_y > ShootingRegionDimensions.BLUE_LEFT_REGION_Y_MIN
|
||||
):
|
||||
region = ShootingRegion.BLUE_LEFT_OPPONENT_ALLIANCE_ZONE
|
||||
elif (
|
||||
robot_x > ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN
|
||||
and robot_y < ShootingRegionDimensions.BLUE_RIGHT_REGION_Y_MAX
|
||||
):
|
||||
region = ShootingRegion.BLUE_RIGHT_OPPONENT_ALLIANCE_ZONE
|
||||
|
||||
elif alliance == DriverStation.Alliance.kRed:
|
||||
if robot_x > ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN:
|
||||
region = ShootingRegion.RED_OWN_ALLIANCE_ZONE
|
||||
elif (
|
||||
in_neutral_x
|
||||
and robot_y < ShootingRegionDimensions.RED_LEFT_REGION_Y_MAX
|
||||
):
|
||||
region = ShootingRegion.RED_LEFT_NEUTRAL_ZONE
|
||||
elif (
|
||||
in_neutral_x
|
||||
and robot_y > ShootingRegionDimensions.RED_RIGHT_REGION_Y_MIN
|
||||
):
|
||||
region = ShootingRegion.RED_RIGHT_NEUTRAL_ZONE
|
||||
elif (
|
||||
robot_x < ShootingRegionDimensions.BLUE_ALLIANCE_ZONE_REGION_X_MAX
|
||||
and robot_y < ShootingRegionDimensions.RED_LEFT_REGION_Y_MAX
|
||||
):
|
||||
region = ShootingRegion.RED_LEFT_OPPONENT_ALLIANCE_ZONE
|
||||
elif (
|
||||
robot_x > ShootingRegionDimensions.RED_ALLIANCE_ZONE_REGION_X_MIN
|
||||
and robot_y > ShootingRegionDimensions.RED_RIGHT_REGION_Y_MIN
|
||||
):
|
||||
region = ShootingRegion.RED_RIGHT_OPPONENT_ALLIANCE_ZONE
|
||||
|
||||
return region
|
||||
|
||||
|
||||
def get_hood_angle_for_distance(distance_meters: float) -> float:
|
||||
"""
|
||||
Returns the hood angle for a given distance.
|
||||
|
||||
:param distance_meters: distance to target in metres
|
||||
:return: hood servo angle
|
||||
"""
|
||||
if distance_meters >= 4:
|
||||
return 200.0
|
||||
return 0.0
|
||||
|
||||
|
||||
def get_launcher_rpm_for_distance(distance_meters: float) -> float:
|
||||
"""
|
||||
Returns the launcher RPM for a given distance, capped at 5000 RPM.
|
||||
|
||||
:param distance_meters: distance to target in metres
|
||||
:return: launcher RPM
|
||||
"""
|
||||
return min((667.557 * distance_meters) + 1500.699, 5000.0)
|
||||
|
||||
|
||||
def find_shooting_target(
|
||||
region: ShootingRegion,
|
||||
alliance: DriverStation.Alliance,
|
||||
) -> Pose3d:
|
||||
"""
|
||||
Determines the appropriate shooting target for the robot's current region
|
||||
and alliance.
|
||||
|
||||
:param region: the robot's current ShootingRegion
|
||||
:param alliance: the robot's alliance (Blue or Red)
|
||||
:return: target Pose3d, or all-zero Pose3d if region/alliance is invalid
|
||||
"""
|
||||
target = Pose3d()
|
||||
|
||||
if alliance == DriverStation.Alliance.kBlue:
|
||||
if region == ShootingRegion.BLUE_OWN_ALLIANCE_ZONE:
|
||||
target = FieldPoses.BLUE_HUB_POSE
|
||||
elif region == ShootingRegion.BLUE_LEFT_NEUTRAL_ZONE:
|
||||
target = FieldPoses.BLUE_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE
|
||||
elif region == ShootingRegion.BLUE_RIGHT_NEUTRAL_ZONE:
|
||||
target = FieldPoses.BLUE_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE
|
||||
elif region == ShootingRegion.BLUE_LEFT_OPPONENT_ALLIANCE_ZONE:
|
||||
target = FieldPoses.BLUE_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE
|
||||
elif region == ShootingRegion.BLUE_RIGHT_OPPONENT_ALLIANCE_ZONE:
|
||||
target = FieldPoses.BLUE_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE
|
||||
|
||||
elif alliance == DriverStation.Alliance.kRed:
|
||||
if region == ShootingRegion.RED_OWN_ALLIANCE_ZONE:
|
||||
target = FieldPoses.RED_HUB_POSE
|
||||
elif region == ShootingRegion.RED_LEFT_NEUTRAL_ZONE:
|
||||
target = FieldPoses.RED_LEFT_ALLIANCE_ZONE_PASS_TARGET_POSE
|
||||
elif region == ShootingRegion.RED_RIGHT_NEUTRAL_ZONE:
|
||||
target = FieldPoses.RED_RIGHT_ALLIANCE_ZONE_PASS_TARGET_POSE
|
||||
elif region == ShootingRegion.RED_LEFT_OPPONENT_ALLIANCE_ZONE:
|
||||
target = FieldPoses.RED_LEFT_NEUTRAL_ZONE_PASS_TARGET_POSE
|
||||
elif region == ShootingRegion.RED_RIGHT_OPPONENT_ALLIANCE_ZONE:
|
||||
target = FieldPoses.RED_RIGHT_NEUTRAL_ZONE_PASS_TARGET_POSE
|
||||
|
||||
return target
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"fileName": "AdvantageKit.json",
|
||||
"name": "AdvantageKit",
|
||||
"version": "26.0.2",
|
||||
"uuid": "d820cc26-74e3-11ec-90d6-0242ac120003",
|
||||
"frcYear": "2026",
|
||||
"mavenUrls": [
|
||||
"https://frcmaven.wpi.edu/artifactory/littletonrobotics-mvn-release/"
|
||||
],
|
||||
"jsonUrl": "https://github.com/Mechanical-Advantage/AdvantageKit/releases/latest/download/AdvantageKit.json",
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "org.littletonrobotics.akit",
|
||||
"artifactId": "akit-java",
|
||||
"version": "26.0.2"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [
|
||||
{
|
||||
"groupId": "org.littletonrobotics.akit",
|
||||
"artifactId": "akit-wpilibio",
|
||||
"version": "26.0.2",
|
||||
"skipInvalidPlatforms": false,
|
||||
"isJar": false,
|
||||
"validPlatforms": [
|
||||
"linuxathena",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal",
|
||||
"windowsx86-64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"cppDependencies": []
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
{
|
||||
"fileName": "ChoreoLib2026.json",
|
||||
"name": "ChoreoLib",
|
||||
"version": "2026.0.2",
|
||||
"uuid": "b5e23f0a-dac9-4ad2-8dd6-02767c520aca",
|
||||
"frcYear": "2026",
|
||||
"mavenUrls": [
|
||||
"https://frcmaven.wpi.edu/artifactory/sleipnirgroup-mvn-release/",
|
||||
"https://repo1.maven.org/maven2"
|
||||
],
|
||||
"jsonUrl": "https://choreo.autos/lib/ChoreoLib2026.json",
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "choreo",
|
||||
"artifactId": "ChoreoLib-java",
|
||||
"version": "2026.0.2"
|
||||
},
|
||||
{
|
||||
"groupId": "com.google.code.gson",
|
||||
"artifactId": "gson",
|
||||
"version": "2.11.0"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "choreo",
|
||||
"artifactId": "ChoreoLib-cpp",
|
||||
"version": "2026.0.2",
|
||||
"libName": "ChoreoLib",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"osxuniversal",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"linuxarm64"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
{
|
||||
"fileName": "Phoenix5-5.36.0.json",
|
||||
"name": "CTRE-Phoenix (v5)",
|
||||
"version": "5.36.0",
|
||||
"frcYear": "2026",
|
||||
"uuid": "ab676553-b602-441f-a38d-f1296eff6537",
|
||||
"mavenUrls": [
|
||||
"https://maven.ctr-electronics.com/release/"
|
||||
],
|
||||
"jsonUrl": "https://maven.ctr-electronics.com/release/com/ctre/phoenix/Phoenix5-frc2026-latest.json",
|
||||
"requires": [
|
||||
{
|
||||
"uuid": "e995de00-2c64-4df5-8831-c1441420ff19",
|
||||
"errorMessage": "Phoenix 5 requires low-level libraries from Phoenix 6. Please add the Phoenix 6 vendordep before adding Phoenix 5.",
|
||||
"offlineFileName": "Phoenix6-frc2026-latest.json",
|
||||
"onlineUrl": "https://maven.ctr-electronics.com/release/com/ctre/phoenix6/latest/Phoenix6-frc2026-latest.json"
|
||||
}
|
||||
],
|
||||
"conflictsWith": [
|
||||
{
|
||||
"uuid": "e7900d8d-826f-4dca-a1ff-182f658e98af",
|
||||
"errorMessage": "Users must use the Phoenix 5 replay vendordep when using the Phoenix 6 replay vendordep.",
|
||||
"offlineFileName": "Phoenix6-replay-frc2026-latest.json"
|
||||
},
|
||||
{
|
||||
"uuid": "fbc886a4-2cec-40c0-9835-71086a8cc3df",
|
||||
"errorMessage": "Users cannot have both the replay and regular Phoenix 5 vendordeps in their robot program.",
|
||||
"offlineFileName": "Phoenix5-replay-frc2026-latest.json"
|
||||
}
|
||||
],
|
||||
"javaDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix",
|
||||
"artifactId": "api-java",
|
||||
"version": "5.36.0"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix",
|
||||
"artifactId": "wpiapi-java",
|
||||
"version": "5.36.0"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix",
|
||||
"artifactId": "cci",
|
||||
"version": "5.36.0",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix.sim",
|
||||
"artifactId": "cci-sim",
|
||||
"version": "5.36.0",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
}
|
||||
],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix",
|
||||
"artifactId": "wpiapi-cpp",
|
||||
"version": "5.36.0",
|
||||
"libName": "CTRE_Phoenix_WPI",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix",
|
||||
"artifactId": "api-cpp",
|
||||
"version": "5.36.0",
|
||||
"libName": "CTRE_Phoenix",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix",
|
||||
"artifactId": "cci",
|
||||
"version": "5.36.0",
|
||||
"libName": "CTRE_PhoenixCCI",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix.sim",
|
||||
"artifactId": "wpiapi-cpp-sim",
|
||||
"version": "5.36.0",
|
||||
"libName": "CTRE_Phoenix_WPISim",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix.sim",
|
||||
"artifactId": "api-cpp-sim",
|
||||
"version": "5.36.0",
|
||||
"libName": "CTRE_PhoenixSim",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix.sim",
|
||||
"artifactId": "cci-sim",
|
||||
"version": "5.36.0",
|
||||
"libName": "CTRE_PhoenixCCISim",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,449 +0,0 @@
|
|||
{
|
||||
"fileName": "Phoenix6-26.1.2.json",
|
||||
"name": "CTRE-Phoenix (v6)",
|
||||
"version": "26.1.2",
|
||||
"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.2"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "api-cpp",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"linuxathena"
|
||||
],
|
||||
"simMode": "hwsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "tools",
|
||||
"version": "26.1.2",
|
||||
"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.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "tools-sim",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simTalonSRX",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simVictorSPX",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simPigeonIMU",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProTalonFX",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProTalonFXS",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANcoder",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProPigeon2",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANrange",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANdi",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
},
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6.sim",
|
||||
"artifactId": "simProCANdle",
|
||||
"version": "26.1.2",
|
||||
"isJar": false,
|
||||
"skipInvalidPlatforms": true,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
}
|
||||
],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "com.ctre.phoenix6",
|
||||
"artifactId": "wpiapi-cpp",
|
||||
"version": "26.1.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"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.2",
|
||||
"libName": "CTRE_SimProCANdle",
|
||||
"headerClassifier": "headers",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxx86-64",
|
||||
"linuxarm64",
|
||||
"osxuniversal"
|
||||
],
|
||||
"simMode": "swsim"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
{
|
||||
"fileName": "REVLib.json",
|
||||
"name": "REVLib",
|
||||
"version": "2026.0.5",
|
||||
"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.5"
|
||||
}
|
||||
],
|
||||
"jniDependencies": [
|
||||
{
|
||||
"groupId": "com.revrobotics.frc",
|
||||
"artifactId": "REVLib-driver",
|
||||
"version": "2026.0.5",
|
||||
"skipInvalidPlatforms": true,
|
||||
"isJar": false,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxarm64",
|
||||
"linuxx86-64",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"osxuniversal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"groupId": "com.revrobotics.frc",
|
||||
"artifactId": "RevLibBackendDriver",
|
||||
"version": "2026.0.5",
|
||||
"skipInvalidPlatforms": true,
|
||||
"isJar": false,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxarm64",
|
||||
"linuxx86-64",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"osxuniversal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"groupId": "com.revrobotics.frc",
|
||||
"artifactId": "RevLibWpiBackendDriver",
|
||||
"version": "2026.0.5",
|
||||
"skipInvalidPlatforms": true,
|
||||
"isJar": false,
|
||||
"validPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxarm64",
|
||||
"linuxx86-64",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"osxuniversal"
|
||||
]
|
||||
}
|
||||
],
|
||||
"cppDependencies": [
|
||||
{
|
||||
"groupId": "com.revrobotics.frc",
|
||||
"artifactId": "REVLib-cpp",
|
||||
"version": "2026.0.5",
|
||||
"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.5",
|
||||
"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.5",
|
||||
"libName": "BackendDriver",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxarm64",
|
||||
"linuxx86-64",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"osxuniversal"
|
||||
]
|
||||
},
|
||||
{
|
||||
"groupId": "com.revrobotics.frc",
|
||||
"artifactId": "RevLibWpiBackendDriver",
|
||||
"version": "2026.0.5",
|
||||
"libName": "REVLibWpi",
|
||||
"sharedLibrary": true,
|
||||
"skipInvalidPlatforms": true,
|
||||
"binaryPlatforms": [
|
||||
"windowsx86-64",
|
||||
"linuxarm64",
|
||||
"linuxx86-64",
|
||||
"linuxathena",
|
||||
"linuxarm32",
|
||||
"osxuniversal"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Loading…
Reference in New Issue